Make the link open the policy url in the analytics setting screen.

This commit is contained in:
Benoit Marty 2023-08-29 16:32:29 +02:00
parent 62d92d3296
commit 03864b3eb0
7 changed files with 47 additions and 2 deletions

View file

@ -21,5 +21,6 @@ import io.element.android.features.analytics.api.AnalyticsOptInEvents
data class AnalyticsPreferencesState( data class AnalyticsPreferencesState(
val applicationName: String, val applicationName: String,
val isEnabled: Boolean, val isEnabled: Boolean,
val policyUrl: String,
val eventSink: (AnalyticsOptInEvents) -> Unit, val eventSink: (AnalyticsOptInEvents) -> Unit,
) )

View file

@ -28,5 +28,6 @@ open class AnalyticsPreferencesStateProvider : PreviewParameterProvider<Analytic
fun aAnalyticsPreferencesState() = AnalyticsPreferencesState( fun aAnalyticsPreferencesState() = AnalyticsPreferencesState(
applicationName = "Element X", applicationName = "Element X",
isEnabled = false, isEnabled = false,
policyUrl = "https://element.io",
eventSink = {} eventSink = {}
) )

View file

@ -17,6 +17,7 @@
package io.element.android.features.analytics.api.preferences package io.element.android.features.analytics.api.preferences
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.compose.foundation.text.ClickableText
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
@ -39,6 +40,7 @@ import io.element.android.libraries.ui.strings.CommonStrings
fun AnalyticsPreferencesView( fun AnalyticsPreferencesView(
state: AnalyticsPreferencesState, state: AnalyticsPreferencesState,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
onOpenAnalyticsPolicy: (url: String) -> Unit,
) { ) {
fun onEnabledChanged(isEnabled: Boolean) { fun onEnabledChanged(isEnabled: Boolean) {
state.eventSink(AnalyticsOptInEvents.EnableAnalytics(isEnabled = isEnabled)) state.eventSink(AnalyticsOptInEvents.EnableAnalytics(isEnabled = isEnabled))
@ -47,7 +49,8 @@ fun AnalyticsPreferencesView(
val firstPart = stringResource(id = CommonStrings.screen_analytics_settings_help_us_improve, state.applicationName) val firstPart = stringResource(id = CommonStrings.screen_analytics_settings_help_us_improve, state.applicationName)
val secondPart = buildAnnotatedStringWithColoredPart( val secondPart = buildAnnotatedStringWithColoredPart(
CommonStrings.screen_analytics_settings_read_terms, CommonStrings.screen_analytics_settings_read_terms,
CommonStrings.screen_analytics_settings_read_terms_content_link CommonStrings.screen_analytics_settings_read_terms_content_link,
link = state.policyUrl,
) )
val subtitle = buildAnnotatedString { val subtitle = buildAnnotatedString {
append(firstPart) append(firstPart)
@ -60,6 +63,16 @@ fun AnalyticsPreferencesView(
Text(stringResource(id = CommonStrings.screen_analytics_settings_share_data)) Text(stringResource(id = CommonStrings.screen_analytics_settings_share_data))
}, },
supportingContent = { supportingContent = {
ClickableText(
text = subtitle,
onClick = {
subtitle
.getStringAnnotations("link", it, it)
.firstOrNull()?.let { stringAnnotation ->
onOpenAnalyticsPolicy(stringAnnotation.item)
}
}
)
Text(text = subtitle) Text(text = subtitle)
}, },
leadingContent = null, leadingContent = null,
@ -68,12 +81,14 @@ fun AnalyticsPreferencesView(
) )
} }
// TODO Use buildAnnotatedStringWithStyledPart.
@Composable @Composable
fun buildAnnotatedStringWithColoredPart( fun buildAnnotatedStringWithColoredPart(
@StringRes fullTextRes: Int, @StringRes fullTextRes: Int,
@StringRes coloredTextRes: Int, @StringRes coloredTextRes: Int,
color: Color = LinkColor, color: Color = LinkColor,
underline: Boolean = true, underline: Boolean = true,
link: String? = null,
) = buildAnnotatedString { ) = buildAnnotatedString {
val coloredPart = stringResource(coloredTextRes) val coloredPart = stringResource(coloredTextRes)
val fullText = stringResource(fullTextRes, coloredPart) val fullText = stringResource(fullTextRes, coloredPart)
@ -87,6 +102,14 @@ fun buildAnnotatedStringWithColoredPart(
start = startIndex, start = startIndex,
end = startIndex + coloredPart.length, end = startIndex + coloredPart.length,
) )
if (link != null) {
addStringAnnotation(
tag = "link",
annotation = link,
start = startIndex,
end = startIndex + coloredPart.length
)
}
} }
@Preview @Preview
@ -101,5 +124,8 @@ internal fun AnalyticsPreferencesViewDarkPreview(@PreviewParameter(AnalyticsPref
@Composable @Composable
private fun ContentToPreview(state: AnalyticsPreferencesState) { private fun ContentToPreview(state: AnalyticsPreferencesState) {
AnalyticsPreferencesView(state) AnalyticsPreferencesView(
state = state,
onOpenAnalyticsPolicy = {},
)
} }

View file

@ -21,6 +21,7 @@ import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
import com.squareup.anvil.annotations.ContributesBinding import com.squareup.anvil.annotations.ContributesBinding
import io.element.android.features.analytics.api.AnalyticsOptInEvents import io.element.android.features.analytics.api.AnalyticsOptInEvents
import io.element.android.features.analytics.api.Config
import io.element.android.features.analytics.api.preferences.AnalyticsPreferencesPresenter import io.element.android.features.analytics.api.preferences.AnalyticsPreferencesPresenter
import io.element.android.features.analytics.api.preferences.AnalyticsPreferencesState import io.element.android.features.analytics.api.preferences.AnalyticsPreferencesState
import io.element.android.libraries.core.meta.BuildMeta import io.element.android.libraries.core.meta.BuildMeta
@ -51,6 +52,7 @@ class DefaultAnalyticsPreferencesPresenter @Inject constructor(
return AnalyticsPreferencesState( return AnalyticsPreferencesState(
applicationName = buildMeta.applicationName, applicationName = buildMeta.applicationName,
isEnabled = isEnabled.value, isEnabled = isEnabled.value,
policyUrl = Config.POLICY_LINK,
eventSink = ::handleEvents eventSink = ::handleEvents
) )
} }

View file

@ -39,6 +39,7 @@ class AnalyticsPreferencesPresenterTest {
skipItems(1) skipItems(1)
val initialState = awaitItem() val initialState = awaitItem()
assertThat(initialState.isEnabled).isTrue() assertThat(initialState.isEnabled).isTrue()
assertThat(initialState.policyUrl).isNotEmpty()
} }
} }

