Merge pull request #5942 from element-hq/feature/bma/roomHistoryVisibilitySettings
Simplify the copy of the history visibility settings
This commit is contained in:
@@ -10,18 +10,13 @@ package io.element.android.features.messages.impl.crypto.historyvisible
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.LinkAnnotation
|
||||
import androidx.compose.ui.text.SpanStyle
|
||||
import androidx.compose.ui.text.buildAnnotatedString
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextDecoration
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import io.element.android.appconfig.LearnMoreConfig
|
||||
import io.element.android.compound.theme.ElementTheme
|
||||
import io.element.android.libraries.designsystem.atomic.molecules.ComposerAlertLevel
|
||||
import io.element.android.libraries.designsystem.atomic.molecules.ComposerAlertMolecule
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||
import io.element.android.libraries.designsystem.text.stringWithLink
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
|
||||
@Composable
|
||||
@@ -33,37 +28,16 @@ fun HistoryVisibleStateView(
|
||||
if (!state.showAlert) {
|
||||
return
|
||||
}
|
||||
|
||||
ComposerAlertMolecule(
|
||||
modifier = modifier,
|
||||
avatar = null,
|
||||
showIcon = true,
|
||||
level = ComposerAlertLevel.Info,
|
||||
content = buildAnnotatedString {
|
||||
val learnMoreStr = stringResource(CommonStrings.action_learn_more)
|
||||
val fullText = stringResource(CommonStrings.crypto_history_visible, learnMoreStr)
|
||||
append(fullText)
|
||||
val learnMoreStartIndex = fullText.lastIndexOf(learnMoreStr)
|
||||
addStyle(
|
||||
style = SpanStyle(
|
||||
textDecoration = TextDecoration.Underline,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = ElementTheme.colors.textPrimary
|
||||
),
|
||||
start = learnMoreStartIndex,
|
||||
end = learnMoreStartIndex + learnMoreStr.length,
|
||||
)
|
||||
addLink(
|
||||
url = LinkAnnotation.Url(
|
||||
url = LearnMoreConfig.HISTORY_VISIBLE_URL,
|
||||
linkInteractionListener = {
|
||||
onLinkClick(LearnMoreConfig.HISTORY_VISIBLE_URL, true)
|
||||
}
|
||||
),
|
||||
start = learnMoreStartIndex,
|
||||
end = learnMoreStartIndex + learnMoreStr.length,
|
||||
)
|
||||
},
|
||||
content = stringWithLink(
|
||||
textRes = CommonStrings.crypto_history_visible,
|
||||
url = LearnMoreConfig.HISTORY_VISIBLE_URL,
|
||||
onLinkClick = { url -> onLinkClick(url, true) },
|
||||
),
|
||||
submitText = stringResource(CommonStrings.action_dismiss),
|
||||
onSubmitClick = { state.eventSink(HistoryVisibleEvent.Acknowledge) },
|
||||
)
|
||||
|
||||
@@ -157,10 +157,11 @@ We do not recommend enabling encryption for rooms that anyone can find and join.
|
||||
<string name="screen_security_and_privacy_room_directory_visibility_section_footer">"Allow for this room to be found by searching %1$s public room directory"</string>
|
||||
<string name="screen_security_and_privacy_room_directory_visibility_toggle_description">"Allow to be found by searching the public directory."</string>
|
||||
<string name="screen_security_and_privacy_room_directory_visibility_toggle_title">"Visible in public directory"</string>
|
||||
<string name="screen_security_and_privacy_room_history_anyone_option_title">"Anyone"</string>
|
||||
<string name="screen_security_and_privacy_room_history_anyone_option_title">"Anyone (history is public)"</string>
|
||||
<string name="screen_security_and_privacy_room_history_section_footer">"Changes won\'t affect past messages, only new ones. %1$s"</string>
|
||||
<string name="screen_security_and_privacy_room_history_section_header">"Who can read history"</string>
|
||||
<string name="screen_security_and_privacy_room_history_since_invite_option_title">"Members only since they were invited"</string>
|
||||
<string name="screen_security_and_privacy_room_history_since_selecting_option_title">"Members only since selecting this option"</string>
|
||||
<string name="screen_security_and_privacy_room_history_since_invite_option_title">"Members since invited"</string>
|
||||
<string name="screen_security_and_privacy_room_history_since_selecting_option_title">"Members (full history)"</string>
|
||||
<string name="screen_security_and_privacy_room_publishing_section_footer">"Room addresses are ways to find and access rooms. This also ensures you can easily share your room with others.
|
||||
You can choose to publish your room in your homeserver public room directory."</string>
|
||||
<string name="screen_security_and_privacy_room_publishing_section_header">"Room publishing"</string>
|
||||
|
||||
@@ -28,7 +28,9 @@ setupDependencyInjection()
|
||||
|
||||
dependencies {
|
||||
api(projects.features.securityandprivacy.api)
|
||||
implementation(projects.appconfig)
|
||||
implementation(projects.appnav)
|
||||
implementation(projects.libraries.androidutils)
|
||||
implementation(projects.libraries.architecture)
|
||||
implementation(projects.libraries.core)
|
||||
implementation(projects.libraries.designsystem)
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
|
||||
package io.element.android.features.securityandprivacy.impl.root
|
||||
|
||||
import android.app.Activity
|
||||
import androidx.activity.compose.LocalActivity
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
@@ -19,7 +21,9 @@ import com.bumble.appyx.core.plugin.plugins
|
||||
import dev.zacsweers.metro.Assisted
|
||||
import dev.zacsweers.metro.AssistedInject
|
||||
import io.element.android.annotations.ContributesNode
|
||||
import io.element.android.compound.theme.ElementTheme
|
||||
import io.element.android.features.securityandprivacy.impl.SecurityAndPrivacyNavigator
|
||||
import io.element.android.libraries.androidutils.browser.openUrlInChromeCustomTab
|
||||
import io.element.android.libraries.architecture.appyx.launchMolecule
|
||||
import io.element.android.libraries.di.RoomScope
|
||||
|
||||
@@ -35,11 +39,20 @@ class SecurityAndPrivacyNode(
|
||||
|
||||
private val stateFlow = launchMolecule { presenter.present() }
|
||||
|
||||
private fun onOpenExternalUrl(activity: Activity, darkTheme: Boolean, url: String) {
|
||||
activity.openUrlInChromeCustomTab(null, darkTheme, url)
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun View(modifier: Modifier) {
|
||||
val activity = requireNotNull(LocalActivity.current)
|
||||
val isDark = ElementTheme.isLightTheme.not()
|
||||
val state by stateFlow.collectAsState()
|
||||
SecurityAndPrivacyView(
|
||||
state = state,
|
||||
onLinkClick = { url ->
|
||||
onOpenExternalUrl(activity, isDark, url)
|
||||
},
|
||||
modifier = modifier
|
||||
)
|
||||
}
|
||||
|
||||
@@ -301,21 +301,21 @@ private fun SecurityAndPrivacyRoomAccess.map(): JoinRule? {
|
||||
|
||||
private fun RoomHistoryVisibility?.map(): SecurityAndPrivacyHistoryVisibility {
|
||||
return when (this) {
|
||||
RoomHistoryVisibility.WorldReadable -> SecurityAndPrivacyHistoryVisibility.Anyone
|
||||
RoomHistoryVisibility.Joined,
|
||||
RoomHistoryVisibility.Invited -> SecurityAndPrivacyHistoryVisibility.SinceInvite
|
||||
RoomHistoryVisibility.Shared -> SecurityAndPrivacyHistoryVisibility.SinceSelection
|
||||
// All other cases are not supported so we default to SinceSelection
|
||||
RoomHistoryVisibility.Invited -> SecurityAndPrivacyHistoryVisibility.Invited
|
||||
RoomHistoryVisibility.Shared -> SecurityAndPrivacyHistoryVisibility.Shared
|
||||
RoomHistoryVisibility.WorldReadable -> SecurityAndPrivacyHistoryVisibility.WorldReadable
|
||||
// All other cases are not supported so we default to Shared
|
||||
is RoomHistoryVisibility.Custom,
|
||||
null -> SecurityAndPrivacyHistoryVisibility.SinceSelection
|
||||
null -> SecurityAndPrivacyHistoryVisibility.Shared
|
||||
}
|
||||
}
|
||||
|
||||
private fun SecurityAndPrivacyHistoryVisibility.map(): RoomHistoryVisibility {
|
||||
return when (this) {
|
||||
SecurityAndPrivacyHistoryVisibility.SinceSelection -> RoomHistoryVisibility.Shared
|
||||
SecurityAndPrivacyHistoryVisibility.SinceInvite -> RoomHistoryVisibility.Invited
|
||||
SecurityAndPrivacyHistoryVisibility.Anyone -> RoomHistoryVisibility.WorldReadable
|
||||
SecurityAndPrivacyHistoryVisibility.Invited -> RoomHistoryVisibility.Invited
|
||||
SecurityAndPrivacyHistoryVisibility.Shared -> RoomHistoryVisibility.Shared
|
||||
SecurityAndPrivacyHistoryVisibility.WorldReadable -> RoomHistoryVisibility.WorldReadable
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ package io.element.android.features.securityandprivacy.impl.root
|
||||
import io.element.android.features.securityandprivacy.api.SecurityAndPrivacyPermissions
|
||||
import io.element.android.libraries.architecture.AsyncAction
|
||||
import io.element.android.libraries.architecture.AsyncData
|
||||
import kotlinx.collections.immutable.toImmutableSet
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
||||
data class SecurityAndPrivacyState(
|
||||
// the settings that are currently applied on the room.
|
||||
@@ -28,14 +28,18 @@ data class SecurityAndPrivacyState(
|
||||
) {
|
||||
val canBeSaved = savedSettings != editedSettings
|
||||
|
||||
val availableHistoryVisibilities = buildSet {
|
||||
add(SecurityAndPrivacyHistoryVisibility.SinceSelection)
|
||||
// Logic is in https://github.com/element-hq/element-meta/issues/3029
|
||||
val availableHistoryVisibilities = buildList {
|
||||
// Shared is always available
|
||||
add(SecurityAndPrivacyHistoryVisibility.Shared)
|
||||
if (editedSettings.roomAccess == SecurityAndPrivacyRoomAccess.Anyone && !editedSettings.isEncrypted) {
|
||||
add(SecurityAndPrivacyHistoryVisibility.Anyone)
|
||||
add(SecurityAndPrivacyHistoryVisibility.WorldReadable)
|
||||
} else {
|
||||
add(SecurityAndPrivacyHistoryVisibility.SinceInvite)
|
||||
add(SecurityAndPrivacyHistoryVisibility.Invited)
|
||||
}
|
||||
}.toImmutableSet()
|
||||
}
|
||||
.sorted()
|
||||
.toImmutableList()
|
||||
|
||||
val showRoomAccessSection = permissions.canChangeRoomAccess
|
||||
|
||||
@@ -55,18 +59,19 @@ data class SecurityAndPrivacySettings(
|
||||
)
|
||||
|
||||
enum class SecurityAndPrivacyHistoryVisibility {
|
||||
SinceSelection,
|
||||
SinceInvite,
|
||||
Anyone;
|
||||
// Order matters, and is from the most to the least restrictive
|
||||
Invited,
|
||||
Shared,
|
||||
WorldReadable;
|
||||
|
||||
/**
|
||||
* Returns the fallback visibility when the current visibility is not available.
|
||||
*/
|
||||
fun fallback(): SecurityAndPrivacyHistoryVisibility {
|
||||
return when (this) {
|
||||
SinceSelection,
|
||||
SinceInvite -> SinceSelection
|
||||
Anyone -> SinceInvite
|
||||
Invited,
|
||||
Shared -> Shared
|
||||
WorldReadable -> Invited
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ fun aSecurityAndPrivacySettings(
|
||||
roomAccess: SecurityAndPrivacyRoomAccess = SecurityAndPrivacyRoomAccess.InviteOnly,
|
||||
isEncrypted: Boolean = true,
|
||||
address: String? = null,
|
||||
historyVisibility: SecurityAndPrivacyHistoryVisibility = SecurityAndPrivacyHistoryVisibility.SinceSelection,
|
||||
historyVisibility: SecurityAndPrivacyHistoryVisibility = SecurityAndPrivacyHistoryVisibility.Shared,
|
||||
isVisibleInRoomDirectory: AsyncData<Boolean> = AsyncData.Uninitialized,
|
||||
) = SecurityAndPrivacySettings(
|
||||
roomAccess = roomAccess,
|
||||
|
||||
@@ -27,8 +27,10 @@ import androidx.compose.material3.ListItemDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.unit.dp
|
||||
import io.element.android.appconfig.LearnMoreConfig
|
||||
import io.element.android.compound.theme.ElementTheme
|
||||
import io.element.android.compound.tokens.generated.CompoundIcons
|
||||
import io.element.android.features.securityandprivacy.impl.R
|
||||
@@ -44,6 +46,7 @@ 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.designsystem.preview.PreviewWithLargeHeight
|
||||
import io.element.android.libraries.designsystem.text.stringWithLink
|
||||
import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator
|
||||
import io.element.android.libraries.designsystem.theme.components.IconSource
|
||||
import io.element.android.libraries.designsystem.theme.components.ListItem
|
||||
@@ -52,11 +55,12 @@ 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.components.TopAppBar
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
import kotlinx.collections.immutable.ImmutableSet
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
@Composable
|
||||
fun SecurityAndPrivacyView(
|
||||
state: SecurityAndPrivacyState,
|
||||
onLinkClick: (String) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
BackHandler {
|
||||
@@ -122,6 +126,7 @@ fun SecurityAndPrivacyView(
|
||||
savedOptions = state.savedSettings.historyVisibility,
|
||||
availableOptions = state.availableHistoryVisibilities,
|
||||
onSelectOption = { state.eventSink(SecurityAndPrivacyEvent.ChangeHistoryVisibility(it)) },
|
||||
onLinkClick = onLinkClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -176,6 +181,7 @@ private fun SecurityAndPrivacyToolbar(
|
||||
private fun SecurityAndPrivacySection(
|
||||
title: String,
|
||||
modifier: Modifier = Modifier,
|
||||
subtitle: AnnotatedString? = null,
|
||||
content: @Composable ColumnScope.() -> Unit,
|
||||
) {
|
||||
Column(
|
||||
@@ -187,6 +193,15 @@ private fun SecurityAndPrivacySection(
|
||||
color = ElementTheme.colors.textPrimary,
|
||||
modifier = Modifier.padding(horizontal = 16.dp),
|
||||
)
|
||||
if (subtitle != null) {
|
||||
Spacer(Modifier.height(8.dp))
|
||||
Text(
|
||||
text = subtitle,
|
||||
style = ElementTheme.typography.fontBodyMdRegular,
|
||||
color = ElementTheme.colors.textSecondary,
|
||||
modifier = Modifier.padding(horizontal = 16.dp),
|
||||
)
|
||||
}
|
||||
content()
|
||||
}
|
||||
}
|
||||
@@ -359,12 +374,18 @@ private fun EncryptionSection(
|
||||
private fun HistoryVisibilitySection(
|
||||
editedOption: SecurityAndPrivacyHistoryVisibility?,
|
||||
savedOptions: SecurityAndPrivacyHistoryVisibility?,
|
||||
availableOptions: ImmutableSet<SecurityAndPrivacyHistoryVisibility>,
|
||||
availableOptions: ImmutableList<SecurityAndPrivacyHistoryVisibility>,
|
||||
onSelectOption: (SecurityAndPrivacyHistoryVisibility) -> Unit,
|
||||
onLinkClick: (String) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
SecurityAndPrivacySection(
|
||||
title = stringResource(R.string.screen_security_and_privacy_room_history_section_header),
|
||||
subtitle = stringWithLink(
|
||||
textRes = R.string.screen_security_and_privacy_room_history_section_footer,
|
||||
url = LearnMoreConfig.HISTORY_VISIBLE_URL,
|
||||
onLinkClick = onLinkClick,
|
||||
),
|
||||
modifier = modifier,
|
||||
) {
|
||||
for (availableOption in availableOptions) {
|
||||
@@ -396,9 +417,9 @@ private fun HistoryVisibilityItem(
|
||||
isEnabled: Boolean = true,
|
||||
) {
|
||||
val headlineText = when (option) {
|
||||
SecurityAndPrivacyHistoryVisibility.SinceSelection -> stringResource(R.string.screen_security_and_privacy_room_history_since_selecting_option_title)
|
||||
SecurityAndPrivacyHistoryVisibility.SinceInvite -> stringResource(R.string.screen_security_and_privacy_room_history_since_invite_option_title)
|
||||
SecurityAndPrivacyHistoryVisibility.Anyone -> stringResource(R.string.screen_security_and_privacy_room_history_anyone_option_title)
|
||||
SecurityAndPrivacyHistoryVisibility.Invited -> stringResource(R.string.screen_security_and_privacy_room_history_since_invite_option_title)
|
||||
SecurityAndPrivacyHistoryVisibility.Shared -> stringResource(R.string.screen_security_and_privacy_room_history_since_selecting_option_title)
|
||||
SecurityAndPrivacyHistoryVisibility.WorldReadable -> stringResource(R.string.screen_security_and_privacy_room_history_anyone_option_title)
|
||||
}
|
||||
ListItem(
|
||||
headlineContent = { Text(text = headlineText) },
|
||||
@@ -424,5 +445,6 @@ internal fun SecurityAndPrivacyViewDarkPreview(@PreviewParameter(SecurityAndPriv
|
||||
private fun ContentToPreview(state: SecurityAndPrivacyState) {
|
||||
SecurityAndPrivacyView(
|
||||
state = state,
|
||||
onLinkClick = {},
|
||||
)
|
||||
}
|
||||
|
||||
@@ -31,10 +31,11 @@ We do not recommend enabling encryption for rooms that anyone can find and join.
|
||||
<string name="screen_security_and_privacy_room_directory_visibility_section_footer">"Allow for this room to be found by searching %1$s public room directory"</string>
|
||||
<string name="screen_security_and_privacy_room_directory_visibility_toggle_description">"Allow to be found by searching the public directory."</string>
|
||||
<string name="screen_security_and_privacy_room_directory_visibility_toggle_title">"Visible in public directory"</string>
|
||||
<string name="screen_security_and_privacy_room_history_anyone_option_title">"Anyone"</string>
|
||||
<string name="screen_security_and_privacy_room_history_anyone_option_title">"Anyone (history is public)"</string>
|
||||
<string name="screen_security_and_privacy_room_history_section_footer">"Changes won\'t affect past messages, only new ones. %1$s"</string>
|
||||
<string name="screen_security_and_privacy_room_history_section_header">"Who can read history"</string>
|
||||
<string name="screen_security_and_privacy_room_history_since_invite_option_title">"Members only since they were invited"</string>
|
||||
<string name="screen_security_and_privacy_room_history_since_selecting_option_title">"Members only since selecting this option"</string>
|
||||
<string name="screen_security_and_privacy_room_history_since_invite_option_title">"Members since invited"</string>
|
||||
<string name="screen_security_and_privacy_room_history_since_selecting_option_title">"Members (full history)"</string>
|
||||
<string name="screen_security_and_privacy_room_publishing_section_footer">"Room addresses are ways to find and access rooms. This also ensures you can easily share your room with others.
|
||||
You can choose to publish your room in your homeserver public room directory."</string>
|
||||
<string name="screen_security_and_privacy_room_publishing_section_header">"Room publishing"</string>
|
||||
|
||||
@@ -84,7 +84,7 @@ class SecurityAndPrivacyPresenterTest {
|
||||
with(awaitItem()) {
|
||||
assertThat(editedSettings).isEqualTo(savedSettings)
|
||||
assertThat(editedSettings.roomAccess).isEqualTo(SecurityAndPrivacyRoomAccess.Anyone)
|
||||
assertThat(editedSettings.historyVisibility).isEqualTo(SecurityAndPrivacyHistoryVisibility.Anyone)
|
||||
assertThat(editedSettings.historyVisibility).isEqualTo(SecurityAndPrivacyHistoryVisibility.WorldReadable)
|
||||
assertThat(editedSettings.address).isEqualTo(A_ROOM_ALIAS.value)
|
||||
assertThat(canBeSaved).isFalse()
|
||||
}
|
||||
@@ -122,16 +122,16 @@ class SecurityAndPrivacyPresenterTest {
|
||||
presenter.test {
|
||||
skipItems(1)
|
||||
with(awaitItem()) {
|
||||
assertThat(editedSettings.historyVisibility).isEqualTo(SecurityAndPrivacyHistoryVisibility.SinceSelection)
|
||||
eventSink(SecurityAndPrivacyEvent.ChangeHistoryVisibility(SecurityAndPrivacyHistoryVisibility.SinceInvite))
|
||||
assertThat(editedSettings.historyVisibility).isEqualTo(SecurityAndPrivacyHistoryVisibility.Shared)
|
||||
eventSink(SecurityAndPrivacyEvent.ChangeHistoryVisibility(SecurityAndPrivacyHistoryVisibility.Invited))
|
||||
}
|
||||
with(awaitItem()) {
|
||||
assertThat(editedSettings.historyVisibility).isEqualTo(SecurityAndPrivacyHistoryVisibility.SinceInvite)
|
||||
assertThat(editedSettings.historyVisibility).isEqualTo(SecurityAndPrivacyHistoryVisibility.Invited)
|
||||
assertThat(canBeSaved).isTrue()
|
||||
eventSink(SecurityAndPrivacyEvent.ChangeHistoryVisibility(SecurityAndPrivacyHistoryVisibility.SinceSelection))
|
||||
eventSink(SecurityAndPrivacyEvent.ChangeHistoryVisibility(SecurityAndPrivacyHistoryVisibility.Shared))
|
||||
}
|
||||
with(awaitItem()) {
|
||||
assertThat(editedSettings.historyVisibility).isEqualTo(SecurityAndPrivacyHistoryVisibility.SinceSelection)
|
||||
assertThat(editedSettings.historyVisibility).isEqualTo(SecurityAndPrivacyHistoryVisibility.Shared)
|
||||
assertThat(canBeSaved).isFalse()
|
||||
}
|
||||
}
|
||||
@@ -250,10 +250,10 @@ class SecurityAndPrivacyPresenterTest {
|
||||
eventSink(SecurityAndPrivacyEvent.ChangeRoomAccess(SecurityAndPrivacyRoomAccess.Anyone))
|
||||
}
|
||||
with(awaitItem()) {
|
||||
eventSink(SecurityAndPrivacyEvent.ChangeHistoryVisibility(SecurityAndPrivacyHistoryVisibility.Anyone))
|
||||
eventSink(SecurityAndPrivacyEvent.ChangeHistoryVisibility(SecurityAndPrivacyHistoryVisibility.WorldReadable))
|
||||
}
|
||||
with(awaitItem()) {
|
||||
assertThat(editedSettings.historyVisibility).isEqualTo(SecurityAndPrivacyHistoryVisibility.Anyone)
|
||||
assertThat(editedSettings.historyVisibility).isEqualTo(SecurityAndPrivacyHistoryVisibility.WorldReadable)
|
||||
eventSink(SecurityAndPrivacyEvent.ConfirmEnableEncryption)
|
||||
}
|
||||
skipItems(1)
|
||||
@@ -318,10 +318,10 @@ class SecurityAndPrivacyPresenterTest {
|
||||
eventSink(SecurityAndPrivacyEvent.ChangeRoomAccess(SecurityAndPrivacyRoomAccess.Anyone))
|
||||
}
|
||||
with(awaitItem()) {
|
||||
eventSink(SecurityAndPrivacyEvent.ChangeHistoryVisibility(SecurityAndPrivacyHistoryVisibility.Anyone))
|
||||
eventSink(SecurityAndPrivacyEvent.ChangeHistoryVisibility(SecurityAndPrivacyHistoryVisibility.WorldReadable))
|
||||
}
|
||||
with(awaitItem()) {
|
||||
assertThat(editedSettings.historyVisibility).isEqualTo(SecurityAndPrivacyHistoryVisibility.Anyone)
|
||||
assertThat(editedSettings.historyVisibility).isEqualTo(SecurityAndPrivacyHistoryVisibility.WorldReadable)
|
||||
eventSink(SecurityAndPrivacyEvent.ConfirmEnableEncryption)
|
||||
}
|
||||
skipItems(1)
|
||||
|
||||
@@ -24,6 +24,7 @@ import io.element.android.features.securityandprivacy.impl.root.aSecurityAndPriv
|
||||
import io.element.android.libraries.architecture.AsyncAction
|
||||
import io.element.android.libraries.architecture.AsyncData
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
import io.element.android.tests.testutils.EnsureNeverCalledWithParam
|
||||
import io.element.android.tests.testutils.EventsRecorder
|
||||
import io.element.android.tests.testutils.clickOn
|
||||
import io.element.android.tests.testutils.pressBack
|
||||
@@ -140,22 +141,22 @@ class SecurityAndPrivacyViewTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(qualifiers = "h640dp")
|
||||
@Config(qualifiers = "h1024dp")
|
||||
fun `click on history visibility item emits the expected event`() {
|
||||
val recorder = EventsRecorder<SecurityAndPrivacyEvent>()
|
||||
val state = aSecurityAndPrivacyState(
|
||||
eventSink = recorder,
|
||||
editedSettings = aSecurityAndPrivacySettings(
|
||||
historyVisibility = SecurityAndPrivacyHistoryVisibility.SinceSelection,
|
||||
historyVisibility = SecurityAndPrivacyHistoryVisibility.Invited,
|
||||
),
|
||||
)
|
||||
rule.setSecurityAndPrivacyView(state)
|
||||
rule.clickOn(R.string.screen_security_and_privacy_room_history_since_selecting_option_title)
|
||||
recorder.assertSingle(SecurityAndPrivacyEvent.ChangeHistoryVisibility(SecurityAndPrivacyHistoryVisibility.SinceSelection))
|
||||
rule.clickOn(R.string.screen_security_and_privacy_room_history_since_invite_option_title)
|
||||
recorder.assertSingle(SecurityAndPrivacyEvent.ChangeHistoryVisibility(SecurityAndPrivacyHistoryVisibility.Invited))
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(qualifiers = "h640dp")
|
||||
@Config(qualifiers = "h1024dp")
|
||||
fun `click on encryption item emits the expected event`() {
|
||||
val recorder = EventsRecorder<SecurityAndPrivacyEvent>()
|
||||
val state = aSecurityAndPrivacyState(
|
||||
@@ -184,10 +185,12 @@ private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setSecur
|
||||
state: SecurityAndPrivacyState = aSecurityAndPrivacyState(
|
||||
eventSink = EventsRecorder(expectEvents = false),
|
||||
),
|
||||
onLinkClick: (String) -> Unit = EnsureNeverCalledWithParam(),
|
||||
) {
|
||||
setContent {
|
||||
SecurityAndPrivacyView(
|
||||
state = state,
|
||||
onLinkClick = onLinkClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.designsystem.text
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.LinkAnnotation
|
||||
import androidx.compose.ui.text.SpanStyle
|
||||
import androidx.compose.ui.text.buildAnnotatedString
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextDecoration
|
||||
import io.element.android.compound.theme.ElementTheme
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
|
||||
@Composable
|
||||
fun stringWithLink(
|
||||
@StringRes textRes: Int,
|
||||
url: String,
|
||||
onLinkClick: (String) -> Unit,
|
||||
@StringRes linkTextRes: Int = CommonStrings.action_learn_more,
|
||||
) = buildAnnotatedString {
|
||||
val learnMoreStr = stringResource(linkTextRes)
|
||||
val fullText = stringResource(textRes, learnMoreStr)
|
||||
append(fullText)
|
||||
val learnMoreStartIndex = fullText.lastIndexOf(learnMoreStr)
|
||||
addStyle(
|
||||
style = SpanStyle(
|
||||
textDecoration = TextDecoration.Underline,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = ElementTheme.colors.textPrimary
|
||||
),
|
||||
start = learnMoreStartIndex,
|
||||
end = learnMoreStartIndex + learnMoreStr.length,
|
||||
)
|
||||
addLink(
|
||||
url = LinkAnnotation.Url(
|
||||
url = url,
|
||||
linkInteractionListener = {
|
||||
onLinkClick(url)
|
||||
}
|
||||
),
|
||||
start = learnMoreStartIndex,
|
||||
end = learnMoreStartIndex + learnMoreStr.length,
|
||||
)
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user