From 1d1a8a816789c8e5ce77dbffbdee2b54d050d921 Mon Sep 17 00:00:00 2001 From: Half-Shot Date: Wed, 17 Dec 2025 23:45:50 +0000 Subject: [PATCH] fixup --- .../e2e/audio-player/audio-player.spec.ts | 2 +- playwright/e2e/right-panel/file-panel.spec.ts | 2 +- playwright/e2e/timeline/timeline.spec.ts | 2 +- res/css/structures/_RoomView.pcss | 4 +++ src/RoomNotifs.ts | 1 + src/components/structures/RoomStatusBar.tsx | 19 ++++++++++-- src/components/structures/RoomView.tsx | 29 +++++++++++++++++-- .../notifications/RoomNotificationState.ts | 2 +- test/test-utils/test-utils.ts | 5 ++++ .../structures/RoomStatusBar-test.tsx | 2 +- .../RoomNotificationState-test.ts | 12 +++++--- 11 files changed, 67 insertions(+), 13 deletions(-) diff --git a/playwright/e2e/audio-player/audio-player.spec.ts b/playwright/e2e/audio-player/audio-player.spec.ts index 44da5e301d..282440f74e 100644 --- a/playwright/e2e/audio-player/audio-player.spec.ts +++ b/playwright/e2e/audio-player/audio-player.spec.ts @@ -35,7 +35,7 @@ test.describe("Audio player", { tag: ["@no-firefox", "@no-webkit"] }, () => { await page.locator(".mx_Dialog").getByRole("button", { name: "Upload" }).click(); // Wait until the file is sent - await expect(page.locator(".mx_RoomView_statusArea")).not.toBeVisible(); + await expect(page.locator(".mx_RoomView_statusArea_expanded")).not.toBeVisible(); await expect(page.locator(".mx_EventTile.mx_EventTile_last .mx_EventTile_receiptSent")).toBeVisible(); // wait for the tile to finish loading await expect( diff --git a/playwright/e2e/right-panel/file-panel.spec.ts b/playwright/e2e/right-panel/file-panel.spec.ts index f7b6e05aa3..5549b2d315 100644 --- a/playwright/e2e/right-panel/file-panel.spec.ts +++ b/playwright/e2e/right-panel/file-panel.spec.ts @@ -22,7 +22,7 @@ async function uploadFile(page: Page, file: string) { await page.locator(".mx_Dialog").getByRole("button", { name: "Upload" }).click(); // Wait until the file is sent - await expect(page.locator(".mx_RoomView_statusArea")).not.toBeVisible(); + await expect(page.locator(".mx_RoomView_statusArea_expanded")).not.toBeVisible(); await expect(page.locator(".mx_EventTile.mx_EventTile_last .mx_EventTile_receiptSent")).toBeVisible(); } diff --git a/playwright/e2e/timeline/timeline.spec.ts b/playwright/e2e/timeline/timeline.spec.ts index a0cce2a178..806e7e9038 100644 --- a/playwright/e2e/timeline/timeline.spec.ts +++ b/playwright/e2e/timeline/timeline.spec.ts @@ -771,7 +771,7 @@ test.describe("Timeline", () => { await page.locator(".mx_Dialog").getByRole("button", { name: "Upload" }).click(); // Wait until the file is sent - await expect(page.locator(".mx_RoomView_statusArea")).not.toBeVisible(); + await expect(page.locator(".mx_RoomView_statusArea_expanded")).not.toBeVisible(); await expect(page.locator(".mx_EventTile.mx_EventTile_last .mx_EventTile_receiptSent")).toBeVisible(); // Assert that the file size is displayed in kibibytes (1024 bytes), not kilobytes (1000 bytes) diff --git a/res/css/structures/_RoomView.pcss b/res/css/structures/_RoomView.pcss index e135e52f0d..03f95020da 100644 --- a/res/css/structures/_RoomView.pcss +++ b/res/css/structures/_RoomView.pcss @@ -99,11 +99,15 @@ Please see LICENSE files in the repository root for full details. width: 100%; flex: 0 0 auto; + max-height: 0px; background-color: $background; z-index: 1000; overflow: hidden; transition: all 0.2s ease-out; +} + +.mx_RoomView_statusArea_expanded { max-height: 100px; } diff --git a/src/RoomNotifs.ts b/src/RoomNotifs.ts index 5d39b4f54b..ba354b828a 100644 --- a/src/RoomNotifs.ts +++ b/src/RoomNotifs.ts @@ -254,6 +254,7 @@ export function determineUnreadState( return { symbol: null, count: 0, level: NotificationLevel.None, invited: false }; } + console.log("determineUnreadState", getUnsentMessages(room, threadId)); if (getUnsentMessages(room, threadId).length > 0) { return { symbol: "!", count: 1, level: NotificationLevel.Unsent, invited: false }; } diff --git a/src/components/structures/RoomStatusBar.tsx b/src/components/structures/RoomStatusBar.tsx index 1196c7ec88..4d34fdeceb 100644 --- a/src/components/structures/RoomStatusBar.tsx +++ b/src/components/structures/RoomStatusBar.tsx @@ -7,7 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com Please see LICENSE files in the repository root for full details. */ -import React, { type JSX } from "react"; +import React, { useEffect, type JSX } from "react"; import { type Room } from "matrix-js-sdk/src/matrix"; import { RestartIcon, WarningIcon, DeleteIcon } from "@vector-im/compound-design-tokens/assets/web/icons"; @@ -21,10 +21,25 @@ import { useRoomStatusBarViewModel } from "../viewmodels/rooms/RoomStatusBarView interface IProps { // the room this statusbar is representing. room: Room; + /** + * Called when the component becomes visible. + * @returns + */ + onVisible: () => void; + /** + * Called when the component becomes hidden. + * @returns + */ + onHidden: () => void; } -export function RoomStatusBar(props: IProps): JSX.Element|null { +export function RoomStatusBar(props: IProps): JSX.Element | null { const vm = useRoomStatusBarViewModel(props); + + useEffect(() => { + vm.visible ? props.onVisible() : props.onHidden(); + }, [vm.visible]); + if (!vm.visible) { return null; } diff --git a/src/components/structures/RoomView.tsx b/src/components/structures/RoomView.tsx index 6c6c6720df..ae1098de31 100644 --- a/src/components/structures/RoomView.tsx +++ b/src/components/structures/RoomView.tsx @@ -243,6 +243,7 @@ export interface IRoomState { // 'scroll to bottom' knob, among a couple of other things. atEndOfLiveTimeline?: boolean; showTopUnreadMessagesBar: boolean; + statusBarVisible: boolean; // We load this later by asking the js-sdk to suggest a version for us. // This object is the result of Room#getRecommendedVersion() @@ -461,6 +462,7 @@ export class RoomView extends React.Component { showRightPanel: false, joining: false, showTopUnreadMessagesBar: false, + statusBarVisible: false, canReact: false, canSendMessages: false, resizing: false, @@ -2014,6 +2016,17 @@ export class RoomView extends React.Component { }; } + private onStatusBarVisible = (): void => { + if (this.unmounted || this.state.statusBarVisible) return; + this.setState({ statusBarVisible: true }); + }; + + private onStatusBarHidden = (): void => { + // This is currently not desired as it is annoying if it keeps expanding and collapsing + if (this.unmounted || !this.state.statusBarVisible) return; + this.setState({ statusBarVisible: false }); + }; + /** * called by the parent component when PageUp/Down/etc is pressed. * @@ -2364,17 +2377,29 @@ export class RoomView extends React.Component { } let statusBar: JSX.Element | undefined; + let isStatusAreaExpanded = true; if (ContentMessages.sharedInstance().getCurrentUploads().length > 0) { statusBar = ; } else if (!this.state.search) { - statusBar = ; + isStatusAreaExpanded = this.state.statusBarVisible; + statusBar = ( + + ); } + const statusBarAreaClass = classNames("mx_RoomView_statusArea", { + mx_RoomView_statusArea_expanded: isStatusAreaExpanded, + }); + // if statusBar does not exist then statusBarArea is blank and takes up unnecessary space on the screen // show statusBarArea only if statusBar is present const statusBarArea = statusBar && ( -
+
{statusBar} diff --git a/src/stores/notifications/RoomNotificationState.ts b/src/stores/notifications/RoomNotificationState.ts index af873f712e..9418e2c8fa 100644 --- a/src/stores/notifications/RoomNotificationState.ts +++ b/src/stores/notifications/RoomNotificationState.ts @@ -141,7 +141,7 @@ export class RoomNotificationState extends NotificationState implements IDestroy private updateNotificationState(): void { const snapshot = this.snapshot(); - + console.log(RoomNotifs.determineUnreadState(this.room, undefined, this.includeThreads)); const { level, symbol, count, invited } = RoomNotifs.determineUnreadState( this.room, undefined, diff --git a/test/test-utils/test-utils.ts b/test/test-utils/test-utils.ts index 525f2e4ed8..9e0ac5cba7 100644 --- a/test/test-utils/test-utils.ts +++ b/test/test-utils/test-utils.ts @@ -32,6 +32,7 @@ import { type GroupCall, HistoryVisibility, type ICreateRoomOpts, + EventStatus, } from "matrix-js-sdk/src/matrix"; import { KnownMembership } from "matrix-js-sdk/src/types"; import { normalize } from "matrix-js-sdk/src/utils"; @@ -399,6 +400,7 @@ type MakeEventProps = MakeEventPassThruProps & { // eslint-disable-next-line camelcase prev_content?: IContent; unsigned?: IUnsigned; + status?: EventStatus; }; export const mkRoomCreateEvent = (userId: string, roomId: string, content?: IContent): MatrixEvent => { @@ -479,6 +481,9 @@ export function mkEvent(opts: MakeEventProps): MatrixEvent { getMxcAvatarUrl: () => {}, } as unknown as RoomMember; } + if (opts.status !== undefined) { + mxEvent.status = opts.status; + } return mxEvent; } diff --git a/test/unit-tests/components/structures/RoomStatusBar-test.tsx b/test/unit-tests/components/structures/RoomStatusBar-test.tsx index 493eb143e1..cc08089312 100644 --- a/test/unit-tests/components/structures/RoomStatusBar-test.tsx +++ b/test/unit-tests/components/structures/RoomStatusBar-test.tsx @@ -48,7 +48,7 @@ describe("RoomStatusBar", () => { }); const getComponent = () => - render(, { + render( {}} onHidden={() => {}} />, { wrapper: ({ children }) => ( {children} ), diff --git a/test/unit-tests/stores/notifications/RoomNotificationState-test.ts b/test/unit-tests/stores/notifications/RoomNotificationState-test.ts index 91d13809ec..5dde41b907 100644 --- a/test/unit-tests/stores/notifications/RoomNotificationState-test.ts +++ b/test/unit-tests/stores/notifications/RoomNotificationState-test.ts @@ -25,7 +25,6 @@ import { NotificationStateEvents } from "../../../../src/stores/notifications/No import { NotificationLevel } from "../../../../src/stores/notifications/NotificationLevel"; import { createMessageEventContent } from "../../../test-utils/events"; import SettingsStore from "../../../../src/settings/SettingsStore"; -import * as RoomStatusBarModule from "../../../../src/components/structures/RoomStatusBar"; import * as UnreadModule from "../../../../src/Unread"; describe("RoomNotificationState", () => { @@ -33,6 +32,7 @@ describe("RoomNotificationState", () => { let client: MatrixClient; beforeEach(() => { + console.log("Creating spy"); client = stubClient(); room = new Room("!room:example.com", client, "@user:example.org", { pendingEventOrdering: PendingEventOrdering.Detached, @@ -210,7 +210,7 @@ describe("RoomNotificationState", () => { describe("computed attributes", () => { beforeEach(() => { - jest.spyOn(RoomStatusBarModule, "getUnsentMessages").mockReturnValue([]); + jest.spyOn(room, "getPendingEvents").mockReturnValue([]); jest.spyOn(UnreadModule, "doesRoomHaveUnreadMessages").mockReturnValue(false); }); @@ -221,7 +221,9 @@ describe("RoomNotificationState", () => { }); it("should has isUnsetMessage at true", () => { - jest.spyOn(RoomStatusBarModule, "getUnsentMessages").mockReturnValue([{} as MatrixEvent]); + jest.spyOn(room, "getPendingEvents").mockReturnValue([ + mkEvent({ status: EventStatus.NOT_SENT, user: "@foobar:example.org", type: "any.event", content: {} }), + ]); const roomNotifState = new RoomNotificationState(room, false); expect(roomNotifState.isUnsentMessage).toBe(true); }); @@ -239,7 +241,9 @@ describe("RoomNotificationState", () => { room.updateMyMembership(KnownMembership.Knock); expect(roomNotifState.isMention).toBe(false); - jest.spyOn(RoomStatusBarModule, "getUnsentMessages").mockReturnValue([{} as MatrixEvent]); + jest.spyOn(room, "getPendingEvents").mockReturnValue([ + mkEvent({ status: EventStatus.NOT_SENT, user: "@foobar:example.org", type: "any.event", content: {} }), + ]); room.updateMyMembership(KnownMembership.Join); expect(roomNotifState.isMention).toBe(false); });