Refresh room summaries when date or time changes in the device (#3683)
* Add `DateTimeObserver` to rebuild the room summary data when the date/time changes. * Add time changed action too, to trigger when the user manually changes date/time * Fix timezone issue by adding `TimezoneProvider`, fix tests * Create test for `DateTimeObserver` usage in `RoomListDataSource` * Create aRoomListRoomSummaryFactory function. * Improve test by faking the lastMessageTimestampFormatter --------- Co-authored-by: Benoit Marty <benoit@matrix.org>
This commit is contained in:
committed by
GitHub
parent
b15ebfda87
commit
6b2aa7eb8c
@@ -51,7 +51,6 @@ import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.encryption.EncryptionService
|
||||
import io.element.android.libraries.matrix.api.encryption.RecoveryState
|
||||
import io.element.android.libraries.matrix.api.roomlist.RoomList
|
||||
import io.element.android.libraries.matrix.api.sync.SyncService
|
||||
import io.element.android.libraries.matrix.api.timeline.ReceiptType
|
||||
import io.element.android.libraries.preferences.api.store.SessionPreferencesStore
|
||||
import io.element.android.libraries.push.api.notifications.NotificationCleaner
|
||||
@@ -93,7 +92,6 @@ class RoomListPresenter @Inject constructor(
|
||||
private val logoutPresenter: Presenter<DirectLogoutState>,
|
||||
) : Presenter<RoomListState> {
|
||||
private val encryptionService: EncryptionService = client.encryptionService()
|
||||
private val syncService: SyncService = client.syncService()
|
||||
|
||||
@Composable
|
||||
override fun present(): RoomListState {
|
||||
|
||||
@@ -10,6 +10,7 @@ package io.element.android.features.roomlist.impl.datasource
|
||||
import io.element.android.features.roomlist.impl.model.RoomListRoomSummary
|
||||
import io.element.android.libraries.androidutils.diff.DiffCacheUpdater
|
||||
import io.element.android.libraries.androidutils.diff.MutableListDiffCache
|
||||
import io.element.android.libraries.androidutils.system.DateTimeObserver
|
||||
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService
|
||||
@@ -36,9 +37,11 @@ class RoomListDataSource @Inject constructor(
|
||||
private val coroutineDispatchers: CoroutineDispatchers,
|
||||
private val notificationSettingsService: NotificationSettingsService,
|
||||
private val appScope: CoroutineScope,
|
||||
private val dateTimeObserver: DateTimeObserver,
|
||||
) {
|
||||
init {
|
||||
observeNotificationSettings()
|
||||
observeDateTimeChanges()
|
||||
}
|
||||
|
||||
private val _allRooms = MutableSharedFlow<ImmutableList<RoomListRoomSummary>>(replay = 1)
|
||||
@@ -77,6 +80,17 @@ class RoomListDataSource @Inject constructor(
|
||||
.launchIn(appScope)
|
||||
}
|
||||
|
||||
private fun observeDateTimeChanges() {
|
||||
dateTimeObserver.changes
|
||||
.onEach { event ->
|
||||
when (event) {
|
||||
is DateTimeObserver.Event.TimeZoneChanged -> rebuildAllRoomSummaries()
|
||||
is DateTimeObserver.Event.DateChanged -> rebuildAllRoomSummaries()
|
||||
}
|
||||
}
|
||||
.launchIn(appScope)
|
||||
}
|
||||
|
||||
private suspend fun replaceWith(roomSummaries: List<RoomSummary>) = withContext(coroutineDispatchers.computation) {
|
||||
lock.withLock {
|
||||
diffCacheUpdater.updateWith(roomSummaries)
|
||||
@@ -84,9 +98,13 @@ class RoomListDataSource @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun buildAndEmitAllRooms(roomSummaries: List<RoomSummary>) {
|
||||
private suspend fun buildAndEmitAllRooms(roomSummaries: List<RoomSummary>, useCache: Boolean = true) {
|
||||
val roomListRoomSummaries = diffCache.indices().mapNotNull { index ->
|
||||
diffCache.get(index) ?: buildAndCacheItem(roomSummaries, index)
|
||||
if (useCache) {
|
||||
diffCache.get(index) ?: buildAndCacheItem(roomSummaries, index)
|
||||
} else {
|
||||
buildAndCacheItem(roomSummaries, index)
|
||||
}
|
||||
}
|
||||
_allRooms.emit(roomListRoomSummaries.toImmutableList())
|
||||
}
|
||||
@@ -96,4 +114,12 @@ class RoomListDataSource @Inject constructor(
|
||||
diffCache[index] = roomListSummary
|
||||
return roomListSummary
|
||||
}
|
||||
|
||||
private suspend fun rebuildAllRoomSummaries() {
|
||||
lock.withLock {
|
||||
roomListService.allRooms.summaries.replayCache.firstOrNull()?.let { roomSummaries ->
|
||||
buildAndEmitAllRooms(roomSummaries, useCache = false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,13 +22,14 @@ import io.element.android.features.logout.api.direct.aDirectLogoutState
|
||||
import io.element.android.features.networkmonitor.api.NetworkMonitor
|
||||
import io.element.android.features.networkmonitor.test.FakeNetworkMonitor
|
||||
import io.element.android.features.roomlist.impl.datasource.RoomListDataSource
|
||||
import io.element.android.features.roomlist.impl.datasource.RoomListRoomSummaryFactory
|
||||
import io.element.android.features.roomlist.impl.datasource.aRoomListRoomSummaryFactory
|
||||
import io.element.android.features.roomlist.impl.filters.RoomListFiltersState
|
||||
import io.element.android.features.roomlist.impl.filters.aRoomListFiltersState
|
||||
import io.element.android.features.roomlist.impl.model.createRoomListRoomSummary
|
||||
import io.element.android.features.roomlist.impl.search.RoomListSearchEvents
|
||||
import io.element.android.features.roomlist.impl.search.RoomListSearchState
|
||||
import io.element.android.features.roomlist.impl.search.aRoomListSearchState
|
||||
import io.element.android.libraries.androidutils.system.DateTimeObserver
|
||||
import io.element.android.libraries.architecture.Presenter
|
||||
import io.element.android.libraries.dateformatter.api.LastMessageTimestampFormatter
|
||||
import io.element.android.libraries.dateformatter.test.A_FORMATTED_DATE
|
||||
@@ -83,6 +84,7 @@ import io.element.android.tests.testutils.lambda.value
|
||||
import io.element.android.tests.testutils.test
|
||||
import io.element.android.tests.testutils.testCoroutineDispatchers
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.advanceTimeBy
|
||||
@@ -649,13 +651,14 @@ class RoomListPresenterTest {
|
||||
leaveRoomPresenter = { leaveRoomState },
|
||||
roomListDataSource = RoomListDataSource(
|
||||
roomListService = client.roomListService,
|
||||
roomListRoomSummaryFactory = RoomListRoomSummaryFactory(
|
||||
roomListRoomSummaryFactory = aRoomListRoomSummaryFactory(
|
||||
lastMessageTimestampFormatter = lastMessageTimestampFormatter,
|
||||
roomLastMessageFormatter = roomLastMessageFormatter,
|
||||
),
|
||||
coroutineDispatchers = testCoroutineDispatchers(),
|
||||
notificationSettingsService = client.notificationSettingsService(),
|
||||
appScope = backgroundScope
|
||||
appScope = backgroundScope,
|
||||
dateTimeObserver = FakeDateTimeObserver(),
|
||||
),
|
||||
featureFlagService = featureFlagService,
|
||||
indicatorService = DefaultIndicatorService(
|
||||
@@ -672,3 +675,11 @@ class RoomListPresenterTest {
|
||||
logoutPresenter = { aDirectLogoutState() },
|
||||
)
|
||||
}
|
||||
|
||||
class FakeDateTimeObserver : DateTimeObserver {
|
||||
override val changes = MutableSharedFlow<DateTimeObserver.Event>(extraBufferCapacity = 1)
|
||||
|
||||
fun given(event: DateTimeObserver.Event) {
|
||||
changes.tryEmit(event)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright 2024 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Please see LICENSE in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.features.roomlist.impl.datasource
|
||||
|
||||
import app.cash.turbine.test
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.features.roomlist.impl.FakeDateTimeObserver
|
||||
import io.element.android.libraries.androidutils.system.DateTimeObserver
|
||||
import io.element.android.libraries.dateformatter.test.FakeLastMessageTimestampFormatter
|
||||
import io.element.android.libraries.matrix.api.roomlist.RoomListService
|
||||
import io.element.android.libraries.matrix.test.notificationsettings.FakeNotificationSettingsService
|
||||
import io.element.android.libraries.matrix.test.room.aRoomSummary
|
||||
import io.element.android.libraries.matrix.test.roomlist.FakeRoomListService
|
||||
import io.element.android.tests.testutils.testCoroutineDispatchers
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Test
|
||||
import java.time.Instant
|
||||
|
||||
class RoomListDataSourceTest {
|
||||
@Test
|
||||
fun `when DateTimeObserver gets a date change, the room summaries are refreshed`() = runTest {
|
||||
val roomListService = FakeRoomListService().apply {
|
||||
postState(RoomListService.State.Running)
|
||||
postAllRooms(listOf(aRoomSummary()))
|
||||
}
|
||||
val dateTimeObserver = FakeDateTimeObserver()
|
||||
val lastMessageTimestampFormatter = FakeLastMessageTimestampFormatter()
|
||||
lastMessageTimestampFormatter.givenFormat("Today")
|
||||
val roomListDataSource = createRoomListDataSource(
|
||||
roomListService = roomListService,
|
||||
roomListRoomSummaryFactory = aRoomListRoomSummaryFactory(
|
||||
lastMessageTimestampFormatter = lastMessageTimestampFormatter,
|
||||
),
|
||||
dateTimeObserver = dateTimeObserver,
|
||||
)
|
||||
|
||||
roomListDataSource.allRooms.test {
|
||||
// Observe room list items changes
|
||||
roomListDataSource.launchIn(backgroundScope)
|
||||
// Get the initial room list
|
||||
val initialRoomList = awaitItem()
|
||||
assertThat(initialRoomList).isNotEmpty()
|
||||
assertThat(initialRoomList.first().timestamp).isEqualTo("Today")
|
||||
lastMessageTimestampFormatter.givenFormat("Yesterday")
|
||||
// Trigger a date change
|
||||
dateTimeObserver.given(DateTimeObserver.Event.DateChanged(Instant.MIN, Instant.now()))
|
||||
// Check there is a new list and it's not the same as the previous one
|
||||
val newRoomList = awaitItem()
|
||||
assertThat(newRoomList).isNotSameInstanceAs(initialRoomList)
|
||||
assertThat(newRoomList.first().timestamp).isEqualTo("Yesterday")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when DateTimeObserver gets a time zone change, the room summaries are refreshed`() = runTest {
|
||||
val roomListService = FakeRoomListService().apply {
|
||||
postState(RoomListService.State.Running)
|
||||
postAllRooms(listOf(aRoomSummary()))
|
||||
}
|
||||
val dateTimeObserver = FakeDateTimeObserver()
|
||||
val lastMessageTimestampFormatter = FakeLastMessageTimestampFormatter()
|
||||
lastMessageTimestampFormatter.givenFormat("Today")
|
||||
val roomListDataSource = createRoomListDataSource(
|
||||
roomListService = roomListService,
|
||||
roomListRoomSummaryFactory = aRoomListRoomSummaryFactory(
|
||||
lastMessageTimestampFormatter = lastMessageTimestampFormatter,
|
||||
),
|
||||
dateTimeObserver = dateTimeObserver,
|
||||
)
|
||||
roomListDataSource.allRooms.test {
|
||||
// Observe room list items changes
|
||||
roomListDataSource.launchIn(backgroundScope)
|
||||
// Get the initial room list
|
||||
val initialRoomList = awaitItem()
|
||||
assertThat(initialRoomList).isNotEmpty()
|
||||
assertThat(initialRoomList.first().timestamp).isEqualTo("Today")
|
||||
lastMessageTimestampFormatter.givenFormat("Yesterday")
|
||||
// Trigger a timezone change
|
||||
dateTimeObserver.given(DateTimeObserver.Event.TimeZoneChanged)
|
||||
// Check there is a new list and it's not the same as the previous one
|
||||
val newRoomList = awaitItem()
|
||||
assertThat(newRoomList).isNotSameInstanceAs(initialRoomList)
|
||||
assertThat(newRoomList.first().timestamp).isEqualTo("Yesterday")
|
||||
}
|
||||
}
|
||||
|
||||
private fun TestScope.createRoomListDataSource(
|
||||
roomListService: FakeRoomListService = FakeRoomListService(),
|
||||
roomListRoomSummaryFactory: RoomListRoomSummaryFactory = aRoomListRoomSummaryFactory(),
|
||||
notificationSettingsService: FakeNotificationSettingsService = FakeNotificationSettingsService(),
|
||||
dateTimeObserver: FakeDateTimeObserver = FakeDateTimeObserver(),
|
||||
) = RoomListDataSource(
|
||||
roomListService = roomListService,
|
||||
roomListRoomSummaryFactory = roomListRoomSummaryFactory,
|
||||
coroutineDispatchers = testCoroutineDispatchers(),
|
||||
notificationSettingsService = notificationSettingsService,
|
||||
appScope = backgroundScope,
|
||||
dateTimeObserver = dateTimeObserver,
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright 2024 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Please see LICENSE in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.features.roomlist.impl.datasource
|
||||
|
||||
import io.element.android.libraries.dateformatter.api.LastMessageTimestampFormatter
|
||||
import io.element.android.libraries.eventformatter.api.RoomLastMessageFormatter
|
||||
|
||||
fun aRoomListRoomSummaryFactory(
|
||||
lastMessageTimestampFormatter: LastMessageTimestampFormatter = LastMessageTimestampFormatter { _ -> "Today" },
|
||||
roomLastMessageFormatter: RoomLastMessageFormatter = RoomLastMessageFormatter { _, _ -> "Hey" }
|
||||
) = RoomListRoomSummaryFactory(
|
||||
lastMessageTimestampFormatter = lastMessageTimestampFormatter,
|
||||
roomLastMessageFormatter = roomLastMessageFormatter
|
||||
)
|
||||
@@ -11,7 +11,7 @@ import app.cash.molecule.RecompositionMode
|
||||
import app.cash.molecule.moleculeFlow
|
||||
import app.cash.turbine.test
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.features.roomlist.impl.datasource.RoomListRoomSummaryFactory
|
||||
import io.element.android.features.roomlist.impl.datasource.aRoomListRoomSummaryFactory
|
||||
import io.element.android.libraries.dateformatter.test.FakeLastMessageTimestampFormatter
|
||||
import io.element.android.libraries.eventformatter.test.FakeRoomLastMessageFormatter
|
||||
import io.element.android.libraries.featureflag.api.FeatureFlagService
|
||||
@@ -142,7 +142,7 @@ fun TestScope.createRoomListSearchPresenter(
|
||||
return RoomListSearchPresenter(
|
||||
dataSource = RoomListSearchDataSource(
|
||||
roomListService = roomListService,
|
||||
roomSummaryFactory = RoomListRoomSummaryFactory(
|
||||
roomSummaryFactory = aRoomListRoomSummaryFactory(
|
||||
lastMessageTimestampFormatter = FakeLastMessageTimestampFormatter(),
|
||||
roomLastMessageFormatter = FakeRoomLastMessageFormatter(),
|
||||
),
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2024 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Please see LICENSE in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.androidutils.system
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import com.squareup.anvil.annotations.ContributesBinding
|
||||
import io.element.android.libraries.androidutils.system.DateTimeObserver.Event
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import io.element.android.libraries.di.ApplicationContext
|
||||
import io.element.android.libraries.di.SingleIn
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import java.time.Instant
|
||||
import javax.inject.Inject
|
||||
|
||||
interface DateTimeObserver {
|
||||
val changes: Flow<Event>
|
||||
|
||||
sealed interface Event {
|
||||
data object TimeZoneChanged : Event
|
||||
data class DateChanged(val previous: Instant, val new: Instant) : Event
|
||||
}
|
||||
}
|
||||
|
||||
@ContributesBinding(AppScope::class)
|
||||
@SingleIn(AppScope::class)
|
||||
class DefaultDateTimeObserver @Inject constructor(
|
||||
@ApplicationContext context: Context
|
||||
) : DateTimeObserver {
|
||||
private val dateTimeReceiver = object : BroadcastReceiver() {
|
||||
private var lastTime = Instant.now()
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
val newDate = Instant.now()
|
||||
when (intent.action) {
|
||||
Intent.ACTION_TIMEZONE_CHANGED -> changes.tryEmit(Event.TimeZoneChanged)
|
||||
Intent.ACTION_DATE_CHANGED -> changes.tryEmit(Event.DateChanged(lastTime, newDate))
|
||||
Intent.ACTION_TIME_CHANGED -> changes.tryEmit(Event.DateChanged(lastTime, newDate))
|
||||
}
|
||||
lastTime = newDate
|
||||
}
|
||||
}
|
||||
|
||||
override val changes = MutableSharedFlow<Event>(extraBufferCapacity = 10)
|
||||
|
||||
init {
|
||||
context.registerReceiver(dateTimeReceiver, IntentFilter().apply {
|
||||
addAction(Intent.ACTION_TIMEZONE_CHANGED)
|
||||
addAction(Intent.ACTION_DATE_CHANGED)
|
||||
addAction(Intent.ACTION_TIME_CHANGED)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,6 @@
|
||||
|
||||
package io.element.android.libraries.dateformatter.api
|
||||
|
||||
interface LastMessageTimestampFormatter {
|
||||
fun interface LastMessageTimestampFormatter {
|
||||
fun format(timestamp: Long?): String
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@ import android.text.format.DateFormat
|
||||
import android.text.format.DateUtils
|
||||
import kotlinx.datetime.Clock
|
||||
import kotlinx.datetime.LocalDateTime
|
||||
import kotlinx.datetime.TimeZone
|
||||
import kotlinx.datetime.toInstant
|
||||
import kotlinx.datetime.toJavaLocalDate
|
||||
import kotlinx.datetime.toJavaLocalDateTime
|
||||
@@ -25,7 +24,7 @@ import kotlin.math.absoluteValue
|
||||
class DateFormatters @Inject constructor(
|
||||
private val locale: Locale,
|
||||
private val clock: Clock,
|
||||
private val timeZone: TimeZone,
|
||||
private val timeZoneProvider: TimezoneProvider,
|
||||
) {
|
||||
private val onlyTimeFormatter: DateTimeFormatter by lazy {
|
||||
DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT).withLocale(locale)
|
||||
@@ -70,7 +69,7 @@ class DateFormatters @Inject constructor(
|
||||
return if (period.years.absoluteValue >= 1) {
|
||||
formatDateWithYear(dateToFormat)
|
||||
} else if (useRelative && period.days.absoluteValue < 2 && period.months.absoluteValue < 1) {
|
||||
getRelativeDay(dateToFormat.toInstant(timeZone).toEpochMilliseconds())
|
||||
getRelativeDay(dateToFormat.toInstant(timeZoneProvider.provide()).toEpochMilliseconds())
|
||||
} else {
|
||||
formatDateWithMonth(dateToFormat)
|
||||
}
|
||||
|
||||
@@ -10,21 +10,20 @@ package io.element.android.libraries.dateformatter.impl
|
||||
import kotlinx.datetime.Clock
|
||||
import kotlinx.datetime.Instant
|
||||
import kotlinx.datetime.LocalDateTime
|
||||
import kotlinx.datetime.TimeZone
|
||||
import kotlinx.datetime.toLocalDateTime
|
||||
import javax.inject.Inject
|
||||
|
||||
class LocalDateTimeProvider @Inject constructor(
|
||||
private val clock: Clock,
|
||||
private val timezone: TimeZone,
|
||||
private val timezoneProvider: TimezoneProvider,
|
||||
) {
|
||||
fun providesNow(): LocalDateTime {
|
||||
val now: Instant = clock.now()
|
||||
return now.toLocalDateTime(timezone)
|
||||
return now.toLocalDateTime(timezoneProvider.provide())
|
||||
}
|
||||
|
||||
fun providesFromTimestamp(timestamp: Long): LocalDateTime {
|
||||
val tsInstant = Instant.fromEpochMilliseconds(timestamp)
|
||||
return tsInstant.toLocalDateTime(timezone)
|
||||
return tsInstant.toLocalDateTime(timezoneProvider.provide())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* Copyright 2024 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Please see LICENSE in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.dateformatter.impl
|
||||
|
||||
import kotlinx.datetime.TimeZone
|
||||
|
||||
fun interface TimezoneProvider {
|
||||
fun provide(): TimeZone
|
||||
}
|
||||
@@ -10,6 +10,7 @@ package io.element.android.libraries.dateformatter.impl.di
|
||||
import com.squareup.anvil.annotations.ContributesTo
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import io.element.android.libraries.dateformatter.impl.TimezoneProvider
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import kotlinx.datetime.Clock
|
||||
import kotlinx.datetime.TimeZone
|
||||
@@ -25,5 +26,5 @@ object DateFormatterModule {
|
||||
fun providesLocale(): Locale = Locale.getDefault()
|
||||
|
||||
@Provides
|
||||
fun providesTimezone(): TimeZone = TimeZone.currentSystemDefault()
|
||||
fun providesTimezone(): TimezoneProvider = TimezoneProvider { TimeZone.currentSystemDefault() }
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ class DefaultLastMessageTimestampFormatterTest {
|
||||
val now = "1980-04-06T18:35:24.00Z"
|
||||
val dat = "1979-04-06T18:35:24.00Z"
|
||||
val clock = FakeClock().apply { givenInstant(Instant.parse(now)) }
|
||||
val dateFormatters = DateFormatters(Locale.US, clock, TimeZone.UTC)
|
||||
val dateFormatters = DateFormatters(Locale.US, clock) { TimeZone.UTC }
|
||||
assertThat(dateFormatters.formatDateWithFullFormat(Instant.parse(dat).toLocalDateTime(TimeZone.UTC))).isEqualTo("Friday, April 6, 1979")
|
||||
}
|
||||
|
||||
@@ -102,8 +102,8 @@ class DefaultLastMessageTimestampFormatterTest {
|
||||
*/
|
||||
private fun createFormatter(@Suppress("SameParameterValue") currentDate: String): LastMessageTimestampFormatter {
|
||||
val clock = FakeClock().apply { givenInstant(Instant.parse(currentDate)) }
|
||||
val localDateTimeProvider = LocalDateTimeProvider(clock, TimeZone.UTC)
|
||||
val dateFormatters = DateFormatters(Locale.US, clock, TimeZone.UTC)
|
||||
val localDateTimeProvider = LocalDateTimeProvider(clock) { TimeZone.UTC }
|
||||
val dateFormatters = DateFormatters(Locale.US, clock) { TimeZone.UTC }
|
||||
return DefaultLastMessageTimestampFormatter(localDateTimeProvider, dateFormatters)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,6 @@ package io.element.android.libraries.eventformatter.api
|
||||
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.EventTimelineItem
|
||||
|
||||
interface RoomLastMessageFormatter {
|
||||
fun interface RoomLastMessageFormatter {
|
||||
fun format(event: EventTimelineItem, isDmRoom: Boolean): CharSequence?
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ dependencies {
|
||||
implementation(projects.libraries.permissions.noop)
|
||||
implementation(projects.libraries.sessionStorage.implMemory)
|
||||
implementation(projects.libraries.designsystem)
|
||||
implementation(projects.libraries.androidutils)
|
||||
implementation(projects.libraries.architecture)
|
||||
implementation(projects.libraries.core)
|
||||
implementation(projects.libraries.network)
|
||||
|
||||
@@ -24,6 +24,7 @@ import io.element.android.features.roomlist.impl.filters.RoomListFiltersPresente
|
||||
import io.element.android.features.roomlist.impl.filters.selection.DefaultFilterSelectionStrategy
|
||||
import io.element.android.features.roomlist.impl.search.RoomListSearchDataSource
|
||||
import io.element.android.features.roomlist.impl.search.RoomListSearchPresenter
|
||||
import io.element.android.libraries.androidutils.system.DefaultDateTimeObserver
|
||||
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
||||
import io.element.android.libraries.dateformatter.impl.DateFormatters
|
||||
import io.element.android.libraries.dateformatter.impl.DefaultLastMessageTimestampFormatter
|
||||
@@ -59,9 +60,8 @@ class RoomListScreen(
|
||||
) {
|
||||
private val clock = Clock.System
|
||||
private val locale = Locale.getDefault()
|
||||
private val timeZone = TimeZone.currentSystemDefault()
|
||||
private val dateTimeProvider = LocalDateTimeProvider(clock, timeZone)
|
||||
private val dateFormatters = DateFormatters(locale, clock, timeZone)
|
||||
private val dateTimeProvider = LocalDateTimeProvider(clock) { TimeZone.currentSystemDefault() }
|
||||
private val dateFormatters = DateFormatters(locale, clock) { TimeZone.currentSystemDefault() }
|
||||
private val sessionVerificationService = matrixClient.sessionVerificationService()
|
||||
private val encryptionService = matrixClient.encryptionService()
|
||||
private val stringProvider = AndroidStringProvider(context.resources)
|
||||
@@ -92,7 +92,8 @@ class RoomListScreen(
|
||||
roomListRoomSummaryFactory = roomListRoomSummaryFactory,
|
||||
coroutineDispatchers = coroutineDispatchers,
|
||||
notificationSettingsService = matrixClient.notificationSettingsService(),
|
||||
appScope = Singleton.appScope
|
||||
appScope = Singleton.appScope,
|
||||
dateTimeObserver = DefaultDateTimeObserver(context),
|
||||
),
|
||||
indicatorService = DefaultIndicatorService(
|
||||
sessionVerificationService = sessionVerificationService,
|
||||
|
||||
Reference in New Issue
Block a user