This commit is contained in:
Half-Shot 2025-12-17 23:45:50 +00:00
parent 73f157d769
commit 1d1a8a8167
11 changed files with 67 additions and 13 deletions

View File

@ -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(

View File

@ -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();
}

View File

@ -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)

View File

@ -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;
}

View File

@ -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 };
}

View File

@ -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;
}

View File

@ -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<IRoomProps, IRoomState> {
showRightPanel: false,
joining: false,
showTopUnreadMessagesBar: false,
statusBarVisible: false,
canReact: false,
canSendMessages: false,
resizing: false,
@ -2014,6 +2016,17 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
};
}
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<IRoomProps, IRoomState> {
}
let statusBar: JSX.Element | undefined;
let isStatusAreaExpanded = true;
if (ContentMessages.sharedInstance().getCurrentUploads().length > 0) {
statusBar = <UploadBar room={this.state.room} />;
} else if (!this.state.search) {
statusBar = <RoomStatusBar room={this.state.room} />;
isStatusAreaExpanded = this.state.statusBarVisible;
statusBar = (
<RoomStatusBar
room={this.state.room}
onVisible={this.onStatusBarVisible}
onHidden={this.onStatusBarHidden}
/>
);
}
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 && (
<div role="region" className="mx_RoomView_statusArea" aria-label={_t("a11y|room_status_bar")}>
<div role="region" className={statusBarAreaClass} aria-label={_t("a11y|room_status_bar")}>
<div className="mx_RoomView_statusAreaBox">
<div className="mx_RoomView_statusAreaBox_line" />
{statusBar}

View File

@ -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,

View File

@ -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;
}

View File

@ -48,7 +48,7 @@ describe("RoomStatusBar", () => {
});
const getComponent = () =>
render(<RoomStatusBar room={room} />, {
render(<RoomStatusBar room={room} onVisible={() => {}} onHidden={() => {}} />, {
wrapper: ({ children }) => (
<MatrixClientContext.Provider value={client}>{children}</MatrixClientContext.Provider>
),

View File

@ -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);
});