Update icon shown for world_readable rooms (#6111)

* Update icon shown for world_readable rooms

Followup to #6090: having discussed this in the team, we want to show a
different icon (with different text) for rooms where the history_visibility is
`world_readable` rather than `shared`.

* delint

* Update screenshots

---------

Co-authored-by: ElementBot <android@element.io>
This commit is contained in:
Richard van der Hoff
2026-02-02 17:32:46 +00:00
committed by GitHub
parent f579a015ac
commit 8ed69c03d2
8 changed files with 75 additions and 21 deletions

View File

@@ -210,10 +210,7 @@ class MessagesPresenter(
// * History sharing is enabled,
// * The room is encrypted, and:
// * The room's history_visibility allows future users to see content.
val showSharedHistoryIcon = isKeyShareOnInviteEnabled &&
roomInfo.isEncrypted == true &&
(roomInfo.historyVisibility == RoomHistoryVisibility.Shared ||
roomInfo.historyVisibility == RoomHistoryVisibility.WorldReadable)
val topBarSharedHistoryIcon = if (isKeyShareOnInviteEnabled) roomInfo.sharedHistoryIcon() else SharedHistoryIcon.NONE
LifecycleResumeEffect(dmRoomMember, roomInfo.isEncrypted) {
if (roomInfo.isEncrypted == true) {
@@ -297,12 +294,24 @@ class MessagesPresenter(
pinnedMessagesBannerState = pinnedMessagesBannerState,
dmUserVerificationState = dmUserVerificationState,
roomMemberModerationState = roomMemberModerationState,
showSharedHistoryIcon = showSharedHistoryIcon,
topBarSharedHistoryIcon = topBarSharedHistoryIcon,
successorRoom = roomInfo.successorRoom,
eventSink = ::handleEvent,
)
}
private fun RoomInfo.sharedHistoryIcon(): SharedHistoryIcon {
if (isEncrypted == true) {
if (historyVisibility == RoomHistoryVisibility.Shared) {
return SharedHistoryIcon.SHARED
} else if (historyVisibility == RoomHistoryVisibility.WorldReadable) {
return SharedHistoryIcon.WORLD_READABLE
}
}
return SharedHistoryIcon.NONE
}
private fun RoomInfo.avatarData(): AvatarData {
return AvatarData(
id = id.value,

View File

@@ -54,10 +54,22 @@ data class MessagesState(
val pinnedMessagesBannerState: PinnedMessagesBannerState,
val dmUserVerificationState: IdentityState?,
val roomMemberModerationState: RoomMemberModerationState,
/** Should the top bar include the "history" icon? */
val showSharedHistoryIcon: Boolean,
/** Type of "shared history" icon to show in the top bar. */
val topBarSharedHistoryIcon: SharedHistoryIcon,
val successorRoom: SuccessorRoom?,
val eventSink: (MessagesEvent) -> Unit
) {
val isTombstoned = successorRoom != null
}
/** Type of "shared history" icon to show in the top bar. */
enum class SharedHistoryIcon {
/** Show no icon at all. */
NONE,
/** history_visibility: shared. */
SHARED,
/** history_visibility: world_readable. */
WORLD_READABLE
}

View File

@@ -120,7 +120,7 @@ fun aMessagesState(
pinnedMessagesBannerState: PinnedMessagesBannerState = aLoadedPinnedMessagesBannerState(),
dmUserVerificationState: IdentityState? = null,
roomMemberModerationState: RoomMemberModerationState = aRoomMemberModerationState(),
showSharedHistoryIcon: Boolean = false,
topBarSharedHistoryIcon: SharedHistoryIcon = SharedHistoryIcon.NONE,
successorRoom: SuccessorRoom? = null,
eventSink: (MessagesEvent) -> Unit = {},
) = MessagesState(
@@ -148,7 +148,7 @@ fun aMessagesState(
pinnedMessagesBannerState = pinnedMessagesBannerState,
dmUserVerificationState = dmUserVerificationState,
roomMemberModerationState = roomMemberModerationState,
showSharedHistoryIcon = showSharedHistoryIcon,
topBarSharedHistoryIcon = topBarSharedHistoryIcon,
successorRoom = successorRoom,
eventSink = eventSink,
)

View File

@@ -225,7 +225,7 @@ fun MessagesView(
heroes = state.heroes,
roomCallState = state.roomCallState,
dmUserIdentityState = state.dmUserVerificationState,
showSharedHistoryIcon = state.showSharedHistoryIcon,
sharedHistoryIcon = state.topBarSharedHistoryIcon,
onBackClick = { hidingKeyboard { onBackClick() } },
onRoomDetailsClick = { hidingKeyboard { onRoomDetailsClick() } },
onJoinCallClick = onJoinCallClick,

View File

@@ -30,6 +30,7 @@ import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import io.element.android.compound.theme.ElementTheme
import io.element.android.compound.tokens.generated.CompoundIcons
import io.element.android.features.messages.impl.SharedHistoryIcon
import io.element.android.features.messages.impl.timeline.components.CallMenuItem
import io.element.android.features.roomcall.api.RoomCallState
import io.element.android.features.roomcall.api.aStandByCallState
@@ -63,7 +64,7 @@ internal fun MessagesViewTopBar(
heroes: ImmutableList<AvatarData>,
roomCallState: RoomCallState,
dmUserIdentityState: IdentityState?,
showSharedHistoryIcon: Boolean,
sharedHistoryIcon: SharedHistoryIcon,
onRoomDetailsClick: () -> Unit,
onJoinCallClick: () -> Unit,
onBackClick: () -> Unit,
@@ -110,12 +111,18 @@ internal fun MessagesViewTopBar(
else -> Unit
}
if (showSharedHistoryIcon) {
Icon(
when (sharedHistoryIcon) {
SharedHistoryIcon.NONE -> Unit
SharedHistoryIcon.SHARED -> Icon(
imageVector = CompoundIcons.History(),
tint = ElementTheme.colors.iconInfoPrimary,
contentDescription = stringResource(CommonStrings.common_shared_history),
)
SharedHistoryIcon.WORLD_READABLE -> Icon(
imageVector = CompoundIcons.UserProfileSolid(),
tint = ElementTheme.colors.iconInfoPrimary,
contentDescription = stringResource(CommonStrings.common_world_readable_history),
)
}
}
},
@@ -178,7 +185,7 @@ internal fun MessagesViewTopBarPreview() = ElementPreview {
heroes: ImmutableList<AvatarData> = persistentListOf(),
roomCallState: RoomCallState = RoomCallState.Unavailable,
dmUserIdentityState: IdentityState? = null,
showSharedHistoryIcon: Boolean = false,
sharedHistoryIcon: SharedHistoryIcon = SharedHistoryIcon.NONE,
) = MessagesViewTopBar(
roomName = roomName,
roomAvatar = roomAvatar,
@@ -186,7 +193,7 @@ internal fun MessagesViewTopBarPreview() = ElementPreview {
heroes = heroes,
roomCallState = roomCallState,
dmUserIdentityState = dmUserIdentityState,
showSharedHistoryIcon = showSharedHistoryIcon,
sharedHistoryIcon = sharedHistoryIcon,
onRoomDetailsClick = {},
onJoinCallClick = {},
onBackClick = {},
@@ -223,7 +230,12 @@ internal fun MessagesViewTopBarPreview() = ElementPreview {
AMessagesViewTopBar(
roomName = "A DM with shared history",
dmUserIdentityState = IdentityState.Verified,
showSharedHistoryIcon = true,
sharedHistoryIcon = SharedHistoryIcon.SHARED,
)
HorizontalDivider()
AMessagesViewTopBar(
roomName = "A room with world_readable history",
sharedHistoryIcon = SharedHistoryIcon.WORLD_READABLE,
)
}
}

View File

@@ -1233,7 +1233,28 @@ class MessagesPresenterTest {
awaitItem()
runCurrent()
val state = awaitItem()
assertThat(state.showSharedHistoryIcon).isTrue()
assertThat(state.topBarSharedHistoryIcon).isEqualTo(SharedHistoryIcon.SHARED)
}
}
@Test
fun `present - shows a "world_readable" icon if the room is encrypted and history is world_readable`() = runTest {
val presenter = createMessagesPresenter(
joinedRoom = FakeJoinedRoom(
baseRoom = FakeBaseRoom(
roomPermissions = roomPermissions(),
initialRoomInfo = aRoomInfo(isEncrypted = true, historyVisibility = RoomHistoryVisibility.WorldReadable),
),
),
featureFlagService = FakeFeatureFlagService(
initialState = mapOf(FeatureFlags.EnableKeyShareOnInvite.key to true)
)
)
presenter.testWithLifecycleOwner {
awaitItem()
runCurrent()
val state = awaitItem()
assertThat(state.topBarSharedHistoryIcon).isEqualTo(SharedHistoryIcon.WORLD_READABLE)
}
}