Skip to content

Commit 1e268b0

Browse files
authored
Add history sharing badges to room details (#6132)
* feat: Add history sharing badges to room details view * tests: Add snapshots for history sharing room details badges * fix: Disable soft-wrapping in badges, use FlowRow * tests: Add unit test for `RoomDetailsState` and history sharing badges. * tests: Add `MatrixBadgeAtomNeutralWrappingPreview` to exceptions * chore: Re-order `MatrixBadgeAtom` previews * fix: Add `Immutable` annotation to `RoomHistoryVisibility`. * fix: Correct translation for shared badge
1 parent 26de441 commit 1e268b0

File tree

20 files changed

+156
-3
lines changed

20 files changed

+156
-3
lines changed

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,8 @@ class RoomDetailsPresenter(
168168

169169
val canReportRoom by produceState(false) { value = client.canReportRoom() }
170170

171+
val enableKeyShareOnInvite by featureFlagService.isFeatureEnabledFlow(FeatureFlags.EnableKeyShareOnInvite).collectAsState(initial = false)
172+
171173
return RoomDetailsState(
172174
roomId = room.roomId,
173175
roomName = roomName,
@@ -197,6 +199,8 @@ class RoomDetailsPresenter(
197199
isTombstoned = roomInfo.successorRoom != null,
198200
showDebugInfo = isDeveloperModeEnabled,
199201
roomVersion = roomInfo.roomVersion,
202+
enableKeyShareOnInvite = enableKeyShareOnInvite,
203+
roomHistoryVisibility = roomInfo.historyVisibility,
200204
eventSink = ::handleEvent,
201205
)
202206
}

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import io.element.android.libraries.matrix.api.core.RoomAlias
1717
import io.element.android.libraries.matrix.api.core.RoomId
1818
import io.element.android.libraries.matrix.api.room.RoomMember
1919
import io.element.android.libraries.matrix.api.room.RoomNotificationSettings
20+
import io.element.android.libraries.matrix.api.room.history.RoomHistoryVisibility
2021
import io.element.android.libraries.matrix.api.user.MatrixUser
2122
import kotlinx.collections.immutable.ImmutableList
2223
import kotlinx.collections.immutable.toImmutableList
@@ -50,6 +51,8 @@ data class RoomDetailsState(
5051
val isTombstoned: Boolean,
5152
val showDebugInfo: Boolean,
5253
val roomVersion: String?,
54+
val enableKeyShareOnInvite: Boolean,
55+
val roomHistoryVisibility: RoomHistoryVisibility,
5356
val eventSink: (RoomDetailsEvent) -> Unit
5457
) {
5558
val roomBadges = buildList {
@@ -61,6 +64,14 @@ data class RoomDetailsState(
6164
if (isPublic) {
6265
add(RoomBadge.PUBLIC)
6366
}
67+
if (enableKeyShareOnInvite && isEncrypted) {
68+
when (roomHistoryVisibility) {
69+
RoomHistoryVisibility.Invited, RoomHistoryVisibility.Joined -> add(RoomBadge.SHARED_HISTORY_HIDDEN)
70+
RoomHistoryVisibility.Shared -> add(RoomBadge.SHARED_HISTORY_SHARED)
71+
RoomHistoryVisibility.WorldReadable -> add(RoomBadge.SHARED_HISTORY_WORLD_READABLE)
72+
else -> {}
73+
}
74+
}
6475
}.toImmutableList()
6576
}
6677

@@ -84,4 +95,7 @@ enum class RoomBadge {
8495
ENCRYPTED,
8596
NOT_ENCRYPTED,
8697
PUBLIC,
98+
SHARED_HISTORY_HIDDEN,
99+
SHARED_HISTORY_SHARED,
100+
SHARED_HISTORY_WORLD_READABLE
87101
}

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import io.element.android.libraries.matrix.api.room.RoomMember
2626
import io.element.android.libraries.matrix.api.room.RoomMembershipState
2727
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
2828
import io.element.android.libraries.matrix.api.room.RoomNotificationSettings
29+
import io.element.android.libraries.matrix.api.room.history.RoomHistoryVisibility
2930
import io.element.android.libraries.matrix.api.user.MatrixUser
3031
import io.element.android.libraries.matrix.ui.components.aMatrixUserList
3132
import kotlinx.collections.immutable.toImmutableList
@@ -57,6 +58,9 @@ open class RoomDetailsStateProvider : PreviewParameterProvider<RoomDetailsState>
5758
aRoomDetailsState(isTombstoned = true),
5859
aDmRoomDetailsState(dmRoomMemberVerificationState = UserProfileVerificationState.VERIFIED),
5960
aDmRoomDetailsState(dmRoomMemberVerificationState = UserProfileVerificationState.VERIFICATION_VIOLATION),
61+
aSharedHistoryRoomDetailsState(roomHistoryVisibility = RoomHistoryVisibility.Joined),
62+
aSharedHistoryRoomDetailsState(roomHistoryVisibility = RoomHistoryVisibility.Shared),
63+
aSharedHistoryRoomDetailsState(roomHistoryVisibility = RoomHistoryVisibility.WorldReadable),
6064
// Add other state here
6165
)
6266
}
@@ -117,6 +121,8 @@ fun aRoomDetailsState(
117121
canReportRoom: Boolean = true,
118122
isTombstoned: Boolean = false,
119123
showDebugInfo: Boolean = false,
124+
enableKeyShareOnInvite: Boolean = false,
125+
roomHistoryVisibility: RoomHistoryVisibility = RoomHistoryVisibility.Shared,
120126
eventSink: (RoomDetailsEvent) -> Unit = {},
121127
) = RoomDetailsState(
122128
roomId = roomId,
@@ -147,6 +153,8 @@ fun aRoomDetailsState(
147153
isTombstoned = isTombstoned,
148154
showDebugInfo = showDebugInfo,
149155
roomVersion = "12",
156+
enableKeyShareOnInvite = enableKeyShareOnInvite,
157+
roomHistoryVisibility = roomHistoryVisibility,
150158
eventSink = eventSink,
151159
)
152160

@@ -182,3 +190,11 @@ fun aDmRoomDetailsState(
182190
verificationState = dmRoomMemberVerificationState,
183191
)
184192
)
193+
194+
fun aSharedHistoryRoomDetailsState(
195+
roomHistoryVisibility: RoomHistoryVisibility
196+
) = aRoomDetailsState(
197+
isEncrypted = true,
198+
enableKeyShareOnInvite = true,
199+
roomHistoryVisibility = roomHistoryVisibility,
200+
)

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

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,27 @@ private fun RoomBadge.toMatrixBadgeData(): MatrixBadgeAtom.MatrixBadgeData {
518518
type = MatrixBadgeAtom.Type.Info,
519519
)
520520
}
521+
RoomBadge.SHARED_HISTORY_HIDDEN -> {
522+
MatrixBadgeAtom.MatrixBadgeData(
523+
text = stringResource(R.string.crypto_history_sharing_room_info_hidden_badge_content),
524+
icon = CompoundIcons.VisibilityOff(),
525+
type = MatrixBadgeAtom.Type.Info
526+
)
527+
}
528+
RoomBadge.SHARED_HISTORY_SHARED -> {
529+
MatrixBadgeAtom.MatrixBadgeData(
530+
text = stringResource(R.string.crypto_history_sharing_room_info_shared_badge_content),
531+
icon = CompoundIcons.History(),
532+
type = MatrixBadgeAtom.Type.Info
533+
)
534+
}
535+
RoomBadge.SHARED_HISTORY_WORLD_READABLE -> {
536+
MatrixBadgeAtom.MatrixBadgeData(
537+
text = stringResource(R.string.crypto_history_sharing_room_info_world_readable_badge_content),
538+
icon = CompoundIcons.UserProfileSolid(),
539+
type = MatrixBadgeAtom.Type.Info
540+
)
541+
}
521542
}
522543
}
523544

