diff --git a/src/components/views/rooms/RoomHeader/RoomHeader.tsx b/src/components/views/rooms/RoomHeader/RoomHeader.tsx
index 2434d5900e7..b6c00868000 100644
--- a/src/components/views/rooms/RoomHeader/RoomHeader.tsx
+++ b/src/components/views/rooms/RoomHeader/RoomHeader.tsx
@@ -22,7 +22,7 @@ import { HistoryVisibility, JoinRule, type Room } from "matrix-js-sdk/src/matrix
import { type ViewRoomOpts } from "@matrix-org/react-sdk-module-api/lib/lifecycles/RoomViewLifecycle";
import { Flex, Box } from "@element-hq/web-shared-components";
import { CallType } from "matrix-js-sdk/src/webrtc/call";
-import { HistoryIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
+import { HistoryIcon, UserProfileSolidIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
import { useRoomName } from "../../../../hooks/useRoomName.ts";
import { RightPanelPhases } from "../../../../stores/right-panel/RightPanelStorePhases.ts";
@@ -391,6 +391,40 @@ function RoomHeaderButtons({
);
}
+/** Create an icon to warn the user about shared history visibility, in encrypted rooms.
+ *
+ * Note that we use the same icon as in the room summary card and elsewhere, to aid user recognition.
+ */
+function historyVisibilityIcon(historyVisibility: HistoryVisibility): JSX.Element | null {
+ if (historyVisibility === HistoryVisibility.Shared) {
+ return (
+
+
+
+ );
+ } else if (historyVisibility === HistoryVisibility.WorldReadable) {
+ return (
+
+
+
+ );
+ } else {
+ return null;
+ }
+}
+
export default function RoomHeader({
room,
additionalButtons,
@@ -490,20 +524,7 @@ export default function RoomHeader({
)}
- {isRoomEncrypted &&
- historySharingEnabled &&
- (historyVisibility === HistoryVisibility.Shared ||
- historyVisibility === HistoryVisibility.WorldReadable) && (
-
-
-
- )}
+ {isRoomEncrypted && historySharingEnabled && historyVisibilityIcon(historyVisibility)}
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index 03989ab9eaa..c9e5e1e0281 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -2032,7 +2032,8 @@
"other": "%(count)s people asking to join"
},
"room_is_public": "This room is public",
- "shared_history_tooltip": "New members see history"
+ "shared_history_tooltip": "New members see history",
+ "world_readable_history_tooltip": "Anyone can see history"
},
"header_avatar_open_settings_label": "Open room settings",
"header_face_pile_tooltip": "People",
diff --git a/test/unit-tests/components/views/rooms/RoomHeader/RoomHeader-test.tsx b/test/unit-tests/components/views/rooms/RoomHeader/RoomHeader-test.tsx
index 7c1b5429cdc..7de539ed545 100644
--- a/test/unit-tests/components/views/rooms/RoomHeader/RoomHeader-test.tsx
+++ b/test/unit-tests/components/views/rooms/RoomHeader/RoomHeader-test.tsx
@@ -744,6 +744,29 @@ describe("RoomHeader", () => {
expect(queryByLabelText(document.body, "New members see history")).not.toBeInTheDocument();
});
+ it("shows a user icon if the room is encrypted and has world readable history", async () => {
+ mocked(client.getCrypto()!).isEncryptionEnabledInRoom.mockResolvedValue(true);
+ await room.addLiveEvents(
+ [
+ new MatrixEvent({
+ type: "m.room.history_visibility",
+ content: { history_visibility: "world_readable" },
+ sender: MatrixClientPeg.get()!.getSafeUserId(),
+ state_key: "",
+ room_id: room.roomId,
+ }),
+ ],
+ { addToState: true },
+ );
+ const featureEnabled = true;
+ jest.spyOn(SettingsStore, "getValue").mockImplementation(
+ (flag) => flag === "feature_share_history_on_invite" && featureEnabled,
+ );
+
+ render(, getWrapper());
+ await waitFor(() => getByLabelText(document.body, "Anyone can see history"));
+ });
+
describe("dm", () => {
beforeEach(() => {
// Make the mocked room a DM
diff --git a/test/unit-tests/components/views/rooms/RoomHeader/__snapshots__/RoomHeader-test.tsx.snap b/test/unit-tests/components/views/rooms/RoomHeader/__snapshots__/RoomHeader-test.tsx.snap
index 404edd3c6aa..e3ff02aeaf2 100644
--- a/test/unit-tests/components/views/rooms/RoomHeader/__snapshots__/RoomHeader-test.tsx.snap
+++ b/test/unit-tests/components/views/rooms/RoomHeader/__snapshots__/RoomHeader-test.tsx.snap
@@ -56,7 +56,7 @@ exports[`RoomHeader dm does not show the face pile for DMs 1`] = `
style="--cpd-icon-button-size: 100%;"
>