From 64238c488a370a302d62570eecbb5305fd61e31d Mon Sep 17 00:00:00 2001 From: Vitor Hugo Schwaab Date: Thu, 27 Jun 2024 17:23:42 +0200 Subject: [PATCH] refactor!: use Instant instead of string in most places [WPB-9216] (#3139) --- .../wire/android/GlobalObserversManager.kt | 1 + .../com/wire/android/mapper/MessageMapper.kt | 4 +- .../mapper/RegularMessageContentMapper.kt | 4 +- .../mapper/SystemMessageContentMapper.kt | 7 +- .../wire/android/migration/MigrationMapper.kt | 21 ++-- .../userDatabase/ScalaConversationDAO.kt | 4 +- .../wire/android/ui/common/AppExtensions.kt | 3 +- .../messages/ConversationMessagesViewModel.kt | 5 +- .../ui/home/conversations/mock/Mock.kt | 21 ++-- .../ui/home/conversations/model/UIMessage.kt | 5 +- ...GetAssetMessagesFromConversationUseCase.kt | 2 +- .../wire/android/util/time/ISOFormatter.kt | 7 +- .../android/GlobalObserversManagerTest.kt | 5 + .../test/kotlin/com/wire/android/TestUtil.kt | 10 +- .../wire/android/framework/TestConnection.kt | 3 +- .../android/framework/TestConversation.kt | 11 ++- .../framework/TestConversationDetails.kt | 3 +- .../com/wire/android/framework/TestMessage.kt | 21 ++-- .../wire/android/mapper/MessageMapperTest.kt | 34 +++---- .../mapper/SystemMessageContentMapperTest.kt | 19 +++- .../conversations/AuthorHeaderHelperTest.kt | 96 ++++++++++--------- .../MessageComposerViewModelArrangement.kt | 3 +- .../GroupConversationDetailsViewModelTest.kt | 3 +- .../home/gallery/MediaGalleryViewModelTest.kt | 3 +- .../NewConversationViewModelArrangement.kt | 3 +- .../OtherUserProfileScreenViewModelTest.kt | 3 +- kalium | 2 +- 27 files changed, 171 insertions(+), 132 deletions(-) diff --git a/app/src/main/kotlin/com/wire/android/GlobalObserversManager.kt b/app/src/main/kotlin/com/wire/android/GlobalObserversManager.kt index 71744a199f0..b63a9da0626 100644 --- a/app/src/main/kotlin/com/wire/android/GlobalObserversManager.kt +++ b/app/src/main/kotlin/com/wire/android/GlobalObserversManager.kt @@ -60,6 +60,7 @@ class GlobalObserversManager @Inject constructor( private val userDataStoreProvider: UserDataStoreProvider, private val currentScreenManager: CurrentScreenManager, ) { + // TODO(tests): refactor so scope/dispatcher can be injected and properly stopped private val scope = CoroutineScope(SupervisorJob() + dispatcherProvider.io()) fun observe() { diff --git a/app/src/main/kotlin/com/wire/android/mapper/MessageMapper.kt b/app/src/main/kotlin/com/wire/android/mapper/MessageMapper.kt index 8361f4758f8..e6fa20f779e 100644 --- a/app/src/main/kotlin/com/wire/android/mapper/MessageMapper.kt +++ b/app/src/main/kotlin/com/wire/android/mapper/MessageMapper.kt @@ -185,8 +185,8 @@ class MessageMapper @Inject constructor( flowStatus = flowStatus, editStatus = if (message is Message.Regular && message.editStatus is Message.EditStatus.Edited) { MessageEditStatus.Edited( - isoFormatter.fromISO8601ToTimeFormat( - utcISO = (message.editStatus as Message.EditStatus.Edited).lastTimeStamp + isoFormatter.fromInstantToTimeFormatter( + instant = (message.editStatus as Message.EditStatus.Edited).lastEditInstant ) ) } else { diff --git a/app/src/main/kotlin/com/wire/android/mapper/RegularMessageContentMapper.kt b/app/src/main/kotlin/com/wire/android/mapper/RegularMessageContentMapper.kt index b65d0c90804..4d374fd46c6 100644 --- a/app/src/main/kotlin/com/wire/android/mapper/RegularMessageContentMapper.kt +++ b/app/src/main/kotlin/com/wire/android/mapper/RegularMessageContentMapper.kt @@ -194,9 +194,9 @@ class RegularMessageMapper @Inject constructor( it.messageId, it.senderId, it.senderName.orUnknownName(), - UIText.StringResource(R.string.label_quote_original_message_date, isoFormatter.fromISO8601ToTimeFormat(it.timeInstant.toString())), + UIText.StringResource(R.string.label_quote_original_message_date, isoFormatter.fromInstantToTimeFormatter(it.timeInstant)), it.editInstant?.let { instant -> - UIText.StringResource(R.string.label_message_status_edited_with_date, isoFormatter.fromISO8601ToTimeFormat(instant.toString())) + UIText.StringResource(R.string.label_message_status_edited_with_date, isoFormatter.fromInstantToTimeFormatter(instant)) }, when (val quotedContent = it.quotedContent) { is MessageContent.QuotedMessageDetails.Asset -> when (AttachmentType.fromMimeTypeString(quotedContent.assetMimeType)) { diff --git a/app/src/main/kotlin/com/wire/android/mapper/SystemMessageContentMapper.kt b/app/src/main/kotlin/com/wire/android/mapper/SystemMessageContentMapper.kt index 752eb9dc28d..611c6f1d0eb 100644 --- a/app/src/main/kotlin/com/wire/android/mapper/SystemMessageContentMapper.kt +++ b/app/src/main/kotlin/com/wire/android/mapper/SystemMessageContentMapper.kt @@ -37,6 +37,8 @@ import com.wire.kalium.logic.data.user.OtherUser import com.wire.kalium.logic.data.user.SelfUser import com.wire.kalium.logic.data.user.User import com.wire.kalium.logic.data.user.UserId +import com.wire.kalium.util.DateTimeUtil.toIsoDateTimeString +import kotlinx.datetime.Instant import java.util.Locale import javax.inject.Inject import kotlin.time.Duration.Companion.milliseconds @@ -74,16 +76,17 @@ class SystemMessageContentMapper @Inject constructor( is MessageContent.LegalHold -> mapLegalHoldMessage(content, message.senderUserId, members) } - private fun mapConversationCreated(senderUserId: UserId, date: String, userList: List): UIMessageContent.SystemMessage { + private fun mapConversationCreated(senderUserId: UserId, date: Instant, userList: List): UIMessageContent.SystemMessage { val sender = userList.findUser(userId = senderUserId) val authorName = mapMemberName( user = sender, type = SelfNameType.ResourceTitleCase ) + val dateString = date.toIsoDateTimeString() return UIMessageContent.SystemMessage.ConversationMessageCreated( author = authorName, isAuthorSelfUser = sender is SelfUser, - date.formatFullDateShortTime().orDefault(date).uppercase(Locale.getDefault()) + dateString.formatFullDateShortTime().orDefault(dateString).uppercase(Locale.getDefault()) ) } diff --git a/app/src/main/kotlin/com/wire/android/migration/MigrationMapper.kt b/app/src/main/kotlin/com/wire/android/migration/MigrationMapper.kt index 0b8762851ef..cd8518024ff 100644 --- a/app/src/main/kotlin/com/wire/android/migration/MigrationMapper.kt +++ b/app/src/main/kotlin/com/wire/android/migration/MigrationMapper.kt @@ -41,7 +41,7 @@ import com.wire.kalium.logic.data.user.SupportedProtocol import com.wire.kalium.logic.data.user.UserAvailabilityStatus import com.wire.kalium.logic.data.user.UserId import com.wire.kalium.logic.data.user.type.UserType -import com.wire.kalium.util.DateTimeUtil +import kotlinx.datetime.Instant import javax.inject.Inject import javax.inject.Singleton @@ -72,17 +72,16 @@ class MigrationMapper @Inject constructor() { fun fromScalaConversationToConversation(scalaConversation: ScalaConversationData, selfUserId: UserId) = with(scalaConversation) { mapConversationType(type)?.let { - val lastEventTime: String = - if (orderTime == null || orderTime == 0L) { - "1970-01-01T00:00:00.000Z" - } else { - DateTimeUtil.fromEpochMillisToIsoDateTimeString(orderTime) - } - - val conversationLastReadTime = if (lastReadTime == null || lastReadTime == 0L) { - "1970-01-01T00:00:00.000Z" + val lastEventTime: Instant = if (orderTime == null || orderTime == 0L) { + Instant.DISTANT_PAST } else { - DateTimeUtil.fromEpochMillisToIsoDateTimeString(lastReadTime) + Instant.fromEpochMilliseconds(orderTime) + } + + val conversationLastReadTime = if (lastReadTimeInMillis == null || lastReadTimeInMillis == 0L) { + Instant.DISTANT_PAST + } else { + Instant.fromEpochMilliseconds(lastReadTimeInMillis) } Conversation( diff --git a/app/src/main/kotlin/com/wire/android/migration/userDatabase/ScalaConversationDAO.kt b/app/src/main/kotlin/com/wire/android/migration/userDatabase/ScalaConversationDAO.kt index 190b604a690..48a871ccf0d 100644 --- a/app/src/main/kotlin/com/wire/android/migration/userDatabase/ScalaConversationDAO.kt +++ b/app/src/main/kotlin/com/wire/android/migration/userDatabase/ScalaConversationDAO.kt @@ -40,7 +40,7 @@ data class ScalaConversationData( val creatorId: String, val receiptMode: Int?, val orderTime: Long?, - val lastReadTime: Long? + val lastReadTimeInMillis: Long? ) class ScalaConversationDAO( @@ -86,7 +86,7 @@ class ScalaConversationDAO( creatorId = cursor.getStringOrNull(creatorIdIndex).orEmpty(), receiptMode = receiptModeIndex?.let { cursor.getIntOrNull(it) }, orderTime = lastEventTimeIndex?.let { cursor.getLongOrNull(it) }, - lastReadTime = lastReadTimeIndex?.let { cursor.getLongOrNull(it) } + lastReadTimeInMillis = lastReadTimeIndex?.let { cursor.getLongOrNull(it) } ) } while (cursor.moveToNext()) accumulator diff --git a/app/src/main/kotlin/com/wire/android/ui/common/AppExtensions.kt b/app/src/main/kotlin/com/wire/android/ui/common/AppExtensions.kt index c6bb16bfc7e..25ea3fa6722 100644 --- a/app/src/main/kotlin/com/wire/android/ui/common/AppExtensions.kt +++ b/app/src/main/kotlin/com/wire/android/ui/common/AppExtensions.kt @@ -45,7 +45,6 @@ import kotlinx.coroutines.flow.StateFlow import kotlinx.datetime.Instant import kotlinx.datetime.LocalDateTime import kotlinx.datetime.TimeZone -import kotlinx.datetime.toInstant import kotlinx.datetime.toLocalDateTime import java.time.format.TextStyle import java.util.Locale @@ -122,6 +121,6 @@ fun List.toImageAssetGroupedByMonthAndYear(timeZone: TimeZone) = } fun List.toGenericAssetGroupedByMonthAndYear(timeZone: TimeZone) = this.groupBy { message -> - val localDateTime = message.date.toInstant().toLocalDateTime(timeZone) + val localDateTime = message.date.toLocalDateTime(timeZone) monthYearHeader(year = localDateTime.year, month = localDateTime.monthNumber) } diff --git a/app/src/main/kotlin/com/wire/android/ui/home/conversations/messages/ConversationMessagesViewModel.kt b/app/src/main/kotlin/com/wire/android/ui/home/conversations/messages/ConversationMessagesViewModel.kt index 9b8afe7520c..d7ffb2d2165 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/conversations/messages/ConversationMessagesViewModel.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/conversations/messages/ConversationMessagesViewModel.kt @@ -79,7 +79,6 @@ import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.shareIn import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -import kotlinx.datetime.Instant import okio.Path import javax.inject.Inject import kotlin.math.max @@ -239,9 +238,7 @@ class ConversationMessagesViewModel @Inject constructor( .flowOn(dispatchers.io()) .collect { conversationDetailsResult -> if (conversationDetailsResult is ObserveConversationDetailsUseCase.Result.Success) { - val lastUnreadInstant = conversationDetailsResult.conversationDetails.conversation.lastReadDate.let { - Instant.parse(it) - } + val lastUnreadInstant = conversationDetailsResult.conversationDetails.conversation.lastReadDate conversationViewState = conversationViewState.copy(firstUnreadInstant = lastUnreadInstant) } } diff --git a/app/src/main/kotlin/com/wire/android/ui/home/conversations/mock/Mock.kt b/app/src/main/kotlin/com/wire/android/ui/home/conversations/mock/Mock.kt index decf9bf9e71..4b3d6e56664 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/conversations/mock/Mock.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/conversations/mock/Mock.kt @@ -52,6 +52,7 @@ import com.wire.kalium.network.NetworkState import com.wire.kalium.network.NetworkStateObserver import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow +import kotlinx.datetime.Clock val mockFooter = MessageFooter("", mapOf("👍" to 1), setOf("👍")) val mockEmptyFooter = MessageFooter("", emptyMap(), emptySet()) @@ -60,7 +61,7 @@ val mockHeader = MessageHeader( username = UIText.DynamicString("John Doe"), membership = Membership.Guest, isLegalHold = true, - messageTime = MessageTime("12.23pm"), + messageTime = MessageTime(Clock.System.now()), messageStatus = MessageStatus( flowStatus = MessageFlowStatus.Sent, expirationStatus = ExpirationStatus.NotExpirable @@ -302,7 +303,7 @@ fun mockAssetMessage() = UIMessage.Regular( username = UIText.DynamicString("John Doe"), membership = Membership.Guest, isLegalHold = true, - messageTime = MessageTime("12.23pm"), + messageTime = MessageTime(Clock.System.now()), messageStatus = MessageStatus( flowStatus = MessageFlowStatus.Sent, expirationStatus = ExpirationStatus.NotExpirable @@ -343,7 +344,7 @@ fun mockedImageUIMessage( username = UIText.DynamicString("John Doe"), membership = Membership.External, isLegalHold = false, - messageTime = MessageTime("12.23pm"), + messageTime = MessageTime(Clock.System.now()), messageStatus = messageStatus, messageId = messageId, connectionState = ConnectionState.ACCEPTED, @@ -364,7 +365,7 @@ fun getMockedMessages(): List = listOf( username = UIText.DynamicString("John Doe"), membership = Membership.Guest, isLegalHold = true, - messageTime = MessageTime("12.23pm"), + messageTime = MessageTime(Clock.System.now()), messageStatus = MessageStatus( flowStatus = MessageFlowStatus.Sent, expirationStatus = ExpirationStatus.NotExpirable @@ -394,7 +395,7 @@ fun getMockedMessages(): List = listOf( username = UIText.DynamicString("John Doe"), membership = Membership.Guest, isLegalHold = true, - messageTime = MessageTime("12.23pm"), + messageTime = MessageTime(Clock.System.now()), messageStatus = MessageStatus( flowStatus = MessageFlowStatus.Delivered, isDeleted = true, expirationStatus = ExpirationStatus.NotExpirable @@ -415,7 +416,7 @@ fun getMockedMessages(): List = listOf( username = UIText.DynamicString("John Doe"), membership = Membership.External, isLegalHold = false, - messageTime = MessageTime("12.23pm"), + messageTime = MessageTime(Clock.System.now()), messageStatus = MessageStatus( flowStatus = MessageFlowStatus.Sent, editStatus = MessageEditStatus.Edited("May 31, 2022 12.24pm"), @@ -437,7 +438,7 @@ fun getMockedMessages(): List = listOf( username = UIText.DynamicString("John Doe"), membership = Membership.External, isLegalHold = false, - messageTime = MessageTime("12.23pm"), + messageTime = MessageTime(Clock.System.now()), messageStatus = MessageStatus( flowStatus = MessageFlowStatus.Sent, editStatus = MessageEditStatus.Edited("May 31, 2022 12.24pm"), @@ -459,7 +460,7 @@ fun getMockedMessages(): List = listOf( username = UIText.DynamicString("John Doe"), membership = Membership.External, isLegalHold = false, - messageTime = MessageTime("12.23pm"), + messageTime = MessageTime(Clock.System.now()), messageStatus = MessageStatus( flowStatus = MessageFlowStatus.Delivered, isDeleted = true, @@ -490,7 +491,7 @@ fun getMockedMessages(): List = listOf( username = UIText.DynamicString("John Doe"), membership = Membership.External, isLegalHold = false, - messageTime = MessageTime("12.23pm"), + messageTime = MessageTime(Clock.System.now()), messageStatus = MessageStatus( flowStatus = MessageFlowStatus.Sent, editStatus = MessageEditStatus.Edited("May 31, 2022 12.24pm"), @@ -512,7 +513,7 @@ fun getMockedMessages(): List = listOf( username = UIText.DynamicString("John Doe"), membership = Membership.External, isLegalHold = false, - messageTime = MessageTime("12.23pm"), + messageTime = MessageTime(Clock.System.now()), messageStatus = MessageStatus( flowStatus = MessageFlowStatus.Sent, editStatus = MessageEditStatus.Edited("May 31, 2022 12.24pm"), 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 ab0105f090b..8148aa3167e 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 @@ -45,12 +45,14 @@ import com.wire.kalium.logic.data.message.MessageContent import com.wire.kalium.logic.data.user.AssetId import com.wire.kalium.logic.data.user.ConnectionState import com.wire.kalium.logic.data.user.UserId +import com.wire.kalium.util.DateTimeUtil.toIsoDateTimeString import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.ImmutableMap import kotlinx.collections.immutable.PersistentList import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentMapOf import kotlinx.collections.immutable.toImmutableList +import kotlinx.datetime.Instant import kotlin.time.Duration sealed interface UIMessage { @@ -624,7 +626,8 @@ enum class MessageSource { Self, OtherUser } -data class MessageTime(val utcISO: String) { +data class MessageTime(val instant: Instant) { + val utcISO: String = instant.toIsoDateTimeString() val formattedDate: String = utcISO.uiMessageDateTime() ?: "" fun getFormattedDateGroup(now: Long): MessageDateTimeGroup? = utcISO.groupedUIMessageDateTime(now = now) fun shouldDisplayDatesDifferenceDivider(previousDate: String): Boolean = diff --git a/app/src/main/kotlin/com/wire/android/ui/home/conversations/usecase/GetAssetMessagesFromConversationUseCase.kt b/app/src/main/kotlin/com/wire/android/ui/home/conversations/usecase/GetAssetMessagesFromConversationUseCase.kt index 9563a17deed..fab1e4ab1ab 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/conversations/usecase/GetAssetMessagesFromConversationUseCase.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/conversations/usecase/GetAssetMessagesFromConversationUseCase.kt @@ -68,7 +68,7 @@ class GetAssetMessagesFromConversationUseCase @Inject constructor( val uiMessagePagingData: PagingData = pagingData.flatMap { messageItem -> val usersForMessage = getUsersForMessage(messageItem) messageMapper.toUIMessage(usersForMessage, messageItem) - ?.let { listOf(UIPagingItem.Message(it, Instant.parse(messageItem.date))) } + ?.let { listOf(UIPagingItem.Message(it, messageItem.date)) } ?: emptyList() }.insertSeparators { before: UIPagingItem.Message?, after: UIPagingItem.Message? -> if (before == null && after != null) { diff --git a/app/src/main/kotlin/com/wire/android/util/time/ISOFormatter.kt b/app/src/main/kotlin/com/wire/android/util/time/ISOFormatter.kt index 52503309175..d258293fe00 100644 --- a/app/src/main/kotlin/com/wire/android/util/time/ISOFormatter.kt +++ b/app/src/main/kotlin/com/wire/android/util/time/ISOFormatter.kt @@ -18,16 +18,17 @@ package com.wire.android.util.time +import kotlinx.datetime.Instant +import kotlinx.datetime.toJavaInstant import java.text.DateFormat -import java.time.Instant import java.util.Date import javax.inject.Inject class ISOFormatter @Inject constructor() { - fun fromISO8601ToTimeFormat(utcISO: String): String { + fun fromInstantToTimeFormatter(instant: Instant): String { val formatter = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.SHORT) - val date = Date.from(Instant.parse(utcISO)) + val date = Date.from(instant.toJavaInstant()) return formatter.format(date) } diff --git a/app/src/test/kotlin/com/wire/android/GlobalObserversManagerTest.kt b/app/src/test/kotlin/com/wire/android/GlobalObserversManagerTest.kt index e9579c3534b..f725bb2f9fc 100644 --- a/app/src/test/kotlin/com/wire/android/GlobalObserversManagerTest.kt +++ b/app/src/test/kotlin/com/wire/android/GlobalObserversManagerTest.kt @@ -34,6 +34,7 @@ import com.wire.kalium.logic.data.team.Team import com.wire.kalium.logic.data.user.SelfUser import com.wire.kalium.logic.feature.UserSessionScope import com.wire.kalium.logic.feature.auth.LogoutCallbackManager +import com.wire.kalium.logic.feature.call.CallsScope import com.wire.kalium.logic.feature.message.MessageScope import com.wire.kalium.logic.feature.session.CurrentSessionResult import com.wire.kalium.logic.feature.user.webSocketStatus.ObservePersistentWebSocketConnectionStatusUseCase @@ -183,6 +184,9 @@ class GlobalObserversManagerTest { @MockK lateinit var logoutCallbackManager: LogoutCallbackManager + @MockK + lateinit var callsScope: CallsScope + @MockK lateinit var userSessionScope: UserSessionScope @@ -209,6 +213,7 @@ class GlobalObserversManagerTest { every { notificationChannelsManager.createUserNotificationChannels(any()) } returns Unit every { coreLogic.getGlobalScope().logoutCallbackManager } returns logoutCallbackManager every { coreLogic.getSessionScope(any()) } returns userSessionScope + every { userSessionScope.calls } returns callsScope every { userSessionScope.messages } returns messageScope coEvery { messageScope.deleteEphemeralMessageEndDate() } returns Unit withPersistentWebSocketConnectionStatuses(emptyList()) diff --git a/app/src/test/kotlin/com/wire/android/TestUtil.kt b/app/src/test/kotlin/com/wire/android/TestUtil.kt index 5c934c8661f..b431016dedd 100644 --- a/app/src/test/kotlin/com/wire/android/TestUtil.kt +++ b/app/src/test/kotlin/com/wire/android/TestUtil.kt @@ -18,6 +18,8 @@ package com.wire.android import org.junit.jupiter.api.Assertions +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.contract import kotlin.random.Random val charPoolWithNumbers: List = ('a'..'z') + ('A'..'Z') + ('0'..'9') @@ -31,4 +33,10 @@ fun Random.string(length: Int) = (1..length) .map { Random.nextInt(0, charPool.size).let { charPool[it] } } .joinToString("") -inline fun assertIs(actualValue: Any): T = Assertions.assertInstanceOf(T::class.java, actualValue) +@OptIn(ExperimentalContracts::class) +inline fun assertIs(actualValue: Any): T { + contract { + returns() implies (actualValue is T) + } + return Assertions.assertInstanceOf(T::class.java, actualValue) +} diff --git a/app/src/test/kotlin/com/wire/android/framework/TestConnection.kt b/app/src/test/kotlin/com/wire/android/framework/TestConnection.kt index 9eb0d4e14ef..56759e5d796 100644 --- a/app/src/test/kotlin/com/wire/android/framework/TestConnection.kt +++ b/app/src/test/kotlin/com/wire/android/framework/TestConnection.kt @@ -20,12 +20,13 @@ package com.wire.android.framework import com.wire.kalium.logic.data.user.Connection import com.wire.kalium.logic.data.user.ConnectionState +import kotlinx.datetime.Instant object TestConnection { val CONNECTION = Connection( TestConversation.ID.value, "FROM", - "2022-03-30T15:36:00.000Z", + Instant.parse("2022-03-30T15:36:00.000Z"), TestConversation.ID, TestUser.USER_ID, ConnectionState.SENT, diff --git a/app/src/test/kotlin/com/wire/android/framework/TestConversation.kt b/app/src/test/kotlin/com/wire/android/framework/TestConversation.kt index dcb717edbb8..0397a2ca9ab 100644 --- a/app/src/test/kotlin/com/wire/android/framework/TestConversation.kt +++ b/app/src/test/kotlin/com/wire/android/framework/TestConversation.kt @@ -25,6 +25,7 @@ import com.wire.kalium.logic.data.conversation.MutedConversationStatus import com.wire.kalium.logic.data.id.ConversationId import com.wire.kalium.logic.data.id.GroupID import com.wire.kalium.logic.data.user.UserId +import kotlinx.datetime.Instant object TestConversation { val ID = ConversationId("valueConvo", "domainConvo") @@ -41,7 +42,7 @@ object TestConversation { null, null, null, - lastReadDate = "2022-03-30T15:36:00.000Z", + lastReadDate = Instant.parse("2022-03-30T15:36:00.000Z"), access = listOf(Conversation.Access.CODE, Conversation.Access.INVITE), accessRole = listOf(Conversation.AccessRole.NON_TEAM_MEMBER, Conversation.AccessRole.GUEST), creatorId = null, @@ -64,7 +65,7 @@ object TestConversation { null, null, null, - lastReadDate = "2022-03-30T15:36:00.000Z", + lastReadDate = Instant.parse("2022-03-30T15:36:00.000Z"), access = listOf(Conversation.Access.CODE, Conversation.Access.INVITE), accessRole = listOf(Conversation.AccessRole.NON_TEAM_MEMBER, Conversation.AccessRole.GUEST), creatorId = null, @@ -88,7 +89,7 @@ object TestConversation { null, null, null, - lastReadDate = "2022-03-30T15:36:00.000Z", + lastReadDate = Instant.parse("2022-03-30T15:36:00.000Z"), access = listOf(Conversation.Access.CODE, Conversation.Access.INVITE), accessRole = listOf(Conversation.AccessRole.NON_TEAM_MEMBER, Conversation.AccessRole.GUEST), creatorId = null, @@ -112,7 +113,7 @@ object TestConversation { null, null, null, - lastReadDate = "2022-03-30T15:36:00.000Z", + lastReadDate = Instant.parse("2022-03-30T15:36:00.000Z"), access = listOf(Conversation.Access.CODE, Conversation.Access.INVITE), accessRole = listOf(Conversation.AccessRole.NON_TEAM_MEMBER, Conversation.AccessRole.GUEST), creatorId = null, @@ -145,7 +146,7 @@ object TestConversation { null, access = listOf(Conversation.Access.CODE, Conversation.Access.INVITE), accessRole = listOf(Conversation.AccessRole.NON_TEAM_MEMBER, Conversation.AccessRole.GUEST), - lastReadDate = "2022-03-30T15:36:00.000Z", + lastReadDate = Instant.parse("2022-03-30T15:36:00.000Z"), creatorId = null, receiptMode = Conversation.ReceiptMode.ENABLED, messageTimer = null, diff --git a/app/src/test/kotlin/com/wire/android/framework/TestConversationDetails.kt b/app/src/test/kotlin/com/wire/android/framework/TestConversationDetails.kt index 6798f892571..0b7c3b1d87a 100644 --- a/app/src/test/kotlin/com/wire/android/framework/TestConversationDetails.kt +++ b/app/src/test/kotlin/com/wire/android/framework/TestConversationDetails.kt @@ -22,6 +22,7 @@ import com.wire.kalium.logic.data.conversation.Conversation import com.wire.kalium.logic.data.conversation.Conversation.ProtocolInfo import com.wire.kalium.logic.data.conversation.ConversationDetails import com.wire.kalium.logic.data.user.type.UserType +import kotlinx.datetime.Instant object TestConversationDetails { @@ -29,7 +30,7 @@ object TestConversationDetails { TestConversation.ID, TestUser.OTHER_USER, UserType.EXTERNAL, - "2022-03-30T15:36:00.000Z", + Instant.parse("2022-03-30T15:36:00.000Z"), TestConnection.CONNECTION, protocolInfo = ProtocolInfo.Proteus, access = listOf(Conversation.Access.CODE, Conversation.Access.INVITE), diff --git a/app/src/test/kotlin/com/wire/android/framework/TestMessage.kt b/app/src/test/kotlin/com/wire/android/framework/TestMessage.kt index a4ec92747cc..f2320a53fa0 100644 --- a/app/src/test/kotlin/com/wire/android/framework/TestMessage.kt +++ b/app/src/test/kotlin/com/wire/android/framework/TestMessage.kt @@ -34,6 +34,7 @@ import com.wire.kalium.logic.data.message.MessageEncryptionAlgorithm import com.wire.kalium.logic.data.message.MessagePreview import com.wire.kalium.logic.data.message.MessagePreviewContent import com.wire.kalium.logic.data.user.UserId +import kotlinx.datetime.Instant object TestMessage { @@ -45,7 +46,7 @@ object TestMessage { isDecryptionResolved = false ), conversationId = ConversationId("convo-id", "convo.domain"), - date = "some-date", + date = Instant.parse("2022-03-30T15:36:00.000Z"), senderUserId = UserId("user-id", "domain"), senderClientId = ClientId("client-id"), status = Message.Status.Sent, @@ -57,7 +58,7 @@ object TestMessage { id = "messageID", content = MessageContent.Text("Some Text Message"), conversationId = ConversationId("convo-id", "convo.domain"), - date = "some-date", + date = Instant.parse("2022-03-30T15:36:00.000Z"), senderUserId = UserId("user-id", "domain"), senderClientId = ClientId("client-id"), status = Message.Status.Sent, @@ -90,7 +91,7 @@ object TestMessage { id = "messageID", content = MessageContent.Asset(ASSET_IMAGE_CONTENT), conversationId = ConversationId("convo-id", "convo.domain"), - date = "some-date", + date = Instant.parse("2022-03-30T15:36:00.000Z"), senderUserId = UserId("user-id", "domain"), senderClientId = ClientId("client-id"), status = Message.Status.Sent, @@ -101,7 +102,7 @@ object TestMessage { id = "messageID", content = MessageContent.Unknown("some-unhandled-message"), conversationId = ConversationId("convo-id", "convo.domain"), - date = "some-date", + date = Instant.parse("2022-03-30T15:36:00.000Z"), senderUserId = UserId("user-id", "domain"), senderClientId = ClientId("client-id"), status = Message.Status.Sent, @@ -113,7 +114,7 @@ object TestMessage { id = "messageID", content = MessageContent.Asset(assetContent), conversationId = ConversationId("convo-id", "convo.domain"), - date = "some-date", + date = Instant.parse("2022-03-30T15:36:00.000Z"), senderUserId = UserId("user-id", "domain"), senderClientId = ClientId("client-id"), status = Message.Status.Sent, @@ -125,7 +126,7 @@ object TestMessage { id = "messageID", content = MessageContent.MissedCall, conversationId = ConversationId("convo-id", "convo.domain"), - date = "some-date", + date = Instant.parse("2022-03-30T15:36:00.000Z"), senderUserId = UserId("user-id", "domain"), status = Message.Status.Sent, expirationData = null @@ -135,7 +136,7 @@ object TestMessage { id = "messageID", content = MessageContent.MemberChange.Removed(listOf(UserId("user-id", "domain"))), conversationId = ConversationId("convo-id", "convo.domain"), - date = "some-date", + date = Instant.parse("2022-03-30T15:36:00.000Z"), senderUserId = UserId("user-id", "domain"), status = Message.Status.Sent, expirationData = null @@ -144,7 +145,7 @@ object TestMessage { username = UIText.DynamicString("username"), membership = Membership.Guest, isLegalHold = true, - messageTime = MessageTime("12.23pm"), + messageTime = MessageTime(Instant.parse("2022-03-30T15:36:00.000Z")), messageStatus = MessageStatus( flowStatus = MessageFlowStatus.Sent, expirationStatus = ExpirationStatus.NotExpirable @@ -158,7 +159,7 @@ object TestMessage { id = "messageID", content = MessageContent.MissedCall, conversationId = ConversationId("convo-id", "convo.domain"), - date = "some-date", + date = Instant.parse("2022-03-30T15:36:00.000Z"), senderUserId = UserId("user-id", "domain"), status = Message.Status.Sent, expirationData = null @@ -168,7 +169,7 @@ object TestMessage { id = "messageID", content = MessageContent.ConversationCreated, conversationId = ConversationId("convo-id", "convo.domain"), - date = "some-date", + date = Instant.parse("2022-03-30T15:36:00.000Z"), senderUserId = UserId("user-id", "domain"), status = Message.Status.Sent, expirationData = null diff --git a/app/src/test/kotlin/com/wire/android/mapper/MessageMapperTest.kt b/app/src/test/kotlin/com/wire/android/mapper/MessageMapperTest.kt index 89e9df57f9d..a77fc14ab8d 100644 --- a/app/src/test/kotlin/com/wire/android/mapper/MessageMapperTest.kt +++ b/app/src/test/kotlin/com/wire/android/mapper/MessageMapperTest.kt @@ -37,21 +37,23 @@ import com.wire.android.util.uiMessageDateTime import com.wire.kalium.logic.data.message.Message import com.wire.kalium.logic.data.message.MessageContent import com.wire.kalium.logic.data.user.UserId +import com.wire.kalium.util.DateTimeUtil.toIsoDateTimeString import io.mockk.MockKAnnotations import io.mockk.coEvery import io.mockk.every import io.mockk.impl.annotations.MockK import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runTest +import kotlinx.datetime.Instant import org.amshove.kluent.internal.assertEquals import org.amshove.kluent.shouldBeEqualTo import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith import java.text.SimpleDateFormat -import java.util.Calendar import java.util.Date import java.util.Locale import java.util.TimeZone +import kotlin.time.Duration.Companion.days @OptIn(ExperimentalCoroutinesApi::class) @ExtendWith(CoroutineTestExtension::class) @@ -82,10 +84,8 @@ class MessageMapperTest { val serverDateFormatter = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.getDefault()) .apply { timeZone = TimeZone.getTimeZone("UTC") } - val now = serverDateFormatter.format(Date()) - val calendar = Calendar.getInstance() - calendar.add(Calendar.DATE, -1) - val yesterday = serverDateFormatter.format(calendar.time) + val now = Instant.parse(serverDateFormatter.format(Date())) + val yesterday = now - 1.days val (arrangement, mapper) = Arrangement().arrange() @@ -114,14 +114,14 @@ class MessageMapperTest { true, checkMessageData( uiMessage = uiMessage1, - time = message1.date.uiMessageDateTime() + time = message1.date ) ) assertEquals( true, checkMessageData( uiMessage = uiMessage2, - time = message2.date.uiMessageDateTime(), + time = message2.date, source = MessageSource.OtherUser, membership = Membership.Guest, status = MessageStatus( @@ -134,10 +134,10 @@ class MessageMapperTest { true, checkMessageData( uiMessage = uiMessage3, - time = message3.date.uiMessageDateTime(), + time = message3.date, status = MessageStatus( flowStatus = MessageFlowStatus.Sent, - editStatus = MessageEditStatus.Edited(now.uiMessageDateTime() ?: ""), + editStatus = MessageEditStatus.Edited(now.toIsoDateTimeString().uiMessageDateTime()!!), expirationStatus = ExpirationStatus.NotExpirable ) ) @@ -146,7 +146,7 @@ class MessageMapperTest { true, checkMessageData( uiMessage = uiMessage4, - time = message4.date.uiMessageDateTime(), + time = message4.date, status = MessageStatus( flowStatus = MessageFlowStatus.Sent, isDeleted = true, @@ -159,7 +159,7 @@ class MessageMapperTest { true, checkMessageData( uiMessage = uiMessage5, - time = message5.date.uiMessageDateTime(), + time = message5.date, status = MessageStatus( flowStatus = MessageFlowStatus.Failure.Decryption(false), isDeleted = false, @@ -172,7 +172,7 @@ class MessageMapperTest { true, checkMessageData( uiMessage = uiMessage6, - time = message6.date.uiMessageDateTime(), + time = message6.date, status = MessageStatus( flowStatus = MessageFlowStatus.Failure.Decryption(true), isDeleted = false, @@ -208,7 +208,7 @@ class MessageMapperTest { private fun checkMessageData( uiMessage: UIMessage?, - time: String?, + time: Instant?, source: MessageSource = MessageSource.Self, membership: Membership = Membership.None, status: MessageStatus = MessageStatus( @@ -217,7 +217,7 @@ class MessageMapperTest { ) ): Boolean { return (uiMessage?.source == source && uiMessage.header.membership == membership - && uiMessage.header.messageTime.formattedDate == time + && uiMessage.header.messageTime.formattedDate == time?.toIsoDateTimeString()?.uiMessageDateTime() && uiMessage.header.messageStatus.flowStatus == status.flowStatus && uiMessage.header.messageStatus.isDeleted == status.isDeleted && uiMessage.header.messageStatus.editStatus == status.editStatus @@ -248,7 +248,9 @@ class MessageMapperTest { coEvery { messageContentMapper.fromMessage(any(), any()) } returns TextMessage( MessageBody(UIText.DynamicString("some message text")) ) - every { isoFormatter.fromISO8601ToTimeFormat(any()) } answers { firstArg().uiMessageDateTime() ?: "" } + every { isoFormatter.fromInstantToTimeFormatter(any()) } answers { + firstArg().toIsoDateTimeString().uiMessageDateTime() ?: "" + } } fun arrange() = this to messageMapper @@ -258,7 +260,7 @@ class MessageMapperTest { status: Message.Status = Message.Status.Sent, visibility: Message.Visibility = Message.Visibility.VISIBLE, editStatus: Message.EditStatus = Message.EditStatus.NotEdited, - date: String = "2016-09-18T17:34:02.666Z" + date: Instant = Instant.parse("2016-09-18T17:34:02.666Z") ): Message.Regular = TestMessage.TEXT_MESSAGE.copy( senderUserId = senderUserId, status = status, diff --git a/app/src/test/kotlin/com/wire/android/mapper/SystemMessageContentMapperTest.kt b/app/src/test/kotlin/com/wire/android/mapper/SystemMessageContentMapperTest.kt index 1fe5287e50b..cc2a903540c 100644 --- a/app/src/test/kotlin/com/wire/android/mapper/SystemMessageContentMapperTest.kt +++ b/app/src/test/kotlin/com/wire/android/mapper/SystemMessageContentMapperTest.kt @@ -19,18 +19,21 @@ package com.wire.android.mapper import android.content.res.Resources +import com.wire.android.assertIs import com.wire.android.config.CoroutineTestExtension import com.wire.android.framework.TestMessage import com.wire.android.framework.TestMessage.CONVERSATION_CREATED_MESSAGE import com.wire.android.framework.TestUser import com.wire.android.ui.home.conversations.model.UIMessageContent.SystemMessage import com.wire.android.ui.home.conversations.name +import com.wire.android.util.formatFullDateShortTime import com.wire.android.util.ui.UIText import com.wire.kalium.logic.data.conversation.Conversation.Member import com.wire.kalium.logic.data.conversation.MemberDetails import com.wire.kalium.logic.data.message.MessageContent import com.wire.kalium.logic.data.user.OtherUser import com.wire.kalium.logic.data.user.UserId +import com.wire.kalium.util.DateTimeUtil.toIsoDateTimeString import io.mockk.MockKAnnotations import io.mockk.every import io.mockk.impl.annotations.MockK @@ -41,6 +44,7 @@ import org.junit.jupiter.api.Assertions.assertInstanceOf import org.junit.jupiter.api.Assertions.assertTrue import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith +import java.util.Locale @OptIn(ExperimentalCoroutinesApi::class) @ExtendWith(CoroutineTestExtension::class) @@ -125,11 +129,16 @@ class SystemMessageContentMapperTest { (resultMyMissedCall.author as UIText.StringResource).resId == arrangement.messageResourceProvider.memberNameYouTitlecase ) - assertTrue( - resultConversationCreated is SystemMessage.ConversationMessageCreated && - (resultConversationCreated.author as UIText.StringResource).resId == 10584735 && - resultConversationCreated.date == "SOME-DATE" - ) + val expectedFormattedDate = CONVERSATION_CREATED_MESSAGE.date + .toIsoDateTimeString() + .formatFullDateShortTime()!! + .uppercase( + Locale.getDefault() + ) + + assertIs(resultConversationCreated) + assertEquals(10584735, (resultConversationCreated.author as UIText.StringResource).resId) + assertEquals(expectedFormattedDate, resultConversationCreated.date) } @Suppress("LongMethod", "ComplexMethod") diff --git a/app/src/test/kotlin/com/wire/android/ui/home/conversations/AuthorHeaderHelperTest.kt b/app/src/test/kotlin/com/wire/android/ui/home/conversations/AuthorHeaderHelperTest.kt index 82adad93c3d..206282464df 100644 --- a/app/src/test/kotlin/com/wire/android/ui/home/conversations/AuthorHeaderHelperTest.kt +++ b/app/src/test/kotlin/com/wire/android/ui/home/conversations/AuthorHeaderHelperTest.kt @@ -29,14 +29,16 @@ import com.wire.android.util.ui.UIText import com.wire.kalium.logic.data.id.ConversationId import com.wire.kalium.logic.data.user.UserAvailabilityStatus import com.wire.kalium.logic.data.user.UserId -import com.wire.kalium.util.DateTimeUtil +import kotlinx.datetime.Instant import org.amshove.kluent.internal.assertEquals import org.junit.jupiter.api.Test import java.util.UUID +import kotlin.time.Duration.Companion.milliseconds class AuthorHeaderHelperTest { private data class Messages(val currentMessage: UIMessage, val messageAbove: UIMessage?, val messageBelow: UIMessage?) + private fun List.forIndex(index: Int, action: (Messages) -> Boolean): Boolean = action(Messages(this[index], this.getOrNull(index + 1), this.getOrNull(index - 1))) @@ -75,8 +77,8 @@ class AuthorHeaderHelperTest { fun givenTwoRegularMessagesFromSameUser_thenShouldNotShowHeaderForRecentMessage() { // given val messages = listOf( // more recent message is first on list - testRegularMessage(userId = SELF_USER_ID, timestamp = "2021-01-01T00:00:01.000Z"), - testRegularMessage(userId = SELF_USER_ID, timestamp = "2021-01-01T00:00:00.000Z") + testRegularMessage(userId = SELF_USER_ID, instant = Instant.parse("2021-01-01T00:00:01.000Z")), + testRegularMessage(userId = SELF_USER_ID, instant = Instant.parse("2021-01-01T00:00:00.000Z")) ) // when val result = messages.forIndex(0) { shouldShowHeader(it.currentMessage, it.messageAbove) } @@ -88,8 +90,8 @@ class AuthorHeaderHelperTest { fun givenTwoRegularMessagesFromDifferentUser_thenShouldShowHeaderForRecentMessage() { // given val messages = listOf( // more recent message is first on list - testRegularMessage(userId = SELF_USER_ID, timestamp = "2021-01-01T00:00:01.000Z"), - testRegularMessage(userId = OTHER_USER_ID, timestamp = "2021-01-01T00:00:00.000Z") + testRegularMessage(userId = SELF_USER_ID, instant = Instant.parse("2021-01-01T00:00:01.000Z")), + testRegularMessage(userId = OTHER_USER_ID, instant = Instant.parse("2021-01-01T00:00:00.000Z")) ) // when val result = messages.forIndex(0) { shouldShowHeader(it.currentMessage, it.messageAbove) } @@ -101,8 +103,8 @@ class AuthorHeaderHelperTest { fun givenSystemAndThenRegularMessageFromSameUser_thenShouldShowHeaderForRecentMessage() { // given val messages = listOf( // more recent message is first on list - testRegularMessage(userId = SELF_USER_ID, timestamp = "2021-01-01T00:00:01.000Z"), - testSystemMessage(userId = SELF_USER_ID, timestamp = "2021-01-01T00:00:00.000Z") + testRegularMessage(userId = SELF_USER_ID, instant = Instant.parse("2021-01-01T00:00:01.000Z")), + testSystemMessage(userId = SELF_USER_ID, timestamp = Instant.parse("2021-01-01T00:00:00.000Z")) ) // when val result = messages.forIndex(0) { shouldShowHeader(it.currentMessage, it.messageAbove) } @@ -114,8 +116,8 @@ class AuthorHeaderHelperTest { fun givenRegularAndThenSystemMessagFromSameUsere_thenShouldNotShowHeaderForRecentMessage() { // given val messages = listOf( // more recent message is first on list - testSystemMessage(userId = SELF_USER_ID, timestamp = "2021-01-01T00:00:01.000Z"), - testRegularMessage(userId = SELF_USER_ID, timestamp = "2021-01-01T00:00:00.000Z") + testSystemMessage(userId = SELF_USER_ID, timestamp = Instant.parse("2021-01-01T00:00:01.000Z")), + testRegularMessage(userId = SELF_USER_ID, instant = Instant.parse("2021-01-01T00:00:00.000Z")) ) // when val result = messages.forIndex(0) { shouldShowHeader(it.currentMessage, it.messageAbove) } @@ -127,8 +129,8 @@ class AuthorHeaderHelperTest { fun givenPingAndThenRegularMessageFromSameUser_thenShouldShowHeaderForRecentMessage() { // given val messages = listOf( // more recent message is first on list - testRegularMessage(userId = SELF_USER_ID, timestamp = "2021-01-01T00:00:01.000Z"), - testPingMessage(userId = SELF_USER_ID, timestamp = "2021-01-01T00:00:00.000Z") + testRegularMessage(userId = SELF_USER_ID, instant = Instant.parse("2021-01-01T00:00:01.000Z")), + testPingMessage(userId = SELF_USER_ID, instant = Instant.parse("2021-01-01T00:00:00.000Z")) ) // when val result = messages.forIndex(0) { shouldShowHeader(it.currentMessage, it.messageAbove) } @@ -140,8 +142,8 @@ class AuthorHeaderHelperTest { fun givenRegularAndThenPingMessageFromSameUser_thenShouldNotShowHeaderForRecentMessage() { // given val messages = listOf( // more recent message is first on list - testPingMessage(userId = SELF_USER_ID, timestamp = "2021-01-01T00:00:01.000Z"), - testRegularMessage(userId = SELF_USER_ID, timestamp = "2021-01-01T00:00:00.000Z") + testPingMessage(userId = SELF_USER_ID, instant = Instant.parse("2021-01-01T00:00:01.000Z")), + testRegularMessage(userId = SELF_USER_ID, instant = Instant.parse("2021-01-01T00:00:00.000Z")) ) // when val result = messages.forIndex(0) { shouldShowHeader(it.currentMessage, it.messageAbove) } @@ -152,11 +154,11 @@ class AuthorHeaderHelperTest { @Test fun givenTwoRegularMessagesFromSameUserAndTimestampsWithinThreshold_thenShouldNotShowHeaderForRecentMessage() { // given - val timestamp = "2021-01-01T00:00:00.000Z" - val timestampMinusLessThanThreshold = DateTimeUtil.minusMilliseconds(timestamp, AuthorHeaderHelper.AGGREGATION_TIME_WINDOW - 1L) + val timestamp = Instant.parse("2021-01-01T00:00:00.000Z") + val timestampMinusLessThanThreshold = timestamp - (AuthorHeaderHelper.AGGREGATION_TIME_WINDOW - 1).milliseconds val messages = listOf( - testRegularMessage(userId = SELF_USER_ID, timestamp = timestamp), - testRegularMessage(userId = SELF_USER_ID, timestamp = timestampMinusLessThanThreshold) + testRegularMessage(userId = SELF_USER_ID, instant = timestamp), + testRegularMessage(userId = SELF_USER_ID, instant = timestampMinusLessThanThreshold) ) // when val result = messages.forIndex(0) { shouldShowHeader(it.currentMessage, it.messageAbove) } @@ -167,11 +169,11 @@ class AuthorHeaderHelperTest { @Test fun givenTwoRegularMessagesFromSameUserAndTimestampsBeyondThreshold_thenShouldShowHeaderForRecentMessage() { // given - val timestamp = "2021-01-01T00:00:00.000Z" - val timestampMinusMoreThanThreshold = DateTimeUtil.minusMilliseconds(timestamp, AuthorHeaderHelper.AGGREGATION_TIME_WINDOW + 1L) + val timestamp = Instant.parse("2021-01-01T00:00:00.000Z") + val timestampMinusMoreThanThreshold = timestamp - (AuthorHeaderHelper.AGGREGATION_TIME_WINDOW + 1).milliseconds val messages = listOf( - testRegularMessage(userId = SELF_USER_ID, timestamp = timestamp), - testRegularMessage(userId = SELF_USER_ID, timestamp = timestampMinusMoreThanThreshold) + testRegularMessage(userId = SELF_USER_ID, instant = timestamp), + testRegularMessage(userId = SELF_USER_ID, instant = timestampMinusMoreThanThreshold) ) // when val result = messages.forIndex(0) { shouldShowHeader(it.currentMessage, it.messageAbove) } @@ -214,8 +216,8 @@ class AuthorHeaderHelperTest { fun givenTwoRegularMessagesFromSameUser_thenPreviousShouldHaveSmallBottomPaddingAndRecentShouldNot() { // given val messages = listOf( // more recent message is first on list - testRegularMessage(userId = SELF_USER_ID, timestamp = "2021-01-01T00:00:01.000Z"), - testRegularMessage(userId = SELF_USER_ID, timestamp = "2021-01-01T00:00:00.000Z") + testRegularMessage(userId = SELF_USER_ID, instant = Instant.parse("2021-01-01T00:00:01.000Z")), + testRegularMessage(userId = SELF_USER_ID, instant = Instant.parse("2021-01-01T00:00:00.000Z")) ) // when val resultPrevious = messages.forIndex(1) { shouldHaveSmallBottomPadding(it.currentMessage, it.messageBelow) } @@ -229,8 +231,8 @@ class AuthorHeaderHelperTest { fun givenTwoRegularMessagesFromDifferentUser_thenBothShouldNotHaveSmallBottomPadding() { // given val messages = listOf( // more recent message is first on list - testRegularMessage(userId = SELF_USER_ID, timestamp = "2021-01-01T00:00:01.000Z"), - testRegularMessage(userId = OTHER_USER_ID, timestamp = "2021-01-01T00:00:00.000Z") + testRegularMessage(userId = SELF_USER_ID, instant = Instant.parse("2021-01-01T00:00:01.000Z")), + testRegularMessage(userId = OTHER_USER_ID, instant = Instant.parse("2021-01-01T00:00:00.000Z")) ) // when val resultPrevious = messages.forIndex(1) { shouldHaveSmallBottomPadding(it.currentMessage, it.messageBelow) } @@ -244,8 +246,8 @@ class AuthorHeaderHelperTest { fun givenSystemAndThenRegularMessageFromSameUser_thenBothShouldNotHaveSmallBottomPadding() { // given val messages = listOf( // more recent message is first on list - testRegularMessage(userId = SELF_USER_ID, timestamp = "2021-01-01T00:00:01.000Z"), - testSystemMessage(userId = SELF_USER_ID, timestamp = "2021-01-01T00:00:00.000Z") + testRegularMessage(userId = SELF_USER_ID, instant = Instant.parse("2021-01-01T00:00:01.000Z")), + testSystemMessage(userId = SELF_USER_ID, timestamp = Instant.parse("2021-01-01T00:00:00.000Z")) ) // when val resultPrevious = messages.forIndex(1) { shouldHaveSmallBottomPadding(it.currentMessage, it.messageBelow) } @@ -259,8 +261,8 @@ class AuthorHeaderHelperTest { fun givenRegularAndThenSystemMessagFromSameUsere_thenBothShouldNotHaveSmallBottomPadding() { // given val messages = listOf( // more recent message is first on list - testSystemMessage(userId = SELF_USER_ID, timestamp = "2021-01-01T00:00:01.000Z"), - testRegularMessage(userId = SELF_USER_ID, timestamp = "2021-01-01T00:00:00.000Z") + testSystemMessage(userId = SELF_USER_ID, timestamp = Instant.parse("2021-01-01T00:00:01.000Z")), + testRegularMessage(userId = SELF_USER_ID, instant = Instant.parse("2021-01-01T00:00:00.000Z")) ) // when val resultPrevious = messages.forIndex(1) { shouldHaveSmallBottomPadding(it.currentMessage, it.messageBelow) } @@ -274,8 +276,8 @@ class AuthorHeaderHelperTest { fun givenPingAndThenRegularMessageFromSameUser_thenBothShouldNotHaveSmallBottomPadding() { // given val messages = listOf( // more recent message is first on list - testRegularMessage(userId = SELF_USER_ID, timestamp = "2021-01-01T00:00:01.000Z"), - testPingMessage(userId = SELF_USER_ID, timestamp = "2021-01-01T00:00:00.000Z") + testRegularMessage(userId = SELF_USER_ID, instant = Instant.parse("2021-01-01T00:00:01.000Z")), + testPingMessage(userId = SELF_USER_ID, instant = Instant.parse("2021-01-01T00:00:00.000Z")) ) // when val resultPrevious = messages.forIndex(1) { shouldHaveSmallBottomPadding(it.currentMessage, it.messageBelow) } @@ -289,8 +291,8 @@ class AuthorHeaderHelperTest { fun givenRegularAndThenPingMessageFromSameUser_thenBothShouldNotHaveSmallBottomPadding() { // given val messages = listOf( // more recent message is first on list - testPingMessage(userId = SELF_USER_ID, timestamp = "2021-01-01T00:00:01.000Z"), - testRegularMessage(userId = SELF_USER_ID, timestamp = "2021-01-01T00:00:00.000Z") + testPingMessage(userId = SELF_USER_ID, instant = Instant.parse("2021-01-01T00:00:01.000Z")), + testRegularMessage(userId = SELF_USER_ID, instant = Instant.parse("2021-01-01T00:00:00.000Z")) ) // when val resultPrevious = messages.forIndex(1) { shouldHaveSmallBottomPadding(it.currentMessage, it.messageBelow) } @@ -303,11 +305,11 @@ class AuthorHeaderHelperTest { @Test fun givenTwoRegularMessagesFromSameUserAndTimestampsWithinThreshold_thenPreviousShouldHaveSmallBottomPaddingAndRecentShouldNot() { // given - val timestamp = "2021-01-01T00:00:00.000Z" - val timestampMinusLessThanThreshold = DateTimeUtil.minusMilliseconds(timestamp, AuthorHeaderHelper.AGGREGATION_TIME_WINDOW - 1L) + val timestamp = Instant.parse("2021-01-01T00:00:00.000Z") + val timestampMinusLessThanThreshold = timestamp - (AuthorHeaderHelper.AGGREGATION_TIME_WINDOW - 1L).milliseconds val messages = listOf( - testRegularMessage(userId = SELF_USER_ID, timestamp = timestamp), - testRegularMessage(userId = SELF_USER_ID, timestamp = timestampMinusLessThanThreshold) + testRegularMessage(userId = SELF_USER_ID, instant = timestamp), + testRegularMessage(userId = SELF_USER_ID, instant = timestampMinusLessThanThreshold) ) // when val resultPrevious = messages.forIndex(1) { shouldHaveSmallBottomPadding(it.currentMessage, it.messageBelow) } @@ -320,11 +322,11 @@ class AuthorHeaderHelperTest { @Test fun givenTwoRegularMessagesFromSameUserAndTimestampsBeyondThreshold_thenBothShouldNotHaveSmallBottomPadding() { // given - val timestamp = "2021-01-01T00:00:00.000Z" - val timestampMinusMoreThanThreshold = DateTimeUtil.minusMilliseconds(timestamp, AuthorHeaderHelper.AGGREGATION_TIME_WINDOW + 1L) + val timestamp = Instant.parse("2021-01-01T00:00:00.000Z") + val timestampMinusMoreThanThreshold = timestamp - (AuthorHeaderHelper.AGGREGATION_TIME_WINDOW + 1L).milliseconds val messages = listOf( - testRegularMessage(userId = SELF_USER_ID, timestamp = timestamp), - testRegularMessage(userId = SELF_USER_ID, timestamp = timestampMinusMoreThanThreshold) + testRegularMessage(userId = SELF_USER_ID, instant = timestamp), + testRegularMessage(userId = SELF_USER_ID, instant = timestampMinusMoreThanThreshold) ) // when val resultPrevious = messages.forIndex(1) { shouldHaveSmallBottomPadding(it.currentMessage, it.messageBelow) } @@ -341,12 +343,12 @@ class AuthorHeaderHelperTest { private fun testSystemMessage( userId: UserId? = null, - timestamp: String = "2021-01-01T00:00:00.000Z" + timestamp: Instant = Instant.parse("2021-01-01T00:00:00.000Z") ) = UIMessage.System( conversationId = CONVERSATION_ID, header = TestMessage.UI_MESSAGE_HEADER.copy( messageTime = TestMessage.UI_MESSAGE_HEADER.messageTime.copy( - utcISO = timestamp + instant = timestamp ), messageId = UUID.randomUUID().toString(), userId = userId @@ -357,12 +359,12 @@ class AuthorHeaderHelperTest { private fun testPingMessage( userId: UserId? = null, - timestamp: String = "2021-01-01T00:00:00.000Z" + instant: Instant = Instant.parse("2021-01-01T00:00:00.000Z") ) = UIMessage.System( conversationId = CONVERSATION_ID, header = TestMessage.UI_MESSAGE_HEADER.copy( messageTime = TestMessage.UI_MESSAGE_HEADER.messageTime.copy( - utcISO = timestamp + instant = instant ), messageId = UUID.randomUUID().toString(), userId = userId @@ -373,14 +375,14 @@ class AuthorHeaderHelperTest { private fun testRegularMessage( userId: UserId? = null, - timestamp: String = "2021-01-01T00:00:00.000Z" + instant: Instant = Instant.parse("2021-01-01T00:00:00.000Z") ) = UIMessage.Regular( conversationId = CONVERSATION_ID, userAvatarData = UserAvatarData(asset = null, availabilityStatus = UserAvailabilityStatus.NONE), source = if (userId == SELF_USER_ID) MessageSource.Self else MessageSource.OtherUser, header = TestMessage.UI_MESSAGE_HEADER.copy( messageTime = TestMessage.UI_MESSAGE_HEADER.messageTime.copy( - utcISO = timestamp + instant = instant ), messageId = UUID.randomUUID().toString(), userId = userId diff --git a/app/src/test/kotlin/com/wire/android/ui/home/conversations/composer/MessageComposerViewModelArrangement.kt b/app/src/test/kotlin/com/wire/android/ui/home/conversations/composer/MessageComposerViewModelArrangement.kt index 8dffe00c1d8..bd95815fbe3 100644 --- a/app/src/test/kotlin/com/wire/android/ui/home/conversations/composer/MessageComposerViewModelArrangement.kt +++ b/app/src/test/kotlin/com/wire/android/ui/home/conversations/composer/MessageComposerViewModelArrangement.kt @@ -75,6 +75,7 @@ import io.mockk.mockk import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.flow.flowOf +import kotlinx.datetime.Instant import okio.Path import okio.buffer @@ -251,7 +252,7 @@ internal fun mockUITextMessage(id: String = "someId", userName: String = "mockUs every { it.messageId } returns id every { it.username } returns UIText.DynamicString(userName) every { it.isLegalHold } returns false - every { it.messageTime } returns MessageTime("") + every { it.messageTime } returns MessageTime(Instant.DISTANT_PAST) every { it.messageStatus } returns MessageStatus( flowStatus = MessageFlowStatus.Sent, expirationStatus = ExpirationStatus.NotExpirable diff --git a/app/src/test/kotlin/com/wire/android/ui/home/conversations/details/GroupConversationDetailsViewModelTest.kt b/app/src/test/kotlin/com/wire/android/ui/home/conversations/details/GroupConversationDetailsViewModelTest.kt index b3db008321e..f738ac8a75f 100644 --- a/app/src/test/kotlin/com/wire/android/ui/home/conversations/details/GroupConversationDetailsViewModelTest.kt +++ b/app/src/test/kotlin/com/wire/android/ui/home/conversations/details/GroupConversationDetailsViewModelTest.kt @@ -68,6 +68,7 @@ import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map import kotlinx.coroutines.test.runTest +import kotlinx.datetime.Instant import org.amshove.kluent.internal.assertEquals import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @@ -617,7 +618,7 @@ class GroupConversationDetailsViewModelTest { lastModifiedDate = null, access = listOf(Conversation.Access.CODE, Conversation.Access.INVITE), accessRole = Conversation.defaultGroupAccessRoles.toMutableList().apply { add(Conversation.AccessRole.GUEST) }, - lastReadDate = "2022-04-04T16:11:28.388Z", + lastReadDate = Instant.parse("2022-04-04T16:11:28.388Z"), creatorId = null, receiptMode = Conversation.ReceiptMode.ENABLED, messageTimer = null, diff --git a/app/src/test/kotlin/com/wire/android/ui/home/gallery/MediaGalleryViewModelTest.kt b/app/src/test/kotlin/com/wire/android/ui/home/gallery/MediaGalleryViewModelTest.kt index d3c3ca6223a..8e41a6d8287 100644 --- a/app/src/test/kotlin/com/wire/android/ui/home/gallery/MediaGalleryViewModelTest.kt +++ b/app/src/test/kotlin/com/wire/android/ui/home/gallery/MediaGalleryViewModelTest.kt @@ -55,6 +55,7 @@ import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.test.runTest +import kotlinx.datetime.Instant import okio.Path import okio.Path.Companion.toPath import okio.buffer @@ -294,7 +295,7 @@ class MediaGalleryViewModelTest { removedBy = null, lastNotificationDate = null, lastModifiedDate = null, - lastReadDate = "2022-04-04T16:11:28.388Z", + lastReadDate = Instant.parse("2022-04-04T16:11:28.388Z"), access = listOf(Conversation.Access.INVITE), accessRole = listOf(Conversation.AccessRole.NON_TEAM_MEMBER), creatorId = null, diff --git a/app/src/test/kotlin/com/wire/android/ui/home/newconversation/NewConversationViewModelArrangement.kt b/app/src/test/kotlin/com/wire/android/ui/home/newconversation/NewConversationViewModelArrangement.kt index fc65ca1e428..c0582d22241 100644 --- a/app/src/test/kotlin/com/wire/android/ui/home/newconversation/NewConversationViewModelArrangement.kt +++ b/app/src/test/kotlin/com/wire/android/ui/home/newconversation/NewConversationViewModelArrangement.kt @@ -43,6 +43,7 @@ import io.mockk.coEvery import io.mockk.every import io.mockk.impl.annotations.MockK import kotlinx.coroutines.flow.flowOf +import kotlinx.datetime.Instant internal class NewConversationViewModelArrangement { init { @@ -86,7 +87,7 @@ internal class NewConversationViewModelArrangement { removedBy = null, lastNotificationDate = null, lastModifiedDate = null, - lastReadDate = "2022-04-04T16:11:28.388Z", + lastReadDate = Instant.parse("2022-04-04T16:11:28.388Z"), access = listOf(Conversation.Access.INVITE), accessRole = listOf(Conversation.AccessRole.NON_TEAM_MEMBER), creatorId = null, diff --git a/app/src/test/kotlin/com/wire/android/ui/userprofile/other/OtherUserProfileScreenViewModelTest.kt b/app/src/test/kotlin/com/wire/android/ui/userprofile/other/OtherUserProfileScreenViewModelTest.kt index c9ae6d8e030..eab68d1dfe0 100644 --- a/app/src/test/kotlin/com/wire/android/ui/userprofile/other/OtherUserProfileScreenViewModelTest.kt +++ b/app/src/test/kotlin/com/wire/android/ui/userprofile/other/OtherUserProfileScreenViewModelTest.kt @@ -45,6 +45,7 @@ import io.mockk.Called import io.mockk.coVerify import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runTest +import kotlinx.datetime.Instant import org.amshove.kluent.internal.assertEquals import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @@ -272,7 +273,7 @@ class OtherUserProfileScreenViewModelTest { removedBy = null, lastNotificationDate = null, lastModifiedDate = null, - lastReadDate = "2022-04-04T16:11:28.388Z", + lastReadDate = Instant.parse("2022-04-04T16:11:28.388Z"), access = listOf(Conversation.Access.INVITE), accessRole = listOf(Conversation.AccessRole.NON_TEAM_MEMBER), creatorId = null, diff --git a/kalium b/kalium index f34993ab6b3..2453ab88f74 160000 --- a/kalium +++ b/kalium @@ -1 +1 @@ -Subproject commit f34993ab6b3ce61be7262a03bc512c6826a9df32 +Subproject commit 2453ab88f7492f323a2e8a2d0ad699c5cbd33776