change (media preview config) : manage migration of local data

This commit is contained in:
ganfra
2025-06-26 21:44:03 +02:00
parent 42af43ea7a
commit 7fb0b36a9e
5 changed files with 99 additions and 11 deletions

View File

@@ -41,6 +41,7 @@ import dagger.assisted.AssistedInject
import im.vector.app.features.analytics.plan.JoinedRoom
import io.element.android.anvilannotations.ContributesNode
import io.element.android.appnav.loggedin.LoggedInNode
import io.element.android.appnav.loggedin.MediaPreviewConfigMigration
import io.element.android.appnav.loggedin.SendQueues
import io.element.android.appnav.room.RoomFlowNode
import io.element.android.appnav.room.RoomNavigationTarget
@@ -114,6 +115,7 @@ class LoggedInFlowNode @AssistedInject constructor(
private val sendingQueue: SendQueues,
private val logoutEntryPoint: LogoutEntryPoint,
private val incomingVerificationEntryPoint: IncomingVerificationEntryPoint,
private val mediaPreviewConfigMigration: MediaPreviewConfigMigration,
snackbarDispatcher: SnackbarDispatcher,
) : BaseFlowNode<LoggedInFlowNode.NavTarget>(
backstack = BackStack(
@@ -179,6 +181,7 @@ class LoggedInFlowNode @AssistedInject constructor(
appNavigationStateService.onNavigateToSpace(id, MAIN_SPACE)
loggedInFlowProcessor.observeEvents(sessionCoroutineScope)
matrixClient.sessionVerificationService().setListener(verificationListener)
mediaPreviewConfigMigration()
ftueService.state
.onEach { ftueState ->

View File

@@ -0,0 +1,56 @@
/*
* Copyright 2025 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.appnav.loggedin
import io.element.android.libraries.di.annotations.SessionCoroutineScope
import io.element.android.libraries.matrix.api.media.MediaPreviewService
import io.element.android.libraries.preferences.api.store.AppPreferencesStore
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
import timber.log.Timber
import javax.inject.Inject
/**
* This migration is temporary, will be safe to remove after some time.
* The goal is to set the server config if it's not set, and remove the local data.
*/
class MediaPreviewConfigMigration @Inject constructor(
private val mediaPreviewService: MediaPreviewService,
private val appPreferencesStore: AppPreferencesStore,
@SessionCoroutineScope
private val sessionCoroutineScope: CoroutineScope,
) {
operator fun invoke() = sessionCoroutineScope.launch {
val hideInviteAvatars = appPreferencesStore.getHideInviteAvatarsFlow().first()
val mediaPreviewValue = appPreferencesStore.getTimelineMediaPreviewValueFlow().first()
if (hideInviteAvatars == null && mediaPreviewValue == null) {
// No local data, abort.
return@launch
}
mediaPreviewService
.fetchMediaPreviewConfig()
.onSuccess { config ->
if (config != null) {
appPreferencesStore.setHideInviteAvatars(null)
appPreferencesStore.setTimelineMediaPreviewValue(null)
} else {
if (hideInviteAvatars != null) {
mediaPreviewService.setHideInviteAvatars(hideInviteAvatars)
appPreferencesStore.setHideInviteAvatars(null)
}
if (mediaPreviewValue != null) {
mediaPreviewService.setMediaPreviewValue(mediaPreviewValue)
appPreferencesStore.setTimelineMediaPreviewValue(null)
}
}
}.onFailure {
Timber.d("Couldn't perform migration, failed to fetch media preview config.")
}
}
}

View File

@@ -22,9 +22,10 @@ interface AppPreferencesStore {
suspend fun setTheme(theme: String)
fun getThemeFlow(): Flow<String?>
fun getHideInviteAvatarsFlow(): Flow<Boolean>
fun getTimelineMediaPreviewValueFlow(): Flow<MediaPreviewValue>
suspend fun setHideInviteAvatars(hide: Boolean?)
fun getHideInviteAvatarsFlow(): Flow<Boolean?>
suspend fun setTimelineMediaPreviewValue(mediaPreviewValue: MediaPreviewValue?)
fun getTimelineMediaPreviewValueFlow(): Flow<MediaPreviewValue?>
suspend fun setTracingLogLevel(logLevel: LogLevel)
fun getTracingLogLevelFlow(): Flow<LogLevel>

View File

@@ -85,15 +85,35 @@ class DefaultAppPreferencesStore @Inject constructor(
}
}
override fun getHideInviteAvatarsFlow(): Flow<Boolean> {
override fun getHideInviteAvatarsFlow(): Flow<Boolean?> {
return store.data.map { prefs ->
prefs[hideInviteAvatarsKey] == true
prefs[hideInviteAvatarsKey]
}
}
override fun getTimelineMediaPreviewValueFlow(): Flow<MediaPreviewValue> {
override suspend fun setHideInviteAvatars(hide: Boolean?) {
store.edit { prefs ->
if (hide != null) {
prefs[hideInviteAvatarsKey] = hide
} else {
prefs.remove(hideInviteAvatarsKey)
}
}
}
override suspend fun setTimelineMediaPreviewValue(mediaPreviewValue: MediaPreviewValue?) {
store.edit { prefs ->
if (mediaPreviewValue != null) {
prefs[timelineMediaPreviewValueKey] = mediaPreviewValue.name
} else {
prefs.remove(timelineMediaPreviewValueKey)
}
}
}
override fun getTimelineMediaPreviewValueFlow(): Flow<MediaPreviewValue?> {
return store.data.map { prefs ->
prefs[timelineMediaPreviewValueKey]?.let { MediaPreviewValue.valueOf(it) } ?: MediaPreviewValue.On
prefs[timelineMediaPreviewValueKey]?.let { MediaPreviewValue.valueOf(it) }
}
}

View File

@@ -17,8 +17,8 @@ import kotlinx.coroutines.flow.MutableStateFlow
class InMemoryAppPreferencesStore(
isDeveloperModeEnabled: Boolean = false,
customElementCallBaseUrl: String? = null,
hideInviteAvatars: Boolean = false,
timelineMediaPreviewValue: MediaPreviewValue = MediaPreviewValue.On,
hideInviteAvatars: Boolean? = null,
timelineMediaPreviewValue: MediaPreviewValue? = null,
theme: String? = null,
logLevel: LogLevel = LogLevel.INFO,
traceLockPacks: Set<TraceLogPack> = emptySet(),
@@ -55,14 +55,22 @@ class InMemoryAppPreferencesStore(
return theme
}
override fun getHideInviteAvatarsFlow(): Flow<Boolean> {
override fun getHideInviteAvatarsFlow(): Flow<Boolean?> {
return hideInviteAvatars
}
override fun getTimelineMediaPreviewValueFlow(): Flow<MediaPreviewValue> {
override fun getTimelineMediaPreviewValueFlow(): Flow<MediaPreviewValue?> {
return timelineMediaPreviewValue
}
override suspend fun setHideInviteAvatars(hide: Boolean?) {
hideInviteAvatars.value = hide
}
override suspend fun setTimelineMediaPreviewValue(mediaPreviewValue: MediaPreviewValue?) {
timelineMediaPreviewValue.value = mediaPreviewValue
}
override suspend fun setTracingLogLevel(logLevel: LogLevel) {
this.logLevel.value = logLevel
}