Skip to content

Commit 800a331

Browse files
authored
Merge pull request #4824 from element-hq/feature/fga/fix_identity_change
fix (identity change) : RoomMemberIdentityStateChange in non encrypted room
2 parents a989368 + e664e24 commit 800a331

File tree

6 files changed

+437
-45
lines changed

6 files changed

+437
-45
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import io.element.android.libraries.architecture.Presenter
1515
import io.element.android.libraries.matrix.api.core.UserId
1616
import io.element.android.libraries.matrix.api.encryption.EncryptionService
1717
import io.element.android.libraries.matrix.api.room.JoinedRoom
18-
import io.element.android.libraries.matrix.ui.room.observeRoomMemberIdentityStateChange
18+
import io.element.android.libraries.matrix.ui.room.roomMemberIdentityStateChange
1919
import kotlinx.collections.immutable.persistentListOf
2020
import kotlinx.coroutines.CoroutineScope
2121
import kotlinx.coroutines.launch
@@ -30,7 +30,7 @@ class IdentityChangeStatePresenter @Inject constructor(
3030
override fun present(): IdentityChangeState {
3131
val coroutineScope = rememberCoroutineScope()
3232
val roomMemberIdentityStateChange by produceState(persistentListOf()) {
33-
observeRoomMemberIdentityStateChange(room)
33+
room.roomMemberIdentityStateChange(waitForEncryption = true).collect { value = it }
3434
}
3535

3636
fun handleEvent(event: IdentityChangeEvent) {

features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsPresenter.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ class RoomDetailsPresenter @Inject constructor(
174174
}
175175

176176
val hasMemberVerificationViolations by produceState(false) {
177-
room.roomMemberIdentityStateChange()
177+
room.roomMemberIdentityStateChange(waitForEncryption = true)
178178
.onEach { identities -> value = identities.any { it.identityState == IdentityState.VerificationViolation } }
179179
.launchIn(this)
180180
}

features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListPresenter.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ class RoomMemberListPresenter @Inject constructor(
6666
val roomModerationState = roomMembersModerationPresenter.present()
6767

6868
val roomMemberIdentityStates by produceState(persistentMapOf<UserId, IdentityState>()) {
69-
room.roomMemberIdentityStateChange()
69+
room.roomMemberIdentityStateChange(waitForEncryption = true)
7070
.onEach { identities ->
7171
value = identities.associateBy({ it.identityRoomMember.userId }, { it.identityState }).toPersistentMap()
7272
}

features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/details/RoomMemberDetailsPresenter.kt

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ package io.element.android.features.roomdetails.impl.members.details
99

1010
import androidx.compose.runtime.Composable
1111
import androidx.compose.runtime.LaunchedEffect
12+
import androidx.compose.runtime.derivedStateOf
1213
import androidx.compose.runtime.getValue
1314
import androidx.compose.runtime.produceState
1415
import androidx.compose.runtime.remember
@@ -33,9 +34,7 @@ import io.element.android.libraries.matrix.ui.room.getRoomMemberAsState
3334
import io.element.android.libraries.matrix.ui.room.roomMemberIdentityStateChange
3435
import io.element.android.libraries.ui.strings.CommonStrings
3536
import kotlinx.coroutines.ExperimentalCoroutinesApi
36-
import kotlinx.coroutines.flow.filter
3737
import kotlinx.coroutines.flow.filterNotNull
38-
import kotlinx.coroutines.flow.flatMapLatest
3938
import kotlinx.coroutines.flow.map
4039
import kotlinx.coroutines.launch
4140

@@ -86,31 +85,30 @@ class RoomMemberDetailsPresenter @AssistedInject constructor(
8685

8786
val userProfileState = userProfilePresenter.present()
8887

89-
val identityStateChanges by produceState<IdentityStateChange?>(initialValue = null) {
90-
room.roomInfoFlow.filter { it.isEncrypted == true }
91-
.flatMapLatest {
92-
// Fetch the initial identity state manually
93-
val identityState = encryptionService.getUserIdentity(roomMemberId).getOrNull()
94-
value = identityState?.let { IdentityStateChange(roomMemberId, it) }
88+
val identityStateChanges = produceState<IdentityStateChange?>(initialValue = null) {
89+
// Fetch the initial identity state manually
90+
val identityState = encryptionService.getUserIdentity(roomMemberId).getOrNull()
91+
value = identityState?.let { IdentityStateChange(roomMemberId, it) }
9592

96-
// Subscribe to the identity changes
97-
room.roomMemberIdentityStateChange()
98-
.map { it.find { it.identityRoomMember.userId == roomMemberId } }
99-
.map { roomMemberIdentityStateChange ->
100-
// If we didn't receive any info, manually fetch it
101-
roomMemberIdentityStateChange?.identityState ?: encryptionService.getUserIdentity(roomMemberId).getOrNull()
102-
}
103-
.filterNotNull()
93+
// Subscribe to the identity changes
94+
room.roomMemberIdentityStateChange(waitForEncryption = false)
95+
.map { it.find { it.identityRoomMember.userId == roomMemberId } }
96+
.map { roomMemberIdentityStateChange ->
97+
// If we didn't receive any info, manually fetch it
98+
roomMemberIdentityStateChange?.identityState ?: encryptionService.getUserIdentity(roomMemberId).getOrNull()
10499
}
100+
.filterNotNull()
105101
.collect { value = IdentityStateChange(roomMemberId, it) }
106102
}
107103

108-
val verificationState = remember(identityStateChanges) {
109-
when (identityStateChanges?.identityState) {
110-
IdentityState.VerificationViolation -> UserProfileVerificationState.VERIFICATION_VIOLATION
111-
IdentityState.Verified -> UserProfileVerificationState.VERIFIED
112-
IdentityState.Pinned, IdentityState.PinViolation -> UserProfileVerificationState.UNVERIFIED
113-
else -> UserProfileVerificationState.UNKNOWN
104+
val verificationState by remember {
105+
derivedStateOf {
106+
when (identityStateChanges.value?.identityState) {
107+
IdentityState.VerificationViolation -> UserProfileVerificationState.VERIFICATION_VIOLATION
108+
IdentityState.Verified -> UserProfileVerificationState.VERIFIED
109+
IdentityState.Pinned, IdentityState.PinViolation -> UserProfileVerificationState.UNVERIFIED
110+
else -> UserProfileVerificationState.UNKNOWN
111+
}
114112
}
115113
}
116114

libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/room/ObserveRoomMemberIdentityStateChange.kt

Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77

88
package io.element.android.libraries.matrix.ui.room
99

10-
import androidx.compose.runtime.ProduceStateScope
1110
import io.element.android.libraries.designsystem.components.avatar.AvatarData
1211
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
1312
import io.element.android.libraries.matrix.api.core.UserId
@@ -17,25 +16,25 @@ import io.element.android.libraries.matrix.api.room.RoomMember
1716
import io.element.android.libraries.matrix.api.room.roomMembers
1817
import io.element.android.libraries.matrix.ui.model.getAvatarData
1918
import kotlinx.collections.immutable.ImmutableList
20-
import kotlinx.collections.immutable.PersistentList
2119
import kotlinx.collections.immutable.toPersistentList
2220
import kotlinx.coroutines.ExperimentalCoroutinesApi
2321
import kotlinx.coroutines.flow.Flow
2422
import kotlinx.coroutines.flow.combine
2523
import kotlinx.coroutines.flow.distinctUntilChanged
26-
import kotlinx.coroutines.flow.filter
24+
import kotlinx.coroutines.flow.first
2725
import kotlinx.coroutines.flow.flatMapLatest
28-
import kotlinx.coroutines.flow.launchIn
29-
import kotlinx.coroutines.flow.onEach
26+
import kotlinx.coroutines.flow.flow
3027

3128
@OptIn(ExperimentalCoroutinesApi::class)
32-
fun JoinedRoom.roomMemberIdentityStateChange(): Flow<ImmutableList<RoomMemberIdentityStateChange>> {
33-
return roomInfoFlow
34-
.filter {
35-
// Room cannot become unencrypted, so we can just apply a filter here.
36-
it.isEncrypted == true
29+
fun JoinedRoom.roomMemberIdentityStateChange(waitForEncryption: Boolean): Flow<ImmutableList<RoomMemberIdentityStateChange>> {
30+
val encryptionChangeFlow = flow {
31+
if (waitForEncryption) {
32+
// Room cannot become unencrypted, so it's ok to use first here
33+
roomInfoFlow.first { roomInfo -> roomInfo.isEncrypted == true }
3734
}
38-
.distinctUntilChanged()
35+
emit(Unit)
36+
}
37+
return encryptionChangeFlow
3938
.flatMapLatest {
4039
combine(identityStateChangesFlow, membersStateFlow) { identityStateChanges, membersState ->
4140
identityStateChanges.map { identityStateChange ->
@@ -52,14 +51,6 @@ fun JoinedRoom.roomMemberIdentityStateChange(): Flow<ImmutableList<RoomMemberIde
5251
}
5352
}
5453

55-
fun ProduceStateScope<PersistentList<RoomMemberIdentityStateChange>>.observeRoomMemberIdentityStateChange(room: JoinedRoom) {
56-
room.roomMemberIdentityStateChange()
57-
.onEach { roomMemberIdentityStateChanges ->
58-
value = roomMemberIdentityStateChanges.toPersistentList()
59-
}
60-
.launchIn(this)
61-
}
62-
6354
private fun RoomMember.toIdentityRoomMember() = IdentityRoomMember(
6455
userId = userId,
6556
displayNameOrDefault = displayNameOrDefault,

0 commit comments

Comments
 (0)