Merge pull request 'fix(ui): Show event dates in card view' (#1) from fix/event-card-date-display into main
Reviewed-on: #1
This commit was merged in pull request #1.
This commit is contained in:
@@ -24,7 +24,6 @@ import androidx.compose.foundation.layout.Column
|
|||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.fillMaxHeight
|
import androidx.compose.foundation.layout.fillMaxHeight
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.material3.Card
|
import androidx.compose.material3.Card
|
||||||
@@ -35,6 +34,7 @@ import androidx.compose.ui.Modifier
|
|||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import ch.parano.myice.models.Event
|
import ch.parano.myice.models.Event
|
||||||
|
import ch.parano.myice.util.formatEventDateTime
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun EventCard(
|
fun EventCard(
|
||||||
@@ -51,9 +51,7 @@ fun EventCard(
|
|||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(horizontal = 16.dp, vertical = 8.dp),
|
.padding(horizontal = 16.dp, vertical = 8.dp),
|
||||||
) {
|
) {
|
||||||
Row(
|
Row {
|
||||||
modifier = Modifier.height(120.dp),
|
|
||||||
) {
|
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.width(4.dp)
|
.width(4.dp)
|
||||||
@@ -62,8 +60,7 @@ fun EventCard(
|
|||||||
)
|
)
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(16.dp)
|
.padding(16.dp),
|
||||||
.fillMaxHeight(),
|
|
||||||
verticalArrangement = Arrangement.spacedBy(4.dp),
|
verticalArrangement = Arrangement.spacedBy(4.dp),
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
@@ -83,7 +80,7 @@ fun EventCard(
|
|||||||
style = MaterialTheme.typography.bodySmall,
|
style = MaterialTheme.typography.bodySmall,
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
text = "${event.start} - ${event.end}",
|
text = formatEventDateTime(event.start, event.end),
|
||||||
style = MaterialTheme.typography.bodySmall,
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user