diff --git a/lib/alarm/data/alarm_app_settings_schema.dart b/lib/alarm/data/alarm_app_settings_schema.dart index eaf9076a..46214132 100644 --- a/lib/alarm/data/alarm_app_settings_schema.dart +++ b/lib/alarm/data/alarm_app_settings_schema.dart @@ -1,5 +1,6 @@ import 'package:clock_app/alarm/data/alarm_settings_schema.dart'; import 'package:clock_app/alarm/types/notification_action.dart'; +import 'package:clock_app/common/types/list_filter.dart'; import 'package:clock_app/icons/flux_icons.dart'; import 'package:clock_app/notifications/widgets/notification_actions/area_notification_action.dart'; import 'package:clock_app/notifications/widgets/notification_actions/buttons_notification_action.dart'; @@ -73,6 +74,30 @@ SettingGroup alarmAppSettingsSchema = SettingGroup( ]), SettingGroup("Filters", (context) => AppLocalizations.of(context)!.filtersSettingGroup, [ + // CustomizableListSetting( + // "Tasks", + // (context) => AppLocalizations.of(context)!.tasksSetting, + // [], + // // kDebugMode + // // ? [AlarmTask(AlarmTaskType.math), AlarmTask(AlarmTaskType.sequence)] + // // : [], + // alarmTaskSchemasMap.keys.map((key) => AlarmTask(key)).toList(), + // addCardBuilder: (item) => AlarmTaskCard(task: item, isAddCard: true), + // cardBuilder: (item, [onDelete, onDuplicate]) => AlarmTaskCard( + // task: item, + // isAddCard: false, + // onPressDelete: onDelete, + // onPressDuplicate: onDuplicate, + // ), + // valueDisplayBuilder: (context, setting) { + // return Text("${setting.value.length} tasks"); + // }, + // itemPreviewBuilder: (item) => TryAlarmTaskButton(alarmTask: item), + // // onChange: (context, value)async{ + // // await appSettings.save(); + // // } + // ), + SwitchSetting("Show Filters", (context) => AppLocalizations.of(context)!.showFiltersSetting, true), SwitchSetting("Show Sort", diff --git a/lib/alarm/data/alarm_settings_schema.dart b/lib/alarm/data/alarm_settings_schema.dart index ed64315e..ffb055b5 100644 --- a/lib/alarm/data/alarm_settings_schema.dart +++ b/lib/alarm/data/alarm_settings_schema.dart @@ -10,6 +10,7 @@ import 'package:clock_app/alarm/types/schedules/weekly_alarm_schedule.dart'; import 'package:clock_app/alarm/widgets/alarm_task_card.dart'; import 'package:clock_app/alarm/widgets/try_alarm_task_button.dart'; import 'package:clock_app/audio/audio_channels.dart'; +import 'package:clock_app/audio/screens/ringtones_screen.dart'; import 'package:clock_app/audio/types/ringtone_player.dart'; import 'package:clock_app/common/data/weekdays.dart'; import 'package:clock_app/common/logic/tags.dart'; @@ -19,13 +20,11 @@ import 'package:clock_app/common/types/tag.dart'; import 'package:clock_app/common/types/weekday.dart'; import 'package:clock_app/common/utils/ringtones.dart'; import 'package:clock_app/settings/data/settings_schema.dart'; -import 'package:clock_app/settings/screens/ringtones_screen.dart'; import 'package:clock_app/settings/screens/tags_screen.dart'; import 'package:clock_app/settings/types/setting.dart'; import 'package:clock_app/settings/types/setting_enable_condition.dart'; import 'package:clock_app/settings/types/setting_group.dart'; import 'package:clock_app/timer/types/time_duration.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; @@ -78,20 +77,6 @@ SettingGroup alarmSettingsSchema = SettingGroup( ), ], ), - // DynamicToggleSetting( - // "Week Days", - // (context) => AppLocalizations.of(context)!.alarmWeekdaysSetting, - // () { - // return weekdays - // .map((weekday) => SelectSettingOption( - // (context) => weekday.getAbbreviation(context), weekday)) - // .toList(); - // }, - // enableConditions: [ - // ValueCondition(["Type"], (value) => value == WeeklyAlarmSchedule) - // ], - // ), - ToggleSetting( "Week Days", (context) => AppLocalizations.of(context)!.alarmWeekdaysSetting, @@ -195,14 +180,13 @@ SettingGroup alarmSettingsSchema = SettingGroup( ], // shouldCloseOnSelect: false, ), - SwitchSetting( + SwitchSetting( "start_melody_at_random_pos", (context) => AppLocalizations.of(context)!.startMelodyAtRandomPos, false, - getDescription: (context) => AppLocalizations.of(context)!.startMelodyAtRandomPosDescription, - + getDescription: (context) => AppLocalizations.of(context)! + .startMelodyAtRandomPosDescription, ), - SliderSetting( "Volume", (context) => AppLocalizations.of(context)!.volumeSetting, @@ -309,13 +293,13 @@ SettingGroup alarmSettingsSchema = SettingGroup( "Length", ], ), - ListSetting( + CustomizableListSetting( "Tasks", (context) => AppLocalizations.of(context)!.tasksSetting, [], // kDebugMode - // ? [AlarmTask(AlarmTaskType.math), AlarmTask(AlarmTaskType.sequence)] - // : [], + // ? [AlarmTask(AlarmTaskType.math), AlarmTask(AlarmTaskType.sequence)] + // : [], alarmTaskSchemasMap.keys.map((key) => AlarmTask(key)).toList(), addCardBuilder: (item) => AlarmTaskCard(task: item, isAddCard: true), cardBuilder: (item, [onDelete, onDuplicate]) => AlarmTaskCard( @@ -328,9 +312,6 @@ SettingGroup alarmSettingsSchema = SettingGroup( return Text("${setting.value.length} tasks"); }, itemPreviewBuilder: (item) => TryAlarmTaskButton(alarmTask: item), - // onChange: (context, value)async{ - // await appSettings.save(); - // } ), DynamicMultiSelectSetting( "Tags", diff --git a/lib/alarm/widgets/try_alarm_task_button.dart b/lib/alarm/widgets/try_alarm_task_button.dart index 6b9d0e06..3e2f461f 100644 --- a/lib/alarm/widgets/try_alarm_task_button.dart +++ b/lib/alarm/widgets/try_alarm_task_button.dart @@ -4,8 +4,7 @@ import 'package:clock_app/common/widgets/card_container.dart'; import 'package:flutter/material.dart'; class TryAlarmTaskButton extends StatelessWidget { - const TryAlarmTaskButton({Key? key, required this.alarmTask}) - : super(key: key); + const TryAlarmTaskButton({super.key, required this.alarmTask}); final AlarmTask alarmTask; diff --git a/lib/clock/screens/search_city_screen.dart b/lib/clock/screens/search_city_screen.dart index b5047ff0..47989b2f 100644 --- a/lib/clock/screens/search_city_screen.dart +++ b/lib/clock/screens/search_city_screen.dart @@ -68,19 +68,21 @@ class _SearchCityScreenState extends State { Widget build(BuildContext context) { return Scaffold( appBar: AppTopBar( - titleWidget: TextField( - autofocus: true, - controller: _filterController, - decoration: InputDecoration( - border: InputBorder.none, - focusedBorder: - const OutlineInputBorder(borderSide: BorderSide.none), - fillColor: Colors.transparent, - hintText: AppLocalizations.of(context)!.searchCityPlaceholder, - hintStyle: Theme.of(context).textTheme.bodyLarge, + titleWidget: Expanded( + child: TextField( + autofocus: true, + controller: _filterController, + decoration: InputDecoration( + border: InputBorder.none, + focusedBorder: + const OutlineInputBorder(borderSide: BorderSide.none), + fillColor: Colors.transparent, + hintText: AppLocalizations.of(context)!.searchCityPlaceholder, + hintStyle: Theme.of(context).textTheme.bodyLarge, + ), + textAlignVertical: TextAlignVertical.center, + style: Theme.of(context).textTheme.bodyLarge, ), - textAlignVertical: TextAlignVertical.center, - style: Theme.of(context).textTheme.bodyLarge, ), ), body: Padding( diff --git a/lib/common/types/list_filter.dart b/lib/common/types/list_filter.dart index d5dd69d7..f454136d 100644 --- a/lib/common/types/list_filter.dart +++ b/lib/common/types/list_filter.dart @@ -1,21 +1,21 @@ +import 'package:clock_app/common/types/json.dart'; import 'package:clock_app/common/types/list_item.dart'; import 'package:clock_app/common/utils/id.dart'; import 'package:clock_app/developer/logic/logger.dart'; +import 'package:clock_app/settings/types/setting_group.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; class ListSortOption { final String Function(BuildContext) getLocalizedName; - // final String abbreviation; final int Function(Item, Item) sortFunction; - String Function(BuildContext) get displayName => getLocalizedName; - - const ListSortOption( - this.getLocalizedName, this.sortFunction); + const ListSortOption(this.getLocalizedName, this.sortFunction); } abstract class ListFilterItem { + bool isEnabled = true; + bool Function(Item) get filterFunction; String Function(BuildContext) get displayName; bool get isActive; @@ -45,7 +45,6 @@ class ListFilter extends ListFilterItem { @override bool Function(Item) get filterFunction { - // print("Filtering $name $isSelected"); return isSelected ? _filterFunction : (Item item) => true; } @@ -64,6 +63,7 @@ class ListFilter extends ListFilterItem { class ListFilterSearch extends ListFilterItem { final String Function(BuildContext) getLocalizedName; String searchText = ''; + @override bool Function(Item) get filterFunction { // if (searchText.isEmpty) { diff --git a/lib/settings/data/general_settings_schema.dart b/lib/settings/data/general_settings_schema.dart index 7ac16d6b..d54245f0 100644 --- a/lib/settings/data/general_settings_schema.dart +++ b/lib/settings/data/general_settings_schema.dart @@ -3,6 +3,7 @@ import 'dart:io'; import 'package:app_settings/app_settings.dart'; import 'package:auto_start_flutter/auto_start_flutter.dart'; import 'package:clock_app/app.dart'; +import 'package:clock_app/audio/screens/ringtones_screen.dart'; import 'package:clock_app/clock/types/time.dart'; import 'package:clock_app/common/data/weekdays.dart'; import 'package:clock_app/common/types/weekday.dart'; @@ -12,7 +13,6 @@ import 'package:clock_app/common/utils/time_format.dart'; import 'package:clock_app/icons/flux_icons.dart'; import 'package:clock_app/l10n/language_local.dart'; import 'package:clock_app/notifications/logic/notifications.dart'; -import 'package:clock_app/settings/screens/ringtones_screen.dart'; import 'package:clock_app/settings/screens/tags_screen.dart'; import 'package:clock_app/settings/types/setting.dart'; import 'package:clock_app/settings/types/setting_action.dart'; diff --git a/lib/settings/logic/get_setting_widget.dart b/lib/settings/logic/get_setting_widget.dart index 78e32542..71ac63fc 100644 --- a/lib/settings/logic/get_setting_widget.dart +++ b/lib/settings/logic/get_setting_widget.dart @@ -184,7 +184,7 @@ Widget? getSettingItemWidget( setting: item, showAsCard: showAsCard, ); - } else if (item is ListSetting) { + } else if (item is CustomizableListSetting) { return ListSettingCard( setting: item, showAsCard: showAsCard, diff --git a/lib/settings/screens/list_filter_settings_screen.dart b/lib/settings/screens/list_filter_settings_screen.dart new file mode 100644 index 00000000..2d8cfb58 --- /dev/null +++ b/lib/settings/screens/list_filter_settings_screen.dart @@ -0,0 +1,67 @@ +import 'package:clock_app/common/types/tag.dart'; +import 'package:clock_app/common/widgets/fab.dart'; +import 'package:clock_app/common/widgets/fields/input_bottom_sheet.dart'; +import 'package:clock_app/common/widgets/list/persistent_list_view.dart'; +import 'package:clock_app/navigation/widgets/app_top_bar.dart'; +import 'package:clock_app/settings/widgets/tag_card.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + +class ListFilterSettingsScreen extends StatefulWidget { + const ListFilterSettingsScreen({ + super.key, + }); + + @override + State createState() => + _ListFilterSettingsScreenState(); +} + +class _ListFilterSettingsScreenState extends State { + final _listController = PersistentListController(); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppTopBar(title: AppLocalizations.of(context)!.tagsSetting), + body: Stack( + children: [ + Column( + children: [ + Expanded( + child: PersistentListView( + saveTag: 'tags', + listController: _listController, + itemBuilder: (tag) => TagCard( + key: ValueKey(tag), + tag: tag, + onPressDelete: () => _listController.deleteItem(tag), + onPressDuplicate: () => _listController.duplicateItem(tag), + ), + onTapItem: (tag, index) async { + Tag? newTag = await showTagEditor(tag); + if (newTag == null) return; + tag.copyFrom(newTag); + _listController.changeItems((tags) {}); + }, + // onDeleteItem: _handleDeleteTimer, + placeholderText: "No tags created", + reloadOnPop: true, + isSelectable: true, + ), + ), + ], + ), + FAB( + bottomPadding: 8, + onPressed: () async { + Tag? tag = await showTagEditor(); + if (tag == null) return; + _listController.addItem(tag); + }, + ) + ], + ), + ); + } +} diff --git a/lib/settings/screens/tags_screen.dart b/lib/settings/screens/tags_screen.dart index 4ff9d921..1173c84c 100644 --- a/lib/settings/screens/tags_screen.dart +++ b/lib/settings/screens/tags_screen.dart @@ -3,7 +3,6 @@ import 'package:clock_app/common/widgets/fab.dart'; import 'package:clock_app/common/widgets/fields/input_bottom_sheet.dart'; import 'package:clock_app/common/widgets/list/persistent_list_view.dart'; import 'package:clock_app/navigation/widgets/app_top_bar.dart'; -import 'package:clock_app/navigation/widgets/search_top_bar.dart'; import 'package:clock_app/settings/widgets/tag_card.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; diff --git a/lib/settings/types/setting.dart b/lib/settings/types/setting.dart index a699cf64..af975507 100644 --- a/lib/settings/types/setting.dart +++ b/lib/settings/types/setting.dart @@ -68,16 +68,16 @@ abstract class Setting extends SettingItem { } } -class ListSetting extends Setting> { +class CustomizableListSetting extends Setting> { List possibleItems; Widget Function(T item, [VoidCallback?, VoidCallback?]) cardBuilder; Widget Function(T item) addCardBuilder; Widget Function(T item)? itemPreviewBuilder; // The widget that will be used to display the value of this setting. - Widget Function(BuildContext context, ListSetting setting) + Widget Function(BuildContext context, CustomizableListSetting setting) valueDisplayBuilder; - ListSetting( + CustomizableListSetting( String name, String Function(BuildContext) getLocalizedName, List defaultValue, @@ -104,8 +104,8 @@ class ListSetting extends Setting> { ); @override - ListSetting copy() { - return ListSetting( + CustomizableListSetting copy() { + return CustomizableListSetting( name, getLocalizedName, _value, @@ -151,6 +151,78 @@ class ListSetting extends Setting> { } } +class ListSetting extends Setting> { + List possibleItems; + Widget Function(T item, [VoidCallback?, VoidCallback?]) cardBuilder; + Widget Function(T item) addCardBuilder; + // The widget that will be used to display the value of this setting. + + ListSetting( + String name, + String Function(BuildContext) getLocalizedName, + List defaultValue, + this.possibleItems, { + required this.cardBuilder, + required this.addCardBuilder, + String Function(BuildContext) getDescription = defaultDescription, + void Function(BuildContext, List)? onChange, + bool isVisual = true, + List enableConditions = const [], + List searchTags = const [], + }) : super( + name, + getLocalizedName, + getDescription, + copyItemList(defaultValue), + onChange, + enableConditions, + searchTags, + isVisual, + valueCopyGetter: copyItemList, + ); + + @override + ListSetting copy() { + return ListSetting( + name, + getLocalizedName, + _value, + possibleItems, + cardBuilder: cardBuilder, + addCardBuilder: addCardBuilder, + getDescription: getDescription, + onChange: onChange, + enableConditions: enableConditions, + isVisual: isVisual, + searchTags: searchTags, + ); + } + + + + Widget getItemAddCard(T item) { + return addCardBuilder(item); + } + + Widget getItemCard(T item, + {VoidCallback? onDelete, VoidCallback? onDuplicate}) { + return cardBuilder(item, onDelete, onDuplicate); + } + + + @override + dynamic valueToJson() { + return _value.map((e) => e.toJson()).toList(); + } + + @override + void loadValueFromJson(dynamic value) { + if (value == null) return; + _value = (value as List).map((e) => fromJsonFactories[T]!(e) as T).toList(); + } +} + + class CustomSetting extends Setting { // The screen that will be navigated to when this setting is tapped. Widget Function(BuildContext, CustomSetting) screenBuilder; diff --git a/lib/settings/widgets/list_filter_setting_card.dart b/lib/settings/widgets/list_filter_setting_card.dart new file mode 100644 index 00000000..903d5a10 --- /dev/null +++ b/lib/settings/widgets/list_filter_setting_card.dart @@ -0,0 +1,49 @@ +import 'package:clock_app/common/types/list_filter.dart'; +import 'package:clock_app/common/types/tag.dart'; +import 'package:clock_app/common/utils/popup_action.dart'; +import 'package:clock_app/common/widgets/card_edit_menu.dart'; +import 'package:flutter/material.dart'; + +class ListFilterSettingCard extends StatefulWidget { + const ListFilterSettingCard({ + super.key, + required this.listFilter, + required this.onEnabledChange, + }); + + final ListFilterItem listFilter; + final void Function(bool) onEnabledChange; + + @override + State createState() => _ListFilterSettingCardState(); +} + +class _ListFilterSettingCardState extends State { + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.only(left: 16.0, right: 4, top: 8, bottom: 8), + child: Row( + children: [ + Expanded( + flex: 999, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + widget.listFilter.displayName(context), + style: Theme.of(context).textTheme.displaySmall, + maxLines: 1, + overflow: TextOverflow.ellipsis, + softWrap: false, + ), + ], + ), + ), + Switch( + value: widget.listFilter.isEnabled, + onChanged: widget.onEnabledChange) + ], + )); + } +} diff --git a/lib/settings/widgets/list_setting_add_bottom_sheet.dart b/lib/settings/widgets/list_setting_add_bottom_sheet.dart index 347252d8..707457a9 100644 --- a/lib/settings/widgets/list_setting_add_bottom_sheet.dart +++ b/lib/settings/widgets/list_setting_add_bottom_sheet.dart @@ -2,14 +2,14 @@ import 'package:clock_app/common/types/list_item.dart'; import 'package:clock_app/settings/types/setting.dart'; import 'package:flutter/material.dart'; -class ListSettingAddBottomSheet +class CustomizableListSettingAddBottomSheet extends StatelessWidget { - const ListSettingAddBottomSheet({ + const CustomizableListSettingAddBottomSheet({ required this.setting, super.key, }); - final ListSetting setting; + final CustomizableListSetting setting; @override Widget build(BuildContext context) { diff --git a/lib/settings/widgets/list_setting_card.dart b/lib/settings/widgets/list_setting_card.dart index a5d4805f..2724a29a 100644 --- a/lib/settings/widgets/list_setting_card.dart +++ b/lib/settings/widgets/list_setting_card.dart @@ -11,7 +11,7 @@ class ListSettingCard extends StatefulWidget { this.showAsCard = true, }); - final ListSetting setting; + final CustomizableListSetting setting; final bool showAsCard; final void Function(BuildContext context) onChanged; @@ -28,7 +28,7 @@ class _ListSettingCardState extends State { onTap: () async { await Navigator.of(context).push( MaterialPageRoute( - builder: (context) => ListSettingScreen( + builder: (context) => CustomizableListSettingScreen( setting: widget.setting, onChanged: widget.onChanged), ), ); diff --git a/lib/settings/widgets/list_setting_screen.dart b/lib/settings/widgets/list_setting_screen.dart index 9deb0cc8..7963eff7 100644 --- a/lib/settings/widgets/list_setting_screen.dart +++ b/lib/settings/widgets/list_setting_screen.dart @@ -9,23 +9,23 @@ import 'package:clock_app/settings/types/setting.dart'; import 'package:clock_app/settings/widgets/list_setting_add_bottom_sheet.dart'; import 'package:flutter/material.dart'; -class ListSettingScreen +class CustomizableListSettingScreen extends StatefulWidget { - const ListSettingScreen({ + const CustomizableListSettingScreen({ super.key, required this.setting, required this.onChanged, }); - final ListSetting setting; + final CustomizableListSetting setting; final void Function(BuildContext context) onChanged; @override - State createState() => _ListSettingScreenState(); + State createState() => _CustomizableListSettingScreenState(); } -class _ListSettingScreenState - extends State> { +class _CustomizableListSettingScreenState + extends State> { final _listController = ListController(); Future _openAddBottomSheet() async { @@ -33,7 +33,7 @@ class _ListSettingScreenState return await showModalBottomSheet( context: context, - builder: (context) => ListSettingAddBottomSheet(setting: widget.setting), + builder: (context) => CustomizableListSettingAddBottomSheet(setting: widget.setting), ); } diff --git a/lib/timer/data/timer_settings_schema.dart b/lib/timer/data/timer_settings_schema.dart index 2b189dfd..8bbfe1da 100644 --- a/lib/timer/data/timer_settings_schema.dart +++ b/lib/timer/data/timer_settings_schema.dart @@ -1,12 +1,12 @@ import 'package:audio_session/audio_session.dart'; import 'package:clock_app/audio/audio_channels.dart'; +import 'package:clock_app/audio/screens/ringtones_screen.dart'; import 'package:clock_app/audio/types/ringtone_player.dart'; import 'package:clock_app/common/logic/tags.dart'; import 'package:clock_app/common/types/file_item.dart'; import 'package:clock_app/common/types/popup_action.dart'; import 'package:clock_app/common/types/tag.dart'; import 'package:clock_app/common/utils/ringtones.dart'; -import 'package:clock_app/settings/screens/ringtones_screen.dart'; import 'package:clock_app/settings/screens/tags_screen.dart'; import 'package:clock_app/settings/types/setting.dart'; import 'package:clock_app/settings/types/setting_enable_condition.dart';