chico_services 1.3.0
chico_services: ^1.3.0 copied to clipboard
One-call facades for networking, storage, files, device, maps, and more on top of Chico Kit — call with parameters, defaults inside.
import 'package:chico_services/chico_services.dart';
import 'package:flutter/widgets.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await ChicoServices.init();
ChicoAuth.configure(
login: (email, password) async {
await Future<void>.delayed(const Duration(milliseconds: 400));
if (password.length < 3) {
throw Exception('Password too short');
}
return ChicoAuthSession(token: 'demo-$email', email: email);
},
);
await ChicoAuth.restore();
runApp(const ServicesGalleryApp());
}
/// Gallery for Chico Services one-liners.
class ServicesGalleryApp extends StatefulWidget {
/// Creates the gallery app.
const ServicesGalleryApp({super.key});
@override
State<ServicesGalleryApp> createState() => _ServicesGalleryAppState();
}
class _ServicesGalleryAppState extends State<ServicesGalleryApp> {
var _mode = ChicoThemeMode.system;
@override
Widget build(BuildContext context) {
return ChicoApp(
themeMode: _mode,
home: _GalleryHome(
mode: _mode,
onModeChanged: (mode) => setState(() => _mode = mode),
),
);
}
}
class _GalleryHome extends StatelessWidget {
const _GalleryHome({required this.mode, required this.onModeChanged});
final ChicoThemeMode mode;
final ValueChanged<ChicoThemeMode> onModeChanged;
@override
Widget build(BuildContext context) {
return ChicoPage(
title: 'Chico Services',
child: ChicoColumn(
gap: ChicoSpace.space16,
children: [
ChicoTabs(
labels: const ['System', 'Light', 'Dark'],
index: mode.index,
onChanged: (i) => onModeChanged(ChicoThemeMode.values[i]),
),
const ChicoText('Prefs', variant: ChicoTextVariant.headline),
const _PrefsDemo(),
const ChicoText('Secure', variant: ChicoTextVariant.headline),
const _SecureDemo(),
const ChicoText('Files', variant: ChicoTextVariant.headline),
const _FilesDemo(),
const ChicoText('API', variant: ChicoTextVariant.headline),
const _ApiDemo(),
const ChicoText(
'Permissions / location',
variant: ChicoTextVariant.headline,
),
const _DeviceDemo(),
const ChicoText('Launcher', variant: ChicoTextVariant.headline),
const _LauncherDemo(),
const ChicoText('Auth', variant: ChicoTextVariant.headline),
const _AuthDemo(),
const ChicoText(
'Store / share / net',
variant: ChicoTextVariant.headline,
),
const _StoreShareDemo(),
const ChicoText('Camera', variant: ChicoTextVariant.headline),
ChicoCameraView(
height: 220,
onCapture: (file) => context.showToast(file.name),
),
const ChicoText('Map', variant: ChicoTextVariant.headline),
const ChicoText(
'Needs a Google Maps API key in AndroidManifest / AppDelegate.',
role: ChicoTextRole.secondary,
variant: ChicoTextVariant.footnote,
),
const ChicoMapView(
height: 180,
lat: 33.5731,
lng: -7.5898,
markers: [
ChicoMapMarker(
id: 'casa',
lat: 33.5731,
lng: -7.5898,
title: 'Casablanca',
),
],
),
],
),
);
}
}
class _PrefsDemo extends StatefulWidget {
const _PrefsDemo();
@override
State<_PrefsDemo> createState() => _PrefsDemoState();
}
class _PrefsDemoState extends State<_PrefsDemo> {
@override
Widget build(BuildContext context) {
final visits = ChicoPrefs.getInt('gallery_visits');
return ChicoColumn(
gap: ChicoSpace.space8,
children: [
ChicoText(
'gallery_visits = $visits',
role: ChicoTextRole.secondary,
variant: ChicoTextVariant.footnote,
),
ChicoButton(
label: 'Increment pref',
expand: true,
onPressed: () async {
await ChicoPrefs.setInt('gallery_visits', visits + 1);
if (!mounted) {
return;
}
setState(() {});
if (!context.mounted) {
return;
}
context.showToast('Saved ${visits + 1}');
},
),
],
);
}
}
class _SecureDemo extends StatelessWidget {
const _SecureDemo();
@override
Widget build(BuildContext context) {
return ChicoButton(
label: 'Secure put / get demo token',
expand: true,
tone: ChicoButtonTone.neutral,
onPressed: () async {
await ChicoSecure.put('demo_token', 'secret-demo');
final value = await ChicoSecure.get('demo_token');
if (context.mounted) {
context.showToast(value ?? 'missing');
}
},
);
}
}
class _FilesDemo extends StatelessWidget {
const _FilesDemo();
@override
Widget build(BuildContext context) {
return ChicoColumn(
gap: ChicoSpace.space8,
children: [
ChicoButton(
label: 'Pick image',
expand: true,
tone: ChicoButtonTone.neutral,
onPressed: () async {
final file = await ChicoFiles.pickImage();
if (!context.mounted) {
return;
}
context.showToast(file?.name ?? 'Cancelled');
},
),
ChicoButton(
label: 'Pick document',
expand: true,
tone: ChicoButtonTone.neutral,
onPressed: () async {
final file = await ChicoFiles.pickDocument();
if (!context.mounted) {
return;
}
context.showToast(file?.name ?? 'Cancelled');
},
),
],
);
}
}
class _ApiDemo extends StatelessWidget {
const _ApiDemo();
@override
Widget build(BuildContext context) {
return ChicoColumn(
gap: ChicoSpace.space8,
children: [
const ChicoText(
'Init with baseUrl in main to enable live calls. '
'Demo below hits https://httpbin.org/get when ready.',
role: ChicoTextRole.secondary,
variant: ChicoTextVariant.footnote,
),
ChicoButton(
label: 'GET httpbin (init if needed)',
expand: true,
onPressed: () async {
if (!ChicoApi.isReady) {
ChicoApi.init(baseUrl: 'https://httpbin.org');
}
final data = await context.apiBusy(
() => ChicoApi.get<Map<String, dynamic>>('/get'),
message: 'Loading',
);
if (context.mounted && data != null) {
context.showToast('url=${data['url']}');
}
},
),
],
);
}
}
class _DeviceDemo extends StatelessWidget {
const _DeviceDemo();
@override
Widget build(BuildContext context) {
return ChicoColumn(
gap: ChicoSpace.space8,
children: [
ChicoButton(
label: 'Request camera permission',
expand: true,
tone: ChicoButtonTone.neutral,
onPressed: () async {
final ok = await ChicoPermissions.camera();
if (context.mounted) {
context.showToast(ok ? 'Camera granted' : 'Camera denied');
}
},
),
ChicoButton(
label: 'Current location',
expand: true,
tone: ChicoButtonTone.neutral,
onPressed: () async {
if (!context.mounted) {
return;
}
context.showBusy(message: 'Locating');
final pos = await ChicoLocation.current();
if (!context.mounted) {
return;
}
context.hideBusy();
if (pos == null) {
context.showToast('Location unavailable');
return;
}
context.showToast(
'${pos.latitude.toStringAsFixed(4)}, '
'${pos.longitude.toStringAsFixed(4)}',
);
},
),
],
);
}
}
class _LauncherDemo extends StatelessWidget {
const _LauncherDemo();
@override
Widget build(BuildContext context) {
return ChicoColumn(
gap: ChicoSpace.space8,
children: [
ChicoButton(
label: 'Open example.com',
expand: true,
tone: ChicoButtonTone.neutral,
onPressed: () => ChicoLauncher.url('https://example.com'),
),
ChicoButton(
label: 'Open maps (Casablanca)',
expand: true,
tone: ChicoButtonTone.neutral,
onPressed: () => ChicoLauncher.maps(
lat: 33.5731,
lng: -7.5898,
label: 'Casablanca',
),
),
],
);
}
}
class _AuthDemo extends StatelessWidget {
const _AuthDemo();
@override
Widget build(BuildContext context) {
return ChicoListen<bool>(
listenable: ChicoAuth.listenable,
builder: (context, signedIn, _) {
return ChicoColumn(
gap: ChicoSpace.space8,
children: [
ChicoText(
signedIn
? 'Signed in as ${ChicoAuth.session?.email ?? 'user'}'
: 'Signed out — demo password needs 3+ chars',
role: ChicoTextRole.secondary,
variant: ChicoTextVariant.footnote,
),
ChicoButton(
label: signedIn ? 'Sign out' : 'Sign in (demo@chico.dev)',
expand: true,
onPressed: () async {
if (signedIn) {
await context.signOutBusy();
return;
}
final session = await context.signInBusy(
email: 'demo@chico.dev',
password: 'demo',
);
if (context.mounted && session != null) {
context.showToast('Welcome');
}
},
),
],
);
},
);
}
}
class _StoreShareDemo extends StatelessWidget {
const _StoreShareDemo();
@override
Widget build(BuildContext context) {
return ChicoColumn(
gap: ChicoSpace.space8,
children: [
ChicoButton(
label: 'Store put / get',
expand: true,
tone: ChicoButtonTone.neutral,
onPressed: () async {
if (!ChicoStore.isReady) {
await ChicoStore.init();
}
await ChicoStore.put('demo', '1', {'hello': 'chico'});
final row = await ChicoStore.get('demo', '1');
if (context.mounted) {
context.showToast('${row?['hello']}');
}
},
),
ChicoButton(
label: 'Share text',
expand: true,
tone: ChicoButtonTone.neutral,
onPressed: () => ChicoShare.text('Hello from Chico Services'),
),
ChicoButton(
label: 'Check online',
expand: true,
tone: ChicoButtonTone.neutral,
onPressed: () async {
final online = await ChicoNet.isOnline;
if (context.mounted) {
context.showToast(online ? 'Online' : 'Offline');
}
},
),
],
);
}
}