diff --git a/.idea/kotlinScripting.xml b/.idea/kotlinScripting.xml deleted file mode 100644 index 97f762a..0000000 --- a/.idea/kotlinScripting.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - 2147483647 - true - - - \ No newline at end of file diff --git a/app/src/main/java/net/buzzert/kordophonedroid/ui/messagelist/MessageListScreen.kt b/app/src/main/java/net/buzzert/kordophonedroid/ui/messagelist/MessageListScreen.kt index 1865a6e..e180f2a 100644 --- a/app/src/main/java/net/buzzert/kordophonedroid/ui/messagelist/MessageListScreen.kt +++ b/app/src/main/java/net/buzzert/kordophonedroid/ui/messagelist/MessageListScreen.kt @@ -14,6 +14,7 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.imePadding import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyListState import androidx.compose.foundation.lazy.rememberLazyListState @@ -39,9 +40,11 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha +import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.SolidColor import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.input.TextFieldValue +import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel @@ -49,6 +52,14 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import net.buzzert.kordophone.backend.model.GUID import net.buzzert.kordophone.backend.model.Message import net.buzzert.kordophonedroid.ui.theme.KordophoneTopAppBar +import java.text.SimpleDateFormat +import java.time.Duration +import java.time.Instant +import java.time.LocalDate +import java.time.Period +import java.time.format.DateTimeFormatter +import java.time.format.FormatStyle +import java.util.Date private val IncomingChatBubbleShape = RoundedCornerShape(4.dp, 20.dp, 20.dp, 20.dp) private val OutgoingChatBubbleShape = RoundedCornerShape(20.dp, 4.dp, 20.dp, 20.dp) @@ -56,6 +67,7 @@ private val OutgoingChatBubbleShape = RoundedCornerShape(20.dp, 4.dp, 20.dp, 20. data class MessageListViewItem( val text: String, val fromMe: Boolean, + val date: Date, val delivered: Boolean = true, ) @@ -79,6 +91,7 @@ fun MessageListScreen( MessageListViewItem( text = it.text, fromMe = it.sender == null, + date = it.date, delivered = !viewModel.isPendingMessage(it) ) } @@ -140,14 +153,48 @@ fun Messages( .fillMaxSize() .padding(horizontal = 16.dp) ) { + var lastDate: Date? = null + val dateFormatter = SimpleDateFormat.getDateTimeInstance() + for (index in messages.indices) { val content = messages[index] + if (lastDate == null) { + lastDate = content.date + } + + val duration = Duration.between(content.date.toInstant(), lastDate.toInstant()) + lastDate = content.date + + Log.d("MessageListScreen", "period: $duration") + + // Remember: This is upside down. item { MessageBubble( text = content.text, mine = content.fromMe, - modifier = Modifier.alpha(if (!content.delivered) 0.5F else 1.0f) + modifier = Modifier + .alpha(if (!content.delivered) 0.5F else 1.0f) ) + + // Greater than 30 minutes: show date: + if (duration.toMinutes() > 30) { + val formattedDate = dateFormatter.format(content.date) + Text( + text = formattedDate, + textAlign = TextAlign.Center, + style = MaterialTheme.typography.caption.copy( + color = MaterialTheme.colors.onSurface.copy(alpha = 0.4f) + ), + modifier = Modifier + .fillMaxWidth() + .padding(18.dp), + ) + } + + // Greater than five minutes: add a bit of space. + else if (duration.toMinutes() > 5) { + Spacer(modifier = Modifier.height(12.dp)) + } } } } @@ -163,21 +210,27 @@ fun MessageBubble( val backgroundBubbleColor = if (mine) MaterialTheme.colors.primary else MaterialTheme.colors.secondary Column() { - Row( - modifier = modifier.fillMaxWidth(), - horizontalArrangement = if (mine) Arrangement.End else Arrangement.Start, - ) { - Surface( - color = backgroundBubbleColor, - shape = if (mine) OutgoingChatBubbleShape else IncomingChatBubbleShape, + Row(modifier = modifier.fillMaxWidth()) { + if (mine) { Spacer(modifier = Modifier.weight(1f)) } + + Row( + modifier = Modifier.fillMaxWidth(0.8f), + horizontalArrangement = if (mine) Arrangement.End else Arrangement.Start, ) { - Text( - text = text, - style = MaterialTheme.typography.body1, - modifier = Modifier - .padding(16.dp) - ) + Surface( + color = backgroundBubbleColor, + shape = if (mine) OutgoingChatBubbleShape else IncomingChatBubbleShape, + ) { + Text( + text = text, + style = MaterialTheme.typography.body1, + modifier = Modifier + .padding(16.dp) + ) + } } + + if (!mine) { Spacer(modifier = Modifier.weight(1f)) } } Spacer(modifier = Modifier.height(4.dp)) @@ -190,9 +243,9 @@ fun MessageBubble( @Composable private fun MessageListScreenPreview() { val messages = listOf( - MessageListViewItem(text = "Hello", fromMe = false), - MessageListViewItem(text = "Hey there", fromMe = true), - MessageListViewItem(text = "How's it going", fromMe = true, delivered = false) + MessageListViewItem(text = "Hello", fromMe = false, date = Date()), + MessageListViewItem(text = "Hey there, this is a longer text message that might wrap to another line", fromMe = true, date = Date()), + MessageListViewItem(text = "How's it going", fromMe = true, delivered = false, date = Date()) ).reversed() Scaffold() {