Skip to content

Commit 44dc004

Browse files
authored
Merge pull request #3630 from element-hq/feature/bma/noIdentityChangeAlertInClearRoom
Do not render pin violation in clear rooms.
2 parents 45e502b + ef4aa8f commit 44dc004

File tree

3 files changed

+68
-17
lines changed

3 files changed

+68
-17
lines changed

features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/crypto/identity/IdentityChangeStatePresenter.kt

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,13 @@ import kotlinx.collections.immutable.PersistentList
2525
import kotlinx.collections.immutable.persistentListOf
2626
import kotlinx.collections.immutable.toPersistentList
2727
import kotlinx.coroutines.CoroutineScope
28+
import kotlinx.coroutines.ExperimentalCoroutinesApi
2829
import kotlinx.coroutines.flow.combine
2930
import kotlinx.coroutines.flow.distinctUntilChanged
31+
import kotlinx.coroutines.flow.filter
32+
import kotlinx.coroutines.flow.flatMapLatest
3033
import kotlinx.coroutines.flow.launchIn
34+
import kotlinx.coroutines.flow.map
3135
import kotlinx.coroutines.flow.onEach
3236
import kotlinx.coroutines.launch
3337
import timber.log.Timber
@@ -56,22 +60,31 @@ class IdentityChangeStatePresenter @Inject constructor(
5660
)
5761
}
5862

63+
@OptIn(ExperimentalCoroutinesApi::class)
5964
private fun ProduceStateScope<PersistentList<RoomMemberIdentityStateChange>>.observeRoomMemberIdentityStateChange() {
60-
combine(room.identityStateChangesFlow, room.membersStateFlow) { identityStateChanges, membersState ->
61-
identityStateChanges.map { identityStateChange ->
62-
val member = membersState.roomMembers()
63-
?.firstOrNull { roomMember -> roomMember.userId == identityStateChange.userId }
64-
?.toIdentityRoomMember()
65-
?: createDefaultRoomMemberForIdentityChange(identityStateChange.userId)
66-
RoomMemberIdentityStateChange(
67-
identityRoomMember = member,
68-
identityState = identityStateChange.identityState,
69-
)
65+
room.syncUpdateFlow
66+
.filter {
67+
// Room cannot become unencrypted, so we can just apply a filter here.
68+
room.isEncrypted
7069
}
71-
}
7270
.distinctUntilChanged()
73-
.onEach { roomMemberIdentityStateChanges ->
74-
value = roomMemberIdentityStateChanges.toPersistentList()
71+
.flatMapLatest {
72+
combine(room.identityStateChangesFlow, room.membersStateFlow,) { identityStateChanges, membersState ->
73+
identityStateChanges.map { identityStateChange ->
74+
val member = membersState.roomMembers()
75+
?.firstOrNull { roomMember -> roomMember.userId == identityStateChange.userId }
76+
?.toIdentityRoomMember()
77+
?: createDefaultRoomMemberForIdentityChange(identityStateChange.userId)
78+
RoomMemberIdentityStateChange(
79+
identityRoomMember = member,
80+
identityState = identityStateChange.identityState,
81+
)
82+
}
83+
}
84+
.distinctUntilChanged()
85+
.onEach { roomMemberIdentityStateChanges ->
86+
value = roomMemberIdentityStateChanges.toPersistentList()
87+
}
7588
}
7689
.launchIn(this)
7790
}

features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/crypto/identity/IdentityChangeStatePresenterTest.kt

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ class IdentityChangeStatePresenterTest {
4444

4545
@Test
4646
fun `present - when the room emits identity change, the presenter emits new state`() = runTest {
47-
val room = FakeMatrixRoom()
47+
val room = FakeMatrixRoom(isEncrypted = true)
4848
val presenter = createIdentityChangeStatePresenter(room)
4949
presenter.test {
5050
val initialState = awaitItem()
@@ -65,10 +65,37 @@ class IdentityChangeStatePresenterTest {
6565
}
6666
}
6767

68+
@Test
69+
fun `present - when the clear room emits identity change, the presenter does not emits new state`() = runTest {
70+
val room = FakeMatrixRoom(isEncrypted = false)
71+
val presenter = createIdentityChangeStatePresenter(room)
72+
presenter.test {
73+
val initialState = awaitItem()
74+
assertThat(initialState.roomMemberIdentityStateChanges).isEmpty()
75+
room.emitIdentityStateChanges(
76+
listOf(
77+
IdentityStateChange(
78+
userId = A_USER_ID_2,
79+
identityState = IdentityState.PinViolation,
80+
),
81+
)
82+
)
83+
// No item emitted.
84+
expectNoEvents()
85+
// Room become encrypted.
86+
room.enableEncryption()
87+
val finalItem = awaitItem()
88+
assertThat(finalItem.roomMemberIdentityStateChanges).hasSize(1)
89+
val value = finalItem.roomMemberIdentityStateChanges.first()
90+
assertThat(value.identityRoomMember.userId).isEqualTo(A_USER_ID_2)
91+
assertThat(value.identityState).isEqualTo(IdentityState.PinViolation)
92+
}
93+
}
94+
6895
@Test
6996
fun `present - when the room emits identity change, the presenter emits new state with member details`() =
7097
runTest {
71-
val room = FakeMatrixRoom().apply {
98+
val room = FakeMatrixRoom(isEncrypted = true).apply {
7299
givenRoomMembersState(
73100
MatrixRoomMembersState.Ready(
74101
listOf(

libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeMatrixRoom.kt

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ import kotlinx.coroutines.flow.Flow
6060
import kotlinx.coroutines.flow.MutableSharedFlow
6161
import kotlinx.coroutines.flow.MutableStateFlow
6262
import kotlinx.coroutines.flow.StateFlow
63+
import kotlinx.coroutines.flow.asStateFlow
6364
import java.io.File
6465

6566
class FakeMatrixRoom(
@@ -68,7 +69,7 @@ class FakeMatrixRoom(
6869
override val displayName: String = "",
6970
override val topic: String? = null,
7071
override val avatarUrl: String? = null,
71-
override val isEncrypted: Boolean = false,
72+
override var isEncrypted: Boolean = false,
7273
override val alias: RoomAlias? = null,
7374
override val alternativeAliases: List<RoomAlias> = emptyList(),
7475
override val isPublic: Boolean = true,
@@ -181,7 +182,17 @@ class FakeMatrixRoom(
181182
return Result.success(Unit)
182183
}
183184

184-
override val syncUpdateFlow: StateFlow<Long> = MutableStateFlow(0L)
185+
fun enableEncryption() {
186+
isEncrypted = true
187+
emitSyncUpdate()
188+
}
189+
190+
private val _syncUpdateFlow = MutableStateFlow(0L)
191+
override val syncUpdateFlow: StateFlow<Long> = _syncUpdateFlow.asStateFlow()
192+
193+
fun emitSyncUpdate() {
194+
_syncUpdateFlow.tryEmit(_syncUpdateFlow.value + 1)
195+
}
185196

186197
override suspend fun timelineFocusedOnEvent(eventId: EventId): Result<Timeline> = simulateLongTask {
187198
timelineFocusedOnEventResult(eventId)

0 commit comments

Comments
 (0)