change (media preview config) : use the new apis
This commit is contained in:
parent
682897cdb6
commit
0b748aa8cb
10 changed files with 158 additions and 60 deletions
|
|
@ -8,27 +8,36 @@
|
||||||
package io.element.android.features.preferences.impl.advanced
|
package io.element.android.features.preferences.impl.advanced
|
||||||
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.derivedStateOf
|
import androidx.compose.runtime.derivedStateOf
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.setValue
|
||||||
import io.element.android.compound.theme.Theme
|
import io.element.android.compound.theme.Theme
|
||||||
import io.element.android.compound.theme.mapToTheme
|
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.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.matrix.api.media.MediaPreviewValue
|
||||||
import io.element.android.libraries.preferences.api.store.AppPreferencesStore
|
import io.element.android.libraries.preferences.api.store.AppPreferencesStore
|
||||||
import io.element.android.libraries.preferences.api.store.SessionPreferencesStore
|
import io.element.android.libraries.preferences.api.store.SessionPreferencesStore
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class AdvancedSettingsPresenter @Inject constructor(
|
class AdvancedSettingsPresenter @Inject constructor(
|
||||||
private val appPreferencesStore: AppPreferencesStore,
|
private val appPreferencesStore: AppPreferencesStore,
|
||||||
private val sessionPreferencesStore: SessionPreferencesStore,
|
private val sessionPreferencesStore: SessionPreferencesStore,
|
||||||
|
private val mediaPreviewConfigStateStore: MediaPreviewConfigStateStore,
|
||||||
|
@SessionCoroutineScope
|
||||||
|
private val sessionCoroutineScope: CoroutineScope,
|
||||||
) : Presenter<AdvancedSettingsState> {
|
) : Presenter<AdvancedSettingsState> {
|
||||||
@Composable
|
@Composable
|
||||||
override fun present(): AdvancedSettingsState {
|
override fun present(): AdvancedSettingsState {
|
||||||
val localCoroutineScope = rememberCoroutineScope()
|
|
||||||
val isDeveloperModeEnabled by remember {
|
val isDeveloperModeEnabled by remember {
|
||||||
appPreferencesStore.isDeveloperModeEnabledFlow()
|
appPreferencesStore.isDeveloperModeEnabledFlow()
|
||||||
}.collectAsState(initial = false)
|
}.collectAsState(initial = false)
|
||||||
|
|
@ -41,13 +50,6 @@ class AdvancedSettingsPresenter @Inject constructor(
|
||||||
val theme = remember {
|
val theme = remember {
|
||||||
appPreferencesStore.getThemeFlow().mapToTheme()
|
appPreferencesStore.getThemeFlow().mapToTheme()
|
||||||
}.collectAsState(initial = Theme.System)
|
}.collectAsState(initial = Theme.System)
|
||||||
val hideInviteAvatars by remember {
|
|
||||||
appPreferencesStore.getHideInviteAvatarsFlow()
|
|
||||||
}.collectAsState(false)
|
|
||||||
|
|
||||||
val timelineMediaPreviewValue by remember {
|
|
||||||
appPreferencesStore.getTimelineMediaPreviewValueFlow()
|
|
||||||
}.collectAsState(initial = MediaPreviewValue.On)
|
|
||||||
|
|
||||||
val themeOption by remember {
|
val themeOption by remember {
|
||||||
derivedStateOf {
|
derivedStateOf {
|
||||||
|
|
@ -61,28 +63,24 @@ class AdvancedSettingsPresenter @Inject constructor(
|
||||||
|
|
||||||
fun handleEvents(event: AdvancedSettingsEvents) {
|
fun handleEvents(event: AdvancedSettingsEvents) {
|
||||||
when (event) {
|
when (event) {
|
||||||
is AdvancedSettingsEvents.SetDeveloperModeEnabled -> localCoroutineScope.launch {
|
is AdvancedSettingsEvents.SetDeveloperModeEnabled -> sessionCoroutineScope.launch {
|
||||||
appPreferencesStore.setDeveloperModeEnabled(event.enabled)
|
appPreferencesStore.setDeveloperModeEnabled(event.enabled)
|
||||||
}
|
}
|
||||||
is AdvancedSettingsEvents.SetSharePresenceEnabled -> localCoroutineScope.launch {
|
is AdvancedSettingsEvents.SetSharePresenceEnabled -> sessionCoroutineScope.launch {
|
||||||
sessionPreferencesStore.setSharePresence(event.enabled)
|
sessionPreferencesStore.setSharePresence(event.enabled)
|
||||||
}
|
}
|
||||||
is AdvancedSettingsEvents.SetCompressMedia -> localCoroutineScope.launch {
|
is AdvancedSettingsEvents.SetCompressMedia -> sessionCoroutineScope.launch {
|
||||||
sessionPreferencesStore.setCompressMedia(event.compress)
|
sessionPreferencesStore.setCompressMedia(event.compress)
|
||||||
}
|
}
|
||||||
is AdvancedSettingsEvents.SetTheme -> localCoroutineScope.launch {
|
is AdvancedSettingsEvents.SetTheme -> sessionCoroutineScope.launch {
|
||||||
when (event.theme) {
|
when (event.theme) {
|
||||||
ThemeOption.System -> appPreferencesStore.setTheme(Theme.System.name)
|
ThemeOption.System -> appPreferencesStore.setTheme(Theme.System.name)
|
||||||
ThemeOption.Dark -> appPreferencesStore.setTheme(Theme.Dark.name)
|
ThemeOption.Dark -> appPreferencesStore.setTheme(Theme.Dark.name)
|
||||||
ThemeOption.Light -> appPreferencesStore.setTheme(Theme.Light.name)
|
ThemeOption.Light -> appPreferencesStore.setTheme(Theme.Light.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is AdvancedSettingsEvents.SetHideInviteAvatars -> localCoroutineScope.launch {
|
is AdvancedSettingsEvents.SetHideInviteAvatars -> mediaPreviewConfigStateStore.setHideInviteAvatars(event.value)
|
||||||
appPreferencesStore.setHideInviteAvatars(event.value)
|
is AdvancedSettingsEvents.SetTimelineMediaPreviewValue -> mediaPreviewConfigStateStore.setTimelineMediaPreviewValue(event.value)
|
||||||
}
|
|
||||||
is AdvancedSettingsEvents.SetTimelineMediaPreviewValue -> localCoroutineScope.launch {
|
|
||||||
appPreferencesStore.setTimelineMediaPreviewValue(event.value)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -91,9 +89,11 @@ class AdvancedSettingsPresenter @Inject constructor(
|
||||||
isSharePresenceEnabled = isSharePresenceEnabled,
|
isSharePresenceEnabled = isSharePresenceEnabled,
|
||||||
doesCompressMedia = doesCompressMedia,
|
doesCompressMedia = doesCompressMedia,
|
||||||
theme = themeOption,
|
theme = themeOption,
|
||||||
hideInviteAvatars = hideInviteAvatars,
|
hideInviteAvatars = mediaPreviewConfigStateStore.hideInviteAvatars.value,
|
||||||
timelineMediaPreviewValue = timelineMediaPreviewValue,
|
timelineMediaPreviewValue = mediaPreviewConfigStateStore.timelineMediaPreviewValue.value,
|
||||||
eventSink = { handleEvents(it) }
|
setHideInviteAvatarsAction = mediaPreviewConfigStateStore.setHideInviteAvatarsAction.value,
|
||||||
|
setTimelineMediaPreviewAction = mediaPreviewConfigStateStore.setTimelineMediaPreviewAction.value,
|
||||||
|
eventSink = ::handleEvents,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ package io.element.android.features.preferences.impl.advanced
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.ReadOnlyComposable
|
import androidx.compose.runtime.ReadOnlyComposable
|
||||||
import androidx.compose.ui.res.stringResource
|
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.designsystem.components.preferences.DropdownOption
|
||||||
import io.element.android.libraries.matrix.api.media.MediaPreviewValue
|
import io.element.android.libraries.matrix.api.media.MediaPreviewValue
|
||||||
import io.element.android.libraries.ui.strings.CommonStrings
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
|
|
@ -21,6 +22,8 @@ data class AdvancedSettingsState(
|
||||||
val theme: ThemeOption,
|
val theme: ThemeOption,
|
||||||
val hideInviteAvatars: Boolean,
|
val hideInviteAvatars: Boolean,
|
||||||
val timelineMediaPreviewValue: MediaPreviewValue,
|
val timelineMediaPreviewValue: MediaPreviewValue,
|
||||||
|
val setHideInviteAvatarsAction: AsyncAction<Unit>,
|
||||||
|
val setTimelineMediaPreviewAction: AsyncAction<Unit>,
|
||||||
val eventSink: (AdvancedSettingsEvents) -> Unit
|
val eventSink: (AdvancedSettingsEvents) -> Unit
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
package io.element.android.features.preferences.impl.advanced
|
package io.element.android.features.preferences.impl.advanced
|
||||||
|
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||||
|
import io.element.android.libraries.architecture.AsyncAction
|
||||||
import io.element.android.libraries.matrix.api.media.MediaPreviewValue
|
import io.element.android.libraries.matrix.api.media.MediaPreviewValue
|
||||||
|
|
||||||
open class AdvancedSettingsStateProvider : PreviewParameterProvider<AdvancedSettingsState> {
|
open class AdvancedSettingsStateProvider : PreviewParameterProvider<AdvancedSettingsState> {
|
||||||
|
|
@ -18,7 +19,9 @@ open class AdvancedSettingsStateProvider : PreviewParameterProvider<AdvancedSett
|
||||||
aAdvancedSettingsState(isSharePresenceEnabled = true),
|
aAdvancedSettingsState(isSharePresenceEnabled = true),
|
||||||
aAdvancedSettingsState(doesCompressMedia = true),
|
aAdvancedSettingsState(doesCompressMedia = true),
|
||||||
aAdvancedSettingsState(hideInviteAvatars = true),
|
aAdvancedSettingsState(hideInviteAvatars = true),
|
||||||
aAdvancedSettingsState(timelineMediaPreviewValue = MediaPreviewValue.Off)
|
aAdvancedSettingsState(timelineMediaPreviewValue = MediaPreviewValue.Off),
|
||||||
|
aAdvancedSettingsState(setHideInviteAvatarsAction = AsyncAction.Loading),
|
||||||
|
aAdvancedSettingsState(setTimelineMediaPreviewAction = AsyncAction.Loading),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -29,6 +32,8 @@ fun aAdvancedSettingsState(
|
||||||
hideInviteAvatars: Boolean = false,
|
hideInviteAvatars: Boolean = false,
|
||||||
theme: ThemeOption = ThemeOption.System,
|
theme: ThemeOption = ThemeOption.System,
|
||||||
timelineMediaPreviewValue: MediaPreviewValue = MediaPreviewValue.On,
|
timelineMediaPreviewValue: MediaPreviewValue = MediaPreviewValue.On,
|
||||||
|
setTimelineMediaPreviewAction: AsyncAction<Unit> = AsyncAction.Uninitialized,
|
||||||
|
setHideInviteAvatarsAction: AsyncAction<Unit> = AsyncAction.Uninitialized,
|
||||||
eventSink: (AdvancedSettingsEvents) -> Unit = {},
|
eventSink: (AdvancedSettingsEvents) -> Unit = {},
|
||||||
) = AdvancedSettingsState(
|
) = AdvancedSettingsState(
|
||||||
isDeveloperModeEnabled = isDeveloperModeEnabled,
|
isDeveloperModeEnabled = isDeveloperModeEnabled,
|
||||||
|
|
@ -37,5 +42,7 @@ fun aAdvancedSettingsState(
|
||||||
theme = theme,
|
theme = theme,
|
||||||
hideInviteAvatars = hideInviteAvatars,
|
hideInviteAvatars = hideInviteAvatars,
|
||||||
timelineMediaPreviewValue = timelineMediaPreviewValue,
|
timelineMediaPreviewValue = timelineMediaPreviewValue,
|
||||||
|
setTimelineMediaPreviewAction = setTimelineMediaPreviewAction,
|
||||||
|
setHideInviteAvatarsAction = setHideInviteAvatarsAction,
|
||||||
eventSink = eventSink
|
eventSink = eventSink
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,109 @@
|
||||||
|
/*
|
||||||
|
* 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.features.preferences.impl.advanced
|
||||||
|
|
||||||
|
import androidx.compose.runtime.State
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import com.squareup.anvil.annotations.ContributesBinding
|
||||||
|
import io.element.android.libraries.architecture.AsyncAction
|
||||||
|
import io.element.android.libraries.architecture.runUpdatingState
|
||||||
|
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatcher
|
||||||
|
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarMessage
|
||||||
|
import io.element.android.libraries.di.SessionScope
|
||||||
|
import io.element.android.libraries.di.SingleIn
|
||||||
|
import io.element.android.libraries.di.annotations.SessionCoroutineScope
|
||||||
|
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.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>>
|
||||||
|
|
||||||
|
fun setHideInviteAvatars(hide: Boolean)
|
||||||
|
fun setTimelineMediaPreviewValue(value: MediaPreviewValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
@ContributesBinding(SessionScope::class, boundType = MediaPreviewConfigStateStore::class)
|
||||||
|
@SingleIn(SessionScope::class)
|
||||||
|
class DefaultMediaPreviewConfigStateStore @Inject constructor(
|
||||||
|
@SessionCoroutineScope
|
||||||
|
private val sessionCoroutineScope: CoroutineScope,
|
||||||
|
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)
|
||||||
|
|
||||||
|
init {
|
||||||
|
val configFlow = mediaPreviewService.getMediaPreviewConfigFlow().shareIn(sessionCoroutineScope, SharingStarted.Eagerly)
|
||||||
|
val hideInviteAvatarsFlow = configFlow.mapNotNull { it?.hideInviteAvatar }.distinctUntilChanged()
|
||||||
|
val timelineMediaPreviewFlow = configFlow.mapNotNull { it?.mediaPreviewValue }.distinctUntilChanged()
|
||||||
|
|
||||||
|
hideInviteAvatarsFlow
|
||||||
|
.onEach {
|
||||||
|
Timber.d("Hide invi@te avatars changed to $it")
|
||||||
|
hideInviteAvatars.value = it
|
||||||
|
}
|
||||||
|
.launchIn(sessionCoroutineScope)
|
||||||
|
|
||||||
|
timelineMediaPreviewFlow
|
||||||
|
.onEach {
|
||||||
|
Timber.d("Timeline media preview value changed to $it")
|
||||||
|
timelineMediaPreviewValue.value = it
|
||||||
|
}
|
||||||
|
.launchIn(sessionCoroutineScope)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setHideInviteAvatars(hide: Boolean) {
|
||||||
|
sessionCoroutineScope.launch {
|
||||||
|
Timber.d("Setting hide invite avatars to $hide")
|
||||||
|
val prevHideInviteAvatars = hideInviteAvatars.value
|
||||||
|
hideInviteAvatars.value = hide
|
||||||
|
runUpdatingState(setHideInviteAvatarsAction) {
|
||||||
|
mediaPreviewService
|
||||||
|
.setHideInviteAvatars(hide)
|
||||||
|
.onFailure {
|
||||||
|
hideInviteAvatars.value = prevHideInviteAvatars
|
||||||
|
snackbarDispatcher.post(SnackbarMessage(CommonStrings.common_something_went_wrong_message))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setTimelineMediaPreviewValue(value: MediaPreviewValue) {
|
||||||
|
sessionCoroutineScope.launch {
|
||||||
|
Timber.d("Setting timeline media preview value to $value")
|
||||||
|
val prevTimelineMediaPreviewValue = timelineMediaPreviewValue.value
|
||||||
|
timelineMediaPreviewValue.value = value
|
||||||
|
runUpdatingState(setTimelineMediaPreviewAction) {
|
||||||
|
mediaPreviewService
|
||||||
|
.setMediaPreviewValue(value)
|
||||||
|
.onFailure {
|
||||||
|
timelineMediaPreviewValue.value = prevTimelineMediaPreviewValue
|
||||||
|
snackbarDispatcher.post(SnackbarMessage(CommonStrings.common_something_went_wrong_message))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -11,10 +11,14 @@ import app.cash.molecule.RecompositionMode
|
||||||
import app.cash.molecule.moleculeFlow
|
import app.cash.molecule.moleculeFlow
|
||||||
import app.cash.turbine.test
|
import app.cash.turbine.test
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import io.element.android.libraries.matrix.api.MatrixClient
|
||||||
|
import io.element.android.libraries.matrix.api.media.MediaPreviewConfig
|
||||||
import io.element.android.libraries.matrix.api.media.MediaPreviewValue
|
import io.element.android.libraries.matrix.api.media.MediaPreviewValue
|
||||||
|
import io.element.android.libraries.matrix.test.FakeMatrixClient
|
||||||
import io.element.android.libraries.preferences.test.InMemoryAppPreferencesStore
|
import io.element.android.libraries.preferences.test.InMemoryAppPreferencesStore
|
||||||
import io.element.android.libraries.preferences.test.InMemorySessionPreferencesStore
|
import io.element.android.libraries.preferences.test.InMemorySessionPreferencesStore
|
||||||
import io.element.android.tests.testutils.WarmUpRule
|
import io.element.android.tests.testutils.WarmUpRule
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
@ -144,7 +148,12 @@ class AdvancedSettingsPresenterTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `present - timeline media preview value`() = runTest {
|
fun `present - timeline media preview value`() = runTest {
|
||||||
val presenter = createAdvancedSettingsPresenter()
|
val mediaPreviewConfigFlow = MutableStateFlow<MediaPreviewConfig?>(null)
|
||||||
|
val presenter = createAdvancedSettingsPresenter(
|
||||||
|
matrixClient = FakeMatrixClient(
|
||||||
|
mediaPreviewConfigFlow = mediaPreviewConfigFlow
|
||||||
|
)
|
||||||
|
)
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
moleculeFlow(RecompositionMode.Immediate) {
|
||||||
presenter.present()
|
presenter.present()
|
||||||
}.test {
|
}.test {
|
||||||
|
|
@ -165,8 +174,10 @@ class AdvancedSettingsPresenterTest {
|
||||||
private fun createAdvancedSettingsPresenter(
|
private fun createAdvancedSettingsPresenter(
|
||||||
appPreferencesStore: InMemoryAppPreferencesStore = InMemoryAppPreferencesStore(),
|
appPreferencesStore: InMemoryAppPreferencesStore = InMemoryAppPreferencesStore(),
|
||||||
sessionPreferencesStore: InMemorySessionPreferencesStore = InMemorySessionPreferencesStore(),
|
sessionPreferencesStore: InMemorySessionPreferencesStore = InMemorySessionPreferencesStore(),
|
||||||
|
matrixClient: MatrixClient = FakeMatrixClient(),
|
||||||
) = AdvancedSettingsPresenter(
|
) = AdvancedSettingsPresenter(
|
||||||
appPreferencesStore = appPreferencesStore,
|
appPreferencesStore = appPreferencesStore,
|
||||||
sessionPreferencesStore = sessionPreferencesStore,
|
sessionPreferencesStore = sessionPreferencesStore,
|
||||||
|
matrixClient = matrixClient,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,10 +22,8 @@ interface AppPreferencesStore {
|
||||||
suspend fun setTheme(theme: String)
|
suspend fun setTheme(theme: String)
|
||||||
fun getThemeFlow(): Flow<String?>
|
fun getThemeFlow(): Flow<String?>
|
||||||
|
|
||||||
suspend fun setHideInviteAvatars(value: Boolean)
|
|
||||||
fun getHideInviteAvatarsFlow(): Flow<Boolean>
|
fun getHideInviteAvatarsFlow(): Flow<Boolean>
|
||||||
|
|
||||||
suspend fun setTimelineMediaPreviewValue(value: MediaPreviewValue)
|
|
||||||
fun getTimelineMediaPreviewValueFlow(): Flow<MediaPreviewValue>
|
fun getTimelineMediaPreviewValueFlow(): Flow<MediaPreviewValue>
|
||||||
|
|
||||||
suspend fun setTracingLogLevel(logLevel: LogLevel)
|
suspend fun setTracingLogLevel(logLevel: LogLevel)
|
||||||
|
|
|
||||||
|
|
@ -85,24 +85,12 @@ class DefaultAppPreferencesStore @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun setHideInviteAvatars(value: Boolean) {
|
|
||||||
store.edit { prefs ->
|
|
||||||
prefs[hideInviteAvatarsKey] = value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getHideInviteAvatarsFlow(): Flow<Boolean> {
|
override fun getHideInviteAvatarsFlow(): Flow<Boolean> {
|
||||||
return store.data.map { prefs ->
|
return store.data.map { prefs ->
|
||||||
prefs[hideInviteAvatarsKey] == true
|
prefs[hideInviteAvatarsKey] == true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun setTimelineMediaPreviewValue(value: MediaPreviewValue) {
|
|
||||||
store.edit { prefs ->
|
|
||||||
prefs[timelineMediaPreviewValueKey] = value.name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getTimelineMediaPreviewValueFlow(): Flow<MediaPreviewValue> {
|
override fun getTimelineMediaPreviewValueFlow(): Flow<MediaPreviewValue> {
|
||||||
return store.data.map { prefs ->
|
return store.data.map { prefs ->
|
||||||
prefs[timelineMediaPreviewValueKey]?.let { MediaPreviewValue.valueOf(it) } ?: MediaPreviewValue.On
|
prefs[timelineMediaPreviewValueKey]?.let { MediaPreviewValue.valueOf(it) } ?: MediaPreviewValue.On
|
||||||
|
|
|
||||||
|
|
@ -55,18 +55,10 @@ class InMemoryAppPreferencesStore(
|
||||||
return theme
|
return theme
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun setHideInviteAvatars(value: Boolean) {
|
|
||||||
hideInviteAvatars.value = value
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getHideInviteAvatarsFlow(): Flow<Boolean> {
|
override fun getHideInviteAvatarsFlow(): Flow<Boolean> {
|
||||||
return hideInviteAvatars
|
return hideInviteAvatars
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun setTimelineMediaPreviewValue(value: MediaPreviewValue) {
|
|
||||||
timelineMediaPreviewValue.value = value
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getTimelineMediaPreviewValueFlow(): Flow<MediaPreviewValue> {
|
override fun getTimelineMediaPreviewValueFlow(): Flow<MediaPreviewValue> {
|
||||||
return timelineMediaPreviewValue
|
return timelineMediaPreviewValue
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,6 @@ import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageTy
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.VideoMessageType
|
import io.element.android.libraries.matrix.api.timeline.item.event.VideoMessageType
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.VoiceMessageType
|
import io.element.android.libraries.matrix.api.timeline.item.event.VoiceMessageType
|
||||||
import io.element.android.libraries.matrix.ui.messages.toPlainText
|
import io.element.android.libraries.matrix.ui.messages.toPlainText
|
||||||
import io.element.android.libraries.preferences.api.store.AppPreferencesStore
|
|
||||||
import io.element.android.libraries.push.impl.R
|
import io.element.android.libraries.push.impl.R
|
||||||
import io.element.android.libraries.push.impl.notifications.model.FallbackNotifiableEvent
|
import io.element.android.libraries.push.impl.notifications.model.FallbackNotifiableEvent
|
||||||
import io.element.android.libraries.push.impl.notifications.model.InviteNotifiableEvent
|
import io.element.android.libraries.push.impl.notifications.model.InviteNotifiableEvent
|
||||||
|
|
@ -50,7 +49,6 @@ import io.element.android.libraries.push.impl.notifications.model.ResolvedPushEv
|
||||||
import io.element.android.libraries.ui.strings.CommonStrings
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
import io.element.android.services.toolbox.api.strings.StringProvider
|
import io.element.android.services.toolbox.api.strings.StringProvider
|
||||||
import io.element.android.services.toolbox.api.systemclock.SystemClock
|
import io.element.android.services.toolbox.api.systemclock.SystemClock
|
||||||
import kotlinx.coroutines.flow.first
|
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
|
@ -79,7 +77,6 @@ class DefaultNotifiableEventResolver @Inject constructor(
|
||||||
@ApplicationContext private val context: Context,
|
@ApplicationContext private val context: Context,
|
||||||
private val permalinkParser: PermalinkParser,
|
private val permalinkParser: PermalinkParser,
|
||||||
private val callNotificationEventResolver: CallNotificationEventResolver,
|
private val callNotificationEventResolver: CallNotificationEventResolver,
|
||||||
private val appPreferencesStore: AppPreferencesStore,
|
|
||||||
) : NotifiableEventResolver {
|
) : NotifiableEventResolver {
|
||||||
override suspend fun resolveEvents(
|
override suspend fun resolveEvents(
|
||||||
sessionId: SessionId,
|
sessionId: SessionId,
|
||||||
|
|
@ -117,6 +114,7 @@ class DefaultNotifiableEventResolver @Inject constructor(
|
||||||
): Result<ResolvedPushEvent> = runCatchingExceptions {
|
): Result<ResolvedPushEvent> = runCatchingExceptions {
|
||||||
when (val content = this.content) {
|
when (val content = this.content) {
|
||||||
is NotificationContent.MessageLike.RoomMessage -> {
|
is NotificationContent.MessageLike.RoomMessage -> {
|
||||||
|
val showMediaPreview = client.mediaPreviewService().getMediaPreviewValue() == MediaPreviewValue.On
|
||||||
val senderDisambiguatedDisplayName = getDisambiguatedDisplayName(content.senderId)
|
val senderDisambiguatedDisplayName = getDisambiguatedDisplayName(content.senderId)
|
||||||
val messageBody = descriptionFromMessageContent(content, senderDisambiguatedDisplayName)
|
val messageBody = descriptionFromMessageContent(content, senderDisambiguatedDisplayName)
|
||||||
val notifiableMessageEvent = buildNotifiableMessageEvent(
|
val notifiableMessageEvent = buildNotifiableMessageEvent(
|
||||||
|
|
@ -129,8 +127,8 @@ class DefaultNotifiableEventResolver @Inject constructor(
|
||||||
timestamp = this.timestamp,
|
timestamp = this.timestamp,
|
||||||
senderDisambiguatedDisplayName = senderDisambiguatedDisplayName,
|
senderDisambiguatedDisplayName = senderDisambiguatedDisplayName,
|
||||||
body = messageBody,
|
body = messageBody,
|
||||||
imageUriString = content.fetchImageIfPresent(client)?.toString(),
|
imageUriString = if (showMediaPreview) content.fetchImageIfPresent(client)?.toString() else null,
|
||||||
imageMimeType = content.getImageMimetype(),
|
imageMimeType = if (showMediaPreview) content.getImageMimetype() else null,
|
||||||
roomName = roomDisplayName,
|
roomName = roomDisplayName,
|
||||||
roomIsDm = isDm,
|
roomIsDm = isDm,
|
||||||
roomAvatarPath = roomAvatarUrl,
|
roomAvatarPath = roomAvatarUrl,
|
||||||
|
|
@ -323,9 +321,6 @@ class DefaultNotifiableEventResolver @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun NotificationContent.MessageLike.RoomMessage.fetchImageIfPresent(client: MatrixClient): Uri? {
|
private suspend fun NotificationContent.MessageLike.RoomMessage.fetchImageIfPresent(client: MatrixClient): Uri? {
|
||||||
if (appPreferencesStore.getTimelineMediaPreviewValueFlow().first() != MediaPreviewValue.On) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
val fileResult = when (val messageType = messageType) {
|
val fileResult = when (val messageType = messageType) {
|
||||||
is ImageMessageType -> notificationMediaRepoFactory.create(client)
|
is ImageMessageType -> notificationMediaRepoFactory.create(client)
|
||||||
.getMediaFile(
|
.getMediaFile(
|
||||||
|
|
@ -349,10 +344,7 @@ class DefaultNotifiableEventResolver @Inject constructor(
|
||||||
.getOrNull()
|
.getOrNull()
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun NotificationContent.MessageLike.RoomMessage.getImageMimetype(): String? {
|
private fun NotificationContent.MessageLike.RoomMessage.getImageMimetype(): String? {
|
||||||
if (appPreferencesStore.getTimelineMediaPreviewValueFlow().first() != MediaPreviewValue.On) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
return when (val messageType = messageType) {
|
return when (val messageType = messageType) {
|
||||||
is ImageMessageType -> messageType.info?.mimetype
|
is ImageMessageType -> messageType.info?.mimetype
|
||||||
is VideoMessageType -> null // Use the thumbnail here?
|
is VideoMessageType -> null // Use the thumbnail here?
|
||||||
|
|
|
||||||
|
|
@ -826,7 +826,6 @@ class DefaultNotifiableEventResolverTest {
|
||||||
private fun createDefaultNotifiableEventResolver(
|
private fun createDefaultNotifiableEventResolver(
|
||||||
notificationService: FakeNotificationService? = FakeNotificationService(),
|
notificationService: FakeNotificationService? = FakeNotificationService(),
|
||||||
notificationResult: Result<Map<EventId, NotificationData>> = Result.success(emptyMap()),
|
notificationResult: Result<Map<EventId, NotificationData>> = Result.success(emptyMap()),
|
||||||
appPreferencesStore: AppPreferencesStore = InMemoryAppPreferencesStore(),
|
|
||||||
callNotificationEventResolver: FakeCallNotificationEventResolver = FakeCallNotificationEventResolver(),
|
callNotificationEventResolver: FakeCallNotificationEventResolver = FakeCallNotificationEventResolver(),
|
||||||
): DefaultNotifiableEventResolver {
|
): DefaultNotifiableEventResolver {
|
||||||
val context = RuntimeEnvironment.getApplication() as Context
|
val context = RuntimeEnvironment.getApplication() as Context
|
||||||
|
|
@ -849,7 +848,6 @@ class DefaultNotifiableEventResolverTest {
|
||||||
context = context,
|
context = context,
|
||||||
permalinkParser = FakePermalinkParser(),
|
permalinkParser = FakePermalinkParser(),
|
||||||
callNotificationEventResolver = callNotificationEventResolver,
|
callNotificationEventResolver = callNotificationEventResolver,
|
||||||
appPreferencesStore = appPreferencesStore,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue