feat: show relative time in notifications + move default duration to profile settings

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 <noreply@anthropic.com>
This commit is contained in:
Guido Schmit
2026-06-15 19:40:46 +02:00
parent 9ced441935
commit 740367b0b9
2 changed files with 23 additions and 10 deletions

View File

@@ -58,7 +58,11 @@ object NotificationScheduler {
} else ev.reminders } else ev.reminders
for (m in offsets) { for (m in offsets) {
val fire = ev.startDate.toEpochMilli() - m * 60_000L 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 } pending.sortBy { it.fire }
@@ -82,6 +86,14 @@ object NotificationScheduler {
prefs.edit().putInt(KEY_COUNT, limited.size).apply() 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 { private fun intentFor(context: Context, code: Int, p: Pending?): PendingIntent {
val intent = Intent(context, ReminderReceiver::class.java).apply { val intent = Intent(context, ReminderReceiver::class.java).apply {
// Distinct action per code so PendingIntents don't collapse together. // Distinct action per code so PendingIntents don't collapse together.

View File

@@ -92,6 +92,16 @@ fun SettingsScreen(
Column(Modifier.fillMaxSize().padding(padding).verticalScroll(rememberScrollState()).padding(16.dp)) { Column(Modifier.fillMaxSize().padding(padding).verticalScroll(rememberScrollState()).padding(16.dp)) {
ProfileChapter(vm) 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)) Divider(Modifier.padding(vertical = 16.dp))
Section(tr("settings.calview")) Section(tr("settings.calview"))
@@ -116,15 +126,6 @@ fun SettingsScreen(
} }
Spacer(Modifier.size(16.dp)) 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)) Divider(Modifier.padding(vertical = 16.dp))
Section(tr("settings.language")) Section(tr("settings.language"))