Merge pull request #5942 from element-hq/feature/bma/roomHistoryVisibilitySettings
Simplify the copy of the history visibility settings
This commit is contained in:
commit
5551f4e039
36 changed files with 199 additions and 127 deletions
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:71acb17375db16b8777221e3a09c85ce821920dfaf7853c456493371e4778b9d
|
||||
size 37050
|
||||
oid sha256:85a7f1e86ee77355ada16764c0cdaa96193237e1e0936188b00b99247b67f272
|
||||
size 39232
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:b03d25813c75712a0b9e23622132bd63e07ca9ec593a1842dacf751347c06ea1
|
||||
size 32023
|
||||
oid sha256:507eec1e5125056ca4980ae67f904dd30bcb88ef6d66d5968aafbb3c1449e4b8
|
||||
size 33779
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:3aaf6da43b5f2882da986ae766d0057421b1f39f7f0bb467bd32f2a957608045
|
||||
size 31478
|
||||
oid sha256:d300a9854096634ea0e6722db487607a75f6e0c46d7341f044a190a212d95307
|
||||
size 32373
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:72be11ed273a790b0ab8e5023c1e21384c020e1b0fc0e3950de8f041c4004e64
|
||||
size 33758
|
||||
oid sha256:b42e3df9fec259210b63431e295e8c7d1a7640149c9616b572b90c0b40392a60
|
||||
size 34637
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:5343bc348bc1be7430243ce6fceeb7c81bbf2d5692486733221cb6c615d9aeea
|
||||
size 41544
|
||||
oid sha256:3bb107a37b14dcbc6aa530a8d47f58c809df7719a0c8a416a268ffd2df165681
|
||||
size 41602
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:9cf6cd1f914a4f31608edceefde79632ebed0c8983d83d8a63c4408bcc2d4ff3
|
||||
size 56743
|
||||
oid sha256:6a2d21173c63d0b9b3a558d23acd380c9d15fe5c4dc1b62f31644817318e049f
|
||||
size 56061
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:00a667f59cd097021a6d363d0e4f578cba6acc405aaaa74bddfa9a3286cfd26e
|
||||
size 56408
|
||||
oid sha256:89598f3f1149cec915196f1abb1998855c3dd161d6f05f32bccc7bb85cd1938a
|
||||
size 55715
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:5bdcf84378968b8e37cc50a300ff19b1917354de764a9f81448e6ca3d4050386
|
||||
size 54711
|
||||
oid sha256:8ae448a2c6f5da0b563873a683884d75a74ded6157edc56e91507a1857ff87ee
|
||||
size 56298
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:577eac69d32648070d896788474104fdf143c040e058f182d6b832e5ea83fad8
|
||||
size 37242
|
||||
oid sha256:b67ebf4536e36571b0867e71533b2fe1953ca2b88f15fe3531f3ddb9043f69ec
|
||||
size 39418
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:745a270883c79932fdde14d11785d9e27d1ec0eee03999af5e494b5c6e30c309
|
||||
size 57329
|
||||
oid sha256:e5fb16ef839b9f93caddbc984c8be260846e7fd7d68ae3b31dcc97c7644b41b4
|
||||
size 56670
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:451eee79c5ca4b61902044c58f99069065fcd11a9fa7d469d2568cd20ea134a3
|
||||
size 56743
|
||||
oid sha256:9402ad99b181b99083abff78d078e9fbb010144e07f80ff995db7884a61fa853
|
||||
size 56060
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:023b2870f5a4291ad8b521dc177db22972a47e5e965458c81cb8688da0cbe6b8
|
||||
size 57097
|
||||
oid sha256:cadacec9344f3ca2c029006c620cd8c309bb7f4b38cbb7b47c7c336ca265a141
|
||||
size 56424
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:1463d9c6b2d968c0a5f375e5135b31e31b32f2d35525e0be1c264d90ff4e723c
|
||||
size 38652
|
||||
oid sha256:cc24db5d5659ddee2787ffc6a3371351478c9ccd7cfb909ede6a06f1e72a907a
|
||||
size 40756
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:09a88867a2f10ce346df8d683d614970f9aad8e8ec7bf06bddf27352dc0e5476
|
||||
size 33520
|
||||
oid sha256:548950d915f6fbfdf1a17b81619d3d4cbefe93b79091d259bcec41ae6bbbc652
|
||||
size 35422
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:81162b1f086e45797db0678eff6bc41ad35eb09a7ac436d540fd3b7e1feffbc6
|
||||
size 33534
|
||||
oid sha256:6b47bcab08cded6e857fe213ab2c90602e557a36feebb45b2b8d4d18115ac68b
|
||||
size 34582
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:c1cbcce698faad80969cd00d2680afd7cd61b6ba649f0b67e8c7fb2fe0dbe746
|
||||
size 35884
|
||||
oid sha256:5cd5de47e285702bf3d2ee325fc83a1168a0367d9c6b54018565daa0ed503a77
|
||||
size 36876
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:b0ce43031e71ffadc53388a66a9ceb66b1c9bb33014a912161ec6006a303050b
|
||||
size 43544
|
||||
oid sha256:59b6d7d5e484b34e1ce7814432144df34b1cd3323d31c90db439cbb5d9f8dc83
|
||||
size 43588
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:a906ec0c412892a241eab241836d4238c1883ec1d27f27b8a012de75894fdaf7
|
||||
size 58785
|
||||
oid sha256:01cab7fd5a8b4e10a4ecca8a31b0f659fb9f2db9260272b0f6c96c4e126050aa
|
||||
size 57895
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:8e4ccb39f3024e3a98be3bc0f94ce769e412b891ed988dad4cf1457aab3cea72
|
||||
size 58442
|
||||
oid sha256:18e03a178666b24e95a9cd0ae5d95d0fe57db49d11b1b1f3cae5ed472e94b6d7
|
||||
size 57550
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:e8b10af4e5006f45e2fe738a3a8a589551378ee9106c09f10b9de81fdbf12e61
|
||||
size 56716
|
||||
oid sha256:f4aee340402c5fa0cdcaf2603ae5999f353eec734a1ab928c242889a1d5d2425
|
||||
size 58272
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:bc82d2ab3bc9d73726bcc0cdc5dc27b628d00db330cfcc7a78f177af029a7803
|
||||
size 38810
|
||||
oid sha256:a3bebec99f2b870e7a38333590f5cb776b30f4f9b976d99601a7fb3bfd05a71f
|
||||
size 40913
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:aef64f63cb176feea3ee1e48de98f7bf6ed104370f84e377c963a2f26ba0fa49
|
||||
size 59387
|
||||
oid sha256:853218e7ddc4d18b260f6ab047beb82778284851e230babc14113c6cb329d29a
|
||||
size 58504
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:e6f46d940ee39961ea128fc7fc607dd6156d827121def3516ef62ff5f617e249
|
||||
size 58785
|
||||
oid sha256:e7caee4430244e294b75e3b6a5830088dd25397b1c272666eb2bec47ecd1f382
|
||||
size 57895
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:6ea58c892886c9de971fd22a5a72340775cb0f973cdfb697d7f517100ce8b65d
|
||||
size 59205
|
||||
oid sha256:bbb4224047c88d838de227e61332775e5efe0ce1380a7446c701f0db5b2d2dcc
|
||||
size 58323
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue