diff --git a/android/gradle.properties b/android/gradle.properties index 588e695c30a170652ec0f6e7ae0648d5d3a099ae..b33cdc8cb304c3e2e8e24f97f7e1fff87cf93379 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1,5 +1,5 @@ org.gradle.jvmargs=-Xmx1536M android.useAndroidX=true android.enableJetifier=true -app.versionName=1.2.29 -app.versionCode=35 +app.versionName=1.2.30 +app.versionCode=36 diff --git a/assets/translations/en.json b/assets/translations/en.json index 42ca82760c02ee4dfb2a118e5147f15875ad76f7..f35b5176c6ba7342e375764aeca807a23805682c 100644 --- a/assets/translations/en.json +++ b/assets/translations/en.json @@ -6,6 +6,7 @@ "bottom_nav_about": "About", "settings_title": "Settings", + "settings_label_theme":"Theme mode", "settings_label_timer_value":"Game turn allowed time", "about_title": "Informations", diff --git a/assets/translations/fr.json b/assets/translations/fr.json index d953c429bb3b25ba086ce5f855f1931c22320866..6ab46bc21015d3cf15a0f3e07444aaa78ca7b0d8 100644 --- a/assets/translations/fr.json +++ b/assets/translations/fr.json @@ -6,6 +6,7 @@ "bottom_nav_about": "Infos", "settings_title": "Réglages", + "settings_label_theme":"Thème de couleurs", "settings_label_timer_value":"Durée du tour de jeu", "about_title": "Informations", diff --git a/fastlane/metadata/android/en-US/changelogs/36.txt b/fastlane/metadata/android/en-US/changelogs/36.txt new file mode 100644 index 0000000000000000000000000000000000000000..e466561363a0fabd2043c6d7903c4280d6b7b3a8 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/36.txt @@ -0,0 +1 @@ +Add light/dark theme setting. diff --git a/fastlane/metadata/android/fr-FR/changelogs/36.txt b/fastlane/metadata/android/fr-FR/changelogs/36.txt new file mode 100644 index 0000000000000000000000000000000000000000..4a93af73582a415da90a3a845509c88ff0682057 --- /dev/null +++ b/fastlane/metadata/android/fr-FR/changelogs/36.txt @@ -0,0 +1 @@ +Ajout d'un réglage de thème clair/sombre. diff --git a/lib/cubit/theme_cubit.dart b/lib/cubit/theme_cubit.dart new file mode 100644 index 0000000000000000000000000000000000000000..b793e895dbb0c672d451cd403e0036c3d9ac9b42 --- /dev/null +++ b/lib/cubit/theme_cubit.dart @@ -0,0 +1,31 @@ +import 'package:equatable/equatable.dart'; +import 'package:flutter/material.dart'; +import 'package:hydrated_bloc/hydrated_bloc.dart'; + +part 'theme_state.dart'; + +class ThemeCubit extends HydratedCubit<ThemeModeState> { + ThemeCubit() : super(const ThemeModeState()); + + void getTheme(ThemeModeState state) { + emit(state); + } + + @override + ThemeModeState? fromJson(Map<String, dynamic> json) { + switch (json['themeMode']) { + case 'ThemeMode.dark': + return const ThemeModeState(themeMode: ThemeMode.dark); + case 'ThemeMode.light': + return const ThemeModeState(themeMode: ThemeMode.light); + case 'ThemeMode.system': + default: + return const ThemeModeState(themeMode: ThemeMode.system); + } + } + + @override + Map<String, String>? toJson(ThemeModeState state) { + return <String, String>{'themeMode': state.themeMode.toString()}; + } +} diff --git a/lib/cubit/theme_state.dart b/lib/cubit/theme_state.dart new file mode 100644 index 0000000000000000000000000000000000000000..e479a50f12fe72a35a1fd1722ff72afbb692a136 --- /dev/null +++ b/lib/cubit/theme_state.dart @@ -0,0 +1,15 @@ +part of 'theme_cubit.dart'; + +@immutable +class ThemeModeState extends Equatable { + const ThemeModeState({ + this.themeMode, + }); + + final ThemeMode? themeMode; + + @override + List<Object?> get props => <Object?>[ + themeMode, + ]; +} diff --git a/lib/main.dart b/lib/main.dart index b90609c0fa03bf7963ee98aabd965f253995dc05..462abf004e0928dbe200e87b7b187e560660ed48 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -6,6 +6,7 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:hive/hive.dart'; import 'package:hydrated_bloc/hydrated_bloc.dart'; import 'package:path_provider/path_provider.dart'; +import 'package:petitbac/cubit/theme_cubit.dart'; import 'package:provider/provider.dart'; import 'package:petitbac/config/theme.dart'; @@ -49,23 +50,29 @@ class MyApp extends StatelessWidget { BlocProvider<BottomNavCubit>(create: (context) => BottomNavCubit()), BlocProvider<GameCubit>(create: (context) => GameCubit()), BlocProvider<SettingsCubit>(create: (context) => SettingsCubit()), + BlocProvider<ThemeCubit>(create: (context) => ThemeCubit()), ], - child: ChangeNotifierProvider( - create: (BuildContext context) => Data(), - child: Consumer<Data>( - builder: (context, data, child) { - return MaterialApp( - title: 'Petit Bac', - theme: appTheme, - home: const SkeletonScreen(), - localizationsDelegates: context.localizationDelegates, - supportedLocales: context.supportedLocales, - locale: context.locale, - debugShowCheckedModeBanner: false, - ); - }, - ), - ), + child: BlocBuilder<ThemeCubit, ThemeModeState>( + builder: (BuildContext context, ThemeModeState state) { + return ChangeNotifierProvider( + create: (BuildContext context) => Data(), + child: Consumer<Data>( + builder: (context, data, child) { + return MaterialApp( + title: 'Petit Bac', + theme: lightTheme, + darkTheme: darkTheme, + themeMode: state.themeMode, + home: const SkeletonScreen(), + localizationsDelegates: context.localizationDelegates, + supportedLocales: context.supportedLocales, + locale: context.locale, + debugShowCheckedModeBanner: false, + ); + }, + ), + ); + }), ); } } diff --git a/lib/ui/widgets/settings_form.dart b/lib/ui/widgets/settings_form.dart index 431c9f1b6ae126d7a1699c0956a22216d31783e6..6251f79e1eded14fcdba7291e5713e1cee4f4931 100644 --- a/lib/ui/widgets/settings_form.dart +++ b/lib/ui/widgets/settings_form.dart @@ -4,6 +4,8 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:petitbac/config/default_settings.dart'; import 'package:petitbac/cubit/settings_cubit.dart'; +import 'package:petitbac/ui/widgets/theme_card.dart'; +import 'package:unicons/unicons.dart'; class SettingsForm extends StatefulWidget { const SettingsForm({super.key}); @@ -47,6 +49,35 @@ class _SettingsFormState extends State<SettingsForm> { crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.max, children: <Widget>[ + // Light/dark theme + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.center, + children: <Widget>[ + const Text('settings_label_theme').tr(), + const Row( + mainAxisAlignment: MainAxisAlignment.end, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + ThemeCard( + mode: ThemeMode.system, + icon: UniconsLine.cog, + ), + ThemeCard( + mode: ThemeMode.light, + icon: UniconsLine.sun, + ), + ThemeCard( + mode: ThemeMode.dark, + icon: UniconsLine.moon, + ) + ], + ), + ], + ), + + const SizedBox(height: 16), + // Timer value Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, diff --git a/lib/ui/widgets/theme_card.dart b/lib/ui/widgets/theme_card.dart new file mode 100644 index 0000000000000000000000000000000000000000..dd9970868b8a36ee0ea017e22e5103773597a6cd --- /dev/null +++ b/lib/ui/widgets/theme_card.dart @@ -0,0 +1,45 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +import 'package:petitbac/cubit/theme_cubit.dart'; + +class ThemeCard extends StatelessWidget { + const ThemeCard({ + super.key, + required this.mode, + required this.icon, + }); + + final IconData icon; + final ThemeMode mode; + + @override + Widget build(BuildContext context) { + return BlocBuilder<ThemeCubit, ThemeModeState>( + builder: (BuildContext context, ThemeModeState state) { + return Card( + elevation: 2, + shadowColor: Theme.of(context).colorScheme.shadow, + color: state.themeMode == mode + ? Theme.of(context).colorScheme.primary + : Theme.of(context).colorScheme.surface, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(12)), + ), + margin: const EdgeInsets.all(5), + child: InkWell( + onTap: () => BlocProvider.of<ThemeCubit>(context).getTheme( + ThemeModeState(themeMode: mode), + ), + borderRadius: const BorderRadius.all(Radius.circular(12)), + child: Icon( + icon, + size: 32, + color: + state.themeMode != mode ? Theme.of(context).colorScheme.primary : Colors.white, + ), + ), + ); + }); + } +} diff --git a/pubspec.yaml b/pubspec.yaml index 540b2ae38963714d9183c5d11d3eff88b5c64c8b..45c8369c7f5369fc66e6f1b558759df333ec4e63 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: petitbac description: A PetitBac game application. publish_to: 'none' -version: 1.2.29+35 +version: 1.2.30+36 environment: sdk: '^3.0.0'