change (media preview config) : final refactoring and tests
This commit is contained in:
parent
4b4cfa341e
commit
ca46166c67
27 changed files with 676 additions and 165 deletions
|
|
@ -8,21 +8,15 @@
|
|||
package io.element.android.features.preferences.impl.advanced
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import io.element.android.compound.theme.Theme
|
||||
import io.element.android.compound.theme.mapToTheme
|
||||
import io.element.android.libraries.architecture.AsyncAction
|
||||
import io.element.android.libraries.architecture.Presenter
|
||||
import io.element.android.libraries.architecture.runUpdatingState
|
||||
import io.element.android.libraries.di.annotations.SessionCoroutineScope
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
import io.element.android.libraries.matrix.api.media.MediaPreviewValue
|
||||
import io.element.android.libraries.preferences.api.store.AppPreferencesStore
|
||||
import io.element.android.libraries.preferences.api.store.SessionPreferencesStore
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
|
|
@ -51,6 +45,8 @@ class AdvancedSettingsPresenter @Inject constructor(
|
|||
appPreferencesStore.getThemeFlow().mapToTheme()
|
||||
}.collectAsState(initial = Theme.System)
|
||||
|
||||
val mediaPreviewConfigState = mediaPreviewConfigStateStore.state()
|
||||
|
||||
val themeOption by remember {
|
||||
derivedStateOf {
|
||||
when (theme.value) {
|
||||
|
|
@ -89,10 +85,7 @@ class AdvancedSettingsPresenter @Inject constructor(
|
|||
isSharePresenceEnabled = isSharePresenceEnabled,
|
||||
doesCompressMedia = doesCompressMedia,
|
||||
theme = themeOption,
|
||||
hideInviteAvatars = mediaPreviewConfigStateStore.hideInviteAvatars.value,
|
||||
timelineMediaPreviewValue = mediaPreviewConfigStateStore.timelineMediaPreviewValue.value,
|
||||
setHideInviteAvatarsAction = mediaPreviewConfigStateStore.setHideInviteAvatarsAction.value,
|
||||
setTimelineMediaPreviewAction = mediaPreviewConfigStateStore.setTimelineMediaPreviewAction.value,
|
||||
mediaPreviewConfigState = mediaPreviewConfigState,
|
||||
eventSink = ::handleEvents,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,9 +10,7 @@ package io.element.android.features.preferences.impl.advanced
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.ReadOnlyComposable
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import io.element.android.libraries.architecture.AsyncAction
|
||||
import io.element.android.libraries.designsystem.components.preferences.DropdownOption
|
||||
import io.element.android.libraries.matrix.api.media.MediaPreviewValue
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
|
||||
data class AdvancedSettingsState(
|
||||
|
|
@ -20,10 +18,7 @@ data class AdvancedSettingsState(
|
|||
val isSharePresenceEnabled: Boolean,
|
||||
val doesCompressMedia: Boolean,
|
||||
val theme: ThemeOption,
|
||||
val hideInviteAvatars: Boolean,
|
||||
val timelineMediaPreviewValue: MediaPreviewValue,
|
||||
val setHideInviteAvatarsAction: AsyncAction<Unit>,
|
||||
val setTimelineMediaPreviewAction: AsyncAction<Unit>,
|
||||
val mediaPreviewConfigState: MediaPreviewConfigState,
|
||||
val eventSink: (AdvancedSettingsEvents) -> Unit
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -29,8 +29,8 @@ fun aAdvancedSettingsState(
|
|||
isDeveloperModeEnabled: Boolean = false,
|
||||
isSharePresenceEnabled: Boolean = false,
|
||||
doesCompressMedia: Boolean = false,
|
||||
hideInviteAvatars: Boolean = false,
|
||||
theme: ThemeOption = ThemeOption.System,
|
||||
hideInviteAvatars: Boolean = false,
|
||||
timelineMediaPreviewValue: MediaPreviewValue = MediaPreviewValue.On,
|
||||
setTimelineMediaPreviewAction: AsyncAction<Unit> = AsyncAction.Uninitialized,
|
||||
setHideInviteAvatarsAction: AsyncAction<Unit> = AsyncAction.Uninitialized,
|
||||
|
|
@ -40,9 +40,11 @@ fun aAdvancedSettingsState(
|
|||
isSharePresenceEnabled = isSharePresenceEnabled,
|
||||
doesCompressMedia = doesCompressMedia,
|
||||
theme = theme,
|
||||
hideInviteAvatars = hideInviteAvatars,
|
||||
timelineMediaPreviewValue = timelineMediaPreviewValue,
|
||||
setTimelineMediaPreviewAction = setTimelineMediaPreviewAction,
|
||||
setHideInviteAvatarsAction = setHideInviteAvatarsAction,
|
||||
mediaPreviewConfigState = MediaPreviewConfigState(
|
||||
hideInviteAvatars = hideInviteAvatars,
|
||||
timelineMediaPreviewValue = timelineMediaPreviewValue,
|
||||
setTimelineMediaPreviewAction = setTimelineMediaPreviewAction,
|
||||
setHideInviteAvatarsAction = setHideInviteAvatarsAction
|
||||
),
|
||||
eventSink = eventSink
|
||||
)
|
||||
|
|
|
|||
|
|
@ -133,11 +133,11 @@ private fun ModerationAndSafety(
|
|||
) {
|
||||
PreferenceSwitch(
|
||||
title = stringResource(R.string.screen_advanced_settings_hide_invite_avatars_toggle_title),
|
||||
isChecked = state.hideInviteAvatars,
|
||||
isChecked = state.mediaPreviewConfigState.hideInviteAvatars,
|
||||
onCheckedChange = {
|
||||
state.eventSink(AdvancedSettingsEvents.SetHideInviteAvatars(it))
|
||||
},
|
||||
enabled = !state.setHideInviteAvatarsAction.isLoading()
|
||||
enabled = !state.mediaPreviewConfigState.setHideInviteAvatarsAction.isLoading()
|
||||
)
|
||||
ListSectionHeader(
|
||||
title = stringResource(R.string.screen_advanced_settings_show_media_timeline_title),
|
||||
|
|
@ -153,27 +153,36 @@ private fun ModerationAndSafety(
|
|||
)
|
||||
ListItem(
|
||||
headlineContent = { Text(text = stringResource(R.string.screen_advanced_settings_show_media_timeline_always_hide)) },
|
||||
leadingContent = ListItemContent.RadioButton(selected = state.timelineMediaPreviewValue == MediaPreviewValue.Off, compact = true),
|
||||
leadingContent = ListItemContent.RadioButton(
|
||||
selected = state.mediaPreviewConfigState.timelineMediaPreviewValue == MediaPreviewValue.Off,
|
||||
compact = true
|
||||
),
|
||||
onClick = {
|
||||
state.eventSink(AdvancedSettingsEvents.SetTimelineMediaPreviewValue(MediaPreviewValue.Off))
|
||||
},
|
||||
enabled = !state.setTimelineMediaPreviewAction.isLoading()
|
||||
enabled = !state.mediaPreviewConfigState.setTimelineMediaPreviewAction.isLoading()
|
||||
)
|
||||
ListItem(
|
||||
headlineContent = { Text(text = stringResource(R.string.screen_advanced_settings_show_media_timeline_private_rooms)) },
|
||||
leadingContent = ListItemContent.RadioButton(selected = state.timelineMediaPreviewValue == MediaPreviewValue.Private, compact = true),
|
||||
leadingContent = ListItemContent.RadioButton(
|
||||
selected = state.mediaPreviewConfigState.timelineMediaPreviewValue == MediaPreviewValue.Private,
|
||||
compact = true
|
||||
),
|
||||
onClick = {
|
||||
state.eventSink(AdvancedSettingsEvents.SetTimelineMediaPreviewValue(MediaPreviewValue.Private))
|
||||
},
|
||||
enabled = !state.setTimelineMediaPreviewAction.isLoading()
|
||||
enabled = !state.mediaPreviewConfigState.setTimelineMediaPreviewAction.isLoading()
|
||||
)
|
||||
ListItem(
|
||||
headlineContent = { Text(text = stringResource(R.string.screen_advanced_settings_show_media_timeline_always_show)) },
|
||||
leadingContent = ListItemContent.RadioButton(selected = state.timelineMediaPreviewValue == MediaPreviewValue.On, compact = true),
|
||||
leadingContent = ListItemContent.RadioButton(
|
||||
selected = state.mediaPreviewConfigState.timelineMediaPreviewValue == MediaPreviewValue.On,
|
||||
compact = true
|
||||
),
|
||||
onClick = {
|
||||
state.eventSink(AdvancedSettingsEvents.SetTimelineMediaPreviewValue(MediaPreviewValue.On))
|
||||
},
|
||||
enabled = !state.setTimelineMediaPreviewAction.isLoading()
|
||||
enabled = !state.mediaPreviewConfigState.setTimelineMediaPreviewAction.isLoading()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
package io.element.android.features.preferences.impl.advanced
|
||||
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import com.squareup.anvil.annotations.ContributesBinding
|
||||
import io.element.android.libraries.architecture.AsyncAction
|
||||
|
|
@ -21,27 +21,29 @@ import io.element.android.libraries.matrix.api.media.MediaPreviewService
|
|||
import io.element.android.libraries.matrix.api.media.MediaPreviewValue
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.mapNotNull
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.shareIn
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
interface MediaPreviewConfigStateStore {
|
||||
val hideInviteAvatars: State<Boolean>
|
||||
val timelineMediaPreviewValue: State<MediaPreviewValue>
|
||||
val setHideInviteAvatarsAction: State<AsyncAction<Unit>>
|
||||
val setTimelineMediaPreviewAction: State<AsyncAction<Unit>>
|
||||
data class MediaPreviewConfigState(
|
||||
val hideInviteAvatars: Boolean,
|
||||
val timelineMediaPreviewValue: MediaPreviewValue,
|
||||
val setHideInviteAvatarsAction: AsyncAction<Unit>,
|
||||
val setTimelineMediaPreviewAction: AsyncAction<Unit>,
|
||||
)
|
||||
|
||||
interface MediaPreviewConfigStateStore {
|
||||
@Composable
|
||||
fun state(): MediaPreviewConfigState
|
||||
fun setHideInviteAvatars(hide: Boolean)
|
||||
fun setTimelineMediaPreviewValue(value: MediaPreviewValue)
|
||||
}
|
||||
|
||||
@ContributesBinding(SessionScope::class, boundType = MediaPreviewConfigStateStore::class)
|
||||
@ContributesBinding(SessionScope::class)
|
||||
@SingleIn(SessionScope::class)
|
||||
class DefaultMediaPreviewConfigStateStore @Inject constructor(
|
||||
@SessionCoroutineScope
|
||||
|
|
@ -49,19 +51,19 @@ class DefaultMediaPreviewConfigStateStore @Inject constructor(
|
|||
private val mediaPreviewService: MediaPreviewService,
|
||||
private val snackbarDispatcher: SnackbarDispatcher,
|
||||
) : MediaPreviewConfigStateStore {
|
||||
override val hideInviteAvatars = mutableStateOf(false)
|
||||
override val timelineMediaPreviewValue = mutableStateOf(MediaPreviewValue.On)
|
||||
override val setHideInviteAvatarsAction = mutableStateOf<AsyncAction<Unit>>(AsyncAction.Uninitialized)
|
||||
override val setTimelineMediaPreviewAction = mutableStateOf<AsyncAction<Unit>>(AsyncAction.Uninitialized)
|
||||
private val hideInviteAvatars = mutableStateOf(false)
|
||||
private val timelineMediaPreviewValue = mutableStateOf(MediaPreviewValue.On)
|
||||
private val setHideInviteAvatarsAction = mutableStateOf<AsyncAction<Unit>>(AsyncAction.Uninitialized)
|
||||
private val setTimelineMediaPreviewAction = mutableStateOf<AsyncAction<Unit>>(AsyncAction.Uninitialized)
|
||||
|
||||
init {
|
||||
val configFlow = mediaPreviewService.getMediaPreviewConfigFlow().shareIn(sessionCoroutineScope, SharingStarted.Eagerly)
|
||||
val hideInviteAvatarsFlow = configFlow.mapNotNull { it?.hideInviteAvatar }.distinctUntilChanged()
|
||||
val timelineMediaPreviewFlow = configFlow.mapNotNull { it?.mediaPreviewValue }.distinctUntilChanged()
|
||||
val configFlow = mediaPreviewService.mediaPreviewConfigFlow
|
||||
val hideInviteAvatarsFlow = configFlow.map { it.hideInviteAvatar }.distinctUntilChanged()
|
||||
val timelineMediaPreviewFlow = configFlow.map { it.mediaPreviewValue }.distinctUntilChanged()
|
||||
|
||||
hideInviteAvatarsFlow
|
||||
.onEach {
|
||||
Timber.d("Hide invi@te avatars changed to $it")
|
||||
Timber.d("Hide invite avatars changed to $it")
|
||||
hideInviteAvatars.value = it
|
||||
}
|
||||
.launchIn(sessionCoroutineScope)
|
||||
|
|
@ -74,6 +76,16 @@ class DefaultMediaPreviewConfigStateStore @Inject constructor(
|
|||
.launchIn(sessionCoroutineScope)
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun state(): MediaPreviewConfigState {
|
||||
return MediaPreviewConfigState(
|
||||
hideInviteAvatars = hideInviteAvatars.value,
|
||||
timelineMediaPreviewValue = timelineMediaPreviewValue.value,
|
||||
setHideInviteAvatarsAction = setHideInviteAvatarsAction.value,
|
||||
setTimelineMediaPreviewAction = setTimelineMediaPreviewAction.value,
|
||||
)
|
||||
}
|
||||
|
||||
override fun setHideInviteAvatars(hide: Boolean) {
|
||||
sessionCoroutineScope.launch {
|
||||
Timber.d("Setting hide invite avatars to $hide")
|
||||
|
|
@ -106,4 +118,3 @@ class DefaultMediaPreviewConfigStateStore @Inject constructor(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue