Merge branch 'develop' into feature/fga/fix_room_list_scroll_position
This commit is contained in:
@@ -139,7 +139,9 @@ class LoggedInFlowNode @AssistedInject constructor(
|
||||
}
|
||||
},
|
||||
onResume = {
|
||||
syncService.startSync()
|
||||
lifecycleScope.launch {
|
||||
syncService.startSync()
|
||||
}
|
||||
},
|
||||
onPause = {
|
||||
syncService.stopSync()
|
||||
|
||||
@@ -139,7 +139,7 @@ class InviteListPresenter @Inject constructor(
|
||||
private fun CoroutineScope.acceptInvite(roomId: RoomId, acceptedAction: MutableState<Async<RoomId>>) = launch {
|
||||
suspend {
|
||||
client.getRoom(roomId)?.use {
|
||||
it.acceptInvitation().getOrThrow()
|
||||
it.join().getOrThrow()
|
||||
notificationDrawerManager.clearMembershipNotificationForRoom(client.sessionId, roomId)
|
||||
analyticsService.capture(it.toAnalyticsJoinedRoom(JoinedRoom.Trigger.Invite))
|
||||
}
|
||||
@@ -150,7 +150,7 @@ class InviteListPresenter @Inject constructor(
|
||||
private fun CoroutineScope.declineInvite(roomId: RoomId, declinedAction: MutableState<Async<Unit>>) = launch {
|
||||
suspend {
|
||||
client.getRoom(roomId)?.use {
|
||||
it.rejectInvitation().getOrThrow()
|
||||
it.leave().getOrThrow()
|
||||
notificationDrawerManager.clearMembershipNotificationForRoom(client.sessionId, roomId)
|
||||
}
|
||||
Unit
|
||||
|
||||
@@ -211,7 +211,6 @@ class InviteListPresenterTests {
|
||||
|
||||
skipItems(2)
|
||||
|
||||
Truth.assertThat(room.isInviteRejected).isTrue()
|
||||
Truth.assertThat(fakeNotificationDrawerManager.getClearMembershipNotificationForRoomCount(client.sessionId, A_ROOM_ID)).isEqualTo(1)
|
||||
}
|
||||
}
|
||||
@@ -225,7 +224,7 @@ class InviteListPresenterTests {
|
||||
val room = FakeMatrixRoom()
|
||||
val presenter = createPresenter(client)
|
||||
val ex = Throwable("Ruh roh!")
|
||||
room.givenRejectInviteResult(Result.failure(ex))
|
||||
room.givenLeaveRoomError(ex)
|
||||
client.givenGetRoomResult(A_ROOM_ID, room)
|
||||
|
||||
moleculeFlow(RecompositionClock.Immediate) {
|
||||
@@ -242,7 +241,6 @@ class InviteListPresenterTests {
|
||||
|
||||
val newState = awaitItem()
|
||||
|
||||
Truth.assertThat(room.isInviteRejected).isTrue()
|
||||
Truth.assertThat(newState.declinedAction).isEqualTo(Async.Failure<Unit>(ex))
|
||||
}
|
||||
}
|
||||
@@ -256,7 +254,7 @@ class InviteListPresenterTests {
|
||||
val room = FakeMatrixRoom()
|
||||
val presenter = createPresenter(client)
|
||||
val ex = Throwable("Ruh roh!")
|
||||
room.givenRejectInviteResult(Result.failure(ex))
|
||||
room.givenLeaveRoomError(ex)
|
||||
client.givenGetRoomResult(A_ROOM_ID, room)
|
||||
|
||||
moleculeFlow(RecompositionClock.Immediate) {
|
||||
@@ -298,7 +296,6 @@ class InviteListPresenterTests {
|
||||
|
||||
val newState = awaitItem()
|
||||
|
||||
Truth.assertThat(room.isInviteAccepted).isTrue()
|
||||
Truth.assertThat(newState.acceptedAction).isEqualTo(Async.Success(A_ROOM_ID))
|
||||
Truth.assertThat(fakeNotificationDrawerManager.getClearMembershipNotificationForRoomCount(client.sessionId, A_ROOM_ID)).isEqualTo(1)
|
||||
}
|
||||
@@ -313,7 +310,7 @@ class InviteListPresenterTests {
|
||||
val room = FakeMatrixRoom()
|
||||
val presenter = createPresenter(client)
|
||||
val ex = Throwable("Ruh roh!")
|
||||
room.givenAcceptInviteResult(Result.failure(ex))
|
||||
room.givenJoinRoomResult(Result.failure(ex))
|
||||
client.givenGetRoomResult(A_ROOM_ID, room)
|
||||
|
||||
moleculeFlow(RecompositionClock.Immediate) {
|
||||
@@ -322,10 +319,7 @@ class InviteListPresenterTests {
|
||||
val originalState = awaitItem()
|
||||
originalState.eventSink(InviteListEvents.AcceptInvite(originalState.inviteList[0]))
|
||||
|
||||
val newState = awaitItem()
|
||||
|
||||
Truth.assertThat(room.isInviteAccepted).isTrue()
|
||||
Truth.assertThat(newState.acceptedAction).isEqualTo(Async.Failure<RoomId>(ex))
|
||||
Truth.assertThat(awaitItem().acceptedAction).isEqualTo(Async.Failure<RoomId>(ex))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -338,7 +332,7 @@ class InviteListPresenterTests {
|
||||
val room = FakeMatrixRoom()
|
||||
val presenter = createPresenter(client)
|
||||
val ex = Throwable("Ruh roh!")
|
||||
room.givenAcceptInviteResult(Result.failure(ex))
|
||||
room.givenJoinRoomResult(Result.failure(ex))
|
||||
client.givenGetRoomResult(A_ROOM_ID, room)
|
||||
|
||||
moleculeFlow(RecompositionClock.Immediate) {
|
||||
|
||||
@@ -51,8 +51,8 @@ import io.element.android.libraries.theme.ElementTheme
|
||||
private val BUBBLE_RADIUS = 12.dp
|
||||
private val BUBBLE_INCOMING_OFFSET = 16.dp
|
||||
|
||||
// Design says: The maximum width of a bubble is still 3/4 of the screen width
|
||||
private const val BUBBLE_WIDTH_RATIO = 0.75f
|
||||
// Design says: The maximum width of a bubble is still 3/4 of the screen width. But try with 85% now.
|
||||
private const val BUBBLE_WIDTH_RATIO = 0.85f
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
|
||||
@@ -145,7 +145,7 @@ jsoup = { module = "org.jsoup:jsoup", version.ref = "jsoup" }
|
||||
appyx_core = { module = "com.bumble.appyx:core", version.ref = "appyx" }
|
||||
molecule-runtime = { module = "app.cash.molecule:molecule-runtime", version.ref = "molecule" }
|
||||
timber = "com.jakewharton.timber:timber:5.0.1"
|
||||
matrix_sdk = "org.matrix.rustcomponents:sdk-android:0.1.31"
|
||||
matrix_sdk = "org.matrix.rustcomponents:sdk-android:0.1.34"
|
||||
sqldelight-driver-android = { module = "com.squareup.sqldelight:android-driver", version.ref = "sqldelight" }
|
||||
sqldelight-driver-jvm = { module = "com.squareup.sqldelight:sqlite-driver", version.ref = "sqldelight" }
|
||||
sqldelight-coroutines = { module = "com.squareup.sqldelight:coroutines-extensions", version.ref = "sqldelight" }
|
||||
|
||||
@@ -95,9 +95,7 @@ interface MatrixRoom : Closeable {
|
||||
|
||||
suspend fun leave(): Result<Unit>
|
||||
|
||||
suspend fun acceptInvitation(): Result<Unit>
|
||||
|
||||
suspend fun rejectInvitation(): Result<Unit>
|
||||
suspend fun join(): Result<Unit>
|
||||
|
||||
suspend fun inviteUserById(id: UserId): Result<Unit>
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ interface SyncService {
|
||||
/**
|
||||
* Tries to start the sync. If already syncing it has no effect.
|
||||
*/
|
||||
fun startSync(): Result<Unit>
|
||||
suspend fun startSync(): Result<Unit>
|
||||
|
||||
/**
|
||||
* Tries to stop the sync. If service is not syncing it has no effect.
|
||||
|
||||
@@ -73,10 +73,12 @@ import java.io.File
|
||||
import org.matrix.rustcomponents.sdk.CreateRoomParameters as RustCreateRoomParameters
|
||||
import org.matrix.rustcomponents.sdk.RoomPreset as RustRoomPreset
|
||||
import org.matrix.rustcomponents.sdk.RoomVisibility as RustRoomVisibility
|
||||
import org.matrix.rustcomponents.sdk.SyncService as ClientSyncService
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
class RustMatrixClient constructor(
|
||||
private val client: Client,
|
||||
private val syncService: ClientSyncService,
|
||||
private val sessionStore: SessionStore,
|
||||
appCoroutineScope: CoroutineScope,
|
||||
private val dispatchers: CoroutineDispatchers,
|
||||
@@ -86,14 +88,11 @@ class RustMatrixClient constructor(
|
||||
) : MatrixClient {
|
||||
|
||||
override val sessionId: UserId = UserId(client.userId())
|
||||
private val app = client.app().use { builder ->
|
||||
builder.finish()
|
||||
}
|
||||
private val roomListService = app.roomListService()
|
||||
private val roomListService = syncService.roomListService()
|
||||
private val sessionDispatcher = dispatchers.io.limitedParallelism(64)
|
||||
private val sessionCoroutineScope = appCoroutineScope.childScope(dispatchers.main, "Session-${sessionId}")
|
||||
private val verificationService = RustSessionVerificationService()
|
||||
private val syncService = RustSyncService(app, roomListService.stateFlow(), sessionCoroutineScope)
|
||||
private val rustSyncService = RustSyncService(syncService, roomListService.stateFlow(), sessionCoroutineScope)
|
||||
private val pushersService = RustPushersService(
|
||||
client = client,
|
||||
dispatchers = dispatchers,
|
||||
@@ -131,7 +130,7 @@ class RustMatrixClient constructor(
|
||||
|
||||
init {
|
||||
client.setDelegate(clientDelegate)
|
||||
syncService.syncState
|
||||
rustSyncService.syncState
|
||||
.onEach { syncState ->
|
||||
if (syncState == SyncState.Syncing) {
|
||||
onSlidingSyncUpdate()
|
||||
@@ -247,7 +246,7 @@ class RustMatrixClient constructor(
|
||||
}
|
||||
}
|
||||
|
||||
override fun syncService(): SyncService = syncService
|
||||
override fun syncService(): SyncService = rustSyncService
|
||||
|
||||
override fun sessionVerificationService(): SessionVerificationService = verificationService
|
||||
|
||||
@@ -259,7 +258,7 @@ class RustMatrixClient constructor(
|
||||
sessionCoroutineScope.cancel()
|
||||
client.setDelegate(null)
|
||||
verificationService.destroy()
|
||||
app.destroy()
|
||||
syncService.destroy()
|
||||
roomListService.destroy()
|
||||
notificationClient.destroy()
|
||||
client.destroy()
|
||||
|
||||
@@ -181,9 +181,11 @@ class RustMatrixAuthenticationService @Inject constructor(
|
||||
*/
|
||||
}
|
||||
|
||||
private fun createMatrixClient(client: Client): MatrixClient {
|
||||
private suspend fun createMatrixClient(client: Client): MatrixClient {
|
||||
val syncService = client.syncService().finish()
|
||||
return RustMatrixClient(
|
||||
client = client,
|
||||
syncService = syncService,
|
||||
sessionStore = sessionStore,
|
||||
appCoroutineScope = appCoroutineScope,
|
||||
dispatchers = coroutineDispatchers,
|
||||
|
||||
@@ -43,7 +43,6 @@ import io.element.android.libraries.matrix.impl.timeline.RustMatrixTimeline
|
||||
import io.element.android.libraries.matrix.impl.timeline.backPaginationStatusFlow
|
||||
import io.element.android.libraries.matrix.impl.timeline.timelineDiffFlow
|
||||
import io.element.android.libraries.sessionstorage.api.SessionData
|
||||
import io.element.android.libraries.sessionstorage.api.SessionStore
|
||||
import io.element.android.services.toolbox.api.systemclock.SystemClock
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
@@ -82,6 +81,7 @@ class RustMatrixRoom(
|
||||
|
||||
// Create a dispatcher for all room methods...
|
||||
private val roomDispatcher = coroutineDispatchers.io.limitedParallelism(32)
|
||||
|
||||
//...except getMember methods as it could quickly fill the roomDispatcher...
|
||||
private val roomMembersDispatcher = coroutineDispatchers.io.limitedParallelism(8)
|
||||
|
||||
@@ -257,15 +257,9 @@ class RustMatrixRoom(
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun acceptInvitation(): Result<Unit> = withContext(roomDispatcher) {
|
||||
override suspend fun join(): Result<Unit> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.acceptInvitation()
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun rejectInvitation(): Result<Unit> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.rejectInvitation()
|
||||
innerRoom.join()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
package io.element.android.libraries.matrix.impl.sync
|
||||
|
||||
import io.element.android.libraries.matrix.api.sync.SyncState
|
||||
import org.matrix.rustcomponents.sdk.AppState
|
||||
import org.matrix.rustcomponents.sdk.RoomListServiceState
|
||||
import org.matrix.rustcomponents.sdk.SyncServiceState
|
||||
|
||||
internal fun RoomListServiceState.toSyncState(): SyncState {
|
||||
return when (this) {
|
||||
@@ -30,10 +30,11 @@ internal fun RoomListServiceState.toSyncState(): SyncState {
|
||||
}
|
||||
}
|
||||
|
||||
internal fun AppState.toSyncState(): SyncState {
|
||||
internal fun SyncServiceState.toSyncState(): SyncState {
|
||||
return when (this) {
|
||||
AppState.RUNNING -> SyncState.Syncing
|
||||
AppState.TERMINATED -> SyncState.Terminated
|
||||
AppState.ERROR -> SyncState.InError
|
||||
SyncServiceState.IDLE -> SyncState.Idle
|
||||
SyncServiceState.RUNNING -> SyncState.Syncing
|
||||
SyncServiceState.TERMINATED -> SyncState.Terminated
|
||||
SyncServiceState.ERROR -> SyncState.InError
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,24 +26,24 @@ import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import org.matrix.rustcomponents.sdk.App
|
||||
import org.matrix.rustcomponents.sdk.RoomListServiceState
|
||||
import org.matrix.rustcomponents.sdk.SyncServiceInterface
|
||||
import timber.log.Timber
|
||||
|
||||
class RustSyncService(
|
||||
private val app: App,
|
||||
private val innerSyncService: SyncServiceInterface,
|
||||
roomListStateFlow: Flow<RoomListServiceState>,
|
||||
sessionCoroutineScope: CoroutineScope
|
||||
) : SyncService {
|
||||
|
||||
override fun startSync() = runCatching {
|
||||
override suspend fun startSync() = runCatching {
|
||||
Timber.v("Start sync")
|
||||
app.start()
|
||||
innerSyncService.start()
|
||||
}
|
||||
|
||||
override fun stopSync() = runCatching {
|
||||
Timber.v("Stop sync")
|
||||
app.pause()
|
||||
innerSyncService.pause()
|
||||
}
|
||||
|
||||
override val syncState: StateFlow<SyncState> =
|
||||
|
||||
@@ -21,14 +21,14 @@ import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.channels.trySendBlocking
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.buffer
|
||||
import org.matrix.rustcomponents.sdk.App
|
||||
import org.matrix.rustcomponents.sdk.AppState
|
||||
import org.matrix.rustcomponents.sdk.AppStateObserver
|
||||
import org.matrix.rustcomponents.sdk.SyncService
|
||||
import org.matrix.rustcomponents.sdk.SyncServiceState
|
||||
import org.matrix.rustcomponents.sdk.SyncServiceStateObserver
|
||||
|
||||
fun App.stateFlow(): Flow<AppState> =
|
||||
fun SyncService.stateFlow(): Flow<SyncServiceState> =
|
||||
mxCallbackFlow {
|
||||
val listener = object : AppStateObserver {
|
||||
override fun onUpdate(state: AppState) {
|
||||
val listener = object : SyncServiceStateObserver {
|
||||
override fun onUpdate(state: SyncServiceState) {
|
||||
trySendBlocking(state)
|
||||
}
|
||||
}
|
||||
@@ -63,8 +63,7 @@ class FakeMatrixRoom(
|
||||
private var userDisplayNameResult = Result.success<String?>(null)
|
||||
private var userAvatarUrlResult = Result.success<String?>(null)
|
||||
private var updateMembersResult: Result<Unit> = Result.success(Unit)
|
||||
private var acceptInviteResult = Result.success(Unit)
|
||||
private var rejectInviteResult = Result.success(Unit)
|
||||
private var joinRoomResult = Result.success(Unit)
|
||||
private var inviteUserResult = Result.success(Unit)
|
||||
private var canInviteResult = Result.success(true)
|
||||
private val canSendStateResults = mutableMapOf<StateEventType, Result<Boolean>>()
|
||||
@@ -101,11 +100,6 @@ class FakeMatrixRoom(
|
||||
var sendLocationCount: Int = 0
|
||||
private set
|
||||
|
||||
var isInviteAccepted: Boolean = false
|
||||
private set
|
||||
|
||||
var isInviteRejected: Boolean = false
|
||||
private set
|
||||
|
||||
var invitedUserId: UserId? = null
|
||||
private set
|
||||
@@ -196,16 +190,11 @@ class FakeMatrixRoom(
|
||||
return Result.success(Unit)
|
||||
}
|
||||
|
||||
override suspend fun leave(): Result<Unit> = leaveRoomError?.let { Result.failure(it) } ?: Result.success(Unit)
|
||||
override suspend fun leave(): Result<Unit> =
|
||||
leaveRoomError?.let { Result.failure(it) } ?: Result.success(Unit)
|
||||
|
||||
override suspend fun acceptInvitation(): Result<Unit> {
|
||||
isInviteAccepted = true
|
||||
return acceptInviteResult
|
||||
}
|
||||
|
||||
override suspend fun rejectInvitation(): Result<Unit> {
|
||||
isInviteRejected = true
|
||||
return rejectInviteResult
|
||||
override suspend fun join(): Result<Unit> {
|
||||
return joinRoomResult
|
||||
}
|
||||
|
||||
override suspend fun inviteUserById(id: UserId): Result<Unit> = simulateLongTask {
|
||||
@@ -316,12 +305,8 @@ class FakeMatrixRoom(
|
||||
userAvatarUrlResult = avatarUrl
|
||||
}
|
||||
|
||||
fun givenAcceptInviteResult(result: Result<Unit>) {
|
||||
acceptInviteResult = result
|
||||
}
|
||||
|
||||
fun givenRejectInviteResult(result: Result<Unit>) {
|
||||
rejectInviteResult = result
|
||||
fun givenJoinRoomResult(result: Result<Unit>) {
|
||||
joinRoomResult = result
|
||||
}
|
||||
|
||||
fun givenInviteUserResult(result: Result<Unit>) {
|
||||
|
||||
@@ -29,7 +29,7 @@ class FakeSyncService : SyncService {
|
||||
syncStateFlow.value = SyncState.InError
|
||||
}
|
||||
|
||||
override fun startSync(): Result<Unit> {
|
||||
override suspend fun startSync(): Result<Unit> {
|
||||
syncStateFlow.value = SyncState.Syncing
|
||||
return Result.success(Unit)
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
|
||||
import io.element.android.services.toolbox.impl.strings.AndroidStringProvider
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.datetime.Clock
|
||||
import kotlinx.datetime.TimeZone
|
||||
@@ -108,7 +109,9 @@ class RoomListScreen(
|
||||
|
||||
DisposableEffect(Unit) {
|
||||
Timber.w("Start sync!")
|
||||
matrixClient.syncService().startSync()
|
||||
runBlocking {
|
||||
matrixClient.syncService().startSync()
|
||||
}
|
||||
onDispose {
|
||||
Timber.w("Stop sync!")
|
||||
matrixClient.syncService().stopSync()
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user