diff --git a/android/gradle.properties b/android/gradle.properties index 6bf54a6ed821c19f76d860d4a24e7c85d440b575..f0be9fb67d6fe0b36ce90df03ff2f3f1551d738c 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=0.0.10 -app.versionCode=10 +app.versionName=0.0.11 +app.versionCode=11 diff --git a/assets/translations/en.json b/assets/translations/en.json index 655cd96fa7ee3282acb235d37e4eee28ca8a8580..435402a46f0aaaede5093f8f4ce57dc90aa9400f 100644 --- a/assets/translations/en.json +++ b/assets/translations/en.json @@ -2,6 +2,11 @@ "app_name": "Twister", "bottom_nav_game": "Game", + "bottom_nav_settings": "Settings", + + "settings_title": "Settings", + "settings_title_game": "Game settings", + "settings_label_game_timer_value": "Timer value: ", "lang_prefix": "en" } diff --git a/assets/translations/fr.json b/assets/translations/fr.json index c7fb863f774d66cdc73203db8d321d86e8e351f9..45fb89746475f43c800ee5a590983273327fd2bc 100644 --- a/assets/translations/fr.json +++ b/assets/translations/fr.json @@ -2,6 +2,11 @@ "app_name": "Twister", "bottom_nav_game": "Jeu", + "bottom_nav_settings": "Réglages", + + "settings_title": "Réglages", + "settings_title_game": "Paramètres du jeu", + "settings_label_game_timer_value": "Durée du chrono : ", "lang_prefix": "fr" } diff --git a/fastlane/metadata/android/en-US/changelogs/11.txt b/fastlane/metadata/android/en-US/changelogs/11.txt new file mode 100644 index 0000000000000000000000000000000000000000..e88f51900f1ac8bcc66d5f48134cf5d9f510da6c --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/11.txt @@ -0,0 +1 @@ +Add (minimal) application settings page. diff --git a/fastlane/metadata/android/fr-FR/changelogs/11.txt b/fastlane/metadata/android/fr-FR/changelogs/11.txt new file mode 100644 index 0000000000000000000000000000000000000000..0a44797f6980ab6ae8e62df25c506dfdb362f093 --- /dev/null +++ b/fastlane/metadata/android/fr-FR/changelogs/11.txt @@ -0,0 +1 @@ +Ajout d'une page (minimale) de paramétrage de l'application. diff --git a/lib/config/default_settings.dart b/lib/config/default_settings.dart new file mode 100644 index 0000000000000000000000000000000000000000..c3271480d414643f6c75e0b3d2cb283596c57b6f --- /dev/null +++ b/lib/config/default_settings.dart @@ -0,0 +1,9 @@ +class DefaultSettings { + static const int defaultTimerValue = 20; + + static const List<int> allowedTimerValues = [ + 10, + defaultTimerValue, + 30, + ]; +} diff --git a/lib/cubit/settings_cubit.dart b/lib/cubit/settings_cubit.dart new file mode 100644 index 0000000000000000000000000000000000000000..200abf9d0734a0ea58fdda0c87207677e54c64c9 --- /dev/null +++ b/lib/cubit/settings_cubit.dart @@ -0,0 +1,39 @@ +import 'package:equatable/equatable.dart'; +import 'package:flutter/material.dart'; +import 'package:hydrated_bloc/hydrated_bloc.dart'; + +import 'package:twister/config/default_settings.dart'; + +part 'settings_state.dart'; + +class SettingsCubit extends HydratedCubit<SettingsState> { + SettingsCubit() : super(const SettingsState()); + + int getTimerValue() { + return state.timerValue ?? DefaultSettings.defaultTimerValue; + } + + void setValues({ + int? timerValue, + }) { + emit(SettingsState( + timerValue: timerValue ?? state.timerValue, + )); + } + + @override + SettingsState? fromJson(Map<String, dynamic> json) { + int timerValue = json['timerValue'] as int; + + return SettingsState( + timerValue: timerValue, + ); + } + + @override + Map<String, dynamic>? toJson(SettingsState state) { + return <String, dynamic>{ + 'timerValue': state.timerValue ?? DefaultSettings.defaultTimerValue, + }; + } +} diff --git a/lib/cubit/settings_state.dart b/lib/cubit/settings_state.dart new file mode 100644 index 0000000000000000000000000000000000000000..381163143e113aad95ce32baff1ae66f3a5c3338 --- /dev/null +++ b/lib/cubit/settings_state.dart @@ -0,0 +1,19 @@ +part of 'settings_cubit.dart'; + +@immutable +class SettingsState extends Equatable { + const SettingsState({ + this.timerValue, + }); + + final int? timerValue; + + @override + List<dynamic> get props => <dynamic>[ + timerValue, + ]; + + Map<String, dynamic> get values => <String, dynamic>{ + 'discoveriesDaysCount': timerValue, + }; +} diff --git a/lib/main.dart b/lib/main.dart index 4d188e4b5d0abf06e30e991143d1fd38d710c110..d30fd3e910b5cf65647fc12c6a7a2d1dd03788a1 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -9,6 +9,7 @@ import 'package:path_provider/path_provider.dart'; import 'package:twister/config/theme.dart'; import 'package:twister/cubit/bottom_nav_cubit.dart'; +import 'package:twister/cubit/settings_cubit.dart'; import 'package:twister/ui/skeleton.dart'; void main() async { @@ -43,6 +44,7 @@ class MyApp extends StatelessWidget { return MultiBlocProvider( providers: [ BlocProvider<BottomNavCubit>(create: (context) => BottomNavCubit()), + BlocProvider<SettingsCubit>(create: (context) => SettingsCubit()), ], child: MaterialApp( title: 'Twister', diff --git a/lib/ui/screens/settings.dart b/lib/ui/screens/settings.dart new file mode 100644 index 0000000000000000000000000000000000000000..6b21d25b979c94c261685034e9cf78a9a35b7228 --- /dev/null +++ b/lib/ui/screens/settings.dart @@ -0,0 +1,29 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; + +import 'package:twister/ui/widgets/app_titles.dart'; +import 'package:twister/ui/widgets/settings_form.dart'; +import 'package:unicons/unicons.dart'; + +class ScreenSettings extends StatelessWidget { + const ScreenSettings({super.key}); + + static Icon navBarIcon = const Icon(UniconsLine.setting); + static String navBarText = 'bottom_nav_settings'; + + @override + Widget build(BuildContext context) { + return Material( + color: Theme.of(context).colorScheme.background, + child: ListView( + padding: const EdgeInsets.symmetric(horizontal: 4), + physics: const BouncingScrollPhysics(), + children: <Widget>[ + SizedBox(height: 8), + AppTitle1(text: tr('settings_title')), + SettingsForm(), + ], + ), + ); + } +} diff --git a/lib/ui/skeleton.dart b/lib/ui/skeleton.dart index 4d56b2330306d3fed579f2963c5a7abcb6081624..ca33599bd3323d162f8c492a9d8baa42f0639623 100644 --- a/lib/ui/skeleton.dart +++ b/lib/ui/skeleton.dart @@ -3,6 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:twister/cubit/bottom_nav_cubit.dart'; import 'package:twister/ui/screens/home.dart'; +import 'package:twister/ui/screens/settings.dart'; import 'package:twister/ui/widgets/app_bar.dart'; import 'package:twister/ui/widgets/bottom_nav_bar.dart'; @@ -18,7 +19,7 @@ class _SkeletonScreenState extends State<SkeletonScreen> { Widget build(BuildContext context) { List<Widget> pageNavigation = <Widget>[ const ScreenHome(), - const ScreenHome(), + const ScreenSettings(), ]; return Scaffold( diff --git a/lib/ui/widgets/bottom_nav_bar.dart b/lib/ui/widgets/bottom_nav_bar.dart index 5181bb9d3b09cf5ea9e1f67fdafe1376e503097a..24e9a838033600975936ce691d5368be7ec999f5 100644 --- a/lib/ui/widgets/bottom_nav_bar.dart +++ b/lib/ui/widgets/bottom_nav_bar.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:twister/cubit/bottom_nav_cubit.dart'; +import 'package:twister/ui/screens/settings.dart'; import 'package:twister/ui/screens/home.dart'; class BottomNavBar extends StatelessWidget { @@ -36,8 +37,8 @@ class BottomNavBar extends StatelessWidget { label: tr(ScreenHome.navBarText), ), BottomNavigationBarItem( - icon: ScreenHome.navBarIcon, - label: tr(ScreenHome.navBarText), + icon: ScreenSettings.navBarIcon, + label: tr(ScreenSettings.navBarText), ), ], ); diff --git a/lib/ui/widgets/settings_form.dart b/lib/ui/widgets/settings_form.dart new file mode 100644 index 0000000000000000000000000000000000000000..fc668fe378bc543689725c15cdf356c0e28fb637 --- /dev/null +++ b/lib/ui/widgets/settings_form.dart @@ -0,0 +1,81 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +import 'package:twister/config/default_settings.dart'; +import 'package:twister/cubit/settings_cubit.dart'; +import 'package:twister/ui/widgets/app_titles.dart'; + +class SettingsForm extends StatefulWidget { + const SettingsForm({super.key}); + + @override + State<SettingsForm> createState() => _SettingsFormState(); +} + +class _SettingsFormState extends State<SettingsForm> { + int timerValue = DefaultSettings.defaultTimerValue; + + List<bool> _selectedTimerValue = []; + + @override + void didChangeDependencies() { + SettingsCubit settings = BlocProvider.of<SettingsCubit>(context); + + timerValue = settings.getTimerValue(); + + _selectedTimerValue = + DefaultSettings.allowedTimerValues.map((e) => (e == timerValue)).toList(); + + super.didChangeDependencies(); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + void saveSettings() { + BlocProvider.of<SettingsCubit>(context).setValues( + timerValue: timerValue, + ); + } + + return Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: <Widget>[ + SizedBox(height: 8), + AppTitle2(text: tr('settings_title_game')), + + // Timer value + Row( + mainAxisAlignment: MainAxisAlignment.end, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text('settings_label_game_timer_value').tr(), + ToggleButtons( + onPressed: (int index) { + setState(() { + timerValue = DefaultSettings.allowedTimerValues[index]; + for (int i = 0; i < _selectedTimerValue.length; i++) { + _selectedTimerValue[i] = i == index; + } + }); + saveSettings(); + }, + borderRadius: const BorderRadius.all(Radius.circular(8)), + constraints: const BoxConstraints(minHeight: 30.0, minWidth: 30.0), + isSelected: _selectedTimerValue, + children: + DefaultSettings.allowedTimerValues.map((e) => Text(e.toString())).toList(), + ), + ], + ), + ], + ); + } +} diff --git a/pubspec.yaml b/pubspec.yaml index 9b820cb51cd529829f84fa142a1b927c5108f810..ac2c2480d0731192995c89dcfde7f84dc605def9 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -3,7 +3,7 @@ description: twister game companion publish_to: 'none' -version: 0.0.10+10 +version: 0.0.11+11 environment: sdk: '^3.0.0'