From d9ba1d2aff053b559d1dc8981c13f56d3dee9c27 Mon Sep 17 00:00:00 2001 From: AhsanSarwar45 Date: Sun, 17 Dec 2023 14:39:07 +0500 Subject: [PATCH] Add about page --- assets/images/logo.png | Bin 0 -> 6507 bytes lib/common/data/app_info.dart | 7 + lib/main.dart | 2 + .../data/accessibility_settings_schema.dart | 10 + lib/settings/data/alarm_settings_schema.dart | 54 +++ .../data/appearance_settings_schema.dart | 94 ++++ lib/settings/data/backup_settings_schema.dart | 69 +++ .../data/developer_settings_schema.dart | 19 + .../data/general_settings_schema.dart | 118 +++++ lib/settings/data/settings_schema.dart | 442 +----------------- .../data/stopwatch_settings_schema.dart | 31 ++ lib/settings/data/timer_settings_schema.dart | 22 + lib/settings/screens/about_screen.dart | 113 +++++ pubspec.lock | 16 + pubspec.yaml | 2 + 15 files changed, 577 insertions(+), 422 deletions(-) create mode 100644 assets/images/logo.png create mode 100644 lib/common/data/app_info.dart create mode 100644 lib/settings/data/accessibility_settings_schema.dart create mode 100644 lib/settings/data/alarm_settings_schema.dart create mode 100644 lib/settings/data/appearance_settings_schema.dart create mode 100644 lib/settings/data/backup_settings_schema.dart create mode 100644 lib/settings/data/developer_settings_schema.dart create mode 100644 lib/settings/data/general_settings_schema.dart create mode 100644 lib/settings/data/stopwatch_settings_schema.dart create mode 100644 lib/settings/data/timer_settings_schema.dart create mode 100644 lib/settings/screens/about_screen.dart diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..3efc7830f3db3f097192e8d627a8273a50f987fb GIT binary patch literal 6507 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 initializePackageInfo() async { + packageInfo = await PackageInfo.fromPlatform(); +} diff --git a/lib/main.dart b/lib/main.dart index 14836fb2..bdec105f 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -11,6 +11,7 @@ import 'package:clock_app/audio/logic/audio_session.dart'; import 'package:clock_app/audio/types/ringtone_manager.dart'; import 'package:clock_app/audio/types/ringtone_player.dart'; import 'package:clock_app/clock/logic/timezone_database.dart'; +import 'package:clock_app/common/data/app_info.dart'; import 'package:clock_app/common/data/paths.dart'; import 'package:clock_app/common/logic/lock_screen_flags.dart'; import 'package:clock_app/common/utils/debug.dart'; @@ -26,6 +27,7 @@ void main() async { WidgetsFlutterBinding.ensureInitialized(); initializeTimeZones(); + await initializePackageInfo(); await initializeAppDataDirectory(); await initializeSettings(); await initializeDatabases(); diff --git a/lib/settings/data/accessibility_settings_schema.dart b/lib/settings/data/accessibility_settings_schema.dart new file mode 100644 index 00000000..2ece8449 --- /dev/null +++ b/lib/settings/data/accessibility_settings_schema.dart @@ -0,0 +1,10 @@ +import 'package:clock_app/settings/types/setting.dart'; +import 'package:clock_app/settings/types/setting_group.dart'; +import 'package:flutter/material.dart'; + +SettingGroup accessibilitySettingsSchema = SettingGroup( + "Accessibility", + [SwitchSetting("Left Handed Mode", false)], + icon: Icons.accessibility_new_rounded, + showExpandedView: false, +); diff --git a/lib/settings/data/alarm_settings_schema.dart b/lib/settings/data/alarm_settings_schema.dart new file mode 100644 index 00000000..aaca2228 --- /dev/null +++ b/lib/settings/data/alarm_settings_schema.dart @@ -0,0 +1,54 @@ +import 'package:clock_app/alarm/data/alarm_settings_schema.dart'; +import 'package:clock_app/alarm/types/notification_action.dart'; +import 'package:clock_app/alarm/widgets/notification_actions/area_notification_action.dart'; +import 'package:clock_app/alarm/widgets/notification_actions/buttons_notification_action.dart'; +import 'package:clock_app/alarm/widgets/notification_actions/slide_notification_action.dart'; +import 'package:clock_app/icons/flux_icons.dart'; +import 'package:clock_app/settings/types/setting.dart'; +import 'package:clock_app/settings/types/setting_group.dart'; +import 'package:flutter/material.dart'; + +SettingGroup alarmAppSettingsSchema = SettingGroup( + "Alarm", + [ + SettingGroup( + "Default Settings", + [...alarmSettingsSchema.settingItems], + description: "Set default settings for new alarms", + icon: Icons.settings, + ), + SelectSetting("Dismiss Action Type", searchTags: [ + "action" + ], [ + SelectSettingOption( + "Slide", + NotificationAction( + builder: (onDismiss, onSnooze) => SlideNotificationAction( + onDismiss: onDismiss, + onSnooze: onSnooze, + ), + ), + ), + SelectSettingOption( + "Buttons", + NotificationAction( + builder: (onDismiss, onSnooze) => ButtonsNotificationAction( + onDismiss: onDismiss, + onSnooze: onSnooze, + ), + ), + ), + SelectSettingOption( + "Area Buttons", + NotificationAction( + builder: (onDismiss, onSnooze) => AreaNotificationAction( + onDismiss: onDismiss, + onSnooze: onSnooze, + ), + ), + ) + ]), + SwitchSetting("Show Filters", true), + ], + icon: FluxIcons.alarm, +); diff --git a/lib/settings/data/appearance_settings_schema.dart b/lib/settings/data/appearance_settings_schema.dart new file mode 100644 index 00000000..46383eee --- /dev/null +++ b/lib/settings/data/appearance_settings_schema.dart @@ -0,0 +1,94 @@ +import 'package:clock_app/app.dart'; +import 'package:clock_app/settings/data/settings_schema.dart'; +import 'package:clock_app/settings/types/setting.dart'; +import 'package:clock_app/settings/types/setting_group.dart'; +import 'package:clock_app/theme/screens/themes_screen.dart'; +import 'package:clock_app/theme/theme.dart'; +import 'package:clock_app/theme/types/color_scheme.dart'; +import 'package:clock_app/theme/types/style_theme.dart'; +import 'package:clock_app/theme/utils/color_scheme.dart'; +import 'package:clock_app/theme/utils/style_theme.dart'; +import 'package:flutter/material.dart'; + +SettingGroup appearanceSettingsSchema = SettingGroup( + "Appearance", + [ + SettingGroup( + "Colors", + [ + CustomSetting( + "Color Scheme", + description: + "Select from predefined color schemes or create your own", + defaultColorScheme, + (context, setting) => ThemesScreen( + saveTag: 'color_schemes', + setting: setting, + getThemeFromItem: (theme, themeItem) => + getThemeFromColorScheme(theme, themeItem), + createThemeItem: () => ColorSchemeData(), + ), + (context, setting) => Text( + setting.value.name, + style: Theme.of(context).textTheme.bodyMedium, + ), + onChange: (context, colorScheme) { + App.setColorScheme(context, colorScheme); + appSettings.save(); + }, + searchTags: ["theme", "style", "visual", "dark mode"], + ), + SwitchSetting("Override Accent Color", false, + onChange: (context, value) { + App.setColorScheme(context); + }, searchTags: ["primary", "color"]), + ColorSetting("Accent Color", Colors.cyan, onChange: (context, color) { + App.setColorScheme(context); + }, enableConditions: [ + SettingEnableConditionParameter("Override Accent Color", true) + ], searchTags: [ + "primary", + "color" + ]), + ], + ), + SettingGroup( + "Style", + [ + CustomSetting( + "Style Theme", + description: "Change styles like shadows, outlines and opacities", + defaultStyleTheme, + (context, setting) => ThemesScreen( + saveTag: 'style_themes', + setting: setting, + getThemeFromItem: (theme, themeItem) => + getThemeFromStyleTheme(theme, themeItem), + createThemeItem: () => StyleTheme(), + ), + (context, setting) => Text( + setting.value.name, + style: Theme.of(context).textTheme.bodyMedium, + ), + onChange: (context, styleTheme) { + App.setStyleTheme(context, styleTheme); + appSettings.save(); + }, + searchTags: [ + "scheme", + "visual", + "shadow", + "outline", + "elevation", + "card", + "border", + "opacity", + "blur" + ], + ), + ], + ), + ], + icon: Icons.palette_outlined, + description: "Set themes, colors and change layout", +); diff --git a/lib/settings/data/backup_settings_schema.dart b/lib/settings/data/backup_settings_schema.dart new file mode 100644 index 00000000..d2cba5bf --- /dev/null +++ b/lib/settings/data/backup_settings_schema.dart @@ -0,0 +1,69 @@ +import 'dart:convert'; +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:clock_app/app.dart'; +import 'package:clock_app/settings/data/settings_schema.dart'; +import 'package:clock_app/settings/types/setting_action.dart'; +import 'package:clock_app/settings/types/setting_group.dart'; +import 'package:flutter/material.dart'; +import 'package:pick_or_save/pick_or_save.dart'; + +SettingGroup backupSettingsSchema = SettingGroup( + "Backup", + description: "Export or Import your settings locally", + icon: Icons.restore_rounded, + [ + SettingGroup( + "Settings", + [ + SettingAction( + "Export", + (context) async { + saveBackupFile(json.encode(appSettings.valueToJson()), "settings"); + }, + searchTags: ["settings", "export", "backup", "save"], + description: "Export settings to a local file", + ), + SettingAction( + "Import", + (context) async { + loadBackupFile( + (data) { + appSettings.loadValueFromJson(json.decode(data)); + appSettings.callAllListeners(); + App.refreshTheme(context); + }, + ); + }, + searchTags: ["settings", "import", "backup", "load"], + description: "Import settings from a local file", + ), + ], + ), + ], +); + +saveBackupFile(String data, String label) async { + await PickOrSave().fileSaver( + params: FileSaverParams( + saveFiles: [ + SaveFileInfo( + fileData: Uint8List.fromList(utf8.encode(data)), + fileName: "chrono_${label}_backup_${DateTime.now().toIso8601String()}", + ) + ], + )); +} + +loadBackupFile(Function(String) onSuccess) async { + List? result = await PickOrSave().filePicker( + params: FilePickerParams( + getCachedFilePath: true, + ), + ); + if (result != null && result.isNotEmpty) { + File file = File(result[0]); + onSuccess(utf8.decode(file.readAsBytesSync())); + } +} diff --git a/lib/settings/data/developer_settings_schema.dart b/lib/settings/data/developer_settings_schema.dart new file mode 100644 index 00000000..890aee0c --- /dev/null +++ b/lib/settings/data/developer_settings_schema.dart @@ -0,0 +1,19 @@ +import 'package:clock_app/settings/types/setting.dart'; +import 'package:clock_app/settings/types/setting_group.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; + +SettingGroup developerSettingsSchema = SettingGroup( + "Developer Options", + [ + SettingGroup("Alarm", [ + SwitchSetting( + "Show Instant Alarm Button", + kDebugMode, + description: + "Show a button on the alarm screen that creates an alarm that rings one second in the future", + ), + ]), + ], + icon: Icons.code_rounded, +); diff --git a/lib/settings/data/general_settings_schema.dart b/lib/settings/data/general_settings_schema.dart new file mode 100644 index 00000000..4b74b0f9 --- /dev/null +++ b/lib/settings/data/general_settings_schema.dart @@ -0,0 +1,118 @@ +import 'package:app_settings/app_settings.dart'; +import 'package:auto_start_flutter/auto_start_flutter.dart'; +import 'package:clock_app/clock/types/time.dart'; +import 'package:clock_app/icons/flux_icons.dart'; +import 'package:clock_app/settings/screens/vendor_list_screen.dart'; +import 'package:clock_app/settings/types/setting.dart'; +import 'package:clock_app/settings/types/setting_action.dart'; +import 'package:clock_app/settings/types/setting_group.dart'; +import 'package:clock_app/settings/types/setting_link.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:intl/intl.dart'; + +SelectSettingOption _getDateSettingOption(String format) { + return SelectSettingOption( + "${DateFormat(format).format(DateTime.now())} ($format)", format); +} + +SettingGroup generalSettingsSchema = SettingGroup( + "General", + [ + SettingGroup("Display", [ + DynamicSelectSetting( + "Date Format", + () => [ + _getDateSettingOption("dd/MM/yyyy"), + _getDateSettingOption("dd-MM-yyyy"), + _getDateSettingOption("d/M/yyyy"), + _getDateSettingOption("d-M-yyyy"), + _getDateSettingOption("MM/dd/yyyy"), + _getDateSettingOption("MM-dd-yyyy"), + _getDateSettingOption("M/d/yy"), + _getDateSettingOption("M-d-yy"), + _getDateSettingOption("M/d/yyyy"), + _getDateSettingOption("M-d-yyyy"), + _getDateSettingOption("yyyy/dd/MM"), + _getDateSettingOption("yyyy-dd-MM"), + _getDateSettingOption("yyyy/MM/dd"), + _getDateSettingOption("yyyy-MM-dd"), + // SelectSettingOption(DateTime.now().toIso8601Date(), "YYYY-MM-DD"), + _getDateSettingOption("d MMM yyyy"), + _getDateSettingOption("d MMMM yyyy"), + ], + description: "How to display the dates", + ), + SelectSetting( + "Time Format", + [ + SelectSettingOption("12 Hours", TimeFormat.h12), + SelectSettingOption("24 Hours", TimeFormat.h24), + SelectSettingOption("Device Settings", TimeFormat.device), + ], + description: "12 or 24 hour time", + ), + SwitchSetting("Show Seconds", true), + ]), + SettingGroup("Reliability", [ + SettingPageLink( + "Vendor Specific", + const VendorListScreen(), + description: "Manually disable vendor-specific optimizations", + ), + SettingAction( + "Disable Battery Optimization", + (context) async { + AppSettings.openAppSettings( + type: AppSettingsType.batteryOptimization); + }, + description: + "Disable battery optimization for this app to prevent alarms from being delayed", + ), + SettingAction( + "Allow Notifications", + (context) async { + AppSettings.openAppSettings(type: AppSettingsType.notification); + }, + description: "Allow lock screen notifications for alarms and timers", + ), + SettingAction( + "Auto Start", + (context) async { + try { + //check auto-start availability. + var test = (await isAutoStartAvailable) ?? false; + //if available then navigate to auto-start setting page. + if (test) { + await getAutoStartPermission(); + } else { + // ignore: use_build_context_synchronously + ScaffoldMessenger.of(context).removeCurrentSnackBar(); + + SnackBar snackBar = SnackBar( + content: Container( + alignment: Alignment.centerLeft, + height: 28, + child: const Text( + "Auto Start is not available for your device")), + margin: const EdgeInsets.only(left: 20, right: 20, bottom: 4), + elevation: 2, + dismissDirection: DismissDirection.none, + ); + + // ignore: use_build_context_synchronously + ScaffoldMessenger.of(context).showSnackBar(snackBar); + } + } on PlatformException catch (e) { + if (kDebugMode) print(e.message); + } + }, + description: + "Some devices require Auto Start to be enabled for alarms to ring while app is closed.", + ) + ]), + ], + icon: FluxIcons.settings, + description: "Set app wide settings like time format", +); diff --git a/lib/settings/data/settings_schema.dart b/lib/settings/data/settings_schema.dart index a02ef420..a57f4d9d 100644 --- a/lib/settings/data/settings_schema.dart +++ b/lib/settings/data/settings_schema.dart @@ -1,39 +1,14 @@ -import 'dart:convert'; -import 'dart:io'; - -import 'package:app_settings/app_settings.dart'; -import 'package:auto_start_flutter/auto_start_flutter.dart'; -import 'package:clock_app/alarm/data/alarm_settings_schema.dart'; -import 'package:clock_app/alarm/types/notification_action.dart'; -import 'package:clock_app/alarm/widgets/notification_actions/area_notification_action.dart'; -import 'package:clock_app/alarm/widgets/notification_actions/buttons_notification_action.dart'; -import 'package:clock_app/alarm/widgets/notification_actions/slide_notification_action.dart'; -import 'package:clock_app/app.dart'; -import 'package:clock_app/clock/types/time.dart'; -import 'package:clock_app/icons/flux_icons.dart'; -import 'package:clock_app/settings/screens/vendor_list_screen.dart'; -import 'package:clock_app/settings/types/setting.dart'; -import 'package:clock_app/settings/types/setting_action.dart'; +import 'package:clock_app/settings/data/accessibility_settings_schema.dart'; +import 'package:clock_app/settings/data/alarm_settings_schema.dart'; +import 'package:clock_app/settings/data/appearance_settings_schema.dart'; +import 'package:clock_app/settings/data/backup_settings_schema.dart'; +import 'package:clock_app/settings/data/developer_settings_schema.dart'; +import 'package:clock_app/settings/data/general_settings_schema.dart'; +import 'package:clock_app/settings/data/stopwatch_settings_schema.dart'; +import 'package:clock_app/settings/data/timer_settings_schema.dart'; +import 'package:clock_app/settings/screens/about_screen.dart'; import 'package:clock_app/settings/types/setting_group.dart'; import 'package:clock_app/settings/types/setting_link.dart'; -import 'package:clock_app/theme/screens/themes_screen.dart'; -import 'package:clock_app/theme/theme.dart'; -import 'package:clock_app/theme/types/color_scheme.dart'; -import 'package:clock_app/theme/types/style_theme.dart'; -import 'package:clock_app/theme/utils/color_scheme.dart'; -import 'package:clock_app/theme/utils/style_theme.dart'; -import 'package:clock_app/timer/data/timer_settings_schema.dart'; -import 'package:clock_app/timer/screens/presets_screen.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:intl/intl.dart'; -import 'package:pick_or_save/pick_or_save.dart'; - -SelectSettingOption _getDateSettingOption(String format) { - return SelectSettingOption( - "${DateFormat(format).format(DateTime.now())} ($format)", format); -} const int settingsSchemaVersion = 1; @@ -42,397 +17,20 @@ SettingGroup appSettings = SettingGroup( version: settingsSchemaVersion, isSearchable: true, [ - SettingGroup( - "General", - [ - SettingGroup("Display", [ - DynamicSelectSetting( - "Date Format", - () => [ - _getDateSettingOption("dd/MM/yyyy"), - _getDateSettingOption("dd-MM-yyyy"), - _getDateSettingOption("d/M/yyyy"), - _getDateSettingOption("d-M-yyyy"), - _getDateSettingOption("MM/dd/yyyy"), - _getDateSettingOption("MM-dd-yyyy"), - _getDateSettingOption("M/d/yy"), - _getDateSettingOption("M-d-yy"), - _getDateSettingOption("M/d/yyyy"), - _getDateSettingOption("M-d-yyyy"), - _getDateSettingOption("yyyy/dd/MM"), - _getDateSettingOption("yyyy-dd-MM"), - _getDateSettingOption("yyyy/MM/dd"), - _getDateSettingOption("yyyy-MM-dd"), - // SelectSettingOption(DateTime.now().toIso8601Date(), "YYYY-MM-DD"), - _getDateSettingOption("d MMM yyyy"), - _getDateSettingOption("d MMMM yyyy"), - ], - description: "How to display the dates", - ), - SelectSetting( - "Time Format", - [ - SelectSettingOption("12 Hours", TimeFormat.h12), - SelectSettingOption("24 Hours", TimeFormat.h24), - SelectSettingOption("Device Settings", TimeFormat.device), - ], - description: "12 or 24 hour time", - ), - SwitchSetting("Show Seconds", true), - ]), - SettingGroup("Reliability", [ - SettingPageLink( - "Vendor Specific", - const VendorListScreen(), - description: "Manually disable vendor-specific optimizations", - ), - SettingAction( - "Disable Battery Optimization", - (context) async { - AppSettings.openAppSettings( - type: AppSettingsType.batteryOptimization); - }, - description: - "Disable battery optimization for this app to prevent alarms from being delayed", - ), - SettingAction( - "Allow Notifications", - (context) async { - AppSettings.openAppSettings(type: AppSettingsType.notification); - }, - description: - "Allow lock screen notifications for alarms and timers", - ), - SettingAction( - "Auto Start", - (context) async { - try { - //check auto-start availability. - var test = (await isAutoStartAvailable) ?? false; - //if available then navigate to auto-start setting page. - if (test) { - await getAutoStartPermission(); - } else { - // ignore: use_build_context_synchronously - ScaffoldMessenger.of(context).removeCurrentSnackBar(); - - SnackBar snackBar = SnackBar( - content: Container( - alignment: Alignment.centerLeft, - height: 28, - child: const Text( - "Auto Start is not available for your device")), - margin: - const EdgeInsets.only(left: 20, right: 20, bottom: 4), - elevation: 2, - dismissDirection: DismissDirection.none, - ); - - // ignore: use_build_context_synchronously - ScaffoldMessenger.of(context).showSnackBar(snackBar); - } - } on PlatformException catch (e) { - if (kDebugMode) print(e.message); - } - }, - description: - "Some devices require Auto Start to be enabled for alarms to ring while app is closed.", - ) - ]), - ], - icon: FluxIcons.settings, - description: "Set app wide settings like time format", - ), - SettingGroup( - "Appearance", - [ - SettingGroup( - "Colors", - [ - CustomSetting( - "Color Scheme", - description: - "Select from predefined color schemes or create your own", - defaultColorScheme, - (context, setting) => ThemesScreen( - saveTag: 'color_schemes', - setting: setting, - getThemeFromItem: (theme, themeItem) => - getThemeFromColorScheme(theme, themeItem), - createThemeItem: () => ColorSchemeData(), - ), - (context, setting) => Text( - setting.value.name, - style: Theme.of(context).textTheme.bodyMedium, - ), - onChange: (context, colorScheme) { - App.setColorScheme(context, colorScheme); - appSettings.save(); - }, - searchTags: ["theme", "style", "visual", "dark mode"], - ), - SwitchSetting("Override Accent Color", false, - onChange: (context, value) { - App.setColorScheme(context); - }, searchTags: ["primary", "color"]), - ColorSetting("Accent Color", Colors.cyan, - onChange: (context, color) { - App.setColorScheme(context); - }, enableConditions: [ - SettingEnableConditionParameter("Override Accent Color", true) - ], searchTags: [ - "primary", - "color" - ]), - ], - ), - SettingGroup( - "Style", - [ - CustomSetting( - "Style Theme", - description: "Change styles like shadows, outlines and opacities", - defaultStyleTheme, - (context, setting) => ThemesScreen( - saveTag: 'style_themes', - setting: setting, - getThemeFromItem: (theme, themeItem) => - getThemeFromStyleTheme(theme, themeItem), - createThemeItem: () => StyleTheme(), - ), - (context, setting) => Text( - setting.value.name, - style: Theme.of(context).textTheme.bodyMedium, - ), - onChange: (context, styleTheme) { - App.setStyleTheme(context, styleTheme); - appSettings.save(); - }, - searchTags: [ - "scheme", - "visual", - "shadow", - "outline", - "elevation", - "card", - "border", - "opacity", - "blur" - ], - ), - ], - ), - ], - icon: Icons.palette_outlined, - description: "Set themes, colors and change layout", - ), - SettingGroup( - "Alarm", - [ - SettingGroup( - "Default Settings", - [...alarmSettingsSchema.settingItems], - description: "Set default settings for new alarms", - icon: Icons.settings, - ), - SelectSetting("Dismiss Action Type", searchTags: [ - "action" - ], [ - SelectSettingOption( - "Slide", - NotificationAction( - builder: (onDismiss, onSnooze) => SlideNotificationAction( - onDismiss: onDismiss, - onSnooze: onSnooze, - ), - ), - ), - SelectSettingOption( - "Buttons", - NotificationAction( - builder: (onDismiss, onSnooze) => ButtonsNotificationAction( - onDismiss: onDismiss, - onSnooze: onSnooze, - ), - ), - ), - SelectSettingOption( - "Area Buttons", - NotificationAction( - builder: (onDismiss, onSnooze) => AreaNotificationAction( - onDismiss: onDismiss, - onSnooze: onSnooze, - ), - ), - ) - ]), - SwitchSetting("Show Filters", true), - ], - icon: FluxIcons.alarm, - ), - SettingGroup( - "Timer", - [ - SettingGroup( - "Default Settings", - [...timerSettingsSchema.settingItems], - description: "Set default settings for new timers", - icon: Icons.settings, - ), - SettingPageLink("Presets", const PresetsScreen()), - SwitchSetting("Show Filters", true), - ], - icon: FluxIcons.timer, - ), - SettingGroup( - "Stopwatch", - [ - SettingGroup( - "Time Format", - [ - SwitchSetting("Show Milliseconds", true), - ], - description: "Show comparison laps bars in stopwatch", - icon: Icons.settings, - searchTags: ["milliseconds"]), - SettingGroup( - "Comparison Lap Bars", - [ - SwitchSetting("Show Previous Lap", true), - SwitchSetting("Show Fastest Lap", true), - SwitchSetting("Show Slowest Lap", true), - SwitchSetting("Show Average Lap", true), - ], - description: "Show comparison laps bars in stopwatch", - icon: Icons.settings, - searchTags: ["fastest", "slowest", "average", "previous"], - ), - ], - icon: FluxIcons.stopwatch, - ), - SettingGroup( - "Accessibility", - [SwitchSetting("Left Handed Mode", false)], - icon: Icons.accessibility_new_rounded, - showExpandedView: false, - ), - SettingGroup( - "Backup", - description: "Export or Import your settings locally", - icon: Icons.restore_rounded, - [ - SettingGroup( - "Settings", - [ - SettingAction( - "Export", - (context) async { - saveBackupFile( - json.encode(appSettings.valueToJson()), "settings"); - }, - searchTags: ["settings", "export", "backup", "save"], - description: "Export settings to a local file", - ), - SettingAction( - "Import", - (context) async { - loadBackupFile( - (data) { - appSettings.loadValueFromJson(json.decode(data)); - appSettings.callAllListeners(); - App.refreshTheme(context); - }, - ); - }, - searchTags: ["settings", "import", "backup", "load"], - description: "Import settings from a local file", - ), - ], - ), - // SettingGroup( - // "Alarms", - // [ - // SettingAction( - // "Export", - // (context) async { - // saveBackupFile( - // json.encode(appSettings.valueToJson()), "alarms"); - // }, - // ), - // SettingAction( - // "Import", - // (context) async { - // loadBackupFile((data) { - // appSettings.loadValueFromJson(json.decode(data)); - // appSettings.callAllListeners(); - // App.refreshTheme(context); - // }); - // }, - // ), - // ], - // ), - // SettingGroup( - // "Timers", - // [ - // SettingAction( - // "Export", - // (context) async { - // saveBackupFile( - // json.encode(appSettings.valueToJson()), "timers"); - // }, - // ), - // SettingAction( - // "Import", - // (context) async { - // loadBackupFile((data) { - // appSettings.loadValueFromJson(json.decode(data)); - // appSettings.callAllListeners(); - // App.refreshTheme(context); - // }); - // }, - // ), - // ], - // ), - ], - ), - SettingGroup( - "Developer Options", - [ - SettingGroup("Alarm", [ - SwitchSetting( - "Show Instant Alarm Button", - kDebugMode, - description: - "Show a button on the alarm screen that creates an alarm that rings one second in the future", - ), - ]), - ], - icon: Icons.code_rounded, + generalSettingsSchema, + appearanceSettingsSchema, + alarmAppSettingsSchema, + timerAppSettingsSchema, + stopwatchSettingsSchema, + accessibilitySettingsSchema, + backupSettingsSchema, + developerSettingsSchema, + SettingPageLink( + "About", + const AboutScreen(), ), ], ); -saveBackupFile(String data, String label) async { - await PickOrSave().fileSaver( - params: FileSaverParams( - saveFiles: [ - SaveFileInfo( - fileData: Uint8List.fromList(utf8.encode(data)), - fileName: "chrono_${label}_backup_${DateTime.now().toIso8601String()}", - ) - ], - )); -} -loadBackupFile(Function(String) onSuccess) async { - List? result = await PickOrSave().filePicker( - params: FilePickerParams( - getCachedFilePath: true, - ), - ); - if (result != null && result.isNotEmpty) { - File file = File(result[0]); - onSuccess(utf8.decode(file.readAsBytesSync())); - } -} // Settings appSettings = Settings(settingsItems); diff --git a/lib/settings/data/stopwatch_settings_schema.dart b/lib/settings/data/stopwatch_settings_schema.dart new file mode 100644 index 00000000..f22603aa --- /dev/null +++ b/lib/settings/data/stopwatch_settings_schema.dart @@ -0,0 +1,31 @@ +import 'package:clock_app/icons/flux_icons.dart'; +import 'package:clock_app/settings/types/setting.dart'; +import 'package:clock_app/settings/types/setting_group.dart'; +import 'package:flutter/material.dart'; + +SettingGroup stopwatchSettingsSchema = SettingGroup( + "Stopwatch", + [ + SettingGroup( + "Time Format", + [ + SwitchSetting("Show Milliseconds", true), + ], + description: "Show comparison laps bars in stopwatch", + icon: Icons.settings, + searchTags: ["milliseconds"]), + SettingGroup( + "Comparison Lap Bars", + [ + SwitchSetting("Show Previous Lap", true), + SwitchSetting("Show Fastest Lap", true), + SwitchSetting("Show Slowest Lap", true), + SwitchSetting("Show Average Lap", true), + ], + description: "Show comparison laps bars in stopwatch", + icon: Icons.settings, + searchTags: ["fastest", "slowest", "average", "previous"], + ), + ], + icon: FluxIcons.stopwatch, +); diff --git a/lib/settings/data/timer_settings_schema.dart b/lib/settings/data/timer_settings_schema.dart new file mode 100644 index 00000000..f54ad216 --- /dev/null +++ b/lib/settings/data/timer_settings_schema.dart @@ -0,0 +1,22 @@ +import 'package:clock_app/icons/flux_icons.dart'; +import 'package:clock_app/settings/types/setting.dart'; +import 'package:clock_app/settings/types/setting_group.dart'; +import 'package:clock_app/settings/types/setting_link.dart'; +import 'package:clock_app/timer/data/timer_settings_schema.dart'; +import 'package:clock_app/timer/screens/presets_screen.dart'; +import 'package:flutter/material.dart'; + +SettingGroup timerAppSettingsSchema = SettingGroup( + "Timer", + [ + SettingGroup( + "Default Settings", + [...timerSettingsSchema.settingItems], + description: "Set default settings for new timers", + icon: Icons.settings, + ), + SettingPageLink("Presets", const PresetsScreen()), + SwitchSetting("Show Filters", true), + ], + icon: FluxIcons.timer, +); diff --git a/lib/settings/screens/about_screen.dart b/lib/settings/screens/about_screen.dart new file mode 100644 index 00000000..0e418776 --- /dev/null +++ b/lib/settings/screens/about_screen.dart @@ -0,0 +1,113 @@ +import 'package:clock_app/common/data/app_info.dart'; +import 'package:clock_app/common/widgets/card_container.dart'; +import 'package:clock_app/navigation/widgets/app_top_bar.dart'; +import 'package:flutter/material.dart'; +import 'package:url_launcher/url_launcher.dart'; + +class AboutScreen extends StatelessWidget { + const AboutScreen({super.key}); + + @override + Widget build(BuildContext context) { + final ThemeData theme = Theme.of(context); + final ColorScheme colorScheme = theme.colorScheme; + final TextTheme textTheme = theme.textTheme; + return Scaffold( + appBar: AppTopBar( + title: Text("About", + style: textTheme.titleMedium?.copyWith( + color: colorScheme.onBackground.withOpacity(0.6), + )), + ), + body: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 20.0), + child: Column( + children: [ + CardContainer( + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + SizedBox( + width: 48, + child: CardContainer( + child: Image.asset('assets/images/logo.png')), + ), + const SizedBox(width: 16.0), + Text( + packageInfo?.appName ?? 'Chrono', + style: textTheme.titleMedium?.copyWith( + color: colorScheme.onBackground, + ), + ), + ], + ), + const SizedBox(height: 8.0), + Row( + children: [ + const SizedBox( + width: 48, + child: Icon( + Icons.info_outline_rounded, + ), + ), + const SizedBox(width: 16.0), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Version", + style: textTheme.bodyMedium?.copyWith( + color: colorScheme.onBackground, + ), + ), + Text( + packageInfo?.version ?? '1.0.0', + style: textTheme.bodyMedium?.copyWith( + color: + colorScheme.onBackground.withOpacity(0.6), + ), + ), + ], + ), + ], + ), + const SizedBox(height: 8.0), + InkWell( + onTap: () async { + await launchUrl(Uri.parse( + "https://github.com/vicolo-dev/chrono")); + }, + child: Row( + children: [ + const SizedBox( + width: 48, + child: Icon( + Icons.code_rounded, + ), + ), + const SizedBox(width: 16.0), + Text( + "View on Github", + style: textTheme.bodyMedium?.copyWith( + color: colorScheme.onBackground, + ), + ), + ], + ), + ), + ], + ), + ), + ), + ], + ), + ), + ), + ); + } +} diff --git a/pubspec.lock b/pubspec.lock index da2528f3..ecced77b 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -596,6 +596,22 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.0" + package_info_plus: + dependency: "direct main" + description: + name: package_info_plus + sha256: "88bc797f44a94814f2213db1c9bd5badebafdfb8290ca9f78d4b9ee2a3db4d79" + url: "https://pub.dev" + source: hosted + version: "5.0.1" + package_info_plus_platform_interface: + dependency: transitive + description: + name: package_info_plus_platform_interface + sha256: "9bc8ba46813a4cc42c66ab781470711781940780fd8beddd0c3da62506d3a6c6" + url: "https://pub.dev" + source: hosted + version: "2.0.1" path: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index af0f51a3..841f6df5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -79,6 +79,7 @@ dependencies: app_settings: ^5.1.1 auto_start_flutter: ^0.1.1 pick_or_save: ^2.2.4 + package_info_plus: ^5.0.1 dev_dependencies: flutter_test: @@ -111,6 +112,7 @@ flutter: # To add assets to your application, add an assets section, like this: assets: - assets/timezones.db + - assets/images/ # - images/a_dot_burr.jpeg # - images/a_dot_ham.jpeg