Compare commits

...
2 Commits
Author SHA1 Message Date
herel 1795337d01 Merge pull request 'fix(ui): Show event dates in card view' (#1) from fix/event-card-date-display into main
Reviewed-on: #1
2026-08-04 07:59:29 +00:00
herel a8905327f0 fix(ui): Show event dates in card view
The EventCard had a fixed 120dp height that clipped the date line.
Remove the height constraint so the card grows to fit all content,
and format ISO datetime strings into readable dd.MM.yyyy HH:mm format.
2026-08-04 09:57:47 +02:00
3 changed files with 105 additions and 7 deletions
@@ -24,7 +24,6 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.material3.Card
@@ -35,6 +34,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import ch.parano.myice.models.Event
import ch.parano.myice.util.formatEventDateTime
@Composable
fun EventCard(
@@ -51,9 +51,7 @@ fun EventCard(
.fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 8.dp),
) {
Row(
modifier = Modifier.height(120.dp),
) {
Row {
Box(
modifier = Modifier
.width(4.dp)
@@ -62,8 +60,7 @@ fun EventCard(
)
Column(
modifier = Modifier
.padding(16.dp)
.fillMaxHeight(),
.padding(16.dp),
verticalArrangement = Arrangement.spacedBy(4.dp),
) {
Text(
@@ -83,7 +80,7 @@ fun EventCard(
style = MaterialTheme.typography.bodySmall,
)
Text(
text = "${event.start} - ${event.end}",
text = formatEventDateTime(event.start, event.end),
style = MaterialTheme.typography.bodySmall,
)
}
@@ -0,0 +1,41 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// MyIce Kotlin Multiplatform — schedule/convocation viewer
// Copyright (C) 2026 parano.ch
//
// 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 <https://www.gnu.org/licenses/>.
package ch.parano.myice.util
import kotlinx.datetime.LocalDateTime
private fun parseOrNull(iso: String): LocalDateTime? = runCatching {
LocalDateTime.parse(iso)
}.getOrNull()
private fun LocalDateTime.dateStr(): String =
"${day.toString().padStart(2, '0')}.${monthNumber.toString().padStart(2, '0')}.${year.toString().padStart(4, '0')}"
private fun LocalDateTime.timeStr(): String =
"${hour.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}"
fun formatEventDateTime(start: String, end: String): String {
val startDt = parseOrNull(start)
val endDt = parseOrNull(end)
if (startDt == null || endDt == null) return "$start - $end"
return if (startDt.date == endDt.date) {
"${startDt.dateStr()} ${startDt.timeStr()} - ${endDt.timeStr()}"
} else {
"${startDt.dateStr()} ${startDt.timeStr()} - ${endDt.timeStr()} (${endDt.dateStr()})"
}
}
@@ -0,0 +1,60 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// MyIce Kotlin Multiplatform — schedule/convocation viewer
// Copyright (C) 2026 parano.ch
//
// 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 <https://www.gnu.org/licenses/>.
package ch.parano.myice.util
import kotlin.test.Test
import kotlin.test.assertEquals
class EventDateTimeFormatterTest {
@Test
fun formatsSameDayEventAsDateFollowedByTimeRange() {
val formatted = formatEventDateTime(
start = "2024-11-10T14:00:00",
end = "2024-11-10T16:15:00",
)
assertEquals("10.11.2024 14:00 - 16:15", formatted)
}
@Test
fun formatsCrossingMidnightEventWithBothDates() {
val formatted = formatEventDateTime(
start = "2024-11-10T20:00:00",
end = "2024-11-11T01:30:00",
)
assertEquals("10.11.2024 20:00 - 01:30 (11.11.2024)", formatted)
}
@Test
fun returnsRawStartWhenStartUnparseable() {
val formatted = formatEventDateTime(start = "s", end = "2024-11-10T16:15:00")
assertEquals("s - 2024-11-10T16:15:00", formatted)
}
@Test
fun returnsRawEndWhenEndUnparseable() {
val formatted = formatEventDateTime(start = "2024-11-10T14:00:00", end = "e")
assertEquals("2024-11-10T14:00:00 - e", formatted)
}
@Test
fun returnsRawWhenBothUnparseable() {
val formatted = formatEventDateTime(start = "s", end = "e")
assertEquals("s - e", formatted)
}
}