Merge branch 'develop' of github.com:matrix-org/matrix-react-sdk into t3chguy/fix/17686
Conflicts: src/components/views/dialogs/CreateRoomDialog.tsx src/components/views/dialogs/RoomUpgradeDialog.tsx src/components/views/dialogs/RoomUpgradeWarningDialog.tsx src/components/views/settings/tabs/room/SecurityRoomSettingsTab.tsx
This commit is contained in:
commit
390b05617c
324 changed files with 4440 additions and 3040 deletions
|
@ -90,7 +90,7 @@ export default class AutoDiscoveryUtils {
|
|||
href="https://github.com/vector-im/element-web/blob/master/docs/config.md"
|
||||
target="_blank"
|
||||
rel="noreferrer noopener"
|
||||
>{sub}</a>;
|
||||
>{ sub }</a>;
|
||||
},
|
||||
},
|
||||
);
|
||||
|
@ -130,8 +130,8 @@ export default class AutoDiscoveryUtils {
|
|||
serverErrorIsFatal: isFatalError,
|
||||
serverDeadError: (
|
||||
<div>
|
||||
<strong>{title}</strong>
|
||||
<div>{body}</div>
|
||||
<strong>{ title }</strong>
|
||||
<div>{ body }</div>
|
||||
</div>
|
||||
),
|
||||
};
|
||||
|
|
|
@ -44,7 +44,7 @@ export function messageForResourceLimitError(
|
|||
|
||||
const linkSub = sub => {
|
||||
if (adminContact) {
|
||||
return <a href={adminContact} target="_blank" rel="noreferrer noopener">{sub}</a>;
|
||||
return <a href={adminContact} target="_blank" rel="noreferrer noopener">{ sub }</a>;
|
||||
} else {
|
||||
return sub;
|
||||
}
|
||||
|
@ -76,12 +76,12 @@ export function messageForSyncError(err: MatrixError | Error): ReactNode {
|
|||
},
|
||||
);
|
||||
return <div>
|
||||
<div>{limitError}</div>
|
||||
<div>{adminContact}</div>
|
||||
<div>{ limitError }</div>
|
||||
<div>{ adminContact }</div>
|
||||
</div>;
|
||||
} else {
|
||||
return <div>
|
||||
{_t("Unable to connect to Homeserver. Retrying...")}
|
||||
{ _t("Unable to connect to Homeserver. Retrying...") }
|
||||
</div>;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -111,14 +111,19 @@ export function getEventDisplayInfo(mxEvent: MatrixEvent): {
|
|||
let tileHandler = getHandlerTile(mxEvent);
|
||||
|
||||
// Info messages are basically information about commands processed on a room
|
||||
let isBubbleMessage = eventType.startsWith("m.key.verification") ||
|
||||
(eventType === EventType.RoomMessage && msgtype && msgtype.startsWith("m.key.verification")) ||
|
||||
(eventType === EventType.RoomCreate) ||
|
||||
(eventType === EventType.RoomEncryption) ||
|
||||
(tileHandler === "messages.MJitsiWidgetEvent");
|
||||
let isBubbleMessage = (
|
||||
eventType.startsWith("m.key.verification") ||
|
||||
(eventType === EventType.RoomMessage && msgtype && msgtype.startsWith("m.key.verification")) ||
|
||||
(eventType === EventType.RoomCreate) ||
|
||||
(eventType === EventType.RoomEncryption) ||
|
||||
(eventType === EventType.CallInvite) ||
|
||||
(tileHandler === "messages.MJitsiWidgetEvent")
|
||||
);
|
||||
let isInfoMessage = (
|
||||
!isBubbleMessage && eventType !== EventType.RoomMessage &&
|
||||
eventType !== EventType.Sticker && eventType !== EventType.RoomCreate
|
||||
!isBubbleMessage &&
|
||||
eventType !== EventType.RoomMessage &&
|
||||
eventType !== EventType.Sticker &&
|
||||
eventType !== EventType.RoomCreate
|
||||
);
|
||||
|
||||
// If we're showing hidden events in the timeline, we should use the
|
||||
|
|
59
src/utils/LazyValue.ts
Normal file
59
src/utils/LazyValue.ts
Normal file
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
Copyright 2021 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Utility class for lazily getting a variable.
|
||||
*/
|
||||
export class LazyValue<T> {
|
||||
private val: T;
|
||||
private prom: Promise<T>;
|
||||
private done = false;
|
||||
|
||||
public constructor(private getFn: () => Promise<T>) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not a cached value is present.
|
||||
*/
|
||||
public get present(): boolean {
|
||||
// we use a tracking variable just in case the final value is falsey
|
||||
return this.done;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value without invoking a get. May be undefined until the
|
||||
* value is fetched properly.
|
||||
*/
|
||||
public get cachedValue(): T {
|
||||
return this.val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a promise which resolves to the value, eventually.
|
||||
*/
|
||||
public get value(): Promise<T> {
|
||||
if (this.prom) return this.prom;
|
||||
this.prom = this.getFn();
|
||||
|
||||
// Fork the promise chain to avoid accidentally making it return undefined always.
|
||||
this.prom.then(v => {
|
||||
this.val = v;
|
||||
this.done = true;
|
||||
});
|
||||
|
||||
return this.prom;
|
||||
}
|
||||
}
|
119
src/utils/MediaEventHelper.ts
Normal file
119
src/utils/MediaEventHelper.ts
Normal file
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
Copyright 2021 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { MatrixEvent } from "matrix-js-sdk/src";
|
||||
import { LazyValue } from "./LazyValue";
|
||||
import { Media, mediaFromContent } from "../customisations/Media";
|
||||
import { decryptFile } from "./DecryptFile";
|
||||
import { IMediaEventContent } from "../customisations/models/IMediaEventContent";
|
||||
import { IDestroyable } from "./IDestroyable";
|
||||
import { EventType, MsgType } from "matrix-js-sdk/src/@types/event";
|
||||
|
||||
// TODO: We should consider caching the blobs. https://github.com/vector-im/element-web/issues/17192
|
||||
|
||||
export class MediaEventHelper implements IDestroyable {
|
||||
// Either an HTTP or Object URL (when encrypted) to the media.
|
||||
public readonly sourceUrl: LazyValue<string>;
|
||||
public readonly thumbnailUrl: LazyValue<string>;
|
||||
|
||||
// Either the raw or decrypted (when encrypted) contents of the file.
|
||||
public readonly sourceBlob: LazyValue<Blob>;
|
||||
public readonly thumbnailBlob: LazyValue<Blob>;
|
||||
|
||||
public readonly media: Media;
|
||||
|
||||
public constructor(private event: MatrixEvent) {
|
||||
this.sourceUrl = new LazyValue(this.prepareSourceUrl);
|
||||
this.thumbnailUrl = new LazyValue(this.prepareThumbnailUrl);
|
||||
this.sourceBlob = new LazyValue(this.fetchSource);
|
||||
this.thumbnailBlob = new LazyValue(this.fetchThumbnail);
|
||||
|
||||
this.media = mediaFromContent(this.event.getContent());
|
||||
}
|
||||
|
||||
public get fileName(): string {
|
||||
return this.event.getContent<IMediaEventContent>().body || "download";
|
||||
}
|
||||
|
||||
public destroy() {
|
||||
if (this.media.isEncrypted) {
|
||||
if (this.sourceUrl.present) URL.revokeObjectURL(this.sourceUrl.cachedValue);
|
||||
if (this.thumbnailUrl.present) URL.revokeObjectURL(this.thumbnailUrl.cachedValue);
|
||||
}
|
||||
}
|
||||
|
||||
private prepareSourceUrl = async () => {
|
||||
if (this.media.isEncrypted) {
|
||||
const blob = await this.sourceBlob.value;
|
||||
return URL.createObjectURL(blob);
|
||||
} else {
|
||||
return this.media.srcHttp;
|
||||
}
|
||||
};
|
||||
|
||||
private prepareThumbnailUrl = async () => {
|
||||
if (this.media.isEncrypted) {
|
||||
const blob = await this.thumbnailBlob.value;
|
||||
return URL.createObjectURL(blob);
|
||||
} else {
|
||||
return this.media.thumbnailHttp;
|
||||
}
|
||||
};
|
||||
|
||||
private fetchSource = () => {
|
||||
if (this.media.isEncrypted) {
|
||||
return decryptFile(this.event.getContent<IMediaEventContent>().file);
|
||||
}
|
||||
return this.media.downloadSource().then(r => r.blob());
|
||||
};
|
||||
|
||||
private fetchThumbnail = () => {
|
||||
if (!this.media.hasThumbnail) return Promise.resolve(null);
|
||||
|
||||
if (this.media.isEncrypted) {
|
||||
const content = this.event.getContent<IMediaEventContent>();
|
||||
if (content.info?.thumbnail_file) {
|
||||
return decryptFile(content.info.thumbnail_file);
|
||||
} else {
|
||||
// "Should never happen"
|
||||
console.warn("Media claims to have thumbnail and is encrypted, but no thumbnail_file found");
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
}
|
||||
|
||||
return fetch(this.media.thumbnailHttp).then(r => r.blob());
|
||||
};
|
||||
|
||||
public static isEligible(event: MatrixEvent): boolean {
|
||||
if (!event) return false;
|
||||
if (event.isRedacted()) return false;
|
||||
if (event.getType() === EventType.Sticker) return true;
|
||||
if (event.getType() !== EventType.RoomMessage) return false;
|
||||
|
||||
const content = event.getContent();
|
||||
const mediaMsgTypes: string[] = [
|
||||
MsgType.Video,
|
||||
MsgType.Audio,
|
||||
MsgType.Image,
|
||||
MsgType.File,
|
||||
];
|
||||
if (mediaMsgTypes.includes(content.msgtype)) return true;
|
||||
if (typeof(content.url) === 'string') return true;
|
||||
|
||||
// Finally, it's probably not media
|
||||
return false;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue