diff --git a/app/src/main/java/com/infomaniak/mail/MatomoMail.kt b/app/src/main/java/com/infomaniak/mail/MatomoMail.kt
index 82ae828b300..8a6c5111437 100644
--- a/app/src/main/java/com/infomaniak/mail/MatomoMail.kt
+++ b/app/src/main/java/com/infomaniak/mail/MatomoMail.kt
@@ -140,6 +140,7 @@ object MatomoMail : Matomo {
CustomFolder("customFolder"),
CustomFolders("customFolders"),
CustomSchedule("customSchedule"),
+ CustomReminder("customReminder"),
CustomScheduleConfirm("customScheduleConfirm"),
DailyLimitReachedUpgrade("dailyLimitReachedUpgrade"),
Delete("delete"),
diff --git a/app/src/main/java/com/infomaniak/mail/ui/alertDialogs/CustomReminderPickerDialog.kt b/app/src/main/java/com/infomaniak/mail/ui/alertDialogs/CustomReminderPickerDialog.kt
new file mode 100644
index 00000000000..f5cabd366c0
--- /dev/null
+++ b/app/src/main/java/com/infomaniak/mail/ui/alertDialogs/CustomReminderPickerDialog.kt
@@ -0,0 +1,124 @@
+/*
+ * Infomaniak Mail - Android
+ * Copyright (C) 2026 Infomaniak Network SA
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.infomaniak.mail.ui.alertDialogs
+
+import android.content.Context
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import com.infomaniak.mail.R
+import com.infomaniak.mail.databinding.DialogCustomReminderPickerBinding
+import com.infomaniak.mail.utils.date.DateFormatUtils.MINUTES_IN_AN_HOUR
+import com.infomaniak.mail.utils.date.DateFormatUtils.MINUTES_IN_A_DAY
+import dagger.hilt.android.qualifiers.ActivityContext
+import dagger.hilt.android.scopes.ActivityScoped
+import javax.inject.Inject
+
+@ActivityScoped
+class CustomReminderPickerDialog @Inject constructor(
+ @ActivityContext private val activityContext: Context,
+) : BaseAlertDialog(activityContext) {
+
+ private val binding: DialogCustomReminderPickerBinding by lazy {
+ DialogCustomReminderPickerBinding.inflate(activity.layoutInflater)
+ }
+
+ override val alertDialog = initDialog()
+
+ private var onDelaySelected: ((Int) -> Unit)? = null
+
+ private val timeUnits = TimeUnit.entries.toTypedArray()
+
+ private fun initDialog() = with(binding) {
+ MaterialAlertDialogBuilder(activityContext)
+ .setTitle(R.string.buttonCustomReminder)
+ .setView(root)
+ .setPositiveButton(R.string.buttonConfirm, null)
+ .setNegativeButton(com.infomaniak.core.legacy.R.string.buttonCancel, null)
+ .create()
+ }
+
+ fun show(onDelaySelected: (Int) -> Unit) {
+ this.onDelaySelected = onDelaySelected
+ alertDialog.show()
+ setupPickers()
+ setupListeners()
+ }
+
+ override fun resetCallbacks() {
+ onDelaySelected = null
+ }
+
+ private fun setupPickers() = with(binding) {
+ numberPicker.minValue = 1
+ numberPicker.maxValue = timeUnits[unitPicker.value].maxValue
+ numberPicker.wrapSelectorWheel = true
+
+ unitPicker.minValue = 0
+ unitPicker.maxValue = timeUnits.size - 1
+ unitPicker.wrapSelectorWheel = false
+
+ updateUnitLabels(numberPicker.value)
+ }
+
+ private fun setupListeners() = with(binding) {
+ numberPicker.setOnValueChangedListener { _, oldVal, newVal ->
+ if ((oldVal == 1 && newVal > 1) || (oldVal > 1 && newVal == 1)) {
+ updateUnitLabels(newVal)
+ }
+ }
+
+ unitPicker.setOnValueChangedListener { _, _, newUnitIndex -> numberPicker.maxValue = timeUnits[newUnitIndex].maxValue }
+
+ positiveButton.setOnClickListener {
+ numberPicker.clearFocus()
+ unitPicker.clearFocus()
+ onDelaySelected?.invoke(getDelayMinutes())
+ alertDialog.dismiss()
+ }
+
+ negativeButton.setOnClickListener { alertDialog.cancel() }
+ }
+
+ private fun updateUnitLabels(currentNumber: Int) {
+ val displayedUnits = timeUnits.map {
+ activityContext.resources.getQuantityString(it.titleRes, currentNumber)
+ }.toTypedArray()
+
+ binding.unitPicker.displayedValues = displayedUnits
+ }
+
+ private fun getDelayMinutes(): Int {
+ val number = binding.numberPicker.value
+ val selectedUnit = timeUnits[binding.unitPicker.value]
+
+ return number * selectedUnit.multiplierInMinutes
+ }
+
+ companion object {
+ private const val MAX_HOURS = 23
+ private const val MAX_DAYS = 30
+
+ enum class TimeUnit(
+ val titleRes: Int,
+ val maxValue: Int,
+ val multiplierInMinutes: Int
+ ) {
+ Hours(R.plurals.unitHours, MAX_HOURS, MINUTES_IN_AN_HOUR),
+ Days(R.plurals.unitDays, MAX_DAYS, MINUTES_IN_A_DAY),
+ }
+ }
+}
diff --git a/app/src/main/java/com/infomaniak/mail/ui/newMessage/sendOptions/DraftSendOptionsFragment.kt b/app/src/main/java/com/infomaniak/mail/ui/newMessage/sendOptions/DraftSendOptionsFragment.kt
index cc97a1dbe53..f983c019073 100644
--- a/app/src/main/java/com/infomaniak/mail/ui/newMessage/sendOptions/DraftSendOptionsFragment.kt
+++ b/app/src/main/java/com/infomaniak/mail/ui/newMessage/sendOptions/DraftSendOptionsFragment.kt
@@ -37,6 +37,7 @@ import com.infomaniak.mail.R
import com.infomaniak.mail.data.LocalSettings
import com.infomaniak.mail.data.models.FeatureFlag
import com.infomaniak.mail.databinding.FragmentSendOptionsBinding
+import com.infomaniak.mail.ui.alertDialogs.CustomReminderPickerDialog
import com.infomaniak.mail.ui.alertDialogs.SelectDateAndTimeForScheduledDraftDialog
import com.infomaniak.mail.ui.bottomSheetDialogs.ScheduleOption
import com.infomaniak.mail.ui.bottomSheetDialogs.ScheduleOptionUtils
@@ -66,6 +67,9 @@ class DraftSendOptionsFragment : Fragment() {
@Inject
lateinit var dateAndTimeScheduleDialog: SelectDateAndTimeForScheduledDraftDialog
+ @Inject
+ lateinit var customReminderPickerDialog: CustomReminderPickerDialog
+
@Inject
lateinit var localSettings: LocalSettings
@@ -81,6 +85,7 @@ class DraftSendOptionsFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) = with(binding) {
dateAndTimeScheduleDialog.bindAlertToLifecycle(viewLifecycleOwner)
+ customReminderPickerDialog.bindAlertToLifecycle(viewLifecycleOwner)
setupScheduleOptions()
lastScheduleOption.associatedValue = lastSelectedEpoch?.toString()
@@ -372,7 +377,17 @@ class DraftSendOptionsFragment : Fragment() {
}
private fun showCustomDelayReminderDatePicker() {
- // TODO
+ customReminderPickerDialog.show(
+ onDelaySelected = { delayMinutes ->
+ trackScheduleSendEvent(MatomoName.CustomReminder)
+ newMessageViewModel.setReminderConfig(ReminderConfig.Delayed(delayMinutes, isCustom = true))
+ binding.customDelayReminder.apply {
+ setSubtitle(requireContext().formatDelayText(delayMinutes))
+ setCheckMark(displayCheckMark = true)
+ }
+ binding.optionsDelays.clearCheck()
+ },
+ )
}
}
diff --git a/app/src/main/res/layout/dialog_custom_reminder_picker.xml b/app/src/main/res/layout/dialog_custom_reminder_picker.xml
new file mode 100644
index 00000000000..aa823ea1f0f
--- /dev/null
+++ b/app/src/main/res/layout/dialog_custom_reminder_picker.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/values-da/strings.xml b/app/src/main/res/values-da/strings.xml
index 60a3115074c..731bdfdb9d0 100644
--- a/app/src/main/res/values-da/strings.xml
+++ b/app/src/main/res/values-da/strings.xml
@@ -729,6 +729,14 @@
Papirkurv
Prøv venligst igen.
Fjern blokering
+
+ - Dag
+ - Dage
+
+
+ - Time
+ - Timer
+
Ukendt afsender
Ukendt modtager
(ukendt)
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index c409fc02c2a..67a0771f300 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -729,6 +729,14 @@
Papierkorb
Bitte versuchen Sie es erneut.
Entsperren
+
+ - Tag
+ - Tage
+
+
+ - Stunde
+ - Stunden
+
Unbekannter Spediteur
Unbekannter Empfänger
(unbekannt)
diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml
index 125a3139aeb..214c8304b31 100644
--- a/app/src/main/res/values-el/strings.xml
+++ b/app/src/main/res/values-el/strings.xml
@@ -729,6 +729,14 @@
Κάδος απορριμμάτων
Παρακαλώ, δοκιμάστε ξανά.
Ξεμπλοκάρισμα
+
+ - Ημέρα
+ - Ημέρες
+
+
+ - Ώρα
+ - Ώρες
+
Άγνωστος αποστολέας
Άγνωστος παραλήπτης
(άγνωστο)
diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml
index 0dace42acdf..df4a38b65b8 100644
--- a/app/src/main/res/values-es/strings.xml
+++ b/app/src/main/res/values-es/strings.xml
@@ -729,6 +729,14 @@
Papelera
Por favor, inténtelo de nuevo.
Desbloquear
+
+ - Día
+ - Días
+
+
+ - Hora
+ - Horas
+
Expedidor desconocido
Destinatario desconocido
(desconocido)
diff --git a/app/src/main/res/values-fi/strings.xml b/app/src/main/res/values-fi/strings.xml
index 37245da2bef..efe815aa824 100644
--- a/app/src/main/res/values-fi/strings.xml
+++ b/app/src/main/res/values-fi/strings.xml
@@ -729,6 +729,14 @@
Roskakori
Yritä uudelleen.
Poista esto
+
+ - Päivä
+ - Päivää
+
+
+ - Tunti
+ - Tuntia
+
Tuntematon lähettäjä
Tuntematon vastaanottaja
(tuntematon)
diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml
index e85db38a77d..aba89e0c3f4 100644
--- a/app/src/main/res/values-fr/strings.xml
+++ b/app/src/main/res/values-fr/strings.xml
@@ -729,6 +729,14 @@
Corbeille
Veuillez réessayer.
Débloquer
+
+ - Jour
+ - Jours
+
+
+ - Heure
+ - Heures
+
Expéditeur inconnu
Destinataire inconnu
(inconnu)
diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml
index 5b83a645176..4c59c927a1e 100644
--- a/app/src/main/res/values-it/strings.xml
+++ b/app/src/main/res/values-it/strings.xml
@@ -729,6 +729,14 @@
Cestino
Per favore, riprova.
Sbloccare
+
+ - Giorno
+ - Giorni
+
+
+ - Ora
+ - Ore
+
Spedizioniere sconosciuto
Destinatario sconosciuto
(sconosciuto)
diff --git a/app/src/main/res/values-nb/strings.xml b/app/src/main/res/values-nb/strings.xml
index 5a528b9a686..c36ea625582 100644
--- a/app/src/main/res/values-nb/strings.xml
+++ b/app/src/main/res/values-nb/strings.xml
@@ -729,6 +729,14 @@
Papirkurv
Vennligst prøv igjen.
Opphev blokkering
+
+ - Dag
+ - Dager
+
+
+ - Time
+ - Timer
+
Ukjent avsender
Ukjent mottaker
(ukjent)
diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml
index 270043cdcf8..752b76350e2 100644
--- a/app/src/main/res/values-nl/strings.xml
+++ b/app/src/main/res/values-nl/strings.xml
@@ -729,6 +729,14 @@
Prullenbak
Probeer het opnieuw.
Deblokkeren
+
+ - Dag
+ - Dagen
+
+
+ - Uur
+ - Uur
+
Onbekende afzender
Onbekende ontvanger
(onbekend)
diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml
index 1ad70767f18..ab3b9449709 100644
--- a/app/src/main/res/values-pl/strings.xml
+++ b/app/src/main/res/values-pl/strings.xml
@@ -787,6 +787,18 @@
Kosz
Spróbuj ponownie.
Odblokuj
+
+ - Dzień
+ - Dni
+ - Dni
+ - Dni
+
+
+ - Godzina
+ - Godziny
+ - Godzin
+ - Godzin
+
Nieznany nadawca
Nieznany odbiorca
(nieznany)
diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml
index 9a15d48785b..c5ebcab3003 100644
--- a/app/src/main/res/values-pt/strings.xml
+++ b/app/src/main/res/values-pt/strings.xml
@@ -729,6 +729,14 @@
Lixo
Por favor, tente novamente.
Desbloquear
+
+ - Dia
+ - Dias
+
+
+ - Hora
+ - Horas
+
Remetente desconhecido
Destinatário desconhecido
(desconhecido)
diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml
index fd038232252..1f2c14f8d51 100644
--- a/app/src/main/res/values-sv/strings.xml
+++ b/app/src/main/res/values-sv/strings.xml
@@ -729,6 +729,14 @@
Papperskorg
Försök igen.
Avblockera
+
+ - Dag
+ - Dagar
+
+
+ - Timme
+ - Timmar
+
Okänd avsändare
Okänd mottagare
(okänd)
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index e5ed9286206..4df26952dfa 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -733,6 +733,14 @@
Trash
Please try again.
Unblock
+
+ - Day
+ - Days
+
+
+ - Hour
+ - Hours
+
Unknown expeditor
Unknown recipient
(unknown)