mirror of
https://github.com/element-hq/element-web
synced 2024-11-29 12:58:53 +03:00
Apply strictNullChecks
to src/stores/widgets/* (#10324)
* Apply `strictNullChecks` to src/stores/widgets/* * Iterate * Iterate
This commit is contained in:
parent
0c1c3f1cde
commit
c0e40217f3
11 changed files with 59 additions and 55 deletions
|
@ -458,7 +458,7 @@ export default class LegacyCallHandler extends EventEmitter {
|
||||||
|
|
||||||
public getAllActiveCallsForPip(roomId: string): MatrixCall[] {
|
public getAllActiveCallsForPip(roomId: string): MatrixCall[] {
|
||||||
const room = MatrixClientPeg.get().getRoom(roomId);
|
const room = MatrixClientPeg.get().getRoom(roomId);
|
||||||
if (WidgetLayoutStore.instance.hasMaximisedWidget(room)) {
|
if (room && WidgetLayoutStore.instance.hasMaximisedWidget(room)) {
|
||||||
// This checks if there is space for the call view in the aux panel
|
// This checks if there is space for the call view in the aux panel
|
||||||
// If there is no space any call should be displayed in PiP
|
// If there is no space any call should be displayed in PiP
|
||||||
return this.getAllActiveCalls();
|
return this.getAllActiveCalls();
|
||||||
|
|
|
@ -67,7 +67,7 @@ export const WidgetContextMenu: React.FC<IProps> = ({
|
||||||
if (getConfigLivestreamUrl() && WidgetType.JITSI.matches(app.type)) {
|
if (getConfigLivestreamUrl() && WidgetType.JITSI.matches(app.type)) {
|
||||||
const onStreamAudioClick = async (): Promise<void> => {
|
const onStreamAudioClick = async (): Promise<void> => {
|
||||||
try {
|
try {
|
||||||
await startJitsiAudioLivestream(widgetMessaging, roomId);
|
await startJitsiAudioLivestream(widgetMessaging!, roomId);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.error("Failed to start livestream", err);
|
logger.error("Failed to start livestream", err);
|
||||||
// XXX: won't i18n well, but looks like widget api only support 'message'?
|
// XXX: won't i18n well, but looks like widget api only support 'message'?
|
||||||
|
@ -84,7 +84,7 @@ export const WidgetContextMenu: React.FC<IProps> = ({
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const pinnedWidgets = WidgetLayoutStore.instance.getContainerWidgets(room, Container.Top);
|
const pinnedWidgets = room ? WidgetLayoutStore.instance.getContainerWidgets(room, Container.Top) : [];
|
||||||
const widgetIndex = pinnedWidgets.findIndex((widget) => widget.id === app.id);
|
const widgetIndex = pinnedWidgets.findIndex((widget) => widget.id === app.id);
|
||||||
|
|
||||||
let editButton;
|
let editButton;
|
||||||
|
@ -196,6 +196,7 @@ export const WidgetContextMenu: React.FC<IProps> = ({
|
||||||
let moveRightButton;
|
let moveRightButton;
|
||||||
if (showUnpin && widgetIndex < pinnedWidgets.length - 1) {
|
if (showUnpin && widgetIndex < pinnedWidgets.length - 1) {
|
||||||
const onClick = (): void => {
|
const onClick = (): void => {
|
||||||
|
if (!room) throw new Error("room must be defined");
|
||||||
WidgetLayoutStore.instance.moveWithinContainer(room, Container.Top, app, 1);
|
WidgetLayoutStore.instance.moveWithinContainer(room, Container.Top, app, 1);
|
||||||
onFinished();
|
onFinished();
|
||||||
};
|
};
|
||||||
|
|
|
@ -99,7 +99,7 @@ interface IState {
|
||||||
hasPermissionToLoad: boolean;
|
hasPermissionToLoad: boolean;
|
||||||
// Wait for user profile load to display correct name
|
// Wait for user profile load to display correct name
|
||||||
isUserProfileReady: boolean;
|
isUserProfileReady: boolean;
|
||||||
error: Error;
|
error: Error | null;
|
||||||
menuDisplayed: boolean;
|
menuDisplayed: boolean;
|
||||||
requiresClient: boolean;
|
requiresClient: boolean;
|
||||||
}
|
}
|
||||||
|
@ -124,7 +124,7 @@ export default class AppTile extends React.Component<IProps, IState> {
|
||||||
private iframe: HTMLIFrameElement; // ref to the iframe (callback style)
|
private iframe: HTMLIFrameElement; // ref to the iframe (callback style)
|
||||||
private allowedWidgetsWatchRef: string;
|
private allowedWidgetsWatchRef: string;
|
||||||
private persistKey: string;
|
private persistKey: string;
|
||||||
private sgWidget: StopGapWidget;
|
private sgWidget: StopGapWidget | null;
|
||||||
private dispatcherRef: string;
|
private dispatcherRef: string;
|
||||||
private unmounted: boolean;
|
private unmounted: boolean;
|
||||||
|
|
||||||
|
@ -202,7 +202,7 @@ export default class AppTile extends React.Component<IProps, IState> {
|
||||||
private determineInitialRequiresClientState(): boolean {
|
private determineInitialRequiresClientState(): boolean {
|
||||||
try {
|
try {
|
||||||
const mockWidget = new ElementWidget(this.props.app);
|
const mockWidget = new ElementWidget(this.props.app);
|
||||||
const widgetApi = WidgetMessagingStore.instance.getMessaging(mockWidget, this.props.room.roomId);
|
const widgetApi = WidgetMessagingStore.instance.getMessaging(mockWidget, this.props.room?.roomId);
|
||||||
if (widgetApi) {
|
if (widgetApi) {
|
||||||
// Load value from existing API to prevent resetting the requiresClient value on layout changes.
|
// Load value from existing API to prevent resetting the requiresClient value on layout changes.
|
||||||
return widgetApi.hasCapability(ElementWidgetCapabilities.RequiresClient);
|
return widgetApi.hasCapability(ElementWidgetCapabilities.RequiresClient);
|
||||||
|
@ -310,9 +310,9 @@ export default class AppTile extends React.Component<IProps, IState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private setupSgListeners(): void {
|
private setupSgListeners(): void {
|
||||||
this.sgWidget.on("preparing", this.onWidgetPreparing);
|
this.sgWidget?.on("preparing", this.onWidgetPreparing);
|
||||||
// emits when the capabilities have been set up or changed
|
// emits when the capabilities have been set up or changed
|
||||||
this.sgWidget.on("capabilitiesNotified", this.onWidgetCapabilitiesNotified);
|
this.sgWidget?.on("capabilitiesNotified", this.onWidgetCapabilitiesNotified);
|
||||||
}
|
}
|
||||||
|
|
||||||
private stopSgListeners(): void {
|
private stopSgListeners(): void {
|
||||||
|
@ -336,7 +336,7 @@ export default class AppTile extends React.Component<IProps, IState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private startWidget(): void {
|
private startWidget(): void {
|
||||||
this.sgWidget.prepare().then(() => {
|
this.sgWidget?.prepare().then(() => {
|
||||||
if (this.unmounted) return;
|
if (this.unmounted) return;
|
||||||
this.setState({ initialising: false });
|
this.setState({ initialising: false });
|
||||||
});
|
});
|
||||||
|
@ -406,7 +406,7 @@ export default class AppTile extends React.Component<IProps, IState> {
|
||||||
|
|
||||||
private onWidgetCapabilitiesNotified = (): void => {
|
private onWidgetCapabilitiesNotified = (): void => {
|
||||||
this.setState({
|
this.setState({
|
||||||
requiresClient: this.sgWidget.widgetApi.hasCapability(ElementWidgetCapabilities.RequiresClient),
|
requiresClient: !!this.sgWidget?.widgetApi?.hasCapability(ElementWidgetCapabilities.RequiresClient),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -415,7 +415,7 @@ export default class AppTile extends React.Component<IProps, IState> {
|
||||||
case "m.sticker":
|
case "m.sticker":
|
||||||
if (
|
if (
|
||||||
payload.widgetId === this.props.app.id &&
|
payload.widgetId === this.props.app.id &&
|
||||||
this.sgWidget.widgetApi.hasCapability(MatrixCapabilities.StickerSending)
|
this.sgWidget?.widgetApi?.hasCapability(MatrixCapabilities.StickerSending)
|
||||||
) {
|
) {
|
||||||
dis.dispatch({
|
dis.dispatch({
|
||||||
action: "post_sticker_message",
|
action: "post_sticker_message",
|
||||||
|
@ -444,8 +444,8 @@ export default class AppTile extends React.Component<IProps, IState> {
|
||||||
logger.info("Granting permission for widget to load: " + this.props.app.eventId);
|
logger.info("Granting permission for widget to load: " + this.props.app.eventId);
|
||||||
const current = SettingsStore.getValue("allowedWidgets", roomId);
|
const current = SettingsStore.getValue("allowedWidgets", roomId);
|
||||||
if (this.props.app.eventId !== undefined) current[this.props.app.eventId] = true;
|
if (this.props.app.eventId !== undefined) current[this.props.app.eventId] = true;
|
||||||
const level = SettingsStore.firstSupportedLevel("allowedWidgets");
|
const level = SettingsStore.firstSupportedLevel("allowedWidgets")!;
|
||||||
SettingsStore.setValue("allowedWidgets", roomId, level, current)
|
SettingsStore.setValue("allowedWidgets", roomId ?? null, level, current)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.setState({ hasPermissionToLoad: true });
|
this.setState({ hasPermissionToLoad: true });
|
||||||
|
|
||||||
|
@ -501,7 +501,7 @@ export default class AppTile extends React.Component<IProps, IState> {
|
||||||
this.resetWidget(this.props);
|
this.resetWidget(this.props);
|
||||||
this.startMessaging();
|
this.startMessaging();
|
||||||
|
|
||||||
if (this.iframe) {
|
if (this.iframe && this.sgWidget) {
|
||||||
// Reload iframe
|
// Reload iframe
|
||||||
this.iframe.src = this.sgWidget.embedUrl;
|
this.iframe.src = this.sgWidget.embedUrl;
|
||||||
}
|
}
|
||||||
|
@ -519,7 +519,7 @@ export default class AppTile extends React.Component<IProps, IState> {
|
||||||
// window.open(this._getPopoutUrl(), '_blank', 'noopener=yes');
|
// window.open(this._getPopoutUrl(), '_blank', 'noopener=yes');
|
||||||
Object.assign(document.createElement("a"), {
|
Object.assign(document.createElement("a"), {
|
||||||
target: "_blank",
|
target: "_blank",
|
||||||
href: this.sgWidget.popoutUrl,
|
href: this.sgWidget?.popoutUrl,
|
||||||
rel: "noreferrer noopener",
|
rel: "noreferrer noopener",
|
||||||
}).click();
|
}).click();
|
||||||
};
|
};
|
||||||
|
@ -676,7 +676,7 @@ export default class AppTile extends React.Component<IProps, IState> {
|
||||||
if (this.state.menuDisplayed) {
|
if (this.state.menuDisplayed) {
|
||||||
contextMenu = (
|
contextMenu = (
|
||||||
<WidgetContextMenu
|
<WidgetContextMenu
|
||||||
{...aboveLeftOf(this.contextMenuButton.current.getBoundingClientRect(), null)}
|
{...aboveLeftOf(this.contextMenuButton.current.getBoundingClientRect())}
|
||||||
app={this.props.app}
|
app={this.props.app}
|
||||||
onFinished={this.closeContextMenu}
|
onFinished={this.closeContextMenu}
|
||||||
showUnpin={!this.props.userWidget}
|
showUnpin={!this.props.userWidget}
|
||||||
|
|
|
@ -43,7 +43,7 @@ export class IntegrationManagerInstance {
|
||||||
|
|
||||||
public get name(): string {
|
public get name(): string {
|
||||||
const parsed = url.parse(this.uiUrl);
|
const parsed = url.parse(this.uiUrl);
|
||||||
return parsed.host;
|
return parsed.host ?? "";
|
||||||
}
|
}
|
||||||
|
|
||||||
public get trimmedApiUrl(): string {
|
public get trimmedApiUrl(): string {
|
||||||
|
|
|
@ -75,7 +75,7 @@ export default class ActiveWidgetStore extends EventEmitter {
|
||||||
this.setWidgetPersistence(widgetId, roomId, false);
|
this.setWidgetPersistence(widgetId, roomId, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public setWidgetPersistence(widgetId: string, roomId: string, val: boolean): void {
|
public setWidgetPersistence(widgetId: string, roomId: string | null, val: boolean): void {
|
||||||
const isPersisted = this.getWidgetPersistence(widgetId, roomId);
|
const isPersisted = this.getWidgetPersistence(widgetId, roomId);
|
||||||
|
|
||||||
if (isPersisted && !val) {
|
if (isPersisted && !val) {
|
||||||
|
@ -88,7 +88,7 @@ export default class ActiveWidgetStore extends EventEmitter {
|
||||||
this.emit(ActiveWidgetStoreEvent.Persistence);
|
this.emit(ActiveWidgetStoreEvent.Persistence);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getWidgetPersistence(widgetId: string, roomId: string): boolean {
|
public getWidgetPersistence(widgetId: string, roomId: string | null): boolean {
|
||||||
return this.persistentWidgetId === widgetId && this.persistentRoomId === roomId;
|
return this.persistentWidgetId === widgetId && this.persistentRoomId === roomId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -285,7 +285,7 @@ export class StopGapWidget extends EventEmitter {
|
||||||
this.messaging = new ClientWidgetApi(this.mockWidget, iframe, driver);
|
this.messaging = new ClientWidgetApi(this.mockWidget, iframe, driver);
|
||||||
this.messaging.on("preparing", () => this.emit("preparing"));
|
this.messaging.on("preparing", () => this.emit("preparing"));
|
||||||
this.messaging.on("ready", () => {
|
this.messaging.on("ready", () => {
|
||||||
WidgetMessagingStore.instance.storeMessaging(this.mockWidget, this.roomId, this.messaging);
|
WidgetMessagingStore.instance.storeMessaging(this.mockWidget, this.roomId, this.messaging!);
|
||||||
this.emit("ready");
|
this.emit("ready");
|
||||||
});
|
});
|
||||||
this.messaging.on("capabilitiesNotified", () => this.emit("capabilitiesNotified"));
|
this.messaging.on("capabilitiesNotified", () => this.emit("capabilitiesNotified"));
|
||||||
|
@ -347,7 +347,7 @@ export class StopGapWidget extends EventEmitter {
|
||||||
if (this.messaging?.hasCapability(MatrixCapabilities.AlwaysOnScreen)) {
|
if (this.messaging?.hasCapability(MatrixCapabilities.AlwaysOnScreen)) {
|
||||||
ActiveWidgetStore.instance.setWidgetPersistence(
|
ActiveWidgetStore.instance.setWidgetPersistence(
|
||||||
this.mockWidget.id,
|
this.mockWidget.id,
|
||||||
this.roomId,
|
this.roomId ?? null,
|
||||||
ev.detail.data.value,
|
ev.detail.data.value,
|
||||||
);
|
);
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
|
@ -393,14 +393,12 @@ export class StopGapWidget extends EventEmitter {
|
||||||
const integType = data?.integType as string;
|
const integType = data?.integType as string;
|
||||||
const integId = <string>data?.integId;
|
const integId = <string>data?.integId;
|
||||||
|
|
||||||
|
const roomId = SdkContextClass.instance.roomViewStore.getRoomId();
|
||||||
|
const room = roomId ? this.client.getRoom(roomId) : undefined;
|
||||||
|
if (!room) return;
|
||||||
|
|
||||||
// noinspection JSIgnoredPromiseFromCall
|
// noinspection JSIgnoredPromiseFromCall
|
||||||
IntegrationManagers.sharedInstance()
|
IntegrationManagers.sharedInstance()?.getPrimaryManager()?.open(room, `type_${integType}`, integId);
|
||||||
.getPrimaryManager()
|
|
||||||
.open(
|
|
||||||
this.client.getRoom(SdkContextClass.instance.roomViewStore.getRoomId()),
|
|
||||||
`type_${integType}`,
|
|
||||||
integId,
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -434,7 +432,7 @@ export class StopGapWidget extends EventEmitter {
|
||||||
if (managers.hasManager()) {
|
if (managers.hasManager()) {
|
||||||
// TODO: Pick the right manager for the widget
|
// TODO: Pick the right manager for the widget
|
||||||
const defaultManager = managers.getPrimaryManager();
|
const defaultManager = managers.getPrimaryManager();
|
||||||
if (WidgetUtils.isScalarUrl(defaultManager.apiUrl)) {
|
if (defaultManager && WidgetUtils.isScalarUrl(defaultManager.apiUrl)) {
|
||||||
const scalar = defaultManager.getScalarClient();
|
const scalar = defaultManager.getScalarClient();
|
||||||
this.scalarToken = await scalar.getScalarToken();
|
this.scalarToken = await scalar.getScalarToken();
|
||||||
}
|
}
|
||||||
|
@ -452,7 +450,10 @@ export class StopGapWidget extends EventEmitter {
|
||||||
* @param opts
|
* @param opts
|
||||||
*/
|
*/
|
||||||
public stopMessaging(opts = { forceDestroy: false }): void {
|
public stopMessaging(opts = { forceDestroy: false }): void {
|
||||||
if (!opts?.forceDestroy && ActiveWidgetStore.instance.getWidgetPersistence(this.mockWidget.id, this.roomId)) {
|
if (
|
||||||
|
!opts?.forceDestroy &&
|
||||||
|
ActiveWidgetStore.instance.getWidgetPersistence(this.mockWidget.id, this.roomId ?? null)
|
||||||
|
) {
|
||||||
logger.log("Skipping destroy - persistent widget");
|
logger.log("Skipping destroy - persistent widget");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -500,9 +501,11 @@ export class StopGapWidget extends EventEmitter {
|
||||||
|
|
||||||
let isBeforeMark = true;
|
let isBeforeMark = true;
|
||||||
|
|
||||||
|
const room = this.client.getRoom(ev.getRoomId()!);
|
||||||
|
if (!room) return;
|
||||||
// Timelines are most recent last, so reverse the order and limit ourselves to 100 events
|
// Timelines are most recent last, so reverse the order and limit ourselves to 100 events
|
||||||
// to avoid overusing the CPU.
|
// to avoid overusing the CPU.
|
||||||
const timeline = this.client.getRoom(ev.getRoomId()!).getLiveTimeline();
|
const timeline = room.getLiveTimeline();
|
||||||
const events = arrayFastClone(timeline.getEvents()).reverse().slice(0, 100);
|
const events = arrayFastClone(timeline.getEvents()).reverse().slice(0, 100);
|
||||||
|
|
||||||
for (const timelineEvent of events) {
|
for (const timelineEvent of events) {
|
||||||
|
@ -533,7 +536,7 @@ export class StopGapWidget extends EventEmitter {
|
||||||
}
|
}
|
||||||
|
|
||||||
const raw = ev.getEffectiveEvent();
|
const raw = ev.getEffectiveEvent();
|
||||||
this.messaging.feedEvent(raw as IRoomEvent, this.eventListenerRoomId).catch((e) => {
|
this.messaging.feedEvent(raw as IRoomEvent, this.eventListenerRoomId!).catch((e) => {
|
||||||
logger.error("Error sending event to widget: ", e);
|
logger.error("Error sending event to widget: ", e);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,7 +113,7 @@ export class StopGapWidgetDriver extends WidgetDriver {
|
||||||
this.allowedCapabilities.add("visibility");
|
this.allowedCapabilities.add("visibility");
|
||||||
} else if (
|
} else if (
|
||||||
virtual &&
|
virtual &&
|
||||||
new URL(SdkConfig.get("element_call").url ?? DEFAULTS.element_call.url).origin === this.forWidget.origin
|
new URL(SdkConfig.get("element_call").url ?? DEFAULTS.element_call.url!).origin === this.forWidget.origin
|
||||||
) {
|
) {
|
||||||
// This is a trusted Element Call widget that we control
|
// This is a trusted Element Call widget that we control
|
||||||
this.allowedCapabilities.add(MatrixCapabilities.AlwaysOnScreen);
|
this.allowedCapabilities.add(MatrixCapabilities.AlwaysOnScreen);
|
||||||
|
@ -202,8 +202,8 @@ export class StopGapWidgetDriver extends WidgetDriver {
|
||||||
widget: this.forWidget,
|
widget: this.forWidget,
|
||||||
widgetKind: this.forWidgetKind,
|
widgetKind: this.forWidgetKind,
|
||||||
}).finished;
|
}).finished;
|
||||||
(result.approved || []).forEach((cap) => allowedSoFar.add(cap));
|
result?.approved?.forEach((cap) => allowedSoFar.add(cap));
|
||||||
rememberApproved = result.remember;
|
rememberApproved = !!result?.remember;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error("Non-fatal error getting capabilities: ", e);
|
logger.error("Non-fatal error getting capabilities: ", e);
|
||||||
}
|
}
|
||||||
|
@ -267,7 +267,7 @@ export class StopGapWidgetDriver extends WidgetDriver {
|
||||||
const client = MatrixClientPeg.get();
|
const client = MatrixClientPeg.get();
|
||||||
|
|
||||||
if (encrypted) {
|
if (encrypted) {
|
||||||
const deviceInfoMap = await client.crypto.deviceList.downloadKeys(Object.keys(contentMap), false);
|
const deviceInfoMap = await client.crypto!.deviceList.downloadKeys(Object.keys(contentMap), false);
|
||||||
|
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
Object.entries(contentMap).flatMap(([userId, userContentMap]) =>
|
Object.entries(contentMap).flatMap(([userId, userContentMap]) =>
|
||||||
|
@ -313,7 +313,7 @@ export class StopGapWidgetDriver extends WidgetDriver {
|
||||||
? roomIds.includes(Symbols.AnyRoom)
|
? roomIds.includes(Symbols.AnyRoom)
|
||||||
? client.getVisibleRooms()
|
? client.getVisibleRooms()
|
||||||
: roomIds.map((r) => client.getRoom(r))
|
: roomIds.map((r) => client.getRoom(r))
|
||||||
: [client.getRoom(SdkContextClass.instance.roomViewStore.getRoomId())];
|
: [client.getRoom(SdkContextClass.instance.roomViewStore.getRoomId()!)];
|
||||||
return targetRooms.filter((r) => !!r) as Room[];
|
return targetRooms.filter((r) => !!r) as Room[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -356,7 +356,7 @@ export class StopGapWidgetDriver extends WidgetDriver {
|
||||||
const allResults: IRoomEvent[] = [];
|
const allResults: IRoomEvent[] = [];
|
||||||
for (const room of rooms) {
|
for (const room of rooms) {
|
||||||
const results: MatrixEvent[] = [];
|
const results: MatrixEvent[] = [];
|
||||||
const state: Map<string, MatrixEvent> = room.currentState.events.get(eventType);
|
const state = room.currentState.events.get(eventType);
|
||||||
if (state) {
|
if (state) {
|
||||||
if (stateKey === "" || !!stateKey) {
|
if (stateKey === "" || !!stateKey) {
|
||||||
const forKey = state.get(stateKey);
|
const forKey = state.get(stateKey);
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
import { Room } from "matrix-js-sdk/src/models/room";
|
import { Room } from "matrix-js-sdk/src/models/room";
|
||||||
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
||||||
import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state";
|
import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state";
|
||||||
import { Optional } from "matrix-events-sdk";
|
|
||||||
import { compare } from "matrix-js-sdk/src/utils";
|
import { compare } from "matrix-js-sdk/src/utils";
|
||||||
|
|
||||||
import SettingsStore from "../../settings/SettingsStore";
|
import SettingsStore from "../../settings/SettingsStore";
|
||||||
|
@ -63,7 +62,7 @@ export interface IStoredLayout {
|
||||||
// this only applies to the top container currently, and that container
|
// this only applies to the top container currently, and that container
|
||||||
// will take the highest value among widgets in the container. Clamped
|
// will take the highest value among widgets in the container. Clamped
|
||||||
// to 0-100 and may have minimums imposed on it.
|
// to 0-100 and may have minimums imposed on it.
|
||||||
height?: number;
|
height?: number | null;
|
||||||
|
|
||||||
// TODO: [Deferred] Maximizing (fullscreen) widgets by default.
|
// TODO: [Deferred] Maximizing (fullscreen) widgets by default.
|
||||||
}
|
}
|
||||||
|
@ -147,6 +146,7 @@ export class WidgetLayoutStore extends ReadyWatchingStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
private updateAllRooms = (): void => {
|
private updateAllRooms = (): void => {
|
||||||
|
if (!this.matrixClient) return;
|
||||||
this.byRoom = {};
|
this.byRoom = {};
|
||||||
for (const room of this.matrixClient.getVisibleRooms()) {
|
for (const room of this.matrixClient.getVisibleRooms()) {
|
||||||
this.recalculateRoom(room);
|
this.recalculateRoom(room);
|
||||||
|
@ -267,7 +267,7 @@ export class WidgetLayoutStore extends ReadyWatchingStore {
|
||||||
const userWidgetLayout = userLayout?.widgets?.[widget.id];
|
const userWidgetLayout = userLayout?.widgets?.[widget.id];
|
||||||
|
|
||||||
if (Number.isFinite(userWidgetLayout?.width) || Number.isFinite(widgetLayout?.width)) {
|
if (Number.isFinite(userWidgetLayout?.width) || Number.isFinite(widgetLayout?.width)) {
|
||||||
const val = userWidgetLayout?.width || widgetLayout?.width;
|
const val = (userWidgetLayout?.width || widgetLayout?.width)!;
|
||||||
const normalized = clamp(val, MIN_WIDGET_WIDTH_PCT, 100);
|
const normalized = clamp(val, MIN_WIDGET_WIDTH_PCT, 100);
|
||||||
widths.push(normalized);
|
widths.push(normalized);
|
||||||
doAutobalance = false; // a manual width was specified
|
doAutobalance = false; // a manual width was specified
|
||||||
|
@ -278,7 +278,7 @@ export class WidgetLayoutStore extends ReadyWatchingStore {
|
||||||
if (widgetLayout?.height || userWidgetLayout?.height) {
|
if (widgetLayout?.height || userWidgetLayout?.height) {
|
||||||
const defRoomHeight = defaultNumber(widgetLayout?.height, MIN_WIDGET_HEIGHT_PCT);
|
const defRoomHeight = defaultNumber(widgetLayout?.height, MIN_WIDGET_HEIGHT_PCT);
|
||||||
const h = defaultNumber(userWidgetLayout?.height, defRoomHeight);
|
const h = defaultNumber(userWidgetLayout?.height, defRoomHeight);
|
||||||
maxHeight = Math.max(maxHeight, clamp(h, MIN_WIDGET_HEIGHT_PCT, 100));
|
maxHeight = Math.max(maxHeight ?? 0, clamp(h, MIN_WIDGET_HEIGHT_PCT, 100));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (doAutobalance) {
|
if (doAutobalance) {
|
||||||
|
@ -346,11 +346,11 @@ export class WidgetLayoutStore extends ReadyWatchingStore {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public getContainerWidgets(room: Optional<Room>, container: Container): IApp[] {
|
public getContainerWidgets(room: Room, container: Container): IApp[] {
|
||||||
return this.byRoom[room?.roomId]?.[container]?.ordered || [];
|
return this.byRoom[room.roomId]?.[container]?.ordered || [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public isInContainer(room: Optional<Room>, widget: IApp, container: Container): boolean {
|
public isInContainer(room: Room, widget: IApp, container: Container): boolean {
|
||||||
return this.getContainerWidgets(room, container).some((w) => w.id === widget.id);
|
return this.getContainerWidgets(room, container).some((w) => w.id === widget.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -406,7 +406,7 @@ export class WidgetLayoutStore extends ReadyWatchingStore {
|
||||||
return this.byRoom[room.roomId]?.[container]?.height ?? null; // let the default get returned if needed
|
return this.byRoom[room.roomId]?.[container]?.height ?? null; // let the default get returned if needed
|
||||||
}
|
}
|
||||||
|
|
||||||
public setContainerHeight(room: Room, container: Container, height?: number): void {
|
public setContainerHeight(room: Room, container: Container, height?: number | null): void {
|
||||||
const widgets = this.getContainerWidgets(room, container);
|
const widgets = this.getContainerWidgets(room, container);
|
||||||
const widths = this.byRoom[room.roomId]?.[container]?.distributions;
|
const widths = this.byRoom[room.roomId]?.[container]?.distributions;
|
||||||
const localLayout: Record<string, IStoredLayout> = {};
|
const localLayout: Record<string, IStoredLayout> = {};
|
||||||
|
@ -438,7 +438,7 @@ export class WidgetLayoutStore extends ReadyWatchingStore {
|
||||||
container: container,
|
container: container,
|
||||||
width: widths?.[i],
|
width: widths?.[i],
|
||||||
index: i,
|
index: i,
|
||||||
height: height,
|
height,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
this.updateUserLayout(room, localLayout);
|
this.updateUserLayout(room, localLayout);
|
||||||
|
@ -477,7 +477,7 @@ export class WidgetLayoutStore extends ReadyWatchingStore {
|
||||||
this.updateUserLayout(room, newLayout);
|
this.updateUserLayout(room, newLayout);
|
||||||
}
|
}
|
||||||
|
|
||||||
public hasMaximisedWidget(room?: Room): boolean {
|
public hasMaximisedWidget(room: Room): boolean {
|
||||||
return this.getContainerWidgets(room, Container.Center).length > 0;
|
return this.getContainerWidgets(room, Container.Center).length > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -517,7 +517,7 @@ export class WidgetLayoutStore extends ReadyWatchingStore {
|
||||||
|
|
||||||
const ret: [IApp, Container][] = [];
|
const ret: [IApp, Container][] = [];
|
||||||
for (const container in containers) {
|
for (const container in containers) {
|
||||||
const widgets = containers[container as Container].ordered;
|
const widgets = containers[container as Container]!.ordered;
|
||||||
for (const widget of widgets) {
|
for (const widget of widgets) {
|
||||||
ret.push([widget, container as Container]);
|
ret.push([widget, container as Container]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,7 +58,7 @@ export class WidgetMessagingStore extends AsyncStoreWithClient<{}> {
|
||||||
this.widgetMap.clear();
|
this.widgetMap.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public storeMessaging(widget: Widget, roomId: string, widgetApi: ClientWidgetApi): void {
|
public storeMessaging(widget: Widget, roomId: string | undefined, widgetApi: ClientWidgetApi): void {
|
||||||
this.stopMessaging(widget, roomId);
|
this.stopMessaging(widget, roomId);
|
||||||
const uid = WidgetUtils.calcWidgetUid(widget.id, roomId);
|
const uid = WidgetUtils.calcWidgetUid(widget.id, roomId);
|
||||||
this.widgetMap.set(uid, widgetApi);
|
this.widgetMap.set(uid, widgetApi);
|
||||||
|
@ -66,11 +66,11 @@ export class WidgetMessagingStore extends AsyncStoreWithClient<{}> {
|
||||||
this.emit(WidgetMessagingStoreEvent.StoreMessaging, uid, widgetApi);
|
this.emit(WidgetMessagingStoreEvent.StoreMessaging, uid, widgetApi);
|
||||||
}
|
}
|
||||||
|
|
||||||
public stopMessaging(widget: Widget, roomId: string): void {
|
public stopMessaging(widget: Widget, roomId: string | undefined): void {
|
||||||
this.stopMessagingByUid(WidgetUtils.calcWidgetUid(widget.id, roomId));
|
this.stopMessagingByUid(WidgetUtils.calcWidgetUid(widget.id, roomId));
|
||||||
}
|
}
|
||||||
|
|
||||||
public getMessaging(widget: Widget, roomId: string): ClientWidgetApi {
|
public getMessaging(widget: Widget, roomId: string | undefined): ClientWidgetApi | undefined {
|
||||||
return this.widgetMap.get(WidgetUtils.calcWidgetUid(widget.id, roomId));
|
return this.widgetMap.get(WidgetUtils.calcWidgetUid(widget.id, roomId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,7 +88,7 @@ export class WidgetMessagingStore extends AsyncStoreWithClient<{}> {
|
||||||
* @param {string} widgetUid The widget UID.
|
* @param {string} widgetUid The widget UID.
|
||||||
* @returns {ClientWidgetApi} The widget API, or a falsy value if not found.
|
* @returns {ClientWidgetApi} The widget API, or a falsy value if not found.
|
||||||
*/
|
*/
|
||||||
public getMessagingForUid(widgetUid: string): ClientWidgetApi {
|
public getMessagingForUid(widgetUid: string): ClientWidgetApi | undefined {
|
||||||
return this.widgetMap.get(widgetUid);
|
return this.widgetMap.get(widgetUid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,7 +57,7 @@ export default class WidgetUtils {
|
||||||
* @return Boolean -- true if the user can modify widgets in this room
|
* @return Boolean -- true if the user can modify widgets in this room
|
||||||
* @throws Error -- specifies the error reason
|
* @throws Error -- specifies the error reason
|
||||||
*/
|
*/
|
||||||
public static canUserModifyWidgets(roomId: string): boolean {
|
public static canUserModifyWidgets(roomId?: string): boolean {
|
||||||
if (!roomId) {
|
if (!roomId) {
|
||||||
logger.warn("No room ID specified");
|
logger.warn("No room ID specified");
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -541,7 +541,7 @@ describe("RoomHeader", () => {
|
||||||
|
|
||||||
await withCall(async (call) => {
|
await withCall(async (call) => {
|
||||||
await call.connect();
|
await call.connect();
|
||||||
const messaging = WidgetMessagingStore.instance.getMessagingForUid(WidgetUtils.getWidgetUid(call.widget));
|
const messaging = WidgetMessagingStore.instance.getMessagingForUid(WidgetUtils.getWidgetUid(call.widget))!;
|
||||||
renderHeader({ viewingCall: true, activeCall: call });
|
renderHeader({ viewingCall: true, activeCall: call });
|
||||||
|
|
||||||
// Should start with Freedom selected
|
// Should start with Freedom selected
|
||||||
|
|
Loading…
Reference in a new issue