From cfcae9d25556002af97e037a294091d2924b6058 Mon Sep 17 00:00:00 2001 From: Florian Fetz <63090558+Futsch1@users.noreply.github.com> Date: Sat, 18 Jan 2025 16:01:10 +0100 Subject: [PATCH] 147 customization to snooze (#436) * Add missing strings * Custom snooze implementation * Test for custom snooze * Bump version to v1.15.0 --- app/build.gradle.kts | 4 +- .../com/futsch1/medtimer/NotificationTest.kt | 33 +++++++- .../com/futsch1/medtimer/ActivityIntent.kt | 15 ++++ .../com/futsch1/medtimer/MainActivity.java | 5 +- .../futsch1/medtimer/helpers/DialogHelper.kt | 10 ++- .../futsch1/medtimer/overview/CustomSnooze.kt | 42 ++++++++++ .../medtimer/overview/VariableAmount.kt | 82 +++++++++---------- .../medtimer/reminders/Notifications.java | 13 ++- .../medtimer/reminders/ReminderProcessor.java | 10 +++ app/src/main/res/values-ta/strings.xml | 12 +++ app/src/main/res/values/arrays.xml | 2 + 11 files changed, 175 insertions(+), 53 deletions(-) create mode 100644 app/src/main/java/com/futsch1/medtimer/ActivityIntent.kt create mode 100644 app/src/main/java/com/futsch1/medtimer/overview/CustomSnooze.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index e62d296b..879f729c 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -23,8 +23,8 @@ android { minSdk = 28 multiDexEnabled = true targetSdk = 35 - versionCode = 94 - versionName = "1.14.0" + versionCode = 95 + versionName = "1.15.0" base.archivesName = "MedTimer" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" diff --git a/app/src/androidTest/java/com/futsch1/medtimer/NotificationTest.kt b/app/src/androidTest/java/com/futsch1/medtimer/NotificationTest.kt index 67463e87..2002de3b 100644 --- a/app/src/androidTest/java/com/futsch1/medtimer/NotificationTest.kt +++ b/app/src/androidTest/java/com/futsch1/medtimer/NotificationTest.kt @@ -28,7 +28,6 @@ import com.adevinta.android.barista.interaction.BaristaDialogInteractions.clickD import com.adevinta.android.barista.interaction.BaristaEditTextInteractions.writeTo import com.adevinta.android.barista.interaction.BaristaMenuClickInteractions.openMenu import com.adevinta.android.barista.interaction.BaristaSleepInteractions.sleep -import com.adevinta.android.barista.rule.flaky.AllowFlaky import com.futsch1.medtimer.AndroidTestHelper.MainMenu import com.futsch1.medtimer.AndroidTestHelper.navigateTo import org.hamcrest.Matchers.allOf @@ -181,7 +180,7 @@ class NotificationTest : BaseTestHelper() { } @Test - @AllowFlaky(attempts = 1) + //@AllowFlaky(attempts = 1) fun variableAmount() { val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) @@ -220,6 +219,35 @@ class NotificationTest : BaseTestHelper() { assertContains("Test variable amount again") } + @Test + //@AllowFlaky(attempts = 1) + fun customSnooze() { + val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) + + openMenu() + clickOn(R.string.tab_settings) + clickOn(R.string.dismiss_notification_action) + clickOn(R.string.snooze) + clickOn(R.string.snooze_duration) + clickOn(R.string.custom) + pressBack() + + AndroidTestHelper.createMedicine("Test med") + AndroidTestHelper.createIntervalReminder("1", 120) + + navigateTo(MainMenu.ANALYSIS) + waitAndDismissNotification(device, 2_000) + + device.wait(Until.findObject(By.displayId(android.R.id.input)), 2_000) + writeTo(android.R.id.input, "1") + clickDialogPositiveButton() + + device.openNotification() + sleep(2_000) + val notification = device.wait(Until.findObject(By.textContains("Test med")), 240_000) + internalAssert(notification != null) + } + private fun getNotificationText(): String { val s = InstrumentationRegistry.getInstrumentation().targetContext.getString(R.string.taken) return if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) { @@ -229,6 +257,7 @@ class NotificationTest : BaseTestHelper() { } } + private fun waitAndDismissNotification(device: UiDevice, timeout: Long = 2000) { device.openNotification() var notification = device.wait(Until.findObject(By.textContains("Test med")), timeout) diff --git a/app/src/main/java/com/futsch1/medtimer/ActivityIntent.kt b/app/src/main/java/com/futsch1/medtimer/ActivityIntent.kt new file mode 100644 index 00000000..30ae87ff --- /dev/null +++ b/app/src/main/java/com/futsch1/medtimer/ActivityIntent.kt @@ -0,0 +1,15 @@ +package com.futsch1.medtimer + +import android.content.Intent +import androidx.appcompat.app.AppCompatActivity +import com.futsch1.medtimer.overview.customSnoozeDialog +import com.futsch1.medtimer.overview.variableAmountDialog + +fun dispatch(activity: AppCompatActivity, intent: Intent) { + if (intent.action == "VARIABLE_AMOUNT") { + variableAmountDialog(activity, intent) + } + if (intent.action == "CUSTOM_SNOOZE") { + customSnoozeDialog(activity, intent) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/futsch1/medtimer/MainActivity.java b/app/src/main/java/com/futsch1/medtimer/MainActivity.java index 92e60017..87528826 100644 --- a/app/src/main/java/com/futsch1/medtimer/MainActivity.java +++ b/app/src/main/java/com/futsch1/medtimer/MainActivity.java @@ -20,7 +20,6 @@ import androidx.navigation.ui.NavigationUI; import androidx.preference.PreferenceManager; -import com.futsch1.medtimer.overview.VariableAmount; import com.google.android.material.bottomnavigation.BottomNavigationView; import java.util.List; @@ -54,7 +53,7 @@ protected void onCreate(Bundle savedInstanceState) { setupNavigation(); - new VariableAmount().process(this, this.getIntent()); + ActivityIntentKt.dispatch(this, this.getIntent()); } private void showIntro(SharedPreferences sharedPref) { @@ -110,7 +109,7 @@ protected void onResume() { @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); - new VariableAmount().process(this, intent); + ActivityIntentKt.dispatch(this, intent); } @Override diff --git a/app/src/main/java/com/futsch1/medtimer/helpers/DialogHelper.kt b/app/src/main/java/com/futsch1/medtimer/helpers/DialogHelper.kt index b7ca12b7..d8b30ca2 100644 --- a/app/src/main/java/com/futsch1/medtimer/helpers/DialogHelper.kt +++ b/app/src/main/java/com/futsch1/medtimer/helpers/DialogHelper.kt @@ -13,9 +13,10 @@ import com.google.android.material.textfield.TextInputLayout class DialogHelper(var context: Context) { var title: Int? = null var hint: Int? = null - var initialText: String? = null - var textSink: TextSink? = null - var cancelCallback: CancelCallback? = null + private var initialText: String? = null + private var textSink: TextSink? = null + private var cancelCallback: CancelCallback? = null + private var inputType: Int? = null fun interface TextSink { fun consumeText(text: String?) @@ -32,6 +33,8 @@ class DialogHelper(var context: Context) { fun cancelCallback(cancelCallback: CancelCallback) = apply { this.cancelCallback = cancelCallback } + fun inputType(inputType: Int) = apply { this.inputType = inputType } + fun show() { val textInputLayout = TextInputLayout(context) val editText = TextInputEditText(context) @@ -46,6 +49,7 @@ class DialogHelper(var context: Context) { editText.id = android.R.id.input initialText?.let(editText::setText) textInputLayout.addView(editText) + inputType?.let(editText::setInputType) val builder = AlertDialog.Builder(context) builder.setView(textInputLayout) diff --git a/app/src/main/java/com/futsch1/medtimer/overview/CustomSnooze.kt b/app/src/main/java/com/futsch1/medtimer/overview/CustomSnooze.kt new file mode 100644 index 00000000..d8fb095f --- /dev/null +++ b/app/src/main/java/com/futsch1/medtimer/overview/CustomSnooze.kt @@ -0,0 +1,42 @@ +package com.futsch1.medtimer.overview + +import android.content.Intent +import android.text.InputType +import androidx.appcompat.app.AppCompatActivity +import com.futsch1.medtimer.ActivityCodes.EXTRA_NOTIFICATION_ID +import com.futsch1.medtimer.ActivityCodes.EXTRA_REMINDER_EVENT_ID +import com.futsch1.medtimer.ActivityCodes.EXTRA_REMINDER_ID +import com.futsch1.medtimer.R +import com.futsch1.medtimer.helpers.DialogHelper +import com.futsch1.medtimer.reminders.NotificationAction +import com.futsch1.medtimer.reminders.ReminderProcessor + +fun customSnoozeDialog(activity: AppCompatActivity, intent: Intent) { + val reminderId: Int = intent.getIntExtra(EXTRA_REMINDER_ID, -1) + val reminderEventId: Int = intent.getIntExtra(EXTRA_REMINDER_EVENT_ID, -1) + val notificationId: Int = intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1) + + // Cancel a potential repeat alarm + NotificationAction.cancelPendingAlarms(activity, reminderEventId) + + DialogHelper(activity) + .title(R.string.snooze_duration) + .hint(R.string.minutes) + .initialText("") + .inputType(InputType.TYPE_NUMBER_FLAG_SIGNED) + .textSink { snoozeTime: String? -> + val snoozeTimeInt = snoozeTime?.toIntOrNull() + if (snoozeTimeInt != null) { + val snooze = ReminderProcessor.getSnoozeIntent( + activity, + reminderId, + reminderEventId, + notificationId, + snoozeTimeInt + ) + activity.sendBroadcast(snooze, "com.futsch1.medtimer.NOTIFICATION_PROCESSED") + } + } + .show() + +} diff --git a/app/src/main/java/com/futsch1/medtimer/overview/VariableAmount.kt b/app/src/main/java/com/futsch1/medtimer/overview/VariableAmount.kt index ee08c9b6..946cc205 100644 --- a/app/src/main/java/com/futsch1/medtimer/overview/VariableAmount.kt +++ b/app/src/main/java/com/futsch1/medtimer/overview/VariableAmount.kt @@ -15,19 +15,14 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import java.time.Instant -class VariableAmount(private val dispatcher: CoroutineDispatcher = Dispatchers.IO) { - fun process(activity: AppCompatActivity, intent: Intent) { - val reminderEventId = intent.getIntExtra(EXTRA_REMINDER_EVENT_ID, -1) - if (reminderEventId != -1) { - showDialogToEnterAmount(activity, reminderEventId, intent.getStringExtra(EXTRA_AMOUNT)) - } - } - - private fun showDialogToEnterAmount( - activity: AppCompatActivity, - reminderEventId: Int, - amount: String? - ) { +fun variableAmountDialog( + activity: AppCompatActivity, + intent: Intent, + dispatcher: CoroutineDispatcher = Dispatchers.IO +) { + val reminderEventId = intent.getIntExtra(EXTRA_REMINDER_EVENT_ID, -1) + val amount = intent.getStringExtra(EXTRA_AMOUNT) + if (reminderEventId != -1) { DialogHelper(activity) .title(R.string.log_additional_dose) .hint(R.string.dosage) @@ -36,39 +31,44 @@ class VariableAmount(private val dispatcher: CoroutineDispatcher = Dispatchers.I updateReminderEvent( activity, reminderEventId, - amountLocal!! + amountLocal!!, + dispatcher ) } - .cancelCallback { touchReminderEvent(activity, reminderEventId) } + .cancelCallback { touchReminderEvent(activity, reminderEventId, dispatcher) } .show() - } +} - private fun touchReminderEvent(activity: AppCompatActivity, reminderEventId: Int) { - activity.lifecycleScope.launch(dispatcher) { - val repository = MedicineRepository(activity.application) - val reminderEvent = repository.getReminderEvent(reminderEventId) - reminderEvent?.processedTimestamp = Instant.now().epochSecond - repository.updateReminderEvent(reminderEvent) - } +private fun touchReminderEvent( + activity: AppCompatActivity, + reminderEventId: Int, + dispatcher: CoroutineDispatcher +) { + activity.lifecycleScope.launch(dispatcher) { + val repository = MedicineRepository(activity.application) + val reminderEvent = repository.getReminderEvent(reminderEventId) + reminderEvent?.processedTimestamp = Instant.now().epochSecond + repository.updateReminderEvent(reminderEvent) } +} - private fun updateReminderEvent( - activity: AppCompatActivity, - reminderEventId: Int, - amount: String - ) { - activity.lifecycleScope.launch(dispatcher) { - val repository = MedicineRepository(activity.application) - val reminderEvent = repository.getReminderEvent(reminderEventId) - reminderEvent?.amount = amount - NotificationAction.processReminderEvent( - activity, - reminderEventId, - ReminderEvent.ReminderStatus.TAKEN, - reminderEvent!!, - repository - ) - } +private fun updateReminderEvent( + activity: AppCompatActivity, + reminderEventId: Int, + amount: String, + dispatcher: CoroutineDispatcher +) { + activity.lifecycleScope.launch(dispatcher) { + val repository = MedicineRepository(activity.application) + val reminderEvent = repository.getReminderEvent(reminderEventId) + reminderEvent?.amount = amount + NotificationAction.processReminderEvent( + activity, + reminderEventId, + ReminderEvent.ReminderStatus.TAKEN, + reminderEvent!!, + repository + ) } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/futsch1/medtimer/reminders/Notifications.java b/app/src/main/java/com/futsch1/medtimer/reminders/Notifications.java index 4155a4ba..cafa44cb 100644 --- a/app/src/main/java/com/futsch1/medtimer/reminders/Notifications.java +++ b/app/src/main/java/com/futsch1/medtimer/reminders/Notifications.java @@ -98,8 +98,7 @@ private void buildActions(NotificationCompat.Builder builder, int notificationId String dismissNotificationAction = defaultSharedPreferences.getString("dismiss_notification_action", "0"); int snoozeTime = Integer.parseInt(defaultSharedPreferences.getString("snooze_duration", "15")); - Intent snooze = ReminderProcessor.getSnoozeIntent(context, reminder.reminderId, reminderEventId, notificationId, snoozeTime); - PendingIntent pendingSnooze = PendingIntent.getBroadcast(context, notificationId, snooze, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT); + PendingIntent pendingSnooze = getSnoozePendingIntent(context, reminder.reminderId, reminderEventId, notificationId, snoozeTime); Intent notifyDismissed = ReminderProcessor.getDismissedActionIntent(context, reminderEventId); PendingIntent pendingDismissed = PendingIntent.getBroadcast(context, notificationId, notifyDismissed, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT); @@ -121,6 +120,16 @@ private void buildActions(NotificationCompat.Builder builder, int notificationId } } + private PendingIntent getSnoozePendingIntent(Context context, int reminderId, int reminderEventId, int notificationId, int snoozeTime) { + if (snoozeTime == -1) { + Intent snooze = ReminderProcessor.getCustomSnoozeActionIntent(context, reminderId, reminderEventId, notificationId); + return PendingIntent.getActivity(context, notificationId, snooze, PendingIntent.FLAG_IMMUTABLE); + } else { + Intent snooze = ReminderProcessor.getSnoozeIntent(context, reminderId, reminderEventId, notificationId, snoozeTime); + return PendingIntent.getBroadcast(context, notificationId, snooze, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT); + } + } + private PendingIntent getTakenPendingIntent(int notificationId, int reminderEventId, Reminder reminder) { if (reminder.variableAmount) { Intent notifyTaken = ReminderProcessor.getVariableAmountActionIntent(context, reminderEventId, reminder.amount); diff --git a/app/src/main/java/com/futsch1/medtimer/reminders/ReminderProcessor.java b/app/src/main/java/com/futsch1/medtimer/reminders/ReminderProcessor.java index 82d71ebc..ff5b1b9b 100644 --- a/app/src/main/java/com/futsch1/medtimer/reminders/ReminderProcessor.java +++ b/app/src/main/java/com/futsch1/medtimer/reminders/ReminderProcessor.java @@ -128,6 +128,16 @@ public static Intent getVariableAmountActionIntent(Context context, int reminder return actionIntent; } + public static Intent getCustomSnoozeActionIntent(Context context, int reminderId, int reminderEventId, int notificationId) { + Intent actionIntent = new Intent(context, MainActivity.class); + actionIntent.setAction("CUSTOM_SNOOZE"); + actionIntent.setFlags(FLAG_ACTIVITY_NEW_TASK); + actionIntent.putExtra(EXTRA_REMINDER_ID, reminderId); + actionIntent.putExtra(EXTRA_REMINDER_EVENT_ID, reminderEventId); + actionIntent.putExtra(EXTRA_NOTIFICATION_ID, notificationId); + return actionIntent; + } + @Override public void onReceive(Context context, Intent intent) { WorkManager workManager = WorkManagerAccess.getWorkManager(context); diff --git a/app/src/main/res/values-ta/strings.xml b/app/src/main/res/values-ta/strings.xml index b67ed382..94aa0a5c 100644 --- a/app/src/main/res/values-ta/strings.xml +++ b/app/src/main/res/values-ta/strings.xml @@ -187,4 +187,16 @@ மறு நிரப்பல் அளவு இப்போது மீண்டும் நிரப்பவும் எடுக்கும்போது அளவை உள்ளிடவும் + + நிமிடம் + நிமிடங்கள் + + + மணிநேரம் + மணிநேரங்கள் + + + நாள் + நாட்கள் + diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index 34acf9b5..61d19dfd 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -62,6 +62,7 @@ @string/minutes_15 @string/minutes_30 @string/minutes_60 + @string/custom 5 @@ -69,6 +70,7 @@ 15 30 60 + -1 @string/monday