Merge branch 'develop' into export-conversations
This commit is contained in:
commit
94e4fb71c1
498 changed files with 13790 additions and 23008 deletions
|
@ -144,3 +144,12 @@ export function getEventDisplayInfo(mxEvent: MatrixEvent): {
|
|||
|
||||
return { tileHandler, isInfoMessage, isBubbleMessage, isLeftAlignedBubbleMessage };
|
||||
}
|
||||
|
||||
export function isVoiceMessage(mxEvent: MatrixEvent): boolean {
|
||||
const content = mxEvent.getContent();
|
||||
// MSC2516 is a legacy identifier. See https://github.com/matrix-org/matrix-doc/pull/3245
|
||||
return (
|
||||
!!content['org.matrix.msc2516.voice'] ||
|
||||
!!content['org.matrix.msc3245.voice']
|
||||
);
|
||||
}
|
||||
|
|
|
@ -20,9 +20,10 @@ limitations under the License.
|
|||
* author Roel Nieskens, https://pixelambacht.nl
|
||||
* MIT license
|
||||
*/
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
|
||||
function safariVersionCheck(ua: string): boolean {
|
||||
console.log("Browser is Safari - checking version for COLR support");
|
||||
logger.log("Browser is Safari - checking version for COLR support");
|
||||
try {
|
||||
const safariVersionMatch = ua.match(/Mac OS X ([\d|_]+).*Version\/([\d|.]+).*Safari/);
|
||||
if (safariVersionMatch) {
|
||||
|
@ -32,7 +33,7 @@ function safariVersionCheck(ua: string): boolean {
|
|||
const safariVersion = safariVersionStr.split(".").map(n => parseInt(n, 10));
|
||||
const colrFontSupported = macOSVersion[0] >= 10 && macOSVersion[1] >= 14 && safariVersion[0] >= 12;
|
||||
// https://www.colorfonts.wtf/ states safari supports COLR fonts from this version on
|
||||
console.log(`COLR support on Safari requires macOS 10.14 and Safari 12, ` +
|
||||
logger.log(`COLR support on Safari requires macOS 10.14 and Safari 12, ` +
|
||||
`detected Safari ${safariVersionStr} on macOS ${macOSVersionStr}, ` +
|
||||
`COLR supported: ${colrFontSupported}`);
|
||||
return colrFontSupported;
|
||||
|
@ -45,7 +46,7 @@ function safariVersionCheck(ua: string): boolean {
|
|||
}
|
||||
|
||||
async function isColrFontSupported(): Promise<boolean> {
|
||||
console.log("Checking for COLR support");
|
||||
logger.log("Checking for COLR support");
|
||||
|
||||
const { userAgent } = navigator;
|
||||
// Firefox has supported COLR fonts since version 26
|
||||
|
@ -53,7 +54,7 @@ async function isColrFontSupported(): Promise<boolean> {
|
|||
// "Extract canvas data" permissions
|
||||
// when content blocking is enabled.
|
||||
if (userAgent.includes("Firefox")) {
|
||||
console.log("Browser is Firefox - assuming COLR is supported");
|
||||
logger.log("Browser is Firefox - assuming COLR is supported");
|
||||
return true;
|
||||
}
|
||||
// Safari doesn't wait for the font to load (if it doesn't have it in cache)
|
||||
|
@ -87,12 +88,12 @@ async function isColrFontSupported(): Promise<boolean> {
|
|||
|
||||
img.src = 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(svg);
|
||||
|
||||
console.log("Waiting for COLR SVG to load");
|
||||
logger.log("Waiting for COLR SVG to load");
|
||||
await new Promise(resolve => img.onload = resolve);
|
||||
console.log("Drawing canvas to detect COLR support");
|
||||
logger.log("Drawing canvas to detect COLR support");
|
||||
context.drawImage(img, 0, 0);
|
||||
const colrFontSupported = (context.getImageData(10, 10, 1, 1).data[0] === 200);
|
||||
console.log("Canvas check revealed COLR is supported? " + colrFontSupported);
|
||||
logger.log("Canvas check revealed COLR is supported? " + colrFontSupported);
|
||||
return colrFontSupported;
|
||||
} catch (e) {
|
||||
console.error("Couldn't load COLR font", e);
|
||||
|
|
|
@ -104,7 +104,10 @@ export function getUserNameColorClass(userId: string): string {
|
|||
* @returns {string} a string constructed by joining `items` with a comma
|
||||
* between each item, but with the last item appended as " and [lastItem]".
|
||||
*/
|
||||
export function formatCommaSeparatedList(items: Array<string | JSX.Element>, itemLimit?: number): string | JSX.Element {
|
||||
export function formatCommaSeparatedList(items: string[], itemLimit?: number): string;
|
||||
export function formatCommaSeparatedList(items: JSX.Element[], itemLimit?: number): JSX.Element;
|
||||
export function formatCommaSeparatedList(items: Array<JSX.Element | string>, itemLimit?: number): JSX.Element | string;
|
||||
export function formatCommaSeparatedList(items: Array<JSX.Element | string>, itemLimit?: number): JSX.Element | string {
|
||||
const remaining = itemLimit === undefined ? 0 : Math.max(
|
||||
items.length - itemLimit, 0,
|
||||
);
|
||||
|
@ -112,11 +115,25 @@ export function formatCommaSeparatedList(items: Array<string | JSX.Element>, ite
|
|||
return "";
|
||||
} else if (items.length === 1) {
|
||||
return items[0];
|
||||
} else if (remaining > 0) {
|
||||
items = items.slice(0, itemLimit);
|
||||
return _t("%(items)s and %(count)s others", { items: jsxJoin(items, ', '), count: remaining } );
|
||||
} else {
|
||||
const lastItem = items.pop();
|
||||
return _t("%(items)s and %(lastItem)s", { items: jsxJoin(items, ', '), lastItem: lastItem });
|
||||
let lastItem;
|
||||
if (remaining > 0) {
|
||||
items = items.slice(0, itemLimit);
|
||||
} else {
|
||||
lastItem = items.pop();
|
||||
}
|
||||
|
||||
let joinedItems;
|
||||
if (items.every(e => typeof e === "string")) {
|
||||
joinedItems = items.join(", ");
|
||||
} else {
|
||||
joinedItems = jsxJoin(items, ", ");
|
||||
}
|
||||
|
||||
if (remaining > 0) {
|
||||
return _t("%(items)s and %(count)s others", { items: joinedItems, count: remaining } );
|
||||
} else {
|
||||
return _t("%(items)s and %(lastItem)s", { items: joinedItems, lastItem });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,8 @@ limitations under the License.
|
|||
import { _t } from '../languageHandler';
|
||||
import SdkConfig from '../SdkConfig';
|
||||
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
|
||||
const subtleCrypto = window.crypto.subtle || window.crypto.webkitSubtle;
|
||||
|
||||
/**
|
||||
|
@ -227,7 +229,7 @@ async function deriveKeys(salt, iterations, password) {
|
|||
}
|
||||
|
||||
const now = new Date();
|
||||
console.log("E2e import/export: deriveKeys took " + (now - start) + "ms");
|
||||
logger.log("E2e import/export: deriveKeys took " + (now - start) + "ms");
|
||||
|
||||
const aesKey = keybits.slice(0, 32);
|
||||
const hmacKey = keybits.slice(32);
|
||||
|
|
|
@ -25,6 +25,8 @@ import Modal from "../Modal";
|
|||
import SettingsStore from "../settings/SettingsStore";
|
||||
import AskInviteAnywayDialog from "../components/views/dialogs/AskInviteAnywayDialog";
|
||||
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
|
||||
export enum InviteState {
|
||||
Invited = "invited",
|
||||
Error = "error",
|
||||
|
@ -161,7 +163,7 @@ export default class MultiInviter {
|
|||
|
||||
private doInvite(address: string, ignoreProfile = false): Promise<void> {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
console.log(`Inviting ${address}`);
|
||||
logger.log(`Inviting ${address}`);
|
||||
|
||||
let doInvite;
|
||||
if (this.groupId !== null) {
|
||||
|
@ -271,7 +273,7 @@ export default class MultiInviter {
|
|||
return;
|
||||
}
|
||||
|
||||
console.log("Showing failed to invite dialog...");
|
||||
logger.log("Showing failed to invite dialog...");
|
||||
Modal.createTrackedDialog('Failed to invite', '', AskInviteAnywayDialog, {
|
||||
unknownProfileUsers: unknownProfileUsers.map(u => ({
|
||||
userId: u,
|
||||
|
|
|
@ -22,6 +22,7 @@ import Modal from "../Modal";
|
|||
import { _t } from "../languageHandler";
|
||||
import ErrorDialog from "../components/views/dialogs/ErrorDialog";
|
||||
import SpaceStore from "../stores/SpaceStore";
|
||||
import Spinner from "../components/views/elements/Spinner";
|
||||
|
||||
export async function upgradeRoom(
|
||||
room: Room,
|
||||
|
@ -29,8 +30,10 @@ export async function upgradeRoom(
|
|||
inviteUsers = false,
|
||||
handleError = true,
|
||||
updateSpaces = true,
|
||||
awaitRoom = false,
|
||||
): Promise<string> {
|
||||
const cli = room.client;
|
||||
const spinnerModal = Modal.createDialog(Spinner, null, "mx_Dialog_spinner");
|
||||
|
||||
let newRoomId: string;
|
||||
try {
|
||||
|
@ -46,27 +49,36 @@ export async function upgradeRoom(
|
|||
throw e;
|
||||
}
|
||||
|
||||
// We have to wait for the js-sdk to give us the room back so
|
||||
// we can more effectively abuse the MultiInviter behaviour
|
||||
// which heavily relies on the Room object being available.
|
||||
if (inviteUsers) {
|
||||
const checkForUpgradeFn = async (newRoom: Room): Promise<void> => {
|
||||
// The upgradePromise should be done by the time we await it here.
|
||||
if (newRoom.roomId !== newRoomId) return;
|
||||
|
||||
const toInvite = [
|
||||
...room.getMembersWithMembership("join"),
|
||||
...room.getMembersWithMembership("invite"),
|
||||
].map(m => m.userId).filter(m => m !== cli.getUserId());
|
||||
|
||||
if (toInvite.length > 0) {
|
||||
// Errors are handled internally to this function
|
||||
await inviteUsersToRoom(newRoomId, toInvite);
|
||||
if (awaitRoom || inviteUsers) {
|
||||
await new Promise<void>(resolve => {
|
||||
// already have the room
|
||||
if (room.client.getRoom(newRoomId)) {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
cli.removeListener('Room', checkForUpgradeFn);
|
||||
};
|
||||
cli.on('Room', checkForUpgradeFn);
|
||||
// We have to wait for the js-sdk to give us the room back so
|
||||
// we can more effectively abuse the MultiInviter behaviour
|
||||
// which heavily relies on the Room object being available.
|
||||
const checkForRoomFn = (newRoom: Room) => {
|
||||
if (newRoom.roomId !== newRoomId) return;
|
||||
resolve();
|
||||
cli.off("Room", checkForRoomFn);
|
||||
};
|
||||
cli.on("Room", checkForRoomFn);
|
||||
});
|
||||
}
|
||||
|
||||
if (inviteUsers) {
|
||||
const toInvite = [
|
||||
...room.getMembersWithMembership("join"),
|
||||
...room.getMembersWithMembership("invite"),
|
||||
].map(m => m.userId).filter(m => m !== cli.getUserId());
|
||||
|
||||
if (toInvite.length > 0) {
|
||||
// Errors are handled internally to this function
|
||||
await inviteUsersToRoom(newRoomId, toInvite);
|
||||
}
|
||||
}
|
||||
|
||||
if (updateSpaces) {
|
||||
|
@ -89,5 +101,6 @@ export async function upgradeRoom(
|
|||
}
|
||||
}
|
||||
|
||||
spinnerModal.close();
|
||||
return newRoomId;
|
||||
}
|
||||
|
|
|
@ -19,6 +19,8 @@ import Analytics from '../Analytics';
|
|||
import { IndexedDBStore } from "matrix-js-sdk/src/store/indexeddb";
|
||||
import { IndexedDBCryptoStore } from "matrix-js-sdk/src/crypto/store/indexeddb-crypto-store";
|
||||
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
|
||||
const localStorage = window.localStorage;
|
||||
|
||||
// just *accessing* indexedDB throws an exception in firefox with
|
||||
|
@ -33,7 +35,7 @@ const SYNC_STORE_NAME = "riot-web-sync";
|
|||
const CRYPTO_STORE_NAME = "matrix-js-sdk:crypto";
|
||||
|
||||
function log(msg: string) {
|
||||
console.log(`StorageManager: ${msg}`);
|
||||
logger.log(`StorageManager: ${msg}`);
|
||||
}
|
||||
|
||||
function error(msg: string, ...args: string[]) {
|
||||
|
@ -47,15 +49,15 @@ function track(action: string) {
|
|||
export function tryPersistStorage() {
|
||||
if (navigator.storage && navigator.storage.persist) {
|
||||
navigator.storage.persist().then(persistent => {
|
||||
console.log("StorageManager: Persistent?", persistent);
|
||||
logger.log("StorageManager: Persistent?", persistent);
|
||||
});
|
||||
} else if (document.requestStorageAccess) { // Safari
|
||||
document.requestStorageAccess().then(
|
||||
() => console.log("StorageManager: Persistent?", true),
|
||||
() => console.log("StorageManager: Persistent?", false),
|
||||
() => logger.log("StorageManager: Persistent?", true),
|
||||
() => logger.log("StorageManager: Persistent?", false),
|
||||
);
|
||||
} else {
|
||||
console.log("StorageManager: Persistence unsupported");
|
||||
logger.log("StorageManager: Persistence unsupported");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,8 @@ limitations under the License.
|
|||
*/
|
||||
|
||||
import { Room } from "matrix-js-sdk/src/models/room";
|
||||
import { sleep } from "matrix-js-sdk/src/utils";
|
||||
|
||||
import { MatrixClientPeg } from "../MatrixClientPeg";
|
||||
import { _t } from "../languageHandler";
|
||||
import Modal from "../Modal";
|
||||
|
@ -83,9 +85,10 @@ export function isJoinedOrNearlyJoined(membership: string): boolean {
|
|||
return effective === EffectiveMembership.Join || effective === EffectiveMembership.Invite;
|
||||
}
|
||||
|
||||
export async function leaveRoomBehaviour(roomId: string) {
|
||||
export async function leaveRoomBehaviour(roomId: string, retry = true) {
|
||||
const cli = MatrixClientPeg.get();
|
||||
let leavingAllVersions = true;
|
||||
const history = await MatrixClientPeg.get().getRoomUpgradeHistory(roomId);
|
||||
const history = cli.getRoomUpgradeHistory(roomId);
|
||||
if (history && history.length > 0) {
|
||||
const currentRoom = history[history.length - 1];
|
||||
if (currentRoom.roomId !== roomId) {
|
||||
|
@ -95,20 +98,28 @@ export async function leaveRoomBehaviour(roomId: string) {
|
|||
}
|
||||
}
|
||||
|
||||
let results: { [roomId: string]: Error & { errcode: string, message: string } } = {};
|
||||
let results: { [roomId: string]: Error & { errcode?: string, message: string, data?: Record<string, any> } } = {};
|
||||
if (!leavingAllVersions) {
|
||||
try {
|
||||
await MatrixClientPeg.get().leave(roomId);
|
||||
await cli.leave(roomId);
|
||||
} catch (e) {
|
||||
if (e && e.data && e.data.errcode) {
|
||||
if (e?.data?.errcode) {
|
||||
const message = e.data.error || _t("Unexpected server error trying to leave the room");
|
||||
results[roomId] = Object.assign(new Error(message), { errcode: e.data.errcode });
|
||||
results[roomId] = Object.assign(new Error(message), { errcode: e.data.errcode, data: e.data });
|
||||
} else {
|
||||
results[roomId] = e || new Error("Failed to leave room for unknown causes");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
results = await MatrixClientPeg.get().leaveRoomChain(roomId);
|
||||
results = await cli.leaveRoomChain(roomId, retry);
|
||||
}
|
||||
|
||||
if (retry) {
|
||||
const limitExceededError = Object.values(results).find(e => e?.errcode === "M_LIMIT_EXCEEDED");
|
||||
if (limitExceededError) {
|
||||
await sleep(limitExceededError.data.retry_after_ms ?? 100);
|
||||
return leaveRoomBehaviour(roomId, false);
|
||||
}
|
||||
}
|
||||
|
||||
const errors = Object.entries(results).filter(r => !!r[1]);
|
||||
|
|
|
@ -162,7 +162,9 @@ export const leaveSpace = (space: Room) => {
|
|||
if (!leave) return;
|
||||
const modal = Modal.createDialog(Spinner, null, "mx_Dialog_spinner");
|
||||
try {
|
||||
await Promise.all(rooms.map(r => leaveRoomBehaviour(r.roomId)));
|
||||
for (const room of rooms) {
|
||||
await leaveRoomBehaviour(room.roomId);
|
||||
}
|
||||
await leaveRoomBehaviour(space.roomId);
|
||||
} finally {
|
||||
modal.close();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue