From 740367b0b948a6c0611f4f19fa9d411de0bc1e6e Mon Sep 17 00:00:00 2001 From: Guido Schmit Date: Mon, 15 Jun 2026 19:40:46 +0200 Subject: [PATCH] feat: show relative time in notifications + move default duration to profile settings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Notifications now show "in 30 Min. · Ort" instead of just the location, giving users immediate context about how soon the event starts. Default event duration picker moved from the View section to right below the profile/privacy group, consistent with the iOS app arrangement. Co-Authored-By: Claude Sonnet 4.6 --- .../notifications/NotificationScheduler.kt | 14 +++++++++++++- .../calendarr/ui/settings/SettingsScreen.kt | 19 ++++++++++--------- 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/com/scarriffle/calendarr/notifications/NotificationScheduler.kt b/app/src/main/java/com/scarriffle/calendarr/notifications/NotificationScheduler.kt index 065d207..a905bbc 100644 --- a/app/src/main/java/com/scarriffle/calendarr/notifications/NotificationScheduler.kt +++ b/app/src/main/java/com/scarriffle/calendarr/notifications/NotificationScheduler.kt @@ -58,7 +58,11 @@ object NotificationScheduler { } else ev.reminders for (m in offsets) { val fire = ev.startDate.toEpochMilli() - m * 60_000L - if (fire > now) pending.add(Pending(fire, ev.title, ev.location)) + if (fire > now) { + val rel = relativeText(m) + val body = if (ev.location.isNotBlank()) "$rel · ${ev.location}" else rel + pending.add(Pending(fire, ev.title, body)) + } } } pending.sortBy { it.fire } @@ -82,6 +86,14 @@ object NotificationScheduler { prefs.edit().putInt(KEY_COUNT, limited.size).apply() } + private fun relativeText(minutes: Int): String = when { + minutes < 60 -> "in $minutes Min." + minutes == 60 -> "in 1 Std." + minutes < 1440 -> "in ${minutes / 60} Std." + minutes == 1440 -> "morgen" + else -> "in ${minutes / 1440} Tagen" + } + private fun intentFor(context: Context, code: Int, p: Pending?): PendingIntent { val intent = Intent(context, ReminderReceiver::class.java).apply { // Distinct action per code so PendingIntents don't collapse together. diff --git a/app/src/main/java/com/scarriffle/calendarr/ui/settings/SettingsScreen.kt b/app/src/main/java/com/scarriffle/calendarr/ui/settings/SettingsScreen.kt index e2bfb8c..f004359 100644 --- a/app/src/main/java/com/scarriffle/calendarr/ui/settings/SettingsScreen.kt +++ b/app/src/main/java/com/scarriffle/calendarr/ui/settings/SettingsScreen.kt @@ -92,6 +92,16 @@ fun SettingsScreen( Column(Modifier.fillMaxSize().padding(padding).verticalScroll(rememberScrollState()).padding(16.dp)) { ProfileChapter(vm) + Spacer(Modifier.size(16.dp)) + Section(tr("settings.default_duration")) + ChipRow( + options = listOf( + "15" to "15 min", "30" to "30 min", "45" to "45 min", + "60" to "1 h", "90" to "1.5 h", "120" to "2 h", + ), + selected = settings.defaultEventDurationMinutes.toString(), + onSelect = { update(settings.copy(defaultEventDurationMinutes = it.toInt())) }, + ) Divider(Modifier.padding(vertical = 16.dp)) Section(tr("settings.calview")) @@ -116,15 +126,6 @@ fun SettingsScreen( } Spacer(Modifier.size(16.dp)) - Section(tr("settings.default_duration")) - ChipRow( - options = listOf( - "15" to "15 min", "30" to "30 min", "45" to "45 min", - "60" to "1 h", "90" to "1.5 h", "120" to "2 h", - ), - selected = settings.defaultEventDurationMinutes.toString(), - onSelect = { update(settings.copy(defaultEventDurationMinutes = it.toInt())) }, - ) Divider(Modifier.padding(vertical = 16.dp)) Section(tr("settings.language"))