diff --git a/android/app/build.gradle b/android/app/build.gradle index d24368ef..08ef8d71 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -52,42 +52,6 @@ android { } defaultConfig { - // Map for the version code that gives each ABI a value. - - // // For per-density APKs, create a similar map: - // // ext.densityCodes = ['mdpi': 1, 'hdpi': 2, 'xhdpi': 3] - - - // // For each APK output variant, override versionCode with a combination of - // // ext.abiCodes * 1000 + variant.versionCode. In this example, variant.versionCode - // // is equal to defaultConfig.versionCode. If you configure product flavors that - // // define their own versionCode, variant.versionCode uses that value instead. - // project.android.applicationVariants.all { variant -> - - // // Assigns a different version code for each output APK - // // other than the universal APK. - // variant.outputs.each { output -> - - // // Stores the value of ext.abiCodes that is associated with the ABI for this variant. - // def baseAbiVersionCode = - // // Determines the ABI for this variant and returns the mapped value. - // project.ext.abiCodes.get(output.getFilter(OutputFile.ABI)) - - // // Because abiCodes.get() returns null for ABIs that are not mapped by ext.abiCodes, - // // the following code doesn't override the version code for universal APKs. - // // However, because you want universal APKs to have the lowest version code, - // // this outcome is desirable. - // if (baseAbiVersionCode != null) { - - // // Assigns the new version code to versionCodeOverride, which changes the - // // version code for only the output APK, not for the variant itself. Skipping - // // this step causes Gradle to use the value of variant.versionCode for the APK. - // output.versionCodeOverride = - // variant.versionCode * 10 + baseAbiVersionCode - // } - // } - // } - applicationId "com.vicolo.chrono" minSdkVersion 21 targetSdkVersion flutter.targetSdkVersion @@ -155,7 +119,3 @@ flutter { source '../..' } -dependencies { - // implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - // -} diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 63cec568..07d76efd 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -126,5 +126,28 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/vicolo/chrono/AnalogueClockWidgetProvider.kt b/android/app/src/main/kotlin/com/vicolo/chrono/AnalogueClockWidgetProvider.kt new file mode 100644 index 00000000..eba3e283 --- /dev/null +++ b/android/app/src/main/kotlin/com/vicolo/chrono/AnalogueClockWidgetProvider.kt @@ -0,0 +1,79 @@ +package com.vicolo.chrono + +import android.app.PendingIntent +import android.appwidget.AppWidgetManager +import android.appwidget.AppWidgetProvider +import android.content.Context +import android.content.Intent +import android.widget.RemoteViews +// import es.antonborri.home_widget.HomeWidgetBackgroundIntent +// import es.antonborri.home_widget.HomeWidgetLaunchIntent +// import es.antonborri.home_widget.HomeWidgetProvider + +class AnalogueClockWidgetProvider : AppWidgetProvider() { + override fun onUpdate( + context: Context, + appWidgetManager: AppWidgetManager, + appWidgetIds: IntArray, + ) { // Perform this loop procedure for each widget that belongs to this + // provider. + appWidgetIds.forEach { appWidgetId -> + // Create an Intent to launch ExampleActivity. + // Open App on Widget Click + val views = + RemoteViews(context.packageName, R.layout.analogue_clock_widget).apply { + // Open App on Widget Click + val pendingIntent: PendingIntent = + PendingIntent.getActivity( + // context = + context, + // requestCode = + 0, + // intent = + Intent(context, MainActivity::class.java), + // flags = + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE, + ) + // Swap Title Text by calling Dart Code in the Background + // setTextViewText(R.id.widget_title, widgetData.getString("title", null) + // ?: "No Title Set") + // val backgroundIntent = HomeWidgetBackgroundIntent.getBroadcast( + // context, + // Uri.parse("homeWidgetExample://titleClicked") + // ) + // setOnClickPendingIntent(R.id.widget_title, backgroundIntent) + // + // val message = widgetData.getString("message", null) + // setTextViewText(R.id.widget_message, message + // ?: "No Message Set") + // // Show Images saved with `renderFlutterWidget` + // val image = widgetData.getString("dashIcon", null) + // if (image != null) { + // setImageViewBitmap(R.id.widget_img, BitmapFactory.decodeFile(image)) + // setViewVisibility(R.id.widget_img, View.VISIBLE) + // } else { + // setViewVisibility(R.id.widget_img, View.GONE) + // } + // + // // Detect App opened via Click inside Flutter + // val pendingIntentWithData = HomeWidgetLaunchIntent.getActivity( + // context, + // MainActivity::class.java, + // Uri.parse("homeWidgetExample://message?message=$message")) + // setOnClickPendingIntent(R.id.widget_message, pendingIntentWithData) + } + // Get the layout for the widget and attach an onClick listener to + // the button. + // val views: RemoteViews = RemoteViews( + // context.packageName, + // R.layout.appwidget_provider_layout + // ).apply { + // setOnClickPendingIntent(R.id.button, pendingIntent) + // } + + // Tell the AppWidgetManager to perform an update on the current + // widget. + appWidgetManager.updateAppWidget(appWidgetId, views) + } + } +} diff --git a/android/app/src/main/kotlin/com/vicolo/chrono/DigitalClockDateWidgetProvider.kt b/android/app/src/main/kotlin/com/vicolo/chrono/DigitalClockDateWidgetProvider.kt new file mode 100644 index 00000000..03b9dd1f --- /dev/null +++ b/android/app/src/main/kotlin/com/vicolo/chrono/DigitalClockDateWidgetProvider.kt @@ -0,0 +1,91 @@ +package com.vicolo.chrono + +import android.app.PendingIntent +import android.appwidget.AppWidgetManager +import android.appwidget.AppWidgetProvider +import android.content.Context +import android.content.Intent +import android.widget.RemoteViews +import android.content.SharedPreferences +import es.antonborri.home_widget.HomeWidgetBackgroundIntent +import es.antonborri.home_widget.HomeWidgetLaunchIntent +import es.antonborri.home_widget.HomeWidgetProvider +import es.antonborri.home_widget.HomeWidgetPlugin +import android.util.Log + +class DigitalClockDateWidgetProvider : HomeWidgetProvider() { + override fun onUpdate( + context: Context, + appWidgetManager: AppWidgetManager, + appWidgetIds: IntArray, + widgetData: SharedPreferences, + ) { // Perform this loop procedure for each widget that belongs to this + // provider. + Log.d("TAG", "======================================YOO") + + appWidgetIds.forEach { appWidgetId -> + // Create an Intent to launch ExampleActivity. + // Open App on Widget Click + val views = + RemoteViews(context.packageName, R.layout.digital_clock_date_widget).apply { + // Open App on Widget Click + val pendingIntent: PendingIntent = + PendingIntent.getActivity( + // context = + context, + // requestCode = + 0, + // intent = + Intent(context, MainActivity::class.java), + // flags = + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE, + ) + val dateFormat = widgetData.getString("dateFormat", "EEE, d MMM") + val timeFormat = widgetData.getString("timeFormat", "HH:mm") + setCharSequence (R.id.widget_text_clock, "setFormat24Hour", timeFormat) + setCharSequence (R.id.widget_text_clock, "setFormat12Hour", timeFormat) + setCharSequence (R.id.widget_date, "setFormat24Hour", dateFormat) + setCharSequence (R.id.widget_date, "setFormat12Hour", dateFormat) + // Swap Title Text by calling Dart Code in the Background + // setTextViewText(R.id.widget_title, widgetData.getString("title", null) + // ?: "No Title Set") + // val backgroundIntent = HomeWidgetBackgroundIntent.getBroadcast( + // context, + // Uri.parse("homeWidgetExample://titleClicked") + // ) + // setOnClickPendingIntent(R.id.widget_title, backgroundIntent) + // + // val message = widgetData.getString("message", null) + // setTextViewText(R.id.widget_message, message + // ?: "No Message Set") + // // Show Images saved with `renderFlutterWidget` + // val image = widgetData.getString("dashIcon", null) + // if (image != null) { + // setImageViewBitmap(R.id.widget_img, BitmapFactory.decodeFile(image)) + // setViewVisibility(R.id.widget_img, View.VISIBLE) + // } else { + // setViewVisibility(R.id.widget_img, View.GONE) + // } + // + // // Detect App opened via Click inside Flutter + // val pendingIntentWithData = HomeWidgetLaunchIntent.getActivity( + // context, + // MainActivity::class.java, + // Uri.parse("homeWidgetExample://message?message=$message")) + // setOnClickPendingIntent(R.id.widget_message, pendingIntentWithData) + } + // Get the layout for the widget and attach an onClick listener to + // the button. + // val views: RemoteViews = RemoteViews( + // context.packageName, + // R.layout.appwidget_provider_layout + // ).apply { + // setOnClickPendingIntent(R.id.button, pendingIntent) + // } + + // Tell the AppWidgetManager to perform an update on the current + // widget. + appWidgetManager.updateAppWidget(appWidgetId, views) + } + } +} diff --git a/android/app/src/main/kotlin/com/vicolo/chrono/DigitalClockWidgetProvider.kt b/android/app/src/main/kotlin/com/vicolo/chrono/DigitalClockWidgetProvider.kt new file mode 100644 index 00000000..0c5f0c7b --- /dev/null +++ b/android/app/src/main/kotlin/com/vicolo/chrono/DigitalClockWidgetProvider.kt @@ -0,0 +1,130 @@ +package com.vicolo.chrono + +import android.app.PendingIntent +import android.appwidget.AppWidgetManager +import android.content.Context +import android.content.Intent +import android.content.SharedPreferences +import android.util.Log +import android.widget.RemoteViews +import android.graphics.Color +import es.antonborri.home_widget.HomeWidgetProvider +import android.view.ViewGroup.LayoutParams +import android.view.View +import android.util.TypedValue + +class DigitalClockWidgetProvider : HomeWidgetProvider() { + override fun onUpdate( + context: Context, + appWidgetManager: AppWidgetManager, + appWidgetIds: IntArray, + widgetData: SharedPreferences, + ) { // Perform this loop procedure for each widget that belongs to this + // provider. + Log.d("TAG", "Updating Digital Clock Widget"); + + appWidgetIds.forEach { appWidgetId -> + // Create an Intent to launch ExampleActivity. + // Open App on Widget Click + val views = + RemoteViews(context.packageName, R.layout.digital_clock_widget).apply { + // Open App on Widget Click + val pendingIntent: PendingIntent = + PendingIntent.getActivity( + // context = + context, + // requestCode = + 0, + // intent = + Intent(context, MainActivity::class.java), + // flags = + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE, + ) + val dateFormat = widgetData.getString("dateFormat", "EEE, d MMM") + val timeFormat = widgetData.getString("timeFormat", "HH:mm") + val dateSize = widgetData.getInt("dateSize", 25) + val timeSize = widgetData.getInt("timeSize", 100) + val textColor = widgetData.getString("textColor", "#FFFFFF") + // val shadowColor = widgetData.getString("shadowColor", "#000000") + // val shadowElevation = widgetData.getFloat("shadowElevation", 1.0f) + // val shadowBlur = widgetData.getFloat("shadowBlur", 1.0f) + val showDate = widgetData.getBoolean("showDate", true) + + setCharSequence(R.id.widget_text_clock, "setFormat24Hour", timeFormat) + setCharSequence(R.id.widget_text_clock, "setFormat12Hour", timeFormat) + setCharSequence(R.id.widget_date, "setFormat24Hour", "EEE, d MMM") + setCharSequence(R.id.widget_date, "setFormat12Hour", "EEE, d MMM") + setColorInt(R.id.widget_text_clock, "setTextColor", Color.parseColor(textColor), Color.parseColor(textColor)) + setColorInt(R.id.widget_date, "setTextColor", Color.parseColor(textColor), Color.parseColor(textColor)) + // setFloat(R.id.widget_text_clock, "setTextSize", timeSize.toFloat()) + // setFloat(R.id.widget_date, "setTextSize", dateSize.toFloat()) + setViewLayoutHeight(R.id.widget_text_clock, timeSize.toFloat(), TypedValue.COMPLEX_UNIT_SP) + setViewLayoutHeight(R.id.widget_date, dateSize.toFloat(), TypedValue.COMPLEX_UNIT_SP) + setViewVisibility(R.id.widget_date, if(showDate) View.VISIBLE else View.GONE) + // + // R.layout.digital_clock_widget.findViewById(R.id.widget_text_clock).apply { + // val param = + // LinearLayout.LayoutParams( + // LayoutParams.MATCH_PARENT, + // LayoutParams.MATCH_PARENT, + // timeSize, + // ) + // setLayoutParams(param) + // setShadowLayer(shadowBlur, 0f, shadowElevation, shadowColor) + // } + // + // R.layout.digital_clock_widget.findViewById(R.id.widget_date).apply { + // val param = + // LinearLayout.LayoutParams( + // LayoutParams.MATCH_PARENT, + // LayoutParams.MATCH_PARENT, + // dateSize, + // ) + // setLayoutParams(param) + // setTextColor(textColor) + // setShadowLayer(shadowBlur, 0f, shadowElevation, shadowColor) + // } + + // Swap Title Text by calling Dart Code in the Background + // setTextViewText(R.id.widget_title, widgetData.getString("title", null) + // ?: "No Title Set") + // val backgroundIntent = HomeWidgetBackgroundIntent.getBroadcast( + // context, + // Uri.parse("homeWidgetExample://titleClicked") + // ) + // setOnClickPendingIntent(R.id.widget_title, backgroundIntent) + // + // val message = widgetData.getString("message", null) + // setTextViewText(R.id.widget_message, message + // ?: "No Message Set") + // // Show Images saved with `renderFlutterWidget` + // val image = widgetData.getString("dashIcon", null) + // if (image != null) { + // setImageViewBitmap(R.id.widget_img, BitmapFactory.decodeFile(image)) + // setViewVisibility(R.id.widget_img, View.VISIBLE) + // } else { + // setViewVisibility(R.id.widget_img, View.GONE) + // } + // + // // Detect App opened via Click inside Flutter + // val pendingIntentWithData = HomeWidgetLaunchIntent.getActivity( + // context, + // MainActivity::class.java, + // Uri.parse("homeWidgetExample://message?message=$message")) + // setOnClickPendingIntent(R.id.widget_message, pendingIntentWithData) + } + // Get the layout for the widget and attach an onClick listener to + // the button. + // val views: RemoteViews = RemoteViews( + // context.packageName, + // R.layout.appwidget_provider_layout + // ).apply { + // setOnClickPendingIntent(R.id.button, pendingIntent) + // } + + // Tell the AppWidgetManager to perform an update on the current + // widget. + appWidgetManager.updateAppWidget(appWidgetId, views) + } + } +} diff --git a/android/app/src/main/res/layout/analogue_clock_widget.xml b/android/app/src/main/res/layout/analogue_clock_widget.xml new file mode 100644 index 00000000..8f85f743 --- /dev/null +++ b/android/app/src/main/res/layout/analogue_clock_widget.xml @@ -0,0 +1,32 @@ + + + + + + diff --git a/android/app/src/main/res/layout/digital_clock_date_widget.xml b/android/app/src/main/res/layout/digital_clock_date_widget.xml new file mode 100644 index 00000000..e0194f67 --- /dev/null +++ b/android/app/src/main/res/layout/digital_clock_date_widget.xml @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/res/layout/digital_clock_widget.xml b/android/app/src/main/res/layout/digital_clock_widget.xml new file mode 100644 index 00000000..e587fbd4 --- /dev/null +++ b/android/app/src/main/res/layout/digital_clock_widget.xml @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/res/xml/analogue_clock_widget.xml b/android/app/src/main/res/xml/analogue_clock_widget.xml new file mode 100644 index 00000000..631b3554 --- /dev/null +++ b/android/app/src/main/res/xml/analogue_clock_widget.xml @@ -0,0 +1,12 @@ + + + diff --git a/android/app/src/main/res/xml/digital_clock_date_widget.xml b/android/app/src/main/res/xml/digital_clock_date_widget.xml new file mode 100644 index 00000000..b5f74582 --- /dev/null +++ b/android/app/src/main/res/xml/digital_clock_date_widget.xml @@ -0,0 +1,12 @@ + + + diff --git a/android/app/src/main/res/xml/digital_clock_widget.xml b/android/app/src/main/res/xml/digital_clock_widget.xml new file mode 100644 index 00000000..4f340999 --- /dev/null +++ b/android/app/src/main/res/xml/digital_clock_widget.xml @@ -0,0 +1,12 @@ + + + diff --git a/android/build.gradle b/android/build.gradle index e0f6c98a..abc3b441 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -3,18 +3,6 @@ allprojects { google() mavenCentral() } - - // subprojects { - // afterEvaluate { project -> - // if (project.hasProperty('android')) { - // project.android { - // if (namespace == null) { - // namespace project.group - // } - // } - // } - // } - // } } rootProject.buildDir = '../build' diff --git a/lib/alarm/data/alarm_settings_schema.dart b/lib/alarm/data/alarm_settings_schema.dart index 3ce22a6d..d6a23c40 100644 --- a/lib/alarm/data/alarm_settings_schema.dart +++ b/lib/alarm/data/alarm_settings_schema.dart @@ -14,8 +14,11 @@ 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'; 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'; import 'package:clock_app/settings/types/setting_group.dart'; @@ -153,7 +156,18 @@ SettingGroup alarmSettingsSchema = SettingGroup( onChange: (context, index) { RingtonePlayer.stop(); }, - + actions: [ + MenuAction( + "Add", + (context) async { + await Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => const RingtonesScreen()), + ); + }, + Icons.add, + ), + ], // shouldCloseOnSelect: false, ), SelectSetting( @@ -278,6 +292,17 @@ SettingGroup alarmSettingsSchema = SettingGroup( (context) => AppLocalizations.of(context)!.tagsSetting, getTagOptions, defaultValue: [], + actions: [ + MenuAction( + "Add", + (context) async { + await Navigator.of(context).push( + MaterialPageRoute(builder: (context) => const TagsScreen()), + ); + }, + Icons.add, + ), + ], ), // ListSetting() diff --git a/lib/alarm/logic/alarm_isolate.dart b/lib/alarm/logic/alarm_isolate.dart index 272a0b71..332cd03c 100644 --- a/lib/alarm/logic/alarm_isolate.dart +++ b/lib/alarm/logic/alarm_isolate.dart @@ -8,7 +8,6 @@ import 'package:clock_app/system/logic/initialize_isolate.dart'; import 'package:clock_app/timer/types/time_duration.dart'; import 'package:clock_app/timer/types/timer.dart'; import 'package:flutter/foundation.dart'; -import 'package:get_storage/get_storage.dart'; import 'package:clock_app/alarm/logic/schedule_alarm.dart'; import 'package:clock_app/alarm/logic/update_alarms.dart'; import 'package:clock_app/alarm/types/alarm.dart'; @@ -19,6 +18,8 @@ import 'package:clock_app/alarm/utils/alarm_id.dart'; import 'package:clock_app/common/utils/time_of_day.dart'; import 'package:clock_app/timer/logic/update_timers.dart'; import 'package:clock_app/timer/utils/timer_id.dart'; +import 'package:flutter/services.dart'; +import 'package:receive_intent/receive_intent.dart'; const String stopAlarmPortName = "stopAlarmPort"; const String updatePortName = "updatePort"; @@ -51,6 +52,16 @@ void triggerScheduledNotification(int scheduleId, Json params) async { stopScheduledNotification(message); }); + try { + final receivedIntent = await ReceiveIntent.getInitialIntent(); + print("reeeeeeeeeeeeeeeeeeeeeeeeeee ${receivedIntent}"); + // Validate receivedIntent and warn the user, if it is not correct, + // but keep in mind it could be `null` or "empty"(`receivedIntent.isNull`). + } on PlatformException { + // Handle exception + } + + if (notificationType == ScheduledNotificationType.alarm) { triggerAlarm(scheduleId, params); } else if (notificationType == ScheduledNotificationType.timer) { @@ -104,8 +115,6 @@ void triggerAlarm(int scheduleId, Json params) async { return; } - GetStorage().write("fullScreenNotificationRecentlyShown", true); - // Pause any currently ringing timers. We will continue them after the alarm // is dismissed if (RingingManager.isTimerRinging) { @@ -168,9 +177,6 @@ void triggerTimer(int scheduleId, Json params) async { await updateTimers("triggerTimer(): Updating all timers on trigger"); - // Notify the front-end to update the timers - GetStorage().write("fullScreenNotificationRecentlyShown", true); - // Pause any currently ringing alarms. We will continue them after the timer // is dismissed if (RingingManager.isAlarmRinging) { diff --git a/lib/alarm/widgets/alarm_card.dart b/lib/alarm/widgets/alarm_card.dart index 3b71298a..928a6f94 100644 --- a/lib/alarm/widgets/alarm_card.dart +++ b/lib/alarm/widgets/alarm_card.dart @@ -207,11 +207,11 @@ class _AlarmCardState extends State { getDeletePopupAction(context, widget.onPressDelete), getDuplicatePopupAction(context, widget.onPressDuplicate), if (widget.alarm.canBeSkipped) - PopupAction( + MenuAction( widget.alarm.shouldSkipNextAlarm ? AppLocalizations.of(context)!.cancelSkipAlarmButton : AppLocalizations.of(context)!.skipAlarmButton, - () { + (context) { if (widget.alarm.shouldSkipNextAlarm) { widget.onSkipChange(false); } else { diff --git a/lib/app.dart b/lib/app.dart index b1caa69f..8d88e18d 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -1,6 +1,8 @@ import 'package:awesome_notifications/awesome_notifications.dart'; import 'package:clock_app/alarm/screens/alarm_notification_screen.dart'; +import 'package:clock_app/clock/types/time.dart'; import 'package:clock_app/common/data/app_info.dart'; +import 'package:clock_app/common/utils/time_format.dart'; import 'package:clock_app/l10n/language_local.dart'; import 'package:clock_app/navigation/data/route_observer.dart'; import 'package:clock_app/navigation/screens/nav_scaffold.dart'; @@ -19,11 +21,13 @@ import 'package:clock_app/theme/theme.dart'; import 'package:clock_app/theme/types/style_theme.dart'; import 'package:clock_app/theme/utils/color_scheme.dart'; import 'package:clock_app/timer/screens/timer_notification_screen.dart'; +import 'package:clock_app/widgets/logic/update_widgets.dart'; import 'package:dynamic_color/dynamic_color.dart'; import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; import 'package:get_storage/get_storage.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:home_widget/home_widget.dart'; class App extends StatefulWidget { const App({super.key}); @@ -59,22 +63,27 @@ class _AppState extends State { void initState() { super.initState(); + // HomeWidget.updateWidget( + // androidName: 'DigitalClockWidgetProvider', + // ); + setDigitalClockWidgetData(context); + NotificationController.setListeners(); _appearanceSettings = appSettings.getGroup("Appearance"); _colorSettings = _appearanceSettings.getGroup("Colors"); _styleSettings = _appearanceSettings.getGroup("Style"); _generalSettings = appSettings.getGroup("General"); - _animationSpeedSetting = _generalSettings - .getGroup("Animations") - .getSetting("Animation Speed"); + _animationSpeedSetting = + _generalSettings.getGroup("Animations").getSetting("Animation Speed"); _animationSpeedSetting.addListener(setAnimationSpeed); + setAnimationSpeed(_animationSpeedSetting.value); } void setAnimationSpeed(dynamic speed) { // setState(() { - timeDilation = 1 / speed; + timeDilation = 1 / speed; // }); } diff --git a/lib/common/logic/show_select.dart b/lib/common/logic/show_select.dart index d6d8d159..b060d6c8 100644 --- a/lib/common/logic/show_select.dart +++ b/lib/common/logic/show_select.dart @@ -1,14 +1,18 @@ +import 'package:clock_app/common/types/popup_action.dart'; import 'package:clock_app/common/types/select_choice.dart'; import 'package:clock_app/common/widgets/fields/select_field/select_bottom_sheet.dart'; import 'package:flutter/material.dart'; Future showSelectBottomSheet( - BuildContext context, void Function(List? indices) onChanged, - {required bool multiSelect, - required String title, - required String? description, - required List choices, - required List initialSelectedIndices}) async { + BuildContext context, + void Function(List? indices) onChanged, { + required bool multiSelect, + required String title, + required String? description, + required List Function() getChoices, + required List Function() getCurrentSelectedIndices, + List actions = const [], +}) async { List? selectedIndices; await showModalBottomSheet>( @@ -16,7 +20,8 @@ Future showSelectBottomSheet( isScrollControlled: true, enableDrag: true, builder: (BuildContext context) { - List currentSelectedIndices = initialSelectedIndices; + List currentSelectedIndices = getCurrentSelectedIndices(); + List choices = getChoices(); return StatefulBuilder( builder: (BuildContext context, StateSetter setState) { void handleSelect(List indices) { @@ -34,8 +39,7 @@ Future showSelectBottomSheet( } else { if (indices.length == 1) { currentSelectedIndices = [indices[0]]; - } - else{ + } else { debugPrint("Too many indices"); } } @@ -53,6 +57,11 @@ Future showSelectBottomSheet( currentSelectedIndices: currentSelectedIndices, onSelect: handleSelect, multiSelect: multiSelect, + actions: actions, + reload: () => setState(() { + choices = getChoices(); + currentSelectedIndices = getCurrentSelectedIndices(); + }), ); }, ); diff --git a/lib/common/types/popup_action.dart b/lib/common/types/popup_action.dart index 115b0862..9b994122 100644 --- a/lib/common/types/popup_action.dart +++ b/lib/common/types/popup_action.dart @@ -1,10 +1,10 @@ import 'package:flutter/material.dart'; -class PopupAction { +class MenuAction { IconData icon; String name; - Function action; + Function(BuildContext context) action; Color? color; - PopupAction(this.name, this.action, this.icon, [this.color]); + MenuAction(this.name, this.action, this.icon, [this.color]); } diff --git a/lib/common/utils/popup_action.dart b/lib/common/utils/popup_action.dart index 7e166c8f..f3776d56 100644 --- a/lib/common/utils/popup_action.dart +++ b/lib/common/utils/popup_action.dart @@ -3,11 +3,11 @@ import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; -PopupAction getDeletePopupAction(BuildContext context, Function callback) { - return PopupAction(AppLocalizations.of(context)!.deleteButton, callback, Icons.delete_rounded, +MenuAction getDeletePopupAction(BuildContext context, void Function() callback) { + return MenuAction(AppLocalizations.of(context)!.deleteButton, (context) => callback(), Icons.delete_rounded, Theme.of(context).colorScheme.error); } -PopupAction getDuplicatePopupAction(BuildContext context, Function callback) { - return PopupAction(AppLocalizations.of(context)!.duplicateButton, callback, Icons.copy_rounded); +MenuAction getDuplicatePopupAction(BuildContext context, void Function() callback) { + return MenuAction(AppLocalizations.of(context)!.duplicateButton, (context)=>callback, Icons.copy_rounded); } diff --git a/lib/common/widgets/card_edit_menu.dart b/lib/common/widgets/card_edit_menu.dart index 4ba40006..efa2432d 100644 --- a/lib/common/widgets/card_edit_menu.dart +++ b/lib/common/widgets/card_edit_menu.dart @@ -9,7 +9,7 @@ class CardEditMenu extends StatelessWidget { required this.actions, }); - final List actions; + final List actions; // final GlobalKey _buttonKey = GlobalKey(); List> getItems() { @@ -24,10 +24,10 @@ class CardEditMenu extends StatelessWidget { return items; } - void onSelected(String action) { + void onSelected(BuildContext context, String action) { for (var item in actions) { if (item.name == action) { - item.action(); + item.action(context); } } } @@ -43,7 +43,7 @@ class CardEditMenu extends StatelessWidget { color: colorScheme.onSurface, ), padding: EdgeInsets.zero, - onSelected: onSelected, + onSelected: (action) => onSelected(context, action), itemBuilder: (BuildContext context) => getItems(), ); } diff --git a/lib/common/widgets/color_picker/picker_selector.dart b/lib/common/widgets/color_picker/picker_selector.dart index cdfe5219..eb520e88 100644 --- a/lib/common/widgets/color_picker/picker_selector.dart +++ b/lib/common/widgets/color_picker/picker_selector.dart @@ -51,7 +51,7 @@ class PickerSelector extends StatelessWidget { }, options: options.where((option) => pickers[option.value]!).toList(), square: false, - innerPadding: 16, + innerPadding: 12, ), ), ); diff --git a/lib/common/widgets/fields/color_bottom_sheet.dart b/lib/common/widgets/fields/color_bottom_sheet.dart index 9cc98718..45efe10b 100644 --- a/lib/common/widgets/fields/color_bottom_sheet.dart +++ b/lib/common/widgets/fields/color_bottom_sheet.dart @@ -10,12 +10,14 @@ class ColorBottomSheet extends StatefulWidget { this.description, required this.value, required this.onChange, + this.enableOpacity = false, }); final String title; final String? description; final Color value; final void Function(Color)? onChange; + final bool enableOpacity; @override State createState() => _ColorBottomSheetState(); @@ -79,7 +81,7 @@ class _ColorBottomSheetState extends State { ), // const SizedBox(height: 16.0), ColorPicker( - wheelDiameter: MediaQuery.of(context).size.width - 8, + wheelDiameter: MediaQuery.of(context).size.width - (widget.enableOpacity ? 64 : 32), color: _color, onColorChanged: (Color color) => setState(() { _color = color; @@ -103,6 +105,9 @@ class _ColorBottomSheetState extends State { style: textTheme.titleSmall ?.copyWith(color: colorScheme.onSurface)), showColorCode: true, + enableOpacity: widget.enableOpacity, + opacityTrackHeight: 20, + opacityThumbRadius: 14, copyPasteBehavior: const ColorPickerCopyPasteBehavior( copyFormat: ColorPickerCopyFormat.hexRRGGBB), customPickerSelectBuilder: diff --git a/lib/common/widgets/fields/color_field.dart b/lib/common/widgets/fields/color_field.dart index cb2539f7..1719ff1b 100644 --- a/lib/common/widgets/fields/color_field.dart +++ b/lib/common/widgets/fields/color_field.dart @@ -3,15 +3,18 @@ import 'package:clock_app/common/widgets/fields/color_bottom_sheet.dart'; import 'package:flutter/material.dart'; class ColorField extends StatefulWidget { - const ColorField( - {super.key, - required this.value, - required this.onChange, - required this.name}); + const ColorField({ + super.key, + required this.value, + required this.onChange, + required this.name, + this.enableOpacity = false, + }); final String name; final Color value; final void Function(Color value)? onChange; + final bool enableOpacity; @override State createState() => _ColorFieldState(); @@ -31,6 +34,8 @@ class _ColorFieldState extends State { description: "", value: widget.value, onChange: widget.onChange, + enableOpacity: widget.enableOpacity, + ); }, ); diff --git a/lib/common/widgets/fields/select_field/select_bottom_sheet.dart b/lib/common/widgets/fields/select_field/select_bottom_sheet.dart index bffcd657..a19cdf19 100644 --- a/lib/common/widgets/fields/select_field/select_bottom_sheet.dart +++ b/lib/common/widgets/fields/select_field/select_bottom_sheet.dart @@ -1,12 +1,13 @@ import 'package:clock_app/common/types/file_item.dart'; +import 'package:clock_app/common/types/popup_action.dart'; import 'package:clock_app/common/types/select_choice.dart'; import 'package:clock_app/common/widgets/fields/select_field/option_cards/audio_option_card.dart'; import 'package:clock_app/common/widgets/fields/select_field/option_cards/color_option_card.dart'; import 'package:clock_app/common/widgets/fields/select_field/option_cards/text_option_card.dart'; +import 'package:clock_app/icons/flux_icons.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; - class SelectBottomSheet extends StatelessWidget { const SelectBottomSheet({ super.key, @@ -15,7 +16,9 @@ class SelectBottomSheet extends StatelessWidget { required this.choices, required this.currentSelectedIndices, required this.onSelect, + this.actions = const [], this.multiSelect = false, + this.reload, }); final String title; @@ -24,6 +27,8 @@ class SelectBottomSheet extends StatelessWidget { final List currentSelectedIndices; final bool multiSelect; final void Function(List) onSelect; + final List actions; + final Function? reload; Widget _getOptionCard() { if (choices[0].value is Color) { @@ -103,15 +108,33 @@ class SelectBottomSheet extends StatelessWidget { ), const SizedBox(height: 12.0), Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), + padding: const EdgeInsets.symmetric(horizontal: 20.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( - title, - style: textTheme.titleMedium?.copyWith( - color: colorScheme.onSurface.withOpacity(0.6)), - textAlign: TextAlign.center, + Row( + children: [ + // Expanded(child: Container()), + if (actions.isNotEmpty) const SizedBox(width: 8), + Expanded( + child: Text( + title, + style: textTheme.titleMedium?.copyWith( + color: colorScheme.onSurface.withOpacity(0.6)), + textAlign: actions.isEmpty ? TextAlign.center : null, + ), + ), + for (var action in actions) + IconButton( + icon: Icon(action.icon, + color: action.color ?? colorScheme.primary), + onPressed: () async { + // Navigator.pop(context, currentSelectedIndices); + await action.action(context); + reload?.call(); + }, + ), + ], ), if (description != null) const SizedBox(height: 8.0), if (description != null) @@ -123,37 +146,55 @@ class SelectBottomSheet extends StatelessWidget { ], ), ), - // const SizedBox(height: 16.0), + // Row( + // children: [ + // Icon(FluxIcons.add), + // Text(AppLocalizations.of(context)!.addButton, + // style: textTheme.labelMedium + // ?.copyWith(color: colorScheme.primary)), + // + // ], + // ), + const SizedBox(height: 12.0), Flexible( child: _getOptionCard(), ), // if (multiSelect) const SizedBox(height: 8.0), if (multiSelect) Padding( - padding: const EdgeInsets.only(left: 16.0, right:16.0, bottom: 4.0), - child: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Row( + padding: + const EdgeInsets.only(left: 16.0, right: 16.0, bottom: 4.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - IconButton( - onPressed: () { - onSelect([]); - }, - icon: Icon(Icons.clear_rounded, color: colorScheme.primary), - ), - IconButton( - onPressed: () { - onSelect([for (var i = 0; i < choices.length; i += 1) i]); - }, - icon: Icon(Icons.select_all_rounded, color: colorScheme.primary), + Row( + children: [ + IconButton( + onPressed: () { + onSelect([]); + }, + icon: Icon(Icons.clear_rounded, + color: colorScheme.primary), + ), + IconButton( + onPressed: () { + onSelect([ + for (var i = 0; i < choices.length; i += 1) i + ]); + }, + icon: Icon(Icons.select_all_rounded, + color: colorScheme.primary), + ), + ], ), - ], - ), - TextButton(onPressed: (){ - Navigator.of(context).pop(); - }, child: Text(AppLocalizations.of(context)!.saveButton, - style: textTheme.labelMedium?.copyWith( - color:colorScheme.primary))), - ]), + TextButton( + onPressed: () { + Navigator.of(context).pop(); + }, + child: Text(AppLocalizations.of(context)!.saveButton, + style: textTheme.labelMedium + ?.copyWith(color: colorScheme.primary))), + ]), ) ], ), diff --git a/lib/common/widgets/fields/select_field/select_field.dart b/lib/common/widgets/fields/select_field/select_field.dart index 8c66e97d..a3cb3ada 100644 --- a/lib/common/widgets/fields/select_field/select_field.dart +++ b/lib/common/widgets/fields/select_field/select_field.dart @@ -1,5 +1,6 @@ import 'package:clock_app/common/logic/show_select.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/select_choice.dart'; import 'package:clock_app/common/types/tag.dart'; import 'package:clock_app/common/widgets/fields/select_field/field_cards/audio_field_card.dart'; @@ -11,34 +12,38 @@ import 'package:flutter/material.dart'; class SelectField extends StatefulWidget { const SelectField({ super.key, - required this.selectedIndices, + required this.getSelectedIndices, required this.title, this.description, - required this.choices, + required this.getChoices, required this.onChanged, this.multiSelect = false, + this.actions = const [], }); - final List selectedIndices; + final List Function() getSelectedIndices; final String title; final String? description; final bool multiSelect; - final List choices; + final List Function() getChoices; final void Function(List indices) onChanged; + final List actions; @override State createState() => _SelectFieldState(); } class _SelectFieldState extends State { - Widget _getFieldCard() { + Widget _getFieldCard(List choices, List selectedIndices) { + + if (widget.multiSelect) { - List choices = - widget.selectedIndices.map((index) => widget.choices[index]).toList(); + List selectedChoices = + selectedIndices.map((index) => choices[index]).toList(); if (choices.isNotEmpty && choices[0].value.runtimeType == Tag) { return MultiSelectFieldCard( title: widget.title, - choices: choices + choices: selectedChoices .map((e) => SelectChoice( name: e.name, value: e.value, @@ -48,7 +53,7 @@ class _SelectFieldState extends State { } return MultiSelectFieldCard(title: widget.title, choices: choices); } else { - SelectChoice choice = widget.choices[widget.selectedIndices[0]]; + SelectChoice choice = choices[selectedIndices[0]]; if (choice.value is Color) { return ColorFieldCard( choice: SelectChoice( @@ -76,24 +81,31 @@ class _SelectFieldState extends State { @override Widget build(BuildContext context) { + List choices = widget.getChoices(); + List selectedIndices = widget.getSelectedIndices(); + void showSelect(List? selectedIndices) async { setState(() { - widget.onChanged(selectedIndices ?? widget.selectedIndices); + widget.onChanged(selectedIndices ?? widget.getSelectedIndices()); }); } return Material( color: Colors.transparent, child: InkWell( - onTap: () => showSelectBottomSheet(context, showSelect, - title: widget.title, - description: widget.description, - choices: widget.choices, - initialSelectedIndices: widget.selectedIndices, - multiSelect: widget.multiSelect), + onTap: () => showSelectBottomSheet( + context, + showSelect, + title: widget.title, + description: widget.description, + getChoices: widget.getChoices, + getCurrentSelectedIndices: widget.getSelectedIndices, + multiSelect: widget.multiSelect, + actions: widget.actions, + ), child: Padding( padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0), - child: _getFieldCard(), + child: _getFieldCard(choices, selectedIndices), ), ), ); diff --git a/lib/common/widgets/list/list_filter_chip.dart b/lib/common/widgets/list/list_filter_chip.dart index d0fb92ec..38bb2890 100644 --- a/lib/common/widgets/list/list_filter_chip.dart +++ b/lib/common/widgets/list/list_filter_chip.dart @@ -7,7 +7,6 @@ import 'package:clock_app/common/widgets/list/action_bottom_sheet.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; - class ListFilterChip extends StatelessWidget { const ListFilterChip({ super.key, @@ -86,7 +85,8 @@ class ListFilterActionChip extends StatelessWidget { child: Row( children: [ Padding( - padding: const EdgeInsets.only(left: 8.0, right: 6.0, top:6.0, bottom: 6.0), + padding: const EdgeInsets.only( + left: 8.0, right: 6.0, top: 6.0, bottom: 6.0), child: Icon( Icons.filter_list_rounded, color: colorScheme.onPrimary, @@ -133,10 +133,11 @@ class ListFilterSelectChip extends StatelessWidget { }, title: listFilter.displayName(context), description: "", - choices: listFilter.filters - .map((e) => SelectChoice(name: e.displayName(context), value: e.id)) + getChoices: () => listFilter.filters + .map((e) => + SelectChoice(name: e.displayName(context), value: e.id)) .toList(), - initialSelectedIndices: [listFilter.selectedIndex], + getCurrentSelectedIndices: () => [listFilter.selectedIndex], multiSelect: false); } @@ -199,10 +200,11 @@ class ListFilterMultiSelectChip extends StatelessWidget { }, title: listFilter.displayName(context), description: "", - choices: listFilter.filters - .map((e) => SelectChoice(name: e.displayName(context), value: e.id)) + getChoices: () => listFilter.filters + .map((e) => + SelectChoice(name: e.displayName(context), value: e.id)) .toList(), - initialSelectedIndices: selectedIndices, + getCurrentSelectedIndices: () => selectedIndices, multiSelect: true); } @@ -249,7 +251,8 @@ class ListSortChip extends StatelessWidget { const ListSortChip({ super.key, required this.sortOptions, - required this.onChange, required this.selectedIndex, + required this.onChange, + required this.selectedIndex, }); @override @@ -265,10 +268,11 @@ class ListSortChip extends StatelessWidget { }, title: AppLocalizations.of(context)!.sortGroup, description: "", - choices: sortOptions - .map((e) => SelectChoice(name: e.displayName(context), value: e.getLocalizedName)) + getChoices: () => sortOptions + .map((e) => SelectChoice( + name: e.displayName(context), value: e.getLocalizedName)) .toList(), - initialSelectedIndices: [selectedIndex], + getCurrentSelectedIndices: () => [selectedIndex], multiSelect: false); } @@ -282,17 +286,14 @@ class ListSortChip extends StatelessWidget { top: 8.0, bottom: 8.0, left: 16.0, right: 2.0), child: Text( "${AppLocalizations.of(context)!.sortGroup}${isFirstSelected ? "" : ": ${sortOptions[selectedIndex].displayName(context)}"}", - style: textTheme.headlineSmall?.copyWith( - color: colorScheme.onSurface - ), + style: textTheme.headlineSmall + ?.copyWith(color: colorScheme.onSurface), ), ), Padding( padding: const EdgeInsets.only(left: 2.0, right: 8.0), - child: Icon( - Icons.keyboard_arrow_down_rounded, - color:colorScheme.onSurface.withOpacity(0.6) - ), + child: Icon(Icons.keyboard_arrow_down_rounded, + color: colorScheme.onSurface.withOpacity(0.6)), ), ], ), diff --git a/lib/common/widgets/time_picker.dart b/lib/common/widgets/time_picker.dart index 2af00c74..a74ba332 100644 --- a/lib/common/widgets/time_picker.dart +++ b/lib/common/widgets/time_picker.dart @@ -20,7 +20,6 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; - // Examples can assume: // late BuildContext context; @@ -307,13 +306,13 @@ class _TitleBar extends StatelessWidget { }, title: setting.name, description: setting.displayDescription(context), - choices: setting.options + getChoices: () => setting.options .map((option) => SelectChoice( name: option.getLocalizedName(context), value: option.value, description: option.getDescription(context))) .toList(), - initialSelectedIndices: [setting.selectedIndex], + getCurrentSelectedIndices: () => [setting.selectedIndex], multiSelect: false, ); diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 562f0bbb..1ec02de0 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -606,6 +606,21 @@ "donorsDescription": "Our generous patreons", "@donorsDescription" : {}, "contributorsDescription" : "People who make this app possible", - "@contributorsDescription" : {} - + "@contributorsDescription" : {}, + "widgetsSettingGroup": "Widgets", + "@widgetsSettingGroup": {}, + "digitalClockSettingGroup": "Digital Clock", + "@digitalClockSettingGroup": {}, + "layoutSettingGroup": "Layout", + "@layoutSettingGroup": {}, + "timeSizeSetting": "Time Size", + "@timeSizeSetting": {}, + "dateSizeSetting": "Date Size", + "@dateSizeSetting": {}, + "textSettingGroup": "Text", + "@textSettingGroup": {}, + "showDateSetting": "ShowDate", + "@showDateSetting": {}, + "settingsTitle": "Settings", + "@settingsTitle": {} } diff --git a/lib/navigation/data/fullscreen_intent.dart b/lib/navigation/data/fullscreen_intent.dart new file mode 100644 index 00000000..faa0c3f9 --- /dev/null +++ b/lib/navigation/data/fullscreen_intent.dart @@ -0,0 +1 @@ +const fullscreenIntentKey = "fullscreen_intent"; diff --git a/lib/navigation/screens/nav_scaffold.dart b/lib/navigation/screens/nav_scaffold.dart index 644a532c..654fde84 100644 --- a/lib/navigation/screens/nav_scaffold.dart +++ b/lib/navigation/screens/nav_scaffold.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'package:clock_app/alarm/logic/new_alarm_snackbar.dart'; import 'package:clock_app/alarm/types/alarm.dart'; +import 'package:clock_app/common/data/app_info.dart'; import 'package:clock_app/common/utils/snackbar.dart'; import 'package:clock_app/icons/flux_icons.dart'; import 'package:clock_app/navigation/data/tabs.dart'; @@ -15,6 +16,7 @@ import 'package:clock_app/settings/types/setting.dart'; import 'package:clock_app/system/logic/handle_intents.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:home_widget/home_widget.dart'; import 'package:receive_intent/receive_intent.dart' as intent_handler; class NavScaffold extends StatefulWidget { @@ -119,13 +121,15 @@ class _NavScaffoldState extends State { return Scaffold( appBar: orientation == Orientation.portrait ? AppTopBar( - title: Text(tabs[_selectedTabIndex].title, - style: Theme.of(context).textTheme.titleMedium?.copyWith( - color: Theme.of(context) - .colorScheme - .onBackground - .withOpacity(0.6), - )), + title: Text( + tabs[_selectedTabIndex].title, + style: Theme.of(context).textTheme.titleMedium?.copyWith( + color: Theme.of(context) + .colorScheme + .onBackground + .withOpacity(0.6), + ), + ), actions: [ IconButton( onPressed: () { diff --git a/lib/navigation/types/app_visibility.dart b/lib/navigation/types/app_visibility.dart index d68ec1a7..069a7774 100644 --- a/lib/navigation/types/app_visibility.dart +++ b/lib/navigation/types/app_visibility.dart @@ -1,7 +1,8 @@ import 'dart:async'; +import 'package:clock_app/common/utils/list_storage.dart'; +import 'package:clock_app/navigation/data/fullscreen_intent.dart'; import 'package:flutter_fgbg/flutter_fgbg.dart'; -import 'package:get_storage/get_storage.dart'; class AppVisibility { static StreamSubscription? subscription; @@ -15,12 +16,11 @@ class AppVisibility { } static void initialize() { - if (GetStorage().read("fullScreenNotificationRecentlyShown") == - true) { - GetStorage().write("fullScreenNotificationRecentlyShown", false); - } else { + // if (loadTextFileSync(fullscreenIntentKey) == "true") { + // saveTextFile(fullscreenIntentKey, "false"); + // } else { setState(FGBGType.foreground); - } + // } subscription = FGBGEvents.stream.listen((event) { setState(event); diff --git a/lib/notifications/logic/notification_callbacks.dart b/lib/notifications/logic/notification_callbacks.dart index b56137a9..faacc9a3 100644 --- a/lib/notifications/logic/notification_callbacks.dart +++ b/lib/notifications/logic/notification_callbacks.dart @@ -1,13 +1,7 @@ import 'package:awesome_notifications/awesome_notifications.dart'; -import 'package:clock_app/alarm/logic/alarm_reminder_notifications.dart'; -import 'package:clock_app/alarm/logic/update_alarms.dart'; -import 'package:clock_app/alarm/types/alarm.dart'; -import 'package:clock_app/alarm/utils/alarm_id.dart'; -import 'package:clock_app/common/types/notification_type.dart'; import 'package:clock_app/notifications/data/notification_channel.dart'; import 'package:clock_app/notifications/types/fullscreen_notification_data.dart'; import 'package:clock_app/notifications/types/fullscreen_notification_manager.dart'; -import 'package:clock_app/settings/data/settings_schema.dart'; import 'package:clock_app/stopwatch/logic/update_stopwatch.dart'; import 'package:clock_app/system/logic/initialize_isolate.dart'; import 'package:clock_app/timer/logic/update_timers.dart'; diff --git a/lib/notifications/types/fullscreen_notification_manager.dart b/lib/notifications/types/fullscreen_notification_manager.dart index 7bce2bb1..86d12ee1 100644 --- a/lib/notifications/types/fullscreen_notification_manager.dart +++ b/lib/notifications/types/fullscreen_notification_manager.dart @@ -8,21 +8,25 @@ import 'package:clock_app/alarm/logic/alarm_isolate.dart'; import 'package:clock_app/alarm/logic/update_alarms.dart'; import 'package:clock_app/app.dart'; import 'package:clock_app/common/types/notification_type.dart'; +import 'package:clock_app/common/utils/list_storage.dart'; +import 'package:clock_app/navigation/data/fullscreen_intent.dart'; import 'package:clock_app/notifications/data/notification_channel.dart'; import 'package:clock_app/alarm/logic/schedule_alarm.dart'; import 'package:clock_app/navigation/types/app_visibility.dart'; import 'package:clock_app/navigation/types/routes.dart'; import 'package:clock_app/notifications/types/fullscreen_notification_data.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_fgbg/flutter_fgbg.dart'; import 'package:flutter_show_when_locked/flutter_show_when_locked.dart'; import 'package:get_storage/get_storage.dart'; import 'package:move_to_background/move_to_background.dart'; +import 'package:receive_intent/receive_intent.dart'; class AlarmNotificationManager { static const String _snoozeActionKey = "snooze"; static const String _dismissActionKey = "dismiss"; - static FGBGType _appVisibilityWhenCreated = FGBGType.foreground; + static FGBGType appVisibilityWhenCreated = FGBGType.foreground; static void showFullScreenNotification({ required ScheduledNotificationType type, @@ -98,22 +102,29 @@ class AlarmNotificationManager { static Future closeNotification(ScheduledNotificationType type) async { await removeNotification(type); - await GetStorage.init(); - // await LockScreenFlagManager.clearLockScreenFlags(); await FlutterShowWhenLocked().hide(); - // If we were on the alarm screen, pop it off the stack. Sometimes the system - // decides to show a heads up notification instead of a full screen one, so - // we can't always pop the top screen. - Routes.popIf(alarmNotificationData[type]?.route); - // If notification was created while app was in background, move app back // to background when we close the notification - if (_appVisibilityWhenCreated == FGBGType.background && + + if (appVisibilityWhenCreated == FGBGType.background && AppVisibility.state == FGBGType.foreground) { MoveToBackground.moveTaskToBack(); } - GetStorage().write("fullScreenNotificationRecentlyShown", false); + + // try { + // final receivedIntent = await ReceiveIntent.getInitialIntent(); + // print("reeeeeeeeeeeeeeeeeeeeeeeeeee ${receivedIntent}"); + // // Validate receivedIntent and warn the user, if it is not correct, + // // but keep in mind it could be `null` or "empty"(`receivedIntent.isNull`). + // } on PlatformException { + // // Handle exception + // } + + // If we were on the alarm screen, pop it off the stack. Sometimes the system + // decides to show a heads up notification instead of a full screen one, so + // we can't always pop the top screen. + Routes.popIf(alarmNotificationData[type]?.route); } static Future snoozeAlarm( @@ -149,7 +160,6 @@ class AlarmNotificationManager { break; } await closeNotification(type); - } static Future stopAlarm(int scheduleId, ScheduledNotificationType type, @@ -162,8 +172,7 @@ class AlarmNotificationManager { } static void handleNotificationCreated(ReceivedNotification notification) { - _appVisibilityWhenCreated = AppVisibility.state; - GetStorage().write("fullScreenNotificationRecentlyShown", false); + // _appVisibilityWhenCreated = AppVisibility.state; } static Future openNotificationScreen( @@ -197,7 +206,7 @@ class AlarmNotificationManager { (json.decode((payload['scheduleIds'])!) as List).cast(); if (scheduleIds.isEmpty) return; - if (tasksRequired && dismissType != AlarmDismissType.snooze){ + if (tasksRequired && dismissType != AlarmDismissType.snooze) { await openNotificationScreen(data, scheduleIds, tasksOnly: true, dismissType: dismissType); } else { @@ -223,7 +232,10 @@ class AlarmNotificationManager { break; default: + /* print("ahsan is the besttttttttttttttttttttt ${AppVisibility.state}"); */ + await openNotificationScreen(data, scheduleIds); + break; } } diff --git a/lib/settings/data/backup_settings_schema.dart b/lib/settings/data/backup_settings_schema.dart index 0e8c5a10..f34fcc90 100644 --- a/lib/settings/data/backup_settings_schema.dart +++ b/lib/settings/data/backup_settings_schema.dart @@ -6,6 +6,7 @@ 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:clock_app/widgets/logic/update_widgets.dart'; import 'package:flutter/material.dart'; import 'package:pick_or_save/pick_or_save.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; @@ -36,11 +37,12 @@ SettingGroup backupSettingsSchema = SettingGroup( (context) => AppLocalizations.of(context)!.importSettingsSetting, (context) async { loadBackupFile( - (data) { + (data) async { appSettings.loadValueFromJson(json.decode(data)); appSettings.callAllListeners(); App.refreshTheme(context); - appSettings.save(); + await appSettings.save(); + if (context.mounted) setDigitalClockWidgetData(context); }, ); }, diff --git a/lib/settings/data/general_settings_schema.dart b/lib/settings/data/general_settings_schema.dart index 9f46b98c..d15675a2 100644 --- a/lib/settings/data/general_settings_schema.dart +++ b/lib/settings/data/general_settings_schema.dart @@ -15,6 +15,7 @@ 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:clock_app/widgets/logic/update_widgets.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -32,6 +33,25 @@ SelectSettingOption _getDateSettingOption(String format) { format); } +final dateFormatOptions = [ + _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"), + _getDateSettingOption("d MMM yyyy"), + _getDateSettingOption("d MMMM yyyy"), +]; + enum SwipeAction { cardActions, switchTabs, @@ -70,35 +90,24 @@ SettingGroup generalSettingsSchema = SettingGroup( SelectSetting( "Date Format", (context) => AppLocalizations.of(context)!.dateFormatSetting, - [ - _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"), - ], + dateFormatOptions, getDescription: (context) => "How to display the dates", + onChange: (context, index) async { + // await HomeWidget.saveWidgetData( + // "dateFormat", dateFormatOptions[index].value); + // updateDigitalClockWidget(); + }, ), SelectSetting( "Time Format", (context) => AppLocalizations.of(context)!.timeFormatSetting, timeFormatOptions, getDescription: (context) => "12 or 24 hour time", - onChange: (context, index) { - saveTextFile("time_format_string", - getTimeFormatString(context, timeFormatOptions[index].value)); + onChange: (context, index) async { + String timeFormat = + getTimeFormatString(context, timeFormatOptions[index].value); + saveTextFile("time_format_string", timeFormat); + setDigitalClockWidgetData(context); }, ), SwitchSetting( diff --git a/lib/settings/data/settings_schema.dart b/lib/settings/data/settings_schema.dart index fd700233..b26375aa 100644 --- a/lib/settings/data/settings_schema.dart +++ b/lib/settings/data/settings_schema.dart @@ -6,6 +6,7 @@ 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_app_settings_schema.dart'; +import 'package:clock_app/settings/data/widget_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'; @@ -25,6 +26,7 @@ SettingGroup appSettings = SettingGroup( alarmAppSettingsSchema, timerAppSettingsSchema, stopwatchSettingsSchema, + widgetSettingSchema, accessibilitySettingsSchema, backupSettingsSchema, developerSettingsSchema, diff --git a/lib/settings/data/widget_settings_schema.dart b/lib/settings/data/widget_settings_schema.dart new file mode 100644 index 00000000..0f1456f7 --- /dev/null +++ b/lib/settings/data/widget_settings_schema.dart @@ -0,0 +1,117 @@ +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/widgets/logic/update_widgets.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:home_widget/home_widget.dart'; + +SettingGroup widgetSettingSchema = SettingGroup( + "Widgets", + (context) => AppLocalizations.of(context)!.widgetsSettingGroup, + [ + SettingGroup( + "Digital Clock", + (context) => AppLocalizations.of(context)!.digitalClockSettingGroup, + [ + SettingGroup( + "Layout", + (context) => AppLocalizations.of(context)!.layoutSettingGroup, + [ + SwitchSetting( + "Show Date", + (context) => AppLocalizations.of(context)!.showDateSetting, + true, + onChange: (context, value) async { + setDigitalClockWidgetData(context); + }, + ), + SliderSetting( + "Time Size", + (context) => AppLocalizations.of(context)!.timeSizeSetting, + 10, + 100, + 100, + onChange: (context, value) async { + setDigitalClockWidgetData(context); + }, + // snapLength: 1, + ), + SliderSetting( + "Date Size", + (context) => AppLocalizations.of(context)!.dateSizeSetting, + 10, + 100, + 25, + onChange: (context, value) async { + setDigitalClockWidgetData(context); + }, + enableConditions: [ + ValueCondition(["Show Date"], (value) => value == true) + ], + // snapLength: 1, + ), + ], + ), + SettingGroup( + "Text", + (context) => AppLocalizations.of(context)!.textSettingGroup, + [ + ColorSetting( + "Color", + (context) => AppLocalizations.of(context)!.colorSetting, + Colors.white, + // enableOpacity: true, + onChange: (context, value) async { + setDigitalClockWidgetData(context); + }, + ), + ], + ), + // SettingGroup( + // "Shadow", + // (context) => + // AppLocalizations.of(context)!.styleThemeShadowSettingGroup, + // [ + // SliderSetting( + // "Elevation", + // (context) => + // AppLocalizations.of(context)!.styleThemeElevationSetting, + // 0, + // 5, + // 1, + // onChange: (context, value) async { + // await HomeWidget.saveWidgetData( + // "shadowElevation", value); + // updateDigitalClockWidget(); + // }, + // ), + // SliderSetting( + // "Blur", + // (context) => AppLocalizations.of(context)!.styleThemeBlurSetting, + // 0, + // 5, + // 1, + // onChange: (context, value) async { + // await HomeWidget.saveWidgetData("shadowBlur", value); + // updateDigitalClockWidget(); + // }, + // ), + // ColorSetting( + // "Color", + // (context) => AppLocalizations.of(context)!.colorSetting, + // Colors.black, + // enableOpacity: true, + // onChange: (context, value) async { + // await HomeWidget.saveWidgetData( + // "shadowColor", '#${value.value.toRadixString(16)}'); + // updateDigitalClockWidget(); + // }, + // ), + // ], + // ), + ], + ), + ], + icon: Icons.widgets_outlined, +); diff --git a/lib/settings/logic/initialize_settings.dart b/lib/settings/logic/initialize_settings.dart index 91711a00..6f1ecdb2 100644 --- a/lib/settings/logic/initialize_settings.dart +++ b/lib/settings/logic/initialize_settings.dart @@ -26,16 +26,9 @@ import 'package:clock_app/timer/types/timer_preset.dart'; import 'package:flutter/foundation.dart'; import 'package:get_storage/get_storage.dart'; - Future _clearSettings() async { - // List timers = await loadList('timers'); - // List alarms = await loadList('alarms'); // We need to remove all scheduled alarms and timers before clearing the data // Otherwise, there would be no way to remove them in the future - - // for (var timer in timers) { - // timer.reset(); - // } await cancelAllAlarms(); await cancelAllTimers(); await GetStorage().erase(); @@ -59,13 +52,10 @@ Future initializeStorage([bool clearSettingsOnDebug = true]) async { // Comment this out after the preferences are cleared if (kDebugMode && clearSettingsOnDebug) await _clearSettings(); - bool? firstLaunch = GetStorage().read('first_launch'); - if (firstLaunch == null) { - // This is used to show alarm and timer edit animations - GetStorage().write('first_alarm_created', false); - GetStorage().write('first_timer_created', false); - } - + // bool? firstLaunch = GetStorage().read('first_launch'); + // if (firstLaunch == null) { + // } + // await initList("alarms", []); await initList("tags", defaultTags); await initList("alarm_events", []); diff --git a/lib/settings/screens/settings_group_screen.dart b/lib/settings/screens/settings_group_screen.dart index 44e967f2..e647bbcf 100644 --- a/lib/settings/screens/settings_group_screen.dart +++ b/lib/settings/screens/settings_group_screen.dart @@ -39,6 +39,7 @@ class _SettingGroupScreenState extends State { return Scaffold( appBar: SettingsTopBar( + title: widget.settingGroup.displayName(context), onSearch: (settingItems) { setState(() { searchedItems = settingItems; @@ -66,7 +67,8 @@ class _SettingGroupScreenState extends State { SettingPageLinkCard( setting: SettingPageLink( 'Restore default values', - (context) =>AppLocalizations.of(context)!.restoreSettingGroup, + (context) => AppLocalizations.of(context)! + .restoreSettingGroup, RestoreDefaultScreen( settingGroup: widget.settingGroup, onRestore: () async { diff --git a/lib/settings/types/setting.dart b/lib/settings/types/setting.dart index d840855c..a69d2e81 100644 --- a/lib/settings/types/setting.dart +++ b/lib/settings/types/setting.dart @@ -1,5 +1,6 @@ import 'package:clock_app/common/types/json.dart'; import 'package:clock_app/common/types/list_item.dart'; +import 'package:clock_app/common/types/popup_action.dart'; import 'package:clock_app/common/utils/json_serialize.dart'; import 'package:clock_app/common/utils/list_item.dart'; import 'package:clock_app/settings/types/setting_enable_condition.dart'; @@ -267,6 +268,8 @@ class NumberSetting extends Setting { } class ColorSetting extends Setting { + final bool enableOpacity; + ColorSetting( String name, String Function(BuildContext) getLocalizedName, @@ -274,6 +277,7 @@ class ColorSetting extends Setting { void Function(BuildContext, Color)? onChange, String Function(BuildContext) getDescription = defaultDescription, bool isVisual = true, + this.enableOpacity = false, List enableConditions = const [], List searchTags = const [], }) : super(name, getLocalizedName, getDescription, defaultValue, onChange, @@ -301,6 +305,7 @@ class ColorSetting extends Setting { enableConditions: enableConditions, isVisual: isVisual, searchTags: searchTags, + enableOpacity: enableOpacity, ); } } @@ -383,6 +388,7 @@ class SliderSetting extends Setting { class SelectSetting extends Setting { final List> _options; + final List actions; List> get options => _options; int get selectedIndex => _value; @@ -415,6 +421,7 @@ class SelectSetting extends Setting { bool isVisual = true, List enableConditions = const [], List searchTags = const [], + this.actions = const [], }) : super(name, getLocalizedName, getDescription, defaultValue, onChange, enableConditions, searchTags, isVisual); @@ -430,6 +437,7 @@ class SelectSetting extends Setting { enableConditions: enableConditions, isVisual: isVisual, searchTags: searchTags, + actions: actions, ); } } @@ -438,6 +446,7 @@ class SelectSetting extends Setting { // This is so that if the options changes, the value remains the same; class DynamicSelectSetting extends Setting { List> Function() optionsGetter; + final List actions; List> get options => optionsGetter(); @override dynamic get value => options[selectedIndex].value; @@ -453,6 +462,7 @@ class DynamicSelectSetting extends Setting { bool isVisual = true, List enableConditions = const [], List searchTags = const [], + this.actions = const [], }) : super(name, getLocalizedName, getDescription, defaultValue, onChange, enableConditions, searchTags, isVisual) { if (defaultValue != -1) { @@ -472,6 +482,7 @@ class DynamicSelectSetting extends Setting { enableConditions: enableConditions, isVisual: isVisual, searchTags: searchTags, + actions: actions, ); } @@ -517,6 +528,7 @@ class DynamicSelectSetting extends Setting { class MultiSelectSetting extends Setting> { final List> _options; + final List actions; List> get options => _options; List get selectedIndices => _value; @@ -552,6 +564,7 @@ class MultiSelectSetting extends Setting> { bool isVisual = true, List enableConditions = const [], List searchTags = const [], + this.actions = const [], }) : super(name, getLocalizedName, getDescription, defaultValue, onChange, enableConditions, searchTags, isVisual); @@ -567,6 +580,7 @@ class MultiSelectSetting extends Setting> { enableConditions: enableConditions, isVisual: isVisual, searchTags: searchTags, + actions: actions, ); } @@ -586,6 +600,7 @@ class MultiSelectSetting extends Setting> { // This is so that if the options changes, the value remains the same; class DynamicMultiSelectSetting extends Setting> { List> Function() optionsGetter; + final List actions; List> get options => optionsGetter(); @override dynamic get value { @@ -607,6 +622,7 @@ class DynamicMultiSelectSetting extends Setting> { bool isVisual = true, List enableConditions = const [], List searchTags = const [], + this.actions = const [], }) : super(name, getLocalizedName, getDescription, defaultValue, onChange, enableConditions, searchTags, isVisual) { if (!defaultValue.contains(-1)) { @@ -626,6 +642,7 @@ class DynamicMultiSelectSetting extends Setting> { enableConditions: enableConditions, isVisual: isVisual, searchTags: searchTags, + actions: actions, ); } diff --git a/lib/settings/widgets/color_setting_card.dart b/lib/settings/widgets/color_setting_card.dart index 87492d47..6fa68b51 100644 --- a/lib/settings/widgets/color_setting_card.dart +++ b/lib/settings/widgets/color_setting_card.dart @@ -24,6 +24,7 @@ class _ColorSettingCardState extends State { ColorField toggleCard = ColorField( name: widget.setting.displayName(context), value: widget.setting.value, + enableOpacity: widget.setting.enableOpacity, onChange: (value) { setState(() { widget.setting.setValue(context, value); diff --git a/lib/settings/widgets/dynamic_multi_select_setting_card.dart b/lib/settings/widgets/dynamic_multi_select_setting_card.dart index 34bf71b9..8eab05fe 100644 --- a/lib/settings/widgets/dynamic_multi_select_setting_card.dart +++ b/lib/settings/widgets/dynamic_multi_select_setting_card.dart @@ -26,10 +26,11 @@ class _DynamicMultiSelectSettingCardState @override Widget build(BuildContext context) { SelectField selectWidget = SelectField( - selectedIndices: widget.setting.selectedIndices, + getSelectedIndices: () => widget.setting.selectedIndices, title: widget.setting.name, multiSelect: true, - choices: widget.setting.options + actions: widget.setting.actions, + getChoices: () => widget.setting.options .map((option) => SelectChoice( name: option.getLocalizedName(context), value: option.value, diff --git a/lib/settings/widgets/dynamic_select_setting_card.dart b/lib/settings/widgets/dynamic_select_setting_card.dart index a0c5313a..2510e8cd 100644 --- a/lib/settings/widgets/dynamic_select_setting_card.dart +++ b/lib/settings/widgets/dynamic_select_setting_card.dart @@ -26,9 +26,10 @@ class _DynamicSelectSettingCardState @override Widget build(BuildContext context) { SelectField selectWidget = SelectField( - selectedIndices: [widget.setting.selectedIndex], + getSelectedIndices: () => [widget.setting.selectedIndex], title: widget.setting.displayName(context), - choices: widget.setting.options + actions: widget.setting.actions, + getChoices: () => widget.setting.options .map((option) => SelectChoice( name: option.getLocalizedName(context), value: option.value, diff --git a/lib/settings/widgets/multi_select_setting_card.dart b/lib/settings/widgets/multi_select_setting_card.dart index 1b9ee9f5..534ca77b 100644 --- a/lib/settings/widgets/multi_select_setting_card.dart +++ b/lib/settings/widgets/multi_select_setting_card.dart @@ -16,17 +16,19 @@ class MultiSelectSettingCard extends StatefulWidget { final bool showAsCard; @override - State> createState() => _MultiSelectSettingCardState(); + State> createState() => + _MultiSelectSettingCardState(); } class _MultiSelectSettingCardState extends State> { @override Widget build(BuildContext context) { SelectField selectWidget = SelectField( - selectedIndices: widget.setting.selectedIndices, + getSelectedIndices: () => widget.setting.selectedIndices, title: widget.setting.name, multiSelect: true, - choices: widget.setting.options + actions: widget.setting.actions, + getChoices: () => widget.setting.options .map((option) => SelectChoice( name: option.getLocalizedName(context), value: option.value, diff --git a/lib/settings/widgets/select_setting_card.dart b/lib/settings/widgets/select_setting_card.dart index 9232313b..8c5d2df6 100644 --- a/lib/settings/widgets/select_setting_card.dart +++ b/lib/settings/widgets/select_setting_card.dart @@ -23,9 +23,10 @@ class _SelectSettingCardState extends State> { @override Widget build(BuildContext context) { SelectField selectWidget = SelectField( - selectedIndices: [widget.setting.selectedIndex], + getSelectedIndices: () => [widget.setting.selectedIndex], title: widget.setting.displayName(context), - choices: widget.setting.options + actions: widget.setting.actions, + getChoices: () => widget.setting.options .map((option) => SelectChoice( name: option.getLocalizedName(context), value: option.value, diff --git a/lib/settings/widgets/setting_group_card.dart b/lib/settings/widgets/setting_group_card.dart index 3ae8873b..6f154e08 100644 --- a/lib/settings/widgets/setting_group_card.dart +++ b/lib/settings/widgets/setting_group_card.dart @@ -6,7 +6,6 @@ import 'package:clock_app/settings/types/setting_item.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; - class SettingGroupCard extends StatefulWidget { final SettingGroup settingGroup; final VoidCallback? checkDependentEnableConditions; @@ -87,8 +86,9 @@ class _SettingGroupCardState extends State { child: Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ - Icon(widget.settingGroup.icon, color: colorScheme.onBackground), - const SizedBox(width: 16), + if (widget.settingGroup.icon != null) + Icon(widget.settingGroup.icon, color: colorScheme.onBackground), + if (widget.settingGroup.icon != null) const SizedBox(width: 16), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, diff --git a/lib/settings/widgets/settings_top_bar.dart b/lib/settings/widgets/settings_top_bar.dart index 1c25ac23..63b4beb3 100644 --- a/lib/settings/widgets/settings_top_bar.dart +++ b/lib/settings/widgets/settings_top_bar.dart @@ -5,15 +5,18 @@ import 'package:fuzzywuzzy/fuzzywuzzy.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; - class SettingsTopBar extends StatefulWidget implements PreferredSizeWidget { @override Size get preferredSize => const Size(0, 56); const SettingsTopBar( - {super.key, required this.onSearch, this.showSearch = false}); + {super.key, + required this.onSearch, + this.showSearch = false, + required this.title}); final void Function(List settings) onSearch; + final String title; final bool showSearch; @override @@ -83,7 +86,13 @@ class _SettingsTopBarState extends State { ); } else { return AppTopBar( - title: Text("Settings", style: Theme.of(context).textTheme.titleMedium), + title: Text( + widget.title, + style: Theme.of(context).textTheme.titleMedium?.copyWith( + color: + Theme.of(context).colorScheme.onBackground.withOpacity(0.6), + ), + ), actions: [ if (widget.showSearch) IconButton( @@ -95,7 +104,7 @@ class _SettingsTopBarState extends State { icon: Icon( Icons.search, color: - Theme.of(context).colorScheme.onBackground.withOpacity(0.6), + Theme.of(context).colorScheme.onBackground, ), ) ], diff --git a/lib/system/logic/handle_intents.dart b/lib/system/logic/handle_intents.dart index d6b9219b..421115e3 100644 --- a/lib/system/logic/handle_intents.dart +++ b/lib/system/logic/handle_intents.dart @@ -4,6 +4,8 @@ import 'package:clock_app/alarm/types/alarm.dart'; import 'package:clock_app/alarm/types/schedules/weekly_alarm_schedule.dart'; import 'package:clock_app/common/types/notification_type.dart'; import 'package:clock_app/common/utils/list_storage.dart'; +import 'package:clock_app/navigation/types/app_visibility.dart'; +import 'package:clock_app/notifications/types/fullscreen_notification_manager.dart'; import 'package:clock_app/settings/types/listener_manager.dart'; import 'package:flutter/material.dart' hide Intent; import 'package:receive_intent/receive_intent.dart'; @@ -92,6 +94,10 @@ void handleIntent(Intent? receivedIntent, BuildContext context, Function(Alarm) break; case "android.intent.action.VIEW_TIMERS": break; + case "SELECT_NOTIFICATION": + AlarmNotificationManager.appVisibilityWhenCreated = AppVisibility.state; + // print("************************************** ${AppVisibility.state}"); + break; default: break; } diff --git a/lib/timer/data/timer_settings_schema.dart b/lib/timer/data/timer_settings_schema.dart index 3ac43a37..2b189dfd 100644 --- a/lib/timer/data/timer_settings_schema.dart +++ b/lib/timer/data/timer_settings_schema.dart @@ -3,8 +3,11 @@ import 'package:clock_app/audio/audio_channels.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'; import 'package:clock_app/settings/types/setting_group.dart'; @@ -36,6 +39,19 @@ SettingGroup timerSettingsSchema = SettingGroup( onChange: (context, index) { RingtonePlayer.stop(); }, + actions: [ + MenuAction( + "Add", + (context) async { + await Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => const RingtonesScreen()), + ); + }, + Icons.add, + ), + ], + // shouldCloseOnSelect: false, ), SelectSetting( @@ -84,6 +100,17 @@ SettingGroup timerSettingsSchema = SettingGroup( (context) => AppLocalizations.of(context)!.tagsSetting, getTagOptions, defaultValue: [], + actions: [ + MenuAction( + "Add", + (context) async { + await Navigator.of(context).push( + MaterialPageRoute(builder: (context) => const TagsScreen()), + ); + }, + Icons.add, + ), + ], ), ], ); diff --git a/lib/timer/logic/edit_duration_picker_mode.dart b/lib/timer/logic/edit_duration_picker_mode.dart index ff3ec827..d078582c 100644 --- a/lib/timer/logic/edit_duration_picker_mode.dart +++ b/lib/timer/logic/edit_duration_picker_mode.dart @@ -21,13 +21,13 @@ Future editDurationPickerMode( }, title: setting.name, description: setting.getDescription(context), - choices: setting.options + getChoices: () => setting.options .map((option) => SelectChoice( name: option.getLocalizedName(context), value: option.value, description: option.getDescription(context))) .toList(), - initialSelectedIndices: [setting.selectedIndex], + getCurrentSelectedIndices: () => [setting.selectedIndex], multiSelect: false, ); diff --git a/lib/timer/widgets/timer_card.dart b/lib/timer/widgets/timer_card.dart index 82f3e9d5..3008ec00 100644 --- a/lib/timer/widgets/timer_card.dart +++ b/lib/timer/widgets/timer_card.dart @@ -15,7 +15,8 @@ class TimerCard extends StatefulWidget { required this.onToggleState, required this.onPressDelete, required this.onPressDuplicate, - required this.onPressReset, required this.onPressAddTime, + required this.onPressReset, + required this.onPressAddTime, }); final ClockTimer timer; @@ -140,15 +141,15 @@ class _TimerCardState extends State { getDeletePopupAction(context, widget.onPressDelete), getDuplicatePopupAction(context, widget.onPressDuplicate), if (!widget.timer.isStopped) - PopupAction( + MenuAction( "Reset", - widget.onPressReset, + (context) => widget.onPressReset(), Icons.replay_rounded, ), if (!widget.timer.isStopped) - PopupAction( + MenuAction( '+${widget.timer.addLength.floor()}:00', - widget.onPressAddTime, + (context) => widget.onPressAddTime(), Icons.add_rounded, ) ]), diff --git a/lib/widgets/logic/update_widgets.dart b/lib/widgets/logic/update_widgets.dart new file mode 100644 index 00000000..d69c14d3 --- /dev/null +++ b/lib/widgets/logic/update_widgets.dart @@ -0,0 +1,45 @@ +import 'package:clock_app/common/utils/time_format.dart'; +import 'package:clock_app/settings/data/general_settings_schema.dart'; +import 'package:clock_app/settings/data/settings_schema.dart'; +import 'package:flutter/material.dart'; +import 'package:home_widget/home_widget.dart'; + +void setDigitalClockWidgetData(BuildContext context) async { + final digitalClockSettingGroup = + appSettings.getGroup('Widgets').getGroup('Digital Clock'); + final bool showDate = + digitalClockSettingGroup.getGroup('Layout').getSetting('Show Date').value; + final int timeSize = digitalClockSettingGroup + .getGroup('Layout') + .getSetting('Time Size') + .value + .round(); + final int dateSize = digitalClockSettingGroup + .getGroup('Layout') + .getSetting('Date Size') + .value + .round(); + final String textColor = + '#${digitalClockSettingGroup.getGroup('Text').getSetting('Color').value.value.toRadixString(16)}'; + final String timeFormat = getTimeFormatString(context, appSettings + .getGroup('General') + .getGroup('Display') + .getSetting('Time Format') + .value); + + await HomeWidget.saveWidgetData("timeFormat", timeFormat); + await HomeWidget.saveWidgetData('showDate', showDate); + await HomeWidget.saveWidgetData('timeSize', timeSize); + await HomeWidget.saveWidgetData('dateSize', dateSize); + await HomeWidget.saveWidgetData('textColor', textColor); + + updateDigitalClockWidget(); +} + +void updateDigitalClockWidget() { + HomeWidget.updateWidget( + androidName: 'DigitalClockWidgetProvider', + name: 'DigitalClockWidgetProvider', + qualifiedAndroidName: 'com.vicolo.chrono.DigitalClockWidgetProvider', + ); +} diff --git a/pubspec.lock b/pubspec.lock index 3257899e..457ce5dd 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -472,6 +472,15 @@ packages: url: "https://github.com/AhsanSarwar45/great_list_view" source: git version: "0.2.3" + home_widget: + dependency: "direct main" + description: + path: "." + ref: main + resolved-ref: "5788ac45f62bef72ff44c52cbd77dc1f9258f633" + url: "https://github.com/AhsanSarwar45/home_widget" + source: git + version: "0.5.0" html: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index b2e6de8e..af25ae43 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -69,6 +69,12 @@ dependencies: material_color_utilities: ^0.8.0 flutter_oss_licenses: ^3.0.2 locale_names: ^1.1.1 + # home_widget: ^0.5.0 + home_widget: + git: + url: https://github.com/AhsanSarwar45/home_widget + ref: main + dev_dependencies: flutter_test: diff --git a/test/common/widgets/fields/select_field_test.dart b/test/common/widgets/fields/select_field_test.dart index 274c8cef..ca305c56 100644 --- a/test/common/widgets/fields/select_field_test.dart +++ b/test/common/widgets/fields/select_field_test.dart @@ -146,9 +146,9 @@ Future _renderWidget(WidgetTester tester, supportedLocales: AppLocalizations.supportedLocales, home: Scaffold( body: SelectField( - selectedIndices: [selectedIndex], + getSelectedIndices: () => [selectedIndex], title: title, - choices: choices, + getChoices: () => choices, onChanged: onChanged ?? (_) {}, ), ),