Delegate call notifications to Element Call, upgrade SDK and EC embedded (#5119)
* Stop sending call notifications manually: the Element Call widget can now assume responsibility for sending them when you start a call. * Upgrade SDK version to `v25.8.5`, fix API breaks * Upgrade Element Call embedded to `v0.14.1` * Fix tests and lint issues * Add `RoomListEntriesDynamicFilterKind.NonSpace` to avoid displaying spaces in the room list --------- Co-authored-by: Robin <robin@robin.town>
This commit is contained in:
committed by
GitHub
parent
0b895f631d
commit
a87bbdd91c
@@ -33,14 +33,11 @@ import io.element.android.libraries.architecture.Presenter
|
||||
import io.element.android.libraries.architecture.runCatchingUpdatingState
|
||||
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
||||
import io.element.android.libraries.di.annotations.AppCoroutineScope
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
import io.element.android.libraries.matrix.api.MatrixClientProvider
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.sync.SyncState
|
||||
import io.element.android.libraries.matrix.api.widget.MatrixWidgetDriver
|
||||
import io.element.android.libraries.network.useragent.UserAgentProvider
|
||||
import io.element.android.services.analytics.api.ScreenTracker
|
||||
import io.element.android.services.appnavstate.api.ActiveRoomsHolder
|
||||
import io.element.android.services.appnavstate.api.AppForegroundStateService
|
||||
import io.element.android.services.toolbox.api.systemclock.SystemClock
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
@@ -64,7 +61,6 @@ class CallScreenPresenter @AssistedInject constructor(
|
||||
private val activeCallManager: ActiveCallManager,
|
||||
private val languageTagProvider: LanguageTagProvider,
|
||||
private val appForegroundStateService: AppForegroundStateService,
|
||||
private val activeRoomsHolder: ActiveRoomsHolder,
|
||||
@AppCoroutineScope
|
||||
private val appCoroutineScope: CoroutineScope,
|
||||
) : Presenter<CallScreenState> {
|
||||
@@ -75,7 +71,6 @@ class CallScreenPresenter @AssistedInject constructor(
|
||||
|
||||
private val isInWidgetMode = callType is CallType.RoomCall
|
||||
private val userAgent = userAgentProvider.provide()
|
||||
private var notifiedCallStart = false
|
||||
|
||||
@Composable
|
||||
override fun present(): CallScreenState {
|
||||
@@ -248,9 +243,7 @@ class CallScreenPresenter @AssistedInject constructor(
|
||||
Timber.d("Observing sync state in-call for sessionId: ${roomCallType.sessionId}")
|
||||
client.syncService().syncState
|
||||
.collect { state ->
|
||||
if (state == SyncState.Running) {
|
||||
client.notifyCallStartIfNeeded(callType.roomId)
|
||||
} else {
|
||||
if (state != SyncState.Running) {
|
||||
appForegroundStateService.updateIsInCallState(true)
|
||||
}
|
||||
}
|
||||
@@ -263,32 +256,6 @@ class CallScreenPresenter @AssistedInject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun MatrixClient.notifyCallStartIfNeeded(roomId: RoomId) {
|
||||
if (notifiedCallStart) return
|
||||
|
||||
val activeRoomForSession = activeRoomsHolder.getActiveRoomMatching(sessionId, roomId)
|
||||
val sendCallNotificationResult = if (activeRoomForSession != null) {
|
||||
Timber.d("Notifying call start for room $roomId. Has room call: ${activeRoomForSession.info().hasRoomCall}")
|
||||
activeRoomForSession.sendCallNotificationIfNeeded()
|
||||
} else {
|
||||
// Instantiate the room from the session and roomId and send the notification
|
||||
getJoinedRoom(roomId)?.use { room ->
|
||||
Timber.d("Notifying call start for room $roomId. Has room call: ${room.info().hasRoomCall}")
|
||||
room.sendCallNotificationIfNeeded()
|
||||
} ?: run {
|
||||
Timber.w("No room found for session $sessionId and room $roomId, skipping call notification.")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
sendCallNotificationResult.fold(
|
||||
onSuccess = { notifiedCallStart = true },
|
||||
onFailure = { error ->
|
||||
Timber.e(error, "Failed to send call notification for room $roomId.")
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private fun parseMessage(message: String): WidgetMessage? {
|
||||
return WidgetMessageSerializer.deserialize(message).getOrNull()
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import io.element.android.libraries.di.AppScope
|
||||
import io.element.android.libraries.matrix.api.MatrixClientProvider
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.core.SessionId
|
||||
import io.element.android.libraries.matrix.api.room.isDm
|
||||
import io.element.android.libraries.matrix.api.widget.CallWidgetSettingsProvider
|
||||
import io.element.android.libraries.preferences.api.store.AppPreferencesStore
|
||||
import io.element.android.services.appnavstate.api.ActiveRoomsHolder
|
||||
@@ -44,7 +45,7 @@ class DefaultCallWidgetProvider @Inject constructor(
|
||||
val baseUrl = customBaseUrl ?: EMBEDDED_CALL_WIDGET_BASE_URL
|
||||
|
||||
val isEncrypted = room.info().isEncrypted ?: room.getUpdatedIsEncrypted().getOrThrow()
|
||||
val widgetSettings = callWidgetSettingsProvider.provide(baseUrl, encrypted = isEncrypted)
|
||||
val widgetSettings = callWidgetSettingsProvider.provide(baseUrl, encrypted = isEncrypted, direct = room.isDm())
|
||||
val callUrl = room.generateWidgetWebViewUrl(
|
||||
widgetSettings = widgetSettings,
|
||||
clientId = clientId,
|
||||
|
||||
@@ -26,13 +26,11 @@ import io.element.android.libraries.matrix.test.A_ROOM_ID
|
||||
import io.element.android.libraries.matrix.test.A_SESSION_ID
|
||||
import io.element.android.libraries.matrix.test.FakeMatrixClient
|
||||
import io.element.android.libraries.matrix.test.FakeMatrixClientProvider
|
||||
import io.element.android.libraries.matrix.test.room.FakeJoinedRoom
|
||||
import io.element.android.libraries.matrix.test.sync.FakeSyncService
|
||||
import io.element.android.libraries.matrix.test.widget.FakeMatrixWidgetDriver
|
||||
import io.element.android.libraries.network.useragent.UserAgentProvider
|
||||
import io.element.android.services.analytics.api.ScreenTracker
|
||||
import io.element.android.services.analytics.test.FakeScreenTracker
|
||||
import io.element.android.services.appnavstate.api.ActiveRoomsHolder
|
||||
import io.element.android.services.appnavstate.test.FakeAppForegroundStateService
|
||||
import io.element.android.services.toolbox.api.systemclock.SystemClock
|
||||
import io.element.android.tests.testutils.WarmUpRule
|
||||
@@ -82,19 +80,12 @@ import kotlin.time.Duration.Companion.seconds
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - with CallType RoomCall sets call as active, loads URL, runs WidgetDriver and notifies the other clients a call started`() = runTest {
|
||||
val sendCallNotificationIfNeededLambda = lambdaRecorder<Result<Boolean>> { Result.success(true) }
|
||||
val syncService = FakeSyncService(SyncState.Running)
|
||||
val fakeRoom = FakeJoinedRoom(sendCallNotificationIfNeededResult = sendCallNotificationIfNeededLambda)
|
||||
val client = FakeMatrixClient(syncService = syncService).apply {
|
||||
givenGetRoomResult(A_ROOM_ID, fakeRoom)
|
||||
}
|
||||
fun `present - with CallType RoomCall sets call as active, loads URL and runs WidgetDriver`() = runTest {
|
||||
val widgetDriver = FakeMatrixWidgetDriver()
|
||||
val widgetProvider = FakeCallWidgetProvider(widgetDriver)
|
||||
val analyticsLambda = lambdaRecorder<MobileScreen.ScreenName, Unit> {}
|
||||
val joinedCallLambda = lambdaRecorder<CallType, Unit> {}
|
||||
val presenter = createCallScreenPresenter(
|
||||
matrixClientsProvider = FakeMatrixClientProvider(getClient = { Result.success(client) }),
|
||||
callType = CallType.RoomCall(A_SESSION_ID, A_ROOM_ID),
|
||||
widgetDriver = widgetDriver,
|
||||
widgetProvider = widgetProvider,
|
||||
@@ -116,7 +107,6 @@ import kotlin.time.Duration.Companion.seconds
|
||||
assertThat(widgetProvider.getWidgetCalled).isTrue()
|
||||
assertThat(widgetDriver.runCalledCount).isEqualTo(1)
|
||||
analyticsLambda.assertions().isCalledOnce().with(value(MobileScreen.ScreenName.RoomCall))
|
||||
sendCallNotificationIfNeededLambda.assertions().isCalledOnce()
|
||||
|
||||
// Wait until the WidgetDriver is loaded
|
||||
skipItems(1)
|
||||
@@ -399,7 +389,6 @@ import kotlin.time.Duration.Companion.seconds
|
||||
activeCallManager: FakeActiveCallManager = FakeActiveCallManager(),
|
||||
screenTracker: ScreenTracker = FakeScreenTracker(),
|
||||
appForegroundStateService: FakeAppForegroundStateService = FakeAppForegroundStateService(),
|
||||
activeRoomsHolder: ActiveRoomsHolder = ActiveRoomsHolder(),
|
||||
): CallScreenPresenter {
|
||||
val userAgentProvider = object : UserAgentProvider {
|
||||
override fun provide(): String {
|
||||
@@ -420,7 +409,6 @@ import kotlin.time.Duration.Companion.seconds
|
||||
languageTagProvider = FakeLanguageTagProvider("en-US"),
|
||||
appForegroundStateService = appForegroundStateService,
|
||||
appCoroutineScope = backgroundScope,
|
||||
activeRoomsHolder = activeRoomsHolder,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,7 +176,7 @@ jsoup = "org.jsoup:jsoup:1.21.1"
|
||||
appyx_core = { module = "com.bumble.appyx:core", version.ref = "appyx" }
|
||||
molecule-runtime = "app.cash.molecule:molecule-runtime:2.1.0"
|
||||
timber = "com.jakewharton.timber:timber:5.0.1"
|
||||
matrix_sdk = "org.matrix.rustcomponents:sdk-android:25.7.28"
|
||||
matrix_sdk = "org.matrix.rustcomponents:sdk-android:25.8.5"
|
||||
matrix_richtexteditor = { module = "io.element.android:wysiwyg", version.ref = "wysiwyg" }
|
||||
matrix_richtexteditor_compose = { module = "io.element.android:wysiwyg-compose", version.ref = "wysiwyg" }
|
||||
sqldelight-driver-android = { module = "app.cash.sqldelight:android-driver", version.ref = "sqldelight" }
|
||||
@@ -215,7 +215,7 @@ anvil_compiler_api = { module = "dev.zacsweers.anvil:compiler-api", version.ref
|
||||
anvil_compiler_utils = { module = "dev.zacsweers.anvil:compiler-utils", version.ref = "anvil" }
|
||||
|
||||
# Element Call
|
||||
element_call_embedded = "io.element.android:element-call-embedded:0.13.1"
|
||||
element_call_embedded = "io.element.android:element-call-embedded:0.14.1"
|
||||
|
||||
# Auto services
|
||||
google_autoservice = { module = "com.google.auto.service:auto-service", version.ref = "autoservice" }
|
||||
|
||||
@@ -156,11 +156,6 @@ interface JoinedRoom : BaseRoom {
|
||||
*/
|
||||
fun getWidgetDriver(widgetSettings: MatrixWidgetSettings): Result<MatrixWidgetDriver>
|
||||
|
||||
/**
|
||||
* Send an Element Call started notification if needed.
|
||||
*/
|
||||
suspend fun sendCallNotificationIfNeeded(): Result<Boolean>
|
||||
|
||||
suspend fun setSendQueueEnabled(enabled: Boolean)
|
||||
|
||||
/**
|
||||
|
||||
@@ -14,5 +14,6 @@ interface CallWidgetSettingsProvider {
|
||||
baseUrl: String,
|
||||
widgetId: String = UUID.randomUUID().toString(),
|
||||
encrypted: Boolean,
|
||||
direct: Boolean,
|
||||
): MatrixWidgetSettings
|
||||
}
|
||||
|
||||
@@ -428,12 +428,6 @@ class JoinedRustRoom(
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun sendCallNotificationIfNeeded(): Result<Boolean> = withContext(roomDispatcher) {
|
||||
runCatchingExceptions {
|
||||
innerRoom.sendCallNotificationIfNeeded()
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun setSendQueueEnabled(enabled: Boolean) {
|
||||
withContext(roomDispatcher) {
|
||||
Timber.d("setSendQueuesEnabled: $enabled")
|
||||
|
||||
@@ -29,6 +29,7 @@ import org.matrix.rustcomponents.sdk.RoomList as InnerRoomList
|
||||
|
||||
private val ROOM_LIST_RUST_FILTERS = listOf(
|
||||
RoomListEntriesDynamicFilterKind.NonLeft,
|
||||
RoomListEntriesDynamicFilterKind.NonSpace,
|
||||
RoomListEntriesDynamicFilterKind.DeduplicateVersions
|
||||
)
|
||||
|
||||
|
||||
@@ -14,7 +14,6 @@ import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import org.matrix.rustcomponents.sdk.TimelineChange
|
||||
import org.matrix.rustcomponents.sdk.TimelineDiff
|
||||
import org.matrix.rustcomponents.sdk.TimelineItem
|
||||
import timber.log.Timber
|
||||
@@ -49,13 +48,13 @@ internal class MatrixTimelineDiffProcessor(
|
||||
}
|
||||
|
||||
private fun MutableList<MatrixTimelineItem>.applyDiff(diff: TimelineDiff) {
|
||||
when (diff.change()) {
|
||||
TimelineChange.APPEND -> {
|
||||
val items = diff.append()?.map { it.asMatrixTimelineItem() } ?: return
|
||||
when (diff) {
|
||||
is TimelineDiff.Append -> {
|
||||
val items = diff.values.map { it.asMatrixTimelineItem() }
|
||||
addAll(items)
|
||||
}
|
||||
TimelineChange.PUSH_BACK -> {
|
||||
val item = diff.pushBack()?.asMatrixTimelineItem() ?: return
|
||||
is TimelineDiff.PushBack -> {
|
||||
val item = diff.value.asMatrixTimelineItem()
|
||||
if (item is MatrixTimelineItem.Event && item.event.content is RoomMembershipContent) {
|
||||
// TODO - This is a temporary solution to notify the room screen about membership changes
|
||||
// Ideally, this should be implemented by the Rust SDK
|
||||
@@ -63,41 +62,37 @@ internal class MatrixTimelineDiffProcessor(
|
||||
}
|
||||
add(item)
|
||||
}
|
||||
TimelineChange.PUSH_FRONT -> {
|
||||
val item = diff.pushFront()?.asMatrixTimelineItem() ?: return
|
||||
is TimelineDiff.PushFront -> {
|
||||
val item = diff.value.asMatrixTimelineItem()
|
||||
add(0, item)
|
||||
}
|
||||
TimelineChange.SET -> {
|
||||
val updateAtData = diff.set() ?: return
|
||||
val item = updateAtData.item.asMatrixTimelineItem()
|
||||
set(updateAtData.index.toInt(), item)
|
||||
is TimelineDiff.Set -> {
|
||||
val item = diff.value.asMatrixTimelineItem()
|
||||
set(diff.index.toInt(), item)
|
||||
}
|
||||
TimelineChange.INSERT -> {
|
||||
val insertAtData = diff.insert() ?: return
|
||||
val item = insertAtData.item.asMatrixTimelineItem()
|
||||
add(insertAtData.index.toInt(), item)
|
||||
is TimelineDiff.Insert -> {
|
||||
val item = diff.value.asMatrixTimelineItem()
|
||||
add(diff.index.toInt(), item)
|
||||
}
|
||||
TimelineChange.REMOVE -> {
|
||||
val removeAtData = diff.remove() ?: return
|
||||
removeAt(removeAtData.toInt())
|
||||
is TimelineDiff.Remove -> {
|
||||
removeAt(diff.index.toInt())
|
||||
}
|
||||
TimelineChange.RESET -> {
|
||||
is TimelineDiff.Reset -> {
|
||||
clear()
|
||||
val items = diff.reset()?.map { it.asMatrixTimelineItem() } ?: return
|
||||
val items = diff.values.map { it.asMatrixTimelineItem() }
|
||||
addAll(items)
|
||||
}
|
||||
TimelineChange.POP_FRONT -> {
|
||||
TimelineDiff.PopFront -> {
|
||||
removeFirstOrNull()
|
||||
}
|
||||
TimelineChange.POP_BACK -> {
|
||||
TimelineDiff.PopBack -> {
|
||||
removeLastOrNull()
|
||||
}
|
||||
TimelineChange.CLEAR -> {
|
||||
TimelineDiff.Clear -> {
|
||||
clear()
|
||||
}
|
||||
TimelineChange.TRUNCATE -> {
|
||||
val index = diff.truncate() ?: return
|
||||
subList(index.toInt(), size).clear()
|
||||
is TimelineDiff.Truncate -> {
|
||||
subList(diff.length.toInt(), size).clear()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
|
||||
package io.element.android.libraries.matrix.impl.timeline
|
||||
|
||||
import org.matrix.rustcomponents.sdk.TimelineChange
|
||||
import org.matrix.rustcomponents.sdk.TimelineDiff
|
||||
import org.matrix.rustcomponents.sdk.TimelineItem
|
||||
import uniffi.matrix_sdk_ui.EventItemOrigin
|
||||
@@ -17,25 +16,13 @@ import uniffi.matrix_sdk_ui.EventItemOrigin
|
||||
* If there is multiple events in the diff, uses the first one as it should be a good indicator.
|
||||
*/
|
||||
internal fun TimelineDiff.eventOrigin(): EventItemOrigin? {
|
||||
return when (change()) {
|
||||
TimelineChange.APPEND -> {
|
||||
append()?.firstOrNull()?.eventOrigin()
|
||||
}
|
||||
TimelineChange.PUSH_BACK -> {
|
||||
pushBack()?.eventOrigin()
|
||||
}
|
||||
TimelineChange.PUSH_FRONT -> {
|
||||
pushFront()?.eventOrigin()
|
||||
}
|
||||
TimelineChange.SET -> {
|
||||
set()?.item?.eventOrigin()
|
||||
}
|
||||
TimelineChange.INSERT -> {
|
||||
insert()?.item?.eventOrigin()
|
||||
}
|
||||
TimelineChange.RESET -> {
|
||||
reset()?.firstOrNull()?.eventOrigin()
|
||||
}
|
||||
return when (this) {
|
||||
is TimelineDiff.Append -> values.firstOrNull()?.eventOrigin()
|
||||
is TimelineDiff.PushBack -> value.eventOrigin()
|
||||
is TimelineDiff.PushFront -> value.eventOrigin()
|
||||
is TimelineDiff.Set -> value.eventOrigin()
|
||||
is TimelineDiff.Insert -> value.eventOrigin()
|
||||
is TimelineDiff.Reset -> values.firstOrNull()?.eventOrigin()
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import kotlinx.coroutines.flow.first
|
||||
import org.matrix.rustcomponents.sdk.newVirtualElementCallWidget
|
||||
import uniffi.matrix_sdk.EncryptionSystem
|
||||
import uniffi.matrix_sdk.HeaderStyle
|
||||
import uniffi.matrix_sdk.NotificationType
|
||||
import uniffi.matrix_sdk.VirtualElementCallWidgetOptions
|
||||
import javax.inject.Inject
|
||||
import uniffi.matrix_sdk.Intent as CallIntent
|
||||
@@ -29,7 +30,7 @@ class DefaultCallWidgetSettingsProvider @Inject constructor(
|
||||
private val callAnalyticsCredentialsProvider: CallAnalyticCredentialsProvider,
|
||||
private val analyticsService: AnalyticsService,
|
||||
) : CallWidgetSettingsProvider {
|
||||
override suspend fun provide(baseUrl: String, widgetId: String, encrypted: Boolean): MatrixWidgetSettings {
|
||||
override suspend fun provide(baseUrl: String, widgetId: String, encrypted: Boolean, direct: Boolean): MatrixWidgetSettings {
|
||||
val isAnalyticsEnabled = analyticsService.userConsentFlow.first()
|
||||
val options = VirtualElementCallWidgetOptions(
|
||||
elementCallUrl = baseUrl,
|
||||
@@ -53,6 +54,7 @@ class DefaultCallWidgetSettingsProvider @Inject constructor(
|
||||
hideHeader = true,
|
||||
controlledMediaDevices = true,
|
||||
header = HeaderStyle.APP_BAR,
|
||||
sendNotificationType = if (direct) NotificationType.RING else NotificationType.NOTIFICATION,
|
||||
)
|
||||
val rustWidgetSettings = newVirtualElementCallWidget(options)
|
||||
return MatrixWidgetSettings.fromRustWidgetSettings(rustWidgetSettings)
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.impl.fixtures.fakes
|
||||
|
||||
import org.matrix.rustcomponents.sdk.InsertData
|
||||
import org.matrix.rustcomponents.sdk.NoPointer
|
||||
import org.matrix.rustcomponents.sdk.SetData
|
||||
import org.matrix.rustcomponents.sdk.TimelineChange
|
||||
import org.matrix.rustcomponents.sdk.TimelineDiff
|
||||
import org.matrix.rustcomponents.sdk.TimelineItem
|
||||
|
||||
class FakeFfiTimelineDiff(
|
||||
private val change: TimelineChange,
|
||||
private val item: TimelineItem? = FakeFfiTimelineItem()
|
||||
) : TimelineDiff(NoPointer) {
|
||||
override fun change() = change
|
||||
override fun append(): List<TimelineItem>? = item?.let { listOf(it) }
|
||||
override fun insert(): InsertData? = item?.let { InsertData(1u, it) }
|
||||
override fun pushBack(): TimelineItem? = item
|
||||
override fun pushFront(): TimelineItem? = item
|
||||
override fun remove(): UInt? = 1u
|
||||
override fun reset(): List<TimelineItem>? = item?.let { listOf(it) }
|
||||
override fun set(): SetData? = item?.let { SetData(1u, it) }
|
||||
override fun truncate(): UInt? = 1u
|
||||
}
|
||||
@@ -9,7 +9,7 @@ package io.element.android.libraries.matrix.impl.timeline
|
||||
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
|
||||
import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeFfiTimelineDiff
|
||||
import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeFfiTimelineItem
|
||||
import io.element.android.libraries.matrix.impl.timeline.item.event.EventTimelineItemMapper
|
||||
import io.element.android.libraries.matrix.impl.timeline.item.event.TimelineEventContentMapper
|
||||
import io.element.android.libraries.matrix.impl.timeline.item.virtual.VirtualTimelineItemMapper
|
||||
@@ -21,7 +21,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Test
|
||||
import org.matrix.rustcomponents.sdk.TimelineChange
|
||||
import org.matrix.rustcomponents.sdk.TimelineDiff
|
||||
|
||||
class MatrixTimelineDiffProcessorTest {
|
||||
private val timelineItems = MutableStateFlow<List<MatrixTimelineItem>>(emptyList())
|
||||
@@ -33,7 +33,7 @@ class MatrixTimelineDiffProcessorTest {
|
||||
fun `Append adds new entries at the end of the list`() = runTest {
|
||||
timelineItems.value = listOf(anEvent)
|
||||
val processor = createMatrixTimelineDiffProcessor(timelineItems)
|
||||
processor.postDiffs(listOf(FakeFfiTimelineDiff(change = TimelineChange.APPEND)))
|
||||
processor.postDiffs(listOf(TimelineDiff.Append(listOf(FakeFfiTimelineItem()))))
|
||||
assertThat(timelineItems.value.count()).isEqualTo(2)
|
||||
assertThat(timelineItems.value).containsExactly(
|
||||
anEvent,
|
||||
@@ -45,7 +45,7 @@ class MatrixTimelineDiffProcessorTest {
|
||||
fun `PushBack adds a new entry at the end of the list`() = runTest {
|
||||
timelineItems.value = listOf(anEvent)
|
||||
val processor = createMatrixTimelineDiffProcessor(timelineItems)
|
||||
processor.postDiffs(listOf(FakeFfiTimelineDiff(change = TimelineChange.PUSH_BACK)))
|
||||
processor.postDiffs(listOf(TimelineDiff.PushBack(FakeFfiTimelineItem())))
|
||||
assertThat(timelineItems.value.count()).isEqualTo(2)
|
||||
assertThat(timelineItems.value).containsExactly(
|
||||
anEvent,
|
||||
@@ -57,7 +57,7 @@ class MatrixTimelineDiffProcessorTest {
|
||||
fun `PushFront inserts a new entry at the start of the list`() = runTest {
|
||||
timelineItems.value = listOf(anEvent)
|
||||
val processor = createMatrixTimelineDiffProcessor(timelineItems)
|
||||
processor.postDiffs(listOf(FakeFfiTimelineDiff(change = TimelineChange.PUSH_FRONT)))
|
||||
processor.postDiffs(listOf(TimelineDiff.PushFront(FakeFfiTimelineItem())))
|
||||
assertThat(timelineItems.value.count()).isEqualTo(2)
|
||||
assertThat(timelineItems.value).containsExactly(
|
||||
MatrixTimelineItem.Other,
|
||||
@@ -69,7 +69,7 @@ class MatrixTimelineDiffProcessorTest {
|
||||
fun `Set replaces an entry at some index`() = runTest {
|
||||
timelineItems.value = listOf(anEvent, anEvent2)
|
||||
val processor = createMatrixTimelineDiffProcessor(timelineItems)
|
||||
processor.postDiffs(listOf(FakeFfiTimelineDiff(change = TimelineChange.SET)))
|
||||
processor.postDiffs(listOf(TimelineDiff.Set(1u, FakeFfiTimelineItem())))
|
||||
assertThat(timelineItems.value.count()).isEqualTo(2)
|
||||
assertThat(timelineItems.value).containsExactly(
|
||||
anEvent,
|
||||
@@ -81,7 +81,7 @@ class MatrixTimelineDiffProcessorTest {
|
||||
fun `Insert inserts a new entry at the provided index`() = runTest {
|
||||
timelineItems.value = listOf(anEvent, anEvent2)
|
||||
val processor = createMatrixTimelineDiffProcessor(timelineItems)
|
||||
processor.postDiffs(listOf(FakeFfiTimelineDiff(change = TimelineChange.INSERT)))
|
||||
processor.postDiffs(listOf(TimelineDiff.Insert(1u, FakeFfiTimelineItem())))
|
||||
assertThat(timelineItems.value.count()).isEqualTo(3)
|
||||
assertThat(timelineItems.value).containsExactly(
|
||||
anEvent,
|
||||
@@ -94,7 +94,7 @@ class MatrixTimelineDiffProcessorTest {
|
||||
fun `Remove removes an entry at some index`() = runTest {
|
||||
timelineItems.value = listOf(anEvent, MatrixTimelineItem.Other, anEvent2)
|
||||
val processor = createMatrixTimelineDiffProcessor(timelineItems)
|
||||
processor.postDiffs(listOf(FakeFfiTimelineDiff(change = TimelineChange.REMOVE)))
|
||||
processor.postDiffs(listOf(TimelineDiff.Remove(1u)))
|
||||
assertThat(timelineItems.value.count()).isEqualTo(2)
|
||||
assertThat(timelineItems.value).containsExactly(
|
||||
anEvent,
|
||||
@@ -106,7 +106,7 @@ class MatrixTimelineDiffProcessorTest {
|
||||
fun `PopBack removes an entry at the end of the list`() = runTest {
|
||||
timelineItems.value = listOf(anEvent, anEvent2)
|
||||
val processor = createMatrixTimelineDiffProcessor(timelineItems)
|
||||
processor.postDiffs(listOf(FakeFfiTimelineDiff(change = TimelineChange.POP_BACK)))
|
||||
processor.postDiffs(listOf(TimelineDiff.PopBack))
|
||||
assertThat(timelineItems.value.count()).isEqualTo(1)
|
||||
assertThat(timelineItems.value).containsExactly(
|
||||
anEvent,
|
||||
@@ -117,7 +117,7 @@ class MatrixTimelineDiffProcessorTest {
|
||||
fun `PopFront removes an entry at the start of the list`() = runTest {
|
||||
timelineItems.value = listOf(anEvent, anEvent2)
|
||||
val processor = createMatrixTimelineDiffProcessor(timelineItems)
|
||||
processor.postDiffs(listOf(FakeFfiTimelineDiff(change = TimelineChange.POP_FRONT)))
|
||||
processor.postDiffs(listOf(TimelineDiff.PopFront))
|
||||
assertThat(timelineItems.value.count()).isEqualTo(1)
|
||||
assertThat(timelineItems.value).containsExactly(
|
||||
anEvent2,
|
||||
@@ -128,7 +128,7 @@ class MatrixTimelineDiffProcessorTest {
|
||||
fun `Clear removes all the entries`() = runTest {
|
||||
timelineItems.value = listOf(anEvent, anEvent2)
|
||||
val processor = createMatrixTimelineDiffProcessor(timelineItems)
|
||||
processor.postDiffs(listOf(FakeFfiTimelineDiff(change = TimelineChange.CLEAR)))
|
||||
processor.postDiffs(listOf(TimelineDiff.Clear))
|
||||
assertThat(timelineItems.value).isEmpty()
|
||||
}
|
||||
|
||||
@@ -136,7 +136,7 @@ class MatrixTimelineDiffProcessorTest {
|
||||
fun `Truncate removes all entries after the provided length`() = runTest {
|
||||
timelineItems.value = listOf(anEvent, MatrixTimelineItem.Other, anEvent2)
|
||||
val processor = createMatrixTimelineDiffProcessor(timelineItems)
|
||||
processor.postDiffs(listOf(FakeFfiTimelineDiff(change = TimelineChange.TRUNCATE)))
|
||||
processor.postDiffs(listOf(TimelineDiff.Truncate(1u)))
|
||||
assertThat(timelineItems.value.count()).isEqualTo(1)
|
||||
assertThat(timelineItems.value).containsExactly(
|
||||
anEvent,
|
||||
@@ -147,7 +147,7 @@ class MatrixTimelineDiffProcessorTest {
|
||||
fun `Reset removes all entries and add the provided ones`() = runTest {
|
||||
timelineItems.value = listOf(anEvent, MatrixTimelineItem.Other, anEvent2)
|
||||
val processor = createMatrixTimelineDiffProcessor(timelineItems)
|
||||
processor.postDiffs(listOf(FakeFfiTimelineDiff(change = TimelineChange.RESET)))
|
||||
processor.postDiffs(listOf(TimelineDiff.Reset(listOf(FakeFfiTimelineItem()))))
|
||||
assertThat(timelineItems.value.count()).isEqualTo(1)
|
||||
assertThat(timelineItems.value).containsExactly(
|
||||
MatrixTimelineItem.Other,
|
||||
|
||||
@@ -18,7 +18,6 @@ import io.element.android.libraries.matrix.api.timeline.Timeline
|
||||
import io.element.android.libraries.matrix.api.timeline.item.virtual.VirtualTimelineItem
|
||||
import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeFfiRoomListService
|
||||
import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeFfiTimeline
|
||||
import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeFfiTimelineDiff
|
||||
import io.element.android.libraries.matrix.impl.room.RoomContentForwarder
|
||||
import io.element.android.libraries.matrix.test.room.FakeJoinedRoom
|
||||
import io.element.android.libraries.matrix.test.room.aRoomInfo
|
||||
@@ -33,7 +32,7 @@ import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.runCurrent
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Test
|
||||
import org.matrix.rustcomponents.sdk.TimelineChange
|
||||
import org.matrix.rustcomponents.sdk.TimelineDiff
|
||||
import uniffi.matrix_sdk.RoomPaginationStatus
|
||||
import org.matrix.rustcomponents.sdk.Timeline as InnerTimeline
|
||||
|
||||
@@ -51,10 +50,7 @@ class RustTimelineTest {
|
||||
runCurrent()
|
||||
inner.emitDiff(
|
||||
listOf(
|
||||
FakeFfiTimelineDiff(
|
||||
item = null,
|
||||
change = TimelineChange.RESET,
|
||||
)
|
||||
TimelineDiff.Reset(emptyList())
|
||||
)
|
||||
)
|
||||
with(awaitItem()) {
|
||||
|
||||
@@ -12,7 +12,6 @@ import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
|
||||
import io.element.android.libraries.matrix.impl.fixtures.factories.aRustEventTimelineItem
|
||||
import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeFfiTimeline
|
||||
import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeFfiTimelineDiff
|
||||
import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeFfiTimelineItem
|
||||
import io.element.android.tests.testutils.lambda.lambdaError
|
||||
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
||||
@@ -24,7 +23,7 @@ import kotlinx.coroutines.test.runCurrent
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Test
|
||||
import org.matrix.rustcomponents.sdk.Timeline
|
||||
import org.matrix.rustcomponents.sdk.TimelineChange
|
||||
import org.matrix.rustcomponents.sdk.TimelineDiff
|
||||
import uniffi.matrix_sdk_ui.EventItemOrigin
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@@ -42,7 +41,7 @@ class TimelineItemsSubscriberTest {
|
||||
timelineItemsSubscriber.subscribeIfNeeded()
|
||||
// Wait for the listener to be set.
|
||||
runCurrent()
|
||||
timeline.emitDiff(listOf(FakeFfiTimelineDiff(item = null, change = TimelineChange.RESET)))
|
||||
timeline.emitDiff(listOf(TimelineDiff.Reset(emptyList())))
|
||||
val final = awaitItem()
|
||||
assertThat(final).isEmpty()
|
||||
timelineItemsSubscriber.unsubscribeIfNeeded()
|
||||
@@ -62,7 +61,7 @@ class TimelineItemsSubscriberTest {
|
||||
timelineItemsSubscriber.subscribeIfNeeded()
|
||||
// Wait for the listener to be set.
|
||||
runCurrent()
|
||||
timeline.emitDiff(listOf(FakeFfiTimelineDiff(item = FakeFfiTimelineItem(), change = TimelineChange.RESET)))
|
||||
timeline.emitDiff(listOf(TimelineDiff.Reset(listOf(FakeFfiTimelineItem()))))
|
||||
val final = awaitItem()
|
||||
assertThat(final).isNotEmpty()
|
||||
timelineItemsSubscriber.unsubscribeIfNeeded()
|
||||
@@ -86,11 +85,10 @@ class TimelineItemsSubscriberTest {
|
||||
runCurrent()
|
||||
timeline.emitDiff(
|
||||
listOf(
|
||||
FakeFfiTimelineDiff(
|
||||
item = FakeFfiTimelineItem(
|
||||
TimelineDiff.Reset(
|
||||
listOf(FakeFfiTimelineItem(
|
||||
asEventResult = aRustEventTimelineItem(origin = EventItemOrigin.SYNC),
|
||||
),
|
||||
change = TimelineChange.RESET,
|
||||
))
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
@@ -55,7 +55,6 @@ class FakeJoinedRoom(
|
||||
private val roomNotificationSettingsService: FakeNotificationSettingsService = FakeNotificationSettingsService(),
|
||||
private var createTimelineResult: (CreateTimelineParams) -> Result<Timeline> = { lambdaError() },
|
||||
private val editMessageLambda: (EventId, String, String?, List<IntentionalMention>) -> Result<Unit> = { _, _, _, _ -> lambdaError() },
|
||||
private val sendCallNotificationIfNeededResult: () -> Result<Boolean> = { lambdaError() },
|
||||
private val progressCallbackValues: List<Pair<Long, Long>> = emptyList(),
|
||||
private val generateWidgetWebViewUrlResult: (MatrixWidgetSettings, String, String?, String?) -> Result<String> = { _, _, _, _ -> lambdaError() },
|
||||
private val getWidgetDriverResult: (MatrixWidgetSettings) -> Result<MatrixWidgetDriver> = { lambdaError() },
|
||||
@@ -207,10 +206,6 @@ class FakeJoinedRoom(
|
||||
return getWidgetDriverResult(widgetSettings)
|
||||
}
|
||||
|
||||
override suspend fun sendCallNotificationIfNeeded(): Result<Boolean> = simulateLongTask {
|
||||
sendCallNotificationIfNeededResult()
|
||||
}
|
||||
|
||||
override suspend fun setSendQueueEnabled(enabled: Boolean) = simulateLongTask {
|
||||
setSendQueueEnabledResult(enabled)
|
||||
}
|
||||
|
||||
@@ -11,12 +11,12 @@ import io.element.android.libraries.matrix.api.widget.CallWidgetSettingsProvider
|
||||
import io.element.android.libraries.matrix.api.widget.MatrixWidgetSettings
|
||||
|
||||
class FakeCallWidgetSettingsProvider(
|
||||
private val provideFn: (String, String) -> MatrixWidgetSettings = { _, _ -> MatrixWidgetSettings("id", true, "url") }
|
||||
private val provideFn: (String, String, Boolean, Boolean) -> MatrixWidgetSettings = { _, _, _, _ -> MatrixWidgetSettings("id", true, "url") }
|
||||
) : CallWidgetSettingsProvider {
|
||||
val providedBaseUrls = mutableListOf<String>()
|
||||
|
||||
override suspend fun provide(baseUrl: String, widgetId: String, encrypted: Boolean): MatrixWidgetSettings {
|
||||
override suspend fun provide(baseUrl: String, widgetId: String, encrypted: Boolean, direct: Boolean): MatrixWidgetSettings {
|
||||
providedBaseUrls += baseUrl
|
||||
return provideFn(baseUrl, widgetId)
|
||||
return provideFn(baseUrl, widgetId, encrypted, direct)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user