Browse Source

Merge pull request #1177 from vector-im/feature/bma/analyticsSettingLink

Fix issue on analytics setting link
pull/1187/head
Benoit Marty 1 year ago committed by GitHub
parent
commit
cbe9c27880
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      changelog.d/1177.bugfix
  2. 1
      features/analytics/api/src/main/kotlin/io/element/android/features/analytics/api/preferences/AnalyticsPreferencesState.kt
  3. 1
      features/analytics/api/src/main/kotlin/io/element/android/features/analytics/api/preferences/AnalyticsPreferencesStateProvider.kt
  4. 76
      features/analytics/api/src/main/kotlin/io/element/android/features/analytics/api/preferences/AnalyticsPreferencesView.kt
  5. 42
      features/analytics/impl/src/main/kotlin/io/element/android/features/analytics/impl/AnalyticsOptInView.kt
  6. 2
      features/analytics/impl/src/main/kotlin/io/element/android/features/analytics/impl/preferences/DefaultAnalyticsPreferencesPresenter.kt
  7. 1
      features/analytics/impl/src/test/kotlin/io/element/android/features/analytics/impl/preferences/AnalyticsPreferencesPresenterTest.kt
  8. 53
      features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemTextView.kt
  9. 4
      libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/ClickableLinkText.kt
  10. 10
      libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/text/AnnotatedStrings.kt
  11. 17
      libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/ListSection.kt
  12. BIN
      tests/uitests/src/test/snapshots/images/ui_S_t[f.analytics.api.preferences_null_AnalyticsPreferencesViewDark_0_null_0,NEXUS_5,1.0,en].png
  13. BIN
      tests/uitests/src/test/snapshots/images/ui_S_t[f.analytics.api.preferences_null_AnalyticsPreferencesViewLight_0_null_0,NEXUS_5,1.0,en].png
  14. BIN
      tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.analytics_null_AnalyticsSettingsViewDark_0_null_0,NEXUS_5,1.0,en].png
  15. BIN
      tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.analytics_null_AnalyticsSettingsViewLight_0_null_0,NEXUS_5,1.0,en].png

1
changelog.d/1177.bugfix

@ -0,0 +1 @@ @@ -0,0 +1 @@
Add missing link to the terms on the analytics setting screen.

1
features/analytics/api/src/main/kotlin/io/element/android/features/analytics/api/preferences/AnalyticsPreferencesState.kt

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

1
features/analytics/api/src/main/kotlin/io/element/android/features/analytics/api/preferences/AnalyticsPreferencesStateProvider.kt

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

76
features/analytics/api/src/main/kotlin/io/element/android/features/analytics/api/preferences/AnalyticsPreferencesView.kt

