From b734fc9ce64321d91e761dd05e9f8b768d960409 Mon Sep 17 00:00:00 2001 From: jahongireshonqulov Date: Sat, 1 Nov 2025 15:37:05 +0500 Subject: [PATCH] feat:theme changing done --- android/app/src/main/AndroidManifest.xml | 2 + lib/core/constants/app_locale_keys.dart | 2 + lib/core/di/injection_container.config.dart | 5 ++ lib/core/services/storage_service.dart | 8 ++ .../blocs/theme_bloc/theme_bloc.dart | 37 +++++++++ .../blocs/theme_bloc/theme_event.dart | 8 ++ .../blocs/theme_bloc/theme_state.dart | 7 ++ .../presentation/pages/profile_page.dart | 36 +++++--- lib/main.dart | 82 +++++++++++-------- 9 files changed, 142 insertions(+), 45 deletions(-) create mode 100644 lib/feature/common/presentation/blocs/theme_bloc/theme_bloc.dart create mode 100644 lib/feature/common/presentation/blocs/theme_bloc/theme_event.dart create mode 100644 lib/feature/common/presentation/blocs/theme_bloc/theme_state.dart diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index f90fc94..241a500 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,6 +1,8 @@ diff --git a/lib/core/constants/app_locale_keys.dart b/lib/core/constants/app_locale_keys.dart index 66647e9..77b6e52 100644 --- a/lib/core/constants/app_locale_keys.dart +++ b/lib/core/constants/app_locale_keys.dart @@ -3,6 +3,8 @@ abstract class AppLocaleKeys { static const String language = 'language'; static const String browseSearchHistory = 'browse-search-history'; static const String token = 'token'; + static const String theme = 'theme'; + static const String appName = "Felix Eats"; diff --git a/lib/core/di/injection_container.config.dart b/lib/core/di/injection_container.config.dart index 1c22a91..f323855 100644 --- a/lib/core/di/injection_container.config.dart +++ b/lib/core/di/injection_container.config.dart @@ -40,6 +40,8 @@ import '../../feature/auth/presentation/blocs/verify_phone_bloc/verify_phone_blo as _i224; import '../../feature/common/presentation/blocs/language_bloc/language_bloc.dart' as _i942; +import '../../feature/common/presentation/blocs/theme_bloc/theme_bloc.dart' + as _i465; import '../../feature/main/presentation/blocs/main_bloc/main_bloc.dart' as _i580; import '../../feature/onboarding/presentation/blocs/splash_bloc/splash_bloc.dart' @@ -68,6 +70,9 @@ extension GetItInjectableX on _i174.GetIt { gh.factory<_i28.SplashBloc>( () => _i28.SplashBloc(gh<_i321.StorageService>()), ); + gh.factory<_i465.ThemeBloc>( + () => _i465.ThemeBloc(gh<_i321.StorageService>()), + ); gh.lazySingleton<_i361.Dio>(() => dioModule.dio(gh<_i667.DioClient>())); gh.singleton<_i354.RequestHandlerService>( () => _i354.RequestHandlerService(gh<_i361.Dio>()), diff --git a/lib/core/services/storage_service.dart b/lib/core/services/storage_service.dart index 6bc660b..531eff7 100644 --- a/lib/core/services/storage_service.dart +++ b/lib/core/services/storage_service.dart @@ -8,6 +8,10 @@ class StorageService { _sharedPreference = await SharedPreferences.getInstance(); } + void setBool({required String key, required bool value}) { + _sharedPreference.setBool(key, value); + } + void setString({required String key, required String value}) { _sharedPreference.setString(key, value); } @@ -25,6 +29,10 @@ class StorageService { String? getString({required String key}) { return _sharedPreference.getString(key); } + + bool getBool({required String key}) { + return _sharedPreference.getBool(key) ?? false; + } } /* diff --git a/lib/feature/common/presentation/blocs/theme_bloc/theme_bloc.dart b/lib/feature/common/presentation/blocs/theme_bloc/theme_bloc.dart new file mode 100644 index 0000000..2926f97 --- /dev/null +++ b/lib/feature/common/presentation/blocs/theme_bloc/theme_bloc.dart @@ -0,0 +1,37 @@ +import 'package:food_delivery_client/food_delivery_client.dart'; + +part 'theme_event.dart'; + +part 'theme_state.dart'; + +part 'theme_bloc.freezed.dart'; + +@injectable +class ThemeBloc extends Bloc { + final StorageService _storageService; + + ThemeBloc(this._storageService) : super(const ThemeState()) { + on<_Started>(_onStarted); + on<_Changed>(_onChanged); + } + + void _onStarted(_Started event, Emitter emit) { + final isDark = _storageService.getBool(key: AppLocaleKeys.theme); + + if (isDark) { + emit(state.copyWith(themeMode: ThemeMode.dark)); + } else { + emit(state.copyWith(themeMode: ThemeMode.light)); + } + } + + void _onChanged(_Changed event, Emitter emit) { + if (state.themeMode == ThemeMode.light) { + _storageService.setBool(key: AppLocaleKeys.theme, value: true); + emit(state.copyWith(themeMode: ThemeMode.dark)); + } else { + _storageService.setBool(key: AppLocaleKeys.theme, value: false); + emit(state.copyWith(themeMode: ThemeMode.light)); + } + } +} diff --git a/lib/feature/common/presentation/blocs/theme_bloc/theme_event.dart b/lib/feature/common/presentation/blocs/theme_bloc/theme_event.dart new file mode 100644 index 0000000..c3a2107 --- /dev/null +++ b/lib/feature/common/presentation/blocs/theme_bloc/theme_event.dart @@ -0,0 +1,8 @@ +part of 'theme_bloc.dart'; + +@freezed +class ThemeEvent with _$ThemeEvent { + const factory ThemeEvent.started() = _Started; + const factory ThemeEvent.changed() = _Changed; + +} diff --git a/lib/feature/common/presentation/blocs/theme_bloc/theme_state.dart b/lib/feature/common/presentation/blocs/theme_bloc/theme_state.dart new file mode 100644 index 0000000..f35451d --- /dev/null +++ b/lib/feature/common/presentation/blocs/theme_bloc/theme_state.dart @@ -0,0 +1,7 @@ +part of 'theme_bloc.dart'; + +@freezed +abstract class ThemeState with _$ThemeState { + const factory ThemeState({@Default(ThemeMode.light) ThemeMode themeMode}) = + _ThemeState; +} diff --git a/lib/feature/profile/presentation/pages/profile_page.dart b/lib/feature/profile/presentation/pages/profile_page.dart index c0d9d32..531bad6 100644 --- a/lib/feature/profile/presentation/pages/profile_page.dart +++ b/lib/feature/profile/presentation/pages/profile_page.dart @@ -1,21 +1,35 @@ import '../../../../../food_delivery_client.dart'; +import '../../../common/presentation/blocs/theme_bloc/theme_bloc.dart'; class ProfilePage extends StatelessWidget { const ProfilePage({super.key}); @override Widget build(BuildContext context) { - return Scaffold( - body: Column( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text("Home"), - GradientSwitch(value:false, onChanged: (value) { - print(value); - }), - ], - ), + return BlocBuilder( + builder: (context, state) { + return Scaffold( + body: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text("Home"), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text("Dark mode"), + GradientSwitch( + value: state.themeMode == ThemeMode.dark, + onChanged: (value) { + context.read().add(ThemeEvent.changed()); + }, + ), + ], + ).paddingSymmetric(horizontal: 20), + ], + ), + ); + }, ); } } diff --git a/lib/main.dart b/lib/main.dart index f032b4c..1042477 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,5 +1,5 @@ +import 'package:food_delivery_client/feature/common/presentation/blocs/theme_bloc/theme_bloc.dart'; import 'package:toastification/toastification.dart'; - import 'food_delivery_client.dart'; void main() { @@ -13,7 +13,13 @@ void main() { Bloc.observer = AppBlocObserver(); await configureDependencies(); runApp( - BlocProvider(create: (context) => sl(), child: MyApp()), + MultiBlocProvider( + providers: [ + BlocProvider(create: (context) => sl()), + BlocProvider(create: (context) => sl()), + ], + child: MyApp(), + ), ); }, (error, stack) { @@ -32,46 +38,54 @@ class MyApp extends StatefulWidget { class _MyAppState extends State { @override void initState() { - SystemChrome.setPreferredOrientations([ - DeviceOrientation.portraitUp, - DeviceOrientation.portraitDown, - ]); + WidgetsBinding.instance.addPostFrameCallback((timeStamp) { + SystemChrome.setPreferredOrientations([ + DeviceOrientation.portraitUp, + DeviceOrientation.portraitDown, + ]); + context.read().add(LanguageEvent.started()); + context.read().add(ThemeEvent.started()); + }); + super.initState(); } @override Widget build(BuildContext context) { return BlocBuilder( - bloc: context.read()..add(LanguageEvent.started()), builder: (context, state) { - return ToastificationWrapper( - child: MaterialApp.router( - title: AppLocaleKeys.appName, - debugShowCheckedModeBanner: false, - theme: AppTheme.lightTheme, - darkTheme: AppTheme.darkTheme, - themeMode: ThemeMode.light, - routerConfig: sl().router, - locale: state.currentLocale, - supportedLocales: L10n.locales, - localizationsDelegates: [ - AppLocalizations.delegate, - GlobalMaterialLocalizations.delegate, - GlobalWidgetsLocalizations.delegate, - GlobalCupertinoLocalizations.delegate, - ], - builder: (context, child) => GestureDetector( - onTap: () { - FocusManager.instance.primaryFocus?.unfocus(); - }, - child: MediaQuery( - data: MediaQuery.of( - context, - ).copyWith(textScaler: const TextScaler.linear(1)), - child: child!, + return BlocBuilder( + builder: (context, themeState) { + return ToastificationWrapper( + child: MaterialApp.router( + title: AppLocaleKeys.appName, + debugShowCheckedModeBanner: false, + theme: AppTheme.lightTheme, + darkTheme: AppTheme.darkTheme, + themeMode: themeState.themeMode, + routerConfig: sl().router, + locale: state.currentLocale, + supportedLocales: L10n.locales, + localizationsDelegates: [ + AppLocalizations.delegate, + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + ], + builder: (context, child) => GestureDetector( + onTap: () { + FocusManager.instance.primaryFocus?.unfocus(); + }, + child: MediaQuery( + data: MediaQuery.of( + context, + ).copyWith(textScaler: const TextScaler.linear(1)), + child: child!, + ), + ), ), - ), - ), + ); + }, ); }, );