change (preferences) : use PreferenceDropdown for appearance (and add some tests)
This commit is contained in:
parent
ce0bac55c5
commit
dffdb15cf0
9 changed files with 198 additions and 138 deletions
|
|
@ -7,16 +7,13 @@
|
||||||
|
|
||||||
package io.element.android.features.preferences.impl.advanced
|
package io.element.android.features.preferences.impl.advanced
|
||||||
|
|
||||||
import io.element.android.compound.theme.Theme
|
|
||||||
import io.element.android.libraries.matrix.api.media.MediaPreviewValue
|
import io.element.android.libraries.matrix.api.media.MediaPreviewValue
|
||||||
|
|
||||||
sealed interface AdvancedSettingsEvents {
|
sealed interface AdvancedSettingsEvents {
|
||||||
data class SetDeveloperModeEnabled(val enabled: Boolean) : AdvancedSettingsEvents
|
data class SetDeveloperModeEnabled(val enabled: Boolean) : AdvancedSettingsEvents
|
||||||
data class SetSharePresenceEnabled(val enabled: Boolean) : AdvancedSettingsEvents
|
data class SetSharePresenceEnabled(val enabled: Boolean) : AdvancedSettingsEvents
|
||||||
data class SetCompressMedia(val compress: Boolean) : AdvancedSettingsEvents
|
data class SetCompressMedia(val compress: Boolean) : AdvancedSettingsEvents
|
||||||
data object ChangeTheme : AdvancedSettingsEvents
|
data class SetTheme(val theme: ThemeOption) : AdvancedSettingsEvents
|
||||||
data object CancelChangeTheme : AdvancedSettingsEvents
|
|
||||||
data class SetTheme(val theme: Theme) : AdvancedSettingsEvents
|
|
||||||
data class SetTimelineMediaPreviewValue(val value: MediaPreviewValue) : AdvancedSettingsEvents
|
data class SetTimelineMediaPreviewValue(val value: MediaPreviewValue) : AdvancedSettingsEvents
|
||||||
data class SetHideInviteAvatars(val value: Boolean) : AdvancedSettingsEvents
|
data class SetHideInviteAvatars(val value: Boolean) : AdvancedSettingsEvents
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,11 +9,10 @@ package io.element.android.features.preferences.impl.advanced
|
||||||
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
|
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.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.Presenter
|
import io.element.android.libraries.architecture.Presenter
|
||||||
|
|
@ -39,11 +38,9 @@ class AdvancedSettingsPresenter @Inject constructor(
|
||||||
val doesCompressMedia by remember {
|
val doesCompressMedia by remember {
|
||||||
sessionPreferencesStore.doesCompressMedia()
|
sessionPreferencesStore.doesCompressMedia()
|
||||||
}.collectAsState(initial = true)
|
}.collectAsState(initial = true)
|
||||||
val theme by remember {
|
val theme = remember {
|
||||||
appPreferencesStore.getThemeFlow().mapToTheme()
|
appPreferencesStore.getThemeFlow().mapToTheme()
|
||||||
}.collectAsState(initial = Theme.System)
|
}.collectAsState(initial = Theme.System)
|
||||||
var showChangeThemeDialog by remember { mutableStateOf(false) }
|
|
||||||
|
|
||||||
val hideInviteAvatars by remember {
|
val hideInviteAvatars by remember {
|
||||||
appPreferencesStore.getHideInviteAvatarsFlow()
|
appPreferencesStore.getHideInviteAvatarsFlow()
|
||||||
}.collectAsState(false)
|
}.collectAsState(false)
|
||||||
|
|
@ -52,6 +49,16 @@ class AdvancedSettingsPresenter @Inject constructor(
|
||||||
appPreferencesStore.getTimelineMediaPreviewValueFlow()
|
appPreferencesStore.getTimelineMediaPreviewValueFlow()
|
||||||
}.collectAsState(initial = MediaPreviewValue.On)
|
}.collectAsState(initial = MediaPreviewValue.On)
|
||||||
|
|
||||||
|
val themeOption by remember {
|
||||||
|
derivedStateOf {
|
||||||
|
when (theme.value) {
|
||||||
|
Theme.System -> ThemeOption.System
|
||||||
|
Theme.Dark -> ThemeOption.Dark
|
||||||
|
Theme.Light -> ThemeOption.Light
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun handleEvents(event: AdvancedSettingsEvents) {
|
fun handleEvents(event: AdvancedSettingsEvents) {
|
||||||
when (event) {
|
when (event) {
|
||||||
is AdvancedSettingsEvents.SetDeveloperModeEnabled -> localCoroutineScope.launch {
|
is AdvancedSettingsEvents.SetDeveloperModeEnabled -> localCoroutineScope.launch {
|
||||||
|
|
@ -63,11 +70,12 @@ class AdvancedSettingsPresenter @Inject constructor(
|
||||||
is AdvancedSettingsEvents.SetCompressMedia -> localCoroutineScope.launch {
|
is AdvancedSettingsEvents.SetCompressMedia -> localCoroutineScope.launch {
|
||||||
sessionPreferencesStore.setCompressMedia(event.compress)
|
sessionPreferencesStore.setCompressMedia(event.compress)
|
||||||
}
|
}
|
||||||
AdvancedSettingsEvents.CancelChangeTheme -> showChangeThemeDialog = false
|
|
||||||
AdvancedSettingsEvents.ChangeTheme -> showChangeThemeDialog = true
|
|
||||||
is AdvancedSettingsEvents.SetTheme -> localCoroutineScope.launch {
|
is AdvancedSettingsEvents.SetTheme -> localCoroutineScope.launch {
|
||||||
appPreferencesStore.setTheme(event.theme.name)
|
when (event.theme) {
|
||||||
showChangeThemeDialog = false
|
ThemeOption.System -> appPreferencesStore.setTheme(Theme.System.name)
|
||||||
|
ThemeOption.Dark -> appPreferencesStore.setTheme(Theme.Dark.name)
|
||||||
|
ThemeOption.Light -> appPreferencesStore.setTheme(Theme.Light.name)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
is AdvancedSettingsEvents.SetHideInviteAvatars -> localCoroutineScope.launch {
|
is AdvancedSettingsEvents.SetHideInviteAvatars -> localCoroutineScope.launch {
|
||||||
appPreferencesStore.setHideInviteAvatars(event.value)
|
appPreferencesStore.setHideInviteAvatars(event.value)
|
||||||
|
|
@ -82,8 +90,7 @@ class AdvancedSettingsPresenter @Inject constructor(
|
||||||
isDeveloperModeEnabled = isDeveloperModeEnabled,
|
isDeveloperModeEnabled = isDeveloperModeEnabled,
|
||||||
isSharePresenceEnabled = isSharePresenceEnabled,
|
isSharePresenceEnabled = isSharePresenceEnabled,
|
||||||
doesCompressMedia = doesCompressMedia,
|
doesCompressMedia = doesCompressMedia,
|
||||||
theme = theme,
|
theme = themeOption,
|
||||||
showChangeThemeDialog = showChangeThemeDialog,
|
|
||||||
hideInviteAvatars = hideInviteAvatars,
|
hideInviteAvatars = hideInviteAvatars,
|
||||||
timelineMediaPreviewValue = timelineMediaPreviewValue,
|
timelineMediaPreviewValue = timelineMediaPreviewValue,
|
||||||
eventSink = { handleEvents(it) }
|
eventSink = { handleEvents(it) }
|
||||||
|
|
|
||||||
|
|
@ -7,16 +7,33 @@
|
||||||
|
|
||||||
package io.element.android.features.preferences.impl.advanced
|
package io.element.android.features.preferences.impl.advanced
|
||||||
|
|
||||||
import io.element.android.compound.theme.Theme
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
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
|
||||||
|
|
||||||
data class AdvancedSettingsState(
|
data class AdvancedSettingsState(
|
||||||
val isDeveloperModeEnabled: Boolean,
|
val isDeveloperModeEnabled: Boolean,
|
||||||
val isSharePresenceEnabled: Boolean,
|
val isSharePresenceEnabled: Boolean,
|
||||||
val doesCompressMedia: Boolean,
|
val doesCompressMedia: Boolean,
|
||||||
val theme: Theme,
|
val theme: ThemeOption,
|
||||||
val showChangeThemeDialog: Boolean,
|
|
||||||
val hideInviteAvatars: Boolean,
|
val hideInviteAvatars: Boolean,
|
||||||
val timelineMediaPreviewValue: MediaPreviewValue,
|
val timelineMediaPreviewValue: MediaPreviewValue,
|
||||||
val eventSink: (AdvancedSettingsEvents) -> Unit
|
val eventSink: (AdvancedSettingsEvents) -> Unit
|
||||||
)
|
)
|
||||||
|
|
||||||
|
enum class ThemeOption : DropdownOption {
|
||||||
|
System {
|
||||||
|
@Composable
|
||||||
|
override fun getText(): String = stringResource(CommonStrings.common_system)
|
||||||
|
},
|
||||||
|
Dark {
|
||||||
|
@Composable
|
||||||
|
override fun getText(): String = stringResource(CommonStrings.common_dark)
|
||||||
|
},
|
||||||
|
Light {
|
||||||
|
@Composable
|
||||||
|
override fun getText(): String = stringResource(CommonStrings.common_light)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@
|
||||||
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.compound.theme.Theme
|
|
||||||
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> {
|
||||||
|
|
@ -16,7 +15,6 @@ open class AdvancedSettingsStateProvider : PreviewParameterProvider<AdvancedSett
|
||||||
get() = sequenceOf(
|
get() = sequenceOf(
|
||||||
aAdvancedSettingsState(),
|
aAdvancedSettingsState(),
|
||||||
aAdvancedSettingsState(isDeveloperModeEnabled = true),
|
aAdvancedSettingsState(isDeveloperModeEnabled = true),
|
||||||
aAdvancedSettingsState(showChangeThemeDialog = true),
|
|
||||||
aAdvancedSettingsState(isSharePresenceEnabled = true),
|
aAdvancedSettingsState(isSharePresenceEnabled = true),
|
||||||
aAdvancedSettingsState(doesCompressMedia = true),
|
aAdvancedSettingsState(doesCompressMedia = true),
|
||||||
aAdvancedSettingsState(hideInviteAvatars = true),
|
aAdvancedSettingsState(hideInviteAvatars = true),
|
||||||
|
|
@ -28,16 +26,15 @@ fun aAdvancedSettingsState(
|
||||||
isDeveloperModeEnabled: Boolean = false,
|
isDeveloperModeEnabled: Boolean = false,
|
||||||
isSharePresenceEnabled: Boolean = false,
|
isSharePresenceEnabled: Boolean = false,
|
||||||
doesCompressMedia: Boolean = false,
|
doesCompressMedia: Boolean = false,
|
||||||
showChangeThemeDialog: Boolean = false,
|
|
||||||
hideInviteAvatars: Boolean = false,
|
hideInviteAvatars: Boolean = false,
|
||||||
|
theme: ThemeOption = ThemeOption.System,
|
||||||
timelineMediaPreviewValue: MediaPreviewValue = MediaPreviewValue.On,
|
timelineMediaPreviewValue: MediaPreviewValue = MediaPreviewValue.On,
|
||||||
eventSink: (AdvancedSettingsEvents) -> Unit = {},
|
eventSink: (AdvancedSettingsEvents) -> Unit = {},
|
||||||
) = AdvancedSettingsState(
|
) = AdvancedSettingsState(
|
||||||
isDeveloperModeEnabled = isDeveloperModeEnabled,
|
isDeveloperModeEnabled = isDeveloperModeEnabled,
|
||||||
isSharePresenceEnabled = isSharePresenceEnabled,
|
isSharePresenceEnabled = isSharePresenceEnabled,
|
||||||
doesCompressMedia = doesCompressMedia,
|
doesCompressMedia = doesCompressMedia,
|
||||||
theme = Theme.System,
|
theme = theme,
|
||||||
showChangeThemeDialog = showChangeThemeDialog,
|
|
||||||
hideInviteAvatars = hideInviteAvatars,
|
hideInviteAvatars = hideInviteAvatars,
|
||||||
timelineMediaPreviewValue = timelineMediaPreviewValue,
|
timelineMediaPreviewValue = timelineMediaPreviewValue,
|
||||||
eventSink = eventSink
|
eventSink = eventSink
|
||||||
|
|
|
||||||
|
|
@ -12,14 +12,11 @@ import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||||
import im.vector.app.features.analytics.plan.Interaction
|
import im.vector.app.features.analytics.plan.Interaction
|
||||||
import io.element.android.compound.theme.Theme
|
|
||||||
import io.element.android.compound.theme.themes
|
|
||||||
import io.element.android.features.preferences.impl.R
|
import io.element.android.features.preferences.impl.R
|
||||||
import io.element.android.libraries.architecture.coverage.ExcludeFromCoverage
|
import io.element.android.libraries.architecture.coverage.ExcludeFromCoverage
|
||||||
import io.element.android.libraries.designsystem.components.dialogs.ListOption
|
|
||||||
import io.element.android.libraries.designsystem.components.dialogs.SingleSelectionDialog
|
|
||||||
import io.element.android.libraries.designsystem.components.list.ListItemContent
|
import io.element.android.libraries.designsystem.components.list.ListItemContent
|
||||||
import io.element.android.libraries.designsystem.components.preferences.PreferenceCategory
|
import io.element.android.libraries.designsystem.components.preferences.PreferenceCategory
|
||||||
|
import io.element.android.libraries.designsystem.components.preferences.PreferenceDropdown
|
||||||
import io.element.android.libraries.designsystem.components.preferences.PreferencePage
|
import io.element.android.libraries.designsystem.components.preferences.PreferencePage
|
||||||
import io.element.android.libraries.designsystem.components.preferences.PreferenceSwitch
|
import io.element.android.libraries.designsystem.components.preferences.PreferenceSwitch
|
||||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||||
|
|
@ -34,8 +31,7 @@ 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
|
||||||
import io.element.android.services.analytics.compose.LocalAnalyticsService
|
import io.element.android.services.analytics.compose.LocalAnalyticsService
|
||||||
import io.element.android.services.analyticsproviders.api.trackers.captureInteraction
|
import io.element.android.services.analyticsproviders.api.trackers.captureInteraction
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.toPersistentList
|
||||||
import kotlinx.collections.immutable.toImmutableList
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun AdvancedSettingsView(
|
fun AdvancedSettingsView(
|
||||||
|
|
@ -49,15 +45,12 @@ fun AdvancedSettingsView(
|
||||||
onBackClick = onBackClick,
|
onBackClick = onBackClick,
|
||||||
title = stringResource(id = CommonStrings.common_advanced_settings)
|
title = stringResource(id = CommonStrings.common_advanced_settings)
|
||||||
) {
|
) {
|
||||||
ListItem(
|
PreferenceDropdown(
|
||||||
headlineContent = {
|
title = stringResource(id = CommonStrings.common_appearance),
|
||||||
Text(text = stringResource(id = CommonStrings.common_appearance))
|
selectedOption = state.theme,
|
||||||
},
|
options = ThemeOption.entries.toPersistentList(),
|
||||||
trailingContent = ListItemContent.Text(
|
onSelectOption = { logLevel ->
|
||||||
state.theme.toHumanReadable()
|
state.eventSink(AdvancedSettingsEvents.SetTheme(logLevel))
|
||||||
),
|
|
||||||
onClick = {
|
|
||||||
state.eventSink(AdvancedSettingsEvents.ChangeTheme)
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
ListItem(
|
ListItem(
|
||||||
|
|
@ -108,21 +101,6 @@ fun AdvancedSettingsView(
|
||||||
)
|
)
|
||||||
ModerationAndSafety(state)
|
ModerationAndSafety(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state.showChangeThemeDialog) {
|
|
||||||
SingleSelectionDialog(
|
|
||||||
options = getOptions(),
|
|
||||||
initialSelection = themes.indexOf(state.theme),
|
|
||||||
onSelectOption = {
|
|
||||||
state.eventSink(
|
|
||||||
AdvancedSettingsEvents.SetTheme(
|
|
||||||
themes[it]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
},
|
|
||||||
onDismissRequest = { state.eventSink(AdvancedSettingsEvents.CancelChangeTheme) },
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -176,24 +154,6 @@ private fun ModerationAndSafety(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
|
||||||
private fun getOptions(): ImmutableList<ListOption> {
|
|
||||||
return themes.map {
|
|
||||||
ListOption(title = it.toHumanReadable())
|
|
||||||
}.toImmutableList()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
private fun Theme.toHumanReadable(): String {
|
|
||||||
return stringResource(
|
|
||||||
id = when (this) {
|
|
||||||
Theme.System -> CommonStrings.common_system
|
|
||||||
Theme.Dark -> CommonStrings.common_dark
|
|
||||||
Theme.Light -> CommonStrings.common_light
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@PreviewWithLargeHeight
|
@PreviewWithLargeHeight
|
||||||
@Composable
|
@Composable
|
||||||
internal fun AdvancedSettingsViewLightPreview(@PreviewParameter(AdvancedSettingsStateProvider::class) state: AdvancedSettingsState) =
|
internal fun AdvancedSettingsViewLightPreview(@PreviewParameter(AdvancedSettingsStateProvider::class) state: AdvancedSettingsState) =
|
||||||
|
|
|
||||||
|
|
@ -7,22 +7,28 @@
|
||||||
|
|
||||||
package io.element.android.features.preferences.impl.developer.tracing
|
package io.element.android.features.preferences.impl.developer.tracing
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
import io.element.android.libraries.designsystem.components.preferences.DropdownOption
|
import io.element.android.libraries.designsystem.components.preferences.DropdownOption
|
||||||
|
|
||||||
enum class LogLevelItem : DropdownOption {
|
enum class LogLevelItem : DropdownOption {
|
||||||
ERROR {
|
ERROR {
|
||||||
override val text: String = "Error"
|
@Composable
|
||||||
|
override fun getText(): String = "Error"
|
||||||
},
|
},
|
||||||
WARN {
|
WARN {
|
||||||
override val text: String = "Warn"
|
@Composable
|
||||||
|
override fun getText(): String = "Warn"
|
||||||
},
|
},
|
||||||
INFO {
|
INFO {
|
||||||
override val text: String = "Info"
|
@Composable
|
||||||
|
override fun getText(): String = "Info"
|
||||||
},
|
},
|
||||||
DEBUG {
|
DEBUG {
|
||||||
override val text: String = "Debug"
|
@Composable
|
||||||
|
override fun getText(): String = "Debug"
|
||||||
},
|
},
|
||||||
TRACE {
|
TRACE {
|
||||||
override val text: String = "Trace"
|
@Composable
|
||||||
|
override fun getText(): String = "Trace"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,11 +11,10 @@ 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.compound.theme.Theme
|
import io.element.android.libraries.matrix.api.media.MediaPreviewValue
|
||||||
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 io.element.android.tests.testutils.awaitLastSequentialItem
|
|
||||||
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
|
||||||
|
|
@ -30,12 +29,12 @@ class AdvancedSettingsPresenterTest {
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
moleculeFlow(RecompositionMode.Immediate) {
|
||||||
presenter.present()
|
presenter.present()
|
||||||
}.test {
|
}.test {
|
||||||
val initialState = awaitLastSequentialItem()
|
with(awaitItem()) {
|
||||||
assertThat(initialState.isDeveloperModeEnabled).isFalse()
|
assertThat(isDeveloperModeEnabled).isFalse()
|
||||||
assertThat(initialState.showChangeThemeDialog).isFalse()
|
assertThat(isSharePresenceEnabled).isTrue()
|
||||||
assertThat(initialState.isSharePresenceEnabled).isTrue()
|
assertThat(doesCompressMedia).isTrue()
|
||||||
assertThat(initialState.doesCompressMedia).isTrue()
|
assertThat(theme).isEqualTo(ThemeOption.System)
|
||||||
assertThat(initialState.theme).isEqualTo(Theme.System)
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -45,12 +44,17 @@ class AdvancedSettingsPresenterTest {
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
moleculeFlow(RecompositionMode.Immediate) {
|
||||||
presenter.present()
|
presenter.present()
|
||||||
}.test {
|
}.test {
|
||||||
val initialState = awaitLastSequentialItem()
|
with(awaitItem()) {
|
||||||
assertThat(initialState.isDeveloperModeEnabled).isFalse()
|
assertThat(isDeveloperModeEnabled).isFalse()
|
||||||
initialState.eventSink.invoke(AdvancedSettingsEvents.SetDeveloperModeEnabled(true))
|
eventSink(AdvancedSettingsEvents.SetDeveloperModeEnabled(true))
|
||||||
assertThat(awaitItem().isDeveloperModeEnabled).isTrue()
|
}
|
||||||
initialState.eventSink.invoke(AdvancedSettingsEvents.SetDeveloperModeEnabled(false))
|
with(awaitItem()) {
|
||||||
assertThat(awaitItem().isDeveloperModeEnabled).isFalse()
|
assertThat(isDeveloperModeEnabled).isTrue()
|
||||||
|
eventSink(AdvancedSettingsEvents.SetDeveloperModeEnabled(false))
|
||||||
|
}
|
||||||
|
with(awaitItem()) {
|
||||||
|
assertThat(isDeveloperModeEnabled).isFalse()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -60,12 +64,17 @@ class AdvancedSettingsPresenterTest {
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
moleculeFlow(RecompositionMode.Immediate) {
|
||||||
presenter.present()
|
presenter.present()
|
||||||
}.test {
|
}.test {
|
||||||
val initialState = awaitLastSequentialItem()
|
with(awaitItem()) {
|
||||||
assertThat(initialState.isSharePresenceEnabled).isTrue()
|
assertThat(isSharePresenceEnabled).isTrue()
|
||||||
initialState.eventSink.invoke(AdvancedSettingsEvents.SetSharePresenceEnabled(false))
|
eventSink(AdvancedSettingsEvents.SetSharePresenceEnabled(false))
|
||||||
assertThat(awaitItem().isSharePresenceEnabled).isFalse()
|
}
|
||||||
initialState.eventSink.invoke(AdvancedSettingsEvents.SetSharePresenceEnabled(true))
|
with(awaitItem()) {
|
||||||
assertThat(awaitItem().isSharePresenceEnabled).isTrue()
|
assertThat(isSharePresenceEnabled).isFalse()
|
||||||
|
eventSink(AdvancedSettingsEvents.SetSharePresenceEnabled(true))
|
||||||
|
}
|
||||||
|
with(awaitItem()) {
|
||||||
|
assertThat(isSharePresenceEnabled).isTrue()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -75,12 +84,17 @@ class AdvancedSettingsPresenterTest {
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
moleculeFlow(RecompositionMode.Immediate) {
|
||||||
presenter.present()
|
presenter.present()
|
||||||
}.test {
|
}.test {
|
||||||
val initialState = awaitLastSequentialItem()
|
with(awaitItem()) {
|
||||||
assertThat(initialState.doesCompressMedia).isTrue()
|
assertThat(doesCompressMedia).isTrue()
|
||||||
initialState.eventSink.invoke(AdvancedSettingsEvents.SetCompressMedia(false))
|
eventSink(AdvancedSettingsEvents.SetCompressMedia(false))
|
||||||
assertThat(awaitItem().doesCompressMedia).isFalse()
|
}
|
||||||
initialState.eventSink.invoke(AdvancedSettingsEvents.SetCompressMedia(true))
|
with(awaitItem()) {
|
||||||
assertThat(awaitItem().doesCompressMedia).isTrue()
|
assertThat(doesCompressMedia).isFalse()
|
||||||
|
eventSink(AdvancedSettingsEvents.SetCompressMedia(true))
|
||||||
|
}
|
||||||
|
with(awaitItem()) {
|
||||||
|
assertThat(doesCompressMedia).isTrue()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -90,20 +104,61 @@ class AdvancedSettingsPresenterTest {
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
moleculeFlow(RecompositionMode.Immediate) {
|
||||||
presenter.present()
|
presenter.present()
|
||||||
}.test {
|
}.test {
|
||||||
val initialState = awaitLastSequentialItem()
|
with(awaitItem()) {
|
||||||
initialState.eventSink.invoke(AdvancedSettingsEvents.ChangeTheme)
|
assertThat(theme).isEqualTo(ThemeOption.System)
|
||||||
val withDialog = awaitItem()
|
eventSink(AdvancedSettingsEvents.SetTheme(ThemeOption.Dark))
|
||||||
assertThat(withDialog.showChangeThemeDialog).isTrue()
|
}
|
||||||
// Cancel
|
with(awaitItem()) {
|
||||||
withDialog.eventSink(AdvancedSettingsEvents.CancelChangeTheme)
|
assertThat(theme).isEqualTo(ThemeOption.Dark)
|
||||||
val withoutDialog = awaitItem()
|
eventSink(AdvancedSettingsEvents.SetTheme(ThemeOption.Light))
|
||||||
assertThat(withoutDialog.showChangeThemeDialog).isFalse()
|
}
|
||||||
withDialog.eventSink.invoke(AdvancedSettingsEvents.ChangeTheme)
|
with(awaitItem()) {
|
||||||
assertThat(awaitItem().showChangeThemeDialog).isTrue()
|
assertThat(theme).isEqualTo(ThemeOption.Light)
|
||||||
withDialog.eventSink(AdvancedSettingsEvents.SetTheme(Theme.Light))
|
eventSink(AdvancedSettingsEvents.SetTheme(ThemeOption.System))
|
||||||
val withNewTheme = awaitItem()
|
}
|
||||||
assertThat(withNewTheme.showChangeThemeDialog).isFalse()
|
with(awaitItem()) {
|
||||||
assertThat(withNewTheme.theme).isEqualTo(Theme.Light)
|
assertThat(theme).isEqualTo(ThemeOption.System)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `present - hide invite avatars`() = runTest {
|
||||||
|
val presenter = createAdvancedSettingsPresenter()
|
||||||
|
moleculeFlow(RecompositionMode.Immediate) {
|
||||||
|
presenter.present()
|
||||||
|
}.test {
|
||||||
|
with(awaitItem()) {
|
||||||
|
assertThat(hideInviteAvatars).isFalse()
|
||||||
|
eventSink(AdvancedSettingsEvents.SetHideInviteAvatars(true))
|
||||||
|
}
|
||||||
|
with(awaitItem()) {
|
||||||
|
assertThat(hideInviteAvatars).isTrue()
|
||||||
|
eventSink(AdvancedSettingsEvents.SetHideInviteAvatars(false))
|
||||||
|
}
|
||||||
|
with(awaitItem()) {
|
||||||
|
assertThat(hideInviteAvatars).isFalse()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `present - timeline media preview value`() = runTest {
|
||||||
|
val presenter = createAdvancedSettingsPresenter()
|
||||||
|
moleculeFlow(RecompositionMode.Immediate) {
|
||||||
|
presenter.present()
|
||||||
|
}.test {
|
||||||
|
with(awaitItem()) {
|
||||||
|
assertThat(timelineMediaPreviewValue).isEqualTo(MediaPreviewValue.On)
|
||||||
|
eventSink(AdvancedSettingsEvents.SetTimelineMediaPreviewValue(MediaPreviewValue.Off))
|
||||||
|
}
|
||||||
|
with(awaitItem()) {
|
||||||
|
assertThat(timelineMediaPreviewValue).isEqualTo(MediaPreviewValue.Off)
|
||||||
|
eventSink(AdvancedSettingsEvents.SetTimelineMediaPreviewValue(MediaPreviewValue.Private))
|
||||||
|
}
|
||||||
|
with(awaitItem()) {
|
||||||
|
assertThat(timelineMediaPreviewValue).isEqualTo(MediaPreviewValue.Private)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,8 @@ import androidx.compose.ui.test.junit4.createAndroidComposeRule
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import im.vector.app.features.analytics.plan.Interaction
|
import im.vector.app.features.analytics.plan.Interaction
|
||||||
import io.element.android.compound.theme.Theme
|
|
||||||
import io.element.android.features.preferences.impl.R
|
import io.element.android.features.preferences.impl.R
|
||||||
|
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
|
||||||
import io.element.android.services.analytics.api.AnalyticsService
|
import io.element.android.services.analytics.api.AnalyticsService
|
||||||
import io.element.android.services.analytics.compose.LocalAnalyticsService
|
import io.element.android.services.analytics.compose.LocalAnalyticsService
|
||||||
|
|
@ -29,6 +29,7 @@ import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.rules.TestRule
|
import org.junit.rules.TestRule
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
|
import org.robolectric.annotation.Config
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4::class)
|
@RunWith(AndroidJUnit4::class)
|
||||||
class AdvancedSettingsViewTest {
|
class AdvancedSettingsViewTest {
|
||||||
|
|
@ -49,29 +50,17 @@ class AdvancedSettingsViewTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `clicking on Appearance emits the expected event`() {
|
|
||||||
val eventsRecorder = EventsRecorder<AdvancedSettingsEvents>()
|
|
||||||
rule.setAdvancedSettingsView(
|
|
||||||
state = aAdvancedSettingsState(
|
|
||||||
eventSink = eventsRecorder
|
|
||||||
),
|
|
||||||
)
|
|
||||||
rule.clickOn(CommonStrings.common_appearance)
|
|
||||||
eventsRecorder.assertSingle(AdvancedSettingsEvents.ChangeTheme)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `clicking on other theme emits the expected event`() {
|
fun `clicking on other theme emits the expected event`() {
|
||||||
val eventsRecorder = EventsRecorder<AdvancedSettingsEvents>()
|
val eventsRecorder = EventsRecorder<AdvancedSettingsEvents>()
|
||||||
rule.setAdvancedSettingsView(
|
rule.setAdvancedSettingsView(
|
||||||
state = aAdvancedSettingsState(
|
state = aAdvancedSettingsState(
|
||||||
eventSink = eventsRecorder,
|
eventSink = eventsRecorder,
|
||||||
showChangeThemeDialog = true
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
rule.clickOn(CommonStrings.common_appearance)
|
||||||
rule.clickOn(CommonStrings.common_dark)
|
rule.clickOn(CommonStrings.common_dark)
|
||||||
eventsRecorder.assertSingle(AdvancedSettingsEvents.SetTheme(Theme.Dark))
|
eventsRecorder.assertSingle(AdvancedSettingsEvents.SetTheme(ThemeOption.Dark))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -140,6 +129,34 @@ class AdvancedSettingsViewTest {
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Config(qualifiers = "h640dp")
|
||||||
|
fun `clicking on hide invite avatars emits the expected event`() {
|
||||||
|
val eventsRecorder = EventsRecorder<AdvancedSettingsEvents>()
|
||||||
|
rule.setAdvancedSettingsView(
|
||||||
|
state = aAdvancedSettingsState(
|
||||||
|
eventSink = eventsRecorder,
|
||||||
|
hideInviteAvatars = false
|
||||||
|
),
|
||||||
|
)
|
||||||
|
rule.clickOn(R.string.screen_advanced_settings_hide_invite_avatars_toggle_title)
|
||||||
|
eventsRecorder.assertSingle(AdvancedSettingsEvents.SetHideInviteAvatars(true))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Config(qualifiers = "h640dp")
|
||||||
|
fun `clicking on timeline media preview emits the expected event`() {
|
||||||
|
val eventsRecorder = EventsRecorder<AdvancedSettingsEvents>()
|
||||||
|
rule.setAdvancedSettingsView(
|
||||||
|
state = aAdvancedSettingsState(
|
||||||
|
eventSink = eventsRecorder,
|
||||||
|
timelineMediaPreviewValue = MediaPreviewValue.On
|
||||||
|
),
|
||||||
|
)
|
||||||
|
rule.clickOn(R.string.screen_advanced_settings_show_media_timeline_always_hide)
|
||||||
|
eventsRecorder.assertSingle(AdvancedSettingsEvents.SetTimelineMediaPreviewValue(MediaPreviewValue.Off))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setAdvancedSettingsView(
|
private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setAdvancedSettingsView(
|
||||||
|
|
|
||||||
|
|
@ -99,9 +99,10 @@ fun <T : DropdownOption> PreferenceDropdown(
|
||||||
*/
|
*/
|
||||||
interface DropdownOption {
|
interface DropdownOption {
|
||||||
/**
|
/**
|
||||||
* The text to display for this option.
|
* Returns the text to be displayed for this option.
|
||||||
*/
|
*/
|
||||||
val text: String
|
@Composable
|
||||||
|
fun getText(): String
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -123,7 +124,7 @@ private fun <T : DropdownOption> DropdownTrailingContent(
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = selectedOption?.text.orEmpty(),
|
text = selectedOption?.getText().orEmpty(),
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
style = ElementTheme.typography.fontBodyMdRegular,
|
style = ElementTheme.typography.fontBodyMdRegular,
|
||||||
color = ElementTheme.colors.textSecondary,
|
color = ElementTheme.colors.textSecondary,
|
||||||
|
|
@ -139,7 +140,7 @@ private fun <T : DropdownOption> DropdownTrailingContent(
|
||||||
DropdownMenuItem(
|
DropdownMenuItem(
|
||||||
text = {
|
text = {
|
||||||
Text(
|
Text(
|
||||||
text = option.text,
|
text = option.getText(),
|
||||||
style = ElementTheme.typography.fontBodyMdRegular
|
style = ElementTheme.typography.fontBodyMdRegular
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
@ -158,13 +159,16 @@ private fun <T : DropdownOption> DropdownTrailingContent(
|
||||||
internal fun PreferenceDropdownPreview() = ElementThemedPreview {
|
internal fun PreferenceDropdownPreview() = ElementThemedPreview {
|
||||||
val options = listOf(
|
val options = listOf(
|
||||||
object : DropdownOption {
|
object : DropdownOption {
|
||||||
override val text = "Option 1"
|
@Composable
|
||||||
|
override fun getText(): String = "Option 1"
|
||||||
},
|
},
|
||||||
object : DropdownOption {
|
object : DropdownOption {
|
||||||
override val text = "Option 2"
|
@Composable
|
||||||
|
override fun getText(): String = "Option 2"
|
||||||
},
|
},
|
||||||
object : DropdownOption {
|
object : DropdownOption {
|
||||||
override val text = "Option 3"
|
@Composable
|
||||||
|
override fun getText(): String = "Option 3"
|
||||||
},
|
},
|
||||||
).toImmutableList()
|
).toImmutableList()
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue