Enable @typescript-eslint/explicit-function-return-type in /src (#9788)

* Enable `@typescript-eslint/explicit-member-accessibility` on /src

* Prettier

* Enable `@typescript-eslint/explicit-function-return-type` in /src

* Fix types

* tsc strict fixes

* Delint

* Fix test

* Fix bad merge
This commit is contained in:
Michael Telatynski 2023-01-12 13:25:14 +00:00 committed by GitHub
parent 7a36ba0fde
commit 030b7e90bf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
683 changed files with 3459 additions and 3013 deletions

View File

@ -100,8 +100,12 @@ module.exports = {
files: ["src/**/*.{ts,tsx}", "test/**/*.{ts,tsx}", "cypress/**/*.ts"], files: ["src/**/*.{ts,tsx}", "test/**/*.{ts,tsx}", "cypress/**/*.ts"],
extends: ["plugin:matrix-org/typescript", "plugin:matrix-org/react"], extends: ["plugin:matrix-org/typescript", "plugin:matrix-org/react"],
rules: { rules: {
// temporary disabled "@typescript-eslint/explicit-function-return-type": [
"@typescript-eslint/explicit-function-return-type": "off", "error",
{
allowExpressions: true,
},
],
// Things we do that break the ideal style // Things we do that break the ideal style
"prefer-promise-reject-errors": "off", "prefer-promise-reject-errors": "off",

View File

@ -20,10 +20,10 @@ declare module "diff-dom" {
name: string; name: string;
text?: string; text?: string;
route: number[]; route: number[];
value: string; value: HTMLElement | string;
element: unknown; element: HTMLElement | string;
oldValue: string; oldValue: HTMLElement | string;
newValue: string; newValue: HTMLElement | string;
} }
interface IOpts {} interface IOpts {}

View File

@ -15,7 +15,7 @@ limitations under the License.
*/ */
// This is intended to fix re-resizer because of its unguarded `instanceof TouchEvent` checks. // This is intended to fix re-resizer because of its unguarded `instanceof TouchEvent` checks.
export function polyfillTouchEvent() { export function polyfillTouchEvent(): void {
// Firefox doesn't have touch events without touch devices being present, so create a fake // Firefox doesn't have touch events without touch devices being present, so create a fake
// one we can rely on lying about. // one we can rely on lying about.
if (!window.TouchEvent) { if (!window.TouchEvent) {

View File

@ -47,7 +47,7 @@ export default class AsyncWrapper extends React.Component<IProps, IState> {
error: null, error: null,
}; };
public componentDidMount() { public componentDidMount(): void {
// XXX: temporary logging to try to diagnose // XXX: temporary logging to try to diagnose
// https://github.com/vector-im/element-web/issues/3148 // https://github.com/vector-im/element-web/issues/3148
logger.log("Starting load of AsyncWrapper for modal"); logger.log("Starting load of AsyncWrapper for modal");
@ -69,15 +69,15 @@ export default class AsyncWrapper extends React.Component<IProps, IState> {
}); });
} }
public componentWillUnmount() { public componentWillUnmount(): void {
this.unmounted = true; this.unmounted = true;
} }
private onWrapperCancelClick = () => { private onWrapperCancelClick = (): void => {
this.props.onFinished(false); this.props.onFinished(false);
}; };
public render() { public render(): JSX.Element {
if (this.state.component) { if (this.state.component) {
const Component = this.state.component; const Component = this.state.component;
return <Component {...this.props} />; return <Component {...this.props} />;

View File

@ -137,7 +137,12 @@ export function getInitialLetter(name: string): string {
return split(name, "", 1)[0].toUpperCase(); return split(name, "", 1)[0].toUpperCase();
} }
export function avatarUrlForRoom(room: Room, width: number, height: number, resizeMethod?: ResizeMethod) { export function avatarUrlForRoom(
room: Room,
width: number,
height: number,
resizeMethod?: ResizeMethod,
): string | null {
if (!room) return null; // null-guard if (!room) return null; // null-guard
if (room.getMxcAvatarUrl()) { if (room.getMxcAvatarUrl()) {

View File

@ -272,7 +272,7 @@ export default abstract class BasePlatform {
return null; return null;
} }
public setLanguage(preferredLangs: string[]) {} public setLanguage(preferredLangs: string[]): void {}
public setSpellCheckEnabled(enabled: boolean): void {} public setSpellCheckEnabled(enabled: boolean): void {}
@ -280,7 +280,7 @@ export default abstract class BasePlatform {
return null; return null;
} }
public setSpellCheckLanguages(preferredLangs: string[]) {} public setSpellCheckLanguages(preferredLangs: string[]): void {}
public getSpellCheckLanguages(): Promise<string[]> | null { public getSpellCheckLanguages(): Promise<string[]> | null {
return null; return null;

View File

@ -40,7 +40,7 @@ export class BlurhashEncoder {
this.worker.onmessage = this.onMessage; this.worker.onmessage = this.onMessage;
} }
private onMessage = (ev: MessageEvent<IBlurhashWorkerResponse>) => { private onMessage = (ev: MessageEvent<IBlurhashWorkerResponse>): void => {
const { seq, blurhash } = ev.data; const { seq, blurhash } = ev.data;
const deferred = this.pendingDeferredMap.get(seq); const deferred = this.pendingDeferredMap.get(seq);
if (deferred) { if (deferred) {

View File

@ -68,16 +68,20 @@ interface IMediaConfig {
* @param {File} imageFile The file to load in an image element. * @param {File} imageFile The file to load in an image element.
* @return {Promise} A promise that resolves with the html image element. * @return {Promise} A promise that resolves with the html image element.
*/ */
async function loadImageElement(imageFile: File) { async function loadImageElement(imageFile: File): Promise<{
width: number;
height: number;
img: HTMLImageElement;
}> {
// Load the file into an html element // Load the file into an html element
const img = new Image(); const img = new Image();
const objectUrl = URL.createObjectURL(imageFile); const objectUrl = URL.createObjectURL(imageFile);
const imgPromise = new Promise((resolve, reject) => { const imgPromise = new Promise((resolve, reject) => {
img.onload = function () { img.onload = function (): void {
URL.revokeObjectURL(objectUrl); URL.revokeObjectURL(objectUrl);
resolve(img); resolve(img);
}; };
img.onerror = function (e) { img.onerror = function (e): void {
reject(e); reject(e);
}; };
}); });
@ -185,13 +189,13 @@ function loadVideoElement(videoFile: File): Promise<HTMLVideoElement> {
const reader = new FileReader(); const reader = new FileReader();
reader.onload = function (ev) { reader.onload = function (ev): void {
// Wait until we have enough data to thumbnail the first frame. // Wait until we have enough data to thumbnail the first frame.
video.onloadeddata = async function () { video.onloadeddata = async function (): Promise<void> {
resolve(video); resolve(video);
video.pause(); video.pause();
}; };
video.onerror = function (e) { video.onerror = function (e): void {
reject(e); reject(e);
}; };
@ -206,7 +210,7 @@ function loadVideoElement(videoFile: File): Promise<HTMLVideoElement> {
video.load(); video.load();
video.play(); video.play();
}; };
reader.onerror = function (e) { reader.onerror = function (e): void {
reject(e); reject(e);
}; };
reader.readAsDataURL(videoFile); reader.readAsDataURL(videoFile);
@ -253,10 +257,10 @@ function infoForVideoFile(
function readFileAsArrayBuffer(file: File | Blob): Promise<ArrayBuffer> { function readFileAsArrayBuffer(file: File | Blob): Promise<ArrayBuffer> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const reader = new FileReader(); const reader = new FileReader();
reader.onload = function (e) { reader.onload = function (e): void {
resolve(e.target.result as ArrayBuffer); resolve(e.target.result as ArrayBuffer);
}; };
reader.onerror = function (e) { reader.onerror = function (e): void {
reject(e); reject(e);
}; };
reader.readAsArrayBuffer(file); reader.readAsArrayBuffer(file);
@ -461,7 +465,7 @@ export default class ContentMessages {
matrixClient: MatrixClient, matrixClient: MatrixClient,
replyToEvent: MatrixEvent | undefined, replyToEvent: MatrixEvent | undefined,
promBefore?: Promise<any>, promBefore?: Promise<any>,
) { ): Promise<void> {
const fileName = file.name || _t("Attachment"); const fileName = file.name || _t("Attachment");
const content: Omit<IMediaEventContent, "info"> & { info: Partial<IMediaEventInfo> } = { const content: Omit<IMediaEventContent, "info"> & { info: Partial<IMediaEventInfo> } = {
body: fileName, body: fileName,
@ -491,7 +495,7 @@ export default class ContentMessages {
this.inprogress.push(upload); this.inprogress.push(upload);
dis.dispatch<UploadStartedPayload>({ action: Action.UploadStarted, upload }); dis.dispatch<UploadStartedPayload>({ action: Action.UploadStarted, upload });
function onProgress(progress: UploadProgress) { function onProgress(progress: UploadProgress): void {
upload.onProgress(progress); upload.onProgress(progress);
dis.dispatch<UploadProgressPayload>({ action: Action.UploadProgress, upload }); dis.dispatch<UploadProgressPayload>({ action: Action.UploadProgress, upload });
} }
@ -568,7 +572,7 @@ export default class ContentMessages {
} }
} }
private isFileSizeAcceptable(file: File) { private isFileSizeAcceptable(file: File): boolean {
if ( if (
this.mediaConfig !== null && this.mediaConfig !== null &&
this.mediaConfig["m.upload.size"] !== undefined && this.mediaConfig["m.upload.size"] !== undefined &&
@ -599,7 +603,7 @@ export default class ContentMessages {
}); });
} }
public static sharedInstance() { public static sharedInstance(): ContentMessages {
if (window.mxContentMessages === undefined) { if (window.mxContentMessages === undefined) {
window.mxContentMessages = new ContentMessages(); window.mxContentMessages = new ContentMessages();
} }

View File

@ -188,7 +188,7 @@ export function wantsDateSeparator(prevEventDate: Date, nextEventDate: Date): bo
return prevEventDate.getDay() !== nextEventDate.getDay(); return prevEventDate.getDay() !== nextEventDate.getDay();
} }
export function formatFullDateNoDay(date: Date) { export function formatFullDateNoDay(date: Date): string {
return _t("%(date)s at %(time)s", { return _t("%(date)s at %(time)s", {
date: date.toLocaleDateString().replace(/\//g, "-"), date: date.toLocaleDateString().replace(/\//g, "-"),
time: date.toLocaleTimeString().replace(/:/g, "-"), time: date.toLocaleTimeString().replace(/:/g, "-"),
@ -205,7 +205,7 @@ export function formatFullDateNoDayISO(date: Date): string {
return date.toISOString(); return date.toISOString();
} }
export function formatFullDateNoDayNoTime(date: Date) { export function formatFullDateNoDayNoTime(date: Date): string {
return date.getFullYear() + "/" + pad(date.getMonth() + 1) + "/" + pad(date.getDate()); return date.getFullYear() + "/" + pad(date.getMonth() + 1) + "/" + pad(date.getDate());
} }

View File

@ -19,6 +19,7 @@ import { logger } from "matrix-js-sdk/src/logger";
import { CryptoEvent } from "matrix-js-sdk/src/crypto"; import { CryptoEvent } from "matrix-js-sdk/src/crypto";
import { ClientEvent, EventType, RoomStateEvent } from "matrix-js-sdk/src/matrix"; import { ClientEvent, EventType, RoomStateEvent } from "matrix-js-sdk/src/matrix";
import { SyncState } from "matrix-js-sdk/src/sync"; import { SyncState } from "matrix-js-sdk/src/sync";
import { IKeyBackupInfo } from "matrix-js-sdk/src/crypto/keybackup";
import { MatrixClientPeg } from "./MatrixClientPeg"; import { MatrixClientPeg } from "./MatrixClientPeg";
import dis from "./dispatcher/dispatcher"; import dis from "./dispatcher/dispatcher";
@ -56,7 +57,7 @@ export default class DeviceListener {
// has the user dismissed any of the various nag toasts to setup encryption on this device? // has the user dismissed any of the various nag toasts to setup encryption on this device?
private dismissedThisDeviceToast = false; private dismissedThisDeviceToast = false;
// cache of the key backup info // cache of the key backup info
private keyBackupInfo: object = null; private keyBackupInfo: IKeyBackupInfo | null = null;
private keyBackupFetchedAt: number = null; private keyBackupFetchedAt: number = null;
private keyBackupStatusChecked = false; private keyBackupStatusChecked = false;
// We keep a list of our own device IDs so we can batch ones that were already // We keep a list of our own device IDs so we can batch ones that were already
@ -70,12 +71,12 @@ export default class DeviceListener {
private enableBulkUnverifiedSessionsReminder = true; private enableBulkUnverifiedSessionsReminder = true;
private deviceClientInformationSettingWatcherRef: string | undefined; private deviceClientInformationSettingWatcherRef: string | undefined;
public static sharedInstance() { public static sharedInstance(): DeviceListener {
if (!window.mxDeviceListener) window.mxDeviceListener = new DeviceListener(); if (!window.mxDeviceListener) window.mxDeviceListener = new DeviceListener();
return window.mxDeviceListener; return window.mxDeviceListener;
} }
public start() { public start(): void {
this.running = true; this.running = true;
MatrixClientPeg.get().on(CryptoEvent.WillUpdateDevices, this.onWillUpdateDevices); MatrixClientPeg.get().on(CryptoEvent.WillUpdateDevices, this.onWillUpdateDevices);
MatrixClientPeg.get().on(CryptoEvent.DevicesUpdated, this.onDevicesUpdated); MatrixClientPeg.get().on(CryptoEvent.DevicesUpdated, this.onDevicesUpdated);
@ -98,7 +99,7 @@ export default class DeviceListener {
this.updateClientInformation(); this.updateClientInformation();
} }
public stop() { public stop(): void {
this.running = false; this.running = false;
if (MatrixClientPeg.get()) { if (MatrixClientPeg.get()) {
MatrixClientPeg.get().removeListener(CryptoEvent.WillUpdateDevices, this.onWillUpdateDevices); MatrixClientPeg.get().removeListener(CryptoEvent.WillUpdateDevices, this.onWillUpdateDevices);
@ -134,7 +135,7 @@ export default class DeviceListener {
* *
* @param {String[]} deviceIds List of device IDs to dismiss notifications for * @param {String[]} deviceIds List of device IDs to dismiss notifications for
*/ */
public async dismissUnverifiedSessions(deviceIds: Iterable<string>) { public async dismissUnverifiedSessions(deviceIds: Iterable<string>): Promise<void> {
logger.log("Dismissing unverified sessions: " + Array.from(deviceIds).join(",")); logger.log("Dismissing unverified sessions: " + Array.from(deviceIds).join(","));
for (const d of deviceIds) { for (const d of deviceIds) {
this.dismissed.add(d); this.dismissed.add(d);
@ -143,19 +144,19 @@ export default class DeviceListener {
this.recheck(); this.recheck();
} }
public dismissEncryptionSetup() { public dismissEncryptionSetup(): void {
this.dismissedThisDeviceToast = true; this.dismissedThisDeviceToast = true;
this.recheck(); this.recheck();
} }
private ensureDeviceIdsAtStartPopulated() { private ensureDeviceIdsAtStartPopulated(): void {
if (this.ourDeviceIdsAtStart === null) { if (this.ourDeviceIdsAtStart === null) {
const cli = MatrixClientPeg.get(); const cli = MatrixClientPeg.get();
this.ourDeviceIdsAtStart = new Set(cli.getStoredDevicesForUser(cli.getUserId()).map((d) => d.deviceId)); this.ourDeviceIdsAtStart = new Set(cli.getStoredDevicesForUser(cli.getUserId()).map((d) => d.deviceId));
} }
} }
private onWillUpdateDevices = async (users: string[], initialFetch?: boolean) => { private onWillUpdateDevices = async (users: string[], initialFetch?: boolean): Promise<void> => {
// If we didn't know about *any* devices before (ie. it's fresh login), // If we didn't know about *any* devices before (ie. it's fresh login),
// then they are all pre-existing devices, so ignore this and set the // then they are all pre-existing devices, so ignore this and set the
// devicesAtStart list to the devices that we see after the fetch. // devicesAtStart list to the devices that we see after the fetch.
@ -168,26 +169,26 @@ export default class DeviceListener {
// before we download any new ones. // before we download any new ones.
}; };
private onDevicesUpdated = (users: string[]) => { private onDevicesUpdated = (users: string[]): void => {
if (!users.includes(MatrixClientPeg.get().getUserId())) return; if (!users.includes(MatrixClientPeg.get().getUserId())) return;
this.recheck(); this.recheck();
}; };
private onDeviceVerificationChanged = (userId: string) => { private onDeviceVerificationChanged = (userId: string): void => {
if (userId !== MatrixClientPeg.get().getUserId()) return; if (userId !== MatrixClientPeg.get().getUserId()) return;
this.recheck(); this.recheck();
}; };
private onUserTrustStatusChanged = (userId: string) => { private onUserTrustStatusChanged = (userId: string): void => {
if (userId !== MatrixClientPeg.get().getUserId()) return; if (userId !== MatrixClientPeg.get().getUserId()) return;
this.recheck(); this.recheck();
}; };
private onCrossSingingKeysChanged = () => { private onCrossSingingKeysChanged = (): void => {
this.recheck(); this.recheck();
}; };
private onAccountData = (ev: MatrixEvent) => { private onAccountData = (ev: MatrixEvent): void => {
// User may have: // User may have:
// * migrated SSSS to symmetric // * migrated SSSS to symmetric
// * uploaded keys to secret storage // * uploaded keys to secret storage
@ -202,13 +203,13 @@ export default class DeviceListener {
} }
}; };
private onSync = (state: SyncState, prevState?: SyncState) => { private onSync = (state: SyncState, prevState?: SyncState): void => {
if (state === "PREPARED" && prevState === null) { if (state === "PREPARED" && prevState === null) {
this.recheck(); this.recheck();
} }
}; };
private onRoomStateEvents = (ev: MatrixEvent) => { private onRoomStateEvents = (ev: MatrixEvent): void => {
if (ev.getType() !== EventType.RoomEncryption) return; if (ev.getType() !== EventType.RoomEncryption) return;
// If a room changes to encrypted, re-check as it may be our first // If a room changes to encrypted, re-check as it may be our first
@ -216,7 +217,7 @@ export default class DeviceListener {
this.recheck(); this.recheck();
}; };
private onAction = ({ action }: ActionPayload) => { private onAction = ({ action }: ActionPayload): void => {
if (action !== Action.OnLoggedIn) return; if (action !== Action.OnLoggedIn) return;
this.recheck(); this.recheck();
this.updateClientInformation(); this.updateClientInformation();
@ -224,7 +225,7 @@ export default class DeviceListener {
// The server doesn't tell us when key backup is set up, so we poll // The server doesn't tell us when key backup is set up, so we poll
// & cache the result // & cache the result
private async getKeyBackupInfo() { private async getKeyBackupInfo(): Promise<IKeyBackupInfo> {
const now = new Date().getTime(); const now = new Date().getTime();
if (!this.keyBackupInfo || this.keyBackupFetchedAt < now - KEY_BACKUP_POLL_INTERVAL) { if (!this.keyBackupInfo || this.keyBackupFetchedAt < now - KEY_BACKUP_POLL_INTERVAL) {
this.keyBackupInfo = await MatrixClientPeg.get().getKeyBackupVersion(); this.keyBackupInfo = await MatrixClientPeg.get().getKeyBackupVersion();
@ -233,7 +234,7 @@ export default class DeviceListener {
return this.keyBackupInfo; return this.keyBackupInfo;
} }
private shouldShowSetupEncryptionToast() { private shouldShowSetupEncryptionToast(): boolean {
// If we're in the middle of a secret storage operation, we're likely // If we're in the middle of a secret storage operation, we're likely
// modifying the state involved here, so don't add new toasts to setup. // modifying the state involved here, so don't add new toasts to setup.
if (isSecretStorageBeingAccessed()) return false; if (isSecretStorageBeingAccessed()) return false;
@ -242,7 +243,7 @@ export default class DeviceListener {
return cli && cli.getRooms().some((r) => cli.isRoomEncrypted(r.roomId)); return cli && cli.getRooms().some((r) => cli.isRoomEncrypted(r.roomId));
} }
private async recheck() { private async recheck(): Promise<void> {
if (!this.running) return; // we have been stopped if (!this.running) return; // we have been stopped
const cli = MatrixClientPeg.get(); const cli = MatrixClientPeg.get();
@ -359,7 +360,7 @@ export default class DeviceListener {
this.displayingToastsForDeviceIds = newUnverifiedDeviceIds; this.displayingToastsForDeviceIds = newUnverifiedDeviceIds;
} }
private checkKeyBackupStatus = async () => { private checkKeyBackupStatus = async (): Promise<void> => {
if (this.keyBackupStatusChecked) { if (this.keyBackupStatusChecked) {
return; return;
} }
@ -388,7 +389,7 @@ export default class DeviceListener {
} }
}; };
private updateClientInformation = async () => { private updateClientInformation = async (): Promise<void> => {
try { try {
if (this.shouldRecordClientInformation) { if (this.shouldRecordClientInformation) {
await recordClientInformation(MatrixClientPeg.get(), SdkConfig.get(), PlatformPeg.get()); await recordClientInformation(MatrixClientPeg.get(), SdkConfig.get(), PlatformPeg.get());

View File

@ -16,5 +16,6 @@ limitations under the License.
import { TimelineRenderingType } from "./contexts/RoomContext"; import { TimelineRenderingType } from "./contexts/RoomContext";
export const editorRoomKey = (roomId: string, context: TimelineRenderingType) => `mx_edit_room_${roomId}_${context}`; export const editorRoomKey = (roomId: string, context: TimelineRenderingType): string =>
export const editorStateKey = (eventId: string) => `mx_edit_state_${eventId}`; `mx_edit_room_${roomId}_${context}`;
export const editorStateKey = (eventId: string): string => `mx_edit_state_${eventId}`;

View File

@ -449,9 +449,9 @@ export interface IOptsReturnString extends IOpts {
returnString: true; returnString: true;
} }
const emojiToHtmlSpan = (emoji: string) => const emojiToHtmlSpan = (emoji: string): string =>
`<span class='mx_Emoji' title='${unicodeToShortcode(emoji)}'>${emoji}</span>`; `<span class='mx_Emoji' title='${unicodeToShortcode(emoji)}'>${emoji}</span>`;
const emojiToJsxSpan = (emoji: string, key: number) => ( const emojiToJsxSpan = (emoji: string, key: number): JSX.Element => (
<span key={key} className="mx_Emoji" title={unicodeToShortcode(emoji)}> <span key={key} className="mx_Emoji" title={unicodeToShortcode(emoji)}>
{emoji} {emoji}
</span> </span>
@ -505,7 +505,7 @@ function formatEmojis(message: string, isHtmlMessage: boolean): (JSX.Element | s
*/ */
export function bodyToHtml(content: IContent, highlights: Optional<string[]>, opts: IOptsReturnString): string; export function bodyToHtml(content: IContent, highlights: Optional<string[]>, opts: IOptsReturnString): string;
export function bodyToHtml(content: IContent, highlights: Optional<string[]>, opts: IOptsReturnNode): ReactNode; export function bodyToHtml(content: IContent, highlights: Optional<string[]>, opts: IOptsReturnNode): ReactNode;
export function bodyToHtml(content: IContent, highlights: Optional<string[]>, opts: IOpts = {}) { export function bodyToHtml(content: IContent, highlights: Optional<string[]>, opts: IOpts = {}): ReactNode | string {
const isFormattedBody = content.format === "org.matrix.custom.html" && !!content.formatted_body; const isFormattedBody = content.format === "org.matrix.custom.html" && !!content.formatted_body;
let bodyHasEmoji = false; let bodyHasEmoji = false;
let isHtmlMessage = false; let isHtmlMessage = false;

View File

@ -28,7 +28,7 @@ limitations under the License.
* consume in the timeline, when performing scroll offset calculations * consume in the timeline, when performing scroll offset calculations
* (e.g. scroll locking) * (e.g. scroll locking)
*/ */
export function thumbHeight(fullWidth: number, fullHeight: number, thumbWidth: number, thumbHeight: number) { export function thumbHeight(fullWidth: number, fullHeight: number, thumbWidth: number, thumbHeight: number): number {
if (!fullWidth || !fullHeight) { if (!fullWidth || !fullHeight) {
// Cannot calculate thumbnail height for image: missing w/h in metadata. We can't even // Cannot calculate thumbnail height for image: missing w/h in metadata. We can't even
// log this because it's spammy // log this because it's spammy

View File

@ -76,7 +76,7 @@ export const Key = {
export const IS_MAC = navigator.platform.toUpperCase().includes("MAC"); export const IS_MAC = navigator.platform.toUpperCase().includes("MAC");
export function isOnlyCtrlOrCmdKeyEvent(ev) { export function isOnlyCtrlOrCmdKeyEvent(ev: KeyboardEvent): boolean {
if (IS_MAC) { if (IS_MAC) {
return ev.metaKey && !ev.altKey && !ev.ctrlKey && !ev.shiftKey; return ev.metaKey && !ev.altKey && !ev.ctrlKey && !ev.shiftKey;
} else { } else {

View File

@ -169,7 +169,7 @@ export default class LegacyCallHandler extends EventEmitter {
private silencedCalls = new Set<string>(); // callIds private silencedCalls = new Set<string>(); // callIds
public static get instance() { public static get instance(): LegacyCallHandler {
if (!window.mxLegacyCallHandler) { if (!window.mxLegacyCallHandler) {
window.mxLegacyCallHandler = new LegacyCallHandler(); window.mxLegacyCallHandler = new LegacyCallHandler();
} }
@ -456,7 +456,7 @@ export default class LegacyCallHandler extends EventEmitter {
return callsNotInThatRoom; return callsNotInThatRoom;
} }
public getAllActiveCallsForPip(roomId: string) { public getAllActiveCallsForPip(roomId: string): MatrixCall[] {
const room = MatrixClientPeg.get().getRoom(roomId); const room = MatrixClientPeg.get().getRoom(roomId);
if (WidgetLayoutStore.instance.hasMaximisedWidget(room)) { if (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
@ -478,7 +478,7 @@ export default class LegacyCallHandler extends EventEmitter {
const audio = document.getElementById(audioId) as HTMLMediaElement; const audio = document.getElementById(audioId) as HTMLMediaElement;
if (audio) { if (audio) {
this.addEventListenersForAudioElement(audio); this.addEventListenersForAudioElement(audio);
const playAudio = async () => { const playAudio = async (): Promise<void> => {
try { try {
if (audio.muted) { if (audio.muted) {
logger.error( logger.error(
@ -524,7 +524,7 @@ export default class LegacyCallHandler extends EventEmitter {
// TODO: Attach an invisible element for this instead // TODO: Attach an invisible element for this instead
// which listens? // which listens?
const audio = document.getElementById(audioId) as HTMLMediaElement; const audio = document.getElementById(audioId) as HTMLMediaElement;
const pauseAudio = () => { const pauseAudio = (): void => {
logger.debug(`${logPrefix} pausing audio`); logger.debug(`${logPrefix} pausing audio`);
// pause doesn't return a promise, so just do it // pause doesn't return a promise, so just do it
audio.pause(); audio.pause();
@ -600,7 +600,7 @@ export default class LegacyCallHandler extends EventEmitter {
this.setCallListeners(newCall); this.setCallListeners(newCall);
this.setCallState(newCall, newCall.state); this.setCallState(newCall, newCall.state);
}); });
call.on(CallEvent.AssertedIdentityChanged, async () => { call.on(CallEvent.AssertedIdentityChanged, async (): Promise<void> => {
if (!this.matchesCallForThisRoom(call)) return; if (!this.matchesCallForThisRoom(call)) return;
logger.log(`Call ID ${call.callId} got new asserted identity:`, call.getRemoteAssertedIdentity()); logger.log(`Call ID ${call.callId} got new asserted identity:`, call.getRemoteAssertedIdentity());
@ -808,7 +808,7 @@ export default class LegacyCallHandler extends EventEmitter {
private showICEFallbackPrompt(): void { private showICEFallbackPrompt(): void {
const cli = MatrixClientPeg.get(); const cli = MatrixClientPeg.get();
const code = (sub) => <code>{sub}</code>; const code = (sub: string): JSX.Element => <code>{sub}</code>;
Modal.createDialog( Modal.createDialog(
QuestionDialog, QuestionDialog,
{ {

View File

@ -219,7 +219,7 @@ export function attemptTokenLogin(
}) })
.then(function (creds) { .then(function (creds) {
logger.log("Logged in with token"); logger.log("Logged in with token");
return clearStorage().then(async () => { return clearStorage().then(async (): Promise<boolean> => {
await persistCredentials(creds); await persistCredentials(creds);
// remember that we just logged in // remember that we just logged in
sessionStorage.setItem("mx_fresh_login", String(true)); sessionStorage.setItem("mx_fresh_login", String(true));
@ -406,7 +406,7 @@ async function pickleKeyToAesKey(pickleKey: string): Promise<Uint8Array> {
); );
} }
async function abortLogin() { async function abortLogin(): Promise<void> {
const signOut = await showStorageEvictedDialog(); const signOut = await showStorageEvictedDialog();
if (signOut) { if (signOut) {
await clearStorage(); await clearStorage();

View File

@ -20,14 +20,14 @@ import { MatrixClientPeg } from "./MatrixClientPeg";
import SdkConfig from "./SdkConfig"; import SdkConfig from "./SdkConfig";
import { ElementWidgetActions } from "./stores/widgets/ElementWidgetActions"; import { ElementWidgetActions } from "./stores/widgets/ElementWidgetActions";
export function getConfigLivestreamUrl() { export function getConfigLivestreamUrl(): string | undefined {
return SdkConfig.get("audio_stream_url"); return SdkConfig.get("audio_stream_url");
} }
// Dummy rtmp URL used to signal that we want a special audio-only stream // Dummy rtmp URL used to signal that we want a special audio-only stream
const AUDIOSTREAM_DUMMY_URL = "rtmp://audiostream.dummy/"; const AUDIOSTREAM_DUMMY_URL = "rtmp://audiostream.dummy/";
async function createLiveStream(roomId: string) { async function createLiveStream(roomId: string): Promise<void> {
const openIdToken = await MatrixClientPeg.get().getOpenIdToken(); const openIdToken = await MatrixClientPeg.get().getOpenIdToken();
const url = getConfigLivestreamUrl() + "/createStream"; const url = getConfigLivestreamUrl() + "/createStream";
@ -47,7 +47,7 @@ async function createLiveStream(roomId: string) {
return respBody["stream_id"]; return respBody["stream_id"];
} }
export async function startJitsiAudioLivestream(widgetMessaging: ClientWidgetApi, roomId: string) { export async function startJitsiAudioLivestream(widgetMessaging: ClientWidgetApi, roomId: string): Promise<void> {
const streamId = await createLiveStream(roomId); const streamId = await createLiveStream(roomId);
await widgetMessaging.transport.send(ElementWidgetActions.StartLiveStream, { await widgetMessaging.transport.send(ElementWidgetActions.StartLiveStream, {

View File

@ -122,7 +122,7 @@ export default class Login {
initial_device_display_name: this.defaultDeviceDisplayName, initial_device_display_name: this.defaultDeviceDisplayName,
}; };
const tryFallbackHs = (originalError) => { const tryFallbackHs = (originalError: Error): Promise<IMatrixClientCreds> => {
return sendLoginRequest(this.fallbackHsUrl, this.isUrl, "m.login.password", loginParams).catch( return sendLoginRequest(this.fallbackHsUrl, this.isUrl, "m.login.password", loginParams).catch(
(fallbackError) => { (fallbackError) => {
logger.log("fallback HS login failed", fallbackError); logger.log("fallback HS login failed", fallbackError);

View File

@ -56,7 +56,7 @@ function isMultiLine(node: commonmark.Node): boolean {
return par.firstChild != par.lastChild; return par.firstChild != par.lastChild;
} }
function getTextUntilEndOrLinebreak(node: commonmark.Node) { function getTextUntilEndOrLinebreak(node: commonmark.Node): string {
let currentNode = node; let currentNode = node;
let text = ""; let text = "";
while (currentNode !== null && currentNode.type !== "softbreak" && currentNode.type !== "linebreak") { while (currentNode !== null && currentNode.type !== "softbreak" && currentNode.type !== "linebreak") {
@ -137,7 +137,7 @@ export default class Markdown {
* See: https://github.com/vector-im/element-web/issues/4674 * See: https://github.com/vector-im/element-web/issues/4674
* @param parsed * @param parsed
*/ */
private repairLinks(parsed: commonmark.Node) { private repairLinks(parsed: commonmark.Node): commonmark.Node {
const walker = parsed.walker(); const walker = parsed.walker();
let event: commonmark.NodeWalkingStep = null; let event: commonmark.NodeWalkingStep = null;
let text = ""; let text = "";

View File

@ -77,7 +77,7 @@ export class ModalManager extends TypedEventEmitter<ModalManagerEvent, HandlerMa
// Neither the static nor priority modal will be in this list. // Neither the static nor priority modal will be in this list.
private modals: IModal<any>[] = []; private modals: IModal<any>[] = [];
private static getOrCreateContainer() { private static getOrCreateContainer(): HTMLElement {
let container = document.getElementById(DIALOG_CONTAINER_ID); let container = document.getElementById(DIALOG_CONTAINER_ID);
if (!container) { if (!container) {
@ -89,7 +89,7 @@ export class ModalManager extends TypedEventEmitter<ModalManagerEvent, HandlerMa
return container; return container;
} }
private static getOrCreateStaticContainer() { private static getOrCreateStaticContainer(): HTMLElement {
let container = document.getElementById(STATIC_DIALOG_CONTAINER_ID); let container = document.getElementById(STATIC_DIALOG_CONTAINER_ID);
if (!container) { if (!container) {
@ -101,31 +101,31 @@ export class ModalManager extends TypedEventEmitter<ModalManagerEvent, HandlerMa
return container; return container;
} }
public toggleCurrentDialogVisibility() { public toggleCurrentDialogVisibility(): void {
const modal = this.getCurrentModal(); const modal = this.getCurrentModal();
if (!modal) return; if (!modal) return;
modal.hidden = !modal.hidden; modal.hidden = !modal.hidden;
} }
public hasDialogs() { public hasDialogs(): boolean {
return this.priorityModal || this.staticModal || this.modals.length > 0; return !!this.priorityModal || !!this.staticModal || this.modals.length > 0;
} }
public createDialog<T extends any[]>( public createDialog<T extends any[]>(
Element: React.ComponentType<any>, Element: React.ComponentType<any>,
...rest: ParametersWithoutFirst<ModalManager["createDialogAsync"]> ...rest: ParametersWithoutFirst<ModalManager["createDialogAsync"]>
) { ): IHandle<T> {
return this.createDialogAsync<T>(Promise.resolve(Element), ...rest); return this.createDialogAsync<T>(Promise.resolve(Element), ...rest);
} }
public appendDialog<T extends any[]>( public appendDialog<T extends any[]>(
Element: React.ComponentType, Element: React.ComponentType,
...rest: ParametersWithoutFirst<ModalManager["appendDialogAsync"]> ...rest: ParametersWithoutFirst<ModalManager["appendDialogAsync"]>
) { ): IHandle<T> {
return this.appendDialogAsync<T>(Promise.resolve(Element), ...rest); return this.appendDialogAsync<T>(Promise.resolve(Element), ...rest);
} }
public closeCurrentModal(reason: string) { public closeCurrentModal(reason: string): void {
const modal = this.getCurrentModal(); const modal = this.getCurrentModal();
if (!modal) { if (!modal) {
return; return;
@ -139,7 +139,11 @@ export class ModalManager extends TypedEventEmitter<ModalManagerEvent, HandlerMa
props?: IProps<T>, props?: IProps<T>,
className?: string, className?: string,
options?: IOptions<T>, options?: IOptions<T>,
) { ): {
modal: IModal<T>;
closeDialog: IHandle<T>["close"];
onFinishedProm: IHandle<T>["finished"];
} {
const modal: IModal<T> = { const modal: IModal<T> = {
onFinished: props ? props.onFinished : null, onFinished: props ? props.onFinished : null,
onBeforeClose: options.onBeforeClose, onBeforeClose: options.onBeforeClose,
@ -173,7 +177,7 @@ export class ModalManager extends TypedEventEmitter<ModalManagerEvent, HandlerMa
): [IHandle<T>["close"], IHandle<T>["finished"]] { ): [IHandle<T>["close"], IHandle<T>["finished"]] {
const deferred = defer<T>(); const deferred = defer<T>();
return [ return [
async (...args: T) => { async (...args: T): Promise<void> => {
if (modal.beforeClosePromise) { if (modal.beforeClosePromise) {
await modal.beforeClosePromise; await modal.beforeClosePromise;
} else if (modal.onBeforeClose) { } else if (modal.onBeforeClose) {
@ -302,7 +306,7 @@ export class ModalManager extends TypedEventEmitter<ModalManagerEvent, HandlerMa
} }
} }
private onBackgroundClick = () => { private onBackgroundClick = (): void => {
const modal = this.getCurrentModal(); const modal = this.getCurrentModal();
if (!modal) { if (!modal) {
return; return;
@ -320,7 +324,7 @@ export class ModalManager extends TypedEventEmitter<ModalManagerEvent, HandlerMa
return this.priorityModal ? this.priorityModal : this.modals[0] || this.staticModal; return this.priorityModal ? this.priorityModal : this.modals[0] || this.staticModal;
} }
private async reRender() { private async reRender(): Promise<void> {
// await next tick because sometimes ReactDOM can race with itself and cause the modal to wrongly stick around // await next tick because sometimes ReactDOM can race with itself and cause the modal to wrongly stick around
await sleep(0); await sleep(0);

View File

@ -32,13 +32,13 @@ import { PlatformSetPayload } from "./dispatcher/payloads/PlatformSetPayload";
* object. * object.
*/ */
export class PlatformPeg { export class PlatformPeg {
private platform: BasePlatform = null; private platform: BasePlatform | null = null;
/** /**
* Returns the current Platform object for the application. * Returns the current Platform object for the application.
* This should be an instance of a class extending BasePlatform. * This should be an instance of a class extending BasePlatform.
*/ */
public get() { public get(): BasePlatform | null {
return this.platform; return this.platform;
} }
@ -46,7 +46,7 @@ export class PlatformPeg {
* Sets the current platform handler object to use for the application. * Sets the current platform handler object to use for the application.
* @param {BasePlatform} platform an instance of a class extending BasePlatform. * @param {BasePlatform} platform an instance of a class extending BasePlatform.
*/ */
public set(platform: BasePlatform) { public set(platform: BasePlatform): void {
this.platform = platform; this.platform = platform;
defaultDispatcher.dispatch<PlatformSetPayload>({ defaultDispatcher.dispatch<PlatformSetPayload>({
action: Action.PlatformSet, action: Action.PlatformSet,

View File

@ -175,7 +175,7 @@ export class PosthogAnalytics {
this.onLayoutUpdated(); this.onLayoutUpdated();
} }
private onLayoutUpdated = () => { private onLayoutUpdated = (): void => {
let layout: UserProperties["WebLayout"]; let layout: UserProperties["WebLayout"];
switch (SettingsStore.getValue("layout")) { switch (SettingsStore.getValue("layout")) {
@ -195,7 +195,7 @@ export class PosthogAnalytics {
this.setProperty("WebLayout", layout); this.setProperty("WebLayout", layout);
}; };
private onAction = (payload: ActionPayload) => { private onAction = (payload: ActionPayload): void => {
if (payload.action !== Action.SettingUpdated) return; if (payload.action !== Action.SettingUpdated) return;
const settingsPayload = payload as SettingUpdatedPayload; const settingsPayload = payload as SettingUpdatedPayload;
if (["layout", "useCompactLayout"].includes(settingsPayload.settingName)) { if (["layout", "useCompactLayout"].includes(settingsPayload.settingName)) {
@ -232,7 +232,7 @@ export class PosthogAnalytics {
return properties; return properties;
}; };
private registerSuperProperties(properties: Properties) { private registerSuperProperties(properties: Properties): void {
if (this.enabled) { if (this.enabled) {
this.posthog.register(properties); this.posthog.register(properties);
} }
@ -255,7 +255,7 @@ export class PosthogAnalytics {
} }
// eslint-disable-nextline no-unused-varsx // eslint-disable-nextline no-unused-varsx
private capture(eventName: string, properties: Properties, options?: IPostHogEventOptions) { private capture(eventName: string, properties: Properties, options?: IPostHogEventOptions): void {
if (!this.enabled) { if (!this.enabled) {
return; return;
} }

View File

@ -107,20 +107,20 @@ export default class PosthogTrackers {
} }
export class PosthogScreenTracker extends PureComponent<{ screenName: ScreenName }> { export class PosthogScreenTracker extends PureComponent<{ screenName: ScreenName }> {
public componentDidMount() { public componentDidMount(): void {
PosthogTrackers.instance.trackOverride(this.props.screenName); PosthogTrackers.instance.trackOverride(this.props.screenName);
} }
public componentDidUpdate() { public componentDidUpdate(): void {
// We do not clear the old override here so that we do not send the non-override screen as a transition // We do not clear the old override here so that we do not send the non-override screen as a transition
PosthogTrackers.instance.trackOverride(this.props.screenName); PosthogTrackers.instance.trackOverride(this.props.screenName);
} }
public componentWillUnmount() { public componentWillUnmount(): void {
PosthogTrackers.instance.clearOverride(this.props.screenName); PosthogTrackers.instance.clearOverride(this.props.screenName);
} }
public render() { public render(): JSX.Element {
return null; // no need to render anything, we just need to hook into the React lifecycle return null; // no need to render anything, we just need to hook into the React lifecycle
} }
} }

View File

@ -41,7 +41,7 @@ class Presence {
* Start listening the user activity to evaluate his presence state. * Start listening the user activity to evaluate his presence state.
* Any state change will be sent to the homeserver. * Any state change will be sent to the homeserver.
*/ */
public async start() { public async start(): Promise<void> {
this.unavailableTimer = new Timer(UNAVAILABLE_TIME_MS); this.unavailableTimer = new Timer(UNAVAILABLE_TIME_MS);
// the user_activity_start action starts the timer // the user_activity_start action starts the timer
this.dispatcherRef = dis.register(this.onAction); this.dispatcherRef = dis.register(this.onAction);
@ -58,7 +58,7 @@ class Presence {
/** /**
* Stop tracking user activity * Stop tracking user activity
*/ */
public stop() { public stop(): void {
if (this.dispatcherRef) { if (this.dispatcherRef) {
dis.unregister(this.dispatcherRef); dis.unregister(this.dispatcherRef);
this.dispatcherRef = null; this.dispatcherRef = null;
@ -73,11 +73,11 @@ class Presence {
* Get the current presence state. * Get the current presence state.
* @returns {string} the presence state (see PRESENCE enum) * @returns {string} the presence state (see PRESENCE enum)
*/ */
public getState() { public getState(): State {
return this.state; return this.state;
} }
private onAction = (payload: ActionPayload) => { private onAction = (payload: ActionPayload): void => {
if (payload.action === "user_activity") { if (payload.action === "user_activity") {
this.setState(State.Online); this.setState(State.Online);
this.unavailableTimer.restart(); this.unavailableTimer.restart();
@ -89,7 +89,7 @@ class Presence {
* If the state has changed, the homeserver will be notified. * If the state has changed, the homeserver will be notified.
* @param {string} newState the new presence state (see PRESENCE enum) * @param {string} newState the new presence state (see PRESENCE enum)
*/ */
private async setState(newState: State) { private async setState(newState: State): Promise<void> {
if (newState === this.state) { if (newState === this.state) {
return; return;
} }

View File

@ -49,7 +49,7 @@ export default class ScalarAuthClient {
this.isDefaultManager = apiUrl === configApiUrl && configUiUrl === uiUrl; this.isDefaultManager = apiUrl === configApiUrl && configUiUrl === uiUrl;
} }
private writeTokenToStore() { private writeTokenToStore(): void {
window.localStorage.setItem("mx_scalar_token_at_" + this.apiUrl, this.scalarToken); window.localStorage.setItem("mx_scalar_token_at_" + this.apiUrl, this.scalarToken);
if (this.isDefaultManager) { if (this.isDefaultManager) {
// We remove the old token from storage to migrate upwards. This is safe // We remove the old token from storage to migrate upwards. This is safe
@ -72,7 +72,7 @@ export default class ScalarAuthClient {
return this.readTokenFromStore(); return this.readTokenFromStore();
} }
public setTermsInteractionCallback(callback) { public setTermsInteractionCallback(callback: TermsInteractionCallback): void {
this.termsInteractionCallback = callback; this.termsInteractionCallback = callback;
} }

View File

@ -711,7 +711,7 @@ function returnStateEvent(event: MessageEvent<any>, roomId: string, eventType: s
sendResponse(event, stateEvent.getContent()); sendResponse(event, stateEvent.getContent());
} }
async function getOpenIdToken(event: MessageEvent<any>) { async function getOpenIdToken(event: MessageEvent<any>): Promise<void> {
try { try {
const tokenObject = await MatrixClientPeg.get().getOpenIdToken(); const tokenObject = await MatrixClientPeg.get().getOpenIdToken();
sendResponse(event, tokenObject); sendResponse(event, tokenObject);
@ -728,7 +728,7 @@ async function sendEvent(
content?: IContent; content?: IContent;
}>, }>,
roomId: string, roomId: string,
) { ): Promise<void> {
const eventType = event.data.type; const eventType = event.data.type;
const stateKey = event.data.state_key; const stateKey = event.data.state_key;
const content = event.data.content; const content = event.data.content;
@ -786,7 +786,7 @@ async function readEvents(
limit?: number; limit?: number;
}>, }>,
roomId: string, roomId: string,
) { ): Promise<void> {
const eventType = event.data.type; const eventType = event.data.type;
const stateKey = event.data.state_key; const stateKey = event.data.state_key;
const limit = event.data.limit; const limit = event.data.limit;

View File

@ -56,7 +56,7 @@ export default class SdkConfig {
private static instance: IConfigOptions; private static instance: IConfigOptions;
private static fallback: SnakedObject<IConfigOptions>; private static fallback: SnakedObject<IConfigOptions>;
private static setInstance(i: IConfigOptions) { private static setInstance(i: IConfigOptions): void {
SdkConfig.instance = i; SdkConfig.instance = i;
SdkConfig.fallback = new SnakedObject(i); SdkConfig.fallback = new SnakedObject(i);
@ -90,18 +90,18 @@ export default class SdkConfig {
return val === undefined ? undefined : null; return val === undefined ? undefined : null;
} }
public static put(cfg: Partial<IConfigOptions>) { public static put(cfg: Partial<IConfigOptions>): void {
SdkConfig.setInstance({ ...DEFAULTS, ...cfg }); SdkConfig.setInstance({ ...DEFAULTS, ...cfg });
} }
/** /**
* Resets the config to be completely empty. * Resets the config to be completely empty.
*/ */
public static unset() { public static unset(): void {
SdkConfig.setInstance(<IConfigOptions>{}); // safe to cast - defaults will be applied SdkConfig.setInstance(<IConfigOptions>{}); // safe to cast - defaults will be applied
} }
public static add(cfg: Partial<IConfigOptions>) { public static add(cfg: Partial<IConfigOptions>): void {
SdkConfig.put({ ...SdkConfig.get(), ...cfg }); SdkConfig.put({ ...SdkConfig.get(), ...cfg });
} }
} }

View File

@ -86,7 +86,7 @@ async function confirmToDismiss(): Promise<boolean> {
type KeyParams = { passphrase: string; recoveryKey: string }; type KeyParams = { passphrase: string; recoveryKey: string };
function makeInputToKey(keyInfo: ISecretStorageKeyInfo): (keyParams: KeyParams) => Promise<Uint8Array> { function makeInputToKey(keyInfo: ISecretStorageKeyInfo): (keyParams: KeyParams) => Promise<Uint8Array> {
return async ({ passphrase, recoveryKey }) => { return async ({ passphrase, recoveryKey }): Promise<Uint8Array> => {
if (passphrase) { if (passphrase) {
return deriveKey(passphrase, keyInfo.passphrase.salt, keyInfo.passphrase.iterations); return deriveKey(passphrase, keyInfo.passphrase.salt, keyInfo.passphrase.iterations);
} else { } else {
@ -151,7 +151,7 @@ async function getSecretStorageKey({
/* props= */ /* props= */
{ {
keyInfo, keyInfo,
checkPrivateKey: async (input: KeyParams) => { checkPrivateKey: async (input: KeyParams): Promise<boolean> => {
const key = await inputToKey(input); const key = await inputToKey(input);
return MatrixClientPeg.get().checkSecretStorageKey(key, keyInfo); return MatrixClientPeg.get().checkSecretStorageKey(key, keyInfo);
}, },
@ -160,7 +160,7 @@ async function getSecretStorageKey({
/* isPriorityModal= */ false, /* isPriorityModal= */ false,
/* isStaticModal= */ false, /* isStaticModal= */ false,
/* options= */ { /* options= */ {
onBeforeClose: async (reason) => { onBeforeClose: async (reason): Promise<boolean> => {
if (reason === "backgroundClick") { if (reason === "backgroundClick") {
return confirmToDismiss(); return confirmToDismiss();
} }
@ -196,7 +196,7 @@ export async function getDehydrationKey(
/* props= */ /* props= */
{ {
keyInfo, keyInfo,
checkPrivateKey: async (input) => { checkPrivateKey: async (input): Promise<boolean> => {
const key = await inputToKey(input); const key = await inputToKey(input);
try { try {
checkFunc(key); checkFunc(key);
@ -210,7 +210,7 @@ export async function getDehydrationKey(
/* isPriorityModal= */ false, /* isPriorityModal= */ false,
/* isStaticModal= */ false, /* isStaticModal= */ false,
/* options= */ { /* options= */ {
onBeforeClose: async (reason) => { onBeforeClose: async (reason): Promise<boolean> => {
if (reason === "backgroundClick") { if (reason === "backgroundClick") {
return confirmToDismiss(); return confirmToDismiss();
} }
@ -324,7 +324,7 @@ export async function promptForBackupPassphrase(): Promise<Uint8Array> {
* bootstrapped. Optional. * bootstrapped. Optional.
* @param {bool} [forceReset] Reset secret storage even if it's already set up * @param {bool} [forceReset] Reset secret storage even if it's already set up
*/ */
export async function accessSecretStorage(func = async () => {}, forceReset = false) { export async function accessSecretStorage(func = async (): Promise<void> => {}, forceReset = false): Promise<void> {
const cli = MatrixClientPeg.get(); const cli = MatrixClientPeg.get();
secretStorageBeingAccessed = true; secretStorageBeingAccessed = true;
try { try {
@ -342,7 +342,7 @@ export async function accessSecretStorage(func = async () => {}, forceReset = fa
/* priority = */ false, /* priority = */ false,
/* static = */ true, /* static = */ true,
/* options = */ { /* options = */ {
onBeforeClose: async (reason) => { onBeforeClose: async (reason): Promise<boolean> => {
// If Secure Backup is required, you cannot leave the modal. // If Secure Backup is required, you cannot leave the modal.
if (reason === "backgroundClick") { if (reason === "backgroundClick") {
return !isSecureBackupRequired(); return !isSecureBackupRequired();
@ -357,7 +357,7 @@ export async function accessSecretStorage(func = async () => {}, forceReset = fa
} }
} else { } else {
await cli.bootstrapCrossSigning({ await cli.bootstrapCrossSigning({
authUploadDeviceSigningKeys: async (makeRequest) => { authUploadDeviceSigningKeys: async (makeRequest): Promise<void> => {
const { finished } = Modal.createDialog(InteractiveAuthDialog, { const { finished } = Modal.createDialog(InteractiveAuthDialog, {
title: _t("Setting up keys"), title: _t("Setting up keys"),
matrixClient: cli, matrixClient: cli,

View File

@ -60,7 +60,7 @@ export default class SendHistoryManager {
}; };
} }
public save(editorModel: EditorModel, replyEvent?: MatrixEvent) { public save(editorModel: EditorModel, replyEvent?: MatrixEvent): void {
const item = SendHistoryManager.createItem(editorModel, replyEvent); const item = SendHistoryManager.createItem(editorModel, replyEvent);
this.history.push(item); this.history.push(item);
this.currentIndex = this.history.length; this.currentIndex = this.history.length;

View File

@ -85,7 +85,7 @@ const singleMxcUpload = async (): Promise<string | null> => {
Modal.createDialog(UploadConfirmDialog, { Modal.createDialog(UploadConfirmDialog, {
file, file,
onFinished: async (shouldContinue) => { onFinished: async (shouldContinue): Promise<void> => {
if (shouldContinue) { if (shouldContinue) {
const { content_uri: uri } = await MatrixClientPeg.get().uploadContent(file); const { content_uri: uri } = await MatrixClientPeg.get().uploadContent(file);
resolve(uri); resolve(uri);
@ -151,11 +151,11 @@ export class Command {
this.analyticsName = opts.analyticsName; this.analyticsName = opts.analyticsName;
} }
public getCommand() { public getCommand(): string {
return `/${this.command}`; return `/${this.command}`;
} }
public getCommandWithArgs() { public getCommandWithArgs(): string {
return this.getCommand() + " " + this.args; return this.getCommand() + " " + this.args;
} }
@ -184,7 +184,7 @@ export class Command {
return this.runFn(roomId, args); return this.runFn(roomId, args);
} }
public getUsage() { public getUsage(): string {
return _t("Usage") + ": " + this.getCommandWithArgs(); return _t("Usage") + ": " + this.getCommandWithArgs();
} }
@ -193,15 +193,15 @@ export class Command {
} }
} }
function reject(error) { function reject(error?: any): RunResult {
return { error }; return { error };
} }
function success(promise?: Promise<any>) { function success(promise?: Promise<any>): RunResult {
return { promise }; return { promise };
} }
function successSync(value: any) { function successSync(value: any): RunResult {
return success(Promise.resolve(value)); return success(Promise.resolve(value));
} }
@ -319,7 +319,7 @@ export const Commands = [
); );
return success( return success(
finished.then(async ([resp]) => { finished.then(async ([resp]): Promise<void> => {
if (!resp?.continue) return; if (!resp?.continue) return;
await upgradeRoom(room, args, resp.invite); await upgradeRoom(room, args, resp.invite);
}), }),
@ -338,7 +338,7 @@ export const Commands = [
runFn: function (roomId, args) { runFn: function (roomId, args) {
if (args) { if (args) {
return success( return success(
(async () => { (async (): Promise<void> => {
const unixTimestamp = Date.parse(args); const unixTimestamp = Date.parse(args);
if (!unixTimestamp) { if (!unixTimestamp) {
throw newTranslatableError( throw newTranslatableError(
@ -501,7 +501,9 @@ export const Commands = [
? ContentHelpers.parseTopicContent(content) ? ContentHelpers.parseTopicContent(content)
: { text: _t("This room has no topic.") }; : { text: _t("This room has no topic.") };
const ref = (e) => e && linkifyElement(e); const ref = (e): void => {
if (e) linkifyElement(e);
};
const body = topicToHtml(topic.text, topic.html, ref, true); const body = topicToHtml(topic.text, topic.html, ref, true);
Modal.createDialog(InfoDialog, { Modal.createDialog(InfoDialog, {
@ -1028,7 +1030,7 @@ export const Commands = [
const fingerprint = matches[3]; const fingerprint = matches[3];
return success( return success(
(async () => { (async (): Promise<void> => {
const device = cli.getStoredDevice(userId, deviceId); const device = cli.getStoredDevice(userId, deviceId);
if (!device) { if (!device) {
throw newTranslatableError("Unknown (user, session) pair: (%(userId)s, %(deviceId)s)", { throw newTranslatableError("Unknown (user, session) pair: (%(userId)s, %(deviceId)s)", {
@ -1205,7 +1207,7 @@ export const Commands = [
}, },
runFn: (roomId) => { runFn: (roomId) => {
return success( return success(
(async () => { (async (): Promise<void> => {
const room = await VoipUserMapper.sharedInstance().getVirtualRoomForRoom(roomId); const room = await VoipUserMapper.sharedInstance().getVirtualRoomForRoom(roomId);
if (!room) throw newTranslatableError("No virtual room for this room"); if (!room) throw newTranslatableError("No virtual room for this room");
dis.dispatch<ViewRoomPayload>({ dis.dispatch<ViewRoomPayload>({
@ -1231,7 +1233,7 @@ export const Commands = [
} }
return success( return success(
(async () => { (async (): Promise<void> => {
if (isPhoneNumber) { if (isPhoneNumber) {
const results = await LegacyCallHandler.instance.pstnLookup(userId); const results = await LegacyCallHandler.instance.pstnLookup(userId);
if (!results || results.length === 0 || !results[0].userid) { if (!results || results.length === 0 || !results[0].userid) {
@ -1265,7 +1267,7 @@ export const Commands = [
const [userId, msg] = matches.slice(1); const [userId, msg] = matches.slice(1);
if (userId && userId.startsWith("@") && userId.includes(":")) { if (userId && userId.startsWith("@") && userId.includes(":")) {
return success( return success(
(async () => { (async (): Promise<void> => {
const cli = MatrixClientPeg.get(); const cli = MatrixClientPeg.get();
const roomId = await ensureDMExists(cli, userId); const roomId = await ensureDMExists(cli, userId);
dis.dispatch<ViewRoomPayload>({ dis.dispatch<ViewRoomPayload>({

View File

@ -302,7 +302,7 @@ export class SlidingSyncManager {
* @param batchSize The number of rooms to return in each request. * @param batchSize The number of rooms to return in each request.
* @param gapBetweenRequestsMs The number of milliseconds to wait between requests. * @param gapBetweenRequestsMs The number of milliseconds to wait between requests.
*/ */
public async startSpidering(batchSize: number, gapBetweenRequestsMs: number) { public async startSpidering(batchSize: number, gapBetweenRequestsMs: number): Promise<void> {
await sleep(gapBetweenRequestsMs); // wait a bit as this is called on first render so let's let things load await sleep(gapBetweenRequestsMs); // wait a bit as this is called on first render so let's let things load
const listIndex = this.getOrAllocateListIndex(SlidingSyncManager.ListSearch); const listIndex = this.getOrAllocateListIndex(SlidingSyncManager.ListSearch);
let startIndex = batchSize; let startIndex = batchSize;

View File

@ -75,7 +75,7 @@ export type TermsInteractionCallback = (
export async function startTermsFlow( export async function startTermsFlow(
services: Service[], services: Service[],
interactionCallback: TermsInteractionCallback = dialogTermsInteractionCallback, interactionCallback: TermsInteractionCallback = dialogTermsInteractionCallback,
) { ): Promise<void> {
const termsPromises = services.map((s) => MatrixClientPeg.get().getTerms(s.serviceType, s.baseUrl)); const termsPromises = services.map((s) => MatrixClientPeg.get().getTerms(s.serviceType, s.baseUrl));
/* /*
@ -176,7 +176,7 @@ export async function startTermsFlow(
urlsForService, urlsForService,
); );
}); });
return Promise.all(agreePromises); await Promise.all(agreePromises);
} }
export async function dialogTermsInteractionCallback( export async function dialogTermsInteractionCallback(

View File

@ -228,7 +228,7 @@ function textForTombstoneEvent(ev: MatrixEvent): () => string | null {
return () => _t("%(senderDisplayName)s upgraded this room.", { senderDisplayName }); return () => _t("%(senderDisplayName)s upgraded this room.", { senderDisplayName });
} }
const onViewJoinRuleSettingsClick = () => { const onViewJoinRuleSettingsClick = (): void => {
defaultDispatcher.dispatch({ defaultDispatcher.dispatch({
action: "open_room_settings", action: "open_room_settings",
initial_tab_id: ROOM_SECURITY_TAB, initial_tab_id: ROOM_SECURITY_TAB,

View File

@ -50,7 +50,7 @@ export default class UserActivity {
this.activeRecentlyTimeout = new Timer(RECENTLY_ACTIVE_THRESHOLD_MS); this.activeRecentlyTimeout = new Timer(RECENTLY_ACTIVE_THRESHOLD_MS);
} }
public static sharedInstance() { public static sharedInstance(): UserActivity {
if (window.mxUserActivity === undefined) { if (window.mxUserActivity === undefined) {
window.mxUserActivity = new UserActivity(window, document); window.mxUserActivity = new UserActivity(window, document);
} }
@ -66,7 +66,7 @@ export default class UserActivity {
* later on when the user does become active. * later on when the user does become active.
* @param {Timer} timer the timer to use * @param {Timer} timer the timer to use
*/ */
public timeWhileActiveNow(timer: Timer) { public timeWhileActiveNow(timer: Timer): void {
this.timeWhile(timer, this.attachedActiveNowTimers); this.timeWhile(timer, this.attachedActiveNowTimers);
if (this.userActiveNow()) { if (this.userActiveNow()) {
timer.start(); timer.start();
@ -82,14 +82,14 @@ export default class UserActivity {
* later on when the user does become active. * later on when the user does become active.
* @param {Timer} timer the timer to use * @param {Timer} timer the timer to use
*/ */
public timeWhileActiveRecently(timer: Timer) { public timeWhileActiveRecently(timer: Timer): void {
this.timeWhile(timer, this.attachedActiveRecentlyTimers); this.timeWhile(timer, this.attachedActiveRecentlyTimers);
if (this.userActiveRecently()) { if (this.userActiveRecently()) {
timer.start(); timer.start();
} }
} }
private timeWhile(timer: Timer, attachedTimers: Timer[]) { private timeWhile(timer: Timer, attachedTimers: Timer[]): void {
// important this happens first // important this happens first
const index = attachedTimers.indexOf(timer); const index = attachedTimers.indexOf(timer);
if (index === -1) { if (index === -1) {
@ -113,7 +113,7 @@ export default class UserActivity {
/** /**
* Start listening to user activity * Start listening to user activity
*/ */
public start() { public start(): void {
this.document.addEventListener("mousedown", this.onUserActivity); this.document.addEventListener("mousedown", this.onUserActivity);
this.document.addEventListener("mousemove", this.onUserActivity); this.document.addEventListener("mousemove", this.onUserActivity);
this.document.addEventListener("keydown", this.onUserActivity); this.document.addEventListener("keydown", this.onUserActivity);
@ -133,7 +133,7 @@ export default class UserActivity {
/** /**
* Stop tracking user activity * Stop tracking user activity
*/ */
public stop() { public stop(): void {
this.document.removeEventListener("mousedown", this.onUserActivity); this.document.removeEventListener("mousedown", this.onUserActivity);
this.document.removeEventListener("mousemove", this.onUserActivity); this.document.removeEventListener("mousemove", this.onUserActivity);
this.document.removeEventListener("keydown", this.onUserActivity); this.document.removeEventListener("keydown", this.onUserActivity);
@ -152,7 +152,7 @@ export default class UserActivity {
* user's attention at any given moment. * user's attention at any given moment.
* @returns {boolean} true if user is currently 'active' * @returns {boolean} true if user is currently 'active'
*/ */
public userActiveNow() { public userActiveNow(): boolean {
return this.activeNowTimeout.isRunning(); return this.activeNowTimeout.isRunning();
} }
@ -164,11 +164,11 @@ export default class UserActivity {
* (or they may have gone to make tea and left the window focused). * (or they may have gone to make tea and left the window focused).
* @returns {boolean} true if user has been active recently * @returns {boolean} true if user has been active recently
*/ */
public userActiveRecently() { public userActiveRecently(): boolean {
return this.activeRecentlyTimeout.isRunning(); return this.activeRecentlyTimeout.isRunning();
} }
private onPageVisibilityChanged = (e) => { private onPageVisibilityChanged = (e): void => {
if (this.document.visibilityState === "hidden") { if (this.document.visibilityState === "hidden") {
this.activeNowTimeout.abort(); this.activeNowTimeout.abort();
this.activeRecentlyTimeout.abort(); this.activeRecentlyTimeout.abort();
@ -177,12 +177,12 @@ export default class UserActivity {
} }
}; };
private onWindowBlurred = () => { private onWindowBlurred = (): void => {
this.activeNowTimeout.abort(); this.activeNowTimeout.abort();
this.activeRecentlyTimeout.abort(); this.activeRecentlyTimeout.abort();
}; };
private onUserActivity = (event: MouseEvent) => { private onUserActivity = (event: MouseEvent): void => {
// ignore anything if the window isn't focused // ignore anything if the window isn't focused
if (!this.document.hasFocus()) return; if (!this.document.hasFocus()) return;
@ -214,7 +214,7 @@ export default class UserActivity {
} }
}; };
private static async runTimersUntilTimeout(attachedTimers: Timer[], timeout: Timer) { private static async runTimersUntilTimeout(attachedTimers: Timer[], timeout: Timer): Promise<void> {
attachedTimers.forEach((t) => t.start()); attachedTimers.forEach((t) => t.start());
try { try {
await timeout.finished(); await timeout.finished();

View File

@ -87,7 +87,7 @@ interface IAction {
}; };
} }
export const reducer = (state: IState, action: IAction) => { export const reducer: Reducer<IState, IAction> = (state: IState, action: IAction) => {
switch (action.type) { switch (action.type) {
case Type.Register: { case Type.Register: {
if (!state.activeRef) { if (!state.activeRef) {

View File

@ -26,7 +26,7 @@ interface IProps extends Omit<React.HTMLProps<HTMLDivElement>, "onKeyDown"> {}
// https://www.w3.org/TR/wai-aria-practices-1.1/#toolbar // https://www.w3.org/TR/wai-aria-practices-1.1/#toolbar
// All buttons passed in children must use RovingTabIndex to set `onFocus`, `isActive`, `ref` // All buttons passed in children must use RovingTabIndex to set `onFocus`, `isActive`, `ref`
const Toolbar: React.FC<IProps> = ({ children, ...props }) => { const Toolbar: React.FC<IProps> = ({ children, ...props }) => {
const onKeyDown = (ev: React.KeyboardEvent) => { const onKeyDown = (ev: React.KeyboardEvent): void => {
const target = ev.target as HTMLElement; const target = ev.target as HTMLElement;
// Don't interfere with input default keydown behaviour // Don't interfere with input default keydown behaviour
if (target.tagName === "INPUT") return; if (target.tagName === "INPUT") return;

View File

@ -33,7 +33,7 @@ interface IProps extends React.ComponentProps<typeof StyledCheckbox> {
export const StyledMenuItemCheckbox: React.FC<IProps> = ({ children, label, onChange, onClose, ...props }) => { export const StyledMenuItemCheckbox: React.FC<IProps> = ({ children, label, onChange, onClose, ...props }) => {
const [onFocus, isActive, ref] = useRovingTabIndex<HTMLInputElement>(); const [onFocus, isActive, ref] = useRovingTabIndex<HTMLInputElement>();
const onKeyDown = (e: React.KeyboardEvent) => { const onKeyDown = (e: React.KeyboardEvent): void => {
let handled = true; let handled = true;
const action = getKeyBindingsManager().getAccessibilityAction(e); const action = getKeyBindingsManager().getAccessibilityAction(e);
@ -55,7 +55,7 @@ export const StyledMenuItemCheckbox: React.FC<IProps> = ({ children, label, onCh
e.preventDefault(); e.preventDefault();
} }
}; };
const onKeyUp = (e: React.KeyboardEvent) => { const onKeyUp = (e: React.KeyboardEvent): void => {
const action = getKeyBindingsManager().getAccessibilityAction(e); const action = getKeyBindingsManager().getAccessibilityAction(e);
switch (action) { switch (action) {
case KeyBindingAction.Space: case KeyBindingAction.Space:

View File

@ -33,7 +33,7 @@ interface IProps extends React.ComponentProps<typeof StyledRadioButton> {
export const StyledMenuItemRadio: React.FC<IProps> = ({ children, label, onChange, onClose, ...props }) => { export const StyledMenuItemRadio: React.FC<IProps> = ({ children, label, onChange, onClose, ...props }) => {
const [onFocus, isActive, ref] = useRovingTabIndex<HTMLInputElement>(); const [onFocus, isActive, ref] = useRovingTabIndex<HTMLInputElement>();
const onKeyDown = (e: React.KeyboardEvent) => { const onKeyDown = (e: React.KeyboardEvent): void => {
let handled = true; let handled = true;
const action = getKeyBindingsManager().getAccessibilityAction(e); const action = getKeyBindingsManager().getAccessibilityAction(e);
@ -55,7 +55,7 @@ export const StyledMenuItemRadio: React.FC<IProps> = ({ children, label, onChang
e.preventDefault(); e.preventDefault();
} }
}; };
const onKeyUp = (e: React.KeyboardEvent) => { const onKeyUp = (e: React.KeyboardEvent): void => {
const action = getKeyBindingsManager().getAccessibilityAction(e); const action = getKeyBindingsManager().getAccessibilityAction(e);
switch (action) { switch (action) {
case KeyBindingAction.Enter: case KeyBindingAction.Enter:

View File

@ -15,7 +15,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
import { AsyncActionPayload } from "../dispatcher/payloads"; import { AsyncActionFn, AsyncActionPayload } from "../dispatcher/payloads";
/** /**
* Create an action thunk that will dispatch actions indicating the current * Create an action thunk that will dispatch actions indicating the current
@ -45,7 +45,7 @@ import { AsyncActionPayload } from "../dispatcher/payloads";
* `fn`. * `fn`.
*/ */
export function asyncAction(id: string, fn: () => Promise<any>, pendingFn: () => any | null): AsyncActionPayload { export function asyncAction(id: string, fn: () => Promise<any>, pendingFn: () => any | null): AsyncActionPayload {
const helper = (dispatch) => { const helper: AsyncActionFn = (dispatch) => {
dispatch({ dispatch({
action: id + ".pending", action: id + ".pending",
request: typeof pendingFn === "function" ? pendingFn() : undefined, request: typeof pendingFn === "function" ? pendingFn() : undefined,

View File

@ -22,7 +22,7 @@ import defaultDispatcher from "../../dispatcher/dispatcher";
* Redirect to the correct device manager section * Redirect to the correct device manager section
* Based on the labs setting * Based on the labs setting
*/ */
export const viewUserDeviceSettings = (isNewDeviceManagerEnabled: boolean) => { export const viewUserDeviceSettings = (isNewDeviceManagerEnabled: boolean): void => {
defaultDispatcher.dispatch({ defaultDispatcher.dispatch({
action: Action.ViewUserSettings, action: Action.ViewUserSettings,
initialTabId: isNewDeviceManagerEnabled ? UserTab.SessionManager : UserTab.Security, initialTabId: isNewDeviceManagerEnabled ? UserTab.SessionManager : UserTab.Security,

View File

@ -56,7 +56,7 @@ export default class ManageEventIndexDialog extends React.Component<IProps, ISta
}; };
} }
public updateCurrentRoom = async (room) => { public updateCurrentRoom = async (room): Promise<void> => {
const eventIndex = EventIndexPeg.get(); const eventIndex = EventIndexPeg.get();
let stats; let stats;
@ -131,17 +131,17 @@ export default class ManageEventIndexDialog extends React.Component<IProps, ISta
}); });
} }
private onDisable = async () => { private onDisable = async (): Promise<void> => {
const DisableEventIndexDialog = (await import("./DisableEventIndexDialog")).default; const DisableEventIndexDialog = (await import("./DisableEventIndexDialog")).default;
Modal.createDialog(DisableEventIndexDialog, null, null, /* priority = */ false, /* static = */ true); Modal.createDialog(DisableEventIndexDialog, null, null, /* priority = */ false, /* static = */ true);
}; };
private onCrawlerSleepTimeChange = (e) => { private onCrawlerSleepTimeChange = (e): void => {
this.setState({ crawlerSleepTime: e.target.value }); this.setState({ crawlerSleepTime: e.target.value });
SettingsStore.setValue("crawlerSleepTime", null, SettingLevel.DEVICE, e.target.value); SettingsStore.setValue("crawlerSleepTime", null, SettingLevel.DEVICE, e.target.value);
}; };
public render() { public render(): JSX.Element {
const brand = SdkConfig.get().brand; const brand = SdkConfig.get().brand;
let crawlerState; let crawlerState;

View File

@ -125,7 +125,7 @@ export default class CreateKeyBackupDialog extends React.PureComponent<IProps, I
let info; let info;
try { try {
if (secureSecretStorage) { if (secureSecretStorage) {
await accessSecretStorage(async () => { await accessSecretStorage(async (): Promise<void> => {
info = await MatrixClientPeg.get().prepareKeyBackupVersion(null /* random key */, { info = await MatrixClientPeg.get().prepareKeyBackupVersion(null /* random key */, {
secureSecretStorage: true, secureSecretStorage: true,
}); });

View File

@ -350,7 +350,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
createSecretStorageKey: async () => this.recoveryKey, createSecretStorageKey: async () => this.recoveryKey,
keyBackupInfo: this.state.backupInfo, keyBackupInfo: this.state.backupInfo,
setupNewKeyBackup: !this.state.backupInfo, setupNewKeyBackup: !this.state.backupInfo,
getKeyBackupPassphrase: async () => { getKeyBackupPassphrase: async (): Promise<Uint8Array> => {
// We may already have the backup key if we earlier went // We may already have the backup key if we earlier went
// through the restore backup path, so pass it along // through the restore backup path, so pass it along
// rather than prompting again. // rather than prompting again.
@ -383,7 +383,9 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
private restoreBackup = async (): Promise<void> => { private restoreBackup = async (): Promise<void> => {
// It's possible we'll need the backup key later on for bootstrapping, // It's possible we'll need the backup key later on for bootstrapping,
// so let's stash it here, rather than prompting for it twice. // so let's stash it here, rather than prompting for it twice.
const keyCallback = (k) => (this.backupKey = k); const keyCallback = (k: Uint8Array): void => {
this.backupKey = k;
};
const { finished } = Modal.createDialog( const { finished } = Modal.createDialog(
RestoreKeyBackupDialog, RestoreKeyBackupDialog,
@ -420,7 +422,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
this.setState({ phase: Phase.ChooseKeyPassphrase }); this.setState({ phase: Phase.ChooseKeyPassphrase });
}; };
private onPassPhraseNextClick = async (e: React.FormEvent) => { private onPassPhraseNextClick = async (e: React.FormEvent): Promise<void> => {
e.preventDefault(); e.preventDefault();
if (!this.passphraseField.current) return; // unmounting if (!this.passphraseField.current) return; // unmounting
@ -434,7 +436,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
this.setState({ phase: Phase.PassphraseConfirm }); this.setState({ phase: Phase.PassphraseConfirm });
}; };
private onPassPhraseConfirmNextClick = async (e: React.FormEvent) => { private onPassPhraseConfirmNextClick = async (e: React.FormEvent): Promise<void> => {
e.preventDefault(); e.preventDefault();
if (this.state.passPhrase !== this.state.passPhraseConfirm) return; if (this.state.passPhrase !== this.state.passPhraseConfirm) return;

View File

@ -121,7 +121,7 @@ export default class ExportE2eKeysDialog extends React.Component<IProps, IState>
return false; return false;
}; };
private onPassphraseChange = (ev: React.ChangeEvent<HTMLInputElement>, phrase: AnyPassphrase) => { private onPassphraseChange = (ev: React.ChangeEvent<HTMLInputElement>, phrase: AnyPassphrase): void => {
this.setState({ this.setState({
[phrase]: ev.target.value, [phrase]: ev.target.value,
} as Pick<IState, AnyPassphrase>); } as Pick<IState, AnyPassphrase>);

View File

@ -91,7 +91,7 @@ export default class ImportE2eKeysDialog extends React.Component<IProps, IState>
return false; return false;
}; };
private startImport(file: File, passphrase: string) { private startImport(file: File, passphrase: string): Promise<void> {
this.setState({ this.setState({
errStr: null, errStr: null,
phase: Phase.Importing, phase: Phase.Importing,

View File

@ -30,7 +30,7 @@ export class ManagedPlayback extends Playback {
return super.play(); return super.play();
} }
public destroy() { public destroy(): void {
this.manager.destroyPlaybackInstance(this); this.manager.destroyPlaybackInstance(this);
super.destroy(); super.destroy();
} }

View File

@ -145,7 +145,7 @@ export class Playback extends EventEmitter implements IDestroyable, PlaybackInte
return true; // we don't ever care if the event had listeners, so just return "yes" return true; // we don't ever care if the event had listeners, so just return "yes"
} }
public destroy() { public destroy(): void {
// Dev note: It's critical that we call stop() during cleanup to ensure that downstream callers // Dev note: It's critical that we call stop() during cleanup to ensure that downstream callers
// are aware of the final clock position before the user triggered an unload. // are aware of the final clock position before the user triggered an unload.
// noinspection JSIgnoredPromiseFromCall - not concerned about being called async here // noinspection JSIgnoredPromiseFromCall - not concerned about being called async here
@ -159,7 +159,7 @@ export class Playback extends EventEmitter implements IDestroyable, PlaybackInte
} }
} }
public async prepare() { public async prepare(): Promise<void> {
// don't attempt to decode the media again // don't attempt to decode the media again
// AudioContext.decodeAudioData detaches the array buffer `this.buf` // AudioContext.decodeAudioData detaches the array buffer `this.buf`
// meaning it cannot be re-read // meaning it cannot be re-read
@ -190,7 +190,7 @@ export class Playback extends EventEmitter implements IDestroyable, PlaybackInte
this.context.decodeAudioData( this.context.decodeAudioData(
this.buf, this.buf,
(b) => resolve(b), (b) => resolve(b),
async (e) => { async (e): Promise<void> => {
try { try {
// This error handler is largely for Safari as well, which doesn't support Opus/Ogg // This error handler is largely for Safari as well, which doesn't support Opus/Ogg
// very well. // very well.
@ -232,12 +232,12 @@ export class Playback extends EventEmitter implements IDestroyable, PlaybackInte
this.emit(PlaybackState.Stopped); // signal that we're not decoding anymore this.emit(PlaybackState.Stopped); // signal that we're not decoding anymore
} }
private onPlaybackEnd = async () => { private onPlaybackEnd = async (): Promise<void> => {
await this.context.suspend(); await this.context.suspend();
this.emit(PlaybackState.Stopped); this.emit(PlaybackState.Stopped);
}; };
public async play() { public async play(): Promise<void> {
// We can't restart a buffer source, so we need to create a new one if we hit the end // We can't restart a buffer source, so we need to create a new one if we hit the end
if (this.state === PlaybackState.Stopped) { if (this.state === PlaybackState.Stopped) {
this.disconnectSource(); this.disconnectSource();
@ -256,13 +256,13 @@ export class Playback extends EventEmitter implements IDestroyable, PlaybackInte
this.emit(PlaybackState.Playing); this.emit(PlaybackState.Playing);
} }
private disconnectSource() { private disconnectSource(): void {
if (this.element) return; // leave connected, we can (and must) re-use it if (this.element) return; // leave connected, we can (and must) re-use it
this.source?.disconnect(); this.source?.disconnect();
this.source?.removeEventListener("ended", this.onPlaybackEnd); this.source?.removeEventListener("ended", this.onPlaybackEnd);
} }
private makeNewSourceBuffer() { private makeNewSourceBuffer(): void {
if (this.element && this.source) return; // leave connected, we can (and must) re-use it if (this.element && this.source) return; // leave connected, we can (and must) re-use it
if (this.element) { if (this.element) {
@ -276,22 +276,22 @@ export class Playback extends EventEmitter implements IDestroyable, PlaybackInte
this.source.connect(this.context.destination); this.source.connect(this.context.destination);
} }
public async pause() { public async pause(): Promise<void> {
await this.context.suspend(); await this.context.suspend();
this.emit(PlaybackState.Paused); this.emit(PlaybackState.Paused);
} }
public async stop() { public async stop(): Promise<void> {
await this.onPlaybackEnd(); await this.onPlaybackEnd();
this.clock.flagStop(); this.clock.flagStop();
} }
public async toggle() { public async toggle(): Promise<void> {
if (this.isPlaying) await this.pause(); if (this.isPlaying) await this.pause();
else await this.play(); else await this.play();
} }
public async skipTo(timeSeconds: number) { public async skipTo(timeSeconds: number): Promise<void> {
// Dev note: this function talks a lot about clock desyncs. There is a clock running // Dev note: this function talks a lot about clock desyncs. There is a clock running
// independently to the audio context and buffer so that accurate human-perceptible // independently to the audio context and buffer so that accurate human-perceptible
// time can be exposed. The PlaybackClock class has more information, but the short // time can be exposed. The PlaybackClock class has more information, but the short

View File

@ -89,7 +89,7 @@ export class PlaybackClock implements IDestroyable {
return this.observable; return this.observable;
} }
private checkTime = (force = false) => { private checkTime = (force = false): void => {
const now = this.timeSeconds; // calculated dynamically const now = this.timeSeconds; // calculated dynamically
if (this.lastCheck !== now || force) { if (this.lastCheck !== now || force) {
this.observable.update([now, this.durationSeconds]); this.observable.update([now, this.durationSeconds]);
@ -102,7 +102,7 @@ export class PlaybackClock implements IDestroyable {
* The placeholders will be overridden once known. * The placeholders will be overridden once known.
* @param {MatrixEvent} event The event to use for placeholders. * @param {MatrixEvent} event The event to use for placeholders.
*/ */
public populatePlaceholdersFrom(event: MatrixEvent) { public populatePlaceholdersFrom(event: MatrixEvent): void {
const durationMs = Number(event.getContent()["info"]?.["duration"]); const durationMs = Number(event.getContent()["info"]?.["duration"]);
if (Number.isFinite(durationMs)) this.placeholderDuration = durationMs / 1000; if (Number.isFinite(durationMs)) this.placeholderDuration = durationMs / 1000;
} }
@ -112,11 +112,11 @@ export class PlaybackClock implements IDestroyable {
* This is to ensure the clock isn't skewed into thinking it is ~0.5s into * This is to ensure the clock isn't skewed into thinking it is ~0.5s into
* a clip when the duration is set. * a clip when the duration is set.
*/ */
public flagLoadTime() { public flagLoadTime(): void {
this.clipStart = this.context.currentTime; this.clipStart = this.context.currentTime;
} }
public flagStart() { public flagStart(): void {
if (this.stopped) { if (this.stopped) {
this.clipStart = this.context.currentTime; this.clipStart = this.context.currentTime;
this.stopped = false; this.stopped = false;
@ -128,7 +128,7 @@ export class PlaybackClock implements IDestroyable {
} }
} }
public flagStop() { public flagStop(): void {
this.stopped = true; this.stopped = true;
// Reset the clock time now so that the update going out will trigger components // Reset the clock time now so that the update going out will trigger components
@ -136,13 +136,13 @@ export class PlaybackClock implements IDestroyable {
this.clipStart = this.context.currentTime; this.clipStart = this.context.currentTime;
} }
public syncTo(contextTime: number, clipTime: number) { public syncTo(contextTime: number, clipTime: number): void {
this.clipStart = contextTime - clipTime; this.clipStart = contextTime - clipTime;
this.stopped = false; // count as a mid-stream pause (if we were stopped) this.stopped = false; // count as a mid-stream pause (if we were stopped)
this.checkTime(true); this.checkTime(true);
} }
public destroy() { public destroy(): void {
this.observable.close(); this.observable.close();
if (this.timerId) clearInterval(this.timerId); if (this.timerId) clearInterval(this.timerId);
} }

View File

@ -38,13 +38,13 @@ export class PlaybackManager {
* instances are paused. * instances are paused.
* @param playback Optional. The playback to leave untouched. * @param playback Optional. The playback to leave untouched.
*/ */
public pauseAllExcept(playback?: Playback) { public pauseAllExcept(playback?: Playback): void {
this.instances this.instances
.filter((p) => p !== playback && p.currentState === PlaybackState.Playing) .filter((p) => p !== playback && p.currentState === PlaybackState.Playing)
.forEach((p) => p.pause()); .forEach((p) => p.pause());
} }
public destroyPlaybackInstance(playback: ManagedPlayback) { public destroyPlaybackInstance(playback: ManagedPlayback): void {
this.instances = this.instances.filter((p) => p !== playback); this.instances = this.instances.filter((p) => p !== playback);
} }

View File

@ -75,28 +75,28 @@ export class PlaybackQueue {
return queue; return queue;
} }
private persistClocks() { private persistClocks(): void {
localStorage.setItem( localStorage.setItem(
`mx_voice_message_clocks_${this.room.roomId}`, `mx_voice_message_clocks_${this.room.roomId}`,
JSON.stringify(Array.from(this.clockStates.entries())), JSON.stringify(Array.from(this.clockStates.entries())),
); );
} }
private loadClocks() { private loadClocks(): void {
const val = localStorage.getItem(`mx_voice_message_clocks_${this.room.roomId}`); const val = localStorage.getItem(`mx_voice_message_clocks_${this.room.roomId}`);
if (!!val) { if (!!val) {
this.clockStates = new Map<string, number>(JSON.parse(val)); this.clockStates = new Map<string, number>(JSON.parse(val));
} }
} }
public unsortedEnqueue(mxEvent: MatrixEvent, playback: Playback) { public unsortedEnqueue(mxEvent: MatrixEvent, playback: Playback): void {
// We don't ever detach our listeners: we expect the Playback to clean up for us // We don't ever detach our listeners: we expect the Playback to clean up for us
this.playbacks.set(mxEvent.getId(), playback); this.playbacks.set(mxEvent.getId(), playback);
playback.on(UPDATE_EVENT, (state) => this.onPlaybackStateChange(playback, mxEvent, state)); playback.on(UPDATE_EVENT, (state) => this.onPlaybackStateChange(playback, mxEvent, state));
playback.clockInfo.liveData.onUpdate((clock) => this.onPlaybackClock(playback, mxEvent, clock)); playback.clockInfo.liveData.onUpdate((clock) => this.onPlaybackClock(playback, mxEvent, clock));
} }
private onPlaybackStateChange(playback: Playback, mxEvent: MatrixEvent, newState: PlaybackState) { private onPlaybackStateChange(playback: Playback, mxEvent: MatrixEvent, newState: PlaybackState): void {
// Remember where the user got to in playback // Remember where the user got to in playback
const wasLastPlaying = this.currentPlaybackId === mxEvent.getId(); const wasLastPlaying = this.currentPlaybackId === mxEvent.getId();
if (newState === PlaybackState.Stopped && this.clockStates.has(mxEvent.getId()) && !wasLastPlaying) { if (newState === PlaybackState.Stopped && this.clockStates.has(mxEvent.getId()) && !wasLastPlaying) {
@ -210,7 +210,7 @@ export class PlaybackQueue {
} }
} }
private onPlaybackClock(playback: Playback, mxEvent: MatrixEvent, clocks: number[]) { private onPlaybackClock(playback: Playback, mxEvent: MatrixEvent, clocks: number[]): void {
if (playback.currentState === PlaybackState.Decoding) return; // ignore pre-ready values if (playback.currentState === PlaybackState.Decoding) return; // ignore pre-ready values
if (playback.currentState !== PlaybackState.Stopped) { if (playback.currentState !== PlaybackState.Stopped) {

View File

@ -43,7 +43,7 @@ class MxVoiceWorklet extends AudioWorkletProcessor {
private nextAmplitudeSecond = 0; private nextAmplitudeSecond = 0;
private amplitudeIndex = 0; private amplitudeIndex = 0;
public process(inputs, outputs, parameters) { public process(inputs, outputs, parameters): boolean {
const currentSecond = roundTimeToTargetFreq(currentTime); const currentSecond = roundTimeToTargetFreq(currentTime);
// We special case the first ping because there's a fairly good chance that we'll miss the zeroth // We special case the first ping because there's a fairly good chance that we'll miss the zeroth
// update. Firefox for instance takes 0.06 seconds (roughly) to call this function for the first // update. Firefox for instance takes 0.06 seconds (roughly) to call this function for the first

View File

@ -141,7 +141,7 @@ export class VoiceMessageRecording implements IDestroyable {
this.voiceRecording.destroy(); this.voiceRecording.destroy();
} }
private onDataAvailable = (data: ArrayBuffer) => { private onDataAvailable = (data: ArrayBuffer): void => {
const buf = new Uint8Array(data); const buf = new Uint8Array(data);
this.buffer = concat(this.buffer, buf); this.buffer = concat(this.buffer, buf);
}; };
@ -153,6 +153,6 @@ export class VoiceMessageRecording implements IDestroyable {
} }
} }
export const createVoiceMessageRecording = (matrixClient: MatrixClient) => { export const createVoiceMessageRecording = (matrixClient: MatrixClient): VoiceMessageRecording => {
return new VoiceMessageRecording(matrixClient, new VoiceRecording()); return new VoiceMessageRecording(matrixClient, new VoiceRecording());
}; };

View File

@ -110,7 +110,7 @@ export class VoiceRecording extends EventEmitter implements IDestroyable {
return !MediaDeviceHandler.getAudioNoiseSuppression(); return !MediaDeviceHandler.getAudioNoiseSuppression();
} }
private async makeRecorder() { private async makeRecorder(): Promise<void> {
try { try {
this.recorderStream = await navigator.mediaDevices.getUserMedia({ this.recorderStream = await navigator.mediaDevices.getUserMedia({
audio: { audio: {
@ -212,14 +212,14 @@ export class VoiceRecording extends EventEmitter implements IDestroyable {
return !!Recorder.isRecordingSupported(); return !!Recorder.isRecordingSupported();
} }
private onAudioProcess = (ev: AudioProcessingEvent) => { private onAudioProcess = (ev: AudioProcessingEvent): void => {
this.processAudioUpdate(ev.playbackTime); this.processAudioUpdate(ev.playbackTime);
// We skip the functionality of the worklet regarding waveform calculations: we // We skip the functionality of the worklet regarding waveform calculations: we
// should get that information pretty quick during the playback info. // should get that information pretty quick during the playback info.
}; };
private processAudioUpdate = (timeSeconds: number) => { private processAudioUpdate = (timeSeconds: number): void => {
if (!this.recording) return; if (!this.recording) return;
this.observable.update({ this.observable.update({
@ -260,7 +260,7 @@ export class VoiceRecording extends EventEmitter implements IDestroyable {
/** /**
* {@link https://github.com/chris-rudmin/opus-recorder#instance-fields ref for recorderSeconds} * {@link https://github.com/chris-rudmin/opus-recorder#instance-fields ref for recorderSeconds}
*/ */
public get recorderSeconds() { public get recorderSeconds(): number {
return this.recorder.encodedSamplePosition / 48000; return this.recorder.encodedSamplePosition / 48000;
} }
@ -279,7 +279,7 @@ export class VoiceRecording extends EventEmitter implements IDestroyable {
} }
public async stop(): Promise<void> { public async stop(): Promise<void> {
return Singleflight.for(this, "stop").do(async () => { return Singleflight.for(this, "stop").do(async (): Promise<void> => {
if (!this.recording) { if (!this.recording) {
throw new Error("No recording to stop"); throw new Error("No recording to stop");
} }
@ -307,7 +307,7 @@ export class VoiceRecording extends EventEmitter implements IDestroyable {
}); });
} }
public destroy() { public destroy(): void {
// noinspection JSIgnoredPromiseFromCall - not concerned about stop() being called async here // noinspection JSIgnoredPromiseFromCall - not concerned about stop() being called async here
this.stop(); this.stop();
this.removeAllListeners(); this.removeAllListeners();

View File

@ -22,7 +22,7 @@ import { TimelineRenderingType } from "../contexts/RoomContext";
import type { ICompletion, ISelectionRange } from "./Autocompleter"; import type { ICompletion, ISelectionRange } from "./Autocompleter";
export interface ICommand { export interface ICommand {
command: string | null; command: RegExpExecArray | null;
range: { range: {
start: number; start: number;
end: number; end: number;
@ -59,7 +59,7 @@ export default abstract class AutocompleteProvider {
} }
} }
public destroy() { public destroy(): void {
// stub // stub
} }
@ -70,7 +70,7 @@ export default abstract class AutocompleteProvider {
* @param {boolean} force True if the user is forcing completion * @param {boolean} force True if the user is forcing completion
* @return {object} { command, range } where both objects fields are null if no match * @return {object} { command, range } where both objects fields are null if no match
*/ */
public getCurrentCommand(query: string, selection: ISelectionRange, force = false) { public getCurrentCommand(query: string, selection: ISelectionRange, force = false): ICommand {
let commandRegex = this.commandRegex; let commandRegex = this.commandRegex;
if (force && this.shouldForceComplete()) { if (force && this.shouldForceComplete()) {
@ -83,7 +83,7 @@ export default abstract class AutocompleteProvider {
commandRegex.lastIndex = 0; commandRegex.lastIndex = 0;
let match; let match: RegExpExecArray;
while ((match = commandRegex.exec(query)) !== null) { while ((match = commandRegex.exec(query)) !== null) {
const start = match.index; const start = match.index;
const end = start + match[0].length; const end = start + match[0].length;

View File

@ -69,7 +69,7 @@ export default class Autocompleter {
}); });
} }
public destroy() { public destroy(): void {
this.providers.forEach((p) => { this.providers.forEach((p) => {
p.destroy(); p.destroy();
}); });
@ -88,7 +88,7 @@ export default class Autocompleter {
*/ */
// list of results from each provider, each being a list of completions or null if it times out // list of results from each provider, each being a list of completions or null if it times out
const completionsList: ICompletion[][] = await Promise.all( const completionsList: ICompletion[][] = await Promise.all(
this.providers.map(async (provider) => { this.providers.map(async (provider): Promise<ICompletion[] | null> => {
return timeout( return timeout(
provider.getCompletions(query, selection, force, limit), provider.getCompletions(query, selection, force, limit),
null, null,

View File

@ -100,7 +100,7 @@ export default class CommandProvider extends AutocompleteProvider {
}); });
} }
public getName() { public getName(): string {
return "*️⃣ " + _t("Commands"); return "*️⃣ " + _t("Commands");
} }

View File

@ -55,7 +55,7 @@ const SORTED_EMOJI: ISortedEmoji[] = EMOJI.sort((a, b) => {
_orderBy: index, _orderBy: index,
})); }));
function score(query, space) { function score(query: string, space: string): number {
const index = space.indexOf(query); const index = space.indexOf(query);
if (index === -1) { if (index === -1) {
return Infinity; return Infinity;
@ -154,7 +154,7 @@ export default class EmojiProvider extends AutocompleteProvider {
return []; return [];
} }
public getName() { public getName(): string {
return "😃 " + _t("Emoji"); return "😃 " + _t("Emoji");
} }

View File

@ -65,7 +65,7 @@ export default class NotifProvider extends AutocompleteProvider {
return []; return [];
} }
public getName() { public getName(): string {
return "❗️ " + _t("Room Notification"); return "❗️ " + _t("Room Notification");
} }

View File

@ -61,7 +61,7 @@ export default class QueryMatcher<T extends {}> {
} }
} }
public setObjects(objects: T[]) { public setObjects(objects: T[]): void {
this._items = new Map(); this._items = new Map();
for (const object of objects) { for (const object of objects) {

View File

@ -37,7 +37,15 @@ function canonicalScore(displayedAlias: string, room: Room): number {
return displayedAlias === room.getCanonicalAlias() ? 0 : 1; return displayedAlias === room.getCanonicalAlias() ? 0 : 1;
} }
function matcherObject(room: Room, displayedAlias: string, matchName = "") { function matcherObject(
room: Room,
displayedAlias: string,
matchName = "",
): {
room: Room;
matchName: string;
displayedAlias: string;
} {
return { return {
room, room,
matchName, matchName,
@ -46,7 +54,7 @@ function matcherObject(room: Room, displayedAlias: string, matchName = "") {
} }
export default class RoomProvider extends AutocompleteProvider { export default class RoomProvider extends AutocompleteProvider {
protected matcher: QueryMatcher<Room>; protected matcher: QueryMatcher<ReturnType<typeof matcherObject>>;
public constructor(room: Room, renderingType?: TimelineRenderingType) { public constructor(room: Room, renderingType?: TimelineRenderingType) {
super({ commandRegex: ROOM_REGEX, renderingType }); super({ commandRegex: ROOM_REGEX, renderingType });
@ -55,7 +63,7 @@ export default class RoomProvider extends AutocompleteProvider {
}); });
} }
protected getRooms() { protected getRooms(): Room[] {
const cli = MatrixClientPeg.get(); const cli = MatrixClientPeg.get();
// filter out spaces here as they get their own autocomplete provider // filter out spaces here as they get their own autocomplete provider
@ -68,7 +76,6 @@ export default class RoomProvider extends AutocompleteProvider {
force = false, force = false,
limit = -1, limit = -1,
): Promise<ICompletion[]> { ): Promise<ICompletion[]> {
let completions = [];
const { command, range } = this.getCurrentCommand(query, selection, force); const { command, range } = this.getCurrentCommand(query, selection, force);
if (command) { if (command) {
// the only reason we need to do this is because Fuse only matches on properties // the only reason we need to do this is because Fuse only matches on properties
@ -96,15 +103,15 @@ export default class RoomProvider extends AutocompleteProvider {
this.matcher.setObjects(matcherObjects); this.matcher.setObjects(matcherObjects);
const matchedString = command[0]; const matchedString = command[0];
completions = this.matcher.match(matchedString, limit); let completions = this.matcher.match(matchedString, limit);
completions = sortBy(completions, [ completions = sortBy(completions, [
(c) => canonicalScore(c.displayedAlias, c.room), (c) => canonicalScore(c.displayedAlias, c.room),
(c) => c.displayedAlias.length, (c) => c.displayedAlias.length,
]); ]);
completions = uniqBy(completions, (match) => match.room); completions = uniqBy(completions, (match) => match.room);
completions = completions return completions
.map((room) => { .map(
return { (room): ICompletion => ({
completion: room.displayedAlias, completion: room.displayedAlias,
completionId: room.room.roomId, completionId: room.room.roomId,
type: "room", type: "room",
@ -116,14 +123,14 @@ export default class RoomProvider extends AutocompleteProvider {
</PillCompletion> </PillCompletion>
), ),
range, range,
}; }),
}) )
.filter((completion) => !!completion.completion && completion.completion.length > 0); .filter((completion) => !!completion.completion && completion.completion.length > 0);
} }
return completions; return [];
} }
public getName() { public getName(): string {
return _t("Rooms"); return _t("Rooms");
} }

View File

@ -14,6 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
import { Room } from "matrix-js-sdk/src/models/room";
import React from "react"; import React from "react";
import { _t } from "../languageHandler"; import { _t } from "../languageHandler";
@ -21,13 +22,13 @@ import { MatrixClientPeg } from "../MatrixClientPeg";
import RoomProvider from "./RoomProvider"; import RoomProvider from "./RoomProvider";
export default class SpaceProvider extends RoomProvider { export default class SpaceProvider extends RoomProvider {
protected getRooms() { protected getRooms(): Room[] {
return MatrixClientPeg.get() return MatrixClientPeg.get()
.getVisibleRooms() .getVisibleRooms()
.filter((r) => r.isSpaceRoom()); .filter((r) => r.isSpaceRoom());
} }
public getName() { public getName(): string {
return _t("Spaces"); return _t("Spaces");
} }

View File

@ -64,7 +64,7 @@ export default class UserProvider extends AutocompleteProvider {
MatrixClientPeg.get().on(RoomStateEvent.Update, this.onRoomStateUpdate); MatrixClientPeg.get().on(RoomStateEvent.Update, this.onRoomStateUpdate);
} }
public destroy() { public destroy(): void {
if (MatrixClientPeg.get()) { if (MatrixClientPeg.get()) {
MatrixClientPeg.get().removeListener(RoomEvent.Timeline, this.onRoomTimeline); MatrixClientPeg.get().removeListener(RoomEvent.Timeline, this.onRoomTimeline);
MatrixClientPeg.get().removeListener(RoomStateEvent.Update, this.onRoomStateUpdate); MatrixClientPeg.get().removeListener(RoomStateEvent.Update, this.onRoomStateUpdate);
@ -77,7 +77,7 @@ export default class UserProvider extends AutocompleteProvider {
toStartOfTimeline: boolean, toStartOfTimeline: boolean,
removed: boolean, removed: boolean,
data: IRoomTimelineData, data: IRoomTimelineData,
) => { ): void => {
if (!room) return; // notification timeline, we'll get this event again with a room specific timeline if (!room) return; // notification timeline, we'll get this event again with a room specific timeline
if (removed) return; if (removed) return;
if (room.roomId !== this.room.roomId) return; if (room.roomId !== this.room.roomId) return;
@ -93,7 +93,7 @@ export default class UserProvider extends AutocompleteProvider {
this.onUserSpoke(ev.sender); this.onUserSpoke(ev.sender);
}; };
private onRoomStateUpdate = (state: RoomState) => { private onRoomStateUpdate = (state: RoomState): void => {
// ignore updates in other rooms // ignore updates in other rooms
if (state.roomId !== this.room.roomId) return; if (state.roomId !== this.room.roomId) return;
@ -150,7 +150,7 @@ export default class UserProvider extends AutocompleteProvider {
return _t("Users"); return _t("Users");
} }
private makeUsers() { private makeUsers(): void {
const events = this.room.getLiveTimeline().getEvents(); const events = this.room.getLiveTimeline().getEvents();
const lastSpoken = {}; const lastSpoken = {};
@ -167,7 +167,7 @@ export default class UserProvider extends AutocompleteProvider {
this.matcher.setObjects(this.users); this.matcher.setObjects(this.users);
} }
public onUserSpoke(user: RoomMember) { public onUserSpoke(user: RoomMember): void {
if (!this.users) return; if (!this.users) return;
if (!user) return; if (!user) return;
if (user.userId === MatrixClientPeg.get().credentials.userId) return; if (user.userId === MatrixClientPeg.get().credentials.userId) return;

View File

@ -22,7 +22,7 @@ type DynamicHtmlElementProps<T extends keyof JSX.IntrinsicElements> =
JSX.IntrinsicElements[T] extends HTMLAttributes<{}> ? DynamicElementProps<T> : DynamicElementProps<"div">; JSX.IntrinsicElements[T] extends HTMLAttributes<{}> ? DynamicElementProps<T> : DynamicElementProps<"div">;
type DynamicElementProps<T extends keyof JSX.IntrinsicElements> = Partial<Omit<JSX.IntrinsicElements[T], "ref">>; type DynamicElementProps<T extends keyof JSX.IntrinsicElements> = Partial<Omit<JSX.IntrinsicElements[T], "ref">>;
export type IProps<T extends keyof JSX.IntrinsicElements> = DynamicHtmlElementProps<T> & { export type IProps<T extends keyof JSX.IntrinsicElements> = Omit<DynamicHtmlElementProps<T>, "onScroll"> & {
element?: T; element?: T;
className?: string; className?: string;
onScroll?: (event: Event) => void; onScroll?: (event: Event) => void;
@ -39,7 +39,7 @@ export default class AutoHideScrollbar<T extends keyof JSX.IntrinsicElements> ex
public readonly containerRef: React.RefObject<HTMLDivElement> = React.createRef(); public readonly containerRef: React.RefObject<HTMLDivElement> = React.createRef();
public componentDidMount() { public componentDidMount(): void {
if (this.containerRef.current && this.props.onScroll) { if (this.containerRef.current && this.props.onScroll) {
// Using the passive option to not block the main thread // Using the passive option to not block the main thread
// https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#improving_scrolling_performance_with_passive_listeners // https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#improving_scrolling_performance_with_passive_listeners
@ -49,13 +49,13 @@ export default class AutoHideScrollbar<T extends keyof JSX.IntrinsicElements> ex
this.props.wrappedRef?.(this.containerRef.current); this.props.wrappedRef?.(this.containerRef.current);
} }
public componentWillUnmount() { public componentWillUnmount(): void {
if (this.containerRef.current && this.props.onScroll) { if (this.containerRef.current && this.props.onScroll) {
this.containerRef.current.removeEventListener("scroll", this.props.onScroll); this.containerRef.current.removeEventListener("scroll", this.props.onScroll);
} }
} }
public render() { public render(): JSX.Element {
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
const { element, className, onScroll, tabIndex, wrappedRef, children, ...otherProps } = this.props; const { element, className, onScroll, tabIndex, wrappedRef, children, ...otherProps } = this.props;

View File

@ -52,11 +52,11 @@ export const AutocompleteInput: React.FC<AutocompleteInputProps> = ({
const editorContainerRef = useRef<HTMLDivElement>(null); const editorContainerRef = useRef<HTMLDivElement>(null);
const editorRef = useRef<HTMLInputElement>(null); const editorRef = useRef<HTMLInputElement>(null);
const focusEditor = () => { const focusEditor = (): void => {
editorRef?.current?.focus(); editorRef?.current?.focus();
}; };
const onQueryChange = async (e: ChangeEvent<HTMLInputElement>) => { const onQueryChange = async (e: ChangeEvent<HTMLInputElement>): Promise<void> => {
const value = e.target.value.trim(); const value = e.target.value.trim();
setQuery(value); setQuery(value);
@ -74,11 +74,11 @@ export const AutocompleteInput: React.FC<AutocompleteInputProps> = ({
setSuggestions(matches); setSuggestions(matches);
}; };
const onClickInputArea = () => { const onClickInputArea = (): void => {
focusEditor(); focusEditor();
}; };
const onKeyDown = (e: KeyboardEvent) => { const onKeyDown = (e: KeyboardEvent): void => {
const hasModifiers = e.ctrlKey || e.shiftKey || e.metaKey; const hasModifiers = e.ctrlKey || e.shiftKey || e.metaKey;
// when the field is empty and the user hits backspace remove the right-most target // when the field is empty and the user hits backspace remove the right-most target
@ -87,7 +87,7 @@ export const AutocompleteInput: React.FC<AutocompleteInputProps> = ({
} }
}; };
const toggleSelection = (completion: ICompletion) => { const toggleSelection = (completion: ICompletion): void => {
const newSelection = [...selection]; const newSelection = [...selection];
const index = selection.findIndex((selection) => selection.completionId === completion.completionId); const index = selection.findIndex((selection) => selection.completionId === completion.completionId);
@ -101,7 +101,7 @@ export const AutocompleteInput: React.FC<AutocompleteInputProps> = ({
focusEditor(); focusEditor();
}; };
const removeSelection = (completion: ICompletion) => { const removeSelection = (completion: ICompletion): void => {
const newSelection = [...selection]; const newSelection = [...selection];
const index = selection.findIndex((selection) => selection.completionId === completion.completionId); const index = selection.findIndex((selection) => selection.completionId === completion.completionId);

View File

@ -64,7 +64,7 @@ export enum ChevronFace {
None = "none", None = "none",
} }
export interface IProps extends IPosition { export interface MenuProps extends IPosition {
menuWidth?: number; menuWidth?: number;
menuHeight?: number; menuHeight?: number;
@ -77,7 +77,9 @@ export interface IProps extends IPosition {
menuPaddingRight?: number; menuPaddingRight?: number;
zIndex?: number; zIndex?: number;
}
export interface IProps extends MenuProps {
// If true, insert an invisible screen-sized element behind the menu that when clicked will close it. // If true, insert an invisible screen-sized element behind the menu that when clicked will close it.
hasBackground?: boolean; hasBackground?: boolean;
// whether this context menu should be focus managed. If false it must handle itself // whether this context menu should be focus managed. If false it must handle itself
@ -128,21 +130,21 @@ export default class ContextMenu extends React.PureComponent<IProps, IState> {
this.initialFocus = document.activeElement as HTMLElement; this.initialFocus = document.activeElement as HTMLElement;
} }
public componentDidMount() { public componentDidMount(): void {
Modal.on(ModalManagerEvent.Opened, this.onModalOpen); Modal.on(ModalManagerEvent.Opened, this.onModalOpen);
} }
public componentWillUnmount() { public componentWillUnmount(): void {
Modal.off(ModalManagerEvent.Opened, this.onModalOpen); Modal.off(ModalManagerEvent.Opened, this.onModalOpen);
// return focus to the thing which had it before us // return focus to the thing which had it before us
this.initialFocus.focus(); this.initialFocus.focus();
} }
private onModalOpen = () => { private onModalOpen = (): void => {
this.props.onFinished?.(); this.props.onFinished?.();
}; };
private collectContextMenuRect = (element: HTMLDivElement) => { private collectContextMenuRect = (element: HTMLDivElement): void => {
// We don't need to clean up when unmounting, so ignore // We don't need to clean up when unmounting, so ignore
if (!element) return; if (!element) return;
@ -159,7 +161,7 @@ export default class ContextMenu extends React.PureComponent<IProps, IState> {
}); });
}; };
private onContextMenu = (e) => { private onContextMenu = (e: React.MouseEvent): void => {
if (this.props.onFinished) { if (this.props.onFinished) {
this.props.onFinished(); this.props.onFinished();
@ -184,20 +186,20 @@ export default class ContextMenu extends React.PureComponent<IProps, IState> {
} }
}; };
private onContextMenuPreventBubbling = (e) => { private onContextMenuPreventBubbling = (e: React.MouseEvent): void => {
// stop propagation so that any context menu handlers don't leak out of this context menu // stop propagation so that any context menu handlers don't leak out of this context menu
// but do not inhibit the default browser menu // but do not inhibit the default browser menu
e.stopPropagation(); e.stopPropagation();
}; };
// Prevent clicks on the background from going through to the component which opened the menu. // Prevent clicks on the background from going through to the component which opened the menu.
private onFinished = (ev: React.MouseEvent) => { private onFinished = (ev: React.MouseEvent): void => {
ev.stopPropagation(); ev.stopPropagation();
ev.preventDefault(); ev.preventDefault();
this.props.onFinished?.(); this.props.onFinished?.();
}; };
private onClick = (ev: React.MouseEvent) => { private onClick = (ev: React.MouseEvent): void => {
// Don't allow clicks to escape the context menu wrapper // Don't allow clicks to escape the context menu wrapper
ev.stopPropagation(); ev.stopPropagation();
@ -208,7 +210,7 @@ export default class ContextMenu extends React.PureComponent<IProps, IState> {
// We now only handle closing the ContextMenu in this keyDown handler. // We now only handle closing the ContextMenu in this keyDown handler.
// All of the item/option navigation is delegated to RovingTabIndex. // All of the item/option navigation is delegated to RovingTabIndex.
private onKeyDown = (ev: React.KeyboardEvent) => { private onKeyDown = (ev: React.KeyboardEvent): void => {
ev.stopPropagation(); // prevent keyboard propagating out of the context menu, we're focus-locked ev.stopPropagation(); // prevent keyboard propagating out of the context menu, we're focus-locked
const action = getKeyBindingsManager().getAccessibilityAction(ev); const action = getKeyBindingsManager().getAccessibilityAction(ev);
@ -243,7 +245,7 @@ export default class ContextMenu extends React.PureComponent<IProps, IState> {
} }
}; };
protected renderMenu(hasBackground = this.props.hasBackground) { protected renderMenu(hasBackground = this.props.hasBackground): JSX.Element {
const position: Partial<Writeable<DOMRect>> = {}; const position: Partial<Writeable<DOMRect>> = {};
const { const {
top, top,
@ -501,17 +503,13 @@ export const toLeftOrRightOf = (elementRect: DOMRect, chevronOffset = 12): ToRig
return toRightOf(elementRect, chevronOffset); return toRightOf(elementRect, chevronOffset);
}; };
export type AboveLeftOf = IPosition & {
chevronFace: ChevronFace;
};
// Placement method for <ContextMenu /> to position context menu right-aligned and flowing to the left of elementRect, // Placement method for <ContextMenu /> to position context menu right-aligned and flowing to the left of elementRect,
// and either above or below: wherever there is more space (maybe this should be aboveOrBelowLeftOf?) // and either above or below: wherever there is more space (maybe this should be aboveOrBelowLeftOf?)
export const aboveLeftOf = ( export const aboveLeftOf = (
elementRect: Pick<DOMRect, "right" | "top" | "bottom">, elementRect: Pick<DOMRect, "right" | "top" | "bottom">,
chevronFace = ChevronFace.None, chevronFace = ChevronFace.None,
vPadding = 0, vPadding = 0,
): AboveLeftOf => { ): MenuProps => {
const menuOptions: IPosition & { chevronFace: ChevronFace } = { chevronFace }; const menuOptions: IPosition & { chevronFace: ChevronFace } = { chevronFace };
const buttonRight = elementRect.right + window.scrollX; const buttonRight = elementRect.right + window.scrollX;
@ -535,7 +533,7 @@ export const aboveRightOf = (
elementRect: Pick<DOMRect, "left" | "top" | "bottom">, elementRect: Pick<DOMRect, "left" | "top" | "bottom">,
chevronFace = ChevronFace.None, chevronFace = ChevronFace.None,
vPadding = 0, vPadding = 0,
): AboveLeftOf => { ): MenuProps => {
const menuOptions: IPosition & { chevronFace: ChevronFace } = { chevronFace }; const menuOptions: IPosition & { chevronFace: ChevronFace } = { chevronFace };
const buttonLeft = elementRect.left + window.scrollX; const buttonLeft = elementRect.left + window.scrollX;
@ -555,11 +553,11 @@ export const aboveRightOf = (
// Placement method for <ContextMenu /> to position context menu right-aligned and flowing to the left of elementRect // Placement method for <ContextMenu /> to position context menu right-aligned and flowing to the left of elementRect
// and always above elementRect // and always above elementRect
export const alwaysAboveLeftOf = ( export const alwaysMenuProps = (
elementRect: Pick<DOMRect, "right" | "bottom" | "top">, elementRect: Pick<DOMRect, "right" | "bottom" | "top">,
chevronFace = ChevronFace.None, chevronFace = ChevronFace.None,
vPadding = 0, vPadding = 0,
) => { ): IPosition & { chevronFace: ChevronFace } => {
const menuOptions: IPosition & { chevronFace: ChevronFace } = { chevronFace }; const menuOptions: IPosition & { chevronFace: ChevronFace } = { chevronFace };
const buttonRight = elementRect.right + window.scrollX; const buttonRight = elementRect.right + window.scrollX;
@ -578,7 +576,7 @@ export const alwaysAboveRightOf = (
elementRect: Pick<DOMRect, "left" | "top">, elementRect: Pick<DOMRect, "left" | "top">,
chevronFace = ChevronFace.None, chevronFace = ChevronFace.None,
vPadding = 0, vPadding = 0,
) => { ): IPosition & { chevronFace: ChevronFace } => {
const menuOptions: IPosition & { chevronFace: ChevronFace } = { chevronFace }; const menuOptions: IPosition & { chevronFace: ChevronFace } = { chevronFace };
const buttonLeft = elementRect.left + window.scrollX; const buttonLeft = elementRect.left + window.scrollX;
@ -607,12 +605,12 @@ export const useContextMenu = <T extends any = HTMLElement>(inputRef?: RefObject
} }
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
const open = (ev?: SyntheticEvent) => { const open = (ev?: SyntheticEvent): void => {
ev?.preventDefault(); ev?.preventDefault();
ev?.stopPropagation(); ev?.stopPropagation();
setIsOpen(true); setIsOpen(true);
}; };
const close = (ev?: SyntheticEvent) => { const close = (ev?: SyntheticEvent): void => {
ev?.preventDefault(); ev?.preventDefault();
ev?.stopPropagation(); ev?.stopPropagation();
setIsOpen(false); setIsOpen(false);
@ -622,8 +620,11 @@ export const useContextMenu = <T extends any = HTMLElement>(inputRef?: RefObject
}; };
// XXX: Deprecated, used only for dynamic Tooltips. Avoid using at all costs. // XXX: Deprecated, used only for dynamic Tooltips. Avoid using at all costs.
export function createMenu(ElementClass, props) { export function createMenu(
const onFinished = function (...args) { ElementClass: typeof React.Component,
props: Record<string, any>,
): { close: (...args: any[]) => void } {
const onFinished = function (...args): void {
ReactDOM.unmountComponentAtNode(getOrCreateContainer()); ReactDOM.unmountComponentAtNode(getOrCreateContainer());
props?.onFinished?.apply(null, args); props?.onFinished?.apply(null, args);
}; };

View File

@ -60,7 +60,7 @@ export default class EmbeddedPage extends React.PureComponent<IProps, IState> {
return sanitizeHtml(_t(s)); return sanitizeHtml(_t(s));
} }
private async fetchEmbed() { private async fetchEmbed(): Promise<void> {
let res: Response; let res: Response;
try { try {

View File

@ -37,7 +37,7 @@ const FileDropTarget: React.FC<IProps> = ({ parent, onFileDrop }) => {
useEffect(() => { useEffect(() => {
if (!parent || parent.ondrop) return; if (!parent || parent.ondrop) return;
const onDragEnter = (ev: DragEvent) => { const onDragEnter = (ev: DragEvent): void => {
ev.stopPropagation(); ev.stopPropagation();
ev.preventDefault(); ev.preventDefault();
@ -55,7 +55,7 @@ const FileDropTarget: React.FC<IProps> = ({ parent, onFileDrop }) => {
})); }));
}; };
const onDragLeave = (ev: DragEvent) => { const onDragLeave = (ev: DragEvent): void => {
ev.stopPropagation(); ev.stopPropagation();
ev.preventDefault(); ev.preventDefault();
@ -65,7 +65,7 @@ const FileDropTarget: React.FC<IProps> = ({ parent, onFileDrop }) => {
})); }));
}; };
const onDragOver = (ev: DragEvent) => { const onDragOver = (ev: DragEvent): void => {
ev.stopPropagation(); ev.stopPropagation();
ev.preventDefault(); ev.preventDefault();
@ -79,7 +79,7 @@ const FileDropTarget: React.FC<IProps> = ({ parent, onFileDrop }) => {
} }
}; };
const onDrop = (ev: DragEvent) => { const onDrop = (ev: DragEvent): void => {
ev.stopPropagation(); ev.stopPropagation();
ev.preventDefault(); ev.preventDefault();
onFileDrop(ev.dataTransfer); onFileDrop(ev.dataTransfer);

View File

@ -223,7 +223,7 @@ class FilePanel extends React.Component<IProps, IState> {
} }
} }
public render() { public render(): JSX.Element {
if (MatrixClientPeg.get().isGuest()) { if (MatrixClientPeg.get().isGuest()) {
return ( return (
<BaseCard className="mx_FilePanel mx_RoomView_messageListWrapper" onClose={this.props.onClose}> <BaseCard className="mx_FilePanel mx_RoomView_messageListWrapper" onClose={this.props.onClose}>

View File

@ -22,7 +22,7 @@ interface IProps {
} }
export default class GenericErrorPage extends React.PureComponent<IProps> { export default class GenericErrorPage extends React.PureComponent<IProps> {
public render() { public render(): JSX.Element {
return ( return (
<div className="mx_GenericErrorPage"> <div className="mx_GenericErrorPage">
<div className="mx_GenericErrorPage_box"> <div className="mx_GenericErrorPage_box">

View File

@ -33,17 +33,17 @@ import MiniAvatarUploader, { AVATAR_SIZE } from "../views/elements/MiniAvatarUpl
import PosthogTrackers from "../../PosthogTrackers"; import PosthogTrackers from "../../PosthogTrackers";
import EmbeddedPage from "./EmbeddedPage"; import EmbeddedPage from "./EmbeddedPage";
const onClickSendDm = (ev: ButtonEvent) => { const onClickSendDm = (ev: ButtonEvent): void => {
PosthogTrackers.trackInteraction("WebHomeCreateChatButton", ev); PosthogTrackers.trackInteraction("WebHomeCreateChatButton", ev);
dis.dispatch({ action: "view_create_chat" }); dis.dispatch({ action: "view_create_chat" });
}; };
const onClickExplore = (ev: ButtonEvent) => { const onClickExplore = (ev: ButtonEvent): void => {
PosthogTrackers.trackInteraction("WebHomeExploreRoomsButton", ev); PosthogTrackers.trackInteraction("WebHomeExploreRoomsButton", ev);
dis.fire(Action.ViewRoomDirectory); dis.fire(Action.ViewRoomDirectory);
}; };
const onClickNewRoom = (ev: ButtonEvent) => { const onClickNewRoom = (ev: ButtonEvent): void => {
PosthogTrackers.trackInteraction("WebHomeCreateRoomButton", ev); PosthogTrackers.trackInteraction("WebHomeCreateRoomButton", ev);
dis.dispatch({ action: "view_create_room" }); dis.dispatch({ action: "view_create_room" });
}; };
@ -52,12 +52,17 @@ interface IProps {
justRegistered?: boolean; justRegistered?: boolean;
} }
const getOwnProfile = (userId: string) => ({ const getOwnProfile = (
userId: string,
): {
displayName: string;
avatarUrl: string;
} => ({
displayName: OwnProfileStore.instance.displayName || userId, displayName: OwnProfileStore.instance.displayName || userId,
avatarUrl: OwnProfileStore.instance.getHttpAvatarUrl(AVATAR_SIZE), avatarUrl: OwnProfileStore.instance.getHttpAvatarUrl(AVATAR_SIZE),
}); });
const UserWelcomeTop = () => { const UserWelcomeTop: React.FC = () => {
const cli = useContext(MatrixClientContext); const cli = useContext(MatrixClientContext);
const userId = cli.getUserId(); const userId = cli.getUserId();
const [ownProfile, setOwnProfile] = useState(getOwnProfile(userId)); const [ownProfile, setOwnProfile] = useState(getOwnProfile(userId));

View File

@ -28,7 +28,7 @@ interface IProps {
interface IState {} interface IState {}
export default class HostSignupAction extends React.PureComponent<IProps, IState> { export default class HostSignupAction extends React.PureComponent<IProps, IState> {
private openDialog = async () => { private openDialog = async (): Promise<void> => {
this.props.onClick?.(); this.props.onClick?.();
await HostSignupStore.instance.setHostSignupActive(true); await HostSignupStore.instance.setHostSignupActive(true);
}; };

View File

@ -130,7 +130,7 @@ export default class InteractiveAuthComponent extends React.Component<IProps, IS
} }
} }
public componentDidMount() { public componentDidMount(): void {
this.authLogic this.authLogic
.attemptAuth() .attemptAuth()
.then((result) => { .then((result) => {
@ -155,7 +155,7 @@ export default class InteractiveAuthComponent extends React.Component<IProps, IS
}); });
} }
public componentWillUnmount() { public componentWillUnmount(): void {
this.unmounted = true; this.unmounted = true;
if (this.intervalId !== null) { if (this.intervalId !== null) {
@ -249,7 +249,7 @@ export default class InteractiveAuthComponent extends React.Component<IProps, IS
this.authLogic.setEmailSid(sid); this.authLogic.setEmailSid(sid);
}; };
public render() { public render(): JSX.Element {
const stage = this.state.authStage; const stage = this.state.authStage;
if (!stage) { if (!stage) {
if (this.state.busy) { if (this.state.busy) {

View File

@ -89,7 +89,7 @@ export default class LeftPanel extends React.Component<IProps, IState> {
return SettingsStore.getValue("feature_breadcrumbs_v2") ? BreadcrumbsMode.Labs : BreadcrumbsMode.Legacy; return SettingsStore.getValue("feature_breadcrumbs_v2") ? BreadcrumbsMode.Labs : BreadcrumbsMode.Legacy;
} }
public componentDidMount() { public componentDidMount(): void {
UIStore.instance.trackElementDimensions("ListContainer", this.listContainerRef.current); UIStore.instance.trackElementDimensions("ListContainer", this.listContainerRef.current);
UIStore.instance.on("ListContainer", this.refreshStickyHeaders); UIStore.instance.on("ListContainer", this.refreshStickyHeaders);
// Using the passive option to not block the main thread // Using the passive option to not block the main thread
@ -97,7 +97,7 @@ export default class LeftPanel extends React.Component<IProps, IState> {
this.listContainerRef.current?.addEventListener("scroll", this.onScroll, { passive: true }); this.listContainerRef.current?.addEventListener("scroll", this.onScroll, { passive: true });
} }
public componentWillUnmount() { public componentWillUnmount(): void {
BreadcrumbsStore.instance.off(UPDATE_EVENT, this.onBreadcrumbsUpdate); BreadcrumbsStore.instance.off(UPDATE_EVENT, this.onBreadcrumbsUpdate);
RoomListStore.instance.off(LISTS_UPDATE_EVENT, this.onBreadcrumbsUpdate); RoomListStore.instance.off(LISTS_UPDATE_EVENT, this.onBreadcrumbsUpdate);
SpaceStore.instance.off(UPDATE_SELECTED_SPACE, this.updateActiveSpace); SpaceStore.instance.off(UPDATE_SELECTED_SPACE, this.updateActiveSpace);
@ -112,25 +112,25 @@ export default class LeftPanel extends React.Component<IProps, IState> {
} }
} }
private updateActiveSpace = (activeSpace: SpaceKey) => { private updateActiveSpace = (activeSpace: SpaceKey): void => {
this.setState({ activeSpace }); this.setState({ activeSpace });
}; };
private onDialPad = () => { private onDialPad = (): void => {
dis.fire(Action.OpenDialPad); dis.fire(Action.OpenDialPad);
}; };
private onExplore = (ev: ButtonEvent) => { private onExplore = (ev: ButtonEvent): void => {
dis.fire(Action.ViewRoomDirectory); dis.fire(Action.ViewRoomDirectory);
PosthogTrackers.trackInteraction("WebLeftPanelExploreRoomsButton", ev); PosthogTrackers.trackInteraction("WebLeftPanelExploreRoomsButton", ev);
}; };
private refreshStickyHeaders = () => { private refreshStickyHeaders = (): void => {
if (!this.listContainerRef.current) return; // ignore: no headers to sticky if (!this.listContainerRef.current) return; // ignore: no headers to sticky
this.handleStickyHeaders(this.listContainerRef.current); this.handleStickyHeaders(this.listContainerRef.current);
}; };
private onBreadcrumbsUpdate = () => { private onBreadcrumbsUpdate = (): void => {
const newVal = LeftPanel.breadcrumbsMode; const newVal = LeftPanel.breadcrumbsMode;
if (newVal !== this.state.showBreadcrumbs) { if (newVal !== this.state.showBreadcrumbs) {
this.setState({ showBreadcrumbs: newVal }); this.setState({ showBreadcrumbs: newVal });
@ -141,7 +141,7 @@ export default class LeftPanel extends React.Component<IProps, IState> {
} }
}; };
private handleStickyHeaders(list: HTMLDivElement) { private handleStickyHeaders(list: HTMLDivElement): void {
if (this.isDoingStickyHeaders) return; if (this.isDoingStickyHeaders) return;
this.isDoingStickyHeaders = true; this.isDoingStickyHeaders = true;
window.requestAnimationFrame(() => { window.requestAnimationFrame(() => {
@ -150,7 +150,7 @@ export default class LeftPanel extends React.Component<IProps, IState> {
}); });
} }
private doStickyHeaders(list: HTMLDivElement) { private doStickyHeaders(list: HTMLDivElement): void {
const topEdge = list.scrollTop; const topEdge = list.scrollTop;
const bottomEdge = list.offsetHeight + list.scrollTop; const bottomEdge = list.offsetHeight + list.scrollTop;
const sublists = list.querySelectorAll<HTMLDivElement>(".mx_RoomSublist:not(.mx_RoomSublist_hidden)"); const sublists = list.querySelectorAll<HTMLDivElement>(".mx_RoomSublist:not(.mx_RoomSublist_hidden)");
@ -282,20 +282,20 @@ export default class LeftPanel extends React.Component<IProps, IState> {
} }
} }
private onScroll = (ev: Event) => { private onScroll = (ev: Event): void => {
const list = ev.target as HTMLDivElement; const list = ev.target as HTMLDivElement;
this.handleStickyHeaders(list); this.handleStickyHeaders(list);
}; };
private onFocus = (ev: React.FocusEvent) => { private onFocus = (ev: React.FocusEvent): void => {
this.focusedElement = ev.target; this.focusedElement = ev.target;
}; };
private onBlur = () => { private onBlur = (): void => {
this.focusedElement = null; this.focusedElement = null;
}; };
private onKeyDown = (ev: React.KeyboardEvent, state?: IRovingTabIndexState) => { private onKeyDown = (ev: React.KeyboardEvent, state?: IRovingTabIndexState): void => {
if (!this.focusedElement) return; if (!this.focusedElement) return;
const action = getKeyBindingsManager().getRoomListAction(ev); const action = getKeyBindingsManager().getRoomListAction(ev);

View File

@ -142,7 +142,7 @@ export default class LegacyCallEventGrouper extends EventEmitter {
return [...this.events][0]?.getRoomId(); return [...this.events][0]?.getRoomId();
} }
private onSilencedCallsChanged = () => { private onSilencedCallsChanged = (): void => {
const newState = LegacyCallHandler.instance.isCallSilenced(this.callId); const newState = LegacyCallHandler.instance.isCallSilenced(this.callId);
this.emit(LegacyCallEventGrouperEvent.SilencedChanged, newState); this.emit(LegacyCallEventGrouperEvent.SilencedChanged, newState);
}; };
@ -163,20 +163,20 @@ export default class LegacyCallEventGrouper extends EventEmitter {
LegacyCallHandler.instance.placeCall(this.roomId, this.isVoice ? CallType.Voice : CallType.Video); LegacyCallHandler.instance.placeCall(this.roomId, this.isVoice ? CallType.Voice : CallType.Video);
}; };
public toggleSilenced = () => { public toggleSilenced = (): void => {
const silenced = LegacyCallHandler.instance.isCallSilenced(this.callId); const silenced = LegacyCallHandler.instance.isCallSilenced(this.callId);
silenced silenced
? LegacyCallHandler.instance.unSilenceCall(this.callId) ? LegacyCallHandler.instance.unSilenceCall(this.callId)
: LegacyCallHandler.instance.silenceCall(this.callId); : LegacyCallHandler.instance.silenceCall(this.callId);
}; };
private setCallListeners() { private setCallListeners(): void {
if (!this.call) return; if (!this.call) return;
this.call.addListener(CallEvent.State, this.setState); this.call.addListener(CallEvent.State, this.setState);
this.call.addListener(CallEvent.LengthChanged, this.onLengthChanged); this.call.addListener(CallEvent.LengthChanged, this.onLengthChanged);
} }
private setState = () => { private setState = (): void => {
if (CONNECTING_STATES.includes(this.call?.state)) { if (CONNECTING_STATES.includes(this.call?.state)) {
this.state = CallState.Connecting; this.state = CallState.Connecting;
} else if (SUPPORTED_STATES.includes(this.call?.state)) { } else if (SUPPORTED_STATES.includes(this.call?.state)) {
@ -190,7 +190,7 @@ export default class LegacyCallEventGrouper extends EventEmitter {
this.emit(LegacyCallEventGrouperEvent.StateChanged, this.state); this.emit(LegacyCallEventGrouperEvent.StateChanged, this.state);
}; };
private setCall = () => { private setCall = (): void => {
if (this.call) return; if (this.call) return;
this.call = LegacyCallHandler.instance.getCallById(this.callId); this.call = LegacyCallHandler.instance.getCallById(this.callId);
@ -198,7 +198,7 @@ export default class LegacyCallEventGrouper extends EventEmitter {
this.setState(); this.setState();
}; };
public add(event: MatrixEvent) { public add(event: MatrixEvent): void {
if (this.events.has(event)) return; // nothing to do if (this.events.has(event)) return; // nothing to do
this.events.add(event); this.events.add(event);
this.setCall(); this.setCall();

View File

@ -159,7 +159,7 @@ class LoggedInView extends React.Component<IProps, IState> {
this.resizeHandler = React.createRef(); this.resizeHandler = React.createRef();
} }
public componentDidMount() { public componentDidMount(): void {
document.addEventListener("keydown", this.onNativeKeyDown, false); document.addEventListener("keydown", this.onNativeKeyDown, false);
LegacyCallHandler.instance.addListener(LegacyCallHandlerEvent.CallState, this.onCallState); LegacyCallHandler.instance.addListener(LegacyCallHandlerEvent.CallState, this.onCallState);
@ -191,7 +191,7 @@ class LoggedInView extends React.Component<IProps, IState> {
this.refreshBackgroundImage(); this.refreshBackgroundImage();
} }
public componentWillUnmount() { public componentWillUnmount(): void {
document.removeEventListener("keydown", this.onNativeKeyDown, false); document.removeEventListener("keydown", this.onNativeKeyDown, false);
LegacyCallHandler.instance.removeListener(LegacyCallHandlerEvent.CallState, this.onCallState); LegacyCallHandler.instance.removeListener(LegacyCallHandlerEvent.CallState, this.onCallState);
this._matrixClient.removeListener(ClientEvent.AccountData, this.onAccountData); this._matrixClient.removeListener(ClientEvent.AccountData, this.onAccountData);
@ -221,14 +221,14 @@ class LoggedInView extends React.Component<IProps, IState> {
this.setState({ backgroundImage }); this.setState({ backgroundImage });
}; };
public canResetTimelineInRoom = (roomId: string) => { public canResetTimelineInRoom = (roomId: string): boolean => {
if (!this._roomView.current) { if (!this._roomView.current) {
return true; return true;
} }
return this._roomView.current.canResetTimeline(); return this._roomView.current.canResetTimeline();
}; };
private createResizer() { private createResizer(): Resizer {
let panelSize; let panelSize;
let panelCollapsed; let panelCollapsed;
const collapseConfig: ICollapseConfig = { const collapseConfig: ICollapseConfig = {
@ -268,7 +268,7 @@ class LoggedInView extends React.Component<IProps, IState> {
return resizer; return resizer;
} }
private loadResizerPreferences() { private loadResizerPreferences(): void {
let lhsSize = parseInt(window.localStorage.getItem("mx_lhs_size"), 10); let lhsSize = parseInt(window.localStorage.getItem("mx_lhs_size"), 10);
if (isNaN(lhsSize)) { if (isNaN(lhsSize)) {
lhsSize = 350; lhsSize = 350;
@ -276,13 +276,13 @@ class LoggedInView extends React.Component<IProps, IState> {
this.resizer.forHandleWithId("lp-resizer").resize(lhsSize); this.resizer.forHandleWithId("lp-resizer").resize(lhsSize);
} }
private onAccountData = (event: MatrixEvent) => { private onAccountData = (event: MatrixEvent): void => {
if (event.getType() === "m.ignored_user_list") { if (event.getType() === "m.ignored_user_list") {
dis.dispatch({ action: "ignore_state_changed" }); dis.dispatch({ action: "ignore_state_changed" });
} }
}; };
private onCompactLayoutChanged = () => { private onCompactLayoutChanged = (): void => {
this.setState({ this.setState({
useCompactLayout: SettingsStore.getValue("useCompactLayout"), useCompactLayout: SettingsStore.getValue("useCompactLayout"),
}); });
@ -311,13 +311,13 @@ class LoggedInView extends React.Component<IProps, IState> {
} }
}; };
private onUsageLimitDismissed = () => { private onUsageLimitDismissed = (): void => {
this.setState({ this.setState({
usageLimitDismissed: true, usageLimitDismissed: true,
}); });
}; };
private calculateServerLimitToast(syncError: IState["syncErrorData"], usageLimitEventContent?: IUsageLimit) { private calculateServerLimitToast(syncError: IState["syncErrorData"], usageLimitEventContent?: IUsageLimit): void {
const error = (syncError?.error as MatrixError)?.errcode === "M_RESOURCE_LIMIT_EXCEEDED"; const error = (syncError?.error as MatrixError)?.errcode === "M_RESOURCE_LIMIT_EXCEEDED";
if (error) { if (error) {
usageLimitEventContent = (syncError?.error as MatrixError).data as IUsageLimit; usageLimitEventContent = (syncError?.error as MatrixError).data as IUsageLimit;
@ -337,9 +337,9 @@ class LoggedInView extends React.Component<IProps, IState> {
} }
} }
private updateServerNoticeEvents = async () => { private updateServerNoticeEvents = async (): Promise<void> => {
const serverNoticeList = RoomListStore.instance.orderedLists[DefaultTagID.ServerNotice]; const serverNoticeList = RoomListStore.instance.orderedLists[DefaultTagID.ServerNotice];
if (!serverNoticeList) return []; if (!serverNoticeList) return;
const events = []; const events = [];
let pinnedEventTs = 0; let pinnedEventTs = 0;
@ -379,7 +379,7 @@ class LoggedInView extends React.Component<IProps, IState> {
}); });
}; };
private onPaste = (ev: ClipboardEvent) => { private onPaste = (ev: ClipboardEvent): void => {
const element = ev.target as HTMLElement; const element = ev.target as HTMLElement;
const inputableElement = getInputableElement(element); const inputableElement = getInputableElement(element);
if (inputableElement === document.activeElement) return; // nothing to do if (inputableElement === document.activeElement) return; // nothing to do
@ -422,13 +422,13 @@ class LoggedInView extends React.Component<IProps, IState> {
We also listen with a native listener on the document to get keydown events when no element is focused. We also listen with a native listener on the document to get keydown events when no element is focused.
Bubbling is irrelevant here as the target is the body element. Bubbling is irrelevant here as the target is the body element.
*/ */
private onReactKeyDown = (ev) => { private onReactKeyDown = (ev): void => {
// events caught while bubbling up on the root element // events caught while bubbling up on the root element
// of this component, so something must be focused. // of this component, so something must be focused.
this.onKeyDown(ev); this.onKeyDown(ev);
}; };
private onNativeKeyDown = (ev) => { private onNativeKeyDown = (ev): void => {
// only pass this if there is no focused element. // only pass this if there is no focused element.
// if there is, onKeyDown will be called by the // if there is, onKeyDown will be called by the
// react keydown handler that respects the react bubbling order. // react keydown handler that respects the react bubbling order.
@ -437,7 +437,7 @@ class LoggedInView extends React.Component<IProps, IState> {
} }
}; };
private onKeyDown = (ev) => { private onKeyDown = (ev): void => {
let handled = false; let handled = false;
const roomAction = getKeyBindingsManager().getRoomAction(ev); const roomAction = getKeyBindingsManager().getRoomAction(ev);
@ -615,13 +615,13 @@ class LoggedInView extends React.Component<IProps, IState> {
* dispatch a page-up/page-down/etc to the appropriate component * dispatch a page-up/page-down/etc to the appropriate component
* @param {Object} ev The key event * @param {Object} ev The key event
*/ */
private onScrollKeyPressed = (ev) => { private onScrollKeyPressed = (ev): void => {
if (this._roomView.current) { if (this._roomView.current) {
this._roomView.current.handleScrollKey(ev); this._roomView.current.handleScrollKey(ev);
} }
}; };
public render() { public render(): JSX.Element {
let pageElement; let pageElement;
switch (this.props.page_type) { switch (this.props.page_type) {

View File

@ -216,7 +216,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
realQueryParams: {}, realQueryParams: {},
startingFragmentQueryParams: {}, startingFragmentQueryParams: {},
config: {}, config: {},
onTokenLoginCompleted: () => {}, onTokenLoginCompleted: (): void => {},
}; };
private firstSyncComplete = false; private firstSyncComplete = false;
@ -317,7 +317,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
this.props.realQueryParams, this.props.realQueryParams,
this.props.defaultDeviceDisplayName, this.props.defaultDeviceDisplayName,
this.getFragmentAfterLogin(), this.getFragmentAfterLogin(),
).then(async (loggedIn) => { ).then(async (loggedIn): Promise<boolean | void> => {
if (this.props.realQueryParams?.loginToken) { if (this.props.realQueryParams?.loginToken) {
// remove the loginToken from the URL regardless // remove the loginToken from the URL regardless
this.props.onTokenLoginCompleted(); this.props.onTokenLoginCompleted();
@ -353,7 +353,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
initSentry(SdkConfig.get("sentry")); initSentry(SdkConfig.get("sentry"));
} }
private async postLoginSetup() { private async postLoginSetup(): Promise<void> {
const cli = MatrixClientPeg.get(); const cli = MatrixClientPeg.get();
const cryptoEnabled = cli.isCryptoEnabled(); const cryptoEnabled = cli.isCryptoEnabled();
if (!cryptoEnabled) { if (!cryptoEnabled) {
@ -367,7 +367,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
// as a proxy to figure out if it's worth prompting the user to verify // as a proxy to figure out if it's worth prompting the user to verify
// from another device. // from another device.
promisesList.push( promisesList.push(
(async () => { (async (): Promise<void> => {
crossSigningIsSetUp = await cli.userHasCrossSigningKeys(); crossSigningIsSetUp = await cli.userHasCrossSigningKeys();
})(), })(),
); );
@ -417,7 +417,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
window.addEventListener("resize", this.onWindowResized); window.addEventListener("resize", this.onWindowResized);
} }
public componentDidUpdate(prevProps, prevState) { public componentDidUpdate(prevProps, prevState): void {
if (this.shouldTrackPageChange(prevState, this.state)) { if (this.shouldTrackPageChange(prevState, this.state)) {
const durationMs = this.stopPageChangeTimer(); const durationMs = this.stopPageChangeTimer();
PosthogTrackers.instance.trackPageChange(this.state.view, this.state.page_type, durationMs); PosthogTrackers.instance.trackPageChange(this.state.view, this.state.page_type, durationMs);
@ -428,7 +428,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
} }
} }
public componentWillUnmount() { public componentWillUnmount(): void {
Lifecycle.stopMatrixClient(); Lifecycle.stopMatrixClient();
dis.unregister(this.dispatcherRef); dis.unregister(this.dispatcherRef);
this.themeWatcher.stop(); this.themeWatcher.stop();
@ -477,7 +477,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
} }
} }
private getServerProperties() { private getServerProperties(): { serverConfig: ValidatedServerConfig } {
let props = this.state.serverConfig; let props = this.state.serverConfig;
if (!props) props = this.props.serverConfig; // for unit tests if (!props) props = this.props.serverConfig; // for unit tests
if (!props) props = SdkConfig.get("validated_server_config"); if (!props) props = SdkConfig.get("validated_server_config");
@ -513,11 +513,11 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
// to try logging out. // to try logging out.
} }
private startPageChangeTimer() { private startPageChangeTimer(): void {
PerformanceMonitor.instance.start(PerformanceEntryNames.PAGE_CHANGE); PerformanceMonitor.instance.start(PerformanceEntryNames.PAGE_CHANGE);
} }
private stopPageChangeTimer() { private stopPageChangeTimer(): number | null {
const perfMonitor = PerformanceMonitor.instance; const perfMonitor = PerformanceMonitor.instance;
perfMonitor.stop(PerformanceEntryNames.PAGE_CHANGE); perfMonitor.stop(PerformanceEntryNames.PAGE_CHANGE);
@ -876,13 +876,13 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
} }
}; };
private setPage(pageType: PageType) { private setPage(pageType: PageType): void {
this.setState({ this.setState({
page_type: pageType, page_type: pageType,
}); });
} }
private async startRegistration(params: { [key: string]: string }) { private async startRegistration(params: { [key: string]: string }): Promise<void> {
const newState: Partial<IState> = { const newState: Partial<IState> = {
view: Views.REGISTER, view: Views.REGISTER,
}; };
@ -916,7 +916,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
} }
// switch view to the given room // switch view to the given room
private async viewRoom(roomInfo: ViewRoomPayload) { private async viewRoom(roomInfo: ViewRoomPayload): Promise<void> {
this.focusComposer = true; this.focusComposer = true;
if (roomInfo.room_alias) { if (roomInfo.room_alias) {
@ -992,7 +992,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
); );
} }
private viewSomethingBehindModal() { private viewSomethingBehindModal(): void {
if (this.state.view !== Views.LOGGED_IN) { if (this.state.view !== Views.LOGGED_IN) {
this.viewWelcome(); this.viewWelcome();
return; return;
@ -1002,7 +1002,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
} }
} }
private viewWelcome() { private viewWelcome(): void {
if (shouldUseLoginForWelcome(SdkConfig.get())) { if (shouldUseLoginForWelcome(SdkConfig.get())) {
return this.viewLogin(); return this.viewLogin();
} }
@ -1014,7 +1014,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
this.themeWatcher.recheck(); this.themeWatcher.recheck();
} }
private viewLogin(otherState?: any) { private viewLogin(otherState?: any): void {
this.setStateForNewView({ this.setStateForNewView({
view: Views.LOGIN, view: Views.LOGIN,
...otherState, ...otherState,
@ -1024,7 +1024,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
this.themeWatcher.recheck(); this.themeWatcher.recheck();
} }
private viewHome(justRegistered = false) { private viewHome(justRegistered = false): void {
// The home page requires the "logged in" view, so we'll set that. // The home page requires the "logged in" view, so we'll set that.
this.setStateForNewView({ this.setStateForNewView({
view: Views.LOGGED_IN, view: Views.LOGGED_IN,
@ -1037,7 +1037,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
this.themeWatcher.recheck(); this.themeWatcher.recheck();
} }
private viewUser(userId: string, subAction: string) { private viewUser(userId: string, subAction: string): void {
// Wait for the first sync so that `getRoom` gives us a room object if it's // Wait for the first sync so that `getRoom` gives us a room object if it's
// in the sync response // in the sync response
const waitForSync = this.firstSyncPromise ? this.firstSyncPromise.promise : Promise.resolve(); const waitForSync = this.firstSyncPromise ? this.firstSyncPromise.promise : Promise.resolve();
@ -1052,7 +1052,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
}); });
} }
private async createRoom(defaultPublic = false, defaultName?: string, type?: RoomType) { private async createRoom(defaultPublic = false, defaultName?: string, type?: RoomType): Promise<void> {
const modal = Modal.createDialog(CreateRoomDialog, { const modal = Modal.createDialog(CreateRoomDialog, {
type, type,
defaultPublic, defaultPublic,
@ -1065,7 +1065,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
} }
} }
private chatCreateOrReuse(userId: string) { private chatCreateOrReuse(userId: string): void {
const snakedConfig = new SnakedObject<IConfigOptions>(this.props.config); const snakedConfig = new SnakedObject<IConfigOptions>(this.props.config);
// Use a deferred action to reshow the dialog once the user has registered // Use a deferred action to reshow the dialog once the user has registered
if (MatrixClientPeg.get().isGuest()) { if (MatrixClientPeg.get().isGuest()) {
@ -1115,11 +1115,11 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
} }
} }
private leaveRoomWarnings(roomId: string) { private leaveRoomWarnings(roomId: string): JSX.Element[] {
const roomToLeave = MatrixClientPeg.get().getRoom(roomId); const roomToLeave = MatrixClientPeg.get().getRoom(roomId);
const isSpace = roomToLeave?.isSpaceRoom(); const isSpace = roomToLeave?.isSpaceRoom();
// Show a warning if there are additional complications. // Show a warning if there are additional complications.
const warnings = []; const warnings: JSX.Element[] = [];
const memberCount = roomToLeave.currentState.getJoinedMemberCount(); const memberCount = roomToLeave.currentState.getJoinedMemberCount();
if (memberCount === 1) { if (memberCount === 1) {
@ -1153,7 +1153,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
return warnings; return warnings;
} }
private leaveRoom(roomId: string) { private leaveRoom(roomId: string): void {
const roomToLeave = MatrixClientPeg.get().getRoom(roomId); const roomToLeave = MatrixClientPeg.get().getRoom(roomId);
const warnings = this.leaveRoomWarnings(roomId); const warnings = this.leaveRoomWarnings(roomId);
@ -1184,7 +1184,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
}); });
} }
private forgetRoom(roomId: string) { private forgetRoom(roomId: string): void {
const room = MatrixClientPeg.get().getRoom(roomId); const room = MatrixClientPeg.get().getRoom(roomId);
MatrixClientPeg.get() MatrixClientPeg.get()
.forget(roomId) .forget(roomId)
@ -1208,7 +1208,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
}); });
} }
private async copyRoom(roomId: string) { private async copyRoom(roomId: string): Promise<void> {
const roomLink = makeRoomPermalink(roomId); const roomLink = makeRoomPermalink(roomId);
const success = await copyPlaintext(roomLink); const success = await copyPlaintext(roomLink);
if (!success) { if (!success) {
@ -1223,13 +1223,13 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
* Starts a chat with the welcome user, if the user doesn't already have one * Starts a chat with the welcome user, if the user doesn't already have one
* @returns {string} The room ID of the new room, or null if no room was created * @returns {string} The room ID of the new room, or null if no room was created
*/ */
private async startWelcomeUserChat() { private async startWelcomeUserChat(): Promise<string | null> {
// We can end up with multiple tabs post-registration where the user // We can end up with multiple tabs post-registration where the user
// might then end up with a session and we don't want them all making // might then end up with a session and we don't want them all making
// a chat with the welcome user: try to de-dupe. // a chat with the welcome user: try to de-dupe.
// We need to wait for the first sync to complete for this to // We need to wait for the first sync to complete for this to
// work though. // work though.
let waitFor; let waitFor: Promise<void>;
if (!this.firstSyncComplete) { if (!this.firstSyncComplete) {
waitFor = this.firstSyncPromise.promise; waitFor = this.firstSyncPromise.promise;
} else { } else {
@ -1254,7 +1254,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
// run without the update to m.direct, making another welcome // run without the update to m.direct, making another welcome
// user room (it doesn't wait for new data from the server, just // user room (it doesn't wait for new data from the server, just
// the saved sync to be loaded). // the saved sync to be loaded).
const saveWelcomeUser = (ev: MatrixEvent) => { const saveWelcomeUser = (ev: MatrixEvent): void => {
if (ev.getType() === EventType.Direct && ev.getContent()[snakedConfig.get("welcome_user_id")]) { if (ev.getType() === EventType.Direct && ev.getContent()[snakedConfig.get("welcome_user_id")]) {
MatrixClientPeg.get().store.save(true); MatrixClientPeg.get().store.save(true);
MatrixClientPeg.get().removeListener(ClientEvent.AccountData, saveWelcomeUser); MatrixClientPeg.get().removeListener(ClientEvent.AccountData, saveWelcomeUser);
@ -1270,7 +1270,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
/** /**
* Called when a new logged in session has started * Called when a new logged in session has started
*/ */
private async onLoggedIn() { private async onLoggedIn(): Promise<void> {
ThemeController.isLogin = false; ThemeController.isLogin = false;
this.themeWatcher.recheck(); this.themeWatcher.recheck();
StorageManager.tryPersistStorage(); StorageManager.tryPersistStorage();
@ -1301,7 +1301,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
} }
} }
private async onShowPostLoginScreen(useCase?: UseCase) { private async onShowPostLoginScreen(useCase?: UseCase): Promise<void> {
if (useCase) { if (useCase) {
PosthogAnalytics.instance.setProperty("ftueUseCaseSelection", useCase); PosthogAnalytics.instance.setProperty("ftueUseCaseSelection", useCase);
SettingsStore.setValue("FTUE.useCaseSelection", null, SettingLevel.ACCOUNT, useCase); SettingsStore.setValue("FTUE.useCaseSelection", null, SettingLevel.ACCOUNT, useCase);
@ -1370,7 +1370,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
} }
} }
private initPosthogAnalyticsToast() { private initPosthogAnalyticsToast(): void {
// Show the analytics toast if necessary // Show the analytics toast if necessary
if (SettingsStore.getValue("pseudonymousAnalyticsOptIn") === null) { if (SettingsStore.getValue("pseudonymousAnalyticsOptIn") === null) {
showAnalyticsToast(); showAnalyticsToast();
@ -1397,7 +1397,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
); );
} }
private showScreenAfterLogin() { private showScreenAfterLogin(): void {
// If screenAfterLogin is set, use that, then null it so that a second login will // If screenAfterLogin is set, use that, then null it so that a second login will
// result in view_home_page, _user_settings or _room_directory // result in view_home_page, _user_settings or _room_directory
if (this.screenAfterLogin && this.screenAfterLogin.screen) { if (this.screenAfterLogin && this.screenAfterLogin.screen) {
@ -1415,7 +1415,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
} }
} }
private viewLastRoom() { private viewLastRoom(): void {
dis.dispatch<ViewRoomPayload>({ dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
room_id: localStorage.getItem("mx_last_room_id"), room_id: localStorage.getItem("mx_last_room_id"),
@ -1426,7 +1426,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
/** /**
* Called when the session is logged out * Called when the session is logged out
*/ */
private onLoggedOut() { private onLoggedOut(): void {
this.viewLogin({ this.viewLogin({
ready: false, ready: false,
collapseLhs: false, collapseLhs: false,
@ -1439,7 +1439,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
/** /**
* Called when the session is softly logged out * Called when the session is softly logged out
*/ */
private onSoftLogout() { private onSoftLogout(): void {
this.notifyNewScreen("soft_logout"); this.notifyNewScreen("soft_logout");
this.setStateForNewView({ this.setStateForNewView({
view: Views.SOFT_LOGOUT, view: Views.SOFT_LOGOUT,
@ -1455,7 +1455,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
* Called just before the matrix client is started * Called just before the matrix client is started
* (useful for setting listeners) * (useful for setting listeners)
*/ */
private onWillStartClient() { private onWillStartClient(): void {
// reset the 'have completed first sync' flag, // reset the 'have completed first sync' flag,
// since we're about to start the client and therefore about // since we're about to start the client and therefore about
// to do the first sync // to do the first sync
@ -1610,7 +1610,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
break; break;
} }
}); });
cli.on(CryptoEvent.KeyBackupFailed, async (errcode) => { cli.on(CryptoEvent.KeyBackupFailed, async (errcode): Promise<void> => {
let haveNewVersion; let haveNewVersion;
let newVersionInfo; let newVersionInfo;
// if key backup is still enabled, there must be a new backup in place // if key backup is still enabled, there must be a new backup in place
@ -1678,7 +1678,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
* setting up anything that requires the client to be started. * setting up anything that requires the client to be started.
* @private * @private
*/ */
private onClientStarted() { private onClientStarted(): void {
const cli = MatrixClientPeg.get(); const cli = MatrixClientPeg.get();
if (cli.isCryptoEnabled()) { if (cli.isCryptoEnabled()) {
@ -1700,7 +1700,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
} }
} }
public showScreen(screen: string, params?: { [key: string]: any }) { public showScreen(screen: string, params?: { [key: string]: any }): void {
const cli = MatrixClientPeg.get(); const cli = MatrixClientPeg.get();
const isLoggedOutOrGuest = !cli || cli.isGuest(); const isLoggedOutOrGuest = !cli || cli.isGuest();
if (!isLoggedOutOrGuest && AUTH_SCREENS.includes(screen)) { if (!isLoggedOutOrGuest && AUTH_SCREENS.includes(screen)) {
@ -1861,14 +1861,14 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
} }
} }
private notifyNewScreen(screen: string, replaceLast = false) { private notifyNewScreen(screen: string, replaceLast = false): void {
if (this.props.onNewScreen) { if (this.props.onNewScreen) {
this.props.onNewScreen(screen, replaceLast); this.props.onNewScreen(screen, replaceLast);
} }
this.setPageSubtitle(); this.setPageSubtitle();
} }
private onLogoutClick(event: React.MouseEvent<HTMLAnchorElement, MouseEvent>) { private onLogoutClick(event: React.MouseEvent<HTMLAnchorElement, MouseEvent>): void {
dis.dispatch({ dis.dispatch({
action: "logout", action: "logout",
}); });
@ -1876,7 +1876,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
event.preventDefault(); event.preventDefault();
} }
private handleResize = () => { private handleResize = (): void => {
const LHS_THRESHOLD = 1000; const LHS_THRESHOLD = 1000;
const width = UIStore.instance.windowWidth; const width = UIStore.instance.windowWidth;
@ -1892,19 +1892,19 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
this.state.resizeNotifier.notifyWindowResized(); this.state.resizeNotifier.notifyWindowResized();
}; };
private dispatchTimelineResize() { private dispatchTimelineResize(): void {
dis.dispatch({ action: "timeline_resize" }); dis.dispatch({ action: "timeline_resize" });
} }
private onRegisterClick = () => { private onRegisterClick = (): void => {
this.showScreen("register"); this.showScreen("register");
}; };
private onLoginClick = () => { private onLoginClick = (): void => {
this.showScreen("login"); this.showScreen("login");
}; };
private onForgotPasswordClick = () => { private onForgotPasswordClick = (): void => {
this.showScreen("forgot_password"); this.showScreen("forgot_password");
}; };
@ -1926,7 +1926,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
}); });
} }
private setPageSubtitle(subtitle = "") { private setPageSubtitle(subtitle = ""): void {
if (this.state.currentRoomId) { if (this.state.currentRoomId) {
const client = MatrixClientPeg.get(); const client = MatrixClientPeg.get();
const room = client && client.getRoom(this.state.currentRoomId); const room = client && client.getRoom(this.state.currentRoomId);
@ -1963,11 +1963,11 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
this.setPageSubtitle(); this.setPageSubtitle();
}; };
private onServerConfigChange = (serverConfig: ValidatedServerConfig) => { private onServerConfigChange = (serverConfig: ValidatedServerConfig): void => {
this.setState({ serverConfig }); this.setState({ serverConfig });
}; };
private makeRegistrationUrl = (params: QueryDict) => { private makeRegistrationUrl = (params: QueryDict): string => {
if (this.props.startingFragmentQueryParams.referrer) { if (this.props.startingFragmentQueryParams.referrer) {
params.referrer = this.props.startingFragmentQueryParams.referrer; params.referrer = this.props.startingFragmentQueryParams.referrer;
} }
@ -2016,7 +2016,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
return fragmentAfterLogin; return fragmentAfterLogin;
} }
public render() { public render(): JSX.Element {
const fragmentAfterLogin = this.getFragmentAfterLogin(); const fragmentAfterLogin = this.getFragmentAfterLogin();
let view = null; let view = null;
@ -2132,7 +2132,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
/> />
); );
} else if (this.state.view === Views.USE_CASE_SELECTION) { } else if (this.state.view === Views.USE_CASE_SELECTION) {
view = <UseCaseSelection onFinished={(useCase) => this.onShowPostLoginScreen(useCase)} />; view = <UseCaseSelection onFinished={(useCase): Promise<void> => this.onShowPostLoginScreen(useCase)} />;
} else { } else {
logger.error(`Unknown view ${this.state.view}`); logger.error(`Unknown view ${this.state.view}`);
} }

View File

@ -296,19 +296,19 @@ export default class MessagePanel extends React.Component<IProps, IState> {
); );
} }
public componentDidMount() { public componentDidMount(): void {
this.calculateRoomMembersCount(); this.calculateRoomMembersCount();
this.props.room?.currentState.on(RoomStateEvent.Update, this.calculateRoomMembersCount); this.props.room?.currentState.on(RoomStateEvent.Update, this.calculateRoomMembersCount);
this.isMounted = true; this.isMounted = true;
} }
public componentWillUnmount() { public componentWillUnmount(): void {
this.isMounted = false; this.isMounted = false;
this.props.room?.currentState.off(RoomStateEvent.Update, this.calculateRoomMembersCount); this.props.room?.currentState.off(RoomStateEvent.Update, this.calculateRoomMembersCount);
SettingsStore.unwatchSetting(this.showTypingNotificationsWatcherRef); SettingsStore.unwatchSetting(this.showTypingNotificationsWatcherRef);
} }
public componentDidUpdate(prevProps, prevState) { public componentDidUpdate(prevProps, prevState): void {
if (prevProps.layout !== this.props.layout) { if (prevProps.layout !== this.props.layout) {
this.calculateRoomMembersCount(); this.calculateRoomMembersCount();
} }
@ -752,7 +752,7 @@ export default class MessagePanel extends React.Component<IProps, IState> {
const readReceipts = this.readReceiptsByEvent[eventId]; const readReceipts = this.readReceiptsByEvent[eventId];
let isLastSuccessful = false; let isLastSuccessful = false;
const isSentState = (s) => !s || s === "sent"; const isSentState = (s): boolean => !s || s === "sent";
const isSent = isSentState(mxEv.getAssociatedStatus()); const isSent = isSentState(mxEv.getAssociatedStatus());
const hasNextEvent = nextEvent && this.shouldShowEvent(nextEvent); const hasNextEvent = nextEvent && this.shouldShowEvent(nextEvent);
if (!hasNextEvent && isSent) { if (!hasNextEvent && isSent) {
@ -982,7 +982,7 @@ export default class MessagePanel extends React.Component<IProps, IState> {
} }
} }
public render() { public render(): JSX.Element {
let topSpinner; let topSpinner;
let bottomSpinner; let bottomSpinner;
if (this.props.backPaginating) { if (this.props.backPaginating) {

View File

@ -37,15 +37,15 @@ export default class NonUrgentToastContainer extends React.PureComponent<IProps,
NonUrgentToastStore.instance.on(UPDATE_EVENT, this.onUpdateToasts); NonUrgentToastStore.instance.on(UPDATE_EVENT, this.onUpdateToasts);
} }
public componentWillUnmount() { public componentWillUnmount(): void {
NonUrgentToastStore.instance.off(UPDATE_EVENT, this.onUpdateToasts); NonUrgentToastStore.instance.off(UPDATE_EVENT, this.onUpdateToasts);
} }
private onUpdateToasts = () => { private onUpdateToasts = (): void => {
this.setState({ toasts: NonUrgentToastStore.instance.components }); this.setState({ toasts: NonUrgentToastStore.instance.components });
}; };
public render() { public render(): JSX.Element {
const toasts = this.state.toasts.map((t, i) => { const toasts = this.state.toasts.map((t, i) => {
return ( return (
<div className="mx_NonUrgentToastContainer_toast" key={`toast-${i}`}> <div className="mx_NonUrgentToastContainer_toast" key={`toast-${i}`}>

View File

@ -55,7 +55,7 @@ export default class NotificationPanel extends React.PureComponent<IProps, IStat
this.setState({ narrow }); this.setState({ narrow });
}; };
public render() { public render(): JSX.Element {
const emptyState = ( const emptyState = (
<div className="mx_RightPanel_empty mx_NotificationPanel_empty"> <div className="mx_RightPanel_empty mx_NotificationPanel_empty">
<h2>{_t("You're all caught up")}</h2> <h2>{_t("You're all caught up")}</h2>

View File

@ -79,7 +79,7 @@ export default class PictureInPictureDragger extends React.Component<IProps> {
this._moving = value; this._moving = value;
} }
public componentDidMount() { public componentDidMount(): void {
document.addEventListener("mousemove", this.onMoving); document.addEventListener("mousemove", this.onMoving);
document.addEventListener("mouseup", this.onEndMoving); document.addEventListener("mouseup", this.onEndMoving);
UIStore.instance.on(UI_EVENTS.Resize, this.onResize); UIStore.instance.on(UI_EVENTS.Resize, this.onResize);
@ -87,7 +87,7 @@ export default class PictureInPictureDragger extends React.Component<IProps> {
this.snap(); this.snap();
} }
public componentWillUnmount() { public componentWillUnmount(): void {
document.removeEventListener("mousemove", this.onMoving); document.removeEventListener("mousemove", this.onMoving);
document.removeEventListener("mouseup", this.onEndMoving); document.removeEventListener("mouseup", this.onEndMoving);
UIStore.instance.off(UI_EVENTS.Resize, this.onResize); UIStore.instance.off(UI_EVENTS.Resize, this.onResize);
@ -97,7 +97,7 @@ export default class PictureInPictureDragger extends React.Component<IProps> {
if (prevProps.children !== this.props.children) this.snap(true); if (prevProps.children !== this.props.children) this.snap(true);
} }
private animationCallback = () => { private animationCallback = (): void => {
if ( if (
!this.moving && !this.moving &&
Math.abs(this.translationX - this.desiredTranslationX) <= 1 && Math.abs(this.translationX - this.desiredTranslationX) <= 1 &&
@ -119,13 +119,13 @@ export default class PictureInPictureDragger extends React.Component<IProps> {
this.props.onMove?.(); this.props.onMove?.();
}; };
private setStyle = () => { private setStyle = (): void => {
if (!this.callViewWrapper.current) return; if (!this.callViewWrapper.current) return;
// Set the element's style directly, bypassing React for efficiency // Set the element's style directly, bypassing React for efficiency
this.callViewWrapper.current.style.transform = `translateX(${this.translationX}px) translateY(${this.translationY}px)`; this.callViewWrapper.current.style.transform = `translateX(${this.translationX}px) translateY(${this.translationY}px)`;
}; };
private setTranslation(inTranslationX: number, inTranslationY: number) { private setTranslation(inTranslationX: number, inTranslationY: number): void {
const width = this.callViewWrapper.current?.clientWidth || PIP_VIEW_WIDTH; const width = this.callViewWrapper.current?.clientWidth || PIP_VIEW_WIDTH;
const height = this.callViewWrapper.current?.clientHeight || PIP_VIEW_HEIGHT; const height = this.callViewWrapper.current?.clientHeight || PIP_VIEW_HEIGHT;
@ -152,7 +152,7 @@ export default class PictureInPictureDragger extends React.Component<IProps> {
this.snap(false); this.snap(false);
}; };
private snap = (animate = false) => { private snap = (animate = false): void => {
const translationX = this.desiredTranslationX; const translationX = this.desiredTranslationX;
const translationY = this.desiredTranslationY; const translationY = this.desiredTranslationY;
// We subtract the PiP size from the window size in order to calculate // We subtract the PiP size from the window size in order to calculate
@ -187,14 +187,14 @@ export default class PictureInPictureDragger extends React.Component<IProps> {
this.scheduledUpdate.mark(); this.scheduledUpdate.mark();
}; };
private onStartMoving = (event: React.MouseEvent | MouseEvent) => { private onStartMoving = (event: React.MouseEvent | MouseEvent): void => {
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
this.mouseHeld = true; this.mouseHeld = true;
}; };
private onMoving = (event: MouseEvent) => { private onMoving = (event: MouseEvent): void => {
if (!this.mouseHeld) return; if (!this.mouseHeld) return;
event.preventDefault(); event.preventDefault();
@ -210,7 +210,7 @@ export default class PictureInPictureDragger extends React.Component<IProps> {
this.setTranslation(event.pageX - this.initX, event.pageY - this.initY); this.setTranslation(event.pageX - this.initX, event.pageY - this.initY);
}; };
private onEndMoving = (event: MouseEvent) => { private onEndMoving = (event: MouseEvent): void => {
if (!this.mouseHeld) return; if (!this.mouseHeld) return;
event.preventDefault(); event.preventDefault();
@ -223,7 +223,7 @@ export default class PictureInPictureDragger extends React.Component<IProps> {
this.snap(true); this.snap(true);
}; };
private onClickCapture = (event: React.MouseEvent) => { private onClickCapture = (event: React.MouseEvent): void => {
// To prevent mouse up events during dragging from being double-counted // To prevent mouse up events during dragging from being double-counted
// as clicks, we cancel clicks before they ever reach the target // as clicks, we cancel clicks before they ever reach the target
if (this.moving) { if (this.moving) {
@ -232,7 +232,7 @@ export default class PictureInPictureDragger extends React.Component<IProps> {
} }
}; };
public render() { public render(): JSX.Element {
const style = { const style = {
transform: `translateX(${this.translationX}px) translateY(${this.translationY}px)`, transform: `translateX(${this.translationX}px) translateY(${this.translationY}px)`,
}; };

View File

@ -135,7 +135,7 @@ class PipContainerInner extends React.Component<IProps, IState> {
}; };
} }
public componentDidMount() { public componentDidMount(): void {
LegacyCallHandler.instance.addListener(LegacyCallHandlerEvent.CallChangeRoom, this.updateCalls); LegacyCallHandler.instance.addListener(LegacyCallHandlerEvent.CallChangeRoom, this.updateCalls);
LegacyCallHandler.instance.addListener(LegacyCallHandlerEvent.CallState, this.updateCalls); LegacyCallHandler.instance.addListener(LegacyCallHandlerEvent.CallState, this.updateCalls);
SdkContextClass.instance.roomViewStore.addListener(UPDATE_EVENT, this.onRoomViewStoreUpdate); SdkContextClass.instance.roomViewStore.addListener(UPDATE_EVENT, this.onRoomViewStoreUpdate);
@ -149,7 +149,7 @@ class PipContainerInner extends React.Component<IProps, IState> {
ActiveWidgetStore.instance.on(ActiveWidgetStoreEvent.Undock, this.onWidgetDockChanges); ActiveWidgetStore.instance.on(ActiveWidgetStoreEvent.Undock, this.onWidgetDockChanges);
} }
public componentWillUnmount() { public componentWillUnmount(): void {
LegacyCallHandler.instance.removeListener(LegacyCallHandlerEvent.CallChangeRoom, this.updateCalls); LegacyCallHandler.instance.removeListener(LegacyCallHandlerEvent.CallChangeRoom, this.updateCalls);
LegacyCallHandler.instance.removeListener(LegacyCallHandlerEvent.CallState, this.updateCalls); LegacyCallHandler.instance.removeListener(LegacyCallHandlerEvent.CallState, this.updateCalls);
const cli = MatrixClientPeg.get(); const cli = MatrixClientPeg.get();
@ -164,9 +164,9 @@ class PipContainerInner extends React.Component<IProps, IState> {
ActiveWidgetStore.instance.off(ActiveWidgetStoreEvent.Undock, this.onWidgetDockChanges); ActiveWidgetStore.instance.off(ActiveWidgetStoreEvent.Undock, this.onWidgetDockChanges);
} }
private onMove = () => this.props.movePersistedElement.current?.(); private onMove = (): void => this.props.movePersistedElement.current?.();
private onRoomViewStoreUpdate = () => { private onRoomViewStoreUpdate = (): void => {
const newRoomId = SdkContextClass.instance.roomViewStore.getRoomId(); const newRoomId = SdkContextClass.instance.roomViewStore.getRoomId();
const oldRoomId = this.state.viewedRoomId; const oldRoomId = this.state.viewedRoomId;
if (newRoomId === oldRoomId) return; if (newRoomId === oldRoomId) return;
@ -213,7 +213,7 @@ class PipContainerInner extends React.Component<IProps, IState> {
this.updateShowWidgetInPip(); this.updateShowWidgetInPip();
}; };
private onCallRemoteHold = () => { private onCallRemoteHold = (): void => {
if (!this.state.viewedRoomId) return; if (!this.state.viewedRoomId) return;
const [primaryCall, secondaryCalls] = getPrimarySecondaryCallsForPip(this.state.viewedRoomId); const [primaryCall, secondaryCalls] = getPrimarySecondaryCallsForPip(this.state.viewedRoomId);
@ -238,7 +238,7 @@ class PipContainerInner extends React.Component<IProps, IState> {
public updateShowWidgetInPip( public updateShowWidgetInPip(
persistentWidgetId = this.state.persistentWidgetId, persistentWidgetId = this.state.persistentWidgetId,
persistentRoomId = this.state.persistentRoomId, persistentRoomId = this.state.persistentRoomId,
) { ): void {
let fromAnotherRoom = false; let fromAnotherRoom = false;
let notDocked = false; let notDocked = false;
// Sanity check the room - the widget may have been destroyed between render cycles, and // Sanity check the room - the widget may have been destroyed between render cycles, and
@ -293,7 +293,7 @@ class PipContainerInner extends React.Component<IProps, IState> {
); );
} }
public render() { public render(): JSX.Element {
const pipMode = true; const pipMode = true;
let pipContent: Array<CreatePipChildren> = []; let pipContent: Array<CreatePipChildren> = [];

View File

@ -101,7 +101,7 @@ export default class RightPanel extends React.Component<IProps, IState> {
}; };
} }
private onRoomStateMember = (ev: MatrixEvent, state: RoomState, member: RoomMember) => { private onRoomStateMember = (ev: MatrixEvent, state: RoomState, member: RoomMember): void => {
if (!this.props.room || member.roomId !== this.props.room.roomId) { if (!this.props.room || member.roomId !== this.props.room.roomId) {
return; return;
} }
@ -118,11 +118,11 @@ export default class RightPanel extends React.Component<IProps, IState> {
} }
}; };
private onRightPanelStoreUpdate = () => { private onRightPanelStoreUpdate = (): void => {
this.setState({ ...(RightPanel.getDerivedStateFromProps(this.props) as IState) }); this.setState({ ...(RightPanel.getDerivedStateFromProps(this.props) as IState) });
}; };
private onClose = () => { private onClose = (): void => {
// XXX: There are three different ways of 'closing' this panel depending on what state // XXX: There are three different ways of 'closing' this panel depending on what state
// things are in... this knows far more than it should do about the state of the rest // things are in... this knows far more than it should do about the state of the rest
// of the app and is generally a bit silly. // of the app and is generally a bit silly.

View File

@ -39,15 +39,15 @@ export default class RoomSearch extends React.PureComponent<IProps> {
this.dispatcherRef = defaultDispatcher.register(this.onAction); this.dispatcherRef = defaultDispatcher.register(this.onAction);
} }
public componentWillUnmount() { public componentWillUnmount(): void {
defaultDispatcher.unregister(this.dispatcherRef); defaultDispatcher.unregister(this.dispatcherRef);
} }
private openSpotlight() { private openSpotlight(): void {
Modal.createDialog(SpotlightDialog, {}, "mx_SpotlightDialog_wrapper", false, true); Modal.createDialog(SpotlightDialog, {}, "mx_SpotlightDialog_wrapper", false, true);
} }
private onAction = (payload: ActionPayload) => { private onAction = (payload: ActionPayload): void => {
if (payload.action === "focus_room_filter") { if (payload.action === "focus_room_filter") {
this.openSpotlight(); this.openSpotlight();
} }

View File

@ -37,7 +37,7 @@ import RoomContext from "../../contexts/RoomContext";
import SettingsStore from "../../settings/SettingsStore"; import SettingsStore from "../../settings/SettingsStore";
const DEBUG = false; const DEBUG = false;
let debuglog = function (msg: string) {}; let debuglog = function (msg: string): void {};
/* istanbul ignore next */ /* istanbul ignore next */
if (DEBUG) { if (DEBUG) {
@ -76,7 +76,7 @@ export const RoomSearchView = forwardRef<ScrollPanel, Props>(
return searchPromise return searchPromise
.then( .then(
async (results) => { async (results): Promise<boolean> => {
debuglog("search complete"); debuglog("search complete");
if (aborted.current) { if (aborted.current) {
logger.error("Discarding stale search results"); logger.error("Discarding stale search results");
@ -209,7 +209,7 @@ export const RoomSearchView = forwardRef<ScrollPanel, Props>(
// once dynamic content in the search results load, make the scrollPanel check // once dynamic content in the search results load, make the scrollPanel check
// the scroll offsets. // the scroll offsets.
const onHeightChanged = () => { const onHeightChanged = (): void => {
const scrollPanel = ref.current; const scrollPanel = ref.current;
scrollPanel?.checkScroll(); scrollPanel?.checkScroll();
}; };

View File

@ -146,7 +146,7 @@ export default class RoomStatusBar extends React.PureComponent<IProps, IState> {
dis.fire(Action.FocusSendMessageComposer); dis.fire(Action.FocusSendMessageComposer);
}; };
private onRoomLocalEchoUpdated = (ev: MatrixEvent, room: Room) => { private onRoomLocalEchoUpdated = (ev: MatrixEvent, room: Room): void => {
if (room.roomId !== this.props.room.roomId) return; if (room.roomId !== this.props.room.roomId) return;
const messages = getUnsentMessages(this.props.room); const messages = getUnsentMessages(this.props.room);
this.setState({ this.setState({

View File

@ -115,7 +115,7 @@ import VoipUserMapper from "../../VoipUserMapper";
import { isCallEvent } from "./LegacyCallEventGrouper"; import { isCallEvent } from "./LegacyCallEventGrouper";
const DEBUG = false; const DEBUG = false;
let debuglog = function (msg: string) {}; let debuglog = function (msg: string): void {};
const BROWSER_SUPPORTS_SANDBOX = "sandbox" in document.createElement("iframe"); const BROWSER_SUPPORTS_SANDBOX = "sandbox" in document.createElement("iframe");
@ -248,7 +248,7 @@ function LocalRoomView(props: LocalRoomViewProps): ReactElement {
encryptionTile = <EncryptionEvent mxEvent={encryptionEvent} />; encryptionTile = <EncryptionEvent mxEvent={encryptionEvent} />;
} }
const onRetryClicked = () => { const onRetryClicked = (): void => {
room.state = LocalRoomState.NEW; room.state = LocalRoomState.NEW;
defaultDispatcher.dispatch({ defaultDispatcher.dispatch({
action: "local_room_event", action: "local_room_event",
@ -470,21 +470,21 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
]; ];
} }
private onIsResizing = (resizing: boolean) => { private onIsResizing = (resizing: boolean): void => {
this.setState({ resizing }); this.setState({ resizing });
}; };
private onWidgetStoreUpdate = () => { private onWidgetStoreUpdate = (): void => {
if (!this.state.room) return; if (!this.state.room) return;
this.checkWidgets(this.state.room); this.checkWidgets(this.state.room);
}; };
private onWidgetEchoStoreUpdate = () => { private onWidgetEchoStoreUpdate = (): void => {
if (!this.state.room) return; if (!this.state.room) return;
this.checkWidgets(this.state.room); this.checkWidgets(this.state.room);
}; };
private onWidgetLayoutChange = () => { private onWidgetLayoutChange = (): void => {
if (!this.state.room) return; if (!this.state.room) return;
dis.dispatch({ dis.dispatch({
action: "appsDrawer", action: "appsDrawer",
@ -505,7 +505,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
}); });
}; };
private getMainSplitContentType = (room: Room) => { private getMainSplitContentType = (room: Room): MainSplitContentType => {
if ( if (
(SettingsStore.getValue("feature_group_calls") && this.context.roomViewStore.isViewingCall()) || (SettingsStore.getValue("feature_group_calls") && this.context.roomViewStore.isViewingCall()) ||
isVideoRoom(room) isVideoRoom(room)
@ -707,7 +707,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
} }
}; };
private onActiveCalls = () => { private onActiveCalls = (): void => {
if (this.state.roomId === undefined) return; if (this.state.roomId === undefined) return;
const activeCall = CallStore.instance.getActiveCall(this.state.roomId); const activeCall = CallStore.instance.getActiveCall(this.state.roomId);
@ -727,7 +727,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
this.setState({ activeCall }); this.setState({ activeCall });
}; };
private getRoomId = () => { private getRoomId = (): string => {
// According to `onRoomViewStoreUpdate`, `state.roomId` can be null // According to `onRoomViewStoreUpdate`, `state.roomId` can be null
// if we have a room alias we haven't resolved yet. To work around this, // if we have a room alias we haven't resolved yet. To work around this,
// first we'll try the room object if it's there, and then fallback to // first we'll try the room object if it's there, and then fallback to
@ -736,7 +736,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
return this.state.room ? this.state.room.roomId : this.state.roomId; return this.state.room ? this.state.room.roomId : this.state.roomId;
}; };
private getPermalinkCreatorForRoom(room: Room) { private getPermalinkCreatorForRoom(room: Room): RoomPermalinkCreator {
if (this.permalinkCreators[room.roomId]) return this.permalinkCreators[room.roomId]; if (this.permalinkCreators[room.roomId]) return this.permalinkCreators[room.roomId];
this.permalinkCreators[room.roomId] = new RoomPermalinkCreator(room); this.permalinkCreators[room.roomId] = new RoomPermalinkCreator(room);
@ -750,14 +750,14 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
return this.permalinkCreators[room.roomId]; return this.permalinkCreators[room.roomId];
} }
private stopAllPermalinkCreators() { private stopAllPermalinkCreators(): void {
if (!this.permalinkCreators) return; if (!this.permalinkCreators) return;
for (const roomId of Object.keys(this.permalinkCreators)) { for (const roomId of Object.keys(this.permalinkCreators)) {
this.permalinkCreators[roomId].stop(); this.permalinkCreators[roomId].stop();
} }
} }
private setupRoom(room: Room, roomId: string, joining: boolean, shouldPeek: boolean) { private setupRoom(room: Room, roomId: string, joining: boolean, shouldPeek: boolean): void {
// if this is an unknown room then we're in one of three states: // if this is an unknown room then we're in one of three states:
// - This is a room we can peek into (search engine) (we can /peek) // - This is a room we can peek into (search engine) (we can /peek)
// - This is a room we can publicly join or were invited to. (we can /join) // - This is a room we can publicly join or were invited to. (we can /join)
@ -822,7 +822,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
} }
} }
private shouldShowApps(room: Room) { private shouldShowApps(room: Room): boolean {
if (!BROWSER_SUPPORTS_SANDBOX || !room) return false; if (!BROWSER_SUPPORTS_SANDBOX || !room) return false;
// Check if user has previously chosen to hide the app drawer for this // Check if user has previously chosen to hide the app drawer for this
@ -838,7 +838,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
return isManuallyShown && widgets.length > 0; return isManuallyShown && widgets.length > 0;
} }
public componentDidMount() { public componentDidMount(): void {
this.onRoomViewStoreUpdate(true); this.onRoomViewStoreUpdate(true);
const call = this.getCallForRoom(); const call = this.getCallForRoom();
@ -851,7 +851,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
window.addEventListener("beforeunload", this.onPageUnload); window.addEventListener("beforeunload", this.onPageUnload);
} }
public shouldComponentUpdate(nextProps, nextState) { public shouldComponentUpdate(nextProps, nextState): boolean {
const hasPropsDiff = objectHasDiff(this.props, nextProps); const hasPropsDiff = objectHasDiff(this.props, nextProps);
const { upgradeRecommendation, ...state } = this.state; const { upgradeRecommendation, ...state } = this.state;
@ -864,7 +864,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
return hasPropsDiff || hasStateDiff; return hasPropsDiff || hasStateDiff;
} }
public componentDidUpdate() { public componentDidUpdate(): void {
// Note: We check the ref here with a flag because componentDidMount, despite // Note: We check the ref here with a flag because componentDidMount, despite
// documentation, does not define our messagePanel ref. It looks like our spinner // documentation, does not define our messagePanel ref. It looks like our spinner
// in render() prevents the ref from being set on first mount, so we try and // in render() prevents the ref from being set on first mount, so we try and
@ -877,7 +877,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
} }
} }
public componentWillUnmount() { public componentWillUnmount(): void {
// set a boolean to say we've been unmounted, which any pending // set a boolean to say we've been unmounted, which any pending
// promises can use to throw away their results. // promises can use to throw away their results.
// //
@ -947,13 +947,13 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
} }
} }
private onRightPanelStoreUpdate = () => { private onRightPanelStoreUpdate = (): void => {
this.setState({ this.setState({
showRightPanel: this.context.rightPanelStore.isOpenForRoom(this.state.roomId), showRightPanel: this.context.rightPanelStore.isOpenForRoom(this.state.roomId),
}); });
}; };
private onPageUnload = (event) => { private onPageUnload = (event): string => {
if (ContentMessages.sharedInstance().getCurrentUploads().length > 0) { if (ContentMessages.sharedInstance().getCurrentUploads().length > 0) {
return (event.returnValue = _t("You seem to be uploading files, are you sure you want to quit?")); return (event.returnValue = _t("You seem to be uploading files, are you sure you want to quit?"));
} else if (this.getCallForRoom() && this.state.callState !== "ended") { } else if (this.getCallForRoom() && this.state.callState !== "ended") {
@ -961,7 +961,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
} }
}; };
private onReactKeyDown = (ev) => { private onReactKeyDown = (ev): void => {
let handled = false; let handled = false;
const action = getKeyBindingsManager().getRoomAction(ev); const action = getKeyBindingsManager().getRoomAction(ev);
@ -1120,12 +1120,12 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
} }
}; };
private onLocalRoomEvent(roomId: string) { private onLocalRoomEvent(roomId: string): void {
if (roomId !== this.state.room.roomId) return; if (roomId !== this.state.room.roomId) return;
createRoomFromLocalRoom(this.context.client, this.state.room as LocalRoom); createRoomFromLocalRoom(this.context.client, this.state.room as LocalRoom);
} }
private onRoomTimeline = (ev: MatrixEvent, room: Room | null, toStartOfTimeline: boolean, removed, data) => { private onRoomTimeline = (ev: MatrixEvent, room: Room | null, toStartOfTimeline: boolean, removed, data): void => {
if (this.unmounted) return; if (this.unmounted) return;
// ignore events for other rooms or the notification timeline set // ignore events for other rooms or the notification timeline set
@ -1167,7 +1167,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
} }
}; };
private onEventDecrypted = (ev: MatrixEvent) => { private onEventDecrypted = (ev: MatrixEvent): void => {
if (!this.state.room || !this.state.matrixClientIsReady) return; // not ready at all if (!this.state.room || !this.state.matrixClientIsReady) return; // not ready at all
if (ev.getRoomId() !== this.state.room.roomId) return; // not for us if (ev.getRoomId() !== this.state.room.roomId) return; // not for us
this.updateVisibleDecryptionFailures(); this.updateVisibleDecryptionFailures();
@ -1175,7 +1175,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
this.handleEffects(ev); this.handleEffects(ev);
}; };
private handleEffects = (ev: MatrixEvent) => { private handleEffects = (ev: MatrixEvent): void => {
const notifState = this.context.roomNotificationStateStore.getRoomState(this.state.room); const notifState = this.context.roomNotificationStateStore.getRoomState(this.state.room);
if (!notifState.isUnread) return; if (!notifState.isUnread) return;
@ -1189,19 +1189,19 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
}); });
}; };
private onRoomName = (room: Room) => { private onRoomName = (room: Room): void => {
if (this.state.room && room.roomId == this.state.room.roomId) { if (this.state.room && room.roomId == this.state.room.roomId) {
this.forceUpdate(); this.forceUpdate();
} }
}; };
private onKeyBackupStatus = () => { private onKeyBackupStatus = (): void => {
// Key backup status changes affect whether the in-room recovery // Key backup status changes affect whether the in-room recovery
// reminder is displayed. // reminder is displayed.
this.forceUpdate(); this.forceUpdate();
}; };
public canResetTimeline = () => { public canResetTimeline = (): boolean => {
if (!this.messagePanel) { if (!this.messagePanel) {
return true; return true;
} }
@ -1216,7 +1216,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
// called when state.room is first initialised (either at initial load, // called when state.room is first initialised (either at initial load,
// after a successful peek, or after we join the room). // after a successful peek, or after we join the room).
private onRoomLoaded = (room: Room) => { private onRoomLoaded = (room: Room): void => {
if (this.unmounted) return; if (this.unmounted) return;
// Attach a widget store listener only when we get a room // Attach a widget store listener only when we get a room
this.context.widgetLayoutStore.on(WidgetLayoutStore.emissionForRoom(room), this.onWidgetLayoutChange); this.context.widgetLayoutStore.on(WidgetLayoutStore.emissionForRoom(room), this.onWidgetLayoutChange);
@ -1251,17 +1251,17 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
} }
}; };
private getRoomTombstone(room = this.state.room) { private getRoomTombstone(room = this.state.room): MatrixEvent | undefined {
return room?.currentState.getStateEvents(EventType.RoomTombstone, ""); return room?.currentState.getStateEvents(EventType.RoomTombstone, "");
} }
private async calculateRecommendedVersion(room: Room) { private async calculateRecommendedVersion(room: Room): Promise<void> {
const upgradeRecommendation = await room.getRecommendedVersion(); const upgradeRecommendation = await room.getRecommendedVersion();
if (this.unmounted) return; if (this.unmounted) return;
this.setState({ upgradeRecommendation }); this.setState({ upgradeRecommendation });
} }
private async loadMembersIfJoined(room: Room) { private async loadMembersIfJoined(room: Room): Promise<void> {
// lazy load members if enabled // lazy load members if enabled
if (this.context.client.hasLazyLoadMembersEnabled()) { if (this.context.client.hasLazyLoadMembersEnabled()) {
if (room && room.getMyMembership() === "join") { if (room && room.getMyMembership() === "join") {
@ -1280,14 +1280,14 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
} }
} }
private calculatePeekRules(room: Room) { private calculatePeekRules(room: Room): void {
const historyVisibility = room.currentState.getStateEvents(EventType.RoomHistoryVisibility, ""); const historyVisibility = room.currentState.getStateEvents(EventType.RoomHistoryVisibility, "");
this.setState({ this.setState({
canPeek: historyVisibility?.getContent().history_visibility === HistoryVisibility.WorldReadable, canPeek: historyVisibility?.getContent().history_visibility === HistoryVisibility.WorldReadable,
}); });
} }
private updatePreviewUrlVisibility({ roomId }: Room) { private updatePreviewUrlVisibility({ roomId }: Room): void {
// URL Previews in E2EE rooms can be a privacy leak so use a different setting which is per-room explicit // URL Previews in E2EE rooms can be a privacy leak so use a different setting which is per-room explicit
const key = this.context.client.isRoomEncrypted(roomId) ? "urlPreviewsEnabled_e2ee" : "urlPreviewsEnabled"; const key = this.context.client.isRoomEncrypted(roomId) ? "urlPreviewsEnabled_e2ee" : "urlPreviewsEnabled";
this.setState({ this.setState({
@ -1295,7 +1295,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
}); });
} }
private onRoom = (room: Room) => { private onRoom = (room: Room): void => {
if (!room || room.roomId !== this.state.roomId) { if (!room || room.roomId !== this.state.roomId) {
return; return;
} }
@ -1318,7 +1318,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
); );
}; };
private onDeviceVerificationChanged = (userId: string) => { private onDeviceVerificationChanged = (userId: string): void => {
const room = this.state.room; const room = this.state.room;
if (!room?.currentState.getMember(userId)) { if (!room?.currentState.getMember(userId)) {
return; return;
@ -1326,7 +1326,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
this.updateE2EStatus(room); this.updateE2EStatus(room);
}; };
private onUserVerificationChanged = (userId: string) => { private onUserVerificationChanged = (userId: string): void => {
const room = this.state.room; const room = this.state.room;
if (!room || !room.currentState.getMember(userId)) { if (!room || !room.currentState.getMember(userId)) {
return; return;
@ -1334,14 +1334,14 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
this.updateE2EStatus(room); this.updateE2EStatus(room);
}; };
private onCrossSigningKeysChanged = () => { private onCrossSigningKeysChanged = (): void => {
const room = this.state.room; const room = this.state.room;
if (room) { if (room) {
this.updateE2EStatus(room); this.updateE2EStatus(room);
} }
}; };
private async updateE2EStatus(room: Room) { private async updateE2EStatus(room: Room): Promise<void> {
if (!this.context.client.isRoomEncrypted(room.roomId)) return; if (!this.context.client.isRoomEncrypted(room.roomId)) return;
// If crypto is not currently enabled, we aren't tracking devices at all, // If crypto is not currently enabled, we aren't tracking devices at all,
@ -1357,13 +1357,13 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
this.setState({ e2eStatus }); this.setState({ e2eStatus });
} }
private onUrlPreviewsEnabledChange = () => { private onUrlPreviewsEnabledChange = (): void => {
if (this.state.room) { if (this.state.room) {
this.updatePreviewUrlVisibility(this.state.room); this.updatePreviewUrlVisibility(this.state.room);
} }
}; };
private onRoomStateEvents = (ev: MatrixEvent, state: RoomState) => { private onRoomStateEvents = (ev: MatrixEvent, state: RoomState): void => {
// ignore if we don't have a room yet // ignore if we don't have a room yet
if (!this.state.room || this.state.room.roomId !== state.roomId) return; if (!this.state.room || this.state.room.roomId !== state.roomId) return;
@ -1377,7 +1377,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
} }
}; };
private onRoomStateUpdate = (state: RoomState) => { private onRoomStateUpdate = (state: RoomState): void => {
// ignore members in other rooms // ignore members in other rooms
if (state.roomId !== this.state.room?.roomId) { if (state.roomId !== this.state.room?.roomId) {
return; return;
@ -1386,7 +1386,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
this.updateRoomMembers(); this.updateRoomMembers();
}; };
private onMyMembership = (room: Room, membership: string, oldMembership: string) => { private onMyMembership = (room: Room, membership: string, oldMembership: string): void => {
if (room.roomId === this.state.roomId) { if (room.roomId === this.state.roomId) {
this.forceUpdate(); this.forceUpdate();
this.loadMembersIfJoined(room); this.loadMembersIfJoined(room);
@ -1394,7 +1394,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
} }
}; };
private updatePermissions(room: Room) { private updatePermissions(room: Room): void {
if (room) { if (room) {
const me = this.context.client.getUserId(); const me = this.context.client.getUserId();
const canReact = const canReact =
@ -1420,7 +1420,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
{ leading: true, trailing: true }, { leading: true, trailing: true },
); );
private checkDesktopNotifications() { private checkDesktopNotifications(): void {
const memberCount = this.state.room.getJoinedMemberCount() + this.state.room.getInvitedMemberCount(); const memberCount = this.state.room.getJoinedMemberCount() + this.state.room.getInvitedMemberCount();
// if they are not alone prompt the user about notifications so they don't miss replies // if they are not alone prompt the user about notifications so they don't miss replies
if (memberCount > 1 && Notifier.shouldShowPrompt()) { if (memberCount > 1 && Notifier.shouldShowPrompt()) {
@ -1428,7 +1428,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
} }
} }
private updateDMState() { private updateDMState(): void {
const room = this.state.room; const room = this.state.room;
if (room.getMyMembership() != "join") { if (room.getMyMembership() != "join") {
return; return;
@ -1439,7 +1439,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
} }
} }
private onInviteClick = () => { private onInviteClick = (): void => {
// open the room inviter // open the room inviter
dis.dispatch({ dis.dispatch({
action: "view_invite", action: "view_invite",
@ -1447,7 +1447,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
}); });
}; };
private onJoinButtonClicked = () => { private onJoinButtonClicked = (): void => {
// If the user is a ROU, allow them to transition to a PWLU // If the user is a ROU, allow them to transition to a PWLU
if (this.context.client?.isGuest()) { if (this.context.client?.isGuest()) {
// Join this room once the user has registered and logged in // Join this room once the user has registered and logged in
@ -1489,7 +1489,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
{ leading: false, trailing: true }, { leading: false, trailing: true },
); );
private onMessageListScroll = () => { private onMessageListScroll = (): void => {
if (this.messagePanel.isAtEndOfLiveTimeline()) { if (this.messagePanel.isAtEndOfLiveTimeline()) {
this.setState({ this.setState({
numUnreadMessages: 0, numUnreadMessages: 0,
@ -1504,7 +1504,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
this.updateVisibleDecryptionFailures(); this.updateVisibleDecryptionFailures();
}; };
private resetJumpToEvent = (eventId?: string) => { private resetJumpToEvent = (eventId?: string): void => {
if ( if (
this.state.initialEventId && this.state.initialEventId &&
this.state.initialEventScrollIntoView && this.state.initialEventScrollIntoView &&
@ -1523,7 +1523,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
} }
}; };
private injectSticker(url: string, info: object, text: string, threadId: string | null) { private injectSticker(url: string, info: object, text: string, threadId: string | null): void {
if (this.context.client.isGuest()) { if (this.context.client.isGuest()) {
dis.dispatch({ action: "require_registration" }); dis.dispatch({ action: "require_registration" });
return; return;
@ -1539,7 +1539,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
}); });
} }
private onSearch = (term: string, scope: SearchScope) => { private onSearch = (term: string, scope: SearchScope): void => {
const roomId = scope === SearchScope.Room ? this.state.room.roomId : undefined; const roomId = scope === SearchScope.Room ? this.state.room.roomId : undefined;
debuglog("sending search request"); debuglog("sending search request");
const abortController = new AbortController(); const abortController = new AbortController();
@ -1569,21 +1569,21 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
}); });
}; };
private onAppsClick = () => { private onAppsClick = (): void => {
dis.dispatch({ dis.dispatch({
action: "appsDrawer", action: "appsDrawer",
show: !this.state.showApps, show: !this.state.showApps,
}); });
}; };
private onForgetClick = () => { private onForgetClick = (): void => {
dis.dispatch({ dis.dispatch({
action: "forget_room", action: "forget_room",
room_id: this.state.room.roomId, room_id: this.state.room.roomId,
}); });
}; };
private onRejectButtonClicked = () => { private onRejectButtonClicked = (): void => {
this.setState({ this.setState({
rejecting: true, rejecting: true,
}); });
@ -1611,7 +1611,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
); );
}; };
private onRejectAndIgnoreClick = async () => { private onRejectAndIgnoreClick = async (): Promise<void> => {
this.setState({ this.setState({
rejecting: true, rejecting: true,
}); });
@ -1644,7 +1644,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
} }
}; };
private onRejectThreepidInviteButtonClicked = () => { private onRejectThreepidInviteButtonClicked = (): void => {
// We can reject 3pid invites in the same way that we accept them, // We can reject 3pid invites in the same way that we accept them,
// using /leave rather than /join. In the short term though, we // using /leave rather than /join. In the short term though, we
// just ignore them. // just ignore them.
@ -1652,7 +1652,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
dis.fire(Action.ViewRoomDirectory); dis.fire(Action.ViewRoomDirectory);
}; };
private onSearchClick = () => { private onSearchClick = (): void => {
this.setState({ this.setState({
timelineRenderingType: timelineRenderingType:
this.state.timelineRenderingType === TimelineRenderingType.Search this.state.timelineRenderingType === TimelineRenderingType.Search
@ -1674,7 +1674,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
}; };
// jump down to the bottom of this room, where new events are arriving // jump down to the bottom of this room, where new events are arriving
private jumpToLiveTimeline = () => { private jumpToLiveTimeline = (): void => {
if (this.state.initialEventId && this.state.isInitialEventHighlighted) { if (this.state.initialEventId && this.state.isInitialEventHighlighted) {
// If we were viewing a highlighted event, firing view_room without // If we were viewing a highlighted event, firing view_room without
// an event will take care of both clearing the URL fragment and // an event will take care of both clearing the URL fragment and
@ -1692,18 +1692,18 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
}; };
// jump up to wherever our read marker is // jump up to wherever our read marker is
private jumpToReadMarker = () => { private jumpToReadMarker = (): void => {
this.messagePanel.jumpToReadMarker(); this.messagePanel.jumpToReadMarker();
}; };
// update the read marker to match the read-receipt // update the read marker to match the read-receipt
private forgetReadMarker = (ev) => { private forgetReadMarker = (ev): void => {
ev.stopPropagation(); ev.stopPropagation();
this.messagePanel.forgetReadMarker(); this.messagePanel.forgetReadMarker();
}; };
// decide whether or not the top 'unread messages' bar should be shown // decide whether or not the top 'unread messages' bar should be shown
private updateTopUnreadMessagesBar = () => { private updateTopUnreadMessagesBar = (): void => {
if (!this.messagePanel) { if (!this.messagePanel) {
return; return;
} }
@ -1754,12 +1754,12 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
}; };
} }
private onStatusBarVisible = () => { private onStatusBarVisible = (): void => {
if (this.unmounted || this.state.statusBarVisible) return; if (this.unmounted || this.state.statusBarVisible) return;
this.setState({ statusBarVisible: true }); this.setState({ statusBarVisible: true });
}; };
private onStatusBarHidden = () => { private onStatusBarHidden = (): void => {
// This is currently not desired as it is annoying if it keeps expanding and collapsing // This is currently not desired as it is annoying if it keeps expanding and collapsing
if (this.unmounted || !this.state.statusBarVisible) return; if (this.unmounted || !this.state.statusBarVisible) return;
this.setState({ statusBarVisible: false }); this.setState({ statusBarVisible: false });
@ -1770,7 +1770,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
* *
* We pass it down to the scroll panel. * We pass it down to the scroll panel.
*/ */
public handleScrollKey = (ev) => { public handleScrollKey = (ev): void => {
let panel: ScrollPanel | TimelinePanel; let panel: ScrollPanel | TimelinePanel;
if (this.searchResultsPanel.current) { if (this.searchResultsPanel.current) {
panel = this.searchResultsPanel.current; panel = this.searchResultsPanel.current;
@ -1793,24 +1793,24 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
// this has to be a proper method rather than an unnamed function, // this has to be a proper method rather than an unnamed function,
// otherwise react calls it with null on each update. // otherwise react calls it with null on each update.
private gatherTimelinePanelRef = (r) => { private gatherTimelinePanelRef = (r): void => {
this.messagePanel = r; this.messagePanel = r;
}; };
private getOldRoom() { private getOldRoom(): Room | null {
const createEvent = this.state.room.currentState.getStateEvents(EventType.RoomCreate, ""); const createEvent = this.state.room.currentState.getStateEvents(EventType.RoomCreate, "");
if (!createEvent || !createEvent.getContent()["predecessor"]) return null; if (!createEvent || !createEvent.getContent()["predecessor"]) return null;
return this.context.client.getRoom(createEvent.getContent()["predecessor"]["room_id"]); return this.context.client.getRoom(createEvent.getContent()["predecessor"]["room_id"]);
} }
public getHiddenHighlightCount() { public getHiddenHighlightCount(): number {
const oldRoom = this.getOldRoom(); const oldRoom = this.getOldRoom();
if (!oldRoom) return 0; if (!oldRoom) return 0;
return oldRoom.getUnreadNotificationCount(NotificationCountType.Highlight); return oldRoom.getUnreadNotificationCount(NotificationCountType.Highlight);
} }
public onHiddenHighlightsClick = () => { public onHiddenHighlightsClick = (): void => {
const oldRoom = this.getOldRoom(); const oldRoom = this.getOldRoom();
if (!oldRoom) return; if (!oldRoom) return;
dis.dispatch<ViewRoomPayload>({ dis.dispatch<ViewRoomPayload>({
@ -1826,7 +1826,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
}); });
} }
private onFileDrop = (dataTransfer: DataTransfer) => private onFileDrop = (dataTransfer: DataTransfer): Promise<void> =>
ContentMessages.sharedInstance().sendContentListToRoom( ContentMessages.sharedInstance().sendContentListToRoom(
Array.from(dataTransfer.files), Array.from(dataTransfer.files),
this.state.room?.roomId ?? this.state.roomId, this.state.room?.roomId ?? this.state.roomId,
@ -1869,7 +1869,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
); );
} }
public render() { public render(): JSX.Element {
if (this.state.room instanceof LocalRoom) { if (this.state.room instanceof LocalRoom) {
if (this.state.room.state === LocalRoomState.CREATING) { if (this.state.room.state === LocalRoomState.CREATING) {
return this.renderLocalRoomCreateLoader(); return this.renderLocalRoomCreateLoader();

View File

@ -35,7 +35,7 @@ const UNFILL_REQUEST_DEBOUNCE_MS = 200;
// much while the content loads. // much while the content loads.
const PAGE_SIZE = 400; const PAGE_SIZE = 400;
const debuglog = (...args: any[]) => { const debuglog = (...args: any[]): void => {
if (SettingsStore.getValue("debug_scroll_panel")) { if (SettingsStore.getValue("debug_scroll_panel")) {
logger.log.call(console, "ScrollPanel debuglog:", ...args); logger.log.call(console, "ScrollPanel debuglog:", ...args);
} }
@ -227,14 +227,14 @@ export default class ScrollPanel extends React.Component<IProps> {
this.props.resizeNotifier?.removeListener("middlePanelResizedNoisy", this.onResize); this.props.resizeNotifier?.removeListener("middlePanelResizedNoisy", this.onResize);
} }
private onScroll = (ev: Event | React.UIEvent): void => { private onScroll = (ev: Event): void => {
// skip scroll events caused by resizing // skip scroll events caused by resizing
if (this.props.resizeNotifier && this.props.resizeNotifier.isResizing) return; if (this.props.resizeNotifier && this.props.resizeNotifier.isResizing) return;
debuglog("onScroll called past resize gate; scroll node top:", this.getScrollNode().scrollTop); debuglog("onScroll called past resize gate; scroll node top:", this.getScrollNode().scrollTop);
this.scrollTimeout.restart(); this.scrollTimeout.restart();
this.saveScrollState(); this.saveScrollState();
this.updatePreventShrinking(); this.updatePreventShrinking();
this.props.onScroll?.(ev as Event); this.props.onScroll?.(ev);
// noinspection JSIgnoredPromiseFromCall // noinspection JSIgnoredPromiseFromCall
this.checkFillState(); this.checkFillState();
}; };
@ -587,7 +587,7 @@ export default class ScrollPanel extends React.Component<IProps> {
* Scroll up/down in response to a scroll key * Scroll up/down in response to a scroll key
* @param {object} ev the keyboard event * @param {object} ev the keyboard event
*/ */
public handleScrollKey = (ev: KeyboardEvent) => { public handleScrollKey = (ev: KeyboardEvent): void => {
const roomAction = getKeyBindingsManager().getRoomAction(ev); const roomAction = getKeyBindingsManager().getRoomAction(ev);
switch (roomAction) { switch (roomAction) {
case KeyBindingAction.ScrollUp: case KeyBindingAction.ScrollUp:
@ -853,7 +853,7 @@ export default class ScrollPanel extends React.Component<IProps> {
return this.divScroll; return this.divScroll;
} }
private collectScroll = (divScroll: HTMLDivElement) => { private collectScroll = (divScroll: HTMLDivElement): void => {
this.divScroll = divScroll; this.divScroll = divScroll;
}; };

View File

@ -114,12 +114,12 @@ const Tile: React.FC<ITileProps> = ({
const [onFocus, isActive, ref] = useRovingTabIndex(); const [onFocus, isActive, ref] = useRovingTabIndex();
const [busy, setBusy] = useState(false); const [busy, setBusy] = useState(false);
const onPreviewClick = (ev: ButtonEvent) => { const onPreviewClick = (ev: ButtonEvent): void => {
ev.preventDefault(); ev.preventDefault();
ev.stopPropagation(); ev.stopPropagation();
onViewRoomClick(); onViewRoomClick();
}; };
const onJoinClick = async (ev: ButtonEvent) => { const onJoinClick = async (ev: ButtonEvent): Promise<void> => {
setBusy(true); setBusy(true);
ev.preventDefault(); ev.preventDefault();
ev.stopPropagation(); ev.stopPropagation();
@ -271,7 +271,7 @@ const Tile: React.FC<ITileProps> = ({
); );
if (showChildren) { if (showChildren) {
const onChildrenKeyDown = (e) => { const onChildrenKeyDown = (e): void => {
const action = getKeyBindingsManager().getAccessibilityAction(e); const action = getKeyBindingsManager().getAccessibilityAction(e);
switch (action) { switch (action) {
case KeyBindingAction.ArrowLeft: case KeyBindingAction.ArrowLeft:
@ -439,7 +439,7 @@ const toLocalRoom = (cli: MatrixClient, room: IHierarchyRoom): IHierarchyRoom =>
return room; return room;
}; };
export const HierarchyLevel = ({ export const HierarchyLevel: React.FC<IHierarchyLevelProps> = ({
root, root,
roomSet, roomSet,
hierarchy, hierarchy,
@ -448,7 +448,7 @@ export const HierarchyLevel = ({
onViewRoomClick, onViewRoomClick,
onJoinRoomClick, onJoinRoomClick,
onToggleClick, onToggleClick,
}: IHierarchyLevelProps) => { }) => {
const cli = useContext(MatrixClientContext); const cli = useContext(MatrixClientContext);
const space = cli.getRoom(root.room_id); const space = cli.getRoom(root.room_id);
const hasPermissions = space?.currentState.maySendStateEvent(EventType.SpaceChild, cli.getUserId()); const hasPermissions = space?.currentState.maySendStateEvent(EventType.SpaceChild, cli.getUserId());
@ -553,7 +553,7 @@ export const useRoomHierarchy = (
}); });
const loadMore = useCallback( const loadMore = useCallback(
async (pageSize?: number) => { async (pageSize?: number): Promise<void> => {
if (hierarchy.loading || !hierarchy.canLoadMore || hierarchy.noSupport || error) return; if (hierarchy.loading || !hierarchy.canLoadMore || hierarchy.noSupport || error) return;
await hierarchy.load(pageSize).catch(setError); await hierarchy.load(pageSize).catch(setError);
setRooms(hierarchy.rooms); setRooms(hierarchy.rooms);
@ -578,8 +578,8 @@ export const useRoomHierarchy = (
}; };
}; };
const useIntersectionObserver = (callback: () => void) => { const useIntersectionObserver = (callback: () => void): ((element: HTMLDivElement) => void) => {
const handleObserver = (entries: IntersectionObserverEntry[]) => { const handleObserver = (entries: IntersectionObserverEntry[]): void => {
const target = entries[0]; const target = entries[0];
if (target.isIntersecting) { if (target.isIntersecting) {
callback(); callback();
@ -610,7 +610,7 @@ interface IManageButtonsProps {
setError: Dispatch<SetStateAction<string>>; setError: Dispatch<SetStateAction<string>>;
} }
const ManageButtons = ({ hierarchy, selected, setSelected, setError }: IManageButtonsProps) => { const ManageButtons: React.FC<IManageButtonsProps> = ({ hierarchy, selected, setSelected, setError }) => {
const cli = useContext(MatrixClientContext); const cli = useContext(MatrixClientContext);
const [removing, setRemoving] = useState(false); const [removing, setRemoving] = useState(false);
@ -645,7 +645,7 @@ const ManageButtons = ({ hierarchy, selected, setSelected, setError }: IManageBu
<> <>
<Button <Button
{...props} {...props}
onClick={async () => { onClick={async (): Promise<void> => {
setRemoving(true); setRemoving(true);
try { try {
const userId = cli.getUserId(); const userId = cli.getUserId();
@ -680,7 +680,7 @@ const ManageButtons = ({ hierarchy, selected, setSelected, setError }: IManageBu
</Button> </Button>
<Button <Button
{...props} {...props}
onClick={async () => { onClick={async (): Promise<void> => {
setSaving(true); setSaving(true);
try { try {
for (const [parentId, childId] of selectedRelations) { for (const [parentId, childId] of selectedRelations) {
@ -713,7 +713,7 @@ const ManageButtons = ({ hierarchy, selected, setSelected, setError }: IManageBu
); );
}; };
const SpaceHierarchy = ({ space, initialText = "", showRoom, additionalButtons }: IProps) => { const SpaceHierarchy: React.FC<IProps> = ({ space, initialText = "", showRoom, additionalButtons }) => {
const cli = useContext(MatrixClientContext); const cli = useContext(MatrixClientContext);
const [query, setQuery] = useState(initialText); const [query, setQuery] = useState(initialText);

View File

@ -103,7 +103,7 @@ enum Phase {
PrivateExistingRooms, PrivateExistingRooms,
} }
const SpaceLandingAddButton = ({ space }) => { const SpaceLandingAddButton: React.FC<{ space: Room }> = ({ space }) => {
const [menuDisplayed, handle, openMenu, closeMenu] = useContextMenu(); const [menuDisplayed, handle, openMenu, closeMenu] = useContextMenu();
const canCreateRoom = shouldShowComponent(UIComponent.CreateRooms); const canCreateRoom = shouldShowComponent(UIComponent.CreateRooms);
const canCreateSpace = shouldShowComponent(UIComponent.CreateSpaces); const canCreateSpace = shouldShowComponent(UIComponent.CreateSpaces);
@ -128,7 +128,7 @@ const SpaceLandingAddButton = ({ space }) => {
<IconizedContextMenuOption <IconizedContextMenuOption
label={_t("New room")} label={_t("New room")}
iconClassName="mx_RoomList_iconNewRoom" iconClassName="mx_RoomList_iconNewRoom"
onClick={async (e) => { onClick={async (e): Promise<void> => {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
closeMenu(); closeMenu();
@ -143,7 +143,7 @@ const SpaceLandingAddButton = ({ space }) => {
<IconizedContextMenuOption <IconizedContextMenuOption
label={_t("New video room")} label={_t("New video room")}
iconClassName="mx_RoomList_iconNewVideoRoom" iconClassName="mx_RoomList_iconNewVideoRoom"
onClick={async (e) => { onClick={async (e): Promise<void> => {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
closeMenu(); closeMenu();
@ -210,7 +210,7 @@ const SpaceLandingAddButton = ({ space }) => {
); );
}; };
const SpaceLanding = ({ space }: { space: Room }) => { const SpaceLanding: React.FC<{ space: Room }> = ({ space }) => {
const cli = useContext(MatrixClientContext); const cli = useContext(MatrixClientContext);
const myMembership = useMyRoomMembership(space); const myMembership = useMyRoomMembership(space);
const userId = cli.getUserId(); const userId = cli.getUserId();
@ -259,7 +259,7 @@ const SpaceLanding = ({ space }: { space: Room }) => {
); );
} }
const onMembersClick = () => { const onMembersClick = (): void => {
RightPanelStore.instance.setCard({ phase: RightPanelPhases.SpaceMemberList }); RightPanelStore.instance.setCard({ phase: RightPanelPhases.SpaceMemberList });
}; };
@ -297,7 +297,12 @@ const SpaceLanding = ({ space }: { space: Room }) => {
); );
}; };
const SpaceSetupFirstRooms = ({ space, title, description, onFinished }) => { const SpaceSetupFirstRooms: React.FC<{
space: Room;
title: string;
description: JSX.Element;
onFinished(firstRoomId?: string): void;
}> = ({ space, title, description, onFinished }) => {
const [busy, setBusy] = useState(false); const [busy, setBusy] = useState(false);
const [error, setError] = useState(""); const [error, setError] = useState("");
const numFields = 3; const numFields = 3;
@ -321,7 +326,7 @@ const SpaceSetupFirstRooms = ({ space, title, description, onFinished }) => {
); );
}); });
const onNextClick = async (ev: ButtonEvent) => { const onNextClick = async (ev: ButtonEvent): Promise<void> => {
ev.preventDefault(); ev.preventDefault();
if (busy) return; if (busy) return;
setError(""); setError("");
@ -354,7 +359,7 @@ const SpaceSetupFirstRooms = ({ space, title, description, onFinished }) => {
setBusy(false); setBusy(false);
}; };
let onClick = (ev: ButtonEvent) => { let onClick = (ev: ButtonEvent): void => {
ev.preventDefault(); ev.preventDefault();
onFinished(); onFinished();
}; };
@ -389,7 +394,10 @@ const SpaceSetupFirstRooms = ({ space, title, description, onFinished }) => {
); );
}; };
const SpaceAddExistingRooms = ({ space, onFinished }) => { const SpaceAddExistingRooms: React.FC<{
space: Room;
onFinished(): void;
}> = ({ space, onFinished }) => {
return ( return (
<div> <div>
<h1>{_t("What do you want to organise?")}</h1> <h1>{_t("What do you want to organise?")}</h1>
@ -420,7 +428,12 @@ interface ISpaceSetupPublicShareProps extends Pick<IProps & IState, "justCreated
onFinished(): void; onFinished(): void;
} }
const SpaceSetupPublicShare = ({ justCreatedOpts, space, onFinished, firstRoomId }: ISpaceSetupPublicShareProps) => { const SpaceSetupPublicShare: React.FC<ISpaceSetupPublicShareProps> = ({
justCreatedOpts,
space,
onFinished,
firstRoomId,
}) => {
return ( return (
<div className="mx_SpaceRoomView_publicShare"> <div className="mx_SpaceRoomView_publicShare">
<h1> <h1>
@ -443,7 +456,11 @@ const SpaceSetupPublicShare = ({ justCreatedOpts, space, onFinished, firstRoomId
); );
}; };
const SpaceSetupPrivateScope = ({ space, justCreatedOpts, onFinished }) => { const SpaceSetupPrivateScope: React.FC<{
space: Room;
justCreatedOpts: IOpts;
onFinished(createRooms: boolean): void;
}> = ({ space, justCreatedOpts, onFinished }) => {
return ( return (
<div className="mx_SpaceRoomView_privateScope"> <div className="mx_SpaceRoomView_privateScope">
<h1>{_t("Who are you working with?")}</h1> <h1>{_t("Who are you working with?")}</h1>
@ -485,7 +502,10 @@ const validateEmailRules = withValidation({
], ],
}); });
const SpaceSetupPrivateInvite = ({ space, onFinished }) => { const SpaceSetupPrivateInvite: React.FC<{
space: Room;
onFinished(): void;
}> = ({ space, onFinished }) => {
const [busy, setBusy] = useState(false); const [busy, setBusy] = useState(false);
const [error, setError] = useState(""); const [error, setError] = useState("");
const numFields = 3; const numFields = 3;
@ -501,7 +521,7 @@ const SpaceSetupPrivateInvite = ({ space, onFinished }) => {
label={_t("Email address")} label={_t("Email address")}
placeholder={_t("Email")} placeholder={_t("Email")}
value={emailAddresses[i]} value={emailAddresses[i]}
onChange={(ev) => setEmailAddress(i, ev.target.value)} onChange={(ev: React.ChangeEvent<HTMLInputElement>) => setEmailAddress(i, ev.target.value)}
ref={fieldRefs[i]} ref={fieldRefs[i]}
onValidate={validateEmailRules} onValidate={validateEmailRules}
autoFocus={i === 0} autoFocus={i === 0}
@ -510,7 +530,7 @@ const SpaceSetupPrivateInvite = ({ space, onFinished }) => {
); );
}); });
const onNextClick = async (ev) => { const onNextClick = async (ev: ButtonEvent): Promise<void> => {
ev.preventDefault(); ev.preventDefault();
if (busy) return; if (busy) return;
setError(""); setError("");
@ -548,7 +568,7 @@ const SpaceSetupPrivateInvite = ({ space, onFinished }) => {
setBusy(false); setBusy(false);
}; };
let onClick = (ev) => { let onClick = (ev: ButtonEvent): void => {
ev.preventDefault(); ev.preventDefault();
onFinished(); onFinished();
}; };
@ -642,29 +662,29 @@ export default class SpaceRoomView extends React.PureComponent<IProps, IState> {
RightPanelStore.instance.on(UPDATE_EVENT, this.onRightPanelStoreUpdate); RightPanelStore.instance.on(UPDATE_EVENT, this.onRightPanelStoreUpdate);
} }
public componentDidMount() { public componentDidMount(): void {
this.context.on(RoomEvent.MyMembership, this.onMyMembership); this.context.on(RoomEvent.MyMembership, this.onMyMembership);
} }
public componentWillUnmount() { public componentWillUnmount(): void {
defaultDispatcher.unregister(this.dispatcherRef); defaultDispatcher.unregister(this.dispatcherRef);
RightPanelStore.instance.off(UPDATE_EVENT, this.onRightPanelStoreUpdate); RightPanelStore.instance.off(UPDATE_EVENT, this.onRightPanelStoreUpdate);
this.context.off(RoomEvent.MyMembership, this.onMyMembership); this.context.off(RoomEvent.MyMembership, this.onMyMembership);
} }
private onMyMembership = (room: Room, myMembership: string) => { private onMyMembership = (room: Room, myMembership: string): void => {
if (room.roomId === this.props.space.roomId) { if (room.roomId === this.props.space.roomId) {
this.setState({ myMembership }); this.setState({ myMembership });
} }
}; };
private onRightPanelStoreUpdate = () => { private onRightPanelStoreUpdate = (): void => {
this.setState({ this.setState({
showRightPanel: RightPanelStore.instance.isOpenForRoom(this.props.space.roomId), showRightPanel: RightPanelStore.instance.isOpenForRoom(this.props.space.roomId),
}); });
}; };
private onAction = (payload: ActionPayload) => { private onAction = (payload: ActionPayload): void => {
if (payload.action === Action.ViewRoom && payload.room_id === this.props.space.roomId) { if (payload.action === Action.ViewRoom && payload.room_id === this.props.space.roomId) {
this.setState({ phase: Phase.Landing }); this.setState({ phase: Phase.Landing });
return; return;
@ -698,7 +718,7 @@ export default class SpaceRoomView extends React.PureComponent<IProps, IState> {
} }
}; };
private goToFirstRoom = async () => { private goToFirstRoom = async (): Promise<void> => {
if (this.state.firstRoomId) { if (this.state.firstRoomId) {
defaultDispatcher.dispatch<ViewRoomPayload>({ defaultDispatcher.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
@ -711,7 +731,7 @@ export default class SpaceRoomView extends React.PureComponent<IProps, IState> {
this.setState({ phase: Phase.Landing }); this.setState({ phase: Phase.Landing });
}; };
private renderBody() { private renderBody(): JSX.Element {
switch (this.state.phase) { switch (this.state.phase) {
case Phase.Landing: case Phase.Landing:
if (this.state.myMembership === "join") { if (this.state.myMembership === "join") {
@ -794,7 +814,7 @@ export default class SpaceRoomView extends React.PureComponent<IProps, IState> {
} }
} }
public render() { public render(): JSX.Element {
const rightPanel = const rightPanel =
this.state.showRightPanel && this.state.phase === Phase.Landing ? ( this.state.showRightPanel && this.state.phase === Phase.Landing ? (
<RightPanel room={this.props.space} resizeNotifier={this.props.resizeNotifier} /> <RightPanel room={this.props.space} resizeNotifier={this.props.resizeNotifier} />

View File

@ -19,7 +19,7 @@ interface Props extends DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLEleme
children?: ReactNode; children?: ReactNode;
} }
export default function SplashPage({ children, className, ...other }: Props) { export default function SplashPage({ children, className, ...other }: Props): JSX.Element {
const classes = classNames(className, "mx_SplashPage"); const classes = classNames(className, "mx_SplashPage");
return ( return (
<main {...other} className={classes}> <main {...other} className={classes}>

View File

@ -86,7 +86,7 @@ export default class TabbedView extends React.Component<IProps, IState> {
* @param {Tab} tab the tab to show * @param {Tab} tab the tab to show
* @private * @private
*/ */
private setActiveTab(tab: Tab) { private setActiveTab(tab: Tab): void {
// make sure this tab is still in available tabs // make sure this tab is still in available tabs
if (!!this.getTabById(tab.id)) { if (!!this.getTabById(tab.id)) {
if (this.props.onChange) this.props.onChange(tab.id); if (this.props.onChange) this.props.onChange(tab.id);
@ -96,7 +96,7 @@ export default class TabbedView extends React.Component<IProps, IState> {
} }
} }
private renderTabLabel(tab: Tab) { private renderTabLabel(tab: Tab): JSX.Element {
let classes = "mx_TabbedView_tabLabel "; let classes = "mx_TabbedView_tabLabel ";
if (this.state.activeTabId === tab.id) classes += "mx_TabbedView_tabLabel_active"; if (this.state.activeTabId === tab.id) classes += "mx_TabbedView_tabLabel_active";
@ -106,7 +106,7 @@ export default class TabbedView extends React.Component<IProps, IState> {
tabIcon = <span className={`mx_TabbedView_maskedIcon ${tab.icon}`} />; tabIcon = <span className={`mx_TabbedView_maskedIcon ${tab.icon}`} />;
} }
const onClickHandler = () => this.setActiveTab(tab); const onClickHandler = (): void => this.setActiveTab(tab);
const label = _t(tab.label); const label = _t(tab.label);
return ( return (

View File

@ -61,15 +61,12 @@ type ThreadPanelHeaderOption = {
key: ThreadFilterType; key: ThreadFilterType;
}; };
export const ThreadPanelHeaderFilterOptionItem = ({ export const ThreadPanelHeaderFilterOptionItem: React.FC<
label, ThreadPanelHeaderOption & {
description, onClick: () => void;
onClick, isSelected: boolean;
isSelected, }
}: ThreadPanelHeaderOption & { > = ({ label, description, onClick, isSelected }) => {
onClick: () => void;
isSelected: boolean;
}) => {
return ( return (
<MenuItemRadio active={isSelected} className="mx_ThreadPanel_Header_FilterOptionItem" onClick={onClick}> <MenuItemRadio active={isSelected} className="mx_ThreadPanel_Header_FilterOptionItem" onClick={onClick}>
<span>{label}</span> <span>{label}</span>
@ -78,15 +75,11 @@ export const ThreadPanelHeaderFilterOptionItem = ({
); );
}; };
export const ThreadPanelHeader = ({ export const ThreadPanelHeader: React.FC<{
filterOption,
setFilterOption,
empty,
}: {
filterOption: ThreadFilterType; filterOption: ThreadFilterType;
setFilterOption: (filterOption: ThreadFilterType) => void; setFilterOption: (filterOption: ThreadFilterType) => void;
empty: boolean; empty: boolean;
}) => { }> = ({ filterOption, setFilterOption, empty }) => {
const [menuDisplayed, button, openMenu, closeMenu] = useContextMenu<HTMLElement>(); const [menuDisplayed, button, openMenu, closeMenu] = useContextMenu<HTMLElement>();
const options: readonly ThreadPanelHeaderOption[] = [ const options: readonly ThreadPanelHeaderOption[] = [
{ {

View File

@ -137,7 +137,7 @@ export default class ThreadView extends React.Component<IProps, IState> {
}); });
} }
public componentDidUpdate(prevProps) { public componentDidUpdate(prevProps): void {
if (prevProps.mxEvent !== this.props.mxEvent) { if (prevProps.mxEvent !== this.props.mxEvent) {
this.setupThread(this.props.mxEvent); this.setupThread(this.props.mxEvent);
} }
@ -192,7 +192,7 @@ export default class ThreadView extends React.Component<IProps, IState> {
} }
}; };
private setupThread = (mxEv: MatrixEvent) => { private setupThread = (mxEv: MatrixEvent): void => {
let thread = this.props.room.getThread(mxEv.getId()); let thread = this.props.room.getThread(mxEv.getId());
if (!thread) { if (!thread) {
thread = this.props.room.createThread(mxEv.getId(), mxEv, [mxEv], true); thread = this.props.room.createThread(mxEv.getId(), mxEv, [mxEv], true);
@ -200,7 +200,7 @@ export default class ThreadView extends React.Component<IProps, IState> {
this.updateThread(thread); this.updateThread(thread);
}; };
private onNewThread = (thread: Thread) => { private onNewThread = (thread: Thread): void => {
if (thread.id === this.props.mxEvent.getId()) { if (thread.id === this.props.mxEvent.getId()) {
this.setupThread(this.props.mxEvent); this.setupThread(this.props.mxEvent);
} }
@ -218,7 +218,7 @@ export default class ThreadView extends React.Component<IProps, IState> {
}); });
} }
private updateThread = (thread?: Thread) => { private updateThread = (thread?: Thread): void => {
if (this.state.thread === thread) return; if (this.state.thread === thread) return;
this.setupThreadListeners(thread, this.state.thread); this.setupThreadListeners(thread, this.state.thread);
@ -276,7 +276,7 @@ export default class ThreadView extends React.Component<IProps, IState> {
this.setState({ narrow }); this.setState({ narrow });
}; };
private onKeyDown = (ev: KeyboardEvent) => { private onKeyDown = (ev: KeyboardEvent): void => {
let handled = false; let handled = false;
const action = getKeyBindingsManager().getRoomAction(ev); const action = getKeyBindingsManager().getRoomAction(ev);
@ -300,7 +300,7 @@ export default class ThreadView extends React.Component<IProps, IState> {
} }
}; };
private onFileDrop = (dataTransfer: DataTransfer) => { private onFileDrop = (dataTransfer: DataTransfer): void => {
const roomId = this.props.mxEvent.getRoomId(); const roomId = this.props.mxEvent.getRoomId();
if (roomId) { if (roomId) {
ContentMessages.sharedInstance().sendContentListToRoom( ContentMessages.sharedInstance().sendContentListToRoom(

View File

@ -31,6 +31,7 @@ import { Thread, ThreadEvent } from "matrix-js-sdk/src/models/thread";
import { ReceiptType } from "matrix-js-sdk/src/@types/read_receipts"; import { ReceiptType } from "matrix-js-sdk/src/@types/read_receipts";
import { MatrixError } from "matrix-js-sdk/src/http-api"; import { MatrixError } from "matrix-js-sdk/src/http-api";
import { ReadReceipt } from "matrix-js-sdk/src/models/read-receipt"; import { ReadReceipt } from "matrix-js-sdk/src/models/read-receipt";
import { Relations } from "matrix-js-sdk/src/models/relations";
import SettingsStore from "../../settings/SettingsStore"; import SettingsStore from "../../settings/SettingsStore";
import { Layout } from "../../settings/enums/Layout"; import { Layout } from "../../settings/enums/Layout";
@ -67,7 +68,7 @@ const READ_MARKER_DEBOUNCE_MS = 100;
// How far off-screen a decryption failure can be for it to still count as "visible" // How far off-screen a decryption failure can be for it to still count as "visible"
const VISIBLE_DECRYPTION_FAILURE_MARGIN = 100; const VISIBLE_DECRYPTION_FAILURE_MARGIN = 100;
const debuglog = (...args: any[]) => { const debuglog = (...args: any[]): void => {
if (SettingsStore.getValue("debug_timeline_panel")) { if (SettingsStore.getValue("debug_timeline_panel")) {
logger.log.call(console, "TimelinePanel debuglog:", ...args); logger.log.call(console, "TimelinePanel debuglog:", ...args);
} }
@ -315,7 +316,7 @@ class TimelinePanel extends React.Component<IProps, IState> {
this.props.timelineSet.room?.on(ThreadEvent.Update, this.onThreadUpdate); this.props.timelineSet.room?.on(ThreadEvent.Update, this.onThreadUpdate);
} }
public componentDidMount() { public componentDidMount(): void {
if (this.props.manageReadReceipts) { if (this.props.manageReadReceipts) {
this.updateReadReceiptOnUserActivity(); this.updateReadReceiptOnUserActivity();
} }
@ -325,7 +326,7 @@ class TimelinePanel extends React.Component<IProps, IState> {
this.initTimeline(this.props); this.initTimeline(this.props);
} }
public componentDidUpdate(prevProps) { public componentDidUpdate(prevProps: Readonly<IProps>): void {
if (prevProps.timelineSet !== this.props.timelineSet) { if (prevProps.timelineSet !== this.props.timelineSet) {
// throw new Error("changing timelineSet on a TimelinePanel is not supported"); // throw new Error("changing timelineSet on a TimelinePanel is not supported");
@ -360,7 +361,7 @@ class TimelinePanel extends React.Component<IProps, IState> {
} }
} }
public componentWillUnmount() { public componentWillUnmount(): void {
// set a boolean to say we've been unmounted, which any pending // set a boolean to say we've been unmounted, which any pending
// promises can use to throw away their results. // promises can use to throw away their results.
// //
@ -616,7 +617,7 @@ class TimelinePanel extends React.Component<IProps, IState> {
}); });
}; };
private onMessageListScroll = (e) => { private onMessageListScroll = (e: Event): void => {
this.props.onScroll?.(e); this.props.onScroll?.(e);
if (this.props.manageReadMarkers) { if (this.props.manageReadMarkers) {
this.doManageReadMarkers(); this.doManageReadMarkers();
@ -777,7 +778,7 @@ class TimelinePanel extends React.Component<IProps, IState> {
} }
}; };
public canResetTimeline = () => this.messagePanel?.current?.isAtBottom(); public canResetTimeline = (): boolean => this.messagePanel?.current?.isAtBottom();
private onRoomRedaction = (ev: MatrixEvent, room: Room): void => { private onRoomRedaction = (ev: MatrixEvent, room: Room): void => {
if (this.unmounted) return; if (this.unmounted) return;
@ -1060,7 +1061,7 @@ class TimelinePanel extends React.Component<IProps, IState> {
this.state.readMarkerEventId ?? "", this.state.readMarkerEventId ?? "",
sendRRs ? lastReadEvent ?? undefined : undefined, // Public read receipt (could be null) sendRRs ? lastReadEvent ?? undefined : undefined, // Public read receipt (could be null)
lastReadEvent ?? undefined, // Private read receipt (could be null) lastReadEvent ?? undefined, // Private read receipt (could be null)
).catch(async (e) => { ).catch(async (e): Promise<void> => {
// /read_markers API is not implemented on this HS, fallback to just RR // /read_markers API is not implemented on this HS, fallback to just RR
if (e.errcode === "M_UNRECOGNIZED" && lastReadEvent) { if (e.errcode === "M_UNRECOGNIZED" && lastReadEvent) {
if ( if (
@ -1070,10 +1071,11 @@ class TimelinePanel extends React.Component<IProps, IState> {
) )
return; return;
try { try {
return await cli.sendReadReceipt( await cli.sendReadReceipt(
lastReadEvent, lastReadEvent,
sendRRs ? ReceiptType.Read : ReceiptType.ReadPrivate, sendRRs ? ReceiptType.Read : ReceiptType.ReadPrivate,
); );
return;
} catch (error) { } catch (error) {
logger.error(e); logger.error(e);
this.lastRRSentEventId = undefined; this.lastRRSentEventId = undefined;
@ -1314,7 +1316,7 @@ class TimelinePanel extends React.Component<IProps, IState> {
* *
* We pass it down to the scroll panel. * We pass it down to the scroll panel.
*/ */
public handleScrollKey = (ev) => { public handleScrollKey = (ev: React.KeyboardEvent): void => {
if (!this.messagePanel.current) return; if (!this.messagePanel.current) return;
// jump to the live timeline on ctrl-end, rather than the end of the // jump to the live timeline on ctrl-end, rather than the end of the
@ -1342,7 +1344,7 @@ class TimelinePanel extends React.Component<IProps, IState> {
} }
private scrollIntoView(eventId?: string, pixelOffset?: number, offsetBase?: number): void { private scrollIntoView(eventId?: string, pixelOffset?: number, offsetBase?: number): void {
const doScroll = () => { const doScroll = (): void => {
if (!this.messagePanel.current) return; if (!this.messagePanel.current) return;
if (eventId) { if (eventId) {
debuglog( debuglog(
@ -1401,7 +1403,7 @@ class TimelinePanel extends React.Component<IProps, IState> {
? new TimelineWindow(cli, this.props.overlayTimelineSet, { windowLimit: this.props.timelineCap }) ? new TimelineWindow(cli, this.props.overlayTimelineSet, { windowLimit: this.props.timelineCap })
: undefined; : undefined;
const onLoaded = () => { const onLoaded = (): void => {
if (this.unmounted) return; if (this.unmounted) return;
// clear the timeline min-height when (re)loading the timeline // clear the timeline min-height when (re)loading the timeline
@ -1441,7 +1443,7 @@ class TimelinePanel extends React.Component<IProps, IState> {
); );
}; };
const onError = (error: MatrixError) => { const onError = (error: MatrixError): void => {
if (this.unmounted) return; if (this.unmounted) return;
this.setState({ timelineLoading: false }); this.setState({ timelineLoading: false });
@ -1504,7 +1506,7 @@ class TimelinePanel extends React.Component<IProps, IState> {
return; return;
} }
const prom = this.timelineWindow.load(eventId, INITIAL_SIZE).then(async () => { const prom = this.timelineWindow.load(eventId, INITIAL_SIZE).then(async (): Promise<void> => {
if (this.overlayTimelineWindow) { if (this.overlayTimelineWindow) {
// @TODO(kerrya) use timestampToEvent to load the overlay timeline // @TODO(kerrya) use timestampToEvent to load the overlay timeline
// with more correct position when main TL eventId is truthy // with more correct position when main TL eventId is truthy
@ -1746,7 +1748,7 @@ class TimelinePanel extends React.Component<IProps, IState> {
const wrapperRect = messagePanelNode.getBoundingClientRect(); const wrapperRect = messagePanelNode.getBoundingClientRect();
const myUserId = MatrixClientPeg.get().credentials.userId; const myUserId = MatrixClientPeg.get().credentials.userId;
const isNodeInView = (node: HTMLElement) => { const isNodeInView = (node: HTMLElement): boolean => {
if (node) { if (node) {
const boundingRect = node.getBoundingClientRect(); const boundingRect = node.getBoundingClientRect();
if ( if (
@ -1877,13 +1879,14 @@ class TimelinePanel extends React.Component<IProps, IState> {
eventId: string, eventId: string,
relationType: RelationType | string, relationType: RelationType | string,
eventType: EventType | string, eventType: EventType | string,
) => this.props.timelineSet.relations?.getChildEventsForEvent(eventId, relationType, eventType); ): Relations | undefined =>
this.props.timelineSet.relations?.getChildEventsForEvent(eventId, relationType, eventType);
private buildLegacyCallEventGroupers(events?: MatrixEvent[]): void { private buildLegacyCallEventGroupers(events?: MatrixEvent[]): void {
this.callEventGroupers = buildLegacyCallEventGroupers(this.callEventGroupers, events); this.callEventGroupers = buildLegacyCallEventGroupers(this.callEventGroupers, events);
} }
public render() { public render(): JSX.Element {
// just show a spinner while the timeline loads. // just show a spinner while the timeline loads.
// //
// put it in a div of the right class (mx_RoomView_messagePanel) so // put it in a div of the right class (mx_RoomView_messagePanel) so

View File

@ -39,18 +39,18 @@ export default class ToastContainer extends React.Component<{}, IState> {
ToastStore.sharedInstance().on("update", this.onToastStoreUpdate); ToastStore.sharedInstance().on("update", this.onToastStoreUpdate);
} }
public componentWillUnmount() { public componentWillUnmount(): void {
ToastStore.sharedInstance().removeListener("update", this.onToastStoreUpdate); ToastStore.sharedInstance().removeListener("update", this.onToastStoreUpdate);
} }
private onToastStoreUpdate = () => { private onToastStoreUpdate = (): void => {
this.setState({ this.setState({
toasts: ToastStore.sharedInstance().getToasts(), toasts: ToastStore.sharedInstance().getToasts(),
countSeen: ToastStore.sharedInstance().getCountSeen(), countSeen: ToastStore.sharedInstance().getCountSeen(),
}); });
}; };
public render() { public render(): JSX.Element {
const totalCount = this.state.toasts.length; const totalCount = this.state.toasts.length;
const isStacked = totalCount > 1; const isStacked = totalCount > 1;
let toast; let toast;

View File

@ -65,12 +65,12 @@ export default class UploadBar extends React.PureComponent<IProps, IState> {
this.state = this.calculateState(); this.state = this.calculateState();
} }
public componentDidMount() { public componentDidMount(): void {
this.dispatcherRef = dis.register(this.onAction); this.dispatcherRef = dis.register(this.onAction);
this.mounted = true; this.mounted = true;
} }
public componentWillUnmount() { public componentWillUnmount(): void {
this.mounted = false; this.mounted = false;
dis.unregister(this.dispatcherRef!); dis.unregister(this.dispatcherRef!);
} }
@ -91,19 +91,19 @@ export default class UploadBar extends React.PureComponent<IProps, IState> {
}; };
} }
private onAction = (payload: ActionPayload) => { private onAction = (payload: ActionPayload): void => {
if (!this.mounted) return; if (!this.mounted) return;
if (isUploadPayload(payload)) { if (isUploadPayload(payload)) {
this.setState(this.calculateState()); this.setState(this.calculateState());
} }
}; };
private onCancelClick = (ev: ButtonEvent) => { private onCancelClick = (ev: ButtonEvent): void => {
ev.preventDefault(); ev.preventDefault();
ContentMessages.sharedInstance().cancelUpload(this.state.currentUpload!); ContentMessages.sharedInstance().cancelUpload(this.state.currentUpload!);
}; };
public render() { public render(): JSX.Element {
if (!this.state.currentFile) { if (!this.state.currentFile) {
return null; return null;
} }

View File

@ -22,7 +22,7 @@ import defaultDispatcher from "../../dispatcher/dispatcher";
import { ActionPayload } from "../../dispatcher/payloads"; import { ActionPayload } from "../../dispatcher/payloads";
import { Action } from "../../dispatcher/actions"; import { Action } from "../../dispatcher/actions";
import { _t } from "../../languageHandler"; import { _t } from "../../languageHandler";
import { ChevronFace, ContextMenuButton } from "./ContextMenu"; import { ChevronFace, ContextMenuButton, MenuProps } from "./ContextMenu";
import { UserTab } from "../views/dialogs/UserTab"; import { UserTab } from "../views/dialogs/UserTab";
import { OpenToTabPayload } from "../../dispatcher/payloads/OpenToTabPayload"; import { OpenToTabPayload } from "../../dispatcher/payloads/OpenToTabPayload";
import FeedbackDialog from "../views/dialogs/FeedbackDialog"; import FeedbackDialog from "../views/dialogs/FeedbackDialog";
@ -67,7 +67,7 @@ interface IState {
showLiveAvatarAddon: boolean; showLiveAvatarAddon: boolean;
} }
const toRightOf = (rect: PartialDOMRect) => { const toRightOf = (rect: PartialDOMRect): MenuProps => {
return { return {
left: rect.width + rect.left + 8, left: rect.width + rect.left + 8,
top: rect.top, top: rect.top,
@ -75,7 +75,7 @@ const toRightOf = (rect: PartialDOMRect) => {
}; };
}; };
const below = (rect: PartialDOMRect) => { const below = (rect: PartialDOMRect): MenuProps => {
return { return {
left: rect.left, left: rect.left,
top: rect.top + rect.height, top: rect.top + rect.height,
@ -118,7 +118,7 @@ export default class UserMenu extends React.Component<IProps, IState> {
}); });
}; };
public componentDidMount() { public componentDidMount(): void {
this.context.voiceBroadcastRecordingsStore.on( this.context.voiceBroadcastRecordingsStore.on(
VoiceBroadcastRecordingsStoreEvent.CurrentChanged, VoiceBroadcastRecordingsStoreEvent.CurrentChanged,
this.onCurrentVoiceBroadcastRecordingChanged, this.onCurrentVoiceBroadcastRecordingChanged,
@ -127,7 +127,7 @@ export default class UserMenu extends React.Component<IProps, IState> {
this.themeWatcherRef = SettingsStore.watchSetting("theme", null, this.onThemeChanged); this.themeWatcherRef = SettingsStore.watchSetting("theme", null, this.onThemeChanged);
} }
public componentWillUnmount() { public componentWillUnmount(): void {
if (this.themeWatcherRef) SettingsStore.unwatchSetting(this.themeWatcherRef); if (this.themeWatcherRef) SettingsStore.unwatchSetting(this.themeWatcherRef);
if (this.dndWatcherRef) SettingsStore.unwatchSetting(this.dndWatcherRef); if (this.dndWatcherRef) SettingsStore.unwatchSetting(this.dndWatcherRef);
if (this.dispatcherRef) defaultDispatcher.unregister(this.dispatcherRef); if (this.dispatcherRef) defaultDispatcher.unregister(this.dispatcherRef);
@ -163,26 +163,26 @@ export default class UserMenu extends React.Component<IProps, IState> {
} }
} }
private onProfileUpdate = async () => { private onProfileUpdate = async (): Promise<void> => {
// the store triggered an update, so force a layout update. We don't // the store triggered an update, so force a layout update. We don't
// have any state to store here for that to magically happen. // have any state to store here for that to magically happen.
this.forceUpdate(); this.forceUpdate();
}; };
private onSelectedSpaceUpdate = async () => { private onSelectedSpaceUpdate = async (): Promise<void> => {
this.setState({ this.setState({
selectedSpace: SpaceStore.instance.activeSpaceRoom, selectedSpace: SpaceStore.instance.activeSpaceRoom,
}); });
}; };
private onThemeChanged = () => { private onThemeChanged = (): void => {
this.setState({ this.setState({
isDarkTheme: this.isUserOnDarkTheme(), isDarkTheme: this.isUserOnDarkTheme(),
isHighContrast: this.isUserOnHighContrastTheme(), isHighContrast: this.isUserOnHighContrastTheme(),
}); });
}; };
private onAction = (payload: ActionPayload) => { private onAction = (payload: ActionPayload): void => {
switch (payload.action) { switch (payload.action) {
case Action.ToggleUserMenu: case Action.ToggleUserMenu:
if (this.state.contextMenuPosition) { if (this.state.contextMenuPosition) {
@ -194,13 +194,13 @@ export default class UserMenu extends React.Component<IProps, IState> {
} }
}; };
private onOpenMenuClick = (ev: React.MouseEvent) => { private onOpenMenuClick = (ev: React.MouseEvent): void => {
ev.preventDefault(); ev.preventDefault();
ev.stopPropagation(); ev.stopPropagation();
this.setState({ contextMenuPosition: ev.currentTarget.getBoundingClientRect() }); this.setState({ contextMenuPosition: ev.currentTarget.getBoundingClientRect() });
}; };
private onContextMenu = (ev: React.MouseEvent) => { private onContextMenu = (ev: React.MouseEvent): void => {
ev.preventDefault(); ev.preventDefault();
ev.stopPropagation(); ev.stopPropagation();
this.setState({ this.setState({
@ -213,11 +213,11 @@ export default class UserMenu extends React.Component<IProps, IState> {
}); });
}; };
private onCloseMenu = () => { private onCloseMenu = (): void => {
this.setState({ contextMenuPosition: null }); this.setState({ contextMenuPosition: null });
}; };
private onSwitchThemeClick = (ev: React.MouseEvent) => { private onSwitchThemeClick = (ev: React.MouseEvent): void => {
ev.preventDefault(); ev.preventDefault();
ev.stopPropagation(); ev.stopPropagation();
@ -236,7 +236,7 @@ export default class UserMenu extends React.Component<IProps, IState> {
SettingsStore.setValue("theme", null, SettingLevel.DEVICE, newTheme); // set at same level as Appearance tab SettingsStore.setValue("theme", null, SettingLevel.DEVICE, newTheme); // set at same level as Appearance tab
}; };
private onSettingsOpen = (ev: ButtonEvent, tabId: string) => { private onSettingsOpen = (ev: ButtonEvent, tabId: string): void => {
ev.preventDefault(); ev.preventDefault();
ev.stopPropagation(); ev.stopPropagation();
@ -245,7 +245,7 @@ export default class UserMenu extends React.Component<IProps, IState> {
this.setState({ contextMenuPosition: null }); // also close the menu this.setState({ contextMenuPosition: null }); // also close the menu
}; };
private onProvideFeedback = (ev: ButtonEvent) => { private onProvideFeedback = (ev: ButtonEvent): void => {
ev.preventDefault(); ev.preventDefault();
ev.stopPropagation(); ev.stopPropagation();
@ -253,7 +253,7 @@ export default class UserMenu extends React.Component<IProps, IState> {
this.setState({ contextMenuPosition: null }); // also close the menu this.setState({ contextMenuPosition: null }); // also close the menu
}; };
private onSignOutClick = async (ev: ButtonEvent) => { private onSignOutClick = async (ev: ButtonEvent): Promise<void> => {
ev.preventDefault(); ev.preventDefault();
ev.stopPropagation(); ev.stopPropagation();
@ -268,17 +268,17 @@ export default class UserMenu extends React.Component<IProps, IState> {
this.setState({ contextMenuPosition: null }); // also close the menu this.setState({ contextMenuPosition: null }); // also close the menu
}; };
private onSignInClick = () => { private onSignInClick = (): void => {
defaultDispatcher.dispatch({ action: "start_login" }); defaultDispatcher.dispatch({ action: "start_login" });
this.setState({ contextMenuPosition: null }); // also close the menu this.setState({ contextMenuPosition: null }); // also close the menu
}; };
private onRegisterClick = () => { private onRegisterClick = (): void => {
defaultDispatcher.dispatch({ action: "start_registration" }); defaultDispatcher.dispatch({ action: "start_registration" });
this.setState({ contextMenuPosition: null }); // also close the menu this.setState({ contextMenuPosition: null }); // also close the menu
}; };
private onHomeClick = (ev: ButtonEvent) => { private onHomeClick = (ev: ButtonEvent): void => {
ev.preventDefault(); ev.preventDefault();
ev.stopPropagation(); ev.stopPropagation();
@ -429,7 +429,7 @@ export default class UserMenu extends React.Component<IProps, IState> {
); );
}; };
public render() { public render(): JSX.Element {
const avatarSize = 32; // should match border-radius of the avatar const avatarSize = 32; // should match border-radius of the avatar
const userId = MatrixClientPeg.get().getUserId(); const userId = MatrixClientPeg.get().getUserId();

View File

@ -57,7 +57,7 @@ export default class CompleteSecurity extends React.Component<IProps, IState> {
store.stop(); store.stop();
} }
public render() { public render(): JSX.Element {
const { phase, lostKeys } = this.state; const { phase, lostKeys } = this.state;
let icon; let icon;
let title; let title;

View File

@ -27,7 +27,7 @@ interface IProps {
} }
export default class E2eSetup extends React.Component<IProps> { export default class E2eSetup extends React.Component<IProps> {
public render() { public render(): JSX.Element {
return ( return (
<AuthPage> <AuthPage>
<CompleteSecurityBody> <CompleteSecurityBody>

View File

@ -110,11 +110,11 @@ export default class ForgotPassword extends React.Component<Props, State> {
this.reset = new PasswordReset(this.props.serverConfig.hsUrl, this.props.serverConfig.isUrl); this.reset = new PasswordReset(this.props.serverConfig.hsUrl, this.props.serverConfig.isUrl);
} }
public componentDidMount() { public componentDidMount(): void {
this.checkServerCapabilities(this.props.serverConfig); this.checkServerCapabilities(this.props.serverConfig);
} }
public componentDidUpdate(prevProps: Readonly<Props>) { public componentDidUpdate(prevProps: Readonly<Props>): void {
if ( if (
prevProps.serverConfig.hsUrl !== this.props.serverConfig.hsUrl || prevProps.serverConfig.hsUrl !== this.props.serverConfig.hsUrl ||
prevProps.serverConfig.isUrl !== this.props.serverConfig.isUrl prevProps.serverConfig.isUrl !== this.props.serverConfig.isUrl
@ -159,7 +159,7 @@ export default class ForgotPassword extends React.Component<Props, State> {
}); });
} }
private async onPhaseEmailInputSubmit() { private async onPhaseEmailInputSubmit(): Promise<void> {
this.phase = Phase.SendingEmail; this.phase = Phase.SendingEmail;
if (await this.sendVerificationMail()) { if (await this.sendVerificationMail()) {
@ -213,7 +213,7 @@ export default class ForgotPassword extends React.Component<Props, State> {
}); });
} }
private async onPhaseEmailSentSubmit() { private async onPhaseEmailSentSubmit(): Promise<void> {
this.setState({ this.setState({
phase: Phase.PasswordInput, phase: Phase.PasswordInput,
}); });
@ -288,7 +288,7 @@ export default class ForgotPassword extends React.Component<Props, State> {
false, false,
false, false,
{ {
onBeforeClose: async (reason?: string) => { onBeforeClose: async (reason?: string): Promise<boolean> => {
if (reason === "backgroundClick") { if (reason === "backgroundClick") {
// Modal dismissed by clicking the background. // Modal dismissed by clicking the background.
// Go one phase back. // Go one phase back.
@ -342,7 +342,7 @@ export default class ForgotPassword extends React.Component<Props, State> {
} }
}; };
private onInputChanged = (stateKey: string, ev: React.FormEvent<HTMLInputElement>) => { private onInputChanged = (stateKey: string, ev: React.FormEvent<HTMLInputElement>): void => {
let value = ev.currentTarget.value; let value = ev.currentTarget.value;
if (stateKey === "email") value = value.trim(); if (stateKey === "email") value = value.trim();
this.setState({ this.setState({
@ -460,7 +460,7 @@ export default class ForgotPassword extends React.Component<Props, State> {
); );
} }
public renderDone() { public renderDone(): JSX.Element {
return ( return (
<> <>
<CheckboxIcon className="mx_Icon mx_Icon_32 mx_Icon_accent" /> <CheckboxIcon className="mx_Icon mx_Icon_32 mx_Icon_accent" />
@ -484,7 +484,7 @@ export default class ForgotPassword extends React.Component<Props, State> {
); );
} }
public render() { public render(): JSX.Element {
let resetPasswordJsx: JSX.Element; let resetPasswordJsx: JSX.Element;
switch (this.state.phase) { switch (this.state.phase) {

Some files were not shown because too many files have changed in this diff Show More