From 63a84dcb8a03d1e45ac28f5d7637e67df3b4515d Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 17 Sep 2021 17:56:21 +0200 Subject: [PATCH] Add incremental sync status to the room list and the room detail (only in developer mode) --- .../initsync/InitialSyncProgressService.kt | 7 ++++ .../DefaultInitialSyncProgressService.kt | 5 +++ .../sdk/internal/session/sync/SyncTask.kt | 4 ++ .../vector/app/features/home/HomeActivity.kt | 5 ++- .../features/home/HomeActivityViewModel.kt | 1 + .../app/features/home/HomeDetailFragment.kt | 2 +- .../app/features/home/HomeDetailViewModel.kt | 14 ++++++- .../app/features/home/HomeDetailViewState.kt | 2 + .../home/room/detail/RoomDetailFragment.kt | 7 +++- .../home/room/detail/RoomDetailViewModel.kt | 13 +++++++ .../home/room/detail/RoomDetailViewState.kt | 2 + .../app/features/sync/widget/SyncStateView.kt | 39 +++++++++++++++++-- .../src/main/res/layout/view_sync_state.xml | 9 +++++ 13 files changed, 100 insertions(+), 10 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/initsync/InitialSyncProgressService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/initsync/InitialSyncProgressService.kt index b5d4ef4dbb..54f515be57 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/initsync/InitialSyncProgressService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/initsync/InitialSyncProgressService.kt @@ -17,6 +17,7 @@ package org.matrix.android.sdk.api.session.initsync import androidx.lifecycle.LiveData +// TODO Rename or since we also observe classical sync here interface InitialSyncProgressService { fun getInitialSyncProgressStatus(): LiveData @@ -27,5 +28,11 @@ interface InitialSyncProgressService { val initSyncStep: InitSyncStep, val percentProgress: Int = 0 ) : Status() + + abstract class IncrementalSyncStatus: Status() + + object IncrementalSyncIdle : IncrementalSyncStatus() + object IncrementalSyncParsing : IncrementalSyncStatus() + object IncrementalSyncDone : IncrementalSyncStatus() } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/initsync/DefaultInitialSyncProgressService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/initsync/DefaultInitialSyncProgressService.kt index eb3e3066b1..3856d6de60 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/initsync/DefaultInitialSyncProgressService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/initsync/DefaultInitialSyncProgressService.kt @@ -35,6 +35,11 @@ internal class DefaultInitialSyncProgressService @Inject constructor() return status } + // Only to be used for incremental sync + fun setStatus(newStatus: InitialSyncProgressService.Status) { + status.postValue(newStatus) + } + /** * Create a rootTask */ diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncTask.kt index c80fbe60c1..656d22b06a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncTask.kt @@ -18,6 +18,7 @@ package org.matrix.android.sdk.internal.session.sync import okhttp3.ResponseBody import org.matrix.android.sdk.api.session.initsync.InitSyncStep +import org.matrix.android.sdk.api.session.initsync.InitialSyncProgressService import org.matrix.android.sdk.internal.di.SessionFilesDirectory import org.matrix.android.sdk.internal.di.UserId import org.matrix.android.sdk.internal.network.GlobalErrorReceiver @@ -129,13 +130,16 @@ internal class DefaultSyncTask @Inject constructor( } initialSyncProgressService.endAll() } else { + initialSyncProgressService.setStatus(InitialSyncProgressService.Status.IncrementalSyncIdle) val syncResponse = executeRequest(globalErrorReceiver) { syncAPI.sync( params = requestParams, readTimeOut = readTimeOut ) } + initialSyncProgressService.setStatus(InitialSyncProgressService.Status.IncrementalSyncParsing) syncResponseHandler.handleResponse(syncResponse, token, null) + initialSyncProgressService.setStatus(InitialSyncProgressService.Status.IncrementalSyncDone) } Timber.v("Sync task finished on Thread: ${Thread.currentThread().name}") } diff --git a/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt b/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt index 51d6ed79db..05730a9414 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt @@ -309,10 +309,10 @@ class HomeActivity : private fun renderState(state: HomeActivityViewState) { when (val status = state.initialSyncProgressServiceStatus) { - is InitialSyncProgressService.Status.Idle -> { + is InitialSyncProgressService.Status.Idle -> { views.waitingView.root.isVisible = false } - is InitialSyncProgressService.Status.Progressing -> { + is InitialSyncProgressService.Status.Progressing -> { val initSyncStepStr = initSyncStepFormatter.format(status.initSyncStep) Timber.v("$initSyncStepStr ${status.percentProgress}") views.waitingView.root.setOnClickListener { @@ -330,6 +330,7 @@ class HomeActivity : } views.waitingView.root.isVisible = true } + is InitialSyncProgressService.Status.IncrementalSyncStatus -> Unit }.exhaustive } diff --git a/vector/src/main/java/im/vector/app/features/home/HomeActivityViewModel.kt b/vector/src/main/java/im/vector/app/features/home/HomeActivityViewModel.kt index bfedbd6f52..b2da4587c2 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeActivityViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeActivityViewModel.kt @@ -136,6 +136,7 @@ class HomeActivityViewModel @AssistedInject constructor( maybeBootstrapCrossSigningAfterInitialSync() } } + else -> Unit } setState { diff --git a/vector/src/main/java/im/vector/app/features/home/HomeDetailFragment.kt b/vector/src/main/java/im/vector/app/features/home/HomeDetailFragment.kt index 95430746a4..ca7a673172 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeDetailFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeDetailFragment.kt @@ -440,7 +440,7 @@ class HomeDetailFragment @Inject constructor( views.bottomNavigationView.getOrCreateBadge(R.id.bottom_action_people).render(it.notificationCountPeople, it.notificationHighlightPeople) views.bottomNavigationView.getOrCreateBadge(R.id.bottom_action_rooms).render(it.notificationCountRooms, it.notificationHighlightRooms) views.bottomNavigationView.getOrCreateBadge(R.id.bottom_action_notification).render(it.notificationCountCatchup, it.notificationHighlightCatchup) - views.syncStateView.render(it.syncState) + views.syncStateView.render(it.syncState, it.incrementalSyncStatus, vectorPreferences.developerMode()) hasUnreadRooms = it.hasUnreadMessages } diff --git a/vector/src/main/java/im/vector/app/features/home/HomeDetailViewModel.kt b/vector/src/main/java/im/vector/app/features/home/HomeDetailViewModel.kt index b960402f90..fbc006bbcd 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeDetailViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeDetailViewModel.kt @@ -40,6 +40,7 @@ import kotlinx.coroutines.launch import org.matrix.android.sdk.api.query.ActiveSpaceFilter import org.matrix.android.sdk.api.query.RoomCategoryFilter import org.matrix.android.sdk.api.session.Session +import org.matrix.android.sdk.api.session.initsync.InitialSyncProgressService import org.matrix.android.sdk.api.session.room.RoomSortOrder import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams @@ -59,7 +60,7 @@ class HomeDetailViewModel @AssistedInject constructor(@Assisted initialState: Ho private val callManager: WebRtcCallManager, private val directRoomHelper: DirectRoomHelper, private val appStateHandler: AppStateHandler, -private val autoAcceptInvites: AutoAcceptInvites) + private val autoAcceptInvites: AutoAcceptInvites) : VectorViewModel(initialState), CallProtocolsChecker.Listener { @@ -173,6 +174,17 @@ private val autoAcceptInvites: AutoAcceptInvites) } } .disposeOnClear() + + session.getInitialSyncProgressStatus() + .asObservable() + .subscribe { + if (it is InitialSyncProgressService.Status.IncrementalSyncStatus) { + setState { + copy(incrementalSyncStatus = it) + } + } + } + .disposeOnClear() } private fun observeRoomGroupingMethod() { diff --git a/vector/src/main/java/im/vector/app/features/home/HomeDetailViewState.kt b/vector/src/main/java/im/vector/app/features/home/HomeDetailViewState.kt index 304444abdd..9932758dc0 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeDetailViewState.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeDetailViewState.kt @@ -22,6 +22,7 @@ import com.airbnb.mvrx.MvRxState import com.airbnb.mvrx.Uninitialized import im.vector.app.R import im.vector.app.RoomGroupingMethod +import org.matrix.android.sdk.api.session.initsync.InitialSyncProgressService import org.matrix.android.sdk.api.session.room.model.RoomSummary import org.matrix.android.sdk.api.session.sync.SyncState import org.matrix.android.sdk.api.util.MatrixItem @@ -39,6 +40,7 @@ data class HomeDetailViewState( val notificationHighlightRooms: Boolean = false, val hasUnreadMessages: Boolean = false, val syncState: SyncState = SyncState.Idle, + val incrementalSyncStatus: InitialSyncProgressService.Status.IncrementalSyncStatus = InitialSyncProgressService.Status.IncrementalSyncIdle, val showDialPadTab: Boolean = false ) : MvRxState diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt index 287ff70dde..4bec83f269 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt @@ -387,8 +387,11 @@ class RoomDetailFragment @Inject constructor( } } - roomDetailViewModel.selectSubscribe(RoomDetailViewState::syncState) { syncState -> - views.syncStateView.render(syncState) + roomDetailViewModel.selectSubscribe( + RoomDetailViewState::syncState, + RoomDetailViewState::incrementalSyncStatus + ) { syncState, incrementalSyncStatus -> + views.syncStateView.render(syncState, incrementalSyncStatus, vectorPreferences.developerMode()) } roomDetailViewModel.observeViewEvents { diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt index 5ea5e81240..6d396adafa 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt @@ -80,6 +80,7 @@ import org.matrix.android.sdk.api.session.events.model.isTextMessage import org.matrix.android.sdk.api.session.events.model.toContent import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.file.FileService +import org.matrix.android.sdk.api.session.initsync.InitialSyncProgressService import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState import org.matrix.android.sdk.api.session.room.members.roomMemberQueryParams import org.matrix.android.sdk.api.session.room.model.Membership @@ -102,6 +103,7 @@ import org.matrix.android.sdk.api.session.space.CreateSpaceParams import org.matrix.android.sdk.api.session.widgets.model.WidgetType import org.matrix.android.sdk.api.util.toOptional import org.matrix.android.sdk.internal.crypto.model.event.WithHeldCode +import org.matrix.android.sdk.rx.asObservable import org.matrix.android.sdk.rx.rx import org.matrix.android.sdk.rx.unwrap import timber.log.Timber @@ -1493,6 +1495,17 @@ class RoomDetailViewModel @AssistedInject constructor( } } .disposeOnClear() + + session.getInitialSyncProgressStatus() + .asObservable() + .subscribe { it -> + if(it is InitialSyncProgressService.Status.IncrementalSyncStatus) { + setState { + copy(incrementalSyncStatus = it) + } + } + } + .disposeOnClear() } private fun observeRoomSummary() { diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewState.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewState.kt index 1c75429d11..421ef5165f 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewState.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewState.kt @@ -21,6 +21,7 @@ import com.airbnb.mvrx.MvRxState import com.airbnb.mvrx.Uninitialized import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.session.events.model.Event +import org.matrix.android.sdk.api.session.initsync.InitialSyncProgressService import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary import org.matrix.android.sdk.api.session.room.model.RoomSummary @@ -77,6 +78,7 @@ data class RoomDetailViewState( val tombstoneEvent: Event? = null, val joinUpgradedRoomAsync: Async = Uninitialized, val syncState: SyncState = SyncState.Idle, + val incrementalSyncStatus: InitialSyncProgressService.Status.IncrementalSyncStatus = InitialSyncProgressService.Status.IncrementalSyncIdle, val highlightedEventId: String? = null, val unreadState: UnreadState = UnreadState.Unknown, val canShowJumpToReadMarker: Boolean = true, diff --git a/vector/src/main/java/im/vector/app/features/sync/widget/SyncStateView.kt b/vector/src/main/java/im/vector/app/features/sync/widget/SyncStateView.kt index ff1da2f8f0..431acb682f 100755 --- a/vector/src/main/java/im/vector/app/features/sync/widget/SyncStateView.kt +++ b/vector/src/main/java/im/vector/app/features/sync/widget/SyncStateView.kt @@ -16,27 +16,37 @@ package im.vector.app.features.sync.widget +import android.annotation.SuppressLint import android.content.Context import android.util.AttributeSet -import android.widget.FrameLayout +import android.widget.LinearLayout import androidx.core.view.isVisible import im.vector.app.R import im.vector.app.core.utils.isAirplaneModeOn import im.vector.app.databinding.ViewSyncStateBinding - +import org.matrix.android.sdk.api.session.initsync.InitialSyncProgressService import org.matrix.android.sdk.api.session.sync.SyncState class SyncStateView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0) - : FrameLayout(context, attrs, defStyle) { + : LinearLayout(context, attrs, defStyle) { private val views: ViewSyncStateBinding init { inflate(context, R.layout.view_sync_state, this) views = ViewSyncStateBinding.bind(this) + orientation = VERTICAL } - fun render(newState: SyncState) { + @SuppressLint("SetTextI18n") + fun render(newState: SyncState, + incrementalSyncStatus: InitialSyncProgressService.Status.IncrementalSyncStatus, + showDebugInfo: Boolean) { + views.syncStateDebugInfo.isVisible = showDebugInfo + if (showDebugInfo) { + views.syncStateDebugInfo.text = + "Sync thread : ${newState.toHumanReadable()}\nSync request: ${incrementalSyncStatus.toHumanReadable()}" + } views.syncStateProgressBar.isVisible = newState is SyncState.Running && newState.afterPause if (newState == SyncState.NoNetwork) { @@ -48,4 +58,25 @@ class SyncStateView @JvmOverloads constructor(context: Context, attrs: Attribute views.syncStateNoNetworkAirplane.isVisible = false } } + + private fun SyncState.toHumanReadable(): String { + return when (this) { + SyncState.Idle -> "Idle" + SyncState.InvalidToken -> "InvalidToken" + SyncState.Killed -> "Killed" + SyncState.Killing -> "Killing" + SyncState.NoNetwork -> "NoNetwork" + SyncState.Paused -> "Paused" + is SyncState.Running -> "$this" + } + } + + private fun InitialSyncProgressService.Status.IncrementalSyncStatus.toHumanReadable(): String { + return when (this) { + is InitialSyncProgressService.Status.IncrementalSyncIdle -> "Idle" + is InitialSyncProgressService.Status.IncrementalSyncParsing -> "Parsing" + is InitialSyncProgressService.Status.IncrementalSyncDone -> "Done" + else -> "?" + } + } } diff --git a/vector/src/main/res/layout/view_sync_state.xml b/vector/src/main/res/layout/view_sync_state.xml index 55b8d4524a..d4de2c8d75 100644 --- a/vector/src/main/res/layout/view_sync_state.xml +++ b/vector/src/main/res/layout/view_sync_state.xml @@ -7,6 +7,15 @@ tools:orientation="vertical" tools:parentTag="android.widget.LinearLayout"> + +