features/roomdetails/impl/src/main/res/values/localazy.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
3+
<string name="crypto_history_sharing_room_info_hidden_badge_content">"New members don\'t see history"</string>
4+
<string name="crypto_history_sharing_room_info_shared_badge_content">"New members see history"</string>
5+
<string name="crypto_history_sharing_room_info_world_readable_badge_content">"Anyone can see history"</string>
36
<string name="screen_edit_room_address_room_address_section_footer">"You’ll need an address in order to make it visible in the public directory."</string>
47
<string name="screen_edit_room_address_title">"Edit address"</string>
58
<string name="screen_notification_settings_edit_failed_updating_default_mode">"An error occurred while updating the notification setting."</string>

features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsStateTest.kt

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
package io.element.android.features.roomdetails.impl
1010

1111
import com.google.common.truth.Truth.assertThat
12+
import io.element.android.libraries.matrix.api.room.history.RoomHistoryVisibility
1213
import kotlinx.collections.immutable.persistentListOf
1314
import org.junit.Test
1415

@@ -56,4 +57,52 @@ class RoomDetailsStateTest {
5657
persistentListOf(RoomBadge.ENCRYPTED)
5758
)
5859
}
60+
61+
@Test
62+
fun `room public not encrypted should not have history sharing badges`() {
63+
val sut = aRoomDetailsState(
64+
isEncrypted = false,
65+
enableKeyShareOnInvite = true,
66+
roomHistoryVisibility = RoomHistoryVisibility.Shared
67+
)
68+
assertThat(sut.roomBadges).isEqualTo(
69+
persistentListOf(RoomBadge.NOT_ENCRYPTED, RoomBadge.PUBLIC)
70+
)
71+
}
72+
73+
@Test
74+
fun `room public encrypted should have history sharing hidden badge`() {
75+
val sut = aRoomDetailsState(
76+
isEncrypted = true,
77+
enableKeyShareOnInvite = true,
78+
roomHistoryVisibility = RoomHistoryVisibility.Joined
79+
)
80+
assertThat(sut.roomBadges).isEqualTo(
81+
persistentListOf(RoomBadge.ENCRYPTED, RoomBadge.PUBLIC, RoomBadge.SHARED_HISTORY_HIDDEN)
82+
)
83+
}
84+
85+
@Test
86+
fun `room public encrypted should have history sharing shared badge`() {
87+
val sut = aRoomDetailsState(
88+
isEncrypted = true,
89+
enableKeyShareOnInvite = true,
90+
roomHistoryVisibility = RoomHistoryVisibility.Shared
91+
)
92+
assertThat(sut.roomBadges).isEqualTo(
93+
persistentListOf(RoomBadge.ENCRYPTED, RoomBadge.PUBLIC, RoomBadge.SHARED_HISTORY_SHARED)
94+
)
95+
}
96+
97+
@Test
98+
fun `room public encrypted should have history sharing world_readable badge`() {
99+
val sut = aRoomDetailsState(
100+
isEncrypted = true,
101+
enableKeyShareOnInvite = true,
102+
roomHistoryVisibility = RoomHistoryVisibility.WorldReadable
103+
)
104+
assertThat(sut.roomBadges).isEqualTo(
105+
persistentListOf(RoomBadge.ENCRYPTED, RoomBadge.PUBLIC, RoomBadge.SHARED_HISTORY_WORLD_READABLE)
106+
)
107+
}
59108
}

libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/atoms/MatrixBadgeAtom.kt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,18 @@ internal fun MatrixBadgeAtomNegativePreview() = ElementPreview {
9898
)
9999
}
100100

101+
@PreviewsDayNight
102+
@Composable
103+
internal fun MatrixBadgeAtomNeutralWrappingPreview() = ElementPreview {
104+
MatrixBadgeAtom.View(
105+
MatrixBadgeAtom.MatrixBadgeData(
106+
text = "How much wood could a wood chuck chuck if a wood chuck could chuck wood",
107+
icon = CompoundIcons.LockOff(),
108+
type = MatrixBadgeAtom.Type.Info,
109+
)
110+
)
111+
}
112+
101113
@PreviewsDayNight
102114
@Composable
103115
internal fun MatrixBadgeAtomInfoPreview() = ElementPreview {

libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/molecules/MatrixBadgeRowMolecule.kt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@
99
package io.element.android.libraries.designsystem.atomic.molecules
1010

1111
import androidx.compose.foundation.layout.Arrangement
12-
import androidx.compose.foundation.layout.Row
12+
import androidx.compose.foundation.layout.FlowRow
1313
import androidx.compose.foundation.layout.padding
1414
import androidx.compose.runtime.Composable
15+
import androidx.compose.ui.Alignment
1516
import androidx.compose.ui.Modifier
1617
import androidx.compose.ui.unit.dp
1718
import io.element.android.libraries.designsystem.atomic.atoms.MatrixBadgeAtom
@@ -22,10 +23,11 @@ fun MatrixBadgeRowMolecule(
2223
data: ImmutableList<MatrixBadgeAtom.MatrixBadgeData>,
2324
modifier: Modifier = Modifier,
2425
) {
25-
Row(
26+
FlowRow(
2627
modifier = modifier
2728
.padding(start = 16.dp, end = 16.dp, top = 8.dp),
28-
horizontalArrangement = Arrangement.spacedBy(8.dp),
29+
horizontalArrangement = Arrangement.spacedBy(8.dp, Alignment.CenterHorizontally),
30+
verticalArrangement = Arrangement.spacedBy(8.dp)
2931
) {
3032
for (badge in data) {
3133
MatrixBadgeAtom.View(badge)

libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/Badge.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import androidx.compose.ui.Modifier
2121
import androidx.compose.ui.graphics.Color
2222
import androidx.compose.ui.graphics.Shape
2323
import androidx.compose.ui.graphics.vector.ImageVector
24+
import androidx.compose.ui.text.style.TextOverflow
2425
import androidx.compose.ui.unit.dp
2526
import io.element.android.compound.theme.ElementTheme
2627
import io.element.android.compound.tokens.generated.CompoundIcons
@@ -63,6 +64,8 @@ fun Badge(
6364
text = text,
6465
style = ElementTheme.typography.fontBodySmRegular,
6566
color = textColor,
67+
overflow = TextOverflow.Ellipsis,
68+
softWrap = false,
6669
)
6770
}
6871
}

libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/history/RoomHistoryVisibility.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88

99
package io.element.android.libraries.matrix.api.room.history
1010

11+
import androidx.compose.runtime.Immutable
12+
13+
@Immutable
1114
sealed interface RoomHistoryVisibility {
1215
/**
1316
* Previous events are accessible to newly joined members from the point

0 commit comments

Comments
 (0)