diff --git a/composeApp/src/androidMain/kotlin/su/reya/coop/screens/ChatScreen.kt b/composeApp/src/androidMain/kotlin/su/reya/coop/screens/ChatScreen.kt index 15264a4..b5a1357 100644 --- a/composeApp/src/androidMain/kotlin/su/reya/coop/screens/ChatScreen.kt +++ b/composeApp/src/androidMain/kotlin/su/reya/coop/screens/ChatScreen.kt @@ -48,6 +48,7 @@ import org.jetbrains.compose.resources.painterResource import rust.nostr.sdk.Event import su.reya.coop.LocalNostrViewModel import su.reya.coop.LocalSnackbarHostState +import su.reya.coop.humanReadable import su.reya.coop.shared.displayNameFlow import su.reya.coop.shared.pictureFlow @@ -177,9 +178,9 @@ fun ChatMessage( RoundedCornerShape(topStart = 20.dp, topEnd = 20.dp, bottomStart = 4.dp, bottomEnd = 20.dp) } - val alignment = if (isMine) Alignment.CenterEnd else Alignment.CenterStart val containerColor = if (isMine) MaterialTheme.colorScheme.primaryContainer else MaterialTheme.colorScheme.secondaryContainer + val contentColor = if (isMine) MaterialTheme.colorScheme.onPrimaryContainer else MaterialTheme.colorScheme.onSecondaryContainer @@ -187,19 +188,26 @@ fun ChatMessage( modifier = Modifier .fillMaxWidth() .padding(vertical = 4.dp), - contentAlignment = alignment + contentAlignment = if (isMine) Alignment.CenterEnd else Alignment.CenterStart ) { - Surface( - color = containerColor, - contentColor = contentColor, - shape = bubbleShape, - modifier = Modifier.widthIn(max = 280.dp) - ) { + Column { Text( - text = event.content(), - modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp), - style = MaterialTheme.typography.bodyMedium + text = event.createdAt().humanReadable(), + style = MaterialTheme.typography.labelSmall, ) + Spacer(modifier = Modifier.size(4.dp)) + Surface( + color = containerColor, + contentColor = contentColor, + shape = bubbleShape, + modifier = Modifier.widthIn(max = 280.dp) + ) { + Text( + text = event.content(), + modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp), + style = MaterialTheme.typography.bodyMedium + ) + } } } } diff --git a/composeApp/src/androidMain/kotlin/su/reya/coop/screens/HomeScreen.kt b/composeApp/src/androidMain/kotlin/su/reya/coop/screens/HomeScreen.kt index 0e5fd51..05a71cb 100644 --- a/composeApp/src/androidMain/kotlin/su/reya/coop/screens/HomeScreen.kt +++ b/composeApp/src/androidMain/kotlin/su/reya/coop/screens/HomeScreen.kt @@ -5,6 +5,7 @@ import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth @@ -56,6 +57,7 @@ import org.jetbrains.compose.resources.painterResource import su.reya.coop.LocalNostrViewModel import su.reya.coop.LocalSnackbarHostState import su.reya.coop.Room +import su.reya.coop.ago import su.reya.coop.shared.displayNameFlow import su.reya.coop.shared.pictureFlow import su.reya.coop.short @@ -265,10 +267,21 @@ fun ChatRoom(room: Room, onClick: () -> Unit) { } }, headlineContent = { - Text( - text = displayName ?: "Unknown", - style = MaterialTheme.typography.titleMediumEmphasized - ) + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = displayName, + style = MaterialTheme.typography.titleMediumEmphasized, + modifier = Modifier.weight(1f) + ) + Text( + text = room.createdAt.ago(), + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.outline + ) + } }, supportingContent = { if (!room.lastMessage.isNullOrBlank()) { diff --git a/shared/src/commonMain/kotlin/su/reya/coop/Room.kt b/shared/src/commonMain/kotlin/su/reya/coop/Room.kt index 7ccb4a8..1b2a7cb 100644 --- a/shared/src/commonMain/kotlin/su/reya/coop/Room.kt +++ b/shared/src/commonMain/kotlin/su/reya/coop/Room.kt @@ -1,6 +1,9 @@ package su.reya.coop +import kotlinx.datetime.DateTimeUnit import kotlinx.datetime.TimeZone +import kotlinx.datetime.minus +import kotlinx.datetime.number import kotlinx.datetime.toLocalDateTime import rust.nostr.sdk.Event import rust.nostr.sdk.PublicKey @@ -117,3 +120,35 @@ fun Timestamp.ago(): String { } } } + +fun Timestamp.humanReadable(): String { + val timeZone = TimeZone.currentSystemDefault() + val inputInstant = Instant.fromEpochSeconds(this.asSecs().toLong()) + val inputDateTime = inputInstant.toLocalDateTime(timeZone) + val inputDate = inputDateTime.date + + val now = Clock.System.now() + val today = now.toLocalDateTime(timeZone).date + val yesterday = today.minus(1, DateTimeUnit.DAY) + + val hour = inputDateTime.hour + val minute = inputDateTime.minute.toString().padStart(2, '0') + val amPm = if (hour < 12) "AM" else "PM" + val hour12 = when { + hour == 0 -> 12 + hour > 12 -> hour - 12 + else -> hour + } + val timeFormat = "$hour12:$minute $amPm" + + return when (inputDate) { + today -> "Today at $timeFormat" + yesterday -> "Yesterday at $timeFormat" + else -> { + val day = inputDateTime.day.toString().padStart(2, '0') + val month = inputDateTime.month.number.toString().padStart(2, '0') + val year = inputDateTime.year.toString().takeLast(2) + "$day/$month/$year, $timeFormat" + } + } +}