Merge branch 'develop' into export-conversations

This commit is contained in:
Jaiwanth 2021-09-22 18:07:01 +05:30
commit 94e4fb71c1
498 changed files with 13790 additions and 23008 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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