Remove "history may be shared" banner. (#6087)
* Revert "Add alert to encrypted rooms with visible history (Android). (#5709)"
This reverts commit d0ba02dd7e.
* fix: Restore identity state change preview and snapshot.
This commit is contained in:
@@ -68,7 +68,6 @@ dependencies {
|
||||
implementation(libs.jsoup)
|
||||
implementation(libs.androidx.constraintlayout)
|
||||
implementation(libs.androidx.constraintlayout.compose)
|
||||
implementation(libs.androidx.datastore.preferences)
|
||||
implementation(libs.androidx.media3.exoplayer)
|
||||
implementation(libs.androidx.media3.ui)
|
||||
implementation(libs.sigpwned.emoji4j)
|
||||
|
||||
@@ -29,7 +29,6 @@ import io.element.android.appconfig.MessageComposerConfig
|
||||
import io.element.android.features.messages.api.timeline.HtmlConverterProvider
|
||||
import io.element.android.features.messages.impl.actionlist.ActionListState
|
||||
import io.element.android.features.messages.impl.actionlist.model.TimelineItemAction
|
||||
import io.element.android.features.messages.impl.crypto.historyvisible.HistoryVisibleState
|
||||
import io.element.android.features.messages.impl.crypto.identity.IdentityChangeState
|
||||
import io.element.android.features.messages.impl.link.LinkState
|
||||
import io.element.android.features.messages.impl.messagecomposer.MessageComposerEvent
|
||||
@@ -102,7 +101,6 @@ class MessagesPresenter(
|
||||
@Assisted private val timelinePresenter: Presenter<TimelineState>,
|
||||
private val timelineProtectionPresenter: Presenter<TimelineProtectionState>,
|
||||
private val identityChangeStatePresenter: Presenter<IdentityChangeState>,
|
||||
private val historyVisibleStatePresenter: Presenter<HistoryVisibleState>,
|
||||
private val linkPresenter: Presenter<LinkState>,
|
||||
@Assisted private val actionListPresenter: Presenter<ActionListState>,
|
||||
private val customReactionPresenter: Presenter<CustomReactionState>,
|
||||
@@ -154,7 +152,6 @@ class MessagesPresenter(
|
||||
val timelineState = timelinePresenter.present()
|
||||
val timelineProtectionState = timelineProtectionPresenter.present()
|
||||
val identityChangeState = identityChangeStatePresenter.present()
|
||||
val historyVisibleState = historyVisibleStatePresenter.present()
|
||||
val actionListState = actionListPresenter.present()
|
||||
val linkState = linkPresenter.present()
|
||||
val customReactionState = customReactionPresenter.present()
|
||||
@@ -286,7 +283,6 @@ class MessagesPresenter(
|
||||
timelineState = timelineState,
|
||||
timelineProtectionState = timelineProtectionState,
|
||||
identityChangeState = identityChangeState,
|
||||
historyVisibleState = historyVisibleState,
|
||||
linkState = linkState,
|
||||
actionListState = actionListState,
|
||||
customReactionState = customReactionState,
|
||||
|
||||
@@ -10,7 +10,6 @@ package io.element.android.features.messages.impl
|
||||
|
||||
import io.element.android.features.messages.api.timeline.voicemessages.composer.VoiceMessageComposerState
|
||||
import io.element.android.features.messages.impl.actionlist.ActionListState
|
||||
import io.element.android.features.messages.impl.crypto.historyvisible.HistoryVisibleState
|
||||
import io.element.android.features.messages.impl.crypto.identity.IdentityChangeState
|
||||
import io.element.android.features.messages.impl.link.LinkState
|
||||
import io.element.android.features.messages.impl.messagecomposer.MessageComposerState
|
||||
@@ -41,7 +40,6 @@ data class MessagesState(
|
||||
val timelineState: TimelineState,
|
||||
val timelineProtectionState: TimelineProtectionState,
|
||||
val identityChangeState: IdentityChangeState,
|
||||
val historyVisibleState: HistoryVisibleState,
|
||||
val linkState: LinkState,
|
||||
val actionListState: ActionListState,
|
||||
val customReactionState: CustomReactionState,
|
||||
|
||||
@@ -14,8 +14,6 @@ import io.element.android.features.messages.api.timeline.voicemessages.composer.
|
||||
import io.element.android.features.messages.api.timeline.voicemessages.composer.aVoiceMessagePreviewState
|
||||
import io.element.android.features.messages.impl.actionlist.ActionListState
|
||||
import io.element.android.features.messages.impl.actionlist.anActionListState
|
||||
import io.element.android.features.messages.impl.crypto.historyvisible.HistoryVisibleState
|
||||
import io.element.android.features.messages.impl.crypto.historyvisible.aHistoryVisibleState
|
||||
import io.element.android.features.messages.impl.crypto.identity.IdentityChangeState
|
||||
import io.element.android.features.messages.impl.crypto.identity.aRoomMemberIdentityStateChange
|
||||
import io.element.android.features.messages.impl.crypto.identity.anIdentityChangeState
|
||||
@@ -92,15 +90,6 @@ open class MessagesStateProvider : PreviewParameterProvider<MessagesState> {
|
||||
composerState = aMessageComposerState(textEditorState = aTextEditorStateMarkdown()),
|
||||
identityChangeState = anIdentityChangeState(listOf(aRoomMemberIdentityStateChange()))
|
||||
),
|
||||
aMessagesState(
|
||||
composerState = aMessageComposerState(textEditorState = aTextEditorStateMarkdown()),
|
||||
historyVisibleState = aHistoryVisibleState(showAlert = true)
|
||||
),
|
||||
aMessagesState(
|
||||
composerState = aMessageComposerState(textEditorState = aTextEditorStateMarkdown()),
|
||||
identityChangeState = anIdentityChangeState(listOf(aRoomMemberIdentityStateChange())),
|
||||
historyVisibleState = aHistoryVisibleState(showAlert = true)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -121,7 +110,6 @@ fun aMessagesState(
|
||||
),
|
||||
timelineProtectionState: TimelineProtectionState = aTimelineProtectionState(),
|
||||
identityChangeState: IdentityChangeState = anIdentityChangeState(),
|
||||
historyVisibleState: HistoryVisibleState = aHistoryVisibleState(),
|
||||
linkState: LinkState = aLinkState(),
|
||||
readReceiptBottomSheetState: ReadReceiptBottomSheetState = aReadReceiptBottomSheetState(),
|
||||
actionListState: ActionListState = anActionListState(),
|
||||
@@ -145,7 +133,6 @@ fun aMessagesState(
|
||||
voiceMessageComposerState = voiceMessageComposerState,
|
||||
timelineProtectionState = timelineProtectionState,
|
||||
identityChangeState = identityChangeState,
|
||||
historyVisibleState = historyVisibleState,
|
||||
linkState = linkState,
|
||||
timelineState = timelineState,
|
||||
readReceiptBottomSheetState = readReceiptBottomSheetState,
|
||||
|
||||
@@ -55,7 +55,6 @@ import io.element.android.features.messages.api.timeline.voicemessages.composer.
|
||||
import io.element.android.features.messages.impl.actionlist.ActionListEvent
|
||||
import io.element.android.features.messages.impl.actionlist.ActionListView
|
||||
import io.element.android.features.messages.impl.actionlist.model.TimelineItemAction
|
||||
import io.element.android.features.messages.impl.crypto.historyvisible.HistoryVisibleStateView
|
||||
import io.element.android.features.messages.impl.crypto.identity.IdentityChangeStateView
|
||||
import io.element.android.features.messages.impl.link.LinkEvent
|
||||
import io.element.android.features.messages.impl.link.LinkView
|
||||
@@ -520,17 +519,10 @@ private fun MessagesViewComposerBottomSheetContents(
|
||||
// Do not show the identity change if user is composing a Rich message or is seeing suggestion(s).
|
||||
if (state.composerState.suggestions.isEmpty() &&
|
||||
state.composerState.textEditorState is TextEditorState.Markdown) {
|
||||
if (state.identityChangeState.roomMemberIdentityStateChanges.isNotEmpty()) {
|
||||
IdentityChangeStateView(
|
||||
state = state.identityChangeState,
|
||||
onLinkClick = onLinkClick,
|
||||
)
|
||||
} else {
|
||||
HistoryVisibleStateView(
|
||||
state = state.historyVisibleState,
|
||||
onLinkClick = onLinkClick,
|
||||
)
|
||||
}
|
||||
IdentityChangeStateView(
|
||||
state = state.identityChangeState,
|
||||
onLinkClick = onLinkClick,
|
||||
)
|
||||
}
|
||||
val verificationViolation = state.identityChangeState.roomMemberIdentityStateChanges.firstOrNull {
|
||||
it.identityState == IdentityState.VerificationViolation
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
/*
|
||||
* 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.features.messages.impl.crypto.historyvisible
|
||||
|
||||
import androidx.datastore.preferences.core.booleanPreferencesKey
|
||||
import androidx.datastore.preferences.core.edit
|
||||
import dev.zacsweers.metro.ContributesBinding
|
||||
import io.element.android.libraries.androidutils.hash.hash
|
||||
import io.element.android.libraries.di.SessionScope
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.core.SessionId
|
||||
import io.element.android.libraries.preferences.api.store.PreferenceDataStoreFactory
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
||||
interface HistoryVisibleAcknowledgementRepository {
|
||||
fun hasAcknowledged(roomId: RoomId): Flow<Boolean>
|
||||
suspend fun setAcknowledged(roomId: RoomId, value: Boolean)
|
||||
}
|
||||
|
||||
@ContributesBinding(SessionScope::class)
|
||||
class DefaultHistoryVisibleAcknowledgementRepository(
|
||||
sessionId: SessionId,
|
||||
preferenceDataStoreFactory: PreferenceDataStoreFactory,
|
||||
) : HistoryVisibleAcknowledgementRepository {
|
||||
val store =
|
||||
sessionId.value.hash().take(16).let { hash ->
|
||||
preferenceDataStoreFactory.create("elementx_historyvisible_$hash")
|
||||
}
|
||||
|
||||
override fun hasAcknowledged(roomId: RoomId): Flow<Boolean> {
|
||||
return store.data.map { prefs ->
|
||||
val acknowledged = prefs[booleanPreferencesKey(roomId.value)] ?: false
|
||||
acknowledged
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun setAcknowledged(roomId: RoomId, value: Boolean) {
|
||||
store.edit { prefs ->
|
||||
prefs[booleanPreferencesKey(roomId.value)] = value
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
/*
|
||||
* 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.features.messages.impl.crypto.historyvisible
|
||||
|
||||
sealed interface HistoryVisibleEvent {
|
||||
data object Acknowledge : HistoryVisibleEvent
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
/*
|
||||
* 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.features.messages.impl.crypto.historyvisible
|
||||
|
||||
data class HistoryVisibleState(
|
||||
val showAlert: Boolean,
|
||||
val eventSink: (HistoryVisibleEvent) -> Unit,
|
||||
)
|
||||
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
* 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.features.messages.impl.crypto.historyvisible
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import dev.zacsweers.metro.Inject
|
||||
import io.element.android.libraries.architecture.Presenter
|
||||
import io.element.android.libraries.featureflag.api.FeatureFlagService
|
||||
import io.element.android.libraries.featureflag.api.FeatureFlags
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||
import io.element.android.libraries.matrix.api.room.history.RoomHistoryVisibility
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@Inject
|
||||
class HistoryVisibleStatePresenter(
|
||||
private val featureFlagService: FeatureFlagService,
|
||||
private val repository: HistoryVisibleAcknowledgementRepository,
|
||||
private val room: JoinedRoom,
|
||||
) : Presenter<HistoryVisibleState> {
|
||||
@Composable
|
||||
override fun present(): HistoryVisibleState {
|
||||
val isFeatureEnabled by featureFlagService.isFeatureEnabledFlow(FeatureFlags.EnableKeyShareOnInvite).collectAsState(initial = false)
|
||||
val roomInfo by room.roomInfoFlow.collectAsState()
|
||||
// Implicitly assume the alert is initially acknowledged to avoid flashes in UI.
|
||||
val acknowledged by repository.hasAcknowledged(room.roomId).collectAsState(initial = true)
|
||||
val isHistoryVisible = roomInfo.historyVisibility == RoomHistoryVisibility.Shared || roomInfo.historyVisibility == RoomHistoryVisibility.WorldReadable
|
||||
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
|
||||
LaunchedEffect(isHistoryVisible, acknowledged) {
|
||||
if (!isHistoryVisible && acknowledged) {
|
||||
// Clear the dismissed flag, if it is set to ensure that if a room is changed public -> private -> public,
|
||||
// we show the banner again when it is set back to public.
|
||||
repository.setAcknowledged(room.roomId, false)
|
||||
}
|
||||
}
|
||||
|
||||
fun handleEvent(event: HistoryVisibleEvent) {
|
||||
when (event) {
|
||||
is HistoryVisibleEvent.Acknowledge -> coroutineScope.setAcknowledged(room.roomId, true)
|
||||
}
|
||||
}
|
||||
|
||||
return HistoryVisibleState(
|
||||
showAlert = isFeatureEnabled && isHistoryVisible && roomInfo.isEncrypted == true && !acknowledged,
|
||||
eventSink = ::handleEvent,
|
||||
)
|
||||
}
|
||||
|
||||
private fun CoroutineScope.setAcknowledged(roomId: RoomId, value: Boolean) = launch {
|
||||
repository.setAcknowledged(roomId, value)
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
/*
|
||||
* 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.features.messages.impl.crypto.historyvisible
|
||||
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
|
||||
class HistoryVisibleStateProvider : PreviewParameterProvider<HistoryVisibleState> {
|
||||
override val values: Sequence<HistoryVisibleState>
|
||||
get() = sequenceOf(
|
||||
aHistoryVisibleState(showAlert = true),
|
||||
)
|
||||
}
|
||||
|
||||
internal fun aHistoryVisibleState(
|
||||
showAlert: Boolean = false,
|
||||
eventSink: (HistoryVisibleEvent) -> Unit = {},
|
||||
) = HistoryVisibleState(
|
||||
showAlert,
|
||||
eventSink = eventSink,
|
||||
)
|
||||
@@ -1,55 +0,0 @@
|
||||
/*
|
||||
* 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.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.tooling.preview.PreviewParameter
|
||||
import io.element.android.appconfig.LearnMoreConfig
|
||||
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
|
||||
fun HistoryVisibleStateView(
|
||||
state: HistoryVisibleState,
|
||||
onLinkClick: (String, Boolean) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
if (!state.showAlert) {
|
||||
return
|
||||
}
|
||||
ComposerAlertMolecule(
|
||||
modifier = modifier,
|
||||
avatar = null,
|
||||
showIcon = true,
|
||||
level = ComposerAlertLevel.Info,
|
||||
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) },
|
||||
)
|
||||
}
|
||||
|
||||
@PreviewsDayNight
|
||||
@Composable
|
||||
internal fun HistoryVisibleStateViewPreview(
|
||||
@PreviewParameter(HistoryVisibleStateProvider::class) state: HistoryVisibleState,
|
||||
) = ElementPreview {
|
||||
HistoryVisibleStateView(
|
||||
state = state,
|
||||
onLinkClick = { _, _ -> },
|
||||
)
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
* 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.features.messages.impl.crypto.historyvisible
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import io.element.android.features.messages.impl.MessagesView
|
||||
import io.element.android.features.messages.impl.aMessagesState
|
||||
import io.element.android.features.messages.impl.messagecomposer.aMessageComposerState
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||
import io.element.android.libraries.textcomposer.model.aTextEditorStateMarkdown
|
||||
|
||||
@PreviewsDayNight
|
||||
@Composable
|
||||
internal fun MessagesViewWithHistoryVisiblePreview() = ElementPreview {
|
||||
MessagesView(
|
||||
state = aMessagesState(
|
||||
composerState = aMessageComposerState(
|
||||
textEditorState = aTextEditorStateMarkdown(
|
||||
initialText = "",
|
||||
initialFocus = false,
|
||||
)
|
||||
),
|
||||
historyVisibleState = aHistoryVisibleState(showAlert = true),
|
||||
),
|
||||
onBackClick = {},
|
||||
onRoomDetailsClick = {},
|
||||
onEventContentClick = { _, _ -> false },
|
||||
onUserDataClick = {},
|
||||
onLinkClick = { _, _ -> },
|
||||
onSendLocationClick = {},
|
||||
onCreatePollClick = {},
|
||||
onJoinCallClick = {},
|
||||
onViewAllPinnedMessagesClick = {},
|
||||
knockRequestsBannerView = {}
|
||||
)
|
||||
}
|
||||
@@ -11,8 +11,6 @@ package io.element.android.features.messages.impl.di
|
||||
import dev.zacsweers.metro.BindingContainer
|
||||
import dev.zacsweers.metro.Binds
|
||||
import dev.zacsweers.metro.ContributesTo
|
||||
import io.element.android.features.messages.impl.crypto.historyvisible.HistoryVisibleState
|
||||
import io.element.android.features.messages.impl.crypto.historyvisible.HistoryVisibleStatePresenter
|
||||
import io.element.android.features.messages.impl.crypto.identity.IdentityChangeState
|
||||
import io.element.android.features.messages.impl.crypto.identity.IdentityChangeStatePresenter
|
||||
import io.element.android.features.messages.impl.crypto.sendfailure.resolve.ResolveVerifiedUserSendFailurePresenter
|
||||
@@ -63,7 +61,4 @@ interface MessagesBindsModule {
|
||||
|
||||
@Binds
|
||||
fun bindIdentityChangeStatePresenter(presenter: IdentityChangeStatePresenter): Presenter<IdentityChangeState>
|
||||
|
||||
@Binds
|
||||
fun bindHistoryVisibleStatePresenter(presenter: HistoryVisibleStatePresenter): Presenter<HistoryVisibleState>
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@ import io.element.android.features.messages.impl.actionlist.ActionListEvent
|
||||
import io.element.android.features.messages.impl.actionlist.ActionListState
|
||||
import io.element.android.features.messages.impl.actionlist.anActionListState
|
||||
import io.element.android.features.messages.impl.actionlist.model.TimelineItemAction
|
||||
import io.element.android.features.messages.impl.crypto.historyvisible.aHistoryVisibleState
|
||||
import io.element.android.features.messages.impl.crypto.identity.anIdentityChangeState
|
||||
import io.element.android.features.messages.impl.fixtures.aMessageEvent
|
||||
import io.element.android.features.messages.impl.link.aLinkState
|
||||
@@ -1310,7 +1309,6 @@ class MessagesPresenterTest {
|
||||
timelinePresenter = { aTimelineState(eventSink = timelineEventSink) },
|
||||
timelineProtectionPresenter = { aTimelineProtectionState() },
|
||||
identityChangeStatePresenter = { anIdentityChangeState() },
|
||||
historyVisibleStatePresenter = { aHistoryVisibleState() },
|
||||
linkPresenter = { aLinkState() },
|
||||
actionListPresenter = { anActionListState(eventSink = actionListEventSink) },
|
||||
customReactionPresenter = { aCustomReactionState() },
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
* 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.features.messages.impl.crypto.historyvisible
|
||||
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
||||
class FakeHistoryVisibleAcknowledgementRepository(
|
||||
private val acknowledgements: MutableMap<RoomId, MutableStateFlow<Boolean>> = mutableMapOf()
|
||||
) : HistoryVisibleAcknowledgementRepository {
|
||||
override fun hasAcknowledged(roomId: RoomId): Flow<Boolean> {
|
||||
return acknowledgements.getOrPut(roomId) {
|
||||
MutableStateFlow(false)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun setAcknowledged(roomId: RoomId, value: Boolean) {
|
||||
val flow = acknowledgements.getOrPut(roomId) {
|
||||
MutableStateFlow(value)
|
||||
}
|
||||
flow.emit(value)
|
||||
}
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* Create the repository with a pre-existing entry.
|
||||
*/
|
||||
fun withRoom(roomId: RoomId, acknowledged: Boolean = false): FakeHistoryVisibleAcknowledgementRepository {
|
||||
return FakeHistoryVisibleAcknowledgementRepository(
|
||||
mutableMapOf(
|
||||
roomId to MutableStateFlow(acknowledged)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,137 +0,0 @@
|
||||
/*
|
||||
* 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.features.messages.impl.crypto.historyvisible
|
||||
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.libraries.featureflag.api.FeatureFlags
|
||||
import io.element.android.libraries.featureflag.test.FakeFeatureFlagService
|
||||
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||
import io.element.android.libraries.matrix.api.room.history.RoomHistoryVisibility
|
||||
import io.element.android.libraries.matrix.test.room.FakeJoinedRoom
|
||||
import io.element.android.libraries.matrix.test.room.aRoomInfo
|
||||
import io.element.android.tests.testutils.WarmUpRule
|
||||
import io.element.android.tests.testutils.awaitLastSequentialItem
|
||||
import io.element.android.tests.testutils.test
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
|
||||
class HistoryVisibleStatePresenterTest {
|
||||
@get:Rule
|
||||
val warmUpRule = WarmUpRule()
|
||||
|
||||
@Test
|
||||
fun `present - not visible if feature disabled`() = runTest {
|
||||
val room = FakeJoinedRoom()
|
||||
room.givenRoomInfo(aRoomInfo(historyVisibility = RoomHistoryVisibility.Shared, isEncrypted = true))
|
||||
val presenter = createHistoryVisibleStatePresenter(room, enabled = false, acknowledged = false)
|
||||
presenter.test {
|
||||
assertThat(awaitLastSequentialItem().showAlert).isFalse()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - initial with room shared, unencrypted`() = runTest {
|
||||
val room = FakeJoinedRoom()
|
||||
room.givenRoomInfo(aRoomInfo(historyVisibility = RoomHistoryVisibility.Shared, isEncrypted = false))
|
||||
val presenter = createHistoryVisibleStatePresenter(room)
|
||||
presenter.test {
|
||||
assertThat(awaitLastSequentialItem().showAlert).isFalse()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - initial with room joined, encrypted`() = runTest {
|
||||
val room = FakeJoinedRoom()
|
||||
room.givenRoomInfo(aRoomInfo(historyVisibility = RoomHistoryVisibility.Joined, isEncrypted = true))
|
||||
val presenter = createHistoryVisibleStatePresenter(room)
|
||||
presenter.test {
|
||||
assertThat(awaitLastSequentialItem().showAlert).isFalse()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - initial with room invited, encrypted`() = runTest {
|
||||
val room = FakeJoinedRoom()
|
||||
room.givenRoomInfo(aRoomInfo(historyVisibility = RoomHistoryVisibility.Invited, isEncrypted = true))
|
||||
val presenter = createHistoryVisibleStatePresenter(room)
|
||||
presenter.test {
|
||||
assertThat(awaitLastSequentialItem().showAlert).isFalse()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - initial with room shared, encrypted, unacknowledged`() = runTest {
|
||||
val room = FakeJoinedRoom()
|
||||
room.givenRoomInfo(aRoomInfo(historyVisibility = RoomHistoryVisibility.Shared, isEncrypted = true))
|
||||
val presenter = createHistoryVisibleStatePresenter(room, acknowledged = false)
|
||||
presenter.test {
|
||||
val initialState = awaitItem()
|
||||
assertThat(initialState.showAlert).isFalse()
|
||||
val nextState = awaitItem()
|
||||
assertThat(nextState.showAlert).isTrue()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - initial with room shared, encrypted, acknowledged`() = runTest {
|
||||
val room = FakeJoinedRoom()
|
||||
room.givenRoomInfo(aRoomInfo(historyVisibility = RoomHistoryVisibility.Shared, isEncrypted = true))
|
||||
val presenter = createHistoryVisibleStatePresenter(room, acknowledged = true)
|
||||
presenter.test {
|
||||
assertThat(awaitLastSequentialItem().showAlert).isFalse()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - transition from joined + unencrypted, to shared + encrypted`() = runTest {
|
||||
val room = FakeJoinedRoom()
|
||||
val featureFlagService = FakeFeatureFlagService(mapOf(FeatureFlags.EnableKeyShareOnInvite.key to true))
|
||||
val repository = FakeHistoryVisibleAcknowledgementRepository()
|
||||
|
||||
room.givenRoomInfo(aRoomInfo(historyVisibility = RoomHistoryVisibility.Joined, isEncrypted = false))
|
||||
|
||||
val presenter = HistoryVisibleStatePresenter(
|
||||
featureFlagService,
|
||||
repository,
|
||||
room,
|
||||
)
|
||||
|
||||
presenter.test {
|
||||
// emitted by the feature flag service(?)
|
||||
assertThat(awaitItem().showAlert).isFalse()
|
||||
|
||||
// emitted state from room info assignment
|
||||
assertThat(awaitItem().showAlert).isFalse()
|
||||
|
||||
// room is marked as encrypted
|
||||
room.givenRoomInfo(aRoomInfo(historyVisibility = RoomHistoryVisibility.Joined, isEncrypted = true))
|
||||
assertThat(awaitItem().showAlert).isFalse()
|
||||
|
||||
// room history visibility is changed to shared
|
||||
room.givenRoomInfo(aRoomInfo(historyVisibility = RoomHistoryVisibility.Shared, isEncrypted = true))
|
||||
assertThat(awaitItem().showAlert).isTrue()
|
||||
|
||||
// alert is acknowledged
|
||||
repository.setAcknowledged(room.roomId, true)
|
||||
assertThat(awaitItem().showAlert).isFalse()
|
||||
}
|
||||
}
|
||||
|
||||
private fun createHistoryVisibleStatePresenter(
|
||||
room: JoinedRoom = FakeJoinedRoom(),
|
||||
enabled: Boolean = true,
|
||||
acknowledged: Boolean = false
|
||||
): HistoryVisibleStatePresenter {
|
||||
return HistoryVisibleStatePresenter(
|
||||
room = room,
|
||||
featureFlagService = FakeFeatureFlagService(mapOf("feature.enableKeyShareOnInvite" to enabled)),
|
||||
repository = FakeHistoryVisibleAcknowledgementRepository.withRoom(room.roomId, acknowledged)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -101,7 +101,6 @@ class KonsistPreviewTest {
|
||||
"MessageComposerViewVoicePreview",
|
||||
"MessagesReactionButtonAddPreview",
|
||||
"MessagesReactionButtonExtraPreview",
|
||||
"MessagesViewWithHistoryVisiblePreview",
|
||||
"MessagesViewWithIdentityChangePreview",
|
||||
"PendingMemberRowWithLongNamePreview",
|
||||
"PinUnlockViewInAppPreview",
|
||||
|
||||
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