diff --git a/app/src/main/kotlin/com/wire/android/ui/home/conversations/ConversationScreen.kt b/app/src/main/kotlin/com/wire/android/ui/home/conversations/ConversationScreen.kt index 92924b93233..7dea288b51e 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/conversations/ConversationScreen.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/conversations/ConversationScreen.kt @@ -1061,11 +1061,12 @@ fun MessageList( if (index > 0) { val previousMessage = lazyPagingMessages[index - 1] ?: message + val shouldDisplayDateTimeDivider = message.header.messageTime.shouldDisplayDatesDifferenceDivider( + previousDate = previousMessage.header.messageTime.utcISO + ) - val currentGroup = message.header.messageTime.getFormattedDateGroup(now = currentTime) - val previousGroup = previousMessage.header.messageTime.getFormattedDateGroup(now = currentTime) - - if (currentGroup != previousGroup) { + if (shouldDisplayDateTimeDivider) { + val previousGroup = previousMessage.header.messageTime.getFormattedDateGroup(now = currentTime) previousMessage.header.messageTime.utcISO.serverDate()?.let { serverDate -> MessageGroupDateTime( messageDateTime = serverDate, @@ -1110,6 +1111,19 @@ fun MessageList( isSelectedMessage = (message.header.messageId == selectedMessageId), isInteractionAvailable = interactionAvailability == InteractionAvailability.ENABLED ) + + val isTheOnlyItem = index == 0 && lazyPagingMessages.itemCount == 1 + val isTheLastItem = (index + 1) == lazyPagingMessages.itemCount + if (isTheOnlyItem || isTheLastItem) { + val currentGroup = message.header.messageTime.getFormattedDateGroup(now = currentTime) + message.header.messageTime.utcISO.serverDate()?.let { serverDate -> + MessageGroupDateTime( + messageDateTime = serverDate, + messageDateTimeGroup = currentGroup, + now = currentTime + ) + } + } } } JumpToLastMessageButton(lazyListState = lazyListState) @@ -1178,6 +1192,10 @@ private fun MessageGroupDateTime( Row( Modifier .fillMaxWidth() + .padding( + top = dimensions().spacing4x, + bottom = dimensions().spacing8x + ) .background(color = colorsScheme().divider) .padding( top = dimensions().spacing6x, diff --git a/app/src/main/kotlin/com/wire/android/ui/home/conversations/model/UIMessage.kt b/app/src/main/kotlin/com/wire/android/ui/home/conversations/model/UIMessage.kt index d568387f0f9..ab0105f090b 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/conversations/model/UIMessage.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/conversations/model/UIMessage.kt @@ -33,6 +33,7 @@ import com.wire.android.ui.theme.Accent import com.wire.android.util.Copyable import com.wire.android.util.MessageDateTimeGroup import com.wire.android.util.groupedUIMessageDateTime +import com.wire.android.util.shouldDisplayDatesDifferenceDivider import com.wire.android.util.ui.LocalizedStringResource import com.wire.android.util.ui.UIText import com.wire.android.util.uiMessageDateTime @@ -626,6 +627,8 @@ enum class MessageSource { data class MessageTime(val utcISO: String) { val formattedDate: String = utcISO.uiMessageDateTime() ?: "" fun getFormattedDateGroup(now: Long): MessageDateTimeGroup? = utcISO.groupedUIMessageDateTime(now = now) + fun shouldDisplayDatesDifferenceDivider(previousDate: String): Boolean = + utcISO.shouldDisplayDatesDifferenceDivider(previousDate = previousDate) } @Stable diff --git a/app/src/main/kotlin/com/wire/android/util/DateTimeUtil.kt b/app/src/main/kotlin/com/wire/android/util/DateTimeUtil.kt index a5086799790..0e712b80d2b 100644 --- a/app/src/main/kotlin/com/wire/android/util/DateTimeUtil.kt +++ b/app/src/main/kotlin/com/wire/android/util/DateTimeUtil.kt @@ -20,7 +20,6 @@ package com.wire.android.util -import android.text.format.DateUtils import com.wire.android.appLogger import kotlinx.datetime.Instant import java.text.DateFormat @@ -28,6 +27,7 @@ import java.text.ParseException import java.text.SimpleDateFormat import java.time.LocalDate import java.time.ZoneId +import java.time.temporal.ChronoUnit import java.util.Calendar import java.util.Date import java.util.Locale @@ -43,16 +43,15 @@ private val longDateShortTimeFormat = DateFormat .getDateTimeInstance(DateFormat.LONG, DateFormat.SHORT) private val mediumOnlyDateTimeFormat = DateFormat .getDateInstance(DateFormat.MEDIUM) -val messageTimeFormatter = DateFormat +private val messageTimeFormatter = DateFormat .getTimeInstance(DateFormat.SHORT) .apply { timeZone = TimeZone.getDefault() } -private val messageDateTimeFormatter = DateFormat - .getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT) - .apply { timeZone = TimeZone.getDefault() } private const val ONE_MINUTE_FROM_MILLIS = 60 * 1000 private const val THIRTY_MINUTES = 30 private const val ONE_WEEK_IN_DAYS = 7 private const val ONE_DAY = 1 +private const val FORTY_FIVE_MINUTES_DIFFERENCE = 45 +private const val MINIMUM_DAYS_DIFFERENCE = 1 private val readReceiptDateTimeFormat = SimpleDateFormat( "MMM dd yyyy, hh:mm a", @@ -181,12 +180,28 @@ sealed interface MessageDateTimeGroup { fun String.uiMessageDateTime(): String? = this .serverDate()?.let { serverDate -> - when (DateUtils.isToday(serverDate.time)) { - true -> messageTimeFormatter.format(serverDate) - false -> messageDateTimeFormatter.format(serverDate) - } + messageTimeFormatter.format(serverDate) } +fun String.shouldDisplayDatesDifferenceDivider(previousDate: String): Boolean { + val currentDate = this@shouldDisplayDatesDifferenceDivider + + val currentLocalDateTime = currentDate.serverDate()?.toInstant()?.atZone(ZoneId.systemDefault())?.toLocalDateTime() + val previousLocalDateTime = previousDate.serverDate()?.toInstant()?.atZone(ZoneId.systemDefault())?.toLocalDateTime() + + val differenceInMinutes = ChronoUnit.MINUTES.between( + currentLocalDateTime, + previousLocalDateTime + ) + + val differenceInDays = ChronoUnit.DAYS.between( + currentLocalDateTime, + previousLocalDateTime + ) + + return differenceInMinutes > FORTY_FIVE_MINUTES_DIFFERENCE || differenceInDays >= MINIMUM_DAYS_DIFFERENCE +} + fun String.groupedUIMessageDateTime(now: Long): MessageDateTimeGroup? = this .serverDate()?.let { serverDate -> val localDate = serverDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate()