Merge pull request #73 from vector-im/feature/bma/moreTests

More tests
This commit is contained in:
Benoit Marty 2023-02-14 17:01:28 +01:00 committed by GitHub
commit 78a83c0592
87 changed files with 4149 additions and 800 deletions

View file

@ -39,7 +39,8 @@ sealed interface Async<out T> {
suspend fun <T> (suspend () -> T).execute(state: MutableState<Async<T>>) {
try {
state.value = Async.Loading()
state.value = Async.Success(this())
val result = this()
state.value = Async.Success(result)
} catch (error: Throwable) {
state.value = Async.Failure(error)
}

View file

@ -24,6 +24,8 @@ class StableCharSequence(val charSequence: CharSequence) {
override fun hashCode() = hash
override fun equals(other: Any?) = other is StableCharSequence && other.hash == hash
override fun toString(): String = "StableCharSequence(\"$charSequence\")"
}
fun CharSequence.toStableCharSequence() = StableCharSequence(this)

1
libraries/dateformatter/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/build

View file

@ -0,0 +1,43 @@
/*
* Copyright (c) 2022 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// TODO: Remove once https://youtrack.jetbrains.com/issue/KTIJ-19369 is fixed
@Suppress("DSL_SCOPE_VIOLATION")
plugins {
id("io.element.android-library")
alias(libs.plugins.ksp)
alias(libs.plugins.anvil)
}
anvil {
generateDaggerFactories.set(true)
}
android {
namespace = "io.element.android.libraries.dateformatter"
dependencies {
anvil(projects.anvilcodegen)
implementation(libs.dagger)
implementation(projects.libraries.di)
implementation(projects.anvilannotations)
api(libs.datetime)
ksp(libs.showkase.processor)
testImplementation(libs.test.junit)
testImplementation(libs.test.truth)
}
}

View file

@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.kts.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View file

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright (c) 2023 New Vector Ltd
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<manifest />

View file

@ -0,0 +1,21 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.libraries.dateformatter
interface LastMessageFormatter {
fun format(timestamp: Long?): String
}

View file

@ -0,0 +1,38 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.libraries.dateformatter.di
import com.squareup.anvil.annotations.ContributesTo
import dagger.Module
import dagger.Provides
import io.element.android.libraries.di.AppScope
import kotlinx.datetime.Clock
import kotlinx.datetime.TimeZone
import java.util.*
@Module
@ContributesTo(AppScope::class)
object DateFormatterModule {
@Provides
fun providesClock(): Clock = Clock.System
@Provides
fun providesLocale(): Locale = Locale.getDefault()
@Provides
fun providesTimezone(): TimeZone = TimeZone.currentSystemDefault()
}

View file

@ -0,0 +1,106 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.libraries.dateformatter.impl
import android.text.format.DateFormat
import android.text.format.DateUtils
import com.squareup.anvil.annotations.ContributesBinding
import io.element.android.libraries.dateformatter.LastMessageFormatter
import io.element.android.libraries.di.AppScope
import kotlinx.datetime.Clock
import kotlinx.datetime.Instant
import kotlinx.datetime.LocalDateTime
import kotlinx.datetime.TimeZone
import kotlinx.datetime.toInstant
import kotlinx.datetime.toJavaLocalDate
import kotlinx.datetime.toJavaLocalDateTime
import kotlinx.datetime.toLocalDateTime
import java.time.Period
import java.time.format.DateTimeFormatter
import java.util.Locale
import javax.inject.Inject
import kotlin.math.absoluteValue
@ContributesBinding(AppScope::class)
class DefaultLastMessageFormatter @Inject constructor(
private val clock: Clock,
private val locale: Locale,
private val timezone: TimeZone,
) : LastMessageFormatter {
private val onlyTimeFormatter: DateTimeFormatter by lazy {
val pattern = DateFormat.getBestDateTimePattern(locale, "HH:mm") ?: "HH:mm"
DateTimeFormatter.ofPattern(pattern)
}
private val dateWithMonthFormatter: DateTimeFormatter by lazy {
val pattern = DateFormat.getBestDateTimePattern(locale, "d MMM") ?: "d MMM"
DateTimeFormatter.ofPattern(pattern)
}
private val dateWithYearFormatter: DateTimeFormatter by lazy {
val pattern = DateFormat.getBestDateTimePattern(locale, "dd.MM.yyyy") ?: "dd.MM.yyyy"
DateTimeFormatter.ofPattern(pattern)
}
override fun format(timestamp: Long?): String {
if (timestamp == null) return ""
val now: Instant = clock.now()
val tsInstant = Instant.fromEpochMilliseconds(timestamp)
val nowDateTime = now.toLocalDateTime(timezone)
val tsDateTime = tsInstant.toLocalDateTime(timezone)
val isSameDay = nowDateTime.date == tsDateTime.date
return when {
isSameDay -> {
onlyTimeFormatter.format(tsDateTime.toJavaLocalDateTime())
}
else -> {
formatDate(tsDateTime, nowDateTime)
}
}
}
private fun formatDate(
date: LocalDateTime,
currentDate: LocalDateTime,
): String {
val period = Period.between(date.date.toJavaLocalDate(), currentDate.date.toJavaLocalDate())
return if (period.years.absoluteValue >= 1) {
formatDateWithYear(date)
} else if (period.days.absoluteValue < 2 && period.months.absoluteValue < 1) {
getRelativeDay(date.toInstant(timezone).toEpochMilliseconds())
} else {
formatDateWithMonth(date)
}
}
private fun formatDateWithMonth(localDateTime: LocalDateTime): String {
return dateWithMonthFormatter.format(localDateTime.toJavaLocalDateTime())
}
private fun formatDateWithYear(localDateTime: LocalDateTime): String {
return dateWithYearFormatter.format(localDateTime.toJavaLocalDateTime())
}
private fun getRelativeDay(ts: Long): String {
return DateUtils.getRelativeTimeSpanString(
ts,
clock.now().toEpochMilliseconds(),
DateUtils.DAY_IN_MILLIS,
DateUtils.FORMAT_SHOW_WEEKDAY
)?.toString() ?: ""
}
}

View file

@ -0,0 +1,106 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.libraries.dateformatter.impl
import com.google.common.truth.Truth.assertThat
import io.element.android.libraries.dateformatter.LastMessageFormatter
import kotlinx.datetime.Instant
import kotlinx.datetime.TimeZone
import org.junit.Test
import java.util.Locale
class DefaultLastMessageFormatterTest {
@Test
fun `test null`() {
val now = "1980-04-06T18:35:24.00Z"
val formatter = createFormatter(now)
assertThat(formatter.format(null)).isEmpty()
}
@Test
fun `test epoch`() {
val now = "1980-04-06T18:35:24.00Z"
val formatter = createFormatter(now)
assertThat(formatter.format(0)).isEqualTo("01.01.1970")
}
@Test
fun `test now`() {
val now = "1980-04-06T18:35:24.00Z"
val dat = "1980-04-06T18:35:24.00Z"
val formatter = createFormatter(now)
assertThat(formatter.format(Instant.parse(dat).toEpochMilliseconds())).isEqualTo("18:35")
}
@Test
fun `test one second before`() {
val now = "1980-04-06T18:35:24.00Z"
val dat = "1980-04-06T18:35:23.00Z"
val formatter = createFormatter(now)
assertThat(formatter.format(Instant.parse(dat).toEpochMilliseconds())).isEqualTo("18:35")
}
@Test
fun `test one minute before`() {
val now = "1980-04-06T18:35:24.00Z"
val dat = "1980-04-06T18:34:24.00Z"
val formatter = createFormatter(now)
assertThat(formatter.format(Instant.parse(dat).toEpochMilliseconds())).isEqualTo("18:34")
}
@Test
fun `test one hour before`() {
val now = "1980-04-06T18:35:24.00Z"
val dat = "1980-04-06T17:35:24.00Z"
val formatter = createFormatter(now)
assertThat(formatter.format(Instant.parse(dat).toEpochMilliseconds())).isEqualTo("17:35")
}
@Test
fun `test one day before same time`() {
val now = "1980-04-06T18:35:24.00Z"
val dat = "1980-04-05T18:35:24.00Z"
val formatter = createFormatter(now)
// TODO DateUtils.getRelativeTimeSpanString returns null.
assertThat(formatter.format(Instant.parse(dat).toEpochMilliseconds())).isEqualTo("")
}
@Test
fun `test one month before same time`() {
val now = "1980-04-06T18:35:24.00Z"
val dat = "1980-03-06T18:35:24.00Z"
val formatter = createFormatter(now)
assertThat(formatter.format(Instant.parse(dat).toEpochMilliseconds())).isEqualTo("6 Mar")
}
@Test
fun `test one year before same time`() {
val now = "1980-04-06T18:35:24.00Z"
val dat = "1979-04-06T18:35:24.00Z"
val formatter = createFormatter(now)
assertThat(formatter.format(Instant.parse(dat).toEpochMilliseconds())).isEqualTo("06.04.1979")
}
/**
* Create DefaultLastMessageFormatter and set current time to the provided date.
*/
private fun createFormatter(@Suppress("SameParameterValue") currentDate: String): LastMessageFormatter {
val clock = FakeClock().also { it.givenInstant(Instant.parse(currentDate)) }
return DefaultLastMessageFormatter(clock, Locale.US, TimeZone.UTC)
}
}

View file

@ -0,0 +1,30 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.libraries.dateformatter.impl
import kotlinx.datetime.Clock
import kotlinx.datetime.Instant
class FakeClock : Clock {
private var instant: Instant = Instant.fromEpochMilliseconds(0)
fun givenInstant(instant: Instant) {
this.instant = instant
}
override fun now(): Instant = instant
}

View file

@ -25,10 +25,18 @@ import io.element.android.libraries.matrix.room.MatrixRoom
import io.element.android.libraries.matrix.room.RoomSummaryDataSource
import io.element.android.libraries.matrixtest.media.FakeMediaResolver
import io.element.android.libraries.matrixtest.room.FakeMatrixRoom
import io.element.android.libraries.matrixtest.room.InMemoryRoomSummaryDataSource
import io.element.android.libraries.matrixtest.room.FakeRoomSummaryDataSource
import kotlinx.coroutines.delay
import org.matrix.rustcomponents.sdk.MediaSource
class FakeMatrixClient(override val sessionId: SessionId) : MatrixClient {
class FakeMatrixClient(
override val sessionId: SessionId = SessionId(A_SESSION_ID),
private val userDisplayName: Result<String> = Result.success(A_USER_NAME),
private val userAvatarURLString: Result<String> = Result.success(AN_AVATAR_URL),
val roomSummaryDataSource: RoomSummaryDataSource = FakeRoomSummaryDataSource()
) : MatrixClient {
private var logoutFailure: Throwable? = null
override fun getRoom(roomId: RoomId): MatrixRoom? {
return FakeMatrixRoom(roomId)
@ -39,23 +47,30 @@ class FakeMatrixClient(override val sessionId: SessionId) : MatrixClient {
override fun stopSync() = Unit
override fun roomSummaryDataSource(): RoomSummaryDataSource {
return InMemoryRoomSummaryDataSource()
return roomSummaryDataSource
}
override fun mediaResolver(): MediaResolver {
return FakeMediaResolver()
}
override suspend fun logout() = Unit
fun givenLogoutError(failure: Throwable) {
logoutFailure = failure
}
override fun userId(): UserId = UserId("")
override suspend fun logout() {
delay(100)
logoutFailure?.let { throw it }
}
override fun userId(): UserId = A_USER_ID
override suspend fun loadUserDisplayName(): Result<String> {
return Result.success("")
return userDisplayName
}
override suspend fun loadUserAvatarURLString(): Result<String> {
return Result.success("")
return userAvatarURLString
}
override suspend fun loadMediaContentForSource(source: MediaSource): Result<ByteArray> {

View file

@ -0,0 +1,44 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.libraries.matrixtest
import io.element.android.libraries.matrix.core.EventId
import io.element.android.libraries.matrix.core.RoomId
import io.element.android.libraries.matrix.core.UserId
const val A_USER_NAME = "alice"
const val A_PASSWORD = "password"
val A_USER_ID = UserId("@alice:server.org")
val A_ROOM_ID = RoomId("!aRoomId")
val AN_EVENT_ID = EventId("\$anEventId")
const val A_ROOM_NAME = "A room name"
const val A_MESSAGE = "Hello world!"
const val A_REPLY = "OK, I'll be there!"
const val ANOTHER_MESSAGE = "Hello universe!"
const val A_HOMESERVER = "matrix.org"
const val A_HOMESERVER_2 = "matrix-client.org"
const val A_SESSION_ID = "sessionId"
const val AN_AVATAR_URL = "mxc://data"
const val A_FAILURE_REASON = "There has been a failure"
val A_THROWABLE = Throwable(A_FAILURE_REASON)
val AN_EXCEPTION = Exception(A_FAILURE_REASON)

View file

@ -0,0 +1,69 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.libraries.matrixtest.auth
import io.element.android.libraries.matrix.MatrixClient
import io.element.android.libraries.matrix.auth.MatrixAuthenticationService
import io.element.android.libraries.matrix.core.SessionId
import io.element.android.libraries.matrixtest.A_HOMESERVER
import io.element.android.libraries.matrixtest.A_SESSION_ID
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
class FakeAuthenticationService : MatrixAuthenticationService {
private var homeserver: String = A_HOMESERVER
private var loginError: Throwable? = null
override fun isLoggedIn(): Flow<Boolean> {
return flowOf(false)
}
override suspend fun getLatestSessionId(): SessionId? {
return null
}
override suspend fun restoreSession(sessionId: SessionId): MatrixClient? {
return null
}
override fun getHomeserver(): String? {
return null
}
fun givenHomeserver(homeserver: String) {
this.homeserver = homeserver
}
override fun getHomeserverOrDefault(): String {
return homeserver
}
override suspend fun setHomeserver(homeserver: String) {
delay(100)
}
override suspend fun login(username: String, password: String): SessionId {
delay(100)
loginError?.let { throw it }
return SessionId(A_SESSION_ID)
}
fun givenLoginError(throwable: Throwable?) {
loginError = throwable
}
}

View file

@ -20,17 +20,20 @@ import io.element.android.libraries.matrix.core.EventId
import io.element.android.libraries.matrix.core.RoomId
import io.element.android.libraries.matrix.room.MatrixRoom
import io.element.android.libraries.matrix.timeline.MatrixTimeline
import io.element.android.libraries.matrixtest.A_ROOM_ID
import io.element.android.libraries.matrixtest.timeline.FakeMatrixTimeline
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.emptyFlow
class FakeMatrixRoom(
override val roomId: RoomId,
override val roomId: RoomId = A_ROOM_ID,
override val name: String? = null,
override val bestName: String = "",
override val displayName: String = "",
override val topic: String? = null,
override val avatarUrl: String? = null
override val avatarUrl: String? = null,
private val matrixTimeline: MatrixTimeline = FakeMatrixTimeline(),
) : MatrixRoom {
override fun syncUpdateFlow(): Flow<Long> {
@ -38,7 +41,7 @@ class FakeMatrixRoom(
}
override fun timeline(): MatrixTimeline {
return FakeMatrixTimeline()
return matrixTimeline
}
override suspend fun userDisplayName(userId: String): Result<String?> {
@ -50,18 +53,34 @@ class FakeMatrixRoom(
}
override suspend fun sendMessage(message: String): Result<Unit> {
TODO("Not yet implemented")
delay(100)
return Result.success(Unit)
}
var editMessageParameter: String? = null
private set
override suspend fun editMessage(originalEventId: EventId, message: String): Result<Unit> {
TODO("Not yet implemented")
editMessageParameter = message
delay(100)
return Result.success(Unit)
}
var replyMessageParameter: String? = null
private set
override suspend fun replyMessage(eventId: EventId, message: String): Result<Unit> {
TODO("Not yet implemented")
replyMessageParameter = message
delay(100)
return Result.success(Unit)
}
var redactEventEventIdParam: EventId? = null
private set
override suspend fun redactEvent(eventId: EventId, reason: String?): Result<Unit> {
TODO("Not yet implemented")
redactEventEventIdParam = eventId
delay(100)
return Result.success(Unit)
}
}

View file

@ -21,11 +21,22 @@ import io.element.android.libraries.matrix.room.RoomSummaryDataSource
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
class InMemoryRoomSummaryDataSource : RoomSummaryDataSource {
class FakeRoomSummaryDataSource : RoomSummaryDataSource {
override fun roomSummaries(): StateFlow<List<RoomSummary>> {
return MutableStateFlow(emptyList())
private val roomSummariesFlow = MutableStateFlow<List<RoomSummary>>(emptyList())
suspend fun postRoomSummary(roomSummaries: List<RoomSummary>) {
roomSummariesFlow.emit(roomSummaries)
}
override fun setSlidingSyncRange(range: IntRange) = Unit
override fun roomSummaries(): StateFlow<List<RoomSummary>> {
return roomSummariesFlow
}
var latestSlidingSyncRange: IntRange? = null
private set
override fun setSlidingSyncRange(range: IntRange) {
latestSlidingSyncRange = range
}
}

View file

@ -0,0 +1,62 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.libraries.matrixtest.room
import io.element.android.libraries.matrix.core.RoomId
import io.element.android.libraries.matrix.room.RoomSummary
import io.element.android.libraries.matrix.room.RoomSummaryDetails
import io.element.android.libraries.matrixtest.A_MESSAGE
import io.element.android.libraries.matrixtest.A_ROOM_ID
import io.element.android.libraries.matrixtest.A_ROOM_NAME
fun aRoomSummaryFilled(
roomId: RoomId = A_ROOM_ID,
name: String = A_ROOM_NAME,
isDirect: Boolean = false,
avatarURLString: String? = null,
lastMessage: CharSequence? = A_MESSAGE,
lastMessageTimestamp: Long? = null,
unreadNotificationCount: Int = 2,
) = RoomSummary.Filled(
aRoomSummaryDetail(
roomId = roomId,
name = name,
isDirect = isDirect,
avatarURLString = avatarURLString,
lastMessage = lastMessage,
lastMessageTimestamp = lastMessageTimestamp,
unreadNotificationCount = unreadNotificationCount,
)
)
fun aRoomSummaryDetail(
roomId: RoomId = A_ROOM_ID,
name: String = A_ROOM_NAME,
isDirect: Boolean = false,
avatarURLString: String? = null,
lastMessage: CharSequence? = A_MESSAGE,
lastMessageTimestamp: Long? = null,
unreadNotificationCount: Int = 2,
) = RoomSummaryDetails(
roomId = roomId,
name = name,
isDirect = isDirect,
avatarURLString = avatarURLString,
lastMessage = lastMessage,
lastMessageTimestamp = lastMessageTimestamp,
unreadNotificationCount = unreadNotificationCount,
)

View file

@ -19,24 +19,29 @@ package io.element.android.libraries.matrixtest.timeline
import io.element.android.libraries.matrix.core.EventId
import io.element.android.libraries.matrix.timeline.MatrixTimeline
import io.element.android.libraries.matrix.timeline.MatrixTimelineItem
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.emptyFlow
import org.matrix.rustcomponents.sdk.TimelineListener
class FakeMatrixTimeline : MatrixTimeline {
override var callback: MatrixTimeline.Callback? = null
override var callback: MatrixTimeline.Callback?
get() = null
set(value) {}
private var hasMoreToLoadValue: Boolean = true
fun givenHasMoreToLoad(hasMoreToLoad: Boolean) {
this.hasMoreToLoadValue = hasMoreToLoad
}
override val hasMoreToLoad: Boolean
get() = true
get() = hasMoreToLoadValue
override fun timelineItems(): Flow<List<MatrixTimelineItem>> {
return emptyFlow()
}
override suspend fun paginateBackwards(count: Int): Result<Unit> {
delay(100)
return Result.success(Unit)
}