diff --git a/src/components/viewmodels/roomlist/RoomListViewModel.tsx b/src/components/viewmodels/roomlist/RoomListViewModel.tsx index b1b39e7f0c1..6c46ca6d383 100644 --- a/src/components/viewmodels/roomlist/RoomListViewModel.tsx +++ b/src/components/viewmodels/roomlist/RoomListViewModel.tsx @@ -8,6 +8,7 @@ Please see LICENSE files in the repository root for full details. import type { Room } from "matrix-js-sdk/src/matrix"; import { type PrimaryFilter, type SecondaryFilters, useFilteredRooms } from "./useFilteredRooms"; import { type SortOption, useSorter } from "./useSorter"; +import { useMessagePreviewToggle } from "./useMessagePreviewToggle"; export interface RoomListViewState { /** @@ -39,6 +40,16 @@ export interface RoomListViewState { * The currently active sort option. */ activeSortOption: SortOption; + + /** + * Whether message previews must be shown or not. + */ + shouldShowMessagePreview: boolean; + + /** + * A function to turn on/off message previews. + */ + toggleMessagePreview: () => void; } /** @@ -48,6 +59,7 @@ export interface RoomListViewState { export function useRoomListViewModel(): RoomListViewState { const { primaryFilters, rooms, activateSecondaryFilter, activeSecondaryFilter } = useFilteredRooms(); const { activeSortOption, sort } = useSorter(); + const { shouldShowMessagePreview, toggleMessagePreview } = useMessagePreviewToggle(); return { rooms, @@ -56,5 +68,7 @@ export function useRoomListViewModel(): RoomListViewState { activeSecondaryFilter, activeSortOption, sort, + shouldShowMessagePreview, + toggleMessagePreview, }; } diff --git a/src/components/viewmodels/roomlist/useMessagePreviewToggle.tsx b/src/components/viewmodels/roomlist/useMessagePreviewToggle.tsx new file mode 100644 index 00000000000..27ccd401066 --- /dev/null +++ b/src/components/viewmodels/roomlist/useMessagePreviewToggle.tsx @@ -0,0 +1,36 @@ +/* + * Copyright 2025 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ +import { useCallback, useState } from "react"; + +import SettingsStore from "../../../settings/SettingsStore"; +import { SettingLevel } from "../../../settings/SettingLevel"; + +interface MessagePreviewToggleState { + shouldShowMessagePreview: boolean; + toggleMessagePreview: () => void; +} + +/** + * This hook: + * - Provides a state that tracks whether message previews are turned on or off. + * - Provides a function to toggle message previews. + */ +export function useMessagePreviewToggle(): MessagePreviewToggleState { + const [shouldShowMessagePreview, setShouldShowMessagePreview] = useState(() => + SettingsStore.getValue("RoomList.showMessagePreview"), + ); + + const toggleMessagePreview = useCallback((): void => { + setShouldShowMessagePreview((current) => { + const toggled = !current; + SettingsStore.setValue("RoomList.showMessagePreview", null, SettingLevel.DEVICE, toggled); + return toggled; + }); + }, []); + + return { toggleMessagePreview, shouldShowMessagePreview }; +} diff --git a/src/settings/Settings.tsx b/src/settings/Settings.tsx index 3084263b2fe..d887c9bb49b 100644 --- a/src/settings/Settings.tsx +++ b/src/settings/Settings.tsx @@ -314,6 +314,7 @@ export interface Settings { "showImages": IBaseSetting; "showAvatarsOnInvites": IBaseSetting; "RoomList.preferredSorting": IBaseSetting; + "RoomList.showMessagePreview": IBaseSetting; "RightPanel.phasesGlobal": IBaseSetting; "RightPanel.phases": IBaseSetting; "enableEventIndexing": IBaseSetting; @@ -1126,6 +1127,10 @@ export const SETTINGS: Settings = { supportedLevels: [SettingLevel.DEVICE], default: SortingAlgorithm.Recency, }, + "RoomList.showMessagePreview": { + supportedLevels: [SettingLevel.DEVICE], + default: false, + }, "RightPanel.phasesGlobal": { supportedLevels: [SettingLevel.DEVICE], default: null, diff --git a/test/unit-tests/components/viewmodels/roomlist/RoomListViewModel-test.tsx b/test/unit-tests/components/viewmodels/roomlist/RoomListViewModel-test.tsx index 99f1483d4a1..43364e0d775 100644 --- a/test/unit-tests/components/viewmodels/roomlist/RoomListViewModel-test.tsx +++ b/test/unit-tests/components/viewmodels/roomlist/RoomListViewModel-test.tsx @@ -218,4 +218,26 @@ describe("RoomListViewModel", () => { expect(vm.current.activeSortOption).toEqual(SortOption.AToZ); }); }); + + describe("message preview toggle", () => { + it("should return shouldShowMessagePreview based on setting", () => { + jest.spyOn(SettingsStore, "getValue").mockImplementation(() => true); + mockAndCreateRooms(); + const { result: vm } = renderHook(() => useRoomListViewModel()); + expect(vm.current.shouldShowMessagePreview).toEqual(true); + }); + + it("should change setting on toggle", () => { + jest.spyOn(SettingsStore, "getValue").mockImplementation(() => true); + const fn = jest.spyOn(SettingsStore, "setValue").mockImplementation(async () => {}); + mockAndCreateRooms(); + const { result: vm } = renderHook(() => useRoomListViewModel()); + expect(vm.current.shouldShowMessagePreview).toEqual(true); + act(() => { + vm.current.toggleMessagePreview(); + }); + expect(vm.current.shouldShowMessagePreview).toEqual(false); + expect(fn).toHaveBeenCalled(); + }); + }); }); diff --git a/test/unit-tests/components/views/rooms/RoomListPanel/RoomList-test.tsx b/test/unit-tests/components/views/rooms/RoomListPanel/RoomList-test.tsx index 11764df7b76..5e2d451ff83 100644 --- a/test/unit-tests/components/views/rooms/RoomListPanel/RoomList-test.tsx +++ b/test/unit-tests/components/views/rooms/RoomListPanel/RoomList-test.tsx @@ -35,6 +35,8 @@ describe("", () => { activeSecondaryFilter: SecondaryFilters.AllActivity, sort: jest.fn(), activeSortOption: SortOption.Activity, + shouldShowMessagePreview: false, + toggleMessagePreview: jest.fn(), }; // Needed to render a room list cell diff --git a/test/unit-tests/components/views/rooms/RoomListPanel/RoomListPrimaryFilters-test.tsx b/test/unit-tests/components/views/rooms/RoomListPanel/RoomListPrimaryFilters-test.tsx index a3e60f765d2..f4b97b84b6b 100644 --- a/test/unit-tests/components/views/rooms/RoomListPanel/RoomListPrimaryFilters-test.tsx +++ b/test/unit-tests/components/views/rooms/RoomListPanel/RoomListPrimaryFilters-test.tsx @@ -28,6 +28,8 @@ describe("", () => { activeSecondaryFilter: SecondaryFilters.AllActivity, sort: jest.fn(), activeSortOption: SortOption.Activity, + shouldShowMessagePreview: false, + toggleMessagePreview: jest.fn(), }; });