Merge pull request #8019 from vector-im/feature/bma/startSync

Start sync
This commit is contained in:
Benoit Marty 2023-01-30 12:01:17 +01:00 committed by GitHub
commit f2ca2c6502
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 90 additions and 29 deletions

View File

@ -10,6 +10,8 @@
<!-- onboarding english only word play --> <!-- onboarding english only word play -->
<string name="cut_the_slack_from_teams" translatable="false">Cut the slack from teams.</string> <string name="cut_the_slack_from_teams" translatable="false">Cut the slack from teams.</string>
<string name="command_description_crash_application" translatable="false">Crash the application.</string>
<!-- WIP --> <!-- WIP -->
<string name="location_map_view_copyright" translatable="false">© MapTiler © OpenStreetMap contributors</string> <string name="location_map_view_copyright" translatable="false">© MapTiler © OpenStreetMap contributors</string>
</resources> </resources>

View File

@ -80,6 +80,9 @@ class FlowSession(private val session: Session) {
fun liveSyncState(): Flow<SyncState> { fun liveSyncState(): Flow<SyncState> {
return session.syncService().getSyncStateLive().asFlow() return session.syncService().getSyncStateLive().asFlow()
.startWith(session.coroutineDispatchers.io) {
session.syncService().getSyncState()
}
} }
fun livePushers(): Flow<List<Pusher>> { fun livePushers(): Flow<List<Pusher>> {

View File

@ -0,0 +1,38 @@
/*
* 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.
*/
package im.vector.app.core.session
import android.content.Context
import dagger.hilt.android.qualifiers.ApplicationContext
import im.vector.app.core.di.ActiveSessionHolder
import im.vector.app.core.extensions.startSyncing
import org.matrix.android.sdk.api.session.sync.SyncState
import timber.log.Timber
import javax.inject.Inject
class EnsureSessionSyncingUseCase @Inject constructor(
@ApplicationContext private val context: Context,
private val activeSessionHolder: ActiveSessionHolder,
) {
fun execute() {
val session = activeSessionHolder.getSafeActiveSession() ?: return
if (session.syncService().getSyncState() == SyncState.Idle) {
Timber.w("EnsureSessionSyncingUseCase: start syncing")
session.startSyncing(context)
}
}
}

View File

@ -32,6 +32,7 @@ enum class Command(
val isDevCommand: Boolean, val isDevCommand: Boolean,
val isThreadCommand: Boolean val isThreadCommand: Boolean
) { ) {
CRASH_APP("/crash", null, "", R.string.command_description_crash_application, true, true),
EMOTE("/me", null, "<message>", R.string.command_description_emote, false, true), EMOTE("/me", null, "<message>", R.string.command_description_emote, false, true),
BAN_USER("/ban", null, "<user-id> [reason]", R.string.command_description_ban_user, false, false), BAN_USER("/ban", null, "<user-id> [reason]", R.string.command_description_ban_user, false, false),
UNBAN_USER("/unban", null, "<user-id> [reason]", R.string.command_description_unban_user, false, false), UNBAN_USER("/unban", null, "<user-id> [reason]", R.string.command_description_unban_user, false, false),

View File

@ -20,13 +20,16 @@ import im.vector.app.core.extensions.isEmail
import im.vector.app.core.extensions.isMsisdn import im.vector.app.core.extensions.isMsisdn
import im.vector.app.core.extensions.orEmpty import im.vector.app.core.extensions.orEmpty
import im.vector.app.features.home.room.detail.ChatEffect import im.vector.app.features.home.room.detail.ChatEffect
import im.vector.app.features.settings.VectorPreferences
import org.matrix.android.sdk.api.MatrixPatterns import org.matrix.android.sdk.api.MatrixPatterns
import org.matrix.android.sdk.api.MatrixUrls.isMxcUrl import org.matrix.android.sdk.api.MatrixUrls.isMxcUrl
import org.matrix.android.sdk.api.session.identity.ThreePid import org.matrix.android.sdk.api.session.identity.ThreePid
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
class CommandParser @Inject constructor() { class CommandParser @Inject constructor(
private val vectorPreferences: VectorPreferences
) {
/** /**
* Convert the text message into a Slash command. * Convert the text message into a Slash command.
@ -404,6 +407,9 @@ class CommandParser @Inject constructor() {
ParsedCommand.ErrorSyntax(Command.UPGRADE_ROOM) ParsedCommand.ErrorSyntax(Command.UPGRADE_ROOM)
} }
} }
Command.CRASH_APP.matches(slashCommand) && vectorPreferences.developerMode() -> {
throw RuntimeException("Application crashed from user demand")
}
else -> { else -> {
// Unknown command // Unknown command
ParsedCommand.ErrorUnknownSlashCommand(slashCommand) ParsedCommand.ErrorUnknownSlashCommand(slashCommand)

View File

@ -30,6 +30,7 @@ import im.vector.app.core.pushers.EnsureFcmTokenIsRetrievedUseCase
import im.vector.app.core.pushers.PushersManager import im.vector.app.core.pushers.PushersManager
import im.vector.app.core.pushers.RegisterUnifiedPushUseCase import im.vector.app.core.pushers.RegisterUnifiedPushUseCase
import im.vector.app.core.pushers.UnregisterUnifiedPushUseCase import im.vector.app.core.pushers.UnregisterUnifiedPushUseCase
import im.vector.app.core.session.EnsureSessionSyncingUseCase
import im.vector.app.features.analytics.AnalyticsConfig import im.vector.app.features.analytics.AnalyticsConfig
import im.vector.app.features.analytics.AnalyticsTracker import im.vector.app.features.analytics.AnalyticsTracker
import im.vector.app.features.analytics.extensions.toAnalyticsType import im.vector.app.features.analytics.extensions.toAnalyticsType
@ -95,6 +96,7 @@ class HomeActivityViewModel @AssistedInject constructor(
private val registerUnifiedPushUseCase: RegisterUnifiedPushUseCase, private val registerUnifiedPushUseCase: RegisterUnifiedPushUseCase,
private val unregisterUnifiedPushUseCase: UnregisterUnifiedPushUseCase, private val unregisterUnifiedPushUseCase: UnregisterUnifiedPushUseCase,
private val ensureFcmTokenIsRetrievedUseCase: EnsureFcmTokenIsRetrievedUseCase, private val ensureFcmTokenIsRetrievedUseCase: EnsureFcmTokenIsRetrievedUseCase,
private val ensureSessionSyncingUseCase: EnsureSessionSyncingUseCase,
) : VectorViewModel<HomeActivityViewState, HomeActivityViewActions, HomeActivityViewEvents>(initialState) { ) : VectorViewModel<HomeActivityViewState, HomeActivityViewActions, HomeActivityViewEvents>(initialState) {
@AssistedFactory @AssistedFactory
@ -118,6 +120,8 @@ class HomeActivityViewModel @AssistedInject constructor(
private fun initialize() { private fun initialize() {
if (isInitialized) return if (isInitialized) return
isInitialized = true isInitialized = true
// Ensure Session is syncing
ensureSessionSyncingUseCase.execute()
registerUnifiedPushIfNeeded() registerUnifiedPushIfNeeded()
cleanupFiles() cleanupFiles()
observeInitialSync() observeInitialSync()

View File

@ -38,8 +38,8 @@ data class HomeDetailViewState(
val notificationCountRooms: Int = 0, val notificationCountRooms: Int = 0,
val notificationHighlightRooms: Boolean = false, val notificationHighlightRooms: Boolean = false,
val hasUnreadMessages: Boolean = false, val hasUnreadMessages: Boolean = false,
val syncState: SyncState = SyncState.Idle, val syncState: SyncState? = null,
val incrementalSyncRequestState: SyncRequestState.IncrementalSyncRequestState = SyncRequestState.IncrementalSyncIdle, val incrementalSyncRequestState: SyncRequestState.IncrementalSyncRequestState? = null,
val pushCounter: Int = 0, val pushCounter: Int = 0,
val pstnSupportFlag: Boolean = false, val pstnSupportFlag: Boolean = false,
val forceDialPadTab: Boolean = false val forceDialPadTab: Boolean = false

View File

@ -60,8 +60,8 @@ data class RoomDetailViewState(
val formattedTypingUsers: String? = null, val formattedTypingUsers: String? = null,
val tombstoneEvent: Event? = null, val tombstoneEvent: Event? = null,
val joinUpgradedRoomAsync: Async<String> = Uninitialized, val joinUpgradedRoomAsync: Async<String> = Uninitialized,
val syncState: SyncState = SyncState.Idle, val syncState: SyncState? = null,
val incrementalSyncRequestState: SyncRequestState.IncrementalSyncRequestState = SyncRequestState.IncrementalSyncIdle, val incrementalSyncRequestState: SyncRequestState.IncrementalSyncRequestState? = null,
val pushCounter: Int = 0, val pushCounter: Int = 0,
val highlightedEventId: String? = null, val highlightedEventId: String? = null,
val unreadState: UnreadState = UnreadState.Unknown, val unreadState: UnreadState = UnreadState.Unknown,

View File

@ -40,8 +40,8 @@ class SyncStateView @JvmOverloads constructor(context: Context, attrs: Attribute
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
fun render( fun render(
newState: SyncState, newState: SyncState?,
incrementalSyncRequestState: SyncRequestState.IncrementalSyncRequestState, incrementalSyncRequestState: SyncRequestState.IncrementalSyncRequestState?,
pushCounter: Int, pushCounter: Int,
showDebugInfo: Boolean showDebugInfo: Boolean
) { ) {
@ -64,8 +64,9 @@ class SyncStateView @JvmOverloads constructor(context: Context, attrs: Attribute
} }
} }
private fun SyncState.toHumanReadable(): String { private fun SyncState?.toHumanReadable(): String {
return when (this) { return when (this) {
null -> "Unknown"
SyncState.Idle -> "Idle" SyncState.Idle -> "Idle"
SyncState.InvalidToken -> "InvalidToken" SyncState.InvalidToken -> "InvalidToken"
SyncState.Killed -> "Killed" SyncState.Killed -> "Killed"
@ -76,8 +77,9 @@ class SyncStateView @JvmOverloads constructor(context: Context, attrs: Attribute
} }
} }
private fun SyncRequestState.IncrementalSyncRequestState.toHumanReadable(): String { private fun SyncRequestState.IncrementalSyncRequestState?.toHumanReadable(): String {
return when (this) { return when (this) {
null -> "Unknown"
SyncRequestState.IncrementalSyncIdle -> "Idle" SyncRequestState.IncrementalSyncIdle -> "Idle"
is SyncRequestState.IncrementalSyncParsing -> "Parsing ${this.rooms} room(s) ${this.toDevice} toDevice(s)" is SyncRequestState.IncrementalSyncParsing -> "Parsing ${this.rooms} room(s) ${this.toDevice} toDevice(s)"
SyncRequestState.IncrementalSyncError -> "Error" SyncRequestState.IncrementalSyncError -> "Error"

View File

@ -17,7 +17,8 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:minHeight="48dp" android:minHeight="48dp"
android:visibility="gone" /> android:visibility="gone"
tools:visibility="visible" />
<com.google.android.material.appbar.MaterialToolbar <com.google.android.material.appbar.MaterialToolbar
android:id="@+id/roomToolbar" android:id="@+id/roomToolbar"
@ -38,9 +39,9 @@
</com.google.android.material.appbar.AppBarLayout> </com.google.android.material.appbar.AppBarLayout>
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/rootConstraintLayout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent">
android:id="@+id/rootConstraintLayout">
<im.vector.app.features.sync.widget.SyncStateView <im.vector.app.features.sync.widget.SyncStateView
android:id="@+id/syncStateView" android:id="@+id/syncStateView"
@ -75,7 +76,7 @@
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="0dp" android:layout_height="0dp"
android:overScrollMode="always" android:overScrollMode="always"
app:layout_constraintBottom_toTopOf="@id/notificationAreaView" app:layout_constraintBottom_toTopOf="@id/failedMessagesWarningStub"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/removeJitsiWidgetView" app:layout_constraintTop_toBottomOf="@id/removeJitsiWidgetView"
@ -95,7 +96,19 @@
app:closeIcon="@drawable/ic_close_24dp" app:closeIcon="@drawable/ic_close_24dp"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/removeJitsiWidgetView" /> app:layout_constraintTop_toBottomOf="@id/removeJitsiWidgetView"
tools:visibility="visible" />
<ViewStub
android:id="@+id/failedMessagesWarningStub"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inflatedId="@+id/failedMessagesWarningStub"
android:layout="@layout/view_stub_failed_message_warning_layout"
app:layout_constraintBottom_toTopOf="@id/notificationAreaView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:layout_height="300dp" />
<im.vector.app.core.ui.views.NotificationAreaView <im.vector.app.core.ui.views.NotificationAreaView
android:id="@+id/notificationAreaView" android:id="@+id/notificationAreaView"
@ -107,17 +120,6 @@
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
tools:visibility="visible" /> tools:visibility="visible" />
<ViewStub
android:id="@+id/failedMessagesWarningStub"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inflatedId="@+id/failedMessagesWarningStub"
android:layout="@layout/view_stub_failed_message_warning_layout"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:layout_height="300dp" />
<ViewStub <ViewStub
android:id="@+id/inviteViewStub" android:id="@+id/inviteViewStub"
android:layout_width="0dp" android:layout_width="0dp"
@ -208,8 +210,8 @@
android:id="@+id/composerContainer" android:id="@+id/composerContainer"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:translationZ="10dp"
android:background="@android:color/transparent" android:background="@android:color/transparent"
android:translationZ="10dp"
app:layout_behavior="im.vector.app.core.utils.ExpandingBottomSheetBehavior" /> app:layout_behavior="im.vector.app.core.utils.ExpandingBottomSheetBehavior" />
<FrameLayout <FrameLayout
@ -217,7 +219,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="bottom" android:layout_gravity="bottom"
android:visibility="visible" android:translationZ="10dp"
android:translationZ="10dp" /> android:visibility="visible" />
</androidx.coordinatorlayout.widget.CoordinatorLayout> </androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -16,12 +16,15 @@
package im.vector.app.features.command package im.vector.app.features.command
import im.vector.app.test.fakes.FakeVectorPreferences
import org.amshove.kluent.shouldBeEqualTo import org.amshove.kluent.shouldBeEqualTo
import org.junit.Test import org.junit.Test
private const val A_SPACE_ID = "!my-space-id" private const val A_SPACE_ID = "!my-space-id"
class CommandParserTest { class CommandParserTest {
private val fakeVectorPreferences = FakeVectorPreferences()
@Test @Test
fun parseSlashCommandEmpty() { fun parseSlashCommandEmpty() {
test("/", ParsedCommand.ErrorEmptySlashCommand) test("/", ParsedCommand.ErrorEmptySlashCommand)
@ -70,7 +73,7 @@ class CommandParserTest {
} }
private fun test(message: String, expectedResult: ParsedCommand) { private fun test(message: String, expectedResult: ParsedCommand) {
val commandParser = CommandParser() val commandParser = CommandParser(fakeVectorPreferences.instance)
val result = commandParser.parseSlashCommand(message, null, false) val result = commandParser.parseSlashCommand(message, null, false)
result shouldBeEqualTo expectedResult result shouldBeEqualTo expectedResult
} }