Skip to content

Commit 41749ed

Browse files
committed
Create data classes TypingRoomMember and IdentityRoomMember to avoid the risk of useless recomposition.
Also remove TypingNotificationStateForMessagesProvider which was not used anymore.
1 parent 8aa34d8 commit 41749ed

File tree

13 files changed

+144
-125
lines changed

13 files changed

+144
-125
lines changed

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
package io.element.android.features.messages.impl.crypto.identity
99

1010
import io.element.android.libraries.matrix.api.encryption.identity.IdentityState
11-
import io.element.android.libraries.matrix.api.room.RoomMember
1211
import kotlinx.collections.immutable.ImmutableList
1312

1413
data class IdentityChangeState(
@@ -17,6 +16,6 @@ data class IdentityChangeState(
1716
)
1817

1918
data class RoomMemberIdentityStateChange(
20-
val roomMember: RoomMember,
19+
val identityRoomMember: IdentityRoomMember,
2120
val identityState: IdentityState,
2221
)

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

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,14 @@ import androidx.compose.runtime.getValue
1313
import androidx.compose.runtime.produceState
1414
import androidx.compose.runtime.rememberCoroutineScope
1515
import io.element.android.libraries.architecture.Presenter
16+
import io.element.android.libraries.designsystem.components.avatar.AvatarData
17+
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
1618
import io.element.android.libraries.matrix.api.core.UserId
1719
import io.element.android.libraries.matrix.api.encryption.EncryptionService
1820
import io.element.android.libraries.matrix.api.room.MatrixRoom
1921
import io.element.android.libraries.matrix.api.room.RoomMember
20-
import io.element.android.libraries.matrix.api.room.RoomMembershipState
2122
import io.element.android.libraries.matrix.api.room.roomMembers
23+
import io.element.android.libraries.matrix.ui.model.getAvatarData
2224
import kotlinx.collections.immutable.PersistentList
2325
import kotlinx.collections.immutable.persistentListOf
2426
import kotlinx.collections.immutable.toPersistentList
@@ -59,9 +61,10 @@ class IdentityChangeStatePresenter @Inject constructor(
5961
identityStateChanges.map { identityStateChange ->
6062
val member = membersState.roomMembers()
6163
?.firstOrNull { roomMember -> roomMember.userId == identityStateChange.userId }
64+
?.toIdentityRoomMember()
6265
?: createDefaultRoomMemberForIdentityChange(identityStateChange.userId)
6366
RoomMemberIdentityStateChange(
64-
roomMember = member,
67+
identityRoomMember = member,
6568
identityState = identityStateChange.identityState,
6669
)
6770
}
@@ -81,21 +84,19 @@ class IdentityChangeStatePresenter @Inject constructor(
8184
}
8285
}
8386

84-
/**
85-
* Create a default [RoomMember] for identity change events.
86-
* In this case, only the userId will be used for rendering, other fields are not used, but keep them
87-
* as close as possible to the actual data.
88-
*/
89-
private fun createDefaultRoomMemberForIdentityChange(userId: UserId): RoomMember {
90-
return RoomMember(
91-
userId = userId,
92-
displayName = null,
93-
avatarUrl = null,
94-
membership = RoomMembershipState.JOIN,
95-
isNameAmbiguous = false,
96-
powerLevel = 0,
97-
normalizedPowerLevel = 0,
98-
isIgnored = false,
99-
role = RoomMember.Role.USER,
100-
)
101-
}
87+
private fun RoomMember.toIdentityRoomMember() = IdentityRoomMember(
88+
userId = userId,
89+
disambiguatedDisplayName = disambiguatedDisplayName,
90+
avatarData = getAvatarData(AvatarSize.ComposerAlert),
91+
)
92+
93+
private fun createDefaultRoomMemberForIdentityChange(userId: UserId) = IdentityRoomMember(
94+
userId = userId,
95+
disambiguatedDisplayName = userId.value,
96+
avatarData = AvatarData(
97+
id = userId.value,
98+
name = null,
99+
url = null,
100+
size = AvatarSize.ComposerAlert,
101+
),
102+
)

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

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88
package io.element.android.features.messages.impl.crypto.identity
99

1010
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
11-
import io.element.android.features.messages.impl.typing.aTypingRoomMember
11+
import io.element.android.libraries.designsystem.components.avatar.AvatarData
12+
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
13+
import io.element.android.libraries.matrix.api.core.UserId
1214
import io.element.android.libraries.matrix.api.encryption.identity.IdentityState
1315
import kotlinx.collections.immutable.toImmutableList
1416

@@ -19,7 +21,7 @@ class IdentityChangeStateProvider : PreviewParameterProvider<IdentityChangeState
1921
anIdentityChangeState(
2022
roomMemberIdentityStateChanges = listOf(
2123
RoomMemberIdentityStateChange(
22-
roomMember = aTypingRoomMember(displayName = "Alice"),
24+
identityRoomMember = anIdentityRoomMember(disambiguatedDisplayName = "Alice"),
2325
identityState = IdentityState.PinViolation,
2426
),
2527
),
@@ -33,3 +35,18 @@ internal fun anIdentityChangeState(
3335
roomMemberIdentityStateChanges = roomMemberIdentityStateChanges.toImmutableList(),
3436
eventSink = {},
3537
)
38+
39+
internal fun anIdentityRoomMember(
40+
userId: UserId = UserId("@alice:example.com"),
41+
disambiguatedDisplayName: String = userId.value,
42+
avatarData: AvatarData = AvatarData(
43+
id = userId.value,
44+
name = null,
45+
url = null,
46+
size = AvatarSize.ComposerAlert,
47+
),
48+
) = IdentityRoomMember(
49+
userId = userId,
50+
disambiguatedDisplayName = disambiguatedDisplayName,
51+
avatarData = avatarData,
52+
)

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,12 @@ fun IdentityChangeStateView(
3939
if (pinViolationIdentityChange != null) {
4040
ComposerAlertMolecule(
4141
modifier = modifier,
42-
avatar = pinViolationIdentityChange.roomMember.getAvatarData(AvatarSize.ComposerAlert),
42+
avatar = pinViolationIdentityChange.identityRoomMember.avatarData,
4343
content = buildAnnotatedString {
4444
val learnMoreStr = stringResource(CommonStrings.action_learn_more)
4545
val fullText = stringResource(
4646
id = CommonStrings.crypto_identity_change_pin_violation,
47-
pinViolationIdentityChange.roomMember.disambiguatedDisplayName,
47+
pinViolationIdentityChange.identityRoomMember.disambiguatedDisplayName,
4848
learnMoreStr,
4949
)
5050
val learnMoreStartIndex = fullText.indexOf(learnMoreStr)
@@ -68,7 +68,7 @@ fun IdentityChangeStateView(
6868
end = learnMoreStartIndex + learnMoreStr.length,
6969
)
7070
},
71-
onSubmitClick = { state.eventSink(IdentityChangeEvent.Submit(pinViolationIdentityChange.roomMember.userId)) },
71+
onSubmitClick = { state.eventSink(IdentityChangeEvent.Submit(pinViolationIdentityChange.identityRoomMember.userId)) },
7272
isCritical = pinViolationIdentityChange.identityState == IdentityState.VerificationViolation,
7373
)
7474
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/*
2+
* Copyright 2024 New Vector Ltd.
3+
*
4+
* SPDX-License-Identifier: AGPL-3.0-only
5+
* Please see LICENSE in the repository root for full details.
6+
*/
7+
8+
package io.element.android.features.messages.impl.crypto.identity
9+
10+
import io.element.android.libraries.designsystem.components.avatar.AvatarData
11+
import io.element.android.libraries.matrix.api.core.UserId
12+
13+
data class IdentityRoomMember(
14+
val userId: UserId,
15+
val disambiguatedDisplayName: String,
16+
val avatarData: AvatarData,
17+
)

features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/typing/TypingNotificationPresenter.kt

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import io.element.android.libraries.architecture.Presenter
2020
import io.element.android.libraries.matrix.api.core.UserId
2121
import io.element.android.libraries.matrix.api.room.MatrixRoom
2222
import io.element.android.libraries.matrix.api.room.RoomMember
23-
import io.element.android.libraries.matrix.api.room.RoomMembershipState
2423
import io.element.android.libraries.matrix.api.room.roomMembers
2524
import io.element.android.libraries.preferences.api.store.SessionPreferencesStore
2625
import kotlinx.collections.immutable.ImmutableList
@@ -60,12 +59,13 @@ class TypingNotificationPresenter @Inject constructor(
6059
)
6160
}
6261

63-
private fun ProduceStateScope<ImmutableList<RoomMember>>.observeRoomTypingMembers() {
62+
private fun ProduceStateScope<ImmutableList<TypingRoomMember>>.observeRoomTypingMembers() {
6463
combine(room.roomTypingMembersFlow, room.membersStateFlow) { typingMembers, membersState ->
6564
typingMembers
6665
.map { userId ->
6766
membersState.roomMembers()
6867
?.firstOrNull { roomMember -> roomMember.userId == userId }
68+
?.toTypingRoomMember()
6969
?: createDefaultRoomMemberForTyping(userId)
7070
}
7171
}
@@ -77,21 +77,14 @@ class TypingNotificationPresenter @Inject constructor(
7777
}
7878
}
7979

80-
/**
81-
* Create a default [RoomMember] for typing events.
82-
* In this case, only the userId will be used for rendering, other fields are not used, but keep them
83-
* as close as possible to the actual data.
84-
*/
85-
private fun createDefaultRoomMemberForTyping(userId: UserId): RoomMember {
86-
return RoomMember(
87-
userId = userId,
88-
displayName = null,
89-
avatarUrl = null,
90-
membership = RoomMembershipState.JOIN,
91-
isNameAmbiguous = false,
92-
powerLevel = 0,
93-
normalizedPowerLevel = 0,
94-
isIgnored = false,
95-
role = RoomMember.Role.USER,
80+
private fun RoomMember.toTypingRoomMember(): TypingRoomMember {
81+
return TypingRoomMember(
82+
disambiguatedDisplayName = disambiguatedDisplayName,
83+
)
84+
}
85+
86+
private fun createDefaultRoomMemberForTyping(userId: UserId): TypingRoomMember {
87+
return TypingRoomMember(
88+
disambiguatedDisplayName = userId.value,
9689
)
9790
}

features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/typing/TypingNotificationState.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77

88
package io.element.android.features.messages.impl.typing
99

10-
import io.element.android.libraries.matrix.api.room.RoomMember
1110
import kotlinx.collections.immutable.ImmutableList
1211

1312
/**
@@ -17,7 +16,7 @@ data class TypingNotificationState(
1716
/** Whether to render the typing notifications based on the user's preferences. */
1817
val renderTypingNotifications: Boolean,
1918
/** The room members currently typing. */
20-
val typingMembers: ImmutableList<RoomMember>,
19+
val typingMembers: ImmutableList<TypingRoomMember>,
2120
/** Whether to reserve space for the typing notifications at the bottom of the timeline. */
2221
val reserveSpace: Boolean,
2322
)

features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/typing/TypingNotificationStateForMessagesProvider.kt

Lines changed: 0 additions & 27 deletions
This file was deleted.

features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/typing/TypingNotificationStateProvider.kt

Lines changed: 18 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,6 @@
88
package io.element.android.features.messages.impl.typing
99

1010
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
11-
import io.element.android.libraries.matrix.api.core.UserId
12-
import io.element.android.libraries.matrix.api.room.RoomMember
13-
import io.element.android.libraries.matrix.api.room.RoomMembershipState
1411
import kotlinx.collections.immutable.toImmutableList
1512

1613
class TypingNotificationStateProvider : PreviewParameterProvider<TypingNotificationState> {
@@ -24,39 +21,39 @@ class TypingNotificationStateProvider : PreviewParameterProvider<TypingNotificat
2421
),
2522
aTypingNotificationState(
2623
typingMembers = listOf(
27-
aTypingRoomMember(displayName = "Alice"),
24+
aTypingRoomMember(disambiguatedDisplayName = "Alice"),
2825
),
2926
),
3027
aTypingNotificationState(
3128
typingMembers = listOf(
32-
aTypingRoomMember(displayName = "Alice", isNameAmbiguous = true),
29+
aTypingRoomMember(disambiguatedDisplayName = "Alice (@alice:example.com)"),
3330
),
3431
),
3532
aTypingNotificationState(
3633
typingMembers = listOf(
37-
aTypingRoomMember(displayName = "Alice"),
38-
aTypingRoomMember(displayName = "Bob"),
34+
aTypingRoomMember(disambiguatedDisplayName = "Alice"),
35+
aTypingRoomMember(disambiguatedDisplayName = "Bob"),
3936
),
4037
),
4138
aTypingNotificationState(
4239
typingMembers = listOf(
43-
aTypingRoomMember(displayName = "Alice"),
44-
aTypingRoomMember(displayName = "Bob"),
45-
aTypingRoomMember(displayName = "Charlie"),
40+
aTypingRoomMember(disambiguatedDisplayName = "Alice"),
41+
aTypingRoomMember(disambiguatedDisplayName = "Bob"),
42+
aTypingRoomMember(disambiguatedDisplayName = "Charlie"),
4643
),
4744
),
4845
aTypingNotificationState(
4946
typingMembers = listOf(
50-
aTypingRoomMember(displayName = "Alice"),
51-
aTypingRoomMember(displayName = "Bob"),
52-
aTypingRoomMember(displayName = "Charlie"),
53-
aTypingRoomMember(displayName = "Dan"),
54-
aTypingRoomMember(displayName = "Eve"),
47+
aTypingRoomMember(disambiguatedDisplayName = "Alice"),
48+
aTypingRoomMember(disambiguatedDisplayName = "Bob"),
49+
aTypingRoomMember(disambiguatedDisplayName = "Charlie"),
50+
aTypingRoomMember(disambiguatedDisplayName = "Dan"),
51+
aTypingRoomMember(disambiguatedDisplayName = "Eve"),
5552
),
5653
),
5754
aTypingNotificationState(
5855
typingMembers = listOf(
59-
aTypingRoomMember(displayName = "Alice with a very long display name which means that it will be truncated"),
56+
aTypingRoomMember(disambiguatedDisplayName = "Alice with a very long display name which means that it will be truncated"),
6057
),
6158
),
6259
aTypingNotificationState(
@@ -67,7 +64,7 @@ class TypingNotificationStateProvider : PreviewParameterProvider<TypingNotificat
6764
}
6865

6966
internal fun aTypingNotificationState(
70-
typingMembers: List<RoomMember> = emptyList(),
67+
typingMembers: List<TypingRoomMember> = emptyList(),
7168
reserveSpace: Boolean = false,
7269
) = TypingNotificationState(
7370
renderTypingNotifications = true,
@@ -76,19 +73,7 @@ internal fun aTypingNotificationState(
7673
)
7774

7875
internal fun aTypingRoomMember(
79-
userId: UserId = UserId("@alice:example.com"),
80-
displayName: String? = null,
81-
isNameAmbiguous: Boolean = false,
82-
): RoomMember {
83-
return RoomMember(
84-
userId = userId,
85-
displayName = displayName,
86-
avatarUrl = null,
87-
membership = RoomMembershipState.JOIN,
88-
isNameAmbiguous = isNameAmbiguous,
89-
powerLevel = 0,
90-
normalizedPowerLevel = 0,
91-
isIgnored = false,
92-
role = RoomMember.Role.USER,
93-
)
94-
}
76+
disambiguatedDisplayName: String = "@alice:example.com",
77+
) = TypingRoomMember(
78+
disambiguatedDisplayName = disambiguatedDisplayName,
79+
)

features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/typing/TypingNotificationView.kt

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ import io.element.android.features.messages.impl.R
4141
import io.element.android.libraries.designsystem.preview.ElementPreview
4242
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
4343
import io.element.android.libraries.designsystem.theme.components.Text
44-
import io.element.android.libraries.matrix.api.room.RoomMember
4544
import kotlinx.collections.immutable.ImmutableList
4645

4746
@Suppress("MultipleEmitters") // False positive
@@ -53,7 +52,8 @@ fun TypingNotificationView(
5352
val displayNotifications = state.typingMembers.isNotEmpty() && state.renderTypingNotifications
5453

5554
@Suppress("ModifierNaming")
56-
@Composable fun TypingText(text: AnnotatedString, textModifier: Modifier = Modifier) {
55+
@Composable
56+
fun TypingText(text: AnnotatedString, textModifier: Modifier = Modifier) {
5757
Text(
5858
modifier = textModifier,
5959
text = text,
@@ -66,7 +66,9 @@ fun TypingNotificationView(
6666

6767
// Display the typing notification space when either a typing notification needs to be displayed or a previous one already was
6868
AnimatedVisibility(
69-
modifier = modifier.fillMaxWidth().padding(vertical = 2.dp),
69+
modifier = modifier
70+
.fillMaxWidth()
71+
.padding(vertical = 2.dp),
7072
visible = displayNotifications || state.reserveSpace,
7173
enter = fadeIn() + expandVertically(),
7274
exit = fadeOut() + shrinkVertically(),
@@ -95,7 +97,7 @@ fun TypingNotificationView(
9597
}
9698

9799
@Composable
98-
private fun computeTypingNotificationText(typingMembers: ImmutableList<RoomMember>): AnnotatedString {
100+
private fun computeTypingNotificationText(typingMembers: ImmutableList<TypingRoomMember>): AnnotatedString {
99101
// Remember the last value to avoid empty typing messages while animating
100102
var result by remember { mutableStateOf(AnnotatedString("")) }
101103
if (typingMembers.isNotEmpty()) {

0 commit comments

Comments
 (0)