View file

@ -16,15 +16,19 @@
package io.element.android.features.preferences.impl.analytics package io.element.android.features.preferences.impl.analytics
import android.app.Activity
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import com.bumble.appyx.core.modality.BuildContext import com.bumble.appyx.core.modality.BuildContext
import com.bumble.appyx.core.node.Node import com.bumble.appyx.core.node.Node
import com.bumble.appyx.core.plugin.Plugin import com.bumble.appyx.core.plugin.Plugin
import dagger.assisted.Assisted import dagger.assisted.Assisted
import dagger.assisted.AssistedInject import dagger.assisted.AssistedInject
import io.element.android.anvilannotations.ContributesNode import io.element.android.anvilannotations.ContributesNode
import io.element.android.libraries.androidutils.browser.openUrlInChromeCustomTab
import io.element.android.libraries.di.SessionScope import io.element.android.libraries.di.SessionScope
import io.element.android.libraries.theme.ElementTheme
@ContributesNode(SessionScope::class) @ContributesNode(SessionScope::class)
class AnalyticsSettingsNode @AssistedInject constructor( class AnalyticsSettingsNode @AssistedInject constructor(
@ -33,12 +37,19 @@ class AnalyticsSettingsNode @AssistedInject constructor(
private val presenter: AnalyticsSettingsPresenter, private val presenter: AnalyticsSettingsPresenter,
) : Node(buildContext, plugins = plugins) { ) : Node(buildContext, plugins = plugins) {
private fun onOpenAnalyticsPolicy(activity: Activity, darkTheme: Boolean, url: String) {
activity.openUrlInChromeCustomTab(null, darkTheme, url)
}
@Composable @Composable
override fun View(modifier: Modifier) { override fun View(modifier: Modifier) {
val activity = LocalContext.current as Activity
val isDark = ElementTheme.colors.isLight.not()
val state = presenter.present() val state = presenter.present()
AnalyticsSettingsView( AnalyticsSettingsView(
state = state, state = state,
onBackPressed = ::navigateUp, onBackPressed = ::navigateUp,
onOpenAnalyticsPolicy = { onOpenAnalyticsPolicy(activity, darkTheme = isDark, it) },
modifier = modifier modifier = modifier
) )
} }

View file

@ -31,6 +31,7 @@ import io.element.android.libraries.ui.strings.CommonStrings
fun AnalyticsSettingsView( fun AnalyticsSettingsView(
state: AnalyticsSettingsState, state: AnalyticsSettingsState,
onBackPressed: () -> Unit, onBackPressed: () -> Unit,
onOpenAnalyticsPolicy: (url: String) -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
PreferenceView( PreferenceView(
@ -40,6 +41,7 @@ fun AnalyticsSettingsView(
) { ) {
AnalyticsPreferencesView( AnalyticsPreferencesView(
state = state.analyticsState, state = state.analyticsState,
onOpenAnalyticsPolicy = onOpenAnalyticsPolicy,
) )
} }
} }
@ -59,5 +61,6 @@ private fun ContentToPreview(state: AnalyticsSettingsState) {
AnalyticsSettingsView( AnalyticsSettingsView(
state = state, state = state,
onBackPressed = {}, onBackPressed = {},
onOpenAnalyticsPolicy = {},
) )
} }