From ecfe71cfa9e2be707b2ec3cfa2b4d3e376043c34 Mon Sep 17 00:00:00 2001 From: Myzel394 <50424412+Myzel394@users.noreply.github.com> Date: Thu, 25 Aug 2022 10:37:35 +0200 Subject: [PATCH] added record button behavior to settings --- .../record_button_behavior/texts.dart | 15 ++ lib/enums/record_button_behavior.dart | 4 + lib/locale/l10n/app_en.arb | 6 +- lib/models/settings.dart | 30 +++- lib/screens/settings_screen.dart | 75 +++----- .../settings_screen/dropdown_tile.dart | 168 ++++++++++++++++++ 6 files changed, 244 insertions(+), 54 deletions(-) create mode 100644 lib/enum_mapping/record_button_behavior/texts.dart create mode 100644 lib/enums/record_button_behavior.dart create mode 100644 lib/screens/settings_screen/dropdown_tile.dart diff --git a/lib/enum_mapping/record_button_behavior/texts.dart b/lib/enum_mapping/record_button_behavior/texts.dart new file mode 100644 index 0000000..8204a90 --- /dev/null +++ b/lib/enum_mapping/record_button_behavior/texts.dart @@ -0,0 +1,15 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:quid_faciam_hodie/enums/record_button_behavior.dart'; + +Map getRecordButtonBehaviorTextMapping( + final BuildContext context) { + final localizations = AppLocalizations.of(context)!; + + return { + RecordButtonBehavior.holdRecording: + localizations.enumMapping_RecordButtonBehavior_holdRecording, + RecordButtonBehavior.switchRecording: + localizations.enumMapping_RecordButtonBehavior_switchRecording, + }; +} diff --git a/lib/enums/record_button_behavior.dart b/lib/enums/record_button_behavior.dart new file mode 100644 index 0000000..ea98a0f --- /dev/null +++ b/lib/enums/record_button_behavior.dart @@ -0,0 +1,4 @@ +enum RecordButtonBehavior { + holdRecording, + switchRecording, +} diff --git a/lib/locale/l10n/app_en.arb b/lib/locale/l10n/app_en.arb index 52ef6c6..fccb07b 100644 --- a/lib/locale/l10n/app_en.arb +++ b/lib/locale/l10n/app_en.arb @@ -159,6 +159,7 @@ "settingsScreenDeleteAccountConfirmLabel": "Delete Account now", "settingsScreenGeneralSectionTitle": "General", "settingsScreenGeneralSectionQualityLabel": "Quality", + "settingsScreenGeneralSectionRecordButtonBehaviorLabel": "Record Behavior", "settingsScreenGeneralSectionAskForMemoryAnnotationsLabel": "Ask for memory annotations", "settingsScreenGeneralSectionStartRecordingOnStartupLabel": "Automatically start recording on startup", "settingsScreenResetHelpSheetsLabel": "Reset Help Sheets", @@ -194,5 +195,8 @@ "enumMapping_ResolutionPreset_high": "High", "enumMapping_ResolutionPreset_veryHigh": "Very High", "enumMapping_ResolutionPreset_ultraHigh": "Ultra High", - "enumMapping_ResolutionPreset_max": "Max" + "enumMapping_ResolutionPreset_max": "Max", + + "enumMapping_RecordButtonBehavior_holdRecording": "Hold to record", + "enumMapping_RecordButtonBehavior_switchRecording": "Tap to start recording, tap again to stop " } \ No newline at end of file diff --git a/lib/models/settings.dart b/lib/models/settings.dart index 3020ba8..bd530ea 100644 --- a/lib/models/settings.dart +++ b/lib/models/settings.dart @@ -5,29 +5,37 @@ import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:quid_faciam_hodie/constants/storage_keys.dart'; +import 'package:quid_faciam_hodie/enums/record_button_behavior.dart'; import 'package:quid_faciam_hodie/utils/string_to_bool.dart'; const secure = FlutterSecureStorage(); class Settings extends ChangeNotifier { ResolutionPreset _resolution = ResolutionPreset.max; + RecordButtonBehavior _recordButtonBehavior = + RecordButtonBehavior.holdRecording; bool _askForMemoryAnnotations = false; bool _recordOnStartup = false; - Settings( - {final ResolutionPreset? resolution, - final bool? askForMemoryAnnotations, - final bool? recordOnStartup}) - : _resolution = resolution ?? ResolutionPreset.max, + Settings({ + final ResolutionPreset? resolution, + final RecordButtonBehavior? recordButtonBehavior, + final bool? askForMemoryAnnotations, + final bool? recordOnStartup, + }) : _resolution = resolution ?? ResolutionPreset.max, _askForMemoryAnnotations = askForMemoryAnnotations ?? true, - _recordOnStartup = recordOnStartup ?? false; + _recordOnStartup = recordOnStartup ?? false, + _recordButtonBehavior = + recordButtonBehavior ?? RecordButtonBehavior.holdRecording; ResolutionPreset get resolution => _resolution; + RecordButtonBehavior get recordButtonBehavior => _recordButtonBehavior; bool get askForMemoryAnnotations => _askForMemoryAnnotations; bool get recordOnStartup => _recordOnStartup; Map toJSONData() => { 'resolution': _resolution.toString(), + 'recordButtonBehavior': _recordButtonBehavior.toString(), 'askForMemoryAnnotations': _askForMemoryAnnotations ? 'true' : 'false', 'recordOnStartup': _recordOnStartup ? 'true' : 'false', }; @@ -52,6 +60,9 @@ class Settings extends ChangeNotifier { final resolution = ResolutionPreset.values.firstWhereOrNull( (preset) => preset.toString() == data['resolution'], ); + final recordButtonBehavior = RecordButtonBehavior.values.firstWhereOrNull( + (preset) => preset.toString() == data['recordButtonBehavior'], + ); final askForMemoryAnnotations = stringToBool(data['askForMemoryAnnotations']); final recordOnStartup = stringToBool(data['recordOnStartup']); @@ -60,6 +71,7 @@ class Settings extends ChangeNotifier { resolution: resolution, askForMemoryAnnotations: askForMemoryAnnotations, recordOnStartup: recordOnStartup, + recordButtonBehavior: recordButtonBehavior, ); } @@ -69,6 +81,12 @@ class Settings extends ChangeNotifier { save(); } + void setRecordButtonBehavior(final RecordButtonBehavior behavior) { + _recordButtonBehavior = behavior; + notifyListeners(); + save(); + } + void setAskForMemoryAnnotations(final bool askForMemoryAnnotations) { _askForMemoryAnnotations = askForMemoryAnnotations; notifyListeners(); diff --git a/lib/screens/settings_screen.dart b/lib/screens/settings_screen.dart index 0c6003e..e32ef4b 100644 --- a/lib/screens/settings_screen.dart +++ b/lib/screens/settings_screen.dart @@ -7,7 +7,9 @@ import 'package:flutter_platform_widgets/flutter_platform_widgets.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:intl/intl.dart'; import 'package:quid_faciam_hodie/constants/spacing.dart'; +import 'package:quid_faciam_hodie/enum_mapping/record_button_behavior/texts.dart'; import 'package:quid_faciam_hodie/enum_mapping/resolution_preset/texts.dart'; +import 'package:quid_faciam_hodie/enums/record_button_behavior.dart'; import 'package:quid_faciam_hodie/extensions/snackbar.dart'; import 'package:quid_faciam_hodie/managers/global_values_manager.dart'; import 'package:quid_faciam_hodie/managers/user_help_sheets_manager.dart'; @@ -15,10 +17,11 @@ import 'package:quid_faciam_hodie/screens/welcome_screen.dart'; import 'package:quid_faciam_hodie/utils/auth_required.dart'; import 'package:quid_faciam_hodie/utils/loadable.dart'; import 'package:quid_faciam_hodie/utils/theme.dart'; -import 'package:quid_faciam_hodie/widgets/cupertino_dropdown.dart'; import 'package:settings_ui/settings_ui.dart'; import 'package:supabase_flutter/supabase_flutter.dart'; +import 'settings_screen/dropdown_tile.dart'; + final supabase = Supabase.instance.client; const storage = FlutterSecureStorage(); @@ -84,46 +87,6 @@ class _SettingsScreenState extends AuthRequiredState ); } - Widget getQualityPicker() { - final settings = GlobalValuesManager.settings!; - final resolutionTextMapping = getResolutionTextMapping(context); - final items = ResolutionPreset.values - .map( - (value) => DropdownMenuItem( - value: value, - child: Text(resolutionTextMapping[value]!), - ), - ) - .toList(); - - if (isMaterial(context)) { - return DropdownButtonFormField( - value: settings.resolution, - onChanged: (value) { - if (value == null) { - return; - } - - settings.setResolution(value); - }, - items: items, - ); - } else { - return CupertinoDropdownButton( - itemExtent: 30, - onChanged: (value) { - if (value == null) { - return; - } - - settings.setResolution(value); - }, - value: settings.resolution, - items: items, - ); - } - } - @override Widget build(BuildContext context) { final settings = GlobalValuesManager.settings!; @@ -202,13 +165,29 @@ class _SettingsScreenState extends AuthRequiredState title: Text( localizations.settingsScreenGeneralSectionTitle, ), - tiles: [ - SettingsTile( - leading: Text( + tiles: [ + SettingsDropdownTile( + leading: const Icon(Icons.high_quality), + title: Text( localizations .settingsScreenGeneralSectionQualityLabel, ), - title: getQualityPicker(), + onUpdate: settings.setResolution, + textMapping: getResolutionTextMapping(context), + value: settings.resolution, + values: ResolutionPreset.values, + ), + SettingsDropdownTile( + leading: const Icon(Icons.fiber_manual_record), + title: Text( + localizations + .settingsScreenGeneralSectionRecordButtonBehaviorLabel, + ), + onUpdate: settings.setRecordButtonBehavior, + textMapping: + getRecordButtonBehaviorTextMapping(context), + value: settings.recordButtonBehavior, + values: RecordButtonBehavior.values, ), SettingsTile.switchTile( initialValue: settings.askForMemoryAnnotations, @@ -221,8 +200,10 @@ class _SettingsScreenState extends AuthRequiredState SettingsTile.switchTile( initialValue: settings.recordOnStartup, onToggle: settings.setRecordOnStartup, - title: Text(localizations - .settingsScreenGeneralSectionStartRecordingOnStartupLabel), + title: Text( + localizations + .settingsScreenGeneralSectionStartRecordingOnStartupLabel, + ), ), SettingsTile( leading: Icon(context.platformIcons.help), diff --git a/lib/screens/settings_screen/dropdown_tile.dart b/lib/screens/settings_screen/dropdown_tile.dart new file mode 100644 index 0000000..15653c1 --- /dev/null +++ b/lib/screens/settings_screen/dropdown_tile.dart @@ -0,0 +1,168 @@ +import 'package:flutter/material.dart'; +import 'package:settings_ui/settings_ui.dart'; + +const IN_DURATION = Duration(seconds: 1); +const OUT_DURATION = Duration(milliseconds: 300); + +class DropdownTile extends StatefulWidget { + final Widget title; + final Iterable values; + final dynamic value; + final Map textMapping; + final void Function(dynamic newValue) onUpdate; + + final bool enabled; + final Widget? leading; + final Widget? description; + + const DropdownTile({ + Key? key, + required this.title, + required this.values, + required this.value, + required this.textMapping, + required this.onUpdate, + this.enabled = true, + this.leading, + this.description, + }) : super(key: key); + + @override + State createState() => _DropdownTileState(); +} + +class _DropdownTileState extends State + with TickerProviderStateMixin { + late final AnimationController controller; + late final Animation animation; + + bool get isExpanding => + animation.status == AnimationStatus.forward || + animation.status == AnimationStatus.completed; + + @override + void initState() { + super.initState(); + + controller = AnimationController( + duration: IN_DURATION, + vsync: this, + ); + animation = CurvedAnimation( + parent: controller, + curve: Curves.fastLinearToSlowEaseIn, + ); + } + + expand() { + controller.forward(); + } + + contract() { + controller.animateBack( + 0.0, + duration: OUT_DURATION, + curve: Curves.decelerate, + ); + } + + toggleContainer() { + if (isExpanding) { + contract(); + } else { + expand(); + } + + setState(() {}); + } + + @override + void dispose() { + controller.dispose(); + + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Column( + children: [ + SettingsTile( + leading: widget.leading, + description: widget.description, + enabled: widget.enabled, + title: widget.title, + value: Text(widget.textMapping[widget.value]!), + trailing: AnimatedRotation( + duration: kThemeChangeDuration, + turns: isExpanding ? .5 : 0, + child: const Icon(Icons.arrow_drop_down), + ), + onPressed: (_) => toggleContainer(), + ), + SizeTransition( + sizeFactor: animation, + axis: Axis.vertical, + child: Column( + children: widget.values + .map( + (value) => RadioListTile( + title: Text(widget.textMapping[value]!), + value: value, + groupValue: widget.value, + onChanged: (value) { + if (value == null) { + return; + } + + widget.onUpdate(value); + + contract(); + }, + ), + ) + .toList(), + ), + ), + ], + ); + } +} + +class SettingsDropdownTile extends AbstractSettingsTile { + final Widget title; + final Iterable values; + final T value; + final Map textMapping; + final void Function(T newValue) onUpdate; + + final bool enabled; + final Widget? leading; + final Widget? description; + + const SettingsDropdownTile({ + Key? key, + required this.title, + required this.values, + required this.value, + required this.textMapping, + required this.onUpdate, + this.enabled = true, + this.leading, + this.description, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return DropdownTile( + title: title, + values: values, + value: value, + textMapping: textMapping, + onUpdate: (value) => onUpdate(value as T), + enabled: enabled, + leading: leading, + description: description, + ); + } +}