From dd6d5a855ca3422b2752553e28b51c45065d5c03 Mon Sep 17 00:00:00 2001 From: Salah Nahed Date: Sat, 30 Mar 2024 00:16:31 +0200 Subject: [PATCH] remove app bloc and replace it with app providers --- lib/bond_app.dart | 15 +++--- lib/core/utils/device_info.dart | 5 +- .../bond_pop_menu/bond_pop_menu_button.dart | 30 +++++------ lib/features/app/app_bloc.dart | 38 ------------- lib/features/app/app_event.dart | 23 -------- lib/features/app/app_providers.dart | 18 +++++++ lib/features/app/app_state.dart | 37 ------------- .../app/data/app_local_data_source.dart | 54 ------------------- .../app/notifiers/local_notifier.dart | 20 +++++++ .../app/notifiers/theme_notifier.dart | 45 ++++++++++++++++ lib/main.dart | 9 +--- lib/providers/app_service_provider.dart | 7 --- pubspec.lock | 12 ++--- 13 files changed, 116 insertions(+), 197 deletions(-) delete mode 100644 lib/features/app/app_bloc.dart delete mode 100644 lib/features/app/app_event.dart create mode 100644 lib/features/app/app_providers.dart delete mode 100644 lib/features/app/app_state.dart delete mode 100644 lib/features/app/data/app_local_data_source.dart create mode 100644 lib/features/app/notifiers/local_notifier.dart create mode 100644 lib/features/app/notifiers/theme_notifier.dart diff --git a/lib/bond_app.dart b/lib/bond_app.dart index f9dbc6e7..299cd63a 100644 --- a/lib/bond_app.dart +++ b/lib/bond_app.dart @@ -1,18 +1,19 @@ import 'package:bond/app/routes.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'core/app_theme.dart'; -import 'features/app/app_bloc.dart'; +import 'features/app/app_providers.dart'; -class BondApp extends StatelessWidget { +class BondApp extends ConsumerWidget { const BondApp({Key? key}) : super(key: key); @override - Widget build(BuildContext context) { - final appBloc = context.watch(); + Widget build(BuildContext context, WidgetRef ref) { + final locale = ref.watch(localProvider); + final theme = ref.watch(themeProvider); return MaterialApp.router( routerConfig: goRouter, localizationsDelegates: const [ @@ -21,12 +22,12 @@ class BondApp extends StatelessWidget { GlobalCupertinoLocalizations.delegate, AppLocalizations.delegate, ], - locale: appBloc.state.currentLocale, + locale: locale, supportedLocales: const [Locale('ar'), Locale('en')], debugShowCheckedModeBanner: true, theme: appLightThemeData(), darkTheme: appDarkThemeData(), - themeMode: appBloc.state.currentThemeMode, + themeMode: theme, ); } } diff --git a/lib/core/utils/device_info.dart b/lib/core/utils/device_info.dart index f7a0c74d..21f24563 100644 --- a/lib/core/utils/device_info.dart +++ b/lib/core/utils/device_info.dart @@ -1,6 +1,6 @@ import 'dart:io'; -import 'package:bond/features/app/data/app_local_data_source.dart'; +import 'package:bond_cache/bond_cache.dart'; import 'package:bond_core/bond_core.dart'; import 'package:device_info_plus/device_info_plus.dart'; import 'package:package_info_plus/package_info_plus.dart'; @@ -10,7 +10,6 @@ class DeviceInfo { Future> toJson() async { final deviceInfoPlugin = sl(); final packageInfo = sl(); - final appLocalDataSource = sl(); final map = {}; map.addAll({ 'device_type': 'mobile', @@ -18,7 +17,7 @@ class DeviceInfo { 'device_brand': getDeviceType(), 'os_version': packageInfo.buildNumber, 'app_version': packageInfo.buildNumber, - 'language': appLocalDataSource.currentLocale.languageCode, + 'language': Cache.get('language', defaultValue: 'en'), 'device_id': await deviceIdInfo(), }); if (UniversalPlatform.isAndroid) { diff --git a/lib/core/widgets/bond_pop_menu/bond_pop_menu_button.dart b/lib/core/widgets/bond_pop_menu/bond_pop_menu_button.dart index 03a24f20..795c30a0 100644 --- a/lib/core/widgets/bond_pop_menu/bond_pop_menu_button.dart +++ b/lib/core/widgets/bond_pop_menu/bond_pop_menu_button.dart @@ -1,20 +1,20 @@ import 'package:bond/core/app_localizations.dart'; -import 'package:bond/features/app/app_bloc.dart'; +import 'package:bond/features/app/app_providers.dart'; import 'package:bond/features/auth/auth.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:bond_core/bond_core.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import 'bond_popup_menu_item.dart'; -class BondPopMenuButton extends StatelessWidget { +class BondPopMenuButton extends ConsumerWidget { const BondPopMenuButton({Key? key}) : super(key: key); @override - Widget build(BuildContext context) { + Widget build(BuildContext context, WidgetRef ref) { return PopupMenuButton( - onSelected: (Menu item) => _onSelected(context, item), + onSelected: (Menu item) => _onSelected(ref, item), icon: const Icon( Icons.more_vert_rounded, ), @@ -56,25 +56,25 @@ class BondPopMenuButton extends StatelessWidget { ); } - void _onSelected(BuildContext context, Menu item) { - final appBloc = context.read(); + void _onSelected(WidgetRef ref, Menu item) { switch (item) { case Menu.theme: - final newThemeMode = appBloc.state.currentThemeMode == ThemeMode.light - ? ThemeMode.dark - : ThemeMode.light; - appBloc.add(ChangeThemeEvent(newThemeMode)); + final theme = ref.read(themeProvider); + final newThemeMode = + theme == ThemeMode.light ? ThemeMode.dark : ThemeMode.light; + ref.read(themeProvider.notifier).update(newThemeMode); break; case Menu.language: - final newLocale = appBloc.state.currentLocale == const Locale('en') + final local = ref.read(localProvider); + final newLocale = local == const Locale('en') ? const Locale('ar') : const Locale('en'); - appBloc.add(ChangeLocaleEvent(newLocale)); + ref.read(localProvider.notifier).update(newLocale); break; case Menu.logout: break; case Menu.notifications: - context.go('/notifications'); + ref.context.go('/notifications'); break; } } diff --git a/lib/features/app/app_bloc.dart b/lib/features/app/app_bloc.dart deleted file mode 100644 index bf4573d3..00000000 --- a/lib/features/app/app_bloc.dart +++ /dev/null @@ -1,38 +0,0 @@ -import 'dart:async'; - -import 'package:bloc/bloc.dart'; -import 'package:bond/features/app/data/app_local_data_source.dart'; -import 'package:bond/features/auth/data/models/user.dart'; -import 'package:equatable/equatable.dart'; -import 'package:flutter/material.dart'; - -part 'app_event.dart'; -part 'app_state.dart'; - -class AppBloc extends Bloc { - AppBloc( - this._appLocalDataSource, - ) : super( - AppState.initial( - currentLocale: _appLocalDataSource.currentLocale, - currentThemeMode: _appLocalDataSource.currentThemeMode, - ), - ) { - on(_onChangeThemeEvent); - on(_onChangeLocaleEvent); - } - - final AppLocalDataSource _appLocalDataSource; - - FutureOr _onChangeThemeEvent( - ChangeThemeEvent event, Emitter emit) { - _appLocalDataSource.currentThemeMode = event.themeMode; - emit(state.copyWith(currentThemeMode: event.themeMode)); - } - - FutureOr _onChangeLocaleEvent( - ChangeLocaleEvent event, Emitter emit) { - _appLocalDataSource.currentLocale = event.locale; - emit(state.copyWith(currentLocale: event.locale)); - } -} diff --git a/lib/features/app/app_event.dart b/lib/features/app/app_event.dart deleted file mode 100644 index bb0403bc..00000000 --- a/lib/features/app/app_event.dart +++ /dev/null @@ -1,23 +0,0 @@ -part of 'app_bloc.dart'; - -abstract class AppEvent extends Equatable { - const AppEvent(); -} - -class ChangeThemeEvent extends AppEvent { - final ThemeMode themeMode; - - const ChangeThemeEvent(this.themeMode); - - @override - List get props => [themeMode]; -} - -class ChangeLocaleEvent extends AppEvent { - final Locale locale; - - const ChangeLocaleEvent(this.locale); - - @override - List get props => [locale]; -} diff --git a/lib/features/app/app_providers.dart b/lib/features/app/app_providers.dart new file mode 100644 index 00000000..78b74600 --- /dev/null +++ b/lib/features/app/app_providers.dart @@ -0,0 +1,18 @@ +library app_providers; + +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import 'notifiers/local_notifier.dart'; +import 'notifiers/theme_notifier.dart'; + +export 'notifiers/local_notifier.dart'; +export 'notifiers/theme_notifier.dart'; + +final localProvider = NotifierProvider(() { + return LocalNotifier(); +}); + +final themeProvider = NotifierProvider(() { + return ThemeNotifier(); +}); diff --git a/lib/features/app/app_state.dart b/lib/features/app/app_state.dart deleted file mode 100644 index 6367288d..00000000 --- a/lib/features/app/app_state.dart +++ /dev/null @@ -1,37 +0,0 @@ -part of 'app_bloc.dart'; - -class AppState extends Equatable { - const AppState({ - required this.currentLocale, - required this.currentThemeMode, - }); - - final Locale currentLocale; - final ThemeMode currentThemeMode; - - factory AppState.initial({ - final User? user, - required Locale currentLocale, - required ThemeMode currentThemeMode, - }) => - AppState( - currentLocale: currentLocale, - currentThemeMode: currentThemeMode, - ); - - @override - List get props => [ - currentLocale.languageCode, - currentThemeMode, - ]; - - AppState copyWith({ - Locale? currentLocale, - ThemeMode? currentThemeMode, - }) { - return AppState( - currentLocale: currentLocale ?? this.currentLocale, - currentThemeMode: currentThemeMode ?? this.currentThemeMode, - ); - } -} diff --git a/lib/features/app/data/app_local_data_source.dart b/lib/features/app/data/app_local_data_source.dart deleted file mode 100644 index 60fe9aa0..00000000 --- a/lib/features/app/data/app_local_data_source.dart +++ /dev/null @@ -1,54 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:shared_preferences/shared_preferences.dart'; - -class AppLocalDataSource { - final SharedPreferences sharedPreferences; - - AppLocalDataSource({required this.sharedPreferences}); - - static var currentLocaleKey = 'CURRENT_LOCALE'; - static var currentThemeKey = 'CURRENT_THEME'; - - set currentLocale(Locale currentLocal) { - sharedPreferences.setString(currentLocaleKey, currentLocal.languageCode); - } - - Locale get currentLocale => Locale( - sharedPreferences.getString(currentLocaleKey) ?? 'en', - ); // default is English - - set currentThemeMode(ThemeMode currentLocal) { - sharedPreferences.setString(currentThemeKey, currentLocal.value); - } - - ThemeMode get currentThemeMode => ThemeModeExtension.fromValue( - sharedPreferences.getString(currentThemeKey) ?? 'system'); -} - -extension ThemeModeExtension on ThemeMode { - String get value { - switch (this) { - case ThemeMode.dark: - return 'dark'; - case ThemeMode.light: - return 'light'; - case ThemeMode.system: - return 'system'; - default: - return 'system'; - } - } - - static ThemeMode fromValue(String value) { - switch (value) { - case 'dark': - return ThemeMode.dark; - case 'light': - return ThemeMode.light; - case 'system': - return ThemeMode.system; - default: - return ThemeMode.system; - } - } -} diff --git a/lib/features/app/notifiers/local_notifier.dart b/lib/features/app/notifiers/local_notifier.dart new file mode 100644 index 00000000..2a5c2374 --- /dev/null +++ b/lib/features/app/notifiers/local_notifier.dart @@ -0,0 +1,20 @@ +import 'dart:io'; +import 'dart:ui'; + +import 'package:bond_cache/bond_cache.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class LocalNotifier extends Notifier { + @override + Locale build() => Locale( + Cache.get( + 'language', + defaultValue: Platform.localeName, + ), + ); + + void update(Locale locale) { + Cache.put('language', locale.languageCode); + state = locale; + } +} diff --git a/lib/features/app/notifiers/theme_notifier.dart b/lib/features/app/notifiers/theme_notifier.dart new file mode 100644 index 00000000..81266092 --- /dev/null +++ b/lib/features/app/notifiers/theme_notifier.dart @@ -0,0 +1,45 @@ +import 'package:bond_cache/bond_cache.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class ThemeNotifier extends Notifier { + @override + ThemeMode build() => XThemeMode.fromValue( + Cache.get( + 'theme', + defaultValue: ThemeMode.system.value, + ), + ); + + void update(ThemeMode themeMode) { + Cache.put('theme', themeMode.value); + } +} + +extension XThemeMode on ThemeMode { + String get value { + switch (this) { + case ThemeMode.dark: + return 'dark'; + case ThemeMode.light: + return 'light'; + case ThemeMode.system: + return 'system'; + default: + return 'system'; + } + } + + static ThemeMode fromValue(String value) { + switch (value) { + case 'dark': + return ThemeMode.dark; + case 'light': + return ThemeMode.light; + case 'system': + return ThemeMode.system; + default: + return ThemeMode.system; + } + } +} diff --git a/lib/main.dart b/lib/main.dart index f3cb7b5c..8b4add31 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,6 +1,4 @@ -import 'package:bond/features/app/app_bloc.dart'; import 'package:bond_core/bond_core.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'app/app.dart'; @@ -8,11 +6,8 @@ import 'app/app_run_tasks.dart'; import 'bond_app.dart'; void main() => run( - () => ProviderScope( - child: BlocProvider( - create: (context) => sl(), - child: const BondApp(), - ), + () => const ProviderScope( + child: BondApp(), ), tasks: RunAppTasks(), providers: providers, diff --git a/lib/providers/app_service_provider.dart b/lib/providers/app_service_provider.dart index 0cb90180..a354a1c3 100644 --- a/lib/providers/app_service_provider.dart +++ b/lib/providers/app_service_provider.dart @@ -1,5 +1,3 @@ -import 'package:bond/features/app/app_bloc.dart'; -import 'package:bond/features/app/data/app_local_data_source.dart'; import 'package:bond/features/update_app/data/update_app_service.dart'; import 'package:bond_core/bond_core.dart'; import 'package:flutter/foundation.dart'; @@ -12,11 +10,6 @@ class AppServiceProvider extends ServiceProvider { final sharedPreferences = await SharedPreferences.getInstance(); it.registerLazySingleton(() => sharedPreferences); - it.registerLazySingleton( - () => AppLocalDataSource(sharedPreferences: sharedPreferences), - ); - - it.registerFactory(() => AppBloc(it())); if (!kIsWeb) { it.registerSingleton( UpdateAppService(remoteConfig: it(), packageInfo: it())..call(), diff --git a/pubspec.lock b/pubspec.lock index 78702937..49ce4f1e 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -53,10 +53,10 @@ packages: dependency: "direct main" description: name: bloc - sha256: "3820f15f502372d979121de1f6b97bfcf1630ebff8fe1d52fb2b0bfa49be5b49" + sha256: "106842ad6569f0b60297619e9e0b1885c2fb9bf84812935490e6c5275777804e" url: "https://pub.dev" source: hosted - version: "8.1.2" + version: "8.1.4" bond_app_analytics: dependency: "direct main" description: @@ -482,10 +482,10 @@ packages: dependency: "direct main" description: name: flutter_bloc - sha256: e74efb89ee6945bcbce74a5b3a5a3376b088e5f21f55c263fc38cbdc6237faae + sha256: f0ecf6e6eb955193ca60af2d5ca39565a86b8a142452c5b24d96fb477428f4d2 url: "https://pub.dev" source: hosted - version: "8.1.3" + version: "8.1.5" flutter_launcher_icons: dependency: "direct dev" description: @@ -1001,10 +1001,10 @@ packages: dependency: transitive description: name: provider - sha256: cdbe7530b12ecd9eb455bdaa2fcb8d4dad22e80b8afb4798b41479d5ce26847f + sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c url: "https://pub.dev" source: hosted - version: "6.0.5" + version: "6.1.2" pub_semver: dependency: transitive description: