From 7091ad2e01f30351ef3a80d06c316fbc6c32f2a0 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 14 Sep 2023 10:25:39 +0200 Subject: [PATCH 01/16] Add Advanced Settings screen in the preferences. --- features/preferences/impl/build.gradle.kts | 2 + .../preferences/impl/PreferencesFlowNode.kt | 13 +++- .../impl/advanced/AdvancedSettingsEvents.kt | 22 ++++++ .../impl/advanced/AdvancedSettingsNode.kt | 45 +++++++++++ .../advanced/AdvancedSettingsPresenter.kt | 59 +++++++++++++++ .../impl/advanced/AdvancedSettingsState.kt | 23 ++++++ .../advanced/AdvancedSettingsStateProvider.kt | 37 +++++++++ .../impl/advanced/AdvancedSettingsView.kt | 63 ++++++++++++++++ .../impl/root/PreferencesRootNode.kt | 6 ++ .../impl/root/PreferencesRootView.kt | 10 +++ libraries/preferences/api/build.gradle.kts | 27 +++++++ .../preferences/api/store/PreferencesStore.kt | 29 +++++++ libraries/preferences/impl/build.gradle.kts | 36 +++++++++ .../impl/store/DefaultPreferencesStore.kt | 75 +++++++++++++++++++ libraries/preferences/test/build.gradle.kts | 28 +++++++ .../test/InMemoryPreferencesStore.kt | 49 ++++++++++++ .../kotlin/extension/DependencyHandleScope.kt | 1 + 17 files changed, 524 insertions(+), 1 deletion(-) create mode 100644 features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsEvents.kt create mode 100644 features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsNode.kt create mode 100644 features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsPresenter.kt create mode 100644 features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsState.kt create mode 100644 features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsStateProvider.kt create mode 100644 features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsView.kt create mode 100644 libraries/preferences/api/build.gradle.kts create mode 100644 libraries/preferences/api/src/main/kotlin/io/element/android/features/preferences/api/store/PreferencesStore.kt create mode 100644 libraries/preferences/impl/build.gradle.kts create mode 100644 libraries/preferences/impl/src/main/kotlin/io/element/android/libraries/preferences/impl/store/DefaultPreferencesStore.kt create mode 100644 libraries/preferences/test/build.gradle.kts create mode 100644 libraries/preferences/test/src/main/kotlin/io/element/android/libraries/featureflag/test/InMemoryPreferencesStore.kt diff --git a/features/preferences/impl/build.gradle.kts b/features/preferences/impl/build.gradle.kts index e2df4cfa9a..447adb5fa3 100644 --- a/features/preferences/impl/build.gradle.kts +++ b/features/preferences/impl/build.gradle.kts @@ -42,6 +42,7 @@ dependencies { implementation(projects.libraries.network) implementation(projects.libraries.pushstore.api) implementation(projects.libraries.pushstore.test) + implementation(projects.libraries.preferences.api) implementation(projects.libraries.testtags) implementation(projects.libraries.uiStrings) implementation(projects.features.rageshake.api) @@ -55,6 +56,7 @@ dependencies { implementation(libs.accompanist.placeholder) implementation(libs.coil.compose) implementation(libs.androidx.browser) + implementation(libs.androidx.datastore.preferences) api(projects.features.preferences.api) ksp(libs.showkase.processor) diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/PreferencesFlowNode.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/PreferencesFlowNode.kt index 85ae3ac55f..238b4006e7 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/PreferencesFlowNode.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/PreferencesFlowNode.kt @@ -31,11 +31,12 @@ import dagger.assisted.AssistedInject import io.element.android.anvilannotations.ContributesNode import io.element.android.features.preferences.api.PreferencesEntryPoint import io.element.android.features.preferences.impl.about.AboutNode +import io.element.android.features.preferences.impl.advanced.AdvancedSettingsNode import io.element.android.features.preferences.impl.analytics.AnalyticsSettingsNode import io.element.android.features.preferences.impl.developer.DeveloperSettingsNode +import io.element.android.features.preferences.impl.developer.tracing.ConfigureTracingNode import io.element.android.features.preferences.impl.notifications.NotificationSettingsNode import io.element.android.features.preferences.impl.notifications.edit.EditDefaultNotificationSettingNode -import io.element.android.features.preferences.impl.developer.tracing.ConfigureTracingNode import io.element.android.features.preferences.impl.root.PreferencesRootNode import io.element.android.libraries.architecture.BackstackNode import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler @@ -63,6 +64,9 @@ class PreferencesFlowNode @AssistedInject constructor( @Parcelize data object DeveloperSettings : NavTarget + @Parcelize + data object AdvancedSettings : NavTarget + @Parcelize data object ConfigureTracing : NavTarget @@ -106,6 +110,10 @@ class PreferencesFlowNode @AssistedInject constructor( override fun onOpenNotificationSettings() { backstack.push(NavTarget.NotificationSettings) } + + override fun onOpenAdvancedSettings() { + backstack.push(NavTarget.AdvancedSettings) + } } createNode(buildContext, plugins = listOf(callback)) } @@ -138,6 +146,9 @@ class PreferencesFlowNode @AssistedInject constructor( val input = EditDefaultNotificationSettingNode.Inputs(navTarget.isOneToOne) createNode(buildContext, plugins = listOf(input)) } + NavTarget.AdvancedSettings -> { + createNode(buildContext) + } } } diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsEvents.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsEvents.kt new file mode 100644 index 0000000000..37641d684c --- /dev/null +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsEvents.kt @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2023 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 io.element.android.features.preferences.impl.advanced + +sealed interface AdvancedSettingsEvents { + data class SetRichTextEditorEnabled(val enabled: Boolean) : AdvancedSettingsEvents + data class SetDeveloperModeEnabled(val enabled: Boolean) : AdvancedSettingsEvents +} diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsNode.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsNode.kt new file mode 100644 index 0000000000..f7f0fd2eb8 --- /dev/null +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsNode.kt @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2023 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 io.element.android.features.preferences.impl.advanced + +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import com.bumble.appyx.core.modality.BuildContext +import com.bumble.appyx.core.node.Node +import com.bumble.appyx.core.plugin.Plugin +import dagger.assisted.Assisted +import dagger.assisted.AssistedInject +import io.element.android.anvilannotations.ContributesNode +import io.element.android.libraries.di.SessionScope + +@ContributesNode(SessionScope::class) +class AdvancedSettingsNode @AssistedInject constructor( + @Assisted buildContext: BuildContext, + @Assisted plugins: List, + private val presenter: AdvancedSettingsPresenter, +) : Node(buildContext, plugins = plugins) { + + @Composable + override fun View(modifier: Modifier) { + val state = presenter.present() + AdvancedSettingsView( + state = state, + modifier = modifier, + onBackPressed = ::navigateUp + ) + } +} diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsPresenter.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsPresenter.kt new file mode 100644 index 0000000000..b30ca63dc8 --- /dev/null +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsPresenter.kt @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2023 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 io.element.android.features.preferences.impl.advanced + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.rememberCoroutineScope +import io.element.android.features.preferences.api.store.PreferencesStore +import io.element.android.libraries.architecture.Presenter +import kotlinx.coroutines.launch +import javax.inject.Inject + +class AdvancedSettingsPresenter @Inject constructor( + private val preferencesStore: PreferencesStore, +) : Presenter { + + @Composable + override fun present(): AdvancedSettingsState { + val localCoroutineScope = rememberCoroutineScope() + val isRichTextEditorEnabled by preferencesStore + .isRichTextEditorEnabledFlow() + .collectAsState(initial = false) + val isDeveloperModeEnabled by preferencesStore + .isDevelopModeEnabledFlow() + .collectAsState(initial = false) + + fun handleEvents(event: AdvancedSettingsEvents) { + when (event) { + is AdvancedSettingsEvents.SetRichTextEditorEnabled -> localCoroutineScope.launch { + preferencesStore.setRichTextEditorEnabled(event.enabled) + } + is AdvancedSettingsEvents.SetDeveloperModeEnabled -> localCoroutineScope.launch { + preferencesStore.setDevelopModeEnabled(event.enabled) + } + } + } + + return AdvancedSettingsState( + isRichTextEditorEnabled = isRichTextEditorEnabled, + isDeveloperModeEnabled = isDeveloperModeEnabled, + eventSink = ::handleEvents + ) + } +} diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsState.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsState.kt new file mode 100644 index 0000000000..19625b9ebc --- /dev/null +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsState.kt @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2023 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 io.element.android.features.preferences.impl.advanced + +data class AdvancedSettingsState constructor( + val isRichTextEditorEnabled: Boolean, + val isDeveloperModeEnabled: Boolean, + val eventSink: (AdvancedSettingsEvents) -> Unit +) diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsStateProvider.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsStateProvider.kt new file mode 100644 index 0000000000..5ab50c8a16 --- /dev/null +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsStateProvider.kt @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2023 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 io.element.android.features.preferences.impl.advanced + +import androidx.compose.ui.tooling.preview.PreviewParameterProvider + +open class AdvancedSettingsStateProvider : PreviewParameterProvider { + override val values: Sequence + get() = sequenceOf( + aAdvancedSettingsState(), + aAdvancedSettingsState(isRichTextEditorEnabled = true), + aAdvancedSettingsState(isDeveloperModeEnabled = true), + ) +} + +fun aAdvancedSettingsState( + isRichTextEditorEnabled: Boolean = false, + isDeveloperModeEnabled: Boolean = false, +) = AdvancedSettingsState( + isRichTextEditorEnabled = isRichTextEditorEnabled, + isDeveloperModeEnabled = isDeveloperModeEnabled, + eventSink = {} +) diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsView.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsView.kt new file mode 100644 index 0000000000..cff1454594 --- /dev/null +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsView.kt @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2023 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 io.element.android.features.preferences.impl.advanced + +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.PreviewParameter +import io.element.android.libraries.designsystem.components.preferences.PreferenceSwitch +import io.element.android.libraries.designsystem.components.preferences.PreferenceView +import io.element.android.libraries.designsystem.preview.DayNightPreviews +import io.element.android.libraries.designsystem.preview.ElementPreview +import io.element.android.libraries.ui.strings.CommonStrings + +@Composable +fun AdvancedSettingsView( + state: AdvancedSettingsState, + onBackPressed: () -> Unit, + modifier: Modifier = Modifier, +) { + PreferenceView( + modifier = modifier, + onBackPressed = onBackPressed, + title = stringResource(id = CommonStrings.common_advanced_settings) + ) { + PreferenceSwitch( + title = stringResource(id = CommonStrings.common_rich_text_editor), + // TODO i18n + subtitle = "Disable the rich text editor to type Markdown manually", + isChecked = state.isRichTextEditorEnabled, + onCheckedChange = { state.eventSink(AdvancedSettingsEvents.SetRichTextEditorEnabled(it)) }, + ) + PreferenceSwitch( + // TODO i18n + title = "Developer mode", + // TODO i18n + subtitle = "The developer mode activates hidden features. For developers only!", + isChecked = state.isDeveloperModeEnabled, + onCheckedChange = { state.eventSink(AdvancedSettingsEvents.SetDeveloperModeEnabled(it)) }, + ) + } +} + +@DayNightPreviews +@Composable +internal fun AdvancedSettingsViewPreview(@PreviewParameter(AdvancedSettingsStateProvider::class) state: AdvancedSettingsState) = + ElementPreview { + AdvancedSettingsView(state = state, onBackPressed = { }) + } diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootNode.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootNode.kt index 5226d55b6b..b4495d8899 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootNode.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootNode.kt @@ -46,6 +46,7 @@ class PreferencesRootNode @AssistedInject constructor( fun onOpenAbout() fun onOpenDeveloperSettings() fun onOpenNotificationSettings() + fun onOpenAdvancedSettings() } private fun onOpenBugReport() { @@ -60,6 +61,10 @@ class PreferencesRootNode @AssistedInject constructor( plugins().forEach { it.onOpenDeveloperSettings() } } + private fun onOpenAdvancedSettings() { + plugins().forEach { it.onOpenAdvancedSettings() } + } + private fun onOpenAnalytics() { plugins().forEach { it.onOpenAnalytics() } } @@ -100,6 +105,7 @@ class PreferencesRootNode @AssistedInject constructor( onOpenAbout = this::onOpenAbout, onVerifyClicked = this::onVerifyClicked, onOpenDeveloperSettings = this::onOpenDeveloperSettings, + onOpenAdvancedSettings = this::onOpenAdvancedSettings, onSuccessLogout = { onSuccessLogout(activity, it) }, onManageAccountClicked = { onManageAccountClicked(activity, it, isDark) }, onOpenNotificationSettings = this::onOpenNotificationSettings diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootView.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootView.kt index 3d901c4617..c6d34c6969 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootView.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootView.kt @@ -25,6 +25,7 @@ import androidx.compose.material.icons.outlined.Help import androidx.compose.material.icons.outlined.InsertChart import androidx.compose.material.icons.outlined.Notifications import androidx.compose.material.icons.outlined.OpenInNew +import androidx.compose.material.icons.outlined.Settings import androidx.compose.material.icons.outlined.VerifiedUser import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier @@ -58,6 +59,7 @@ fun PreferencesRootView( onOpenRageShake: () -> Unit, onOpenAbout: () -> Unit, onOpenDeveloperSettings: () -> Unit, + onOpenAdvancedSettings: () -> Unit, onSuccessLogout: (logoutUrlResult: String?) -> Unit, onOpenNotificationSettings: () -> Unit, modifier: Modifier = Modifier, @@ -125,6 +127,13 @@ fun PreferencesRootView( DeveloperPreferencesView(onOpenDeveloperSettings) HorizontalDivider() } + HorizontalDivider() + PreferenceText( + title = stringResource(id = CommonStrings.common_advanced_settings), + icon = Icons.Outlined.Settings, + onClick = onOpenAdvancedSettings, + ) + HorizontalDivider() LogoutPreferenceView( state = state.logoutState, onSuccessLogout = onSuccessLogout, @@ -168,6 +177,7 @@ private fun ContentToPreview(matrixUser: MatrixUser) { onOpenAnalytics = {}, onOpenRageShake = {}, onOpenDeveloperSettings = {}, + onOpenAdvancedSettings = {}, onOpenAbout = {}, onVerifyClicked = {}, onSuccessLogout = {}, diff --git a/libraries/preferences/api/build.gradle.kts b/libraries/preferences/api/build.gradle.kts new file mode 100644 index 0000000000..f782dd328b --- /dev/null +++ b/libraries/preferences/api/build.gradle.kts @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2023 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. + */ + +plugins { + id("io.element.android-library") +} + +android { + namespace = "io.element.android.libraries.preferences.api" +} + +dependencies { + implementation(libs.coroutines.core) +} diff --git a/libraries/preferences/api/src/main/kotlin/io/element/android/features/preferences/api/store/PreferencesStore.kt b/libraries/preferences/api/src/main/kotlin/io/element/android/features/preferences/api/store/PreferencesStore.kt new file mode 100644 index 0000000000..57ad7859c1 --- /dev/null +++ b/libraries/preferences/api/src/main/kotlin/io/element/android/features/preferences/api/store/PreferencesStore.kt @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2023 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 io.element.android.features.preferences.api.store + +import kotlinx.coroutines.flow.Flow + +interface PreferencesStore { + suspend fun setRichTextEditorEnabled(enabled: Boolean) + fun isRichTextEditorEnabledFlow(): Flow + + suspend fun setDevelopModeEnabled(enabled: Boolean) + fun isDevelopModeEnabledFlow(): Flow + + suspend fun reset() +} diff --git a/libraries/preferences/impl/build.gradle.kts b/libraries/preferences/impl/build.gradle.kts new file mode 100644 index 0000000000..9c31d83481 --- /dev/null +++ b/libraries/preferences/impl/build.gradle.kts @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2023 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. + */ + +plugins { + id("io.element.android-library") + alias(libs.plugins.anvil) +} + +android { + namespace = "io.element.android.libraries.preferences.impl" +} + +anvil { + generateDaggerFactories.set(true) +} + +dependencies { + api(projects.libraries.preferences.api) + implementation(libs.dagger) + implementation(libs.androidx.datastore.preferences) + implementation(projects.libraries.di) + implementation(projects.libraries.core) +} diff --git a/libraries/preferences/impl/src/main/kotlin/io/element/android/libraries/preferences/impl/store/DefaultPreferencesStore.kt b/libraries/preferences/impl/src/main/kotlin/io/element/android/libraries/preferences/impl/store/DefaultPreferencesStore.kt new file mode 100644 index 0000000000..5b0cbfb9ee --- /dev/null +++ b/libraries/preferences/impl/src/main/kotlin/io/element/android/libraries/preferences/impl/store/DefaultPreferencesStore.kt @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2023 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 io.element.android.libraries.preferences.impl.store + +import android.content.Context +import androidx.datastore.core.DataStore +import androidx.datastore.preferences.core.Preferences +import androidx.datastore.preferences.core.booleanPreferencesKey +import androidx.datastore.preferences.core.edit +import androidx.datastore.preferences.preferencesDataStore +import com.squareup.anvil.annotations.ContributesBinding +import io.element.android.features.preferences.api.store.PreferencesStore +import io.element.android.libraries.core.bool.orFalse +import io.element.android.libraries.core.bool.orTrue +import io.element.android.libraries.di.AppScope +import io.element.android.libraries.di.ApplicationContext +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import javax.inject.Inject + +private val Context.dataStore: DataStore by preferencesDataStore(name = "elementx_preferences") + +private val richTextEditorKey = booleanPreferencesKey("richTextEditor") +private val developerModeKey = booleanPreferencesKey("developerMode") + +@ContributesBinding(AppScope::class) +class DefaultPreferencesStore @Inject constructor( + @ApplicationContext context: Context +) : PreferencesStore { + private val store = context.dataStore + + override suspend fun setRichTextEditorEnabled(enabled: Boolean) { + store.edit { prefs -> + prefs[richTextEditorKey] = enabled + } + } + + override fun isRichTextEditorEnabledFlow(): Flow { + return store.data.map { prefs -> + // enabled by default + prefs[richTextEditorKey].orTrue() + } + } + + override suspend fun setDevelopModeEnabled(enabled: Boolean) { + store.edit { prefs -> + prefs[developerModeKey] = enabled + } + } + + override fun isDevelopModeEnabledFlow(): Flow { + return store.data.map { prefs -> + // disabled by default + prefs[developerModeKey].orFalse() + } + } + + override suspend fun reset() { + store.edit { it.clear() } + } +} diff --git a/libraries/preferences/test/build.gradle.kts b/libraries/preferences/test/build.gradle.kts new file mode 100644 index 0000000000..86b891b21e --- /dev/null +++ b/libraries/preferences/test/build.gradle.kts @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2023 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. + */ + +plugins { + id("io.element.android-library") +} + +android { + namespace = "io.element.android.libraries.preferences.test" + + dependencies { + api(projects.libraries.preferences.api) + implementation(libs.coroutines.core) + } +} diff --git a/libraries/preferences/test/src/main/kotlin/io/element/android/libraries/featureflag/test/InMemoryPreferencesStore.kt b/libraries/preferences/test/src/main/kotlin/io/element/android/libraries/featureflag/test/InMemoryPreferencesStore.kt new file mode 100644 index 0000000000..550713747e --- /dev/null +++ b/libraries/preferences/test/src/main/kotlin/io/element/android/libraries/featureflag/test/InMemoryPreferencesStore.kt @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2023 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 io.element.android.libraries.featureflag.test + +import io.element.android.features.preferences.api.store.PreferencesStore +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow + +class InMemoryPreferencesStore( + isRichTextEditorEnabled: Boolean = false, + isDeveloperModeEnabled: Boolean = false, +) : PreferencesStore { + private var _isRichTextEditorEnabled = MutableStateFlow(isRichTextEditorEnabled) + private var _isDeveloperModeEnabled = MutableStateFlow(isDeveloperModeEnabled) + + override suspend fun setRichTextEditorEnabled(enabled: Boolean) { + _isRichTextEditorEnabled.value = enabled + } + + override fun isRichTextEditorEnabledFlow(): Flow { + return _isRichTextEditorEnabled + } + + override suspend fun setDevelopModeEnabled(enabled: Boolean) { + _isDeveloperModeEnabled.value = enabled + } + + override fun isDevelopModeEnabledFlow(): Flow { + return _isDeveloperModeEnabled + } + + override suspend fun reset() { + // No op + } +} diff --git a/plugins/src/main/kotlin/extension/DependencyHandleScope.kt b/plugins/src/main/kotlin/extension/DependencyHandleScope.kt index 592cf3c52a..1029100823 100644 --- a/plugins/src/main/kotlin/extension/DependencyHandleScope.kt +++ b/plugins/src/main/kotlin/extension/DependencyHandleScope.kt @@ -92,6 +92,7 @@ fun DependencyHandlerScope.allLibrariesImpl() { implementation(project(":libraries:pushproviders:unifiedpush")) implementation(project(":libraries:featureflag:impl")) implementation(project(":libraries:pushstore:impl")) + implementation(project(":libraries:preferences:impl")) implementation(project(":libraries:architecture")) implementation(project(":libraries:dateformatter:impl")) implementation(project(":libraries:di")) From f55e8a6ad899334545eac98168b8a28d92fc967f Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 14 Sep 2023 11:26:02 +0200 Subject: [PATCH 02/16] Remove feature flag RichTextEditor, it's replaced by an advanced settings. --- features/messages/impl/build.gradle.kts | 2 ++ .../messages/impl/MessagesPresenter.kt | 28 +++++++++++-------- .../messages/MessagesPresenterTest.kt | 7 +++-- .../libraries/featureflag/api/FeatureFlags.kt | 5 ---- .../impl/StaticFeatureFlagProvider.kt | 1 - 5 files changed, 23 insertions(+), 20 deletions(-) diff --git a/features/messages/impl/build.gradle.kts b/features/messages/impl/build.gradle.kts index 00d65eba6a..cd0b6dda2d 100644 --- a/features/messages/impl/build.gradle.kts +++ b/features/messages/impl/build.gradle.kts @@ -48,6 +48,7 @@ dependencies { implementation(projects.libraries.mediapickers.api) implementation(projects.libraries.featureflag.api) implementation(projects.libraries.mediaupload.api) + implementation(projects.libraries.preferences.api) implementation(projects.features.networkmonitor.api) implementation(projects.services.analytics.api) implementation(libs.coil.compose) @@ -76,6 +77,7 @@ dependencies { testImplementation(projects.libraries.featureflag.test) testImplementation(projects.libraries.mediaupload.test) testImplementation(projects.libraries.mediapickers.test) + testImplementation(projects.libraries.preferences.test) testImplementation(projects.libraries.textcomposer.test) testImplementation(libs.test.mockk) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt index 8c985d45d9..1636687d74 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt @@ -57,6 +57,7 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt import io.element.android.features.messages.impl.utils.messagesummary.MessageSummaryFormatter import io.element.android.features.networkmonitor.api.NetworkMonitor import io.element.android.features.networkmonitor.api.NetworkStatus +import io.element.android.features.preferences.api.store.PreferencesStore import io.element.android.libraries.androidutils.clipboard.ClipboardHelper import io.element.android.libraries.architecture.Async import io.element.android.libraries.architecture.Presenter @@ -66,8 +67,6 @@ import io.element.android.libraries.designsystem.components.avatar.AvatarSize import io.element.android.libraries.designsystem.utils.SnackbarDispatcher import io.element.android.libraries.designsystem.utils.SnackbarMessage import io.element.android.libraries.designsystem.utils.collectSnackbarMessageAsState -import io.element.android.libraries.featureflag.api.FeatureFlagService -import io.element.android.libraries.featureflag.api.FeatureFlags import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.room.MatrixRoom import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState @@ -97,7 +96,7 @@ class MessagesPresenter @AssistedInject constructor( private val dispatchers: CoroutineDispatchers, private val clipboardHelper: ClipboardHelper, private val analyticsService: AnalyticsService, - private val featureFlagService: FeatureFlagService, + private val preferencesStore: PreferencesStore, @Assisted private val navigator: MessagesNavigator, ) : Presenter { @@ -146,15 +145,17 @@ class MessagesPresenter @AssistedInject constructor( timelineState.eventSink(TimelineEvents.SetHighlightedEvent(composerState.mode.relatedEventId)) } - var enableTextFormatting by remember { mutableStateOf(true) } - LaunchedEffect(Unit) { - enableTextFormatting = featureFlagService.isFeatureEnabled(FeatureFlags.RichTextEditor) - } + val enableTextFormatting by preferencesStore.isRichTextEditorEnabledFlow().collectAsState(initial = true) fun handleEvents(event: MessagesEvents) { when (event) { is MessagesEvents.HandleAction -> { - localCoroutineScope.handleTimelineAction(event.action, event.event, composerState) + localCoroutineScope.handleTimelineAction( + action = event.action, + targetEvent = event.event, + composerState = composerState, + enableTextFormatting = enableTextFormatting, + ) } is MessagesEvents.ToggleReaction -> { localCoroutineScope.toggleReaction(event.emoji, event.eventId) @@ -204,11 +205,12 @@ class MessagesPresenter @AssistedInject constructor( action: TimelineItemAction, targetEvent: TimelineItem.Event, composerState: MessageComposerState, + enableTextFormatting: Boolean, ) = launch { when (action) { TimelineItemAction.Copy -> handleCopyContents(targetEvent) TimelineItemAction.Redact -> handleActionRedact(targetEvent) - TimelineItemAction.Edit -> handleActionEdit(targetEvent, composerState) + TimelineItemAction.Edit -> handleActionEdit(targetEvent, composerState, enableTextFormatting) TimelineItemAction.Reply, TimelineItemAction.ReplyInThread -> handleActionReply(targetEvent, composerState) TimelineItemAction.Developer -> handleShowDebugInfoAction(targetEvent) @@ -260,11 +262,15 @@ class MessagesPresenter @AssistedInject constructor( } } - private suspend fun handleActionEdit(targetEvent: TimelineItem.Event, composerState: MessageComposerState) { + private suspend fun handleActionEdit( + targetEvent: TimelineItem.Event, + composerState: MessageComposerState, + enableTextFormatting: Boolean, + ) { val composerMode = MessageComposerMode.Edit( targetEvent.eventId, (targetEvent.content as? TimelineItemTextBasedContent)?.let { - if (featureFlagService.isFeatureEnabled(FeatureFlags.RichTextEditor)) { + if (enableTextFormatting) { it.htmlBody ?: it.body } else { it.body diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/MessagesPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/MessagesPresenterTest.kt index c9ef88f18c..cb455425a0 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/MessagesPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/MessagesPresenterTest.kt @@ -54,6 +54,7 @@ import io.element.android.libraries.designsystem.components.avatar.AvatarSize import io.element.android.libraries.designsystem.utils.SnackbarDispatcher import io.element.android.libraries.featureflag.api.FeatureFlags import io.element.android.libraries.featureflag.test.FakeFeatureFlagService +import io.element.android.libraries.featureflag.test.InMemoryPreferencesStore import io.element.android.libraries.matrix.api.media.MediaSource import io.element.android.libraries.matrix.api.room.MatrixRoom import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState @@ -614,7 +615,7 @@ class MessagesPresenterTest { messageComposerContext = MessageComposerContextImpl(), richTextEditorStateFactory = TestRichTextEditorStateFactory(), - ) + ) val timelinePresenter = TimelinePresenter( timelineItemsFactory = aTimelineItemsFactory(), room = matrixRoom, @@ -627,7 +628,7 @@ class MessagesPresenterTest { val customReactionPresenter = CustomReactionPresenter(emojibaseProvider = FakeEmojibaseProvider()) val reactionSummaryPresenter = ReactionSummaryPresenter(room = matrixRoom) val retrySendMenuPresenter = RetrySendMenuPresenter(room = matrixRoom) - val featureFlagsService = FakeFeatureFlagService(mapOf(FeatureFlags.RichTextEditor.key to true)) + val preferencesStore = InMemoryPreferencesStore(isRichTextEditorEnabled = true) return MessagesPresenter( room = matrixRoom, composerPresenter = messageComposerPresenter, @@ -642,7 +643,7 @@ class MessagesPresenterTest { navigator = navigator, clipboardHelper = clipboardHelper, analyticsService = analyticsService, - featureFlagService = featureFlagsService, + preferencesStore = preferencesStore, dispatchers = coroutineDispatchers, ) } diff --git a/libraries/featureflag/api/src/main/kotlin/io/element/android/libraries/featureflag/api/FeatureFlags.kt b/libraries/featureflag/api/src/main/kotlin/io/element/android/libraries/featureflag/api/FeatureFlags.kt index ca68b0cbd1..990aee3a93 100644 --- a/libraries/featureflag/api/src/main/kotlin/io/element/android/libraries/featureflag/api/FeatureFlags.kt +++ b/libraries/featureflag/api/src/main/kotlin/io/element/android/libraries/featureflag/api/FeatureFlags.kt @@ -43,9 +43,4 @@ enum class FeatureFlags( title = "Show notification settings", defaultValue = true, ), - RichTextEditor( - key = "feature.richtexteditor", - title = "Enable rich text editor", - defaultValue = true, - ), } diff --git a/libraries/featureflag/impl/src/main/kotlin/io/element/android/libraries/featureflag/impl/StaticFeatureFlagProvider.kt b/libraries/featureflag/impl/src/main/kotlin/io/element/android/libraries/featureflag/impl/StaticFeatureFlagProvider.kt index d7759ac474..82184d510c 100644 --- a/libraries/featureflag/impl/src/main/kotlin/io/element/android/libraries/featureflag/impl/StaticFeatureFlagProvider.kt +++ b/libraries/featureflag/impl/src/main/kotlin/io/element/android/libraries/featureflag/impl/StaticFeatureFlagProvider.kt @@ -35,7 +35,6 @@ class StaticFeatureFlagProvider @Inject constructor() : FeatureFlags.LocationSharing -> true FeatureFlags.Polls -> true FeatureFlags.NotificationSettings -> true - FeatureFlags.RichTextEditor -> true } } else { false From bf67c6e349b597f9753d11322c12795fddac5483 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 14 Sep 2023 11:35:58 +0200 Subject: [PATCH 03/16] Rename Developer -> ViewSource --- .../features/messages/impl/MessagesPresenter.kt | 2 +- .../impl/actionlist/ActionListPresenter.kt | 8 ++++---- .../impl/actionlist/ActionListStateProvider.kt | 4 ++-- .../impl/actionlist/model/TimelineItemAction.kt | 2 +- .../features/messages/MessagesPresenterTest.kt | 2 +- .../actionlist/ActionListPresenterTest.kt | 16 ++++++++-------- 6 files changed, 17 insertions(+), 17 deletions(-) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt index 1636687d74..1dc46aa2bd 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt @@ -213,7 +213,7 @@ class MessagesPresenter @AssistedInject constructor( TimelineItemAction.Edit -> handleActionEdit(targetEvent, composerState, enableTextFormatting) TimelineItemAction.Reply, TimelineItemAction.ReplyInThread -> handleActionReply(targetEvent, composerState) - TimelineItemAction.Developer -> handleShowDebugInfoAction(targetEvent) + TimelineItemAction.ViewSource -> handleShowDebugInfoAction(targetEvent) TimelineItemAction.Forward -> handleForwardAction(targetEvent) TimelineItemAction.ReportContent -> handleReportAction(targetEvent) TimelineItemAction.EndPoll -> handleEndPollAction(targetEvent) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt index e87523d702..2ba0230f85 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt @@ -86,7 +86,7 @@ class ActionListPresenter @Inject constructor( when (timelineItem.content) { is TimelineItemRedactedContent -> { if (buildMeta.isDebuggable) { - listOf(TimelineItemAction.Developer) + listOf(TimelineItemAction.ViewSource) } else { emptyList() } @@ -95,7 +95,7 @@ class ActionListPresenter @Inject constructor( buildList { add(TimelineItemAction.Copy) if (buildMeta.isDebuggable) { - add(TimelineItemAction.Developer) + add(TimelineItemAction.ViewSource) } } } @@ -116,7 +116,7 @@ class ActionListPresenter @Inject constructor( add(TimelineItemAction.Copy) } if (buildMeta.isDebuggable) { - add(TimelineItemAction.Developer) + add(TimelineItemAction.ViewSource) } if (!timelineItem.isMine) { add(TimelineItemAction.ReportContent) @@ -145,7 +145,7 @@ class ActionListPresenter @Inject constructor( add(TimelineItemAction.Copy) } if (buildMeta.isDebuggable) { - add(TimelineItemAction.Developer) + add(TimelineItemAction.ViewSource) } if (!timelineItem.isMine) { add(TimelineItemAction.ReportContent) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListStateProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListStateProvider.kt index bb9c851288..44736bc076 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListStateProvider.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListStateProvider.kt @@ -111,7 +111,7 @@ fun aTimelineItemActionList(): ImmutableList { TimelineItemAction.Edit, TimelineItemAction.Redact, TimelineItemAction.ReportContent, - TimelineItemAction.Developer, + TimelineItemAction.ViewSource, ) } fun aTimelineItemPollActionList(): ImmutableList { @@ -119,7 +119,7 @@ fun aTimelineItemPollActionList(): ImmutableList { TimelineItemAction.EndPoll, TimelineItemAction.Reply, TimelineItemAction.Copy, - TimelineItemAction.Developer, + TimelineItemAction.ViewSource, TimelineItemAction.ReportContent, TimelineItemAction.Redact, ) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/model/TimelineItemAction.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/model/TimelineItemAction.kt index 331edfa1a5..948c0b0cb1 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/model/TimelineItemAction.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/model/TimelineItemAction.kt @@ -34,7 +34,7 @@ sealed class TimelineItemAction( data object Reply : TimelineItemAction(CommonStrings.action_reply, VectorIcons.Reply) data object ReplyInThread : TimelineItemAction(CommonStrings.action_reply_in_thread, VectorIcons.Reply) data object Edit : TimelineItemAction(CommonStrings.action_edit, VectorIcons.Edit) - data object Developer : TimelineItemAction(CommonStrings.action_view_source, VectorIcons.DeveloperMode) + data object ViewSource : TimelineItemAction(CommonStrings.action_view_source, VectorIcons.DeveloperMode) data object ReportContent : TimelineItemAction(CommonStrings.action_report_content, VectorIcons.ReportContent, destructive = true) data object EndPoll : TimelineItemAction(CommonStrings.action_end_poll, VectorIcons.PollEnd) } diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/MessagesPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/MessagesPresenterTest.kt index cb455425a0..9d37f39e85 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/MessagesPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/MessagesPresenterTest.kt @@ -365,7 +365,7 @@ class MessagesPresenterTest { presenter.present() }.test { val initialState = awaitItem() - initialState.eventSink.invoke(MessagesEvents.HandleAction(TimelineItemAction.Developer, aMessageEvent())) + initialState.eventSink.invoke(MessagesEvents.HandleAction(TimelineItemAction.ViewSource, aMessageEvent())) assertThat(awaitItem().actionListState.target).isEqualTo(ActionListState.Target.None) assertThat(navigator.onShowEventDebugInfoClickedCount).isEqualTo(1) } diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/actionlist/ActionListPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/actionlist/ActionListPresenterTest.kt index 2682a71207..f07fbd0091 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/actionlist/ActionListPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/actionlist/ActionListPresenterTest.kt @@ -71,7 +71,7 @@ class ActionListPresenterTest { ActionListState.Target.Success( messageEvent, persistentListOf( - TimelineItemAction.Developer, + TimelineItemAction.ViewSource, ) ) ) @@ -96,7 +96,7 @@ class ActionListPresenterTest { ActionListState.Target.Success( messageEvent, persistentListOf( - TimelineItemAction.Developer, + TimelineItemAction.ViewSource, ) ) ) @@ -127,7 +127,7 @@ class ActionListPresenterTest { TimelineItemAction.Reply, TimelineItemAction.Forward, TimelineItemAction.Copy, - TimelineItemAction.Developer, + TimelineItemAction.ViewSource, TimelineItemAction.ReportContent, ) ) @@ -158,7 +158,7 @@ class ActionListPresenterTest { persistentListOf( TimelineItemAction.Forward, TimelineItemAction.Copy, - TimelineItemAction.Developer, + TimelineItemAction.ViewSource, TimelineItemAction.ReportContent, ) ) @@ -188,7 +188,7 @@ class ActionListPresenterTest { TimelineItemAction.Reply, TimelineItemAction.Forward, TimelineItemAction.Copy, - TimelineItemAction.Developer, + TimelineItemAction.ViewSource, TimelineItemAction.ReportContent, TimelineItemAction.Redact, ) @@ -222,7 +222,7 @@ class ActionListPresenterTest { TimelineItemAction.Forward, TimelineItemAction.Edit, TimelineItemAction.Copy, - TimelineItemAction.Developer, + TimelineItemAction.ViewSource, TimelineItemAction.Redact, ) ) @@ -253,7 +253,7 @@ class ActionListPresenterTest { persistentListOf( TimelineItemAction.Reply, TimelineItemAction.Forward, - TimelineItemAction.Developer, + TimelineItemAction.ViewSource, TimelineItemAction.Redact, ) ) @@ -283,7 +283,7 @@ class ActionListPresenterTest { stateEvent, persistentListOf( TimelineItemAction.Copy, - TimelineItemAction.Developer, + TimelineItemAction.ViewSource, ) ) ) From 1a6641a5f7910b351c25b12b4f6e2a144ddafb35 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 14 Sep 2023 14:11:53 +0200 Subject: [PATCH 04/16] Show "View Event" if the developer mode is enabled. --- .../impl/actionlist/ActionListPresenter.kt | 17 ++++++--- .../messages/MessagesPresenterTest.kt | 6 +-- .../actionlist/ActionListPresenterTest.kt | 37 ++++++++++--------- 3 files changed, 33 insertions(+), 27 deletions(-) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt index 2ba0230f85..4bcccd3d25 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt @@ -18,6 +18,7 @@ package io.element.android.features.messages.impl.actionlist import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState +import androidx.compose.runtime.collectAsState import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -30,15 +31,15 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStateContent import io.element.android.features.messages.impl.timeline.model.event.canBeCopied import io.element.android.features.messages.impl.timeline.model.event.canReact +import io.element.android.features.preferences.api.store.PreferencesStore import io.element.android.libraries.architecture.Presenter -import io.element.android.libraries.core.meta.BuildMeta import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch import javax.inject.Inject class ActionListPresenter @Inject constructor( - private val buildMeta: BuildMeta, + private val preferencesStore: PreferencesStore, ) : Presenter { @Composable @@ -49,6 +50,8 @@ class ActionListPresenter @Inject constructor( mutableStateOf(ActionListState.Target.None) } + val isDeveloperModeEnabled by preferencesStore.isDevelopModeEnabledFlow().collectAsState(initial = false) + val displayEmojiReactions by remember { derivedStateOf { val event = (target.value as? ActionListState.Target.Success)?.event @@ -63,6 +66,7 @@ class ActionListPresenter @Inject constructor( timelineItem = event.event, userCanRedact = event.canRedact, userCanSendMessage = event.canSendMessage, + isDeveloperModeEnabled = isDeveloperModeEnabled, target = target, ) } @@ -79,13 +83,14 @@ class ActionListPresenter @Inject constructor( timelineItem: TimelineItem.Event, userCanRedact: Boolean, userCanSendMessage: Boolean, + isDeveloperModeEnabled: Boolean, target: MutableState ) = launch { target.value = ActionListState.Target.Loading(timelineItem) val actions = when (timelineItem.content) { is TimelineItemRedactedContent -> { - if (buildMeta.isDebuggable) { + if (isDeveloperModeEnabled) { listOf(TimelineItemAction.ViewSource) } else { emptyList() @@ -94,7 +99,7 @@ class ActionListPresenter @Inject constructor( is TimelineItemStateContent -> { buildList { add(TimelineItemAction.Copy) - if (buildMeta.isDebuggable) { + if (isDeveloperModeEnabled) { add(TimelineItemAction.ViewSource) } } @@ -115,7 +120,7 @@ class ActionListPresenter @Inject constructor( if (timelineItem.content.canBeCopied()) { add(TimelineItemAction.Copy) } - if (buildMeta.isDebuggable) { + if (isDeveloperModeEnabled) { add(TimelineItemAction.ViewSource) } if (!timelineItem.isMine) { @@ -144,7 +149,7 @@ class ActionListPresenter @Inject constructor( if (timelineItem.content.canBeCopied()) { add(TimelineItemAction.Copy) } - if (buildMeta.isDebuggable) { + if (isDeveloperModeEnabled) { add(TimelineItemAction.ViewSource) } if (!timelineItem.isMine) { diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/MessagesPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/MessagesPresenterTest.kt index 9d37f39e85..db2abcc1dd 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/MessagesPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/MessagesPresenterTest.kt @@ -65,7 +65,6 @@ import io.element.android.libraries.matrix.test.AN_EVENT_ID import io.element.android.libraries.matrix.test.A_ROOM_ID import io.element.android.libraries.matrix.test.A_SESSION_ID import io.element.android.libraries.matrix.test.A_SESSION_ID_2 -import io.element.android.libraries.matrix.test.core.aBuildMeta import io.element.android.libraries.matrix.test.room.FakeMatrixRoom import io.element.android.libraries.matrix.test.room.aRoomMember import io.element.android.libraries.mediapickers.test.FakePickerProvider @@ -623,12 +622,11 @@ class MessagesPresenterTest { appScope = this, analyticsService = analyticsService, ) - val buildMeta = aBuildMeta() - val actionListPresenter = ActionListPresenter(buildMeta = buildMeta) + val preferencesStore = InMemoryPreferencesStore(isRichTextEditorEnabled = true) + val actionListPresenter = ActionListPresenter(preferencesStore = preferencesStore) val customReactionPresenter = CustomReactionPresenter(emojibaseProvider = FakeEmojibaseProvider()) val reactionSummaryPresenter = ReactionSummaryPresenter(room = matrixRoom) val retrySendMenuPresenter = RetrySendMenuPresenter(room = matrixRoom) - val preferencesStore = InMemoryPreferencesStore(isRichTextEditorEnabled = true) return MessagesPresenter( room = matrixRoom, composerPresenter = messageComposerPresenter, diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/actionlist/ActionListPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/actionlist/ActionListPresenterTest.kt index f07fbd0091..316e39317e 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/actionlist/ActionListPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/actionlist/ActionListPresenterTest.kt @@ -31,8 +31,8 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemImageContent import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemPollContent import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemStateEventContent +import io.element.android.libraries.featureflag.test.InMemoryPreferencesStore import io.element.android.libraries.matrix.test.A_MESSAGE -import io.element.android.libraries.matrix.test.core.aBuildMeta import io.element.android.tests.testutils.WarmUpRule import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.test.runTest @@ -46,7 +46,7 @@ class ActionListPresenterTest { @Test fun `present - initial state`() = runTest { - val presenter = anActionListPresenter(isBuildDebuggable = true) + val presenter = anActionListPresenter(isDeveloperModeEnabled = true) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -57,7 +57,7 @@ class ActionListPresenterTest { @Test fun `present - compute for message from me redacted`() = runTest { - val presenter = anActionListPresenter(isBuildDebuggable = true) + val presenter = anActionListPresenter(isDeveloperModeEnabled = true) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -82,7 +82,7 @@ class ActionListPresenterTest { @Test fun `present - compute for message from others redacted`() = runTest { - val presenter = anActionListPresenter(isBuildDebuggable = true) + val presenter = anActionListPresenter(isDeveloperModeEnabled = true) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -107,7 +107,7 @@ class ActionListPresenterTest { @Test fun `present - compute for others message`() = runTest { - val presenter = anActionListPresenter(isBuildDebuggable = true) + val presenter = anActionListPresenter(isDeveloperModeEnabled = true) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -139,7 +139,7 @@ class ActionListPresenterTest { @Test fun `present - compute for others message cannot sent message`() = runTest { - val presenter = anActionListPresenter(isBuildDebuggable = true) + val presenter = anActionListPresenter(isDeveloperModeEnabled = true) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -170,7 +170,7 @@ class ActionListPresenterTest { @Test fun `present - compute for others message and can redact`() = runTest { - val presenter = anActionListPresenter(isBuildDebuggable = true) + val presenter = anActionListPresenter(isDeveloperModeEnabled = true) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -201,7 +201,7 @@ class ActionListPresenterTest { @Test fun `present - compute for my message`() = runTest { - val presenter = anActionListPresenter(isBuildDebuggable = true) + val presenter = anActionListPresenter(isDeveloperModeEnabled = true) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -234,7 +234,7 @@ class ActionListPresenterTest { @Test fun `present - compute for a media item`() = runTest { - val presenter = anActionListPresenter(isBuildDebuggable = true) + val presenter = anActionListPresenter(isDeveloperModeEnabled = true) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -265,7 +265,7 @@ class ActionListPresenterTest { @Test fun `present - compute for a state item in debug build`() = runTest { - val presenter = anActionListPresenter(isBuildDebuggable = true) + val presenter = anActionListPresenter(isDeveloperModeEnabled = true) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -294,7 +294,7 @@ class ActionListPresenterTest { @Test fun `present - compute for a state item in non-debuggable build`() = runTest { - val presenter = anActionListPresenter(isBuildDebuggable = false) + val presenter = anActionListPresenter(isDeveloperModeEnabled = false) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -322,7 +322,7 @@ class ActionListPresenterTest { @Test fun `present - compute message in non-debuggable build`() = runTest { - val presenter = anActionListPresenter(isBuildDebuggable = false) + val presenter = anActionListPresenter(isDeveloperModeEnabled = false) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -354,7 +354,7 @@ class ActionListPresenterTest { @Test fun `present - compute message with no actions`() = runTest { - val presenter = anActionListPresenter(isBuildDebuggable = false) + val presenter = anActionListPresenter(isDeveloperModeEnabled = false) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -381,7 +381,7 @@ class ActionListPresenterTest { @Test fun `present - compute not sent message`() = runTest { - val presenter = anActionListPresenter(isBuildDebuggable = false) + val presenter = anActionListPresenter(isDeveloperModeEnabled = false) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -410,7 +410,7 @@ class ActionListPresenterTest { @Test fun `present - compute for poll message`() = runTest { - val presenter = anActionListPresenter(isBuildDebuggable = false) + val presenter = anActionListPresenter(isDeveloperModeEnabled = false) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -436,7 +436,7 @@ class ActionListPresenterTest { @Test fun `present - compute for ended poll message`() = runTest { - val presenter = anActionListPresenter(isBuildDebuggable = false) + val presenter = anActionListPresenter(isDeveloperModeEnabled = false) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -460,5 +460,8 @@ class ActionListPresenterTest { } } -private fun anActionListPresenter(isBuildDebuggable: Boolean) = ActionListPresenter(buildMeta = aBuildMeta(isDebuggable = isBuildDebuggable)) +private fun anActionListPresenter(isDeveloperModeEnabled: Boolean): ActionListPresenter { + val preferencesStore = InMemoryPreferencesStore(isDeveloperModeEnabled = isDeveloperModeEnabled) + return ActionListPresenter(preferencesStore = preferencesStore) +} From cdd8f0e158c938dc65a1a08d7f316d9487b2cab8 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 14 Sep 2023 14:17:30 +0200 Subject: [PATCH 05/16] Developer mode on for debug build. --- .../preferences/impl/store/DefaultPreferencesStore.kt | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/libraries/preferences/impl/src/main/kotlin/io/element/android/libraries/preferences/impl/store/DefaultPreferencesStore.kt b/libraries/preferences/impl/src/main/kotlin/io/element/android/libraries/preferences/impl/store/DefaultPreferencesStore.kt index 5b0cbfb9ee..4d2465a1a0 100644 --- a/libraries/preferences/impl/src/main/kotlin/io/element/android/libraries/preferences/impl/store/DefaultPreferencesStore.kt +++ b/libraries/preferences/impl/src/main/kotlin/io/element/android/libraries/preferences/impl/store/DefaultPreferencesStore.kt @@ -24,8 +24,9 @@ import androidx.datastore.preferences.core.edit import androidx.datastore.preferences.preferencesDataStore import com.squareup.anvil.annotations.ContributesBinding import io.element.android.features.preferences.api.store.PreferencesStore -import io.element.android.libraries.core.bool.orFalse import io.element.android.libraries.core.bool.orTrue +import io.element.android.libraries.core.meta.BuildMeta +import io.element.android.libraries.core.meta.BuildType import io.element.android.libraries.di.AppScope import io.element.android.libraries.di.ApplicationContext import kotlinx.coroutines.flow.Flow @@ -39,7 +40,8 @@ private val developerModeKey = booleanPreferencesKey("developerMode") @ContributesBinding(AppScope::class) class DefaultPreferencesStore @Inject constructor( - @ApplicationContext context: Context + @ApplicationContext context: Context, + private val buildMeta: BuildMeta, ) : PreferencesStore { private val store = context.dataStore @@ -64,8 +66,8 @@ class DefaultPreferencesStore @Inject constructor( override fun isDevelopModeEnabledFlow(): Flow { return store.data.map { prefs -> - // disabled by default - prefs[developerModeKey].orFalse() + // disabled by default on release and nightly, enabled by default on debug + prefs[developerModeKey] ?: (buildMeta.buildType == BuildType.DEBUG) } } From 33bf410710679286fd88013da1e8e65eee18c452 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 14 Sep 2023 14:18:28 +0200 Subject: [PATCH 06/16] Fix typo in fun names. --- .../features/messages/impl/actionlist/ActionListPresenter.kt | 2 +- .../preferences/impl/advanced/AdvancedSettingsPresenter.kt | 4 ++-- .../features/preferences/api/store/PreferencesStore.kt | 4 ++-- .../preferences/impl/store/DefaultPreferencesStore.kt | 4 ++-- .../libraries/featureflag/test/InMemoryPreferencesStore.kt | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt index 4bcccd3d25..588adb1020 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt @@ -50,7 +50,7 @@ class ActionListPresenter @Inject constructor( mutableStateOf(ActionListState.Target.None) } - val isDeveloperModeEnabled by preferencesStore.isDevelopModeEnabledFlow().collectAsState(initial = false) + val isDeveloperModeEnabled by preferencesStore.isDeveloperModeEnabledFlow().collectAsState(initial = false) val displayEmojiReactions by remember { derivedStateOf { diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsPresenter.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsPresenter.kt index b30ca63dc8..5738fe43c8 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsPresenter.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsPresenter.kt @@ -36,7 +36,7 @@ class AdvancedSettingsPresenter @Inject constructor( .isRichTextEditorEnabledFlow() .collectAsState(initial = false) val isDeveloperModeEnabled by preferencesStore - .isDevelopModeEnabledFlow() + .isDeveloperModeEnabledFlow() .collectAsState(initial = false) fun handleEvents(event: AdvancedSettingsEvents) { @@ -45,7 +45,7 @@ class AdvancedSettingsPresenter @Inject constructor( preferencesStore.setRichTextEditorEnabled(event.enabled) } is AdvancedSettingsEvents.SetDeveloperModeEnabled -> localCoroutineScope.launch { - preferencesStore.setDevelopModeEnabled(event.enabled) + preferencesStore.setDeveloperModeEnabled(event.enabled) } } } diff --git a/libraries/preferences/api/src/main/kotlin/io/element/android/features/preferences/api/store/PreferencesStore.kt b/libraries/preferences/api/src/main/kotlin/io/element/android/features/preferences/api/store/PreferencesStore.kt index 57ad7859c1..8ad2c098f6 100644 --- a/libraries/preferences/api/src/main/kotlin/io/element/android/features/preferences/api/store/PreferencesStore.kt +++ b/libraries/preferences/api/src/main/kotlin/io/element/android/features/preferences/api/store/PreferencesStore.kt @@ -22,8 +22,8 @@ interface PreferencesStore { suspend fun setRichTextEditorEnabled(enabled: Boolean) fun isRichTextEditorEnabledFlow(): Flow - suspend fun setDevelopModeEnabled(enabled: Boolean) - fun isDevelopModeEnabledFlow(): Flow + suspend fun setDeveloperModeEnabled(enabled: Boolean) + fun isDeveloperModeEnabledFlow(): Flow suspend fun reset() } diff --git a/libraries/preferences/impl/src/main/kotlin/io/element/android/libraries/preferences/impl/store/DefaultPreferencesStore.kt b/libraries/preferences/impl/src/main/kotlin/io/element/android/libraries/preferences/impl/store/DefaultPreferencesStore.kt index 4d2465a1a0..337301f23e 100644 --- a/libraries/preferences/impl/src/main/kotlin/io/element/android/libraries/preferences/impl/store/DefaultPreferencesStore.kt +++ b/libraries/preferences/impl/src/main/kotlin/io/element/android/libraries/preferences/impl/store/DefaultPreferencesStore.kt @@ -58,13 +58,13 @@ class DefaultPreferencesStore @Inject constructor( } } - override suspend fun setDevelopModeEnabled(enabled: Boolean) { + override suspend fun setDeveloperModeEnabled(enabled: Boolean) { store.edit { prefs -> prefs[developerModeKey] = enabled } } - override fun isDevelopModeEnabledFlow(): Flow { + override fun isDeveloperModeEnabledFlow(): Flow { return store.data.map { prefs -> // disabled by default on release and nightly, enabled by default on debug prefs[developerModeKey] ?: (buildMeta.buildType == BuildType.DEBUG) diff --git a/libraries/preferences/test/src/main/kotlin/io/element/android/libraries/featureflag/test/InMemoryPreferencesStore.kt b/libraries/preferences/test/src/main/kotlin/io/element/android/libraries/featureflag/test/InMemoryPreferencesStore.kt index 550713747e..a2a9fdaa3f 100644 --- a/libraries/preferences/test/src/main/kotlin/io/element/android/libraries/featureflag/test/InMemoryPreferencesStore.kt +++ b/libraries/preferences/test/src/main/kotlin/io/element/android/libraries/featureflag/test/InMemoryPreferencesStore.kt @@ -35,11 +35,11 @@ class InMemoryPreferencesStore( return _isRichTextEditorEnabled } - override suspend fun setDevelopModeEnabled(enabled: Boolean) { + override suspend fun setDeveloperModeEnabled(enabled: Boolean) { _isDeveloperModeEnabled.value = enabled } - override fun isDevelopModeEnabledFlow(): Flow { + override fun isDeveloperModeEnabledFlow(): Flow { return _isDeveloperModeEnabled } From 2a217700e708ac8b16d61f0f7681899fc88fbdb7 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 14 Sep 2023 14:37:45 +0200 Subject: [PATCH 07/16] Add test on AdvancedSettingsPresenterTest --- features/preferences/impl/build.gradle.kts | 1 + .../advanced/AdvancedSettingsPresenterTest.kt | 78 +++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsPresenterTest.kt diff --git a/features/preferences/impl/build.gradle.kts b/features/preferences/impl/build.gradle.kts index 447adb5fa3..f523a2c6f4 100644 --- a/features/preferences/impl/build.gradle.kts +++ b/features/preferences/impl/build.gradle.kts @@ -67,6 +67,7 @@ dependencies { testImplementation(libs.test.turbine) testImplementation(projects.libraries.matrix.test) testImplementation(projects.libraries.featureflag.test) + testImplementation(projects.libraries.preferences.test) testImplementation(projects.features.rageshake.test) testImplementation(projects.features.rageshake.impl) testImplementation(projects.features.logout.impl) diff --git a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsPresenterTest.kt b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsPresenterTest.kt new file mode 100644 index 0000000000..76808ee5f9 --- /dev/null +++ b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsPresenterTest.kt @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2023 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 io.element.android.features.preferences.impl.advanced + +import app.cash.molecule.RecompositionMode +import app.cash.molecule.moleculeFlow +import app.cash.turbine.test +import com.google.common.truth.Truth.assertThat +import io.element.android.libraries.featureflag.test.InMemoryPreferencesStore +import io.element.android.tests.testutils.WarmUpRule +import kotlinx.coroutines.test.runTest +import org.junit.Rule +import org.junit.Test + +class AdvancedSettingsPresenterTest { + + @get:Rule + val warmUpRule = WarmUpRule() + + @Test + fun `present - initial state`() = runTest { + val store = InMemoryPreferencesStore() + val presenter = AdvancedSettingsPresenter(store) + moleculeFlow(RecompositionMode.Immediate) { + presenter.present() + }.test { + val initialState = awaitItem() + assertThat(initialState.isDeveloperModeEnabled).isFalse() + assertThat(initialState.isRichTextEditorEnabled).isFalse() + } + } + + @Test + fun `present - developer mode on off`() = runTest { + val store = InMemoryPreferencesStore() + val presenter = AdvancedSettingsPresenter(store) + moleculeFlow(RecompositionMode.Immediate) { + presenter.present() + }.test { + val initialState = awaitItem() + assertThat(initialState.isDeveloperModeEnabled).isFalse() + initialState.eventSink.invoke(AdvancedSettingsEvents.SetDeveloperModeEnabled(true)) + assertThat(awaitItem().isDeveloperModeEnabled).isTrue() + initialState.eventSink.invoke(AdvancedSettingsEvents.SetDeveloperModeEnabled(false)) + assertThat(awaitItem().isDeveloperModeEnabled).isFalse() + } + } + + @Test + fun `present - rich text editor on off`() = runTest { + val store = InMemoryPreferencesStore() + val presenter = AdvancedSettingsPresenter(store) + moleculeFlow(RecompositionMode.Immediate) { + presenter.present() + }.test { + val initialState = awaitItem() + assertThat(initialState.isRichTextEditorEnabled).isFalse() + initialState.eventSink.invoke(AdvancedSettingsEvents.SetRichTextEditorEnabled(true)) + assertThat(awaitItem().isRichTextEditorEnabled).isTrue() + initialState.eventSink.invoke(AdvancedSettingsEvents.SetRichTextEditorEnabled(false)) + assertThat(awaitItem().isRichTextEditorEnabled).isFalse() + } + } +} From 8242654ebd2dca189cd669baf4e7d67bf0c49972 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 14 Sep 2023 18:31:51 +0200 Subject: [PATCH 08/16] Move developer settings and remove extra dividers. --- .../features/preferences/impl/root/PreferencesRootView.kt | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootView.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootView.kt index c6d34c6969..16c7df6b51 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootView.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootView.kt @@ -123,16 +123,14 @@ fun PreferencesRootView( ) HorizontalDivider() } - if (state.showDeveloperSettings) { - DeveloperPreferencesView(onOpenDeveloperSettings) - HorizontalDivider() - } - HorizontalDivider() PreferenceText( title = stringResource(id = CommonStrings.common_advanced_settings), icon = Icons.Outlined.Settings, onClick = onOpenAdvancedSettings, ) + if (state.showDeveloperSettings) { + DeveloperPreferencesView(onOpenDeveloperSettings) + } HorizontalDivider() LogoutPreferenceView( state = state.logoutState, From f1db77faf12c12ea1885cba7c2a7de7eabca9981 Mon Sep 17 00:00:00 2001 From: ElementBot Date: Thu, 14 Sep 2023 16:48:54 +0000 Subject: [PATCH 09/16] Update screenshots --- ...null_AdvancedSettingsView-D-0_1_null_0,NEXUS_5,1.0,en].png | 3 +++ ...null_AdvancedSettingsView-D-0_1_null_1,NEXUS_5,1.0,en].png | 3 +++ ...null_AdvancedSettingsView-D-0_1_null_2,NEXUS_5,1.0,en].png | 3 +++ ...null_AdvancedSettingsView-N-0_2_null_0,NEXUS_5,1.0,en].png | 3 +++ ...null_AdvancedSettingsView-N-0_2_null_1,NEXUS_5,1.0,en].png | 3 +++ ...null_AdvancedSettingsView-N-0_2_null_2,NEXUS_5,1.0,en].png | 3 +++ ...ull_ConfigureTracingView-D-1_2_null_0,NEXUS_5,1.0,en].png} | 0 ...ull_ConfigureTracingView-N-1_3_null_0,NEXUS_5,1.0,en].png} | 0 ...tNotificationSettingOption-D-2_3_null,NEXUS_5,1.0,en].png} | 0 ...tNotificationSettingOption-N-2_4_null,NEXUS_5,1.0,en].png} | 0 ...ll_PreferencesRootViewDark--1_1_null_0,NEXUS_5,1.0,en].png | 4 ++-- ...ll_PreferencesRootViewDark--1_1_null_1,NEXUS_5,1.0,en].png | 4 ++-- ...l_PreferencesRootViewLight--0_0_null_0,NEXUS_5,1.0,en].png | 4 ++-- ...l_PreferencesRootViewLight--0_0_null_1,NEXUS_5,1.0,en].png | 4 ++-- 14 files changed, 26 insertions(+), 8 deletions(-) create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_null_AdvancedSettingsView-D-0_1_null_0,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_null_AdvancedSettingsView-D-0_1_null_1,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_null_AdvancedSettingsView-D-0_1_null_2,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_null_AdvancedSettingsView-N-0_2_null_0,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_null_AdvancedSettingsView-N-0_2_null_1,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_null_AdvancedSettingsView-N-0_2_null_2,NEXUS_5,1.0,en].png rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.preferences.impl.developer.tracing_null_ConfigureTracingView-D-0_1_null_0,NEXUS_5,1.0,en].png => ui_S_t[f.preferences.impl.developer.tracing_null_ConfigureTracingView-D-1_2_null_0,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.preferences.impl.developer.tracing_null_ConfigureTracingView-N-0_2_null_0,NEXUS_5,1.0,en].png => ui_S_t[f.preferences.impl.developer.tracing_null_ConfigureTracingView-N-1_3_null_0,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.preferences.impl.notifications.edit_null_DefaultNotificationSettingOption-D-1_2_null,NEXUS_5,1.0,en].png => ui_S_t[f.preferences.impl.notifications.edit_null_DefaultNotificationSettingOption-D-2_3_null,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.preferences.impl.notifications.edit_null_DefaultNotificationSettingOption-N-1_3_null,NEXUS_5,1.0,en].png => ui_S_t[f.preferences.impl.notifications.edit_null_DefaultNotificationSettingOption-N-2_4_null,NEXUS_5,1.0,en].png} (100%) diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_null_AdvancedSettingsView-D-0_1_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_null_AdvancedSettingsView-D-0_1_null_0,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..aa5e7b202a --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_null_AdvancedSettingsView-D-0_1_null_0,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a11d23d53b983a6cb5448f6083e448902b50889d6393f48454ef1b19c0ad0f07 +size 38028 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_null_AdvancedSettingsView-D-0_1_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_null_AdvancedSettingsView-D-0_1_null_1,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..99efbef109 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_null_AdvancedSettingsView-D-0_1_null_1,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:18063647932eef08f66236825751456801e2a172a72ff09691a1d4b93897466d +size 37617 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_null_AdvancedSettingsView-D-0_1_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_null_AdvancedSettingsView-D-0_1_null_2,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..9cfecc1b15 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_null_AdvancedSettingsView-D-0_1_null_2,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:333e3cb2b49f6d2794e732b7b9fc4204a7fc8564d0518b8cf60a9e7f14ea9a39 +size 37688 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_null_AdvancedSettingsView-N-0_2_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_null_AdvancedSettingsView-N-0_2_null_0,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..ca2c271e89 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_null_AdvancedSettingsView-N-0_2_null_0,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:47332a39d0c1a95a8396548b45bc3822b734111b268c06d917fa2ffb2d277cc1 +size 35649 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_null_AdvancedSettingsView-N-0_2_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_null_AdvancedSettingsView-N-0_2_null_1,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..e31840c360 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_null_AdvancedSettingsView-N-0_2_null_1,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9deacb3ff9bdd2dbee7dd97686941cee9b1f19855f6b87c7e6860e9d47c671e4 +size 35278 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_null_AdvancedSettingsView-N-0_2_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_null_AdvancedSettingsView-N-0_2_null_2,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..44081fe3ab --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.advanced_null_AdvancedSettingsView-N-0_2_null_2,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:16b226707d1e862aa004c426221b89dbc9c7b2cedee19b11ff8843fa524a76ad +size 35378 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.developer.tracing_null_ConfigureTracingView-D-0_1_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.developer.tracing_null_ConfigureTracingView-D-1_2_null_0,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.developer.tracing_null_ConfigureTracingView-D-0_1_null_0,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.developer.tracing_null_ConfigureTracingView-D-1_2_null_0,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.developer.tracing_null_ConfigureTracingView-N-0_2_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.developer.tracing_null_ConfigureTracingView-N-1_3_null_0,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.developer.tracing_null_ConfigureTracingView-N-0_2_null_0,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.developer.tracing_null_ConfigureTracingView-N-1_3_null_0,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_null_DefaultNotificationSettingOption-D-1_2_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_null_DefaultNotificationSettingOption-D-2_3_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_null_DefaultNotificationSettingOption-D-1_2_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_null_DefaultNotificationSettingOption-D-2_3_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_null_DefaultNotificationSettingOption-N-1_3_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_null_DefaultNotificationSettingOption-N-2_4_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_null_DefaultNotificationSettingOption-N-1_3_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_null_DefaultNotificationSettingOption-N-2_4_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.root_null_PreferencesRootViewDark--1_1_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.root_null_PreferencesRootViewDark--1_1_null_0,NEXUS_5,1.0,en].png index 05ac81ce49..72fbec227e 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.root_null_PreferencesRootViewDark--1_1_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.root_null_PreferencesRootViewDark--1_1_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:aed6ab34c685d32aa77e926c416621716acedd586eea2e76e51f1c51867be6cf -size 43419 +oid sha256:56f2a7a7aca8336fb669030a98af4fd851ab1bf52c68d33be36fe8df922c01ee +size 46097 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.root_null_PreferencesRootViewDark--1_1_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.root_null_PreferencesRootViewDark--1_1_null_1,NEXUS_5,1.0,en].png index 66bf07e1ce..a2d529d3a0 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.root_null_PreferencesRootViewDark--1_1_null_1,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.root_null_PreferencesRootViewDark--1_1_null_1,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d4dce8dec2408bcf8e1e8a547689cdac25145d2fef603b21ff20ba2a40e181b1 -size 42741 +oid sha256:6936337fd9365fc5d38d5570798ceaa409099240593e32a468e7688398926e4d +size 45415 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.root_null_PreferencesRootViewLight--0_0_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.root_null_PreferencesRootViewLight--0_0_null_0,NEXUS_5,1.0,en].png index 793b31326f..29b2a82cea 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.root_null_PreferencesRootViewLight--0_0_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.root_null_PreferencesRootViewLight--0_0_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b01d7dcb16041285c2915b7572c16e39d199ac930ed0f6a69b1219bdf5d0ccd5 -size 46362 +oid sha256:c9bc0aa48e94e2a4fb61ebc52b5d62d3fd960a3a3c52300906c76ad52f92b662 +size 49333 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.root_null_PreferencesRootViewLight--0_0_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.root_null_PreferencesRootViewLight--0_0_null_1,NEXUS_5,1.0,en].png index 399417d8ac..97fc36e283 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.root_null_PreferencesRootViewLight--0_0_null_1,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.root_null_PreferencesRootViewLight--0_0_null_1,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a9667115ed339726a09e7917737a6aa5698f4f03249f2704f162461775ddc20b -size 46229 +oid sha256:bc40ec0fb6fa758768fc697496f54b9381a0fd0a67cce1ee36b6dd703e11ea18 +size 49229 From 2dbba53c956dbf5e23599df32094fe6cab78406d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 14 Sep 2023 20:30:44 +0000 Subject: [PATCH 10/16] Update dependency app.cash.molecule:molecule-runtime to v1.2.1 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index cdc80fbd1b..42e4c3659d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -6,7 +6,7 @@ android_gradle_plugin = "8.1.1" kotlin = "1.9.10" ksp = "1.9.10-1.0.13" -molecule = "1.2.0" +molecule = "1.2.1" # AndroidX material = "1.9.0" From 731a48750459602399e60035c8fa2eb75eeab9fc Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 14 Sep 2023 20:30:50 +0000 Subject: [PATCH 11/16] Update dependency com.google.firebase:firebase-bom to v32.3.0 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index cdc80fbd1b..e8a90f9857 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -66,7 +66,7 @@ android_gradle_plugin = { module = "com.android.tools.build:gradle", version.ref android_desugar = "com.android.tools:desugar_jdk_libs:2.0.3" kotlin_gradle_plugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" } # https://firebase.google.com/docs/android/setup#available-libraries -google_firebase_bom = "com.google.firebase:firebase-bom:32.2.3" +google_firebase_bom = "com.google.firebase:firebase-bom:32.3.0" # AndroidX androidx_material = { module = "com.google.android.material:material", version.ref = "material" } From 47ea202de45ca6c338f3cda95ac5f60ffbb3e2e9 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 15 Sep 2023 09:19:30 +0200 Subject: [PATCH 12/16] Revert "Update codecov/codecov-action action to v4" --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 2fdaa2195e..f662e5352d 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -81,6 +81,6 @@ jobs: # https://github.com/codecov/codecov-action - name: ☂️ Upload coverage reports to codecov if: always() - uses: codecov/codecov-action@v4 + uses: codecov/codecov-action@v3 # with: # files: build/reports/kover/merged/xml/report.xml From 3f721f57cb2562ea1ab1abcbc6865dea40a7903f Mon Sep 17 00:00:00 2001 From: Marco Romano Date: Fri, 15 Sep 2023 09:20:29 +0200 Subject: [PATCH 13/16] Remove suppressUnsupportedCompileSdk We're now an AGP 8.1.0 so should be safe to remove as per the comment. --- gradle.properties | 3 --- 1 file changed, 3 deletions(-) diff --git a/gradle.properties b/gradle.properties index 6f311e45ef..9847be0949 100644 --- a/gradle.properties +++ b/gradle.properties @@ -56,6 +56,3 @@ android.experimental.enableTestFixtures=true # Create BuildConfig files as bytecode to avoid Java compilation phase android.enableBuildConfigAsBytecode=true - -# This should be removed after upgrading to AGP 8.1.0 -android.suppressUnsupportedCompileSdk=34 From 79e5bc7ae5d296e8b48521171748a775c1780aab Mon Sep 17 00:00:00 2001 From: Marco Romano Date: Fri, 15 Sep 2023 09:24:55 +0200 Subject: [PATCH 14/16] Add preview for progressIndicatorTrackColor Forgot to add it in https://github.com/vector-im/element-x-android/pull/1295 --- .../element/android/libraries/designsystem/theme/ColorAliases.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/ColorAliases.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/ColorAliases.kt index 52e0a69430..77ca4bd010 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/ColorAliases.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/ColorAliases.kt @@ -100,6 +100,7 @@ private fun ContentToPreview() { "placeholderBackground" to ElementTheme.colors.placeholderBackground, "messageFromMeBackground" to ElementTheme.colors.messageFromMeBackground, "messageFromOtherBackground" to ElementTheme.colors.messageFromOtherBackground, + "progressIndicatorTrackColor" to ElementTheme.colors.progressIndicatorTrackColor, "temporaryColorBgSpecial" to ElementTheme.colors.temporaryColorBgSpecial, ) ) From 33ce114d4a3c8335d5351451d12171b05b8de80f Mon Sep 17 00:00:00 2001 From: ElementBot Date: Fri, 15 Sep 2023 07:44:17 +0000 Subject: [PATCH 15/16] Update screenshots --- ...tem.theme_null_ColorAliasesDark_0_null,NEXUS_5,1.0,en].png | 4 ++-- ...em.theme_null_ColorAliasesLight_0_null,NEXUS_5,1.0,en].png | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme_null_ColorAliasesDark_0_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme_null_ColorAliasesDark_0_null,NEXUS_5,1.0,en].png index 5c56f5f39b..b1c6c996d8 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme_null_ColorAliasesDark_0_null,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme_null_ColorAliasesDark_0_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:38642daa43d72b6b8e0626ed5fcd034df1e79bb844af8ade06112225dfc0f5b7 -size 40707 +oid sha256:d57924194a017902912825d4f43fcd290db11430d4d64abd89abe39b9e2ffc27 +size 48726 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme_null_ColorAliasesLight_0_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme_null_ColorAliasesLight_0_null,NEXUS_5,1.0,en].png index 0b39e21087..eaf130c209 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme_null_ColorAliasesLight_0_null,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme_null_ColorAliasesLight_0_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4aa0a56393799bcc582f8c384b4bf782fff63bc8402bbef5733c938ce564a75f -size 40000 +oid sha256:0eaa20c7c00c18cf08135aca70407d55ea9fc33a7f262aee3fa6ced272f7ab16 +size 48465 From 6c45945f577425fe2d07bd11927742d3d22d5751 Mon Sep 17 00:00:00 2001 From: ganfra Date: Fri, 15 Sep 2023 10:27:57 +0200 Subject: [PATCH 16/16] Update rust sdk to 0.1.53 --- gradle/libs.versions.toml | 2 +- .../matrix/impl/auth/RustMatrixAuthenticationService.kt | 2 ++ .../matrix/impl/roomlist/RoomSummaryListProcessor.kt | 8 ++++---- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e8a90f9857..ec3d760a27 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -149,7 +149,7 @@ jsoup = { module = "org.jsoup:jsoup", version.ref = "jsoup" } appyx_core = { module = "com.bumble.appyx:core", version.ref = "appyx" } molecule-runtime = { module = "app.cash.molecule:molecule-runtime", version.ref = "molecule" } timber = "com.jakewharton.timber:timber:5.0.1" -matrix_sdk = "org.matrix.rustcomponents:sdk-android:0.1.52" +matrix_sdk = "org.matrix.rustcomponents:sdk-android:0.1.53" matrix_richtexteditor = { module = "io.element.android:wysiwyg", version.ref = "wysiwyg" } matrix_richtexteditor_compose = { module = "io.element.android:wysiwyg-compose", version.ref = "wysiwyg" } sqldelight-driver-android = { module = "com.squareup.sqldelight:android-driver", version.ref = "sqldelight" } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/RustMatrixAuthenticationService.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/RustMatrixAuthenticationService.kt index 6014644733..f2acb0b1be 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/RustMatrixAuthenticationService.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/RustMatrixAuthenticationService.kt @@ -57,6 +57,8 @@ class RustMatrixAuthenticationService @Inject constructor( userAgent = userAgentProvider.provide(), oidcConfiguration = oidcConfiguration, customSlidingSyncProxy = null, + sessionDelegate = null, + crossProcessRefreshLockId = null, ) private var currentHomeserver = MutableStateFlow(null) diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryListProcessor.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryListProcessor.kt index 03b58ed2ce..4bade9cc81 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryListProcessor.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryListProcessor.kt @@ -59,7 +59,7 @@ class RoomSummaryListProcessor( } } - private suspend fun MutableList.applyUpdate(update: RoomListEntriesUpdate) { + private fun MutableList.applyUpdate(update: RoomListEntriesUpdate) { when (update) { is RoomListEntriesUpdate.Append -> { val roomSummaries = update.values.map { @@ -102,7 +102,7 @@ class RoomSummaryListProcessor( } } - private suspend fun buildSummaryForRoomListEntry(entry: RoomListEntry): RoomSummary { + private fun buildSummaryForRoomListEntry(entry: RoomListEntry): RoomSummary { return when (entry) { RoomListEntry.Empty -> buildEmptyRoomSummary() is RoomListEntry.Filled -> buildAndCacheRoomSummaryForIdentifier(entry.roomId) @@ -116,9 +116,9 @@ class RoomSummaryListProcessor( return RoomSummary.Empty(UUID.randomUUID().toString()) } - private suspend fun buildAndCacheRoomSummaryForIdentifier(identifier: String): RoomSummary { + private fun buildAndCacheRoomSummaryForIdentifier(identifier: String): RoomSummary { val builtRoomSummary = roomListService.roomOrNull(identifier)?.use { roomListItem -> - roomListItem.roomInfo().use { roomInfo -> + roomListItem.roomInfoBlocking().use { roomInfo -> RoomSummary.Filled( details = roomSummaryDetailsFactory.create(roomInfo) )