From 0caea70b2fbe4ade14fc6a876fc4500929381ef4 Mon Sep 17 00:00:00 2001 From: Hans Kokx Date: Wed, 30 Apr 2025 11:45:20 +0200 Subject: [PATCH] Updated example to add a services example Signed-off-by: Hans Kokx --- example/lib/main.dart | 123 ++++++++++++++++-- .../lib/services/favorite_color_service.dart | 43 ++++++ test/providers/service_provider_test.dart | 7 +- 3 files changed, 161 insertions(+), 12 deletions(-) create mode 100644 example/lib/services/favorite_color_service.dart diff --git a/example/lib/main.dart b/example/lib/main.dart index 64b97c1..017ff09 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -5,6 +5,7 @@ import "package:example/config.dart"; import "package:example/interfaces/debug_auth_interface.dart"; import "package:example/interfaces/debug_print_interface.dart"; import "package:example/services/demo_service.dart"; +import "package:example/services/favorite_color_service.dart"; import "package:example/theme/theme.dart"; import "package:flutter/material.dart"; @@ -81,8 +82,9 @@ class HomeScreen extends StatefulWidget { class _HomeScreenState extends State { late final StreamSubscription _subscription; + late final StreamSubscription _serviceSubscription; final List latestLogs = []; - final List themeColors = [ + static const List colors = [ Colors.red, Colors.orange, Colors.yellow, @@ -94,7 +96,6 @@ class _HomeScreenState extends State { @override Widget build(BuildContext context) { - final bool isSignedIn = Arcane.auth.isSignedIn.value; return Column( children: [ Expanded( @@ -192,7 +193,7 @@ class _HomeScreenState extends State { const Text("Color"), Expanded( child: ListView.separated( - itemCount: themeColors.length, + itemCount: colors.length, scrollDirection: Axis.horizontal, separatorBuilder: (_, __) => const SizedBox(width: 4), @@ -204,7 +205,7 @@ class _HomeScreenState extends State { Arcane.theme.setDarkTheme( ThemeData( brightness: Brightness.dark, - colorSchemeSeed: themeColors[index], + colorSchemeSeed: colors[index], ), ); } else if (Arcane @@ -213,17 +214,17 @@ class _HomeScreenState extends State { Arcane.theme.setLightTheme( ThemeData( brightness: Brightness.light, - colorSchemeSeed: themeColors[index], + colorSchemeSeed: colors[index], ), ); } Arcane.log( - "Setting ${Arcane.theme.currentThemeMode.name} theme color to ${themeColors[index]}", + "Setting ${Arcane.theme.currentThemeMode.name} theme color to ${colors[index]}", ); }, child: Container( - color: themeColors[index], + color: colors[index], width: 20, height: 20, ), @@ -259,7 +260,7 @@ class _HomeScreenState extends State { ElevatedButton( onPressed: Feature.authentication.enabled ? () async { - if (isSignedIn) { + if (Arcane.auth.isSignedIn.value) { await Arcane.auth.logOut( onLoggedOut: () async { setState(() {}); @@ -278,7 +279,9 @@ class _HomeScreenState extends State { } } : null, - child: Text(isSignedIn ? "Sign out" : "Sign in"), + child: Text( + Arcane.auth.isSignedIn.value ? "Sign out" : "Sign in", + ), ), Center( child: Text("Status: ${Arcane.auth.status.name}"), @@ -377,6 +380,108 @@ class _HomeScreenState extends State { ), ), ), + + // Services + Card( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Text( + "Services", + style: Theme.of(context).textTheme.headlineSmall, + ), + ValueListenableBuilder( + valueListenable: + ArcaneService.ofType( + context, + )?.notifier ?? + ValueNotifier(null), + builder: (context, color, _) { + return Text( + color != null + ? "Favorite color: ${color.name}" + : "", + ); + }, + ), + ElevatedButton( + onPressed: ArcaneServiceProvider.serviceOfType< + FavoriteColorService>(context) == + null + ? () { + ArcaneServiceProvider.of(context).addService( + FavoriteColorService.I, + ); + Arcane.log( + "Service registered.", + metadata: { + "service": "FavoriteColorService", + }, + ); + } + : () { + ArcaneServiceProvider.of(context) + .removeService(); + Arcane.log( + "Service removed.", + metadata: { + "service": "FavoriteColorService", + }, + ); + }, + child: Text( + '${ArcaneServiceProvider.serviceOfType(context) == null ? 'Register' : 'Remove'} service', + ), + ), + SizedBox( + height: 20, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + spacing: 8, + children: [ + const Text("Color"), + Expanded( + child: ListView.separated( + itemCount: colors.length, + scrollDirection: Axis.horizontal, + separatorBuilder: (_, __) => + const SizedBox(width: 4), + itemBuilder: (context, index) { + return InkWell( + onTap: () { + ArcaneService.ofType< + FavoriteColorService>( + context, + )?.setMyFavoriteColor(colors[index]); + Arcane.log( + "Set a color in FavoriteColorService", + metadata: { + "color": colors[index].name, + }, + ); + }, + child: Container( + color: colors[index], + width: 20, + height: 20, + ), + ); + }, + ), + ), + ], + ), + ), + Text( + "Service is ${ArcaneService.ofType(context) != null ? "" : "not "}registered", + ), + ], + ), + ), + ), ], ), ), diff --git a/example/lib/services/favorite_color_service.dart b/example/lib/services/favorite_color_service.dart new file mode 100644 index 0000000..53b8fba --- /dev/null +++ b/example/lib/services/favorite_color_service.dart @@ -0,0 +1,43 @@ +import "package:arcane_framework/arcane_framework.dart"; +import "package:flutter/material.dart"; + +class FavoriteColorService extends ArcaneService { + static final FavoriteColorService _instance = + FavoriteColorService._internal(); + + static FavoriteColorService get I => _instance; + + FavoriteColorService._internal(); + + MaterialColor? get myFavoriteColor => _notifier.value; + + final ValueNotifier _notifier = + ValueNotifier(null); + + ValueNotifier get notifier => _notifier; + + void setMyFavoriteColor(MaterialColor? newValue) { + if (_notifier.value != newValue) { + _notifier.value = newValue; + } + + notifyListeners(); + } +} + +extension ColorName on MaterialColor { + String get name { + final double red = double.parse(r.toStringAsFixed(4)); + final double green = double.parse(g.toStringAsFixed(4)); + final double blue = double.parse(b.toStringAsFixed(4)); + if (red == 0.9569 && green == 0.2627 && blue == 0.2118) return "red"; + if (red == 1 && green == 0.5961 && blue == 0) return "orange"; + if (red == 1 && green == 0.9216 && blue == 0.2314) return "yellow"; + if (red == 0.2980 && green == 0.6863 && blue == 0.3137) return "green"; + if (red == 0.1294 && green == 0.5882 && blue == 0.9529) return "blue"; + if (red == 0.6118 && green == 0.1529 && blue == 0.6902) return "indigo"; + if (red == 0.4039 && green == 0.2275 && blue == 0.7176) return "violet"; + + return ""; + } +} diff --git a/test/providers/service_provider_test.dart b/test/providers/service_provider_test.dart index bf2c4ca..fa10d76 100644 --- a/test/providers/service_provider_test.dart +++ b/test/providers/service_provider_test.dart @@ -194,7 +194,7 @@ void main() { services: testServices, child: Builder( builder: (context) { - final service = ArcaneService.of(context); + final service = ArcaneService.ofType(context); expect(service, isNotNull); expect(service, isA()); return const SizedBox(); @@ -212,11 +212,12 @@ void main() { child: Builder( builder: (context) { final service = - ArcaneService.requiredOf(context); + ArcaneService.requiredOfType(context); expect(service, isA()); expect( - () => ArcaneService.requiredOf(context), + () => + ArcaneService.requiredOfType(context), throwsA(isA()), );