From f56d47800cb8336f41ffca4c483d3d5b0b4ac3af Mon Sep 17 00:00:00 2001 From: Honey Date: Fri, 21 Aug 2026 20:00:49 +0200 Subject: [PATCH] =?UTF-8?q?fix(android):=20even=20concert=20rows=20?= =?UTF-8?q?=E2=80=94=20fixed=20calendar-style=20date=20block?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "16. Sep. 2026" date wrapped inside the 52dp column, so rows with/without a time ended up different heights and the divider/venue misaligned. The date block is now a fixed 56dp calendar block: big day number, small month/year and time, each single-line — every row is the same height and lines up. Co-Authored-By: Claude Opus 4.8 --- .../app/ui/component/ConcertsSheet.kt | 39 ++++++++++++------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/android/app/src/main/kotlin/com/novasonic/app/ui/component/ConcertsSheet.kt b/android/app/src/main/kotlin/com/novasonic/app/ui/component/ConcertsSheet.kt index 3d822fb..36001c4 100644 --- a/android/app/src/main/kotlin/com/novasonic/app/ui/component/ConcertsSheet.kt +++ b/android/app/src/main/kotlin/com/novasonic/app/ui/component/ConcertsSheet.kt @@ -88,7 +88,7 @@ fun ConcertsSheet( @Composable private fun EventRow(event: ConcertEvent, onTicketClick: (String) -> Unit) { - val (dateStr, timeStr) = formatEventDateTime(event.datetime) + val w = formatEventWhen(event.datetime) val venue = event.venue?.name.orEmpty() val city = listOfNotNull(event.venue?.city, event.venue?.country).joinToString(", ") val offer = event.offers.firstOrNull { !it.url.isNullOrBlank() } @@ -102,26 +102,33 @@ private fun EventRow(event: ConcertEvent, onTicketClick: (String) -> Unit) { .background(NsSurface2) .padding(horizontal = 14.dp, vertical = 12.dp), ) { - // Date block + // Date block — fixed width, calendar style (day big, month/year + time small) so every + // row is the same height and the divider/venue line up. Column( horizontalAlignment = Alignment.CenterHorizontally, - modifier = Modifier.width(52.dp), + modifier = Modifier.width(56.dp), ) { Text( - dateStr, + w.day, fontFamily = Outfit, fontWeight = FontWeight.Bold, - fontSize = 13.sp, color = NsAccent, + fontSize = 18.sp, color = NsAccent, maxLines = 1, ) - if (timeStr.isNotBlank()) { + if (w.monthYear.isNotBlank()) { Text( - timeStr, - fontFamily = Outfit, fontSize = 11.sp, color = NsOnSurface2, + w.monthYear, + fontFamily = Outfit, fontSize = 10.sp, color = NsOnSurface2, maxLines = 1, + ) + } + if (w.time.isNotBlank()) { + Text( + w.time, + fontFamily = Outfit, fontSize = 10.sp, color = NsOnSurface2, maxLines = 1, ) } } Spacer(Modifier.width(14.dp)) - Box(Modifier.width(1.dp).height(36.dp).background(NsBorder)) + Box(Modifier.width(1.dp).height(40.dp).background(NsBorder)) Spacer(Modifier.width(14.dp)) // Venue @@ -166,19 +173,21 @@ private fun EventRow(event: ConcertEvent, onTicketClick: (String) -> Unit) { } } -private val DATE_FMT = DateTimeFormatter.ofPattern("dd. MMM yyyy", Locale.GERMAN) -private val TIME_FMT = DateTimeFormatter.ofPattern("HH:mm") +private data class EventWhen(val day: String, val monthYear: String, val time: String) -private fun formatEventDateTime(datetime: String): Pair { +private val DAY_FMT = DateTimeFormatter.ofPattern("dd", Locale.GERMAN) +private val MONTH_FMT = DateTimeFormatter.ofPattern("MMM yyyy", Locale.GERMAN) +private val TIME_FMT = DateTimeFormatter.ofPattern("HH:mm") + +private fun formatEventWhen(datetime: String): EventWhen { return try { // Backend now sends a naive venue-local datetime ("2026-09-16T20:00:00"); older/zoned // values ("…Z") still parse via the ZonedDateTime fallback. val ldt = runCatching { LocalDateTime.parse(datetime) } .getOrElse { ZonedDateTime.parse(datetime).toLocalDateTime() } - val date = ldt.format(DATE_FMT) val time = if (ldt.hour == 0 && ldt.minute == 0) "" else ldt.format(TIME_FMT) - date to time + EventWhen(ldt.format(DAY_FMT), ldt.format(MONTH_FMT), time) } catch (_: Exception) { - datetime.take(10) to "" + EventWhen(datetime.take(10), "", "") } }