@ -16,22 +16,21 @@ @@ -16,22 +16,21 @@
package io.element.android.features.analytics.api.preferences
import androidx.annotation.StringRes
import androidx.compose.foundation.layout.Column
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import io.element.android.features.analytics.api.AnalyticsOptInEvents
import io.element.android.libraries.designsystem.components.preferences.PreferenceSwitch
import io.element.android.libraries.designsystem.components.LINK_TAG
import io.element.android.libraries.designsystem.components.list.ListItemContent
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
import io.element.android.libraries.theme.LinkColor
import io.element.android.libraries.designsystem.text.buildAnnotatedStringWithStyledPart
import io.element.android.libraries.designsystem.theme.components.ListItem
import io.element.android.libraries.designsystem.theme.components.ListSupportingText
import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.ui.strings.CommonStrings
@Composable
@ -43,40 +42,33 @@ fun AnalyticsPreferencesView( @@ -43,40 +42,33 @@ fun AnalyticsPreferencesView(
state.eventSink(AnalyticsOptInEvents.EnableAnalytics(isEnabled = isEnabled))
}
val firstPart = stringResource(id = CommonStrings.screen_analytics_settings_help_us_improve, state.applicationName)
val secondPart = buildAnnotatedStringWithColoredPart(
CommonStrings.screen_analytics_settings_read_terms,
CommonStrings.screen_analytics_settings_read_terms_content_link
)
val subtitle = "$firstPart\n\n$secondPart"
PreferenceSwitch(
modifier = modifier,
title = stringResource(id = CommonStrings.screen_analytics_settings_share_data),
subtitle = subtitle,
isChecked = state.isEnabled,
onCheckedChange = ::onEnabledChanged,
switchAlignment = Alignment.Top,
val supportingText = stringResource(
id = CommonStrings.screen_analytics_settings_help_us_improve,
state.applicationName
)
}
@Composable
fun buildAnnotatedStringWithColoredPart(
@StringRes fullTextRes: Int,
@StringRes coloredTextRes: Int,
color: Color = LinkColor,
underline: Boolean = true,
) = buildAnnotatedString {
val coloredPart = stringResource(coloredTextRes)
val fullText = stringResource(fullTextRes, coloredPart)
val startIndex = fullText.indexOf(coloredPart)
append(fullText)
addStyle(
style = SpanStyle(
color = color,
textDecoration = if (underline) TextDecoration.Underline else null
), start = startIndex, end = startIndex + coloredPart.length
val linkText = buildAnnotatedStringWithStyledPart(
CommonStrings.screen_analytics_settings_read_terms,
CommonStrings.screen_analytics_settings_read_terms_content_link,
tagAndLink = LINK_TAG to state.policyUrl,
)
Column(modifier) {
ListItem(
headlineContent = {
Text(stringResource(id = CommonStrings.screen_analytics_settings_share_data))
},
supportingContent = {
Text(supportingText)
},
leadingContent = null,
trailingContent = ListItemContent.Switch(
checked = state.isEnabled,
),
onClick = {
onEnabledChanged(!state.isEnabled)
}
)
ListSupportingText(annotatedString = linkText)
}
}
@Preview
@ -91,5 +83,7 @@ internal fun AnalyticsPreferencesViewDarkPreview(@PreviewParameter(AnalyticsPref @@ -91,5 +83,7 @@ internal fun AnalyticsPreferencesViewDarkPreview(@PreviewParameter(AnalyticsPref
@Composable
private fun ContentToPreview(state: AnalyticsPreferencesState) {
AnalyticsPreferencesView(state)
AnalyticsPreferencesView(
state = state,
)
}

42
features/analytics/impl/src/main/kotlin/io/element/android/features/analytics/impl/AnalyticsOptInView.kt

@ -18,7 +18,6 @@ package io.element.android.features.analytics.impl @@ -18,7 +18,6 @@ package io.element.android.features.analytics.impl
import androidx.activity.compose.BackHandler
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
@ -28,7 +27,7 @@ import androidx.compose.foundation.layout.padding @@ -28,7 +27,7 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.systemBarsPadding
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.ClickableText
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Poll
import androidx.compose.material.icons.rounded.Check
@ -37,7 +36,6 @@ import androidx.compose.runtime.Composable @@ -37,7 +36,6 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.BiasAlignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
@ -45,6 +43,7 @@ import androidx.compose.ui.tooling.preview.Preview @@ -45,6 +43,7 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp
import io.element.android.features.analytics.api.AnalyticsOptInEvents
import io.element.android.features.analytics.api.Config
import io.element.android.libraries.designsystem.atomic.molecules.ButtonColumnMolecule
import io.element.android.libraries.designsystem.atomic.molecules.IconTitleSubtitleMolecule
import io.element.android.libraries.designsystem.atomic.molecules.InfoListItem
@ -56,7 +55,6 @@ import io.element.android.libraries.designsystem.text.buildAnnotatedStringWithSt @@ -56,7 +55,6 @@ import io.element.android.libraries.designsystem.text.buildAnnotatedStringWithSt
import io.element.android.libraries.designsystem.theme.components.Button
import io.element.android.libraries.designsystem.theme.components.ButtonSize
import io.element.android.libraries.designsystem.theme.components.Icon
import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.designsystem.theme.components.TextButton
import io.element.android.libraries.designsystem.theme.temporaryColorBgSpecial
import io.element.android.libraries.designsystem.utils.LogCompositions
@ -98,6 +96,8 @@ fun AnalyticsOptInView( @@ -98,6 +96,8 @@ fun AnalyticsOptInView(
)
}
private const val LINK_TAG = "link"
@Composable
private fun AnalyticsOptInHeader(
state: AnalyticsOptInState,
@ -114,21 +114,29 @@ private fun AnalyticsOptInHeader( @@ -114,21 +114,29 @@ private fun AnalyticsOptInHeader(
subTitle = stringResource(id = R.string.screen_analytics_prompt_help_us_improve),
iconImageVector = Icons.Filled.Poll
)
Text(
text = buildAnnotatedStringWithStyledPart(
R.string.screen_analytics_prompt_read_terms,
R.string.screen_analytics_prompt_read_terms_content_link,
color = Color.Unspecified,
underline = false,
bold = true,
),
val text = buildAnnotatedStringWithStyledPart(
R.string.screen_analytics_prompt_read_terms,
R.string.screen_analytics_prompt_read_terms_content_link,
color = Color.Unspecified,
underline = false,
bold = true,
tagAndLink = LINK_TAG to Config.POLICY_LINK,
)
ClickableText(
text = text,
onClick = {
text
.getStringAnnotations(LINK_TAG, it, it)
.firstOrNull()
?.let { _ -> onClickTerms() }
},
modifier = Modifier
.clip(shape = RoundedCornerShape(8.dp))
.clickable { onClickTerms() }
.padding(8.dp),
style = ElementTheme.typography.fontBodyMdRegular,
textAlign = TextAlign.Center,
color = MaterialTheme.colorScheme.secondary,
style = ElementTheme.typography.fontBodyMdRegular
.copy(
color = MaterialTheme.colorScheme.secondary,
textAlign = TextAlign.Center,
)
)
}
}

2
features/analytics/impl/src/main/kotlin/io/element/android/features/analytics/impl/preferences/DefaultAnalyticsPreferencesPresenter.kt

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

1
features/analytics/impl/src/test/kotlin/io/element/android/features/analytics/impl/preferences/AnalyticsPreferencesPresenterTest.kt

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

53
features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemTextView.kt

@ -21,7 +21,9 @@ import androidx.compose.foundation.layout.Box @@ -21,7 +21,9 @@ import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.material3.LocalContentColor
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
@ -35,6 +37,7 @@ import io.element.android.libraries.designsystem.components.ClickableLinkText @@ -35,6 +37,7 @@ import io.element.android.libraries.designsystem.components.ClickableLinkText
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
import io.element.android.libraries.designsystem.text.toAnnotatedString
import io.element.android.libraries.theme.ElementTheme
@Composable
fun TimelineItemTextView(
@ -45,31 +48,33 @@ fun TimelineItemTextView( @@ -45,31 +48,33 @@ fun TimelineItemTextView(
onTextClicked: () -> Unit = {},
onTextLongClicked: () -> Unit = {},
) {
val htmlDocument = content.htmlDocument
if (htmlDocument != null) {
// For now we ignore the extra padding for html content, so add some spacing
// below the content (as previous behavior)
Column(modifier = modifier) {
HtmlDocument(
document = htmlDocument,
modifier = Modifier,
onTextClicked = onTextClicked,
onTextLongClicked = onTextLongClicked,
interactionSource = interactionSource
)
Spacer(Modifier.height(16.dp))
}
} else {
Box(modifier) {
val textWithPadding = remember(content.body) {
content.body + extraPadding.getStr(16.sp).toAnnotatedString()
CompositionLocalProvider(LocalContentColor provides ElementTheme.colors.textPrimary) {
val htmlDocument = content.htmlDocument
if (htmlDocument != null) {
// For now we ignore the extra padding for html content, so add some spacing
// below the content (as previous behavior)
Column(modifier = modifier) {
HtmlDocument(
document = htmlDocument,
modifier = Modifier,
onTextClicked = onTextClicked,
onTextLongClicked = onTextLongClicked,
interactionSource = interactionSource
)
Spacer(Modifier.height(16.dp))
}
} else {
Box(modifier) {
val textWithPadding = remember(content.body) {
content.body + extraPadding.getStr(16.sp).toAnnotatedString()
}
ClickableLinkText(
text = textWithPadding,
onClick = onTextClicked,
onLongClick = onTextLongClicked,
interactionSource = interactionSource
)
}
ClickableLinkText(
text = textWithPadding,
onClick = onTextClicked,
onLongClick = onTextLongClicked,
interactionSource = interactionSource
)
}
}
}

4
libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/ClickableLinkText.kt

@ -24,7 +24,6 @@ import androidx.compose.foundation.interaction.MutableInteractionSource @@ -24,7 +24,6 @@ import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.PressInteraction
import androidx.compose.foundation.text.InlineTextContent
import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
@ -79,8 +78,8 @@ fun ClickableLinkText( @@ -79,8 +78,8 @@ fun ClickableLinkText(
@Composable
fun ClickableLinkText(
annotatedString: AnnotatedString,
interactionSource: MutableInteractionSource,
modifier: Modifier = Modifier,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
linkify: Boolean = true,
linkAnnotationTag: String = LINK_TAG,
onClick: () -> Unit = {},
@ -136,7 +135,6 @@ fun ClickableLinkText( @@ -136,7 +135,6 @@ fun ClickableLinkText(
layoutResult.value = it
},
inlineContent = inlineContent,
color = MaterialTheme.colorScheme.primary,
)
}

10
libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/text/AnnotatedStrings.kt

@ -59,6 +59,7 @@ fun String.toAnnotatedString(): AnnotatedString = buildAnnotatedString { @@ -59,6 +59,7 @@ fun String.toAnnotatedString(): AnnotatedString = buildAnnotatedString {
* @param color the color to apply to the string
* @param underline whether to underline the string
* @param bold whether to bold the string
* @param tagAndLink an optional pair of tag and link to add to the styled part of the string, as StringAnnotation
*/
@Composable
fun buildAnnotatedStringWithStyledPart(
@ -67,6 +68,7 @@ fun buildAnnotatedStringWithStyledPart( @@ -67,6 +68,7 @@ fun buildAnnotatedStringWithStyledPart(
color: Color = LinkColor,
underline: Boolean = true,
bold: Boolean = false,
tagAndLink: Pair<String, String>? = null,
) = buildAnnotatedString {
val coloredPart = stringResource(coloredTextRes)
val fullText = stringResource(fullTextRes, coloredPart)
@ -81,6 +83,14 @@ fun buildAnnotatedStringWithStyledPart( @@ -81,6 +83,14 @@ fun buildAnnotatedStringWithStyledPart(
start = startIndex,
end = startIndex + coloredPart.length,
)
if (tagAndLink != null) {
addStringAnnotation(
tag = tagAndLink.first,
annotation = tagAndLink.second,
start = startIndex,
end = startIndex + coloredPart.length
)
}
}
/**

17
libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/ListSection.kt

@ -22,7 +22,6 @@ import androidx.compose.foundation.layout.PaddingValues @@ -22,7 +22,6 @@ import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Share
import androidx.compose.material.icons.outlined.Share
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.LocalTextStyle
@ -30,9 +29,11 @@ import androidx.compose.runtime.Composable @@ -30,9 +29,11 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.ExperimentalTextApi
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import io.element.android.libraries.designsystem.components.ClickableLinkText
import io.element.android.libraries.designsystem.components.list.ListItemContent
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
import io.element.android.libraries.designsystem.preview.PreviewGroup
@ -103,17 +104,21 @@ fun ListSupportingText( @@ -103,17 +104,21 @@ fun ListSupportingText(
* @param modifier The modifier to be applied to the text.
* @param contentPadding The padding to apply to the text. Default is [ListSupportingTextDefaults.Padding.Default].
*/
@OptIn(ExperimentalTextApi::class)
@Composable
fun ListSupportingText(
annotatedString: AnnotatedString,
modifier: Modifier = Modifier,
contentPadding: ListSupportingTextDefaults.Padding = ListSupportingTextDefaults.Padding.Default,
) {
Text(
text = annotatedString,
modifier = modifier.padding(contentPadding.paddingValues()),
style = ElementTheme.typography.fontBodySmRegular,
color = ElementTheme.colors.textSecondary,
val style = ElementTheme.typography.fontBodySmRegular
.copy(color = ElementTheme.colors.textSecondary)
val paddedModifier = modifier.padding(contentPadding.paddingValues())
ClickableLinkText(
annotatedString = annotatedString,
modifier = paddedModifier,
style = style,
linkify = false,
)
}

BIN
tests/uitests/src/test/snapshots/images/ui_S_t[f.analytics.api.preferences_null_AnalyticsPreferencesViewDark_0_null_0,NEXUS_5,1.0,en].png (Stored with Git LFS)

Binary file not shown.

BIN
tests/uitests/src/test/snapshots/images/ui_S_t[f.analytics.api.preferences_null_AnalyticsPreferencesViewLight_0_null_0,NEXUS_5,1.0,en].png (Stored with Git LFS)

Binary file not shown.

BIN
tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.analytics_null_AnalyticsSettingsViewDark_0_null_0,NEXUS_5,1.0,en].png (Stored with Git LFS)

Binary file not shown.

BIN
tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.analytics_null_AnalyticsSettingsViewLight_0_null_0,NEXUS_5,1.0,en].png (Stored with Git LFS)

Binary file not shown.
Loading…
Cancel
Save