Element config (#4471)

* Add handy extension "VariantDimension.buildConfigFieldStr"

* Update configuration for MapTiler.

* Update configuration for Sentry.

* Build AnalyticsConfig depending on analytics configuration.

* Configure analytics policy url.

* Add handy extension "VariantDimension.buildConfigFieldBoolean"

* Configure legal urls.

* Add a way to disable rageshake / reporting bugs.

* Update screenshots

* Quality

* Fix test

* Use `ifBlank` extension

* Add missing configuration for PostHog

* Update configuration for Rageshake.

* Add build log.

* Disable crash detection if rageshake feature is not available.
Disabled twice.

* Hide link to analytics policy if the link is missing.

* Fix test when run in enterprise context.

* Use RageshakeFeatureAvailability where appropriate.

* Rename file.

* Move some classes to their correct module.

* Update screenshots

---------

Co-authored-by: ElementBot <android@element.io>
This commit is contained in:
Benoit Marty 2025-03-27 11:25:04 +01:00 committed by GitHub
parent c6b99c853c
commit 3c1deff79c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
95 changed files with 613 additions and 273 deletions

View file

@ -8,11 +8,12 @@
package io.element.android.features.preferences.impl.about
import androidx.annotation.StringRes
import io.element.android.features.preferences.impl.BuildConfig
import io.element.android.libraries.ui.strings.CommonStrings
private const val COPYRIGHT_URL = "https://element.io/copyright"
private const val USE_POLICY_URL = "https://element.io/acceptable-use-policy-terms"
private const val PRIVACY_URL = "https://element.io/privacy"
private const val COPYRIGHT_URL = BuildConfig.URL_COPYRIGHT
private const val USE_POLICY_URL = BuildConfig.URL_ACCEPTABLE_USE
private const val PRIVACY_URL = BuildConfig.URL_PRIVACY
sealed class ElementLegal(
@StringRes val titleRes: Int,

View file

@ -18,6 +18,7 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import io.element.android.features.logout.api.direct.DirectLogoutState
import io.element.android.features.preferences.impl.utils.ShowDeveloperSettingsProvider
import io.element.android.features.rageshake.api.RageshakeFeatureAvailability
import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatcher
import io.element.android.libraries.designsystem.utils.snackbar.collectSnackbarMessageAsState
@ -44,6 +45,7 @@ class PreferencesRootPresenter @Inject constructor(
private val indicatorService: IndicatorService,
private val directLogoutPresenter: Presenter<DirectLogoutState>,
private val showDeveloperSettingsProvider: ShowDeveloperSettingsProvider,
private val rageshakeFeatureAvailability: RageshakeFeatureAvailability,
) : Presenter<PreferencesRootState> {
@Composable
override fun present(): PreferencesRootState {
@ -79,6 +81,7 @@ class PreferencesRootPresenter @Inject constructor(
var canDeactivateAccount by remember {
mutableStateOf(false)
}
val canReportBug = remember { rageshakeFeatureAvailability.isAvailable() }
LaunchedEffect(Unit) {
canDeactivateAccount = matrixClient.canDeactivateAccount()
}
@ -114,6 +117,7 @@ class PreferencesRootPresenter @Inject constructor(
accountManagementUrl = accountManagementUrl.value,
devicesManagementUrl = devicesManagementUrl.value,
showAnalyticsSettings = hasAnalyticsProviders,
canReportBug = canReportBug,
showDeveloperSettings = showDeveloperSettings,
canDeactivateAccount = canDeactivateAccount,
showNotificationSettings = showNotificationSettings.value,

View file

@ -20,6 +20,7 @@ data class PreferencesRootState(
val showSecureBackupBadge: Boolean,
val accountManagementUrl: String?,
val devicesManagementUrl: String?,
val canReportBug: Boolean,
val showAnalyticsSettings: Boolean,
val showDeveloperSettings: Boolean,
val canDeactivateAccount: Boolean,

View file

@ -25,6 +25,7 @@ fun aPreferencesRootState(
accountManagementUrl = "aUrl",
devicesManagementUrl = "anOtherUrl",
showAnalyticsSettings = true,
canReportBug = true,
showDeveloperSettings = true,
showNotificationSettings = true,
showLockScreenSettings = true,

View file

@ -202,11 +202,13 @@ private fun ColumnScope.GeneralSection(
leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.Info())),
onClick = onOpenAbout,
)
ListItem(
headlineContent = { Text(stringResource(id = CommonStrings.common_report_a_problem)) },
leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.ChatProblem())),
onClick = onOpenRageShake
)
if (state.canReportBug) {
ListItem(
headlineContent = { Text(stringResource(id = CommonStrings.common_report_a_problem)) },
leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.ChatProblem())),
onClick = onOpenRageShake
)
}
if (state.showAnalyticsSettings) {
ListItem(
headlineContent = { Text(stringResource(id = CommonStrings.common_analytics)) },

View file

@ -13,6 +13,7 @@ import app.cash.turbine.ReceiveTurbine
import com.google.common.truth.Truth.assertThat
import io.element.android.features.logout.api.direct.aDirectLogoutState
import io.element.android.features.preferences.impl.utils.ShowDeveloperSettingsProvider
import io.element.android.features.rageshake.api.RageshakeFeatureAvailability
import io.element.android.libraries.core.meta.BuildType
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatcher
import io.element.android.libraries.featureflag.test.FakeFeatureFlagService
@ -78,6 +79,7 @@ class PreferencesRootPresenterTest {
assertThat(loadedState.showLockScreenSettings).isTrue()
assertThat(loadedState.showNotificationSettings).isTrue()
assertThat(loadedState.canDeactivateAccount).isTrue()
assertThat(loadedState.canReportBug).isTrue()
assertThat(loadedState.directLogoutState).isEqualTo(aDirectLogoutState())
assertThat(loadedState.snackbarMessage).isNull()
skipItems(1)
@ -92,6 +94,22 @@ class PreferencesRootPresenterTest {
}
}
@Test
fun `present - cannot report bug`() = runTest {
val matrixClient = FakeMatrixClient(
canDeactivateAccountResult = { true },
accountManagementUrlResult = { Result.success("") },
)
createPresenter(
matrixClient = matrixClient,
rageshakeFeatureAvailability = { false },
).test {
val initialState = awaitItem()
assertThat(initialState.canReportBug).isFalse()
skipItems(1)
}
}
@Test
fun `present - can deactivate account is false if the Matrix client say so`() = runTest {
createPresenter(
@ -146,6 +164,7 @@ class PreferencesRootPresenterTest {
matrixClient: FakeMatrixClient = FakeMatrixClient(),
sessionVerificationService: FakeSessionVerificationService = FakeSessionVerificationService(),
showDeveloperSettingsProvider: ShowDeveloperSettingsProvider = ShowDeveloperSettingsProvider(aBuildMeta(BuildType.DEBUG)),
rageshakeFeatureAvailability: RageshakeFeatureAvailability = RageshakeFeatureAvailability { true },
) = PreferencesRootPresenter(
matrixClient = matrixClient,
sessionVerificationService = sessionVerificationService,
@ -159,5 +178,6 @@ class PreferencesRootPresenterTest {
),
directLogoutPresenter = { aDirectLogoutState() },
showDeveloperSettingsProvider = showDeveloperSettingsProvider,
rageshakeFeatureAvailability = rageshakeFeatureAvailability,
)
}