mirror of
https://github.com/element-hq/element-web.git
synced 2024-12-15 17:41:31 +03:00
Merge branch 'develop' of github.com:matrix-org/matrix-react-sdk into spaces-jump-to-room
This commit is contained in:
commit
a99b24ef83
666 changed files with 5083 additions and 5561 deletions
38
.eslintrc.js
38
.eslintrc.js
|
@ -1,7 +1,9 @@
|
||||||
module.exports = {
|
module.exports = {
|
||||||
extends: ["matrix-org", "matrix-org/react-legacy"],
|
plugins: ["matrix-org"],
|
||||||
parser: "babel-eslint",
|
extends: [
|
||||||
|
"plugin:matrix-org/babel",
|
||||||
|
"plugin:matrix-org/react",
|
||||||
|
],
|
||||||
env: {
|
env: {
|
||||||
browser: true,
|
browser: true,
|
||||||
node: true,
|
node: true,
|
||||||
|
@ -15,12 +17,32 @@ module.exports = {
|
||||||
"prefer-promise-reject-errors": "off",
|
"prefer-promise-reject-errors": "off",
|
||||||
"no-async-promise-executor": "off",
|
"no-async-promise-executor": "off",
|
||||||
"quotes": "off",
|
"quotes": "off",
|
||||||
},
|
"no-extra-boolean-cast": "off",
|
||||||
|
|
||||||
|
// Bind or arrow functions in props causes performance issues (but we
|
||||||
|
// currently use them in some places).
|
||||||
|
// It's disabled here, but we should using it sparingly.
|
||||||
|
"react/jsx-no-bind": "off",
|
||||||
|
"react/jsx-key": ["error"],
|
||||||
|
},
|
||||||
overrides: [{
|
overrides: [{
|
||||||
"files": ["src/**/*.{ts,tsx}", "test/**/*.{ts,tsx}"],
|
files: [
|
||||||
"extends": ["matrix-org/ts"],
|
"src/**/*.{ts,tsx}",
|
||||||
"rules": {
|
"test/**/*.{ts,tsx}",
|
||||||
|
],
|
||||||
|
extends: [
|
||||||
|
"plugin:matrix-org/typescript",
|
||||||
|
"plugin:matrix-org/react",
|
||||||
|
],
|
||||||
|
rules: {
|
||||||
|
// Things we do that break the ideal style
|
||||||
|
"prefer-promise-reject-errors": "off",
|
||||||
|
"quotes": "off",
|
||||||
|
"no-extra-boolean-cast": "off",
|
||||||
|
|
||||||
|
// Remove Babel things manually due to override limitations
|
||||||
|
"@babel/no-invalid-this": ["off"],
|
||||||
|
|
||||||
// We're okay being explicit at the moment
|
// We're okay being explicit at the moment
|
||||||
"@typescript-eslint/no-empty-interface": "off",
|
"@typescript-eslint/no-empty-interface": "off",
|
||||||
// We disable this while we're transitioning
|
// We disable this while we're transitioning
|
||||||
|
@ -28,8 +50,6 @@ module.exports = {
|
||||||
// We'd rather not do this but we do
|
// We'd rather not do this but we do
|
||||||
"@typescript-eslint/ban-ts-comment": "off",
|
"@typescript-eslint/ban-ts-comment": "off",
|
||||||
|
|
||||||
"quotes": "off",
|
|
||||||
"no-extra-boolean-cast": "off",
|
|
||||||
"no-restricted-properties": [
|
"no-restricted-properties": [
|
||||||
"error",
|
"error",
|
||||||
...buildRestrictedPropertiesOptions(
|
...buildRestrictedPropertiesOptions(
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
[include]
|
|
||||||
src/**/*.js
|
|
||||||
test/**/*.js
|
|
||||||
|
|
||||||
[ignore]
|
|
||||||
node_modules/
|
|
|
@ -10,7 +10,6 @@ module.exports = {
|
||||||
],
|
],
|
||||||
}],
|
}],
|
||||||
"@babel/preset-typescript",
|
"@babel/preset-typescript",
|
||||||
"@babel/preset-flow",
|
|
||||||
"@babel/preset-react",
|
"@babel/preset-react",
|
||||||
],
|
],
|
||||||
"plugins": [
|
"plugins": [
|
||||||
|
@ -19,7 +18,6 @@ module.exports = {
|
||||||
"@babel/plugin-proposal-numeric-separator",
|
"@babel/plugin-proposal-numeric-separator",
|
||||||
"@babel/plugin-proposal-class-properties",
|
"@babel/plugin-proposal-class-properties",
|
||||||
"@babel/plugin-proposal-object-rest-spread",
|
"@babel/plugin-proposal-object-rest-spread",
|
||||||
"@babel/plugin-transform-flow-comments",
|
|
||||||
"@babel/plugin-syntax-dynamic-import",
|
"@babel/plugin-syntax-dynamic-import",
|
||||||
"@babel/plugin-transform-runtime",
|
"@babel/plugin-transform-runtime",
|
||||||
],
|
],
|
||||||
|
|
14
package.json
14
package.json
|
@ -104,16 +104,16 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/cli": "^7.12.10",
|
"@babel/cli": "^7.12.10",
|
||||||
"@babel/core": "^7.12.10",
|
"@babel/core": "^7.12.10",
|
||||||
|
"@babel/eslint-parser": "^7.12.10",
|
||||||
|
"@babel/eslint-plugin": "^7.12.10",
|
||||||
"@babel/parser": "^7.12.11",
|
"@babel/parser": "^7.12.11",
|
||||||
"@babel/plugin-proposal-class-properties": "^7.12.1",
|
"@babel/plugin-proposal-class-properties": "^7.12.1",
|
||||||
"@babel/plugin-proposal-decorators": "^7.12.12",
|
"@babel/plugin-proposal-decorators": "^7.12.12",
|
||||||
"@babel/plugin-proposal-export-default-from": "^7.12.1",
|
"@babel/plugin-proposal-export-default-from": "^7.12.1",
|
||||||
"@babel/plugin-proposal-numeric-separator": "^7.12.7",
|
"@babel/plugin-proposal-numeric-separator": "^7.12.7",
|
||||||
"@babel/plugin-proposal-object-rest-spread": "^7.12.1",
|
"@babel/plugin-proposal-object-rest-spread": "^7.12.1",
|
||||||
"@babel/plugin-transform-flow-comments": "^7.12.1",
|
|
||||||
"@babel/plugin-transform-runtime": "^7.12.10",
|
"@babel/plugin-transform-runtime": "^7.12.10",
|
||||||
"@babel/preset-env": "^7.12.11",
|
"@babel/preset-env": "^7.12.11",
|
||||||
"@babel/preset-flow": "^7.12.1",
|
|
||||||
"@babel/preset-react": "^7.12.10",
|
"@babel/preset-react": "^7.12.10",
|
||||||
"@babel/preset-typescript": "^7.12.7",
|
"@babel/preset-typescript": "^7.12.7",
|
||||||
"@babel/register": "^7.12.10",
|
"@babel/register": "^7.12.10",
|
||||||
|
@ -139,18 +139,16 @@
|
||||||
"@types/react-transition-group": "^4.4.0",
|
"@types/react-transition-group": "^4.4.0",
|
||||||
"@types/sanitize-html": "^2.3.1",
|
"@types/sanitize-html": "^2.3.1",
|
||||||
"@types/zxcvbn": "^4.4.0",
|
"@types/zxcvbn": "^4.4.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^4.14.0",
|
"@typescript-eslint/eslint-plugin": "^4.17.0",
|
||||||
"@typescript-eslint/parser": "^4.14.0",
|
"@typescript-eslint/parser": "^4.17.0",
|
||||||
"@wojtekmaj/enzyme-adapter-react-17": "^0.6.1",
|
"@wojtekmaj/enzyme-adapter-react-17": "^0.6.1",
|
||||||
"babel-eslint": "^10.1.0",
|
|
||||||
"babel-jest": "^26.6.3",
|
"babel-jest": "^26.6.3",
|
||||||
"chokidar": "^3.5.1",
|
"chokidar": "^3.5.1",
|
||||||
"concurrently": "^5.3.0",
|
"concurrently": "^5.3.0",
|
||||||
"enzyme": "^3.11.0",
|
"enzyme": "^3.11.0",
|
||||||
"eslint": "7.18.0",
|
"eslint": "7.18.0",
|
||||||
"eslint-config-matrix-org": "^0.2.0",
|
"eslint-config-google": "^0.14.0",
|
||||||
"eslint-plugin-babel": "^5.3.1",
|
"eslint-plugin-matrix-org": "github:matrix-org/eslint-plugin-matrix-org#main",
|
||||||
"eslint-plugin-flowtype": "^5.2.0",
|
|
||||||
"eslint-plugin-react": "^7.22.0",
|
"eslint-plugin-react": "^7.22.0",
|
||||||
"eslint-plugin-react-hooks": "^4.2.0",
|
"eslint-plugin-react-hooks": "^4.2.0",
|
||||||
"glob": "^7.1.6",
|
"glob": "^7.1.6",
|
||||||
|
|
|
@ -134,12 +134,15 @@ limitations under the License.
|
||||||
.mx_Toast_buttons {
|
.mx_Toast_buttons {
|
||||||
float: right;
|
float: right;
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 5px;
|
|
||||||
|
|
||||||
.mx_AccessibleButton {
|
.mx_AccessibleButton {
|
||||||
min-width: 96px;
|
min-width: 96px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mx_AccessibleButton + .mx_AccessibleButton {
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_Toast_description {
|
.mx_Toast_description {
|
||||||
|
|
|
@ -17,7 +17,7 @@ limitations under the License.
|
||||||
import { JSXElementConstructor } from "react";
|
import { JSXElementConstructor } from "react";
|
||||||
|
|
||||||
// Based on https://stackoverflow.com/a/53229857/3532235
|
// Based on https://stackoverflow.com/a/53229857/3532235
|
||||||
export type Without<T, U> = {[P in Exclude<keyof T, keyof U>] ? : never};
|
export type Without<T, U> = {[P in Exclude<keyof T, keyof U>]?: never};
|
||||||
export type XOR<T, U> = (T | U) extends object ? (Without<T, U> & U) | (Without<U, T> & T) : T | U;
|
export type XOR<T, U> = (T | U) extends object ? (Without<T, U> & U) | (Without<U, T> & T) : T | U;
|
||||||
export type Writeable<T> = { -readonly [P in keyof T]: T[P] };
|
export type Writeable<T> = { -readonly [P in keyof T]: T[P] };
|
||||||
|
|
||||||
|
|
32
src/@types/global.d.ts
vendored
32
src/@types/global.d.ts
vendored
|
@ -16,6 +16,7 @@ limitations under the License.
|
||||||
|
|
||||||
import "matrix-js-sdk/src/@types/global"; // load matrix-js-sdk's type extensions first
|
import "matrix-js-sdk/src/@types/global"; // load matrix-js-sdk's type extensions first
|
||||||
import * as ModernizrStatic from "modernizr";
|
import * as ModernizrStatic from "modernizr";
|
||||||
|
|
||||||
import ContentMessages from "../ContentMessages";
|
import ContentMessages from "../ContentMessages";
|
||||||
import { IMatrixClientPeg } from "../MatrixClientPeg";
|
import { IMatrixClientPeg } from "../MatrixClientPeg";
|
||||||
import ToastStore from "../stores/ToastStore";
|
import ToastStore from "../stores/ToastStore";
|
||||||
|
@ -23,25 +24,25 @@ import DeviceListener from "../DeviceListener";
|
||||||
import { RoomListStoreClass } from "../stores/room-list/RoomListStore";
|
import { RoomListStoreClass } from "../stores/room-list/RoomListStore";
|
||||||
import { PlatformPeg } from "../PlatformPeg";
|
import { PlatformPeg } from "../PlatformPeg";
|
||||||
import RoomListLayoutStore from "../stores/room-list/RoomListLayoutStore";
|
import RoomListLayoutStore from "../stores/room-list/RoomListLayoutStore";
|
||||||
import {IntegrationManagers} from "../integrations/IntegrationManagers";
|
import { IntegrationManagers } from "../integrations/IntegrationManagers";
|
||||||
import {ModalManager} from "../Modal";
|
import { ModalManager } from "../Modal";
|
||||||
import SettingsStore from "../settings/SettingsStore";
|
import SettingsStore from "../settings/SettingsStore";
|
||||||
import {ActiveRoomObserver} from "../ActiveRoomObserver";
|
import { ActiveRoomObserver } from "../ActiveRoomObserver";
|
||||||
import {Notifier} from "../Notifier";
|
import { Notifier } from "../Notifier";
|
||||||
import type {Renderer} from "react-dom";
|
import type { Renderer } from "react-dom";
|
||||||
import RightPanelStore from "../stores/RightPanelStore";
|
import RightPanelStore from "../stores/RightPanelStore";
|
||||||
import WidgetStore from "../stores/WidgetStore";
|
import WidgetStore from "../stores/WidgetStore";
|
||||||
import CallHandler from "../CallHandler";
|
import CallHandler from "../CallHandler";
|
||||||
import {Analytics} from "../Analytics";
|
import { Analytics } from "../Analytics";
|
||||||
import CountlyAnalytics from "../CountlyAnalytics";
|
import CountlyAnalytics from "../CountlyAnalytics";
|
||||||
import UserActivity from "../UserActivity";
|
import UserActivity from "../UserActivity";
|
||||||
import {ModalWidgetStore} from "../stores/ModalWidgetStore";
|
import { ModalWidgetStore } from "../stores/ModalWidgetStore";
|
||||||
import { WidgetLayoutStore } from "../stores/widgets/WidgetLayoutStore";
|
import { WidgetLayoutStore } from "../stores/widgets/WidgetLayoutStore";
|
||||||
import VoipUserMapper from "../VoipUserMapper";
|
import VoipUserMapper from "../VoipUserMapper";
|
||||||
import {SpaceStoreClass} from "../stores/SpaceStore";
|
import { SpaceStoreClass } from "../stores/SpaceStore";
|
||||||
import TypingStore from "../stores/TypingStore";
|
import TypingStore from "../stores/TypingStore";
|
||||||
import { EventIndexPeg } from "../indexing/EventIndexPeg";
|
import { EventIndexPeg } from "../indexing/EventIndexPeg";
|
||||||
import {VoiceRecordingStore} from "../stores/VoiceRecordingStore";
|
import { VoiceRecordingStore } from "../stores/VoiceRecordingStore";
|
||||||
import PerformanceMonitor from "../performance";
|
import PerformanceMonitor from "../performance";
|
||||||
import UIStore from "../stores/UIStore";
|
import UIStore from "../stores/UIStore";
|
||||||
import { SetupEncryptionStore } from "../stores/SetupEncryptionStore";
|
import { SetupEncryptionStore } from "../stores/SetupEncryptionStore";
|
||||||
|
@ -127,11 +128,24 @@ declare global {
|
||||||
setSinkId(outputId: string);
|
setSinkId(outputId: string);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add Chrome-specific `instant` ScrollBehaviour
|
||||||
|
type _ScrollBehavior = ScrollBehavior | "instant";
|
||||||
|
|
||||||
|
interface _ScrollOptions {
|
||||||
|
behavior?: _ScrollBehavior;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface _ScrollIntoViewOptions extends _ScrollOptions {
|
||||||
|
block?: ScrollLogicalPosition;
|
||||||
|
inline?: ScrollLogicalPosition;
|
||||||
|
}
|
||||||
|
|
||||||
interface Element {
|
interface Element {
|
||||||
// Safari & IE11 only have this prefixed: we used prefixed versions
|
// Safari & IE11 only have this prefixed: we used prefixed versions
|
||||||
// previously so let's continue to support them for now
|
// previously so let's continue to support them for now
|
||||||
webkitRequestFullScreen(options?: FullscreenOptions): Promise<void>;
|
webkitRequestFullScreen(options?: FullscreenOptions): Promise<void>;
|
||||||
msRequestFullscreen(options?: FullscreenOptions): Promise<void>;
|
msRequestFullscreen(options?: FullscreenOptions): Promise<void>;
|
||||||
|
scrollIntoView(arg?: boolean | _ScrollIntoViewOptions): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Error {
|
interface Error {
|
||||||
|
|
|
@ -16,12 +16,12 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {MatrixClientPeg} from './MatrixClientPeg';
|
import { MatrixClientPeg } from './MatrixClientPeg';
|
||||||
import * as sdk from './index';
|
import * as sdk from './index';
|
||||||
import Modal from './Modal';
|
import Modal from './Modal';
|
||||||
import { _t } from './languageHandler';
|
import { _t } from './languageHandler';
|
||||||
import IdentityAuthClient from './IdentityAuthClient';
|
import IdentityAuthClient from './IdentityAuthClient';
|
||||||
import {SSOAuthEntry} from "./components/views/auth/InteractiveAuthEntryComponents";
|
import { SSOAuthEntry } from "./components/views/auth/InteractiveAuthEntryComponents";
|
||||||
|
|
||||||
function getIdServerDomain() {
|
function getIdServerDomain() {
|
||||||
return MatrixClientPeg.get().idBaseUrl.split("://")[1];
|
return MatrixClientPeg.get().idBaseUrl.split("://")[1];
|
||||||
|
@ -189,7 +189,6 @@ export default class AddThreepid {
|
||||||
// pop up an interactive auth dialog
|
// pop up an interactive auth dialog
|
||||||
const InteractiveAuthDialog = sdk.getComponent("dialogs.InteractiveAuthDialog");
|
const InteractiveAuthDialog = sdk.getComponent("dialogs.InteractiveAuthDialog");
|
||||||
|
|
||||||
|
|
||||||
const dialogAesthetics = {
|
const dialogAesthetics = {
|
||||||
[SSOAuthEntry.PHASE_PREAUTH]: {
|
[SSOAuthEntry.PHASE_PREAUTH]: {
|
||||||
title: _t("Use Single Sign On to continue"),
|
title: _t("Use Single Sign On to continue"),
|
||||||
|
|
|
@ -17,7 +17,7 @@ limitations under the License.
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import {getCurrentLanguage, _t, _td, IVariables} from './languageHandler';
|
import { getCurrentLanguage, _t, _td, IVariables } from './languageHandler';
|
||||||
import PlatformPeg from './PlatformPeg';
|
import PlatformPeg from './PlatformPeg';
|
||||||
import SdkConfig from './SdkConfig';
|
import SdkConfig from './SdkConfig';
|
||||||
import Modal from './Modal';
|
import Modal from './Modal';
|
||||||
|
|
|
@ -17,16 +17,16 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {MatrixClient} from "matrix-js-sdk/src/client";
|
import { MatrixClient } from "matrix-js-sdk/src/client";
|
||||||
import {encodeUnpaddedBase64} from "matrix-js-sdk/src/crypto/olmlib";
|
import { encodeUnpaddedBase64 } from "matrix-js-sdk/src/crypto/olmlib";
|
||||||
import dis from './dispatcher/dispatcher';
|
import dis from './dispatcher/dispatcher';
|
||||||
import BaseEventIndexManager from './indexing/BaseEventIndexManager';
|
import BaseEventIndexManager from './indexing/BaseEventIndexManager';
|
||||||
import {ActionPayload} from "./dispatcher/payloads";
|
import { ActionPayload } from "./dispatcher/payloads";
|
||||||
import {CheckUpdatesPayload} from "./dispatcher/payloads/CheckUpdatesPayload";
|
import { CheckUpdatesPayload } from "./dispatcher/payloads/CheckUpdatesPayload";
|
||||||
import {Action} from "./dispatcher/actions";
|
import { Action } from "./dispatcher/actions";
|
||||||
import {hideToast as hideUpdateToast} from "./toasts/UpdateToast";
|
import { hideToast as hideUpdateToast } from "./toasts/UpdateToast";
|
||||||
import {MatrixClientPeg} from "./MatrixClientPeg";
|
import { MatrixClientPeg } from "./MatrixClientPeg";
|
||||||
import {idbLoad, idbSave, idbDelete} from "./utils/StorageManager";
|
import { idbLoad, idbSave, idbDelete } from "./utils/StorageManager";
|
||||||
|
|
||||||
export const SSO_HOMESERVER_URL_KEY = "mx_sso_hs_url";
|
export const SSO_HOMESERVER_URL_KEY = "mx_sso_hs_url";
|
||||||
export const SSO_ID_SERVER_URL_KEY = "mx_sso_is_url";
|
export const SSO_ID_SERVER_URL_KEY = "mx_sso_is_url";
|
||||||
|
@ -335,7 +335,7 @@ export default abstract class BasePlatform {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const key = await crypto.subtle.decrypt(
|
const key = await crypto.subtle.decrypt(
|
||||||
{name: "AES-GCM", iv: data.iv, additionalData}, data.cryptoKey,
|
{ name: "AES-GCM", iv: data.iv, additionalData }, data.cryptoKey,
|
||||||
data.encrypted,
|
data.encrypted,
|
||||||
);
|
);
|
||||||
return encodeUnpaddedBase64(key);
|
return encodeUnpaddedBase64(key);
|
||||||
|
@ -348,7 +348,7 @@ export default abstract class BasePlatform {
|
||||||
/**
|
/**
|
||||||
* Create and store a pickle key for encrypting libolm objects.
|
* Create and store a pickle key for encrypting libolm objects.
|
||||||
* @param {string} userId the user ID for the user that the pickle key is for.
|
* @param {string} userId the user ID for the user that the pickle key is for.
|
||||||
* @param {string} userId the device ID that the pickle key is for.
|
* @param {string} deviceId the device ID that the pickle key is for.
|
||||||
* @returns {string|null} the pickle key, or null if the platform does not
|
* @returns {string|null} the pickle key, or null if the platform does not
|
||||||
* support storing pickle keys.
|
* support storing pickle keys.
|
||||||
*/
|
*/
|
||||||
|
@ -360,7 +360,7 @@ export default abstract class BasePlatform {
|
||||||
const randomArray = new Uint8Array(32);
|
const randomArray = new Uint8Array(32);
|
||||||
crypto.getRandomValues(randomArray);
|
crypto.getRandomValues(randomArray);
|
||||||
const cryptoKey = await crypto.subtle.generateKey(
|
const cryptoKey = await crypto.subtle.generateKey(
|
||||||
{name: "AES-GCM", length: 256}, false, ["encrypt", "decrypt"],
|
{ name: "AES-GCM", length: 256 }, false, ["encrypt", "decrypt"],
|
||||||
);
|
);
|
||||||
const iv = new Uint8Array(32);
|
const iv = new Uint8Array(32);
|
||||||
crypto.getRandomValues(iv);
|
crypto.getRandomValues(iv);
|
||||||
|
@ -375,11 +375,11 @@ export default abstract class BasePlatform {
|
||||||
}
|
}
|
||||||
|
|
||||||
const encrypted = await crypto.subtle.encrypt(
|
const encrypted = await crypto.subtle.encrypt(
|
||||||
{name: "AES-GCM", iv, additionalData}, cryptoKey, randomArray,
|
{ name: "AES-GCM", iv, additionalData }, cryptoKey, randomArray,
|
||||||
);
|
);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await idbSave("pickleKey", [userId, deviceId], {encrypted, iv, cryptoKey});
|
await idbSave("pickleKey", [userId, deviceId], { encrypted, iv, cryptoKey });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,7 +55,7 @@ limitations under the License.
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import {MatrixClientPeg} from './MatrixClientPeg';
|
import { MatrixClientPeg } from './MatrixClientPeg';
|
||||||
import PlatformPeg from './PlatformPeg';
|
import PlatformPeg from './PlatformPeg';
|
||||||
import Modal from './Modal';
|
import Modal from './Modal';
|
||||||
import { _t } from './languageHandler';
|
import { _t } from './languageHandler';
|
||||||
|
@ -63,11 +63,11 @@ import dis from './dispatcher/dispatcher';
|
||||||
import WidgetUtils from './utils/WidgetUtils';
|
import WidgetUtils from './utils/WidgetUtils';
|
||||||
import WidgetEchoStore from './stores/WidgetEchoStore';
|
import WidgetEchoStore from './stores/WidgetEchoStore';
|
||||||
import SettingsStore from './settings/SettingsStore';
|
import SettingsStore from './settings/SettingsStore';
|
||||||
import {Jitsi} from "./widgets/Jitsi";
|
import { Jitsi } from "./widgets/Jitsi";
|
||||||
import {WidgetType} from "./widgets/WidgetType";
|
import { WidgetType } from "./widgets/WidgetType";
|
||||||
import {SettingLevel} from "./settings/SettingLevel";
|
import { SettingLevel } from "./settings/SettingLevel";
|
||||||
import { ActionPayload } from "./dispatcher/payloads";
|
import { ActionPayload } from "./dispatcher/payloads";
|
||||||
import {base32} from "rfc4648";
|
import { base32 } from "rfc4648";
|
||||||
|
|
||||||
import QuestionDialog from "./components/views/dialogs/QuestionDialog";
|
import QuestionDialog from "./components/views/dialogs/QuestionDialog";
|
||||||
import ErrorDialog from "./components/views/dialogs/ErrorDialog";
|
import ErrorDialog from "./components/views/dialogs/ErrorDialog";
|
||||||
|
@ -77,10 +77,10 @@ import { ElementWidgetActions } from "./stores/widgets/ElementWidgetActions";
|
||||||
import { MatrixCall, CallErrorCode, CallState, CallEvent, CallParty, CallType } from "matrix-js-sdk/src/webrtc/call";
|
import { MatrixCall, CallErrorCode, CallState, CallEvent, CallParty, CallType } from "matrix-js-sdk/src/webrtc/call";
|
||||||
import Analytics from './Analytics';
|
import Analytics from './Analytics';
|
||||||
import CountlyAnalytics from "./CountlyAnalytics";
|
import CountlyAnalytics from "./CountlyAnalytics";
|
||||||
import {UIFeature} from "./settings/UIFeature";
|
import { UIFeature } from "./settings/UIFeature";
|
||||||
import { CallError } from "matrix-js-sdk/src/webrtc/call";
|
import { CallError } from "matrix-js-sdk/src/webrtc/call";
|
||||||
import { logger } from 'matrix-js-sdk/src/logger';
|
import { logger } from 'matrix-js-sdk/src/logger';
|
||||||
import DesktopCapturerSourcePicker from "./components/views/elements/DesktopCapturerSourcePicker"
|
import DesktopCapturerSourcePicker from "./components/views/elements/DesktopCapturerSourcePicker";
|
||||||
import { Action } from './dispatcher/actions';
|
import { Action } from './dispatcher/actions';
|
||||||
import VoipUserMapper from './VoipUserMapper';
|
import VoipUserMapper from './VoipUserMapper';
|
||||||
import { addManagedHybridWidget, isManagedHybridWidgetEnabled } from './widgets/ManagedHybrid';
|
import { addManagedHybridWidget, isManagedHybridWidgetEnabled } from './widgets/ManagedHybrid';
|
||||||
|
@ -166,7 +166,7 @@ export default class CallHandler extends EventEmitter {
|
||||||
|
|
||||||
static sharedInstance() {
|
static sharedInstance() {
|
||||||
if (!window.mxCallHandler) {
|
if (!window.mxCallHandler) {
|
||||||
window.mxCallHandler = new CallHandler()
|
window.mxCallHandler = new CallHandler();
|
||||||
}
|
}
|
||||||
|
|
||||||
return window.mxCallHandler;
|
return window.mxCallHandler;
|
||||||
|
@ -185,7 +185,7 @@ export default class CallHandler extends EventEmitter {
|
||||||
const nativeUser = this.assertedIdentityNativeUsers[call.callId];
|
const nativeUser = this.assertedIdentityNativeUsers[call.callId];
|
||||||
if (nativeUser) {
|
if (nativeUser) {
|
||||||
const room = findDMForUser(MatrixClientPeg.get(), nativeUser);
|
const room = findDMForUser(MatrixClientPeg.get(), nativeUser);
|
||||||
if (room) return room.roomId
|
if (room) return room.roomId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -238,7 +238,7 @@ export default class CallHandler extends EventEmitter {
|
||||||
this.supportsPstnProtocol = null;
|
this.supportsPstnProtocol = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
dis.dispatch({action: Action.PstnSupportUpdated});
|
dis.dispatch({ action: Action.PstnSupportUpdated });
|
||||||
|
|
||||||
if (protocols[PROTOCOL_SIP_NATIVE] !== undefined && protocols[PROTOCOL_SIP_VIRTUAL] !== undefined) {
|
if (protocols[PROTOCOL_SIP_NATIVE] !== undefined && protocols[PROTOCOL_SIP_VIRTUAL] !== undefined) {
|
||||||
this.supportsSipNativeVirtual = Boolean(
|
this.supportsSipNativeVirtual = Boolean(
|
||||||
|
@ -246,7 +246,7 @@ export default class CallHandler extends EventEmitter {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
dis.dispatch({action: Action.VirtualRoomSupportUpdated});
|
dis.dispatch({ action: Action.VirtualRoomSupportUpdated });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (maxTries === 1) {
|
if (maxTries === 1) {
|
||||||
console.log("Failed to check for protocol support and no retries remain: assuming no support", e);
|
console.log("Failed to check for protocol support and no retries remain: assuming no support", e);
|
||||||
|
@ -299,7 +299,7 @@ export default class CallHandler extends EventEmitter {
|
||||||
action: 'incoming_call',
|
action: 'incoming_call',
|
||||||
call: call,
|
call: call,
|
||||||
}, true);
|
}, true);
|
||||||
}
|
};
|
||||||
|
|
||||||
getCallForRoom(roomId: string): MatrixCall {
|
getCallForRoom(roomId: string): MatrixCall {
|
||||||
return this.calls.get(roomId) || null;
|
return this.calls.get(roomId) || null;
|
||||||
|
@ -711,7 +711,7 @@ export default class CallHandler extends EventEmitter {
|
||||||
|
|
||||||
call.placeScreenSharingCall(
|
call.placeScreenSharingCall(
|
||||||
async (): Promise<DesktopCapturerSource> => {
|
async (): Promise<DesktopCapturerSource> => {
|
||||||
const {finished} = Modal.createDialog(DesktopCapturerSourcePicker);
|
const { finished } = Modal.createDialog(DesktopCapturerSourcePicker);
|
||||||
const [source] = await finished;
|
const [source] = await finished;
|
||||||
return source;
|
return source;
|
||||||
},
|
},
|
||||||
|
@ -816,7 +816,7 @@ export default class CallHandler extends EventEmitter {
|
||||||
|
|
||||||
Analytics.trackEvent('voip', 'receiveCall', 'type', call.type);
|
Analytics.trackEvent('voip', 'receiveCall', 'type', call.type);
|
||||||
console.log("Adding call for room ", mappedRoomId);
|
console.log("Adding call for room ", mappedRoomId);
|
||||||
this.calls.set(mappedRoomId, call)
|
this.calls.set(mappedRoomId, call);
|
||||||
this.emit(CallHandlerEvent.CallsChanged, this.calls);
|
this.emit(CallHandlerEvent.CallsChanged, this.calls);
|
||||||
this.setCallListeners(call);
|
this.setCallListeners(call);
|
||||||
|
|
||||||
|
@ -872,7 +872,7 @@ export default class CallHandler extends EventEmitter {
|
||||||
this.dialNumber(payload.number);
|
this.dialNumber(payload.number);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
private async dialNumber(number: string) {
|
private async dialNumber(number: string) {
|
||||||
const results = await this.pstnLookup(number);
|
const results = await this.pstnLookup(number);
|
||||||
|
@ -966,7 +966,7 @@ export default class CallHandler extends EventEmitter {
|
||||||
confId = 'Jitsi' + random;
|
confId = 'Jitsi' + random;
|
||||||
}
|
}
|
||||||
|
|
||||||
let widgetUrl = WidgetUtils.getLocalJitsiWrapperUrl({auth: jitsiAuth});
|
let widgetUrl = WidgetUtils.getLocalJitsiWrapperUrl({ auth: jitsiAuth });
|
||||||
|
|
||||||
// TODO: Remove URL hacks when the mobile clients eventually support v2 widgets
|
// TODO: Remove URL hacks when the mobile clients eventually support v2 widgets
|
||||||
const parsedUrl = new URL(widgetUrl);
|
const parsedUrl = new URL(widgetUrl);
|
||||||
|
|
|
@ -18,8 +18,8 @@ limitations under the License.
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import dis from './dispatcher/dispatcher';
|
import dis from './dispatcher/dispatcher';
|
||||||
import {MatrixClientPeg} from './MatrixClientPeg';
|
import { MatrixClientPeg } from './MatrixClientPeg';
|
||||||
import {MatrixClient} from "matrix-js-sdk/src/client";
|
import { MatrixClient } from "matrix-js-sdk/src/client";
|
||||||
import * as sdk from './index';
|
import * as sdk from './index';
|
||||||
import { _t } from './languageHandler';
|
import { _t } from './languageHandler';
|
||||||
import Modal from './Modal';
|
import Modal from './Modal';
|
||||||
|
@ -37,7 +37,7 @@ import {
|
||||||
UploadProgressPayload,
|
UploadProgressPayload,
|
||||||
UploadStartedPayload,
|
UploadStartedPayload,
|
||||||
} from "./dispatcher/payloads/UploadPayload";
|
} from "./dispatcher/payloads/UploadPayload";
|
||||||
import {IUpload} from "./models/IUpload";
|
import { IUpload } from "./models/IUpload";
|
||||||
import { IImageInfo } from "matrix-js-sdk/src/@types/partials";
|
import { IImageInfo } from "matrix-js-sdk/src/@types/partials";
|
||||||
|
|
||||||
const MAX_WIDTH = 800;
|
const MAX_WIDTH = 800;
|
||||||
|
@ -189,7 +189,7 @@ async function loadImageElement(imageFile: File) {
|
||||||
const [hidpi] = await Promise.all([parsePromise, imgPromise]);
|
const [hidpi] = await Promise.all([parsePromise, imgPromise]);
|
||||||
const width = hidpi ? (img.width >> 1) : img.width;
|
const width = hidpi ? (img.width >> 1) : img.width;
|
||||||
const height = hidpi ? (img.height >> 1) : img.height;
|
const height = hidpi ? (img.height >> 1) : img.height;
|
||||||
return {width, height, img};
|
return { width, height, img };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -343,7 +343,7 @@ export function uploadFile(
|
||||||
if (file.type) {
|
if (file.type) {
|
||||||
encryptInfo.mimetype = file.type;
|
encryptInfo.mimetype = file.type;
|
||||||
}
|
}
|
||||||
return {"file": encryptInfo};
|
return { "file": encryptInfo };
|
||||||
});
|
});
|
||||||
(prom as IAbortablePromise<any>).abort = () => {
|
(prom as IAbortablePromise<any>).abort = () => {
|
||||||
canceled = true;
|
canceled = true;
|
||||||
|
@ -357,7 +357,7 @@ export function uploadFile(
|
||||||
const promise1 = basePromise.then(function(url) {
|
const promise1 = basePromise.then(function(url) {
|
||||||
if (canceled) throw new UploadCanceledError();
|
if (canceled) throw new UploadCanceledError();
|
||||||
// If the attachment isn't encrypted then include the URL directly.
|
// If the attachment isn't encrypted then include the URL directly.
|
||||||
return {"url": url};
|
return { "url": url };
|
||||||
});
|
});
|
||||||
(promise1 as any).abort = () => {
|
(promise1 as any).abort = () => {
|
||||||
canceled = true;
|
canceled = true;
|
||||||
|
@ -377,7 +377,7 @@ export default class ContentMessages {
|
||||||
console.warn(`Failed to send content with URL ${url} to room ${roomId}`, e);
|
console.warn(`Failed to send content with URL ${url} to room ${roomId}`, e);
|
||||||
throw e;
|
throw e;
|
||||||
});
|
});
|
||||||
CountlyAnalytics.instance.trackSendMessage(startTime, prom, roomId, false, false, {msgtype: "m.sticker"});
|
CountlyAnalytics.instance.trackSendMessage(startTime, prom, roomId, false, false, { msgtype: "m.sticker" });
|
||||||
return prom;
|
return prom;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -391,14 +391,14 @@ export default class ContentMessages {
|
||||||
|
|
||||||
async sendContentListToRoom(files: File[], roomId: string, matrixClient: MatrixClient) {
|
async sendContentListToRoom(files: File[], roomId: string, matrixClient: MatrixClient) {
|
||||||
if (matrixClient.isGuest()) {
|
if (matrixClient.isGuest()) {
|
||||||
dis.dispatch({action: 'require_registration'});
|
dis.dispatch({ action: 'require_registration' });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const isQuoting = Boolean(RoomViewStore.getQuotingEvent());
|
const isQuoting = Boolean(RoomViewStore.getQuotingEvent());
|
||||||
if (isQuoting) {
|
if (isQuoting) {
|
||||||
const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog");
|
const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog");
|
||||||
const {finished} = Modal.createTrackedDialog<[boolean]>('Upload Reply Warning', '', QuestionDialog, {
|
const { finished } = Modal.createTrackedDialog<[boolean]>('Upload Reply Warning', '', QuestionDialog, {
|
||||||
title: _t('Replying With Files'),
|
title: _t('Replying With Files'),
|
||||||
description: (
|
description: (
|
||||||
<div>{_t(
|
<div>{_t(
|
||||||
|
@ -432,7 +432,7 @@ export default class ContentMessages {
|
||||||
|
|
||||||
if (tooBigFiles.length > 0) {
|
if (tooBigFiles.length > 0) {
|
||||||
const UploadFailureDialog = sdk.getComponent("dialogs.UploadFailureDialog");
|
const UploadFailureDialog = sdk.getComponent("dialogs.UploadFailureDialog");
|
||||||
const {finished} = Modal.createTrackedDialog<[boolean]>('Upload Failure', '', UploadFailureDialog, {
|
const { finished } = Modal.createTrackedDialog<[boolean]>('Upload Failure', '', UploadFailureDialog, {
|
||||||
badFiles: tooBigFiles,
|
badFiles: tooBigFiles,
|
||||||
totalFiles: files.length,
|
totalFiles: files.length,
|
||||||
contentMessages: this,
|
contentMessages: this,
|
||||||
|
@ -449,7 +449,7 @@ export default class ContentMessages {
|
||||||
for (let i = 0; i < okFiles.length; ++i) {
|
for (let i = 0; i < okFiles.length; ++i) {
|
||||||
const file = okFiles[i];
|
const file = okFiles[i];
|
||||||
if (!uploadAll) {
|
if (!uploadAll) {
|
||||||
const {finished} = Modal.createTrackedDialog<[boolean, boolean]>('Upload Files confirmation',
|
const { finished } = Modal.createTrackedDialog<[boolean, boolean]>('Upload Files confirmation',
|
||||||
'', UploadConfirmDialog, {
|
'', UploadConfirmDialog, {
|
||||||
file,
|
file,
|
||||||
currentIndex: i,
|
currentIndex: i,
|
||||||
|
@ -481,7 +481,7 @@ export default class ContentMessages {
|
||||||
if (upload) {
|
if (upload) {
|
||||||
upload.canceled = true;
|
upload.canceled = true;
|
||||||
MatrixClientPeg.get().cancelUpload(upload.promise);
|
MatrixClientPeg.get().cancelUpload(upload.promise);
|
||||||
dis.dispatch<UploadCanceledPayload>({action: Action.UploadCanceled, upload});
|
dis.dispatch<UploadCanceledPayload>({ action: Action.UploadCanceled, upload });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -542,7 +542,7 @@ export default class ContentMessages {
|
||||||
promise: prom,
|
promise: prom,
|
||||||
};
|
};
|
||||||
this.inprogress.push(upload);
|
this.inprogress.push(upload);
|
||||||
dis.dispatch<UploadStartedPayload>({action: Action.UploadStarted, upload});
|
dis.dispatch<UploadStartedPayload>({ action: Action.UploadStarted, upload });
|
||||||
|
|
||||||
// Focus the composer view
|
// Focus the composer view
|
||||||
dis.fire(Action.FocusComposer);
|
dis.fire(Action.FocusComposer);
|
||||||
|
@ -550,7 +550,7 @@ export default class ContentMessages {
|
||||||
function onProgress(ev) {
|
function onProgress(ev) {
|
||||||
upload.total = ev.total;
|
upload.total = ev.total;
|
||||||
upload.loaded = ev.loaded;
|
upload.loaded = ev.loaded;
|
||||||
dis.dispatch<UploadProgressPayload>({action: Action.UploadProgress, upload});
|
dis.dispatch<UploadProgressPayload>({ action: Action.UploadProgress, upload });
|
||||||
}
|
}
|
||||||
|
|
||||||
let error;
|
let error;
|
||||||
|
@ -577,11 +577,11 @@ export default class ContentMessages {
|
||||||
}, function(err) {
|
}, function(err) {
|
||||||
error = err;
|
error = err;
|
||||||
if (!upload.canceled) {
|
if (!upload.canceled) {
|
||||||
let desc = _t("The file '%(fileName)s' failed to upload.", {fileName: upload.fileName});
|
let desc = _t("The file '%(fileName)s' failed to upload.", { fileName: upload.fileName });
|
||||||
if (err.http_status === 413) {
|
if (err.http_status === 413) {
|
||||||
desc = _t(
|
desc = _t(
|
||||||
"The file '%(fileName)s' exceeds this homeserver's size limit for uploads",
|
"The file '%(fileName)s' exceeds this homeserver's size limit for uploads",
|
||||||
{fileName: upload.fileName},
|
{ fileName: upload.fileName },
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||||
|
@ -604,10 +604,10 @@ export default class ContentMessages {
|
||||||
if (error && error.http_status === 413) {
|
if (error && error.http_status === 413) {
|
||||||
this.mediaConfig = null;
|
this.mediaConfig = null;
|
||||||
}
|
}
|
||||||
dis.dispatch<UploadErrorPayload>({action: Action.UploadFailed, upload, error});
|
dis.dispatch<UploadErrorPayload>({ action: Action.UploadFailed, upload, error });
|
||||||
} else {
|
} else {
|
||||||
dis.dispatch<UploadFinishedPayload>({action: Action.UploadFinished, upload});
|
dis.dispatch<UploadFinishedPayload>({ action: Action.UploadFinished, upload });
|
||||||
dis.dispatch({action: 'message_sent'});
|
dis.dispatch({ action: 'message_sent' });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,13 +14,13 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {randomString} from "matrix-js-sdk/src/randomstring";
|
import { randomString } from "matrix-js-sdk/src/randomstring";
|
||||||
|
|
||||||
import {getCurrentLanguage} from './languageHandler';
|
import { getCurrentLanguage } from './languageHandler';
|
||||||
import PlatformPeg from './PlatformPeg';
|
import PlatformPeg from './PlatformPeg';
|
||||||
import SdkConfig from './SdkConfig';
|
import SdkConfig from './SdkConfig';
|
||||||
import {MatrixClientPeg} from "./MatrixClientPeg";
|
import { MatrixClientPeg } from "./MatrixClientPeg";
|
||||||
import {sleep} from "./utils/promise";
|
import { sleep } from "./utils/promise";
|
||||||
import RoomViewStore from "./stores/RoomViewStore";
|
import RoomViewStore from "./stores/RoomViewStore";
|
||||||
import { Action } from "./dispatcher/actions";
|
import { Action } from "./dispatcher/actions";
|
||||||
|
|
||||||
|
@ -338,8 +338,8 @@ const getRoomStats = (roomId: string) => {
|
||||||
"is_encrypted": cli?.isRoomEncrypted(roomId),
|
"is_encrypted": cli?.isRoomEncrypted(roomId),
|
||||||
// eslint-disable-next-line camelcase
|
// eslint-disable-next-line camelcase
|
||||||
"is_public": room?.currentState.getStateEvents("m.room.join_rules", "")?.getContent()?.join_rule === "public",
|
"is_public": room?.currentState.getStateEvents("m.room.join_rules", "")?.getContent()?.join_rule === "public",
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
// async wrapper for regex-powered String.prototype.replace
|
// async wrapper for regex-powered String.prototype.replace
|
||||||
const strReplaceAsync = async (str: string, regex: RegExp, fn: (...args: string[]) => Promise<string>) => {
|
const strReplaceAsync = async (str: string, regex: RegExp, fn: (...args: string[]) => Promise<string>) => {
|
||||||
|
@ -414,7 +414,7 @@ export default class CountlyAnalytics {
|
||||||
|
|
||||||
this.anonymous = anonymous;
|
this.anonymous = anonymous;
|
||||||
if (anonymous) {
|
if (anonymous) {
|
||||||
await this.changeUserKey(randomString(64))
|
await this.changeUserKey(randomString(64));
|
||||||
} else {
|
} else {
|
||||||
await this.changeUserKey(await hashHex(MatrixClientPeg.get().getUserId()), true);
|
await this.changeUserKey(await hashHex(MatrixClientPeg.get().getUserId()), true);
|
||||||
}
|
}
|
||||||
|
@ -438,7 +438,7 @@ export default class CountlyAnalytics {
|
||||||
await this.track("Opt-Out" );
|
await this.track("Opt-Out" );
|
||||||
this.endSession();
|
this.endSession();
|
||||||
window.clearInterval(this.heartbeatIntervalId);
|
window.clearInterval(this.heartbeatIntervalId);
|
||||||
window.clearTimeout(this.activityIntervalId)
|
window.clearTimeout(this.activityIntervalId);
|
||||||
this.baseUrl = null;
|
this.baseUrl = null;
|
||||||
// remove listeners bound in trackSessions()
|
// remove listeners bound in trackSessions()
|
||||||
window.removeEventListener("beforeunload", this.endSession);
|
window.removeEventListener("beforeunload", this.endSession);
|
||||||
|
@ -662,14 +662,14 @@ export default class CountlyAnalytics {
|
||||||
}
|
}
|
||||||
|
|
||||||
private queue(args: Omit<IEvent, "timestamp" | "hour" | "dow" | "count"> & Partial<Pick<IEvent, "count">>) {
|
private queue(args: Omit<IEvent, "timestamp" | "hour" | "dow" | "count"> & Partial<Pick<IEvent, "count">>) {
|
||||||
const {count = 1, ...rest} = args;
|
const { count = 1, ...rest } = args;
|
||||||
const ev = {
|
const ev = {
|
||||||
...this.getTimeParams(),
|
...this.getTimeParams(),
|
||||||
...rest,
|
...rest,
|
||||||
count,
|
count,
|
||||||
platform: this.appPlatform,
|
platform: this.appPlatform,
|
||||||
app_version: this.appVersion,
|
app_version: this.appVersion,
|
||||||
}
|
};
|
||||||
|
|
||||||
this.pendingEvents.push(ev);
|
this.pendingEvents.push(ev);
|
||||||
if (this.pendingEvents.length > MAX_PENDING_EVENTS) {
|
if (this.pendingEvents.length > MAX_PENDING_EVENTS) {
|
||||||
|
@ -680,7 +680,7 @@ export default class CountlyAnalytics {
|
||||||
private getOrientation = (): Orientation => {
|
private getOrientation = (): Orientation => {
|
||||||
return window.matchMedia("(orientation: landscape)").matches
|
return window.matchMedia("(orientation: landscape)").matches
|
||||||
? Orientation.Landscape
|
? Orientation.Landscape
|
||||||
: Orientation.Portrait
|
: Orientation.Portrait;
|
||||||
};
|
};
|
||||||
|
|
||||||
private reportOrientation = () => {
|
private reportOrientation = () => {
|
||||||
|
@ -749,7 +749,7 @@ export default class CountlyAnalytics {
|
||||||
const request: Parameters<typeof CountlyAnalytics.prototype.request>[0] = {
|
const request: Parameters<typeof CountlyAnalytics.prototype.request>[0] = {
|
||||||
begin_session: 1,
|
begin_session: 1,
|
||||||
user_details: JSON.stringify(userDetails),
|
user_details: JSON.stringify(userDetails),
|
||||||
}
|
};
|
||||||
|
|
||||||
const metrics = this.getMetrics();
|
const metrics = this.getMetrics();
|
||||||
if (metrics) {
|
if (metrics) {
|
||||||
|
@ -773,7 +773,7 @@ export default class CountlyAnalytics {
|
||||||
|
|
||||||
private endSession = () => {
|
private endSession = () => {
|
||||||
if (this.sessionStarted) {
|
if (this.sessionStarted) {
|
||||||
window.removeEventListener("resize", this.reportOrientation)
|
window.removeEventListener("resize", this.reportOrientation);
|
||||||
|
|
||||||
this.reportViewDuration();
|
this.reportViewDuration();
|
||||||
this.request({
|
this.request({
|
||||||
|
|
|
@ -168,7 +168,7 @@ export class DecryptionFailureTracker {
|
||||||
const trackedEventIds = [...dedupedFailuresMap.keys()];
|
const trackedEventIds = [...dedupedFailuresMap.keys()];
|
||||||
|
|
||||||
this.trackedEventHashMap = trackedEventIds.reduce(
|
this.trackedEventHashMap = trackedEventIds.reduce(
|
||||||
(result, eventId) => ({...result, [eventId]: true}),
|
(result, eventId) => ({ ...result, [eventId]: true }),
|
||||||
this.trackedEventHashMap,
|
this.trackedEventHashMap,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {MatrixClientPeg} from './MatrixClientPeg';
|
import { MatrixClientPeg } from './MatrixClientPeg';
|
||||||
import dis from "./dispatcher/dispatcher";
|
import dis from "./dispatcher/dispatcher";
|
||||||
import {
|
import {
|
||||||
hideToast as hideBulkUnverifiedSessionsToast,
|
hideToast as hideBulkUnverifiedSessionsToast,
|
||||||
|
|
|
@ -19,7 +19,7 @@ import Modal from './Modal';
|
||||||
import * as sdk from './';
|
import * as sdk from './';
|
||||||
import MultiInviter from './utils/MultiInviter';
|
import MultiInviter from './utils/MultiInviter';
|
||||||
import { _t } from './languageHandler';
|
import { _t } from './languageHandler';
|
||||||
import {MatrixClientPeg} from './MatrixClientPeg';
|
import { MatrixClientPeg } from './MatrixClientPeg';
|
||||||
import GroupStore from './stores/GroupStore';
|
import GroupStore from './stores/GroupStore';
|
||||||
import StyledCheckbox from './components/views/elements/StyledCheckbox';
|
import StyledCheckbox from './components/views/elements/StyledCheckbox';
|
||||||
|
|
||||||
|
@ -103,7 +103,7 @@ function _onGroupInviteFinished(groupId, addrs) {
|
||||||
if (errorList.length > 0) {
|
if (errorList.length > 0) {
|
||||||
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||||
Modal.createTrackedDialog('Failed to invite the following users to the group', '', ErrorDialog, {
|
Modal.createTrackedDialog('Failed to invite the following users to the group', '', ErrorDialog, {
|
||||||
title: _t("Failed to invite the following users to %(groupId)s:", {groupId: groupId}),
|
title: _t("Failed to invite the following users to %(groupId)s:", { groupId: groupId }),
|
||||||
description: errorList.join(", "),
|
description: errorList.join(", "),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -111,7 +111,7 @@ function _onGroupInviteFinished(groupId, addrs) {
|
||||||
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||||
Modal.createTrackedDialog('Failed to invite users to group', '', ErrorDialog, {
|
Modal.createTrackedDialog('Failed to invite users to group', '', ErrorDialog, {
|
||||||
title: _t("Failed to invite users to community"),
|
title: _t("Failed to invite users to community"),
|
||||||
description: _t("Failed to invite users to %(groupId)s", {groupId: groupId}),
|
description: _t("Failed to invite users to %(groupId)s", { groupId: groupId }),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -137,7 +137,7 @@ function _onGroupAddRoomFinished(groupId, addrs, addRoomsPublicly) {
|
||||||
// Add this group as related
|
// Add this group as related
|
||||||
if (!groups.includes(groupId)) {
|
if (!groups.includes(groupId)) {
|
||||||
groups.push(groupId);
|
groups.push(groupId);
|
||||||
return MatrixClientPeg.get().sendStateEvent(roomId, 'm.room.related_groups', {groups}, '');
|
return MatrixClientPeg.get().sendStateEvent(roomId, 'm.room.related_groups', { groups }, '');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
})).then(() => {
|
})).then(() => {
|
||||||
|
@ -152,7 +152,7 @@ function _onGroupAddRoomFinished(groupId, addrs, addRoomsPublicly) {
|
||||||
{
|
{
|
||||||
title: _t(
|
title: _t(
|
||||||
"Failed to add the following rooms to %(groupId)s:",
|
"Failed to add the following rooms to %(groupId)s:",
|
||||||
{groupId},
|
{ groupId },
|
||||||
),
|
),
|
||||||
description: errorList.join(", "),
|
description: errorList.join(", "),
|
||||||
},
|
},
|
||||||
|
|
|
@ -138,7 +138,7 @@ export function getHtmlText(insaneHtml: string): string {
|
||||||
selfClosing: [],
|
selfClosing: [],
|
||||||
allowedSchemes: [],
|
allowedSchemes: [],
|
||||||
disallowedTagsMode: 'discard',
|
disallowedTagsMode: 'discard',
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -183,7 +183,7 @@ const transformTags: IExtendedSanitizeOptions["transformTags"] = { // custom to
|
||||||
// images" preference is disabled. Future work might expose some UI to reveal them
|
// images" preference is disabled. Future work might expose some UI to reveal them
|
||||||
// like standalone image events have.
|
// like standalone image events have.
|
||||||
if (!attribs.src || !attribs.src.startsWith('mxc://') || !SettingsStore.getValue("showImages")) {
|
if (!attribs.src || !attribs.src.startsWith('mxc://') || !SettingsStore.getValue("showImages")) {
|
||||||
return { tagName, attribs: {}};
|
return { tagName, attribs: {} };
|
||||||
}
|
}
|
||||||
const width = Number(attribs.width) || 800;
|
const width = Number(attribs.width) || 800;
|
||||||
const height = Number(attribs.height) || 600;
|
const height = Number(attribs.height) || 600;
|
||||||
|
|
|
@ -17,7 +17,7 @@ limitations under the License.
|
||||||
import { SERVICE_TYPES } from 'matrix-js-sdk/src/service-types';
|
import { SERVICE_TYPES } from 'matrix-js-sdk/src/service-types';
|
||||||
import { createClient } from 'matrix-js-sdk/src/matrix';
|
import { createClient } from 'matrix-js-sdk/src/matrix';
|
||||||
|
|
||||||
import {MatrixClientPeg} from './MatrixClientPeg';
|
import { MatrixClientPeg } from './MatrixClientPeg';
|
||||||
import Modal from './Modal';
|
import Modal from './Modal';
|
||||||
import * as sdk from './index';
|
import * as sdk from './index';
|
||||||
import { _t } from './languageHandler';
|
import { _t } from './languageHandler';
|
||||||
|
|
|
@ -156,7 +156,7 @@ const messageComposerBindings = (): KeyBinding<MessageComposerAction>[] => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return bindings;
|
return bindings;
|
||||||
}
|
};
|
||||||
|
|
||||||
const autocompleteBindings = (): KeyBinding<AutocompleteAction>[] => {
|
const autocompleteBindings = (): KeyBinding<AutocompleteAction>[] => {
|
||||||
return [
|
return [
|
||||||
|
@ -207,7 +207,7 @@ const autocompleteBindings = (): KeyBinding<AutocompleteAction>[] => {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
}
|
};
|
||||||
|
|
||||||
const roomListBindings = (): KeyBinding<RoomListAction>[] => {
|
const roomListBindings = (): KeyBinding<RoomListAction>[] => {
|
||||||
return [
|
return [
|
||||||
|
@ -248,7 +248,7 @@ const roomListBindings = (): KeyBinding<RoomListAction>[] => {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
}
|
};
|
||||||
|
|
||||||
const roomBindings = (): KeyBinding<RoomAction>[] => {
|
const roomBindings = (): KeyBinding<RoomAction>[] => {
|
||||||
const bindings: KeyBinding<RoomAction>[] = [
|
const bindings: KeyBinding<RoomAction>[] = [
|
||||||
|
@ -312,7 +312,7 @@ const roomBindings = (): KeyBinding<RoomAction>[] => {
|
||||||
}
|
}
|
||||||
|
|
||||||
return bindings;
|
return bindings;
|
||||||
}
|
};
|
||||||
|
|
||||||
const navigationBindings = (): KeyBinding<NavigationAction>[] => {
|
const navigationBindings = (): KeyBinding<NavigationAction>[] => {
|
||||||
return [
|
return [
|
||||||
|
@ -396,7 +396,7 @@ const navigationBindings = (): KeyBinding<NavigationAction>[] => {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
}
|
};
|
||||||
|
|
||||||
export const defaultBindingsProvider: IKeyBindingsProvider = {
|
export const defaultBindingsProvider: IKeyBindingsProvider = {
|
||||||
getMessageComposerBindings: messageComposerBindings,
|
getMessageComposerBindings: messageComposerBindings,
|
||||||
|
@ -404,4 +404,4 @@ export const defaultBindingsProvider: IKeyBindingsProvider = {
|
||||||
getRoomListBindings: roomListBindings,
|
getRoomListBindings: roomListBindings,
|
||||||
getRoomBindings: roomBindings,
|
getRoomBindings: roomBindings,
|
||||||
getNavigationBindings: navigationBindings,
|
getNavigationBindings: navigationBindings,
|
||||||
}
|
};
|
||||||
|
|
|
@ -140,12 +140,12 @@ export type KeyCombo = {
|
||||||
ctrlKey?: boolean;
|
ctrlKey?: boolean;
|
||||||
metaKey?: boolean;
|
metaKey?: boolean;
|
||||||
shiftKey?: boolean;
|
shiftKey?: boolean;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type KeyBinding<T extends string> = {
|
export type KeyBinding<T extends string> = {
|
||||||
action: T;
|
action: T;
|
||||||
keyCombo: KeyCombo;
|
keyCombo: KeyCombo;
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper method to check if a KeyboardEvent matches a KeyCombo
|
* Helper method to check if a KeyboardEvent matches a KeyCombo
|
||||||
|
|
|
@ -20,9 +20,9 @@ limitations under the License.
|
||||||
import { createClient } from 'matrix-js-sdk/src/matrix';
|
import { createClient } from 'matrix-js-sdk/src/matrix';
|
||||||
import { InvalidStoreError } from "matrix-js-sdk/src/errors";
|
import { InvalidStoreError } from "matrix-js-sdk/src/errors";
|
||||||
import { MatrixClient } from "matrix-js-sdk/src/client";
|
import { MatrixClient } from "matrix-js-sdk/src/client";
|
||||||
import {decryptAES, encryptAES} from "matrix-js-sdk/src/crypto/aes";
|
import { decryptAES, encryptAES, IEncryptedPayload } from "matrix-js-sdk/src/crypto/aes";
|
||||||
|
|
||||||
import {IMatrixClientCreds, MatrixClientPeg} from './MatrixClientPeg';
|
import { IMatrixClientCreds, MatrixClientPeg } from './MatrixClientPeg';
|
||||||
import SecurityCustomisations from "./customisations/Security";
|
import SecurityCustomisations from "./customisations/Security";
|
||||||
import EventIndexPeg from './indexing/EventIndexPeg';
|
import EventIndexPeg from './indexing/EventIndexPeg';
|
||||||
import createMatrixClient from './utils/createMatrixClient';
|
import createMatrixClient from './utils/createMatrixClient';
|
||||||
|
@ -41,17 +41,17 @@ import * as StorageManager from './utils/StorageManager';
|
||||||
import SettingsStore from "./settings/SettingsStore";
|
import SettingsStore from "./settings/SettingsStore";
|
||||||
import TypingStore from "./stores/TypingStore";
|
import TypingStore from "./stores/TypingStore";
|
||||||
import ToastStore from "./stores/ToastStore";
|
import ToastStore from "./stores/ToastStore";
|
||||||
import {IntegrationManagers} from "./integrations/IntegrationManagers";
|
import { IntegrationManagers } from "./integrations/IntegrationManagers";
|
||||||
import {Mjolnir} from "./mjolnir/Mjolnir";
|
import { Mjolnir } from "./mjolnir/Mjolnir";
|
||||||
import DeviceListener from "./DeviceListener";
|
import DeviceListener from "./DeviceListener";
|
||||||
import {Jitsi} from "./widgets/Jitsi";
|
import { Jitsi } from "./widgets/Jitsi";
|
||||||
import {SSO_HOMESERVER_URL_KEY, SSO_ID_SERVER_URL_KEY, SSO_IDP_ID_KEY} from "./BasePlatform";
|
import { SSO_HOMESERVER_URL_KEY, SSO_ID_SERVER_URL_KEY, SSO_IDP_ID_KEY } from "./BasePlatform";
|
||||||
import ThreepidInviteStore from "./stores/ThreepidInviteStore";
|
import ThreepidInviteStore from "./stores/ThreepidInviteStore";
|
||||||
import CountlyAnalytics from "./CountlyAnalytics";
|
import CountlyAnalytics from "./CountlyAnalytics";
|
||||||
import CallHandler from './CallHandler';
|
import CallHandler from './CallHandler';
|
||||||
import LifecycleCustomisations from "./customisations/Lifecycle";
|
import LifecycleCustomisations from "./customisations/Lifecycle";
|
||||||
import ErrorDialog from "./components/views/dialogs/ErrorDialog";
|
import ErrorDialog from "./components/views/dialogs/ErrorDialog";
|
||||||
import {_t} from "./languageHandler";
|
import { _t } from "./languageHandler";
|
||||||
|
|
||||||
const HOMESERVER_URL_KEY = "mx_hs_url";
|
const HOMESERVER_URL_KEY = "mx_hs_url";
|
||||||
const ID_SERVER_URL_KEY = "mx_is_url";
|
const ID_SERVER_URL_KEY = "mx_is_url";
|
||||||
|
@ -154,7 +154,7 @@ export async function loadSession(opts: ILoadSessionOpts = {}): Promise<boolean>
|
||||||
* return [null, null].
|
* return [null, null].
|
||||||
*/
|
*/
|
||||||
export async function getStoredSessionOwner(): Promise<[string, boolean]> {
|
export async function getStoredSessionOwner(): Promise<[string, boolean]> {
|
||||||
const {hsUrl, userId, hasAccessToken, isGuest} = await getStoredSessionVars();
|
const { hsUrl, userId, hasAccessToken, isGuest } = await getStoredSessionVars();
|
||||||
return hsUrl && userId && hasAccessToken ? [userId, isGuest] : [null, null];
|
return hsUrl && userId && hasAccessToken ? [userId, isGuest] : [null, null];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -303,7 +303,7 @@ export interface IStoredSession {
|
||||||
hsUrl: string;
|
hsUrl: string;
|
||||||
isUrl: string;
|
isUrl: string;
|
||||||
hasAccessToken: boolean;
|
hasAccessToken: boolean;
|
||||||
accessToken: string | object;
|
accessToken: string | IEncryptedPayload;
|
||||||
userId: string;
|
userId: string;
|
||||||
deviceId: string;
|
deviceId: string;
|
||||||
isGuest: boolean;
|
isGuest: boolean;
|
||||||
|
@ -346,11 +346,11 @@ export async function getStoredSessionVars(): Promise<IStoredSession> {
|
||||||
isGuest = localStorage.getItem("matrix-is-guest") === "true";
|
isGuest = localStorage.getItem("matrix-is-guest") === "true";
|
||||||
}
|
}
|
||||||
|
|
||||||
return {hsUrl, isUrl, hasAccessToken, accessToken, userId, deviceId, isGuest};
|
return { hsUrl, isUrl, hasAccessToken, accessToken, userId, deviceId, isGuest };
|
||||||
}
|
}
|
||||||
|
|
||||||
// The pickle key is a string of unspecified length and format. For AES, we
|
// The pickle key is a string of unspecified length and format. For AES, we
|
||||||
// need a 256-bit Uint8Array. So we HKDF the pickle key to generate the AES
|
// need a 256-bit Uint8Array. So we HKDF the pickle key to generate the AES
|
||||||
// key. The AES key should be zeroed after it is used.
|
// key. The AES key should be zeroed after it is used.
|
||||||
async function pickleKeyToAesKey(pickleKey: string): Promise<Uint8Array> {
|
async function pickleKeyToAesKey(pickleKey: string): Promise<Uint8Array> {
|
||||||
const pickleKeyBuffer = new Uint8Array(pickleKey.length);
|
const pickleKeyBuffer = new Uint8Array(pickleKey.length);
|
||||||
|
@ -402,7 +402,7 @@ export async function restoreFromLocalStorage(opts?: { ignoreGuest?: boolean }):
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const {hsUrl, isUrl, hasAccessToken, accessToken, userId, deviceId, isGuest} = await getStoredSessionVars();
|
const { hsUrl, isUrl, hasAccessToken, accessToken, userId, deviceId, isGuest } = await getStoredSessionVars();
|
||||||
|
|
||||||
if (hasAccessToken && !accessToken) {
|
if (hasAccessToken && !accessToken) {
|
||||||
abortLogin();
|
abortLogin();
|
||||||
|
@ -495,7 +495,7 @@ export async function setLoggedIn(credentials: IMatrixClientCreds): Promise<Matr
|
||||||
console.log("Pickle key not created");
|
console.log("Pickle key not created");
|
||||||
}
|
}
|
||||||
|
|
||||||
return doSetLoggedIn(Object.assign({}, credentials, {pickleKey}), true);
|
return doSetLoggedIn(Object.assign({}, credentials, { pickleKey }), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -562,7 +562,7 @@ async function doSetLoggedIn(
|
||||||
//
|
//
|
||||||
// we fire it *synchronously* to make sure it fires before on_logged_in.
|
// we fire it *synchronously* to make sure it fires before on_logged_in.
|
||||||
// (dis.dispatch uses `setTimeout`, which does not guarantee ordering.)
|
// (dis.dispatch uses `setTimeout`, which does not guarantee ordering.)
|
||||||
dis.dispatch({action: 'on_logging_in'}, true);
|
dis.dispatch({ action: 'on_logging_in' }, true);
|
||||||
|
|
||||||
if (clearStorageEnabled) {
|
if (clearStorageEnabled) {
|
||||||
await clearStorage();
|
await clearStorage();
|
||||||
|
@ -745,7 +745,7 @@ export function softLogout(): void {
|
||||||
// Ensure that we dispatch a view change **before** stopping the client so
|
// Ensure that we dispatch a view change **before** stopping the client so
|
||||||
// so that React components unmount first. This avoids React soft crashes
|
// so that React components unmount first. This avoids React soft crashes
|
||||||
// that can occur when components try to use a null client.
|
// that can occur when components try to use a null client.
|
||||||
dis.dispatch({action: 'on_client_not_viable'}); // generic version of on_logged_out
|
dis.dispatch({ action: 'on_client_not_viable' }); // generic version of on_logged_out
|
||||||
stopMatrixClient(/*unsetClient=*/false);
|
stopMatrixClient(/*unsetClient=*/false);
|
||||||
|
|
||||||
// DO NOT CALL LOGOUT. A soft logout preserves data, logout does not.
|
// DO NOT CALL LOGOUT. A soft logout preserves data, logout does not.
|
||||||
|
@ -772,7 +772,7 @@ async function startMatrixClient(startSyncing = true): Promise<void> {
|
||||||
// to add listeners for the 'sync' event so otherwise we'd have
|
// to add listeners for the 'sync' event so otherwise we'd have
|
||||||
// a race condition (and we need to dispatch synchronously for this
|
// a race condition (and we need to dispatch synchronously for this
|
||||||
// to work).
|
// to work).
|
||||||
dis.dispatch({action: 'will_start_client'}, true);
|
dis.dispatch({ action: 'will_start_client' }, true);
|
||||||
|
|
||||||
// reset things first just in case
|
// reset things first just in case
|
||||||
TypingStore.sharedInstance().reset();
|
TypingStore.sharedInstance().reset();
|
||||||
|
@ -814,7 +814,7 @@ async function startMatrixClient(startSyncing = true): Promise<void> {
|
||||||
|
|
||||||
// dispatch that we finished starting up to wire up any other bits
|
// dispatch that we finished starting up to wire up any other bits
|
||||||
// of the matrix client that cannot be set prior to starting up.
|
// of the matrix client that cannot be set prior to starting up.
|
||||||
dis.dispatch({action: 'client_started'});
|
dis.dispatch({ action: 'client_started' });
|
||||||
|
|
||||||
if (isSoftLogout()) {
|
if (isSoftLogout()) {
|
||||||
softLogout();
|
softLogout();
|
||||||
|
@ -830,9 +830,9 @@ export async function onLoggedOut(): Promise<void> {
|
||||||
// Ensure that we dispatch a view change **before** stopping the client so
|
// Ensure that we dispatch a view change **before** stopping the client so
|
||||||
// so that React components unmount first. This avoids React soft crashes
|
// so that React components unmount first. This avoids React soft crashes
|
||||||
// that can occur when components try to use a null client.
|
// that can occur when components try to use a null client.
|
||||||
dis.dispatch({action: 'on_logged_out'}, true);
|
dis.dispatch({ action: 'on_logged_out' }, true);
|
||||||
stopMatrixClient();
|
stopMatrixClient();
|
||||||
await clearStorage({deleteEverything: true});
|
await clearStorage({ deleteEverything: true });
|
||||||
LifecycleCustomisations.onLoggedOutAndStorageCleared?.();
|
LifecycleCustomisations.onLoggedOutAndStorageCleared?.();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// @ts-ignore - XXX: tsc doesn't like this: our js-sdk imports are complex so this isn't surprising
|
// @ts-ignore - XXX: tsc doesn't like this: our js-sdk imports are complex so this isn't surprising
|
||||||
import {createClient} from "matrix-js-sdk/src/matrix";
|
import { createClient } from "matrix-js-sdk/src/matrix";
|
||||||
import { MatrixClient } from "matrix-js-sdk/src/client";
|
import { MatrixClient } from "matrix-js-sdk/src/client";
|
||||||
import { IMatrixClientCreds } from "./MatrixClientPeg";
|
import { IMatrixClientCreds } from "./MatrixClientPeg";
|
||||||
import SecurityCustomisations from "./customisations/Security";
|
import SecurityCustomisations from "./customisations/Security";
|
||||||
|
@ -190,7 +190,6 @@ export default class Login {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send a login request to the given server, and format the response
|
* Send a login request to the given server, and format the response
|
||||||
* as a MatrixClientCreds
|
* as a MatrixClientCreds
|
||||||
|
|
|
@ -18,22 +18,22 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { ICreateClientOpts } from 'matrix-js-sdk/src/matrix';
|
import { ICreateClientOpts } from 'matrix-js-sdk/src/matrix';
|
||||||
import {MatrixClient} from 'matrix-js-sdk/src/client';
|
import { MatrixClient } from 'matrix-js-sdk/src/client';
|
||||||
import {MemoryStore} from 'matrix-js-sdk/src/store/memory';
|
import { MemoryStore } from 'matrix-js-sdk/src/store/memory';
|
||||||
import * as utils from 'matrix-js-sdk/src/utils';
|
import * as utils from 'matrix-js-sdk/src/utils';
|
||||||
import {EventTimeline} from 'matrix-js-sdk/src/models/event-timeline';
|
import { EventTimeline } from 'matrix-js-sdk/src/models/event-timeline';
|
||||||
import {EventTimelineSet} from 'matrix-js-sdk/src/models/event-timeline-set';
|
import { EventTimelineSet } from 'matrix-js-sdk/src/models/event-timeline-set';
|
||||||
import * as sdk from './index';
|
import * as sdk from './index';
|
||||||
import createMatrixClient from './utils/createMatrixClient';
|
import createMatrixClient from './utils/createMatrixClient';
|
||||||
import SettingsStore from './settings/SettingsStore';
|
import SettingsStore from './settings/SettingsStore';
|
||||||
import MatrixActionCreators from './actions/MatrixActionCreators';
|
import MatrixActionCreators from './actions/MatrixActionCreators';
|
||||||
import Modal from './Modal';
|
import Modal from './Modal';
|
||||||
import {verificationMethods} from 'matrix-js-sdk/src/crypto';
|
import { verificationMethods } from 'matrix-js-sdk/src/crypto';
|
||||||
import MatrixClientBackedSettingsHandler from "./settings/handlers/MatrixClientBackedSettingsHandler";
|
import MatrixClientBackedSettingsHandler from "./settings/handlers/MatrixClientBackedSettingsHandler";
|
||||||
import * as StorageManager from './utils/StorageManager';
|
import * as StorageManager from './utils/StorageManager';
|
||||||
import IdentityAuthClient from './IdentityAuthClient';
|
import IdentityAuthClient from './IdentityAuthClient';
|
||||||
import { crossSigningCallbacks, tryToUnlockSecretStorageWithDehydrationKey } from './SecurityManager';
|
import { crossSigningCallbacks, tryToUnlockSecretStorageWithDehydrationKey } from './SecurityManager';
|
||||||
import {SHOW_QR_CODE_METHOD} from "matrix-js-sdk/src/crypto/verification/QRCode";
|
import { SHOW_QR_CODE_METHOD } from "matrix-js-sdk/src/crypto/verification/QRCode";
|
||||||
import SecurityCustomisations from "./customisations/Security";
|
import SecurityCustomisations from "./customisations/Security";
|
||||||
|
|
||||||
export interface IMatrixClientCreds {
|
export interface IMatrixClientCreds {
|
||||||
|
|
|
@ -15,14 +15,13 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
|
||||||
import Analytics from './Analytics';
|
import Analytics from './Analytics';
|
||||||
import dis from './dispatcher/dispatcher';
|
import dis from './dispatcher/dispatcher';
|
||||||
import {defer} from './utils/promise';
|
import { defer } from './utils/promise';
|
||||||
import AsyncWrapper from './AsyncWrapper';
|
import AsyncWrapper from './AsyncWrapper';
|
||||||
|
|
||||||
const DIALOG_CONTAINER_ID = "mx_Dialog_Container";
|
const DIALOG_CONTAINER_ID = "mx_Dialog_Container";
|
||||||
|
@ -193,7 +192,7 @@ export class ModalManager {
|
||||||
modal.elem = <AsyncWrapper key={modalCount} prom={prom} {...props} onFinished={closeDialog} />;
|
modal.elem = <AsyncWrapper key={modalCount} prom={prom} {...props} onFinished={closeDialog} />;
|
||||||
modal.close = closeDialog;
|
modal.close = closeDialog;
|
||||||
|
|
||||||
return {modal, closeDialog, onFinishedProm};
|
return { modal, closeDialog, onFinishedProm };
|
||||||
}
|
}
|
||||||
|
|
||||||
private getCloseFn<T extends any[]>(
|
private getCloseFn<T extends any[]>(
|
||||||
|
@ -282,7 +281,7 @@ export class ModalManager {
|
||||||
isStaticModal = false,
|
isStaticModal = false,
|
||||||
options: IOptions<T> = {},
|
options: IOptions<T> = {},
|
||||||
): IHandle<T> {
|
): IHandle<T> {
|
||||||
const {modal, closeDialog, onFinishedProm} = this.buildModal<T>(prom, props, className, options);
|
const { modal, closeDialog, onFinishedProm } = this.buildModal<T>(prom, props, className, options);
|
||||||
if (isPriorityModal) {
|
if (isPriorityModal) {
|
||||||
// XXX: This is destructive
|
// XXX: This is destructive
|
||||||
this.priorityModal = modal;
|
this.priorityModal = modal;
|
||||||
|
@ -305,7 +304,7 @@ export class ModalManager {
|
||||||
props?: IProps<T>,
|
props?: IProps<T>,
|
||||||
className?: string,
|
className?: string,
|
||||||
): IHandle<T> {
|
): IHandle<T> {
|
||||||
const {modal, closeDialog, onFinishedProm} = this.buildModal<T>(prom, props, className, {});
|
const { modal, closeDialog, onFinishedProm } = this.buildModal<T>(prom, props, className, {});
|
||||||
|
|
||||||
this.modals.push(modal);
|
this.modals.push(modal);
|
||||||
this.reRender();
|
this.reRender();
|
||||||
|
|
|
@ -32,11 +32,11 @@ import { _t } from './languageHandler';
|
||||||
import Modal from './Modal';
|
import Modal from './Modal';
|
||||||
import SettingsStore from "./settings/SettingsStore";
|
import SettingsStore from "./settings/SettingsStore";
|
||||||
import { hideToast as hideNotificationsToast } from "./toasts/DesktopNotificationsToast";
|
import { hideToast as hideNotificationsToast } from "./toasts/DesktopNotificationsToast";
|
||||||
import {SettingLevel} from "./settings/SettingLevel";
|
import { SettingLevel } from "./settings/SettingLevel";
|
||||||
import {isPushNotifyDisabled} from "./settings/controllers/NotificationControllers";
|
import { isPushNotifyDisabled } from "./settings/controllers/NotificationControllers";
|
||||||
import RoomViewStore from "./stores/RoomViewStore";
|
import RoomViewStore from "./stores/RoomViewStore";
|
||||||
import UserActivity from "./UserActivity";
|
import UserActivity from "./UserActivity";
|
||||||
import {mediaFromMxc} from "./customisations/Media";
|
import { mediaFromMxc } from "./customisations/Media";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Dispatches:
|
* Dispatches:
|
||||||
|
|
|
@ -16,10 +16,10 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {MatrixClientPeg} from "./MatrixClientPeg";
|
import { MatrixClientPeg } from "./MatrixClientPeg";
|
||||||
import dis from "./dispatcher/dispatcher";
|
import dis from "./dispatcher/dispatcher";
|
||||||
import Timer from './utils/Timer';
|
import Timer from './utils/Timer';
|
||||||
import {ActionPayload} from "./dispatcher/payloads";
|
import { ActionPayload } from "./dispatcher/payloads";
|
||||||
|
|
||||||
// Time in ms after that a user is considered as unavailable/away
|
// Time in ms after that a user is considered as unavailable/away
|
||||||
const UNAVAILABLE_TIME_MS = 3 * 60 * 1000; // 3 mins
|
const UNAVAILABLE_TIME_MS = 3 * 60 * 1000; // 3 mins
|
||||||
|
@ -78,7 +78,7 @@ class Presence {
|
||||||
this.setState(State.Online);
|
this.setState(State.Online);
|
||||||
this.unavailableTimer.restart();
|
this.unavailableTimer.restart();
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the presence state.
|
* Set the presence state.
|
||||||
|
@ -98,7 +98,7 @@ class Presence {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await MatrixClientPeg.get().setPresence({presence: this.state});
|
await MatrixClientPeg.get().setPresence({ presence: this.state });
|
||||||
console.info("Presence:", newState);
|
console.info("Presence:", newState);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Failed to set presence:", err);
|
console.error("Failed to set presence:", err);
|
||||||
|
|
|
@ -53,16 +53,16 @@ export async function startAnyRegistrationFlow(options) {
|
||||||
extraButtons: [
|
extraButtons: [
|
||||||
<button key="start_login" onClick={() => {
|
<button key="start_login" onClick={() => {
|
||||||
modal.close();
|
modal.close();
|
||||||
dis.dispatch({action: 'start_login', screenAfterLogin: options.screen_after});
|
dis.dispatch({ action: 'start_login', screenAfterLogin: options.screen_after });
|
||||||
}}>{ _t('Sign In') }</button>,
|
}}>{ _t('Sign In') }</button>,
|
||||||
],
|
],
|
||||||
onFinished: (proceed) => {
|
onFinished: (proceed) => {
|
||||||
if (proceed) {
|
if (proceed) {
|
||||||
dis.dispatch({action: 'start_registration', screenAfterLogin: options.screen_after});
|
dis.dispatch({ action: 'start_registration', screenAfterLogin: options.screen_after });
|
||||||
} else if (options.go_home_on_cancel) {
|
} else if (options.go_home_on_cancel) {
|
||||||
dis.dispatch({action: 'view_home_page'});
|
dis.dispatch({ action: 'view_home_page' });
|
||||||
} else if (options.go_welcome_on_cancel) {
|
} else if (options.go_welcome_on_cancel) {
|
||||||
dis.dispatch({action: 'view_welcome_page'});
|
dis.dispatch({ action: 'view_welcome_page' });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -31,6 +31,6 @@ export function textualPowerLevel(level: number, usersDefault: number): string {
|
||||||
if (LEVEL_ROLE_MAP[level]) {
|
if (LEVEL_ROLE_MAP[level]) {
|
||||||
return LEVEL_ROLE_MAP[level];
|
return LEVEL_ROLE_MAP[level];
|
||||||
} else {
|
} else {
|
||||||
return _t("Custom (%(level)s)", {level});
|
return _t("Custom (%(level)s)", { level });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,7 +53,7 @@ export function showStartChatInviteDialog(initialText = ""): void {
|
||||||
// This dialog handles the room creation internally - we don't need to worry about it.
|
// This dialog handles the room creation internally - we don't need to worry about it.
|
||||||
const InviteDialog = sdk.getComponent("dialogs.InviteDialog");
|
const InviteDialog = sdk.getComponent("dialogs.InviteDialog");
|
||||||
Modal.createTrackedDialog(
|
Modal.createTrackedDialog(
|
||||||
'Start DM', '', InviteDialog, {kind: KIND_DM, initialText},
|
'Start DM', '', InviteDialog, { kind: KIND_DM, initialText },
|
||||||
/*className=*/null, /*isPriority=*/false, /*isStatic=*/true,
|
/*className=*/null, /*isPriority=*/false, /*isStatic=*/true,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -72,7 +72,7 @@ export function showRoomInviteDialog(roomId: string, initialText = ""): void {
|
||||||
|
|
||||||
export function showCommunityRoomInviteDialog(roomId: string, communityName: string): void {
|
export function showCommunityRoomInviteDialog(roomId: string, communityName: string): void {
|
||||||
Modal.createTrackedDialog(
|
Modal.createTrackedDialog(
|
||||||
'Invite Users to Community', '', CommunityPrototypeInviteDialog, {communityName, roomId},
|
'Invite Users to Community', '', CommunityPrototypeInviteDialog, { communityName, roomId },
|
||||||
/*className=*/null, /*isPriority=*/false, /*isStatic=*/true,
|
/*className=*/null, /*isPriority=*/false, /*isStatic=*/true,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -133,7 +133,7 @@ export function showAnyInviteErrors(
|
||||||
// pointless for us to list who failed exactly.
|
// pointless for us to list who failed exactly.
|
||||||
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||||
Modal.createTrackedDialog('Failed to invite users to the room', '', ErrorDialog, {
|
Modal.createTrackedDialog('Failed to invite users to the room', '', ErrorDialog, {
|
||||||
title: _t("Failed to invite users to the room:", {roomName: room.name}),
|
title: _t("Failed to invite users to the room:", { roomName: room.name }),
|
||||||
description: inviter.getErrorText(failedUsers[0]),
|
description: inviter.getErrorText(failedUsers[0]),
|
||||||
});
|
});
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -15,8 +15,8 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {MatrixClientPeg} from './MatrixClientPeg';
|
import { MatrixClientPeg } from './MatrixClientPeg';
|
||||||
import {PushProcessor} from 'matrix-js-sdk/src/pushprocessor';
|
import { PushProcessor } from 'matrix-js-sdk/src/pushprocessor';
|
||||||
|
|
||||||
export const ALL_MESSAGES_LOUD = 'all_messages_loud';
|
export const ALL_MESSAGES_LOUD = 'all_messages_loud';
|
||||||
export const ALL_MESSAGES = 'all_messages';
|
export const ALL_MESSAGES = 'all_messages';
|
||||||
|
@ -52,7 +52,7 @@ export function aggregateNotificationCount(rooms) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}, {count: 0, highlight: false});
|
}, { count: 0, highlight: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getRoomHasBadge(room) {
|
export function getRoomHasBadge(room) {
|
||||||
|
|
|
@ -104,7 +104,6 @@ export function setDMRoom(roomId: string, userId: string): Promise<void> {
|
||||||
dmRoomMap[userId] = roomList;
|
dmRoomMap[userId] = roomList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return MatrixClientPeg.get().setAccountData('m.direct', dmRoomMap);
|
return MatrixClientPeg.get().setAccountData('m.direct', dmRoomMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,12 +17,12 @@ limitations under the License.
|
||||||
import url from 'url';
|
import url from 'url';
|
||||||
import SettingsStore from "./settings/SettingsStore";
|
import SettingsStore from "./settings/SettingsStore";
|
||||||
import { Service, startTermsFlow, TermsInteractionCallback, TermsNotSignedError } from './Terms';
|
import { Service, startTermsFlow, TermsInteractionCallback, TermsNotSignedError } from './Terms';
|
||||||
import {MatrixClientPeg} from "./MatrixClientPeg";
|
import { MatrixClientPeg } from "./MatrixClientPeg";
|
||||||
import request from "browser-request";
|
import request from "browser-request";
|
||||||
|
|
||||||
import SdkConfig from "./SdkConfig";
|
import SdkConfig from "./SdkConfig";
|
||||||
import {WidgetType} from "./widgets/WidgetType";
|
import { WidgetType } from "./widgets/WidgetType";
|
||||||
import {SERVICE_TYPES} from "matrix-js-sdk/src/service-types";
|
import { SERVICE_TYPES } from "matrix-js-sdk/src/service-types";
|
||||||
import { Room } from "matrix-js-sdk/src/models/room";
|
import { Room } from "matrix-js-sdk/src/models/room";
|
||||||
|
|
||||||
// The version of the integration manager API we're intending to work with
|
// The version of the integration manager API we're intending to work with
|
||||||
|
@ -109,7 +109,7 @@ export default class ScalarAuthClient {
|
||||||
request({
|
request({
|
||||||
method: "GET",
|
method: "GET",
|
||||||
uri: url,
|
uri: url,
|
||||||
qs: {scalar_token: token, v: imApiVersion},
|
qs: { scalar_token: token, v: imApiVersion },
|
||||||
json: true,
|
json: true,
|
||||||
}, (err, response, body) => {
|
}, (err, response, body) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
@ -189,7 +189,7 @@ export default class ScalarAuthClient {
|
||||||
request({
|
request({
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
uri: scalarRestUrl + '/register',
|
uri: scalarRestUrl + '/register',
|
||||||
qs: {v: imApiVersion},
|
qs: { v: imApiVersion },
|
||||||
body: openidTokenObject,
|
body: openidTokenObject,
|
||||||
json: true,
|
json: true,
|
||||||
}, (err, response, body) => {
|
}, (err, response, body) => {
|
||||||
|
|
|
@ -208,7 +208,6 @@ Example:
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
membership_state AND bot_options
|
membership_state AND bot_options
|
||||||
--------------------------------
|
--------------------------------
|
||||||
Get the content of the "m.room.member" or "m.room.bot.options" state event respectively.
|
Get the content of the "m.room.member" or "m.room.bot.options" state event respectively.
|
||||||
|
@ -236,15 +235,15 @@ Example:
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {MatrixClientPeg} from './MatrixClientPeg';
|
import { MatrixClientPeg } from './MatrixClientPeg';
|
||||||
import { MatrixEvent } from 'matrix-js-sdk/src/models/event';
|
import { MatrixEvent } from 'matrix-js-sdk/src/models/event';
|
||||||
import dis from './dispatcher/dispatcher';
|
import dis from './dispatcher/dispatcher';
|
||||||
import WidgetUtils from './utils/WidgetUtils';
|
import WidgetUtils from './utils/WidgetUtils';
|
||||||
import RoomViewStore from './stores/RoomViewStore';
|
import RoomViewStore from './stores/RoomViewStore';
|
||||||
import { _t } from './languageHandler';
|
import { _t } from './languageHandler';
|
||||||
import {IntegrationManagers} from "./integrations/IntegrationManagers";
|
import { IntegrationManagers } from "./integrations/IntegrationManagers";
|
||||||
import {WidgetType} from "./widgets/WidgetType";
|
import { WidgetType } from "./widgets/WidgetType";
|
||||||
import {objectClone} from "./utils/objects";
|
import { objectClone } from "./utils/objects";
|
||||||
|
|
||||||
function sendResponse(event, res) {
|
function sendResponse(event, res) {
|
||||||
const data = objectClone(event.data);
|
const data = objectClone(event.data);
|
||||||
|
@ -608,7 +607,7 @@ const onMessage = function(event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (roomId !== RoomViewStore.getRoomId()) {
|
if (roomId !== RoomViewStore.getRoomId()) {
|
||||||
sendError(event, _t('Room %(roomId)s not visible', {roomId: roomId}));
|
sendError(event, _t('Room %(roomId)s not visible', { roomId: roomId }));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import EventIndexPeg from "./indexing/EventIndexPeg";
|
import EventIndexPeg from "./indexing/EventIndexPeg";
|
||||||
import {MatrixClientPeg} from "./MatrixClientPeg";
|
import { MatrixClientPeg } from "./MatrixClientPeg";
|
||||||
|
|
||||||
const SEARCH_LIMIT = 10;
|
const SEARCH_LIMIT = 10;
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ async function serverSideSearch(term, roomId = undefined) {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const response = await client.search({body: body});
|
const response = await client.search({ body: body });
|
||||||
|
|
||||||
const result = {
|
const result = {
|
||||||
response: response,
|
response: response,
|
||||||
|
@ -498,7 +498,7 @@ async function combinedPagination(searchResult) {
|
||||||
// Fetch events from the server if we have a token for it and if it's the
|
// Fetch events from the server if we have a token for it and if it's the
|
||||||
// local indexes turn or the local index has exhausted its results.
|
// local indexes turn or the local index has exhausted its results.
|
||||||
if (searchResult.serverSideNextBatch && (oldestEventFrom === "local" || !searchArgs.next_batch)) {
|
if (searchResult.serverSideNextBatch && (oldestEventFrom === "local" || !searchArgs.next_batch)) {
|
||||||
const body = {body: searchResult._query, next_batch: searchResult.serverSideNextBatch};
|
const body = { body: searchResult._query, next_batch: searchResult.serverSideNextBatch };
|
||||||
serverSideResult = await client.search(body);
|
serverSideResult = await client.search(body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ import { ICryptoCallbacks, ISecretStorageKeyInfo } from 'matrix-js-sdk/src/matri
|
||||||
import { MatrixClient } from 'matrix-js-sdk/src/client';
|
import { MatrixClient } from 'matrix-js-sdk/src/client';
|
||||||
import Modal from './Modal';
|
import Modal from './Modal';
|
||||||
import * as sdk from './index';
|
import * as sdk from './index';
|
||||||
import {MatrixClientPeg} from './MatrixClientPeg';
|
import { MatrixClientPeg } from './MatrixClientPeg';
|
||||||
import { deriveKey } from 'matrix-js-sdk/src/crypto/key_passphrase';
|
import { deriveKey } from 'matrix-js-sdk/src/crypto/key_passphrase';
|
||||||
import { decodeRecoveryKey } from 'matrix-js-sdk/src/crypto/recoverykey';
|
import { decodeRecoveryKey } from 'matrix-js-sdk/src/crypto/recoverykey';
|
||||||
import { _t } from './languageHandler';
|
import { _t } from './languageHandler';
|
||||||
|
@ -135,7 +135,7 @@ async function getSecretStorageKey(
|
||||||
|
|
||||||
const keyFromCustomisations = SecurityCustomisations.getSecretStorageKey?.();
|
const keyFromCustomisations = SecurityCustomisations.getSecretStorageKey?.();
|
||||||
if (keyFromCustomisations) {
|
if (keyFromCustomisations) {
|
||||||
console.log("Using key from security customisations (secret storage)")
|
console.log("Using key from security customisations (secret storage)");
|
||||||
cacheSecretStorageKey(keyId, keyInfo, keyFromCustomisations);
|
cacheSecretStorageKey(keyId, keyInfo, keyFromCustomisations);
|
||||||
return [keyId, keyFromCustomisations];
|
return [keyId, keyFromCustomisations];
|
||||||
}
|
}
|
||||||
|
@ -185,7 +185,7 @@ export async function getDehydrationKey(
|
||||||
): Promise<Uint8Array> {
|
): Promise<Uint8Array> {
|
||||||
const keyFromCustomisations = SecurityCustomisations.getSecretStorageKey?.();
|
const keyFromCustomisations = SecurityCustomisations.getSecretStorageKey?.();
|
||||||
if (keyFromCustomisations) {
|
if (keyFromCustomisations) {
|
||||||
console.log("Using key from security customisations (dehydration)")
|
console.log("Using key from security customisations (dehydration)");
|
||||||
return keyFromCustomisations;
|
return keyFromCustomisations;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,7 +224,7 @@ export async function getDehydrationKey(
|
||||||
const key = await inputToKey(input);
|
const key = await inputToKey(input);
|
||||||
|
|
||||||
// need to copy the key because rehydration (unpickling) will clobber it
|
// need to copy the key because rehydration (unpickling) will clobber it
|
||||||
dehydrationCache = {key: new Uint8Array(key), keyInfo};
|
dehydrationCache = { key: new Uint8Array(key), keyInfo };
|
||||||
|
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
//@flow
|
|
||||||
/*
|
/*
|
||||||
Copyright 2017 Aviral Dasgupta
|
Copyright 2017 Aviral Dasgupta
|
||||||
|
|
||||||
|
@ -15,10 +14,10 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {clamp} from "lodash";
|
import { clamp } from "lodash";
|
||||||
import {MatrixEvent} from "matrix-js-sdk/src/models/event";
|
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
||||||
|
|
||||||
import {SerializedPart} from "./editor/parts";
|
import { SerializedPart } from "./editor/parts";
|
||||||
import EditorModel from "./editor/model";
|
import EditorModel from "./editor/model";
|
||||||
|
|
||||||
interface IHistoryItem {
|
interface IHistoryItem {
|
||||||
|
|
|
@ -21,21 +21,21 @@ import * as React from 'react';
|
||||||
import { User } from "matrix-js-sdk/src/models/user";
|
import { User } from "matrix-js-sdk/src/models/user";
|
||||||
|
|
||||||
import * as ContentHelpers from 'matrix-js-sdk/src/content-helpers';
|
import * as ContentHelpers from 'matrix-js-sdk/src/content-helpers';
|
||||||
import {MatrixClientPeg} from './MatrixClientPeg';
|
import { MatrixClientPeg } from './MatrixClientPeg';
|
||||||
import dis from './dispatcher/dispatcher';
|
import dis from './dispatcher/dispatcher';
|
||||||
import * as sdk from './index';
|
import * as sdk from './index';
|
||||||
import {_t, _td} from './languageHandler';
|
import { _t, _td } from './languageHandler';
|
||||||
import Modal from './Modal';
|
import Modal from './Modal';
|
||||||
import MultiInviter from './utils/MultiInviter';
|
import MultiInviter from './utils/MultiInviter';
|
||||||
import { linkifyAndSanitizeHtml } from './HtmlUtils';
|
import { linkifyAndSanitizeHtml } from './HtmlUtils';
|
||||||
import QuestionDialog from "./components/views/dialogs/QuestionDialog";
|
import QuestionDialog from "./components/views/dialogs/QuestionDialog";
|
||||||
import WidgetUtils from "./utils/WidgetUtils";
|
import WidgetUtils from "./utils/WidgetUtils";
|
||||||
import {textToHtmlRainbow} from "./utils/colour";
|
import { textToHtmlRainbow } from "./utils/colour";
|
||||||
import { getAddressType } from './UserAddress';
|
import { getAddressType } from './UserAddress';
|
||||||
import { abbreviateUrl } from './utils/UrlUtils';
|
import { abbreviateUrl } from './utils/UrlUtils';
|
||||||
import { getDefaultIdentityServerUrl, useDefaultIdentityServer } from './utils/IdentityServerUtils';
|
import { getDefaultIdentityServerUrl, useDefaultIdentityServer } from './utils/IdentityServerUtils';
|
||||||
import {isPermalinkHost, parsePermalink} from "./utils/permalinks/Permalinks";
|
import { isPermalinkHost, parsePermalink } from "./utils/permalinks/Permalinks";
|
||||||
import {inviteUsersToRoom} from "./RoomInvite";
|
import { inviteUsersToRoom } from "./RoomInvite";
|
||||||
import { WidgetType } from "./widgets/WidgetType";
|
import { WidgetType } from "./widgets/WidgetType";
|
||||||
import { Jitsi } from "./widgets/Jitsi";
|
import { Jitsi } from "./widgets/Jitsi";
|
||||||
import { parseFragment as parseHtml, Element as ChildElement } from "parse5";
|
import { parseFragment as parseHtml, Element as ChildElement } from "parse5";
|
||||||
|
@ -46,10 +46,10 @@ import { Action } from "./dispatcher/actions";
|
||||||
import { EffectiveMembership, getEffectiveMembership, leaveRoomBehaviour } from "./utils/membership";
|
import { EffectiveMembership, getEffectiveMembership, leaveRoomBehaviour } from "./utils/membership";
|
||||||
import SdkConfig from "./SdkConfig";
|
import SdkConfig from "./SdkConfig";
|
||||||
import SettingsStore from "./settings/SettingsStore";
|
import SettingsStore from "./settings/SettingsStore";
|
||||||
import {UIFeature} from "./settings/UIFeature";
|
import { UIFeature } from "./settings/UIFeature";
|
||||||
import {CHAT_EFFECTS} from "./effects"
|
import { CHAT_EFFECTS } from "./effects";
|
||||||
import CallHandler from "./CallHandler";
|
import CallHandler from "./CallHandler";
|
||||||
import {guessAndSetDMRoom} from "./Rooms";
|
import { guessAndSetDMRoom } from "./Rooms";
|
||||||
|
|
||||||
// XXX: workaround for https://github.com/microsoft/TypeScript/issues/31816
|
// XXX: workaround for https://github.com/microsoft/TypeScript/issues/31816
|
||||||
interface HTMLInputEvent extends Event {
|
interface HTMLInputEvent extends Event {
|
||||||
|
@ -143,11 +143,11 @@ export class Command {
|
||||||
}
|
}
|
||||||
|
|
||||||
function reject(error) {
|
function reject(error) {
|
||||||
return {error};
|
return { error };
|
||||||
}
|
}
|
||||||
|
|
||||||
function success(promise?: Promise<any>) {
|
function success(promise?: Promise<any>) {
|
||||||
return {promise};
|
return { promise };
|
||||||
}
|
}
|
||||||
|
|
||||||
function successSync(value: any) {
|
function successSync(value: any) {
|
||||||
|
@ -271,8 +271,8 @@ export const Commands = [
|
||||||
|
|
||||||
const RoomUpgradeWarningDialog = sdk.getComponent("dialogs.RoomUpgradeWarningDialog");
|
const RoomUpgradeWarningDialog = sdk.getComponent("dialogs.RoomUpgradeWarningDialog");
|
||||||
|
|
||||||
const {finished} = Modal.createTrackedDialog('Slash Commands', 'upgrade room confirmation',
|
const { finished } = Modal.createTrackedDialog('Slash Commands', 'upgrade room confirmation',
|
||||||
RoomUpgradeWarningDialog, {roomId: roomId, targetVersion: args}, /*className=*/null,
|
RoomUpgradeWarningDialog, { roomId: roomId, targetVersion: args }, /*className=*/null,
|
||||||
/*isPriority=*/false, /*isStatic=*/true);
|
/*isPriority=*/false, /*isStatic=*/true);
|
||||||
|
|
||||||
return success(finished.then(async ([resp]) => {
|
return success(finished.then(async ([resp]) => {
|
||||||
|
@ -288,7 +288,7 @@ export const Commands = [
|
||||||
if (resp.invite) {
|
if (resp.invite) {
|
||||||
checkForUpgradeFn = async (newRoom) => {
|
checkForUpgradeFn = async (newRoom) => {
|
||||||
// The upgradePromise should be done by the time we await it here.
|
// The upgradePromise should be done by the time we await it here.
|
||||||
const {replacement_room: newRoomId} = await upgradePromise;
|
const { replacement_room: newRoomId } = await upgradePromise;
|
||||||
if (newRoom.roomId !== newRoomId) return;
|
if (newRoom.roomId !== newRoomId) return;
|
||||||
|
|
||||||
const toInvite = [
|
const toInvite = [
|
||||||
|
@ -370,7 +370,7 @@ export const Commands = [
|
||||||
|
|
||||||
return success(promise.then((url) => {
|
return success(promise.then((url) => {
|
||||||
if (!url) return;
|
if (!url) return;
|
||||||
return MatrixClientPeg.get().sendStateEvent(roomId, 'm.room.avatar', {url}, '');
|
return MatrixClientPeg.get().sendStateEvent(roomId, 'm.room.avatar', { url }, '');
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
category: CommandCategories.actions,
|
category: CommandCategories.actions,
|
||||||
|
@ -741,7 +741,7 @@ export const Commands = [
|
||||||
Modal.createTrackedDialog('Slash Commands', 'User ignored', InfoDialog, {
|
Modal.createTrackedDialog('Slash Commands', 'User ignored', InfoDialog, {
|
||||||
title: _t('Ignored user'),
|
title: _t('Ignored user'),
|
||||||
description: <div>
|
description: <div>
|
||||||
<p>{ _t('You are now ignoring %(userId)s', {userId}) }</p>
|
<p>{ _t('You are now ignoring %(userId)s', { userId }) }</p>
|
||||||
</div>,
|
</div>,
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
|
@ -772,7 +772,7 @@ export const Commands = [
|
||||||
Modal.createTrackedDialog('Slash Commands', 'User unignored', InfoDialog, {
|
Modal.createTrackedDialog('Slash Commands', 'User unignored', InfoDialog, {
|
||||||
title: _t('Unignored user'),
|
title: _t('Unignored user'),
|
||||||
description: <div>
|
description: <div>
|
||||||
<p>{ _t('You are no longer ignoring %(userId)s', {userId}) }</p>
|
<p>{ _t('You are no longer ignoring %(userId)s', { userId }) }</p>
|
||||||
</div>,
|
</div>,
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
|
@ -839,7 +839,7 @@ export const Commands = [
|
||||||
description: _td('Opens the Developer Tools dialog'),
|
description: _td('Opens the Developer Tools dialog'),
|
||||||
runFn: function(roomId) {
|
runFn: function(roomId) {
|
||||||
const DevtoolsDialog = sdk.getComponent('dialogs.DevtoolsDialog');
|
const DevtoolsDialog = sdk.getComponent('dialogs.DevtoolsDialog');
|
||||||
Modal.createDialog(DevtoolsDialog, {roomId});
|
Modal.createDialog(DevtoolsDialog, { roomId });
|
||||||
return success();
|
return success();
|
||||||
},
|
},
|
||||||
category: CommandCategories.advanced,
|
category: CommandCategories.advanced,
|
||||||
|
@ -951,7 +951,7 @@ export const Commands = [
|
||||||
{
|
{
|
||||||
_t('The signing key you provided matches the signing key you received ' +
|
_t('The signing key you provided matches the signing key you received ' +
|
||||||
'from %(userId)s\'s session %(deviceId)s. Session marked as verified.',
|
'from %(userId)s\'s session %(deviceId)s. Session marked as verified.',
|
||||||
{userId, deviceId})
|
{ userId, deviceId })
|
||||||
}
|
}
|
||||||
</p>
|
</p>
|
||||||
</div>,
|
</div>,
|
||||||
|
@ -1172,11 +1172,11 @@ export const Commands = [
|
||||||
};
|
};
|
||||||
MatrixClientPeg.get().sendMessage(roomId, content);
|
MatrixClientPeg.get().sendMessage(roomId, content);
|
||||||
}
|
}
|
||||||
dis.dispatch({action: `effects.${effect.command}`});
|
dis.dispatch({ action: `effects.${effect.command}` });
|
||||||
})());
|
})());
|
||||||
},
|
},
|
||||||
category: CommandCategories.effects,
|
category: CommandCategories.effects,
|
||||||
})
|
});
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -1205,7 +1205,7 @@ export function parseCommandString(input: string) {
|
||||||
cmd = input;
|
cmd = input;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {cmd, args};
|
return { cmd, args };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1217,7 +1217,7 @@ export function parseCommandString(input: string) {
|
||||||
* Returns null if the input didn't match a command.
|
* Returns null if the input didn't match a command.
|
||||||
*/
|
*/
|
||||||
export function getCommand(input: string) {
|
export function getCommand(input: string) {
|
||||||
const {cmd, args} = parseCommandString(input);
|
const { cmd, args } = parseCommandString(input);
|
||||||
|
|
||||||
if (CommandMap.has(cmd) && CommandMap.get(cmd).isEnabled()) {
|
if (CommandMap.has(cmd) && CommandMap.get(cmd).isEnabled()) {
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -16,7 +16,7 @@ limitations under the License.
|
||||||
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
|
||||||
import {MatrixClientPeg} from './MatrixClientPeg';
|
import { MatrixClientPeg } from './MatrixClientPeg';
|
||||||
import * as sdk from '.';
|
import * as sdk from '.';
|
||||||
import Modal from './Modal';
|
import Modal from './Modal';
|
||||||
|
|
||||||
|
@ -117,7 +117,7 @@ export async function startTermsFlow(
|
||||||
// but that is not a thing the API supports, so probably best to just show
|
// but that is not a thing the API supports, so probably best to just show
|
||||||
// things they've not agreed to yet.
|
// things they've not agreed to yet.
|
||||||
const unagreedPoliciesAndServicePairs = [];
|
const unagreedPoliciesAndServicePairs = [];
|
||||||
for (const {service, policies} of policiesAndServicePairs) {
|
for (const { service, policies } of policiesAndServicePairs) {
|
||||||
const unagreedPolicies = {};
|
const unagreedPolicies = {};
|
||||||
for (const [policyName, policy] of Object.entries(policies)) {
|
for (const [policyName, policy] of Object.entries(policies)) {
|
||||||
let policyAgreed = false;
|
let policyAgreed = false;
|
||||||
|
@ -131,7 +131,7 @@ export async function startTermsFlow(
|
||||||
if (!policyAgreed) unagreedPolicies[policyName] = policy;
|
if (!policyAgreed) unagreedPolicies[policyName] = policy;
|
||||||
}
|
}
|
||||||
if (Object.keys(unagreedPolicies).length > 0) {
|
if (Object.keys(unagreedPolicies).length > 0) {
|
||||||
unagreedPoliciesAndServicePairs.push({service, policies: unagreedPolicies});
|
unagreedPoliciesAndServicePairs.push({ service, policies: unagreedPolicies });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,7 +148,7 @@ export async function startTermsFlow(
|
||||||
|
|
||||||
// We only ever add to the set of URLs, so if anything has changed then we'd see a different length
|
// We only ever add to the set of URLs, so if anything has changed then we'd see a different length
|
||||||
if (agreedUrlSet.size !== numAcceptedBeforeAgreement) {
|
if (agreedUrlSet.size !== numAcceptedBeforeAgreement) {
|
||||||
const newAcceptedTerms = {accepted: Array.from(agreedUrlSet)};
|
const newAcceptedTerms = { accepted: Array.from(agreedUrlSet) };
|
||||||
await MatrixClientPeg.get().setAccountData('m.accepted_terms', newAcceptedTerms);
|
await MatrixClientPeg.get().setAccountData('m.accepted_terms', newAcceptedTerms);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,13 +15,13 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {MatrixClientPeg} from './MatrixClientPeg';
|
import { MatrixClientPeg } from './MatrixClientPeg';
|
||||||
import { _t } from './languageHandler';
|
import { _t } from './languageHandler';
|
||||||
import * as Roles from './Roles';
|
import * as Roles from './Roles';
|
||||||
import {isValid3pidInvite} from "./RoomInvite";
|
import { isValid3pidInvite } from "./RoomInvite";
|
||||||
import SettingsStore from "./settings/SettingsStore";
|
import SettingsStore from "./settings/SettingsStore";
|
||||||
import {ALL_RULE_TYPES, ROOM_RULE_TYPES, SERVER_RULE_TYPES, USER_RULE_TYPES} from "./mjolnir/BanList";
|
import { ALL_RULE_TYPES, ROOM_RULE_TYPES, SERVER_RULE_TYPES, USER_RULE_TYPES } from "./mjolnir/BanList";
|
||||||
import {WIDGET_LAYOUT_EVENT_TYPE} from "./stores/widgets/WidgetLayoutStore";
|
import { WIDGET_LAYOUT_EVENT_TYPE } from "./stores/widgets/WidgetLayoutStore";
|
||||||
import { RightPanelPhases } from './stores/RightPanelStorePhases';
|
import { RightPanelPhases } from './stores/RightPanelStorePhases';
|
||||||
import { Action } from './dispatcher/actions';
|
import { Action } from './dispatcher/actions';
|
||||||
import defaultDispatcher from './dispatcher/dispatcher';
|
import defaultDispatcher from './dispatcher/dispatcher';
|
||||||
|
@ -112,7 +112,7 @@ function textForMemberEvent(ev): () => string | null {
|
||||||
targetName,
|
targetName,
|
||||||
reason,
|
reason,
|
||||||
})
|
})
|
||||||
: _t('%(senderName)s withdrew %(targetName)s\'s invitation', { senderName, targetName })
|
: _t('%(senderName)s withdrew %(targetName)s\'s invitation', { senderName, targetName });
|
||||||
} else if (prevContent.membership === "join") {
|
} else if (prevContent.membership === "join") {
|
||||||
return () => reason
|
return () => reason
|
||||||
? _t('%(senderName)s kicked %(targetName)s: %(reason)s', {
|
? _t('%(senderName)s kicked %(targetName)s: %(reason)s', {
|
||||||
|
@ -139,7 +139,7 @@ function textForRoomNameEvent(ev): () => string | null {
|
||||||
const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender();
|
const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender();
|
||||||
|
|
||||||
if (!ev.getContent().name || ev.getContent().name.trim().length === 0) {
|
if (!ev.getContent().name || ev.getContent().name.trim().length === 0) {
|
||||||
return () => _t('%(senderDisplayName)s removed the room name.', {senderDisplayName});
|
return () => _t('%(senderDisplayName)s removed the room name.', { senderDisplayName });
|
||||||
}
|
}
|
||||||
if (ev.getPrevContent().name) {
|
if (ev.getPrevContent().name) {
|
||||||
return () => _t('%(senderDisplayName)s changed the room name from %(oldRoomName)s to %(newRoomName)s.', {
|
return () => _t('%(senderDisplayName)s changed the room name from %(oldRoomName)s to %(newRoomName)s.', {
|
||||||
|
@ -156,7 +156,7 @@ function textForRoomNameEvent(ev): () => string | null {
|
||||||
|
|
||||||
function textForTombstoneEvent(ev): () => string | null {
|
function textForTombstoneEvent(ev): () => string | null {
|
||||||
const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender();
|
const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender();
|
||||||
return () => _t('%(senderDisplayName)s upgraded this room.', {senderDisplayName});
|
return () => _t('%(senderDisplayName)s upgraded this room.', { senderDisplayName });
|
||||||
}
|
}
|
||||||
|
|
||||||
function textForJoinRulesEvent(ev): () => string | null {
|
function textForJoinRulesEvent(ev): () => string | null {
|
||||||
|
@ -183,9 +183,9 @@ function textForGuestAccessEvent(ev): () => string | null {
|
||||||
const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender();
|
const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender();
|
||||||
switch (ev.getContent().guest_access) {
|
switch (ev.getContent().guest_access) {
|
||||||
case "can_join":
|
case "can_join":
|
||||||
return () => _t('%(senderDisplayName)s has allowed guests to join the room.', {senderDisplayName});
|
return () => _t('%(senderDisplayName)s has allowed guests to join the room.', { senderDisplayName });
|
||||||
case "forbidden":
|
case "forbidden":
|
||||||
return () => _t('%(senderDisplayName)s has prevented guests from joining the room.', {senderDisplayName});
|
return () => _t('%(senderDisplayName)s has prevented guests from joining the room.', { senderDisplayName });
|
||||||
default:
|
default:
|
||||||
// There's no other options we can expect, however just for safety's sake we'll do this.
|
// There's no other options we can expect, however just for safety's sake we'll do this.
|
||||||
return () => _t('%(senderDisplayName)s changed guest access to %(rule)s', {
|
return () => _t('%(senderDisplayName)s changed guest access to %(rule)s', {
|
||||||
|
@ -237,9 +237,9 @@ function textForServerACLEvent(ev): () => string | null {
|
||||||
|
|
||||||
let getText = null;
|
let getText = null;
|
||||||
if (prev.deny.length === 0 && prev.allow.length === 0) {
|
if (prev.deny.length === 0 && prev.allow.length === 0) {
|
||||||
getText = () => _t("%(senderDisplayName)s set the server ACLs for this room.", {senderDisplayName});
|
getText = () => _t("%(senderDisplayName)s set the server ACLs for this room.", { senderDisplayName });
|
||||||
} else {
|
} else {
|
||||||
getText = () => _t("%(senderDisplayName)s changed the server ACLs for this room.", {senderDisplayName});
|
getText = () => _t("%(senderDisplayName)s changed the server ACLs for this room.", { senderDisplayName });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Array.isArray(current.allow)) {
|
if (!Array.isArray(current.allow)) {
|
||||||
|
@ -262,7 +262,7 @@ function textForMessageEvent(ev): () => string | null {
|
||||||
if (ev.getContent().msgtype === "m.emote") {
|
if (ev.getContent().msgtype === "m.emote") {
|
||||||
message = "* " + senderDisplayName + " " + message;
|
message = "* " + senderDisplayName + " " + message;
|
||||||
} else if (ev.getContent().msgtype === "m.image") {
|
} else if (ev.getContent().msgtype === "m.image") {
|
||||||
message = _t('%(senderDisplayName)s sent an image.', {senderDisplayName});
|
message = _t('%(senderDisplayName)s sent an image.', { senderDisplayName });
|
||||||
}
|
}
|
||||||
return message;
|
return message;
|
||||||
};
|
};
|
||||||
|
@ -323,7 +323,7 @@ function textForCallAnswerEvent(event): () => string | null {
|
||||||
return () => {
|
return () => {
|
||||||
const senderName = event.sender ? event.sender.name : _t('Someone');
|
const senderName = event.sender ? event.sender.name : _t('Someone');
|
||||||
const supported = MatrixClientPeg.get().supportsVoip() ? '' : _t('(not supported by this browser)');
|
const supported = MatrixClientPeg.get().supportsVoip() ? '' : _t('(not supported by this browser)');
|
||||||
return _t('%(senderName)s answered the call.', {senderName}) + ' ' + supported;
|
return _t('%(senderName)s answered the call.', { senderName }) + ' ' + supported;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -358,16 +358,16 @@ function textForCallHangupEvent(event): () => string | null {
|
||||||
// Also the correct hangup code as of VoIP v1 (with underscore)
|
// Also the correct hangup code as of VoIP v1 (with underscore)
|
||||||
getReason = () => '';
|
getReason = () => '';
|
||||||
} else {
|
} else {
|
||||||
getReason = () => _t('(unknown failure: %(reason)s)', {reason: eventContent.reason});
|
getReason = () => _t('(unknown failure: %(reason)s)', { reason: eventContent.reason });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return () => _t('%(senderName)s ended the call.', {senderName: getSenderName()}) + ' ' + getReason();
|
return () => _t('%(senderName)s ended the call.', { senderName: getSenderName() }) + ' ' + getReason();
|
||||||
}
|
}
|
||||||
|
|
||||||
function textForCallRejectEvent(event): () => string | null {
|
function textForCallRejectEvent(event): () => string | null {
|
||||||
return () => {
|
return () => {
|
||||||
const senderName = event.sender ? event.sender.name : _t('Someone');
|
const senderName = event.sender ? event.sender.name : _t('Someone');
|
||||||
return _t('%(senderName)s declined the call.', {senderName});
|
return _t('%(senderName)s declined the call.', { senderName });
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -424,14 +424,14 @@ function textForHistoryVisibilityEvent(event): () => string | null {
|
||||||
switch (event.getContent().history_visibility) {
|
switch (event.getContent().history_visibility) {
|
||||||
case 'invited':
|
case 'invited':
|
||||||
return () => _t('%(senderName)s made future room history visible to all room members, '
|
return () => _t('%(senderName)s made future room history visible to all room members, '
|
||||||
+ 'from the point they are invited.', {senderName});
|
+ 'from the point they are invited.', { senderName });
|
||||||
case 'joined':
|
case 'joined':
|
||||||
return () => _t('%(senderName)s made future room history visible to all room members, '
|
return () => _t('%(senderName)s made future room history visible to all room members, '
|
||||||
+ 'from the point they joined.', {senderName});
|
+ 'from the point they joined.', { senderName });
|
||||||
case 'shared':
|
case 'shared':
|
||||||
return () => _t('%(senderName)s made future room history visible to all room members.', {senderName});
|
return () => _t('%(senderName)s made future room history visible to all room members.', { senderName });
|
||||||
case 'world_readable':
|
case 'world_readable':
|
||||||
return () => _t('%(senderName)s made future room history visible to anyone.', {senderName});
|
return () => _t('%(senderName)s made future room history visible to anyone.', { senderName });
|
||||||
default:
|
default:
|
||||||
return () => _t('%(senderName)s made future room history visible to unknown (%(visibility)s).', {
|
return () => _t('%(senderName)s made future room history visible to unknown (%(visibility)s).', {
|
||||||
senderName,
|
senderName,
|
||||||
|
@ -492,7 +492,7 @@ const onPinnedMessagesClick = (): void => {
|
||||||
phase: RightPanelPhases.PinnedMessages,
|
phase: RightPanelPhases.PinnedMessages,
|
||||||
allowClose: false,
|
allowClose: false,
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
function textForPinnedEvent(event: MatrixEvent, allowJSX: boolean): () => string | JSX.Element | null {
|
function textForPinnedEvent(event: MatrixEvent, allowJSX: boolean): () => string | JSX.Element | null {
|
||||||
if (!SettingsStore.getValue("feature_pinning")) return null;
|
if (!SettingsStore.getValue("feature_pinning")) return null;
|
||||||
|
@ -517,8 +517,8 @@ function textForPinnedEvent(event: MatrixEvent, allowJSX: boolean): () => string
|
||||||
|
|
||||||
function textForWidgetEvent(event): () => string | null {
|
function textForWidgetEvent(event): () => string | null {
|
||||||
const senderName = event.getSender();
|
const senderName = event.getSender();
|
||||||
const {name: prevName, type: prevType, url: prevUrl} = event.getPrevContent();
|
const { name: prevName, type: prevType, url: prevUrl } = event.getPrevContent();
|
||||||
const {name, type, url} = event.getContent() || {};
|
const { name, type, url } = event.getContent() || {};
|
||||||
|
|
||||||
let widgetName = name || prevName || type || prevType || '';
|
let widgetName = name || prevName || type || prevType || '';
|
||||||
// Apply sentence case to widget name
|
// Apply sentence case to widget name
|
||||||
|
@ -547,68 +547,68 @@ function textForWidgetEvent(event): () => string | null {
|
||||||
|
|
||||||
function textForWidgetLayoutEvent(event): () => string | null {
|
function textForWidgetLayoutEvent(event): () => string | null {
|
||||||
const senderName = event.sender?.name || event.getSender();
|
const senderName = event.sender?.name || event.getSender();
|
||||||
return () => _t("%(senderName)s has updated the widget layout", {senderName});
|
return () => _t("%(senderName)s has updated the widget layout", { senderName });
|
||||||
}
|
}
|
||||||
|
|
||||||
function textForMjolnirEvent(event): () => string | null {
|
function textForMjolnirEvent(event): () => string | null {
|
||||||
const senderName = event.getSender();
|
const senderName = event.getSender();
|
||||||
const {entity: prevEntity} = event.getPrevContent();
|
const { entity: prevEntity } = event.getPrevContent();
|
||||||
const {entity, recommendation, reason} = event.getContent();
|
const { entity, recommendation, reason } = event.getContent();
|
||||||
|
|
||||||
// Rule removed
|
// Rule removed
|
||||||
if (!entity) {
|
if (!entity) {
|
||||||
if (USER_RULE_TYPES.includes(event.getType())) {
|
if (USER_RULE_TYPES.includes(event.getType())) {
|
||||||
return () => _t("%(senderName)s removed the rule banning users matching %(glob)s",
|
return () => _t("%(senderName)s removed the rule banning users matching %(glob)s",
|
||||||
{senderName, glob: prevEntity});
|
{ senderName, glob: prevEntity });
|
||||||
} else if (ROOM_RULE_TYPES.includes(event.getType())) {
|
} else if (ROOM_RULE_TYPES.includes(event.getType())) {
|
||||||
return () => _t("%(senderName)s removed the rule banning rooms matching %(glob)s",
|
return () => _t("%(senderName)s removed the rule banning rooms matching %(glob)s",
|
||||||
{senderName, glob: prevEntity});
|
{ senderName, glob: prevEntity });
|
||||||
} else if (SERVER_RULE_TYPES.includes(event.getType())) {
|
} else if (SERVER_RULE_TYPES.includes(event.getType())) {
|
||||||
return () => _t("%(senderName)s removed the rule banning servers matching %(glob)s",
|
return () => _t("%(senderName)s removed the rule banning servers matching %(glob)s",
|
||||||
{senderName, glob: prevEntity});
|
{ senderName, glob: prevEntity });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unknown type. We'll say something, but we shouldn't end up here.
|
// Unknown type. We'll say something, but we shouldn't end up here.
|
||||||
return () => _t("%(senderName)s removed a ban rule matching %(glob)s", {senderName, glob: prevEntity});
|
return () => _t("%(senderName)s removed a ban rule matching %(glob)s", { senderName, glob: prevEntity });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invalid rule
|
// Invalid rule
|
||||||
if (!recommendation || !reason) return () => _t(`%(senderName)s updated an invalid ban rule`, {senderName});
|
if (!recommendation || !reason) return () => _t(`%(senderName)s updated an invalid ban rule`, { senderName });
|
||||||
|
|
||||||
// Rule updated
|
// Rule updated
|
||||||
if (entity === prevEntity) {
|
if (entity === prevEntity) {
|
||||||
if (USER_RULE_TYPES.includes(event.getType())) {
|
if (USER_RULE_TYPES.includes(event.getType())) {
|
||||||
return () => _t("%(senderName)s updated the rule banning users matching %(glob)s for %(reason)s",
|
return () => _t("%(senderName)s updated the rule banning users matching %(glob)s for %(reason)s",
|
||||||
{senderName, glob: entity, reason});
|
{ senderName, glob: entity, reason });
|
||||||
} else if (ROOM_RULE_TYPES.includes(event.getType())) {
|
} else if (ROOM_RULE_TYPES.includes(event.getType())) {
|
||||||
return () => _t("%(senderName)s updated the rule banning rooms matching %(glob)s for %(reason)s",
|
return () => _t("%(senderName)s updated the rule banning rooms matching %(glob)s for %(reason)s",
|
||||||
{senderName, glob: entity, reason});
|
{ senderName, glob: entity, reason });
|
||||||
} else if (SERVER_RULE_TYPES.includes(event.getType())) {
|
} else if (SERVER_RULE_TYPES.includes(event.getType())) {
|
||||||
return () => _t("%(senderName)s updated the rule banning servers matching %(glob)s for %(reason)s",
|
return () => _t("%(senderName)s updated the rule banning servers matching %(glob)s for %(reason)s",
|
||||||
{senderName, glob: entity, reason});
|
{ senderName, glob: entity, reason });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unknown type. We'll say something but we shouldn't end up here.
|
// Unknown type. We'll say something but we shouldn't end up here.
|
||||||
return () => _t("%(senderName)s updated a ban rule matching %(glob)s for %(reason)s",
|
return () => _t("%(senderName)s updated a ban rule matching %(glob)s for %(reason)s",
|
||||||
{senderName, glob: entity, reason});
|
{ senderName, glob: entity, reason });
|
||||||
}
|
}
|
||||||
|
|
||||||
// New rule
|
// New rule
|
||||||
if (!prevEntity) {
|
if (!prevEntity) {
|
||||||
if (USER_RULE_TYPES.includes(event.getType())) {
|
if (USER_RULE_TYPES.includes(event.getType())) {
|
||||||
return () => _t("%(senderName)s created a rule banning users matching %(glob)s for %(reason)s",
|
return () => _t("%(senderName)s created a rule banning users matching %(glob)s for %(reason)s",
|
||||||
{senderName, glob: entity, reason});
|
{ senderName, glob: entity, reason });
|
||||||
} else if (ROOM_RULE_TYPES.includes(event.getType())) {
|
} else if (ROOM_RULE_TYPES.includes(event.getType())) {
|
||||||
return () => _t("%(senderName)s created a rule banning rooms matching %(glob)s for %(reason)s",
|
return () => _t("%(senderName)s created a rule banning rooms matching %(glob)s for %(reason)s",
|
||||||
{senderName, glob: entity, reason});
|
{ senderName, glob: entity, reason });
|
||||||
} else if (SERVER_RULE_TYPES.includes(event.getType())) {
|
} else if (SERVER_RULE_TYPES.includes(event.getType())) {
|
||||||
return () => _t("%(senderName)s created a rule banning servers matching %(glob)s for %(reason)s",
|
return () => _t("%(senderName)s created a rule banning servers matching %(glob)s for %(reason)s",
|
||||||
{senderName, glob: entity, reason});
|
{ senderName, glob: entity, reason });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unknown type. We'll say something but we shouldn't end up here.
|
// Unknown type. We'll say something but we shouldn't end up here.
|
||||||
return () => _t("%(senderName)s created a ban rule matching %(glob)s for %(reason)s",
|
return () => _t("%(senderName)s created a ban rule matching %(glob)s for %(reason)s",
|
||||||
{senderName, glob: entity, reason});
|
{ senderName, glob: entity, reason });
|
||||||
}
|
}
|
||||||
|
|
||||||
// else the entity !== prevEntity - count as a removal & add
|
// else the entity !== prevEntity - count as a removal & add
|
||||||
|
@ -616,25 +616,25 @@ function textForMjolnirEvent(event): () => string | null {
|
||||||
return () => _t(
|
return () => _t(
|
||||||
"%(senderName)s changed a rule that was banning users matching %(oldGlob)s to matching " +
|
"%(senderName)s changed a rule that was banning users matching %(oldGlob)s to matching " +
|
||||||
"%(newGlob)s for %(reason)s",
|
"%(newGlob)s for %(reason)s",
|
||||||
{senderName, oldGlob: prevEntity, newGlob: entity, reason},
|
{ senderName, oldGlob: prevEntity, newGlob: entity, reason },
|
||||||
);
|
);
|
||||||
} else if (ROOM_RULE_TYPES.includes(event.getType())) {
|
} else if (ROOM_RULE_TYPES.includes(event.getType())) {
|
||||||
return () => _t(
|
return () => _t(
|
||||||
"%(senderName)s changed a rule that was banning rooms matching %(oldGlob)s to matching " +
|
"%(senderName)s changed a rule that was banning rooms matching %(oldGlob)s to matching " +
|
||||||
"%(newGlob)s for %(reason)s",
|
"%(newGlob)s for %(reason)s",
|
||||||
{senderName, oldGlob: prevEntity, newGlob: entity, reason},
|
{ senderName, oldGlob: prevEntity, newGlob: entity, reason },
|
||||||
);
|
);
|
||||||
} else if (SERVER_RULE_TYPES.includes(event.getType())) {
|
} else if (SERVER_RULE_TYPES.includes(event.getType())) {
|
||||||
return () => _t(
|
return () => _t(
|
||||||
"%(senderName)s changed a rule that was banning servers matching %(oldGlob)s to matching " +
|
"%(senderName)s changed a rule that was banning servers matching %(oldGlob)s to matching " +
|
||||||
"%(newGlob)s for %(reason)s",
|
"%(newGlob)s for %(reason)s",
|
||||||
{senderName, oldGlob: prevEntity, newGlob: entity, reason},
|
{ senderName, oldGlob: prevEntity, newGlob: entity, reason },
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unknown type. We'll say something but we shouldn't end up here.
|
// Unknown type. We'll say something but we shouldn't end up here.
|
||||||
return () => _t("%(senderName)s updated a ban rule that was matching %(oldGlob)s to matching %(newGlob)s " +
|
return () => _t("%(senderName)s updated a ban rule that was matching %(oldGlob)s to matching %(newGlob)s " +
|
||||||
"for %(reason)s", {senderName, oldGlob: prevEntity, newGlob: entity, reason});
|
"for %(reason)s", { senderName, oldGlob: prevEntity, newGlob: entity, reason });
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IHandlers {
|
interface IHandlers {
|
||||||
|
|
458
src/Tinter.js
458
src/Tinter.js
|
@ -1,458 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2015 OpenMarket Ltd
|
|
||||||
Copyright 2017 New Vector Ltd
|
|
||||||
|
|
||||||
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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
const DEBUG = 0;
|
|
||||||
|
|
||||||
// utility to turn #rrggbb or rgb(r,g,b) into [red,green,blue]
|
|
||||||
function colorToRgb(color) {
|
|
||||||
if (!color) {
|
|
||||||
return [0, 0, 0];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (color[0] === '#') {
|
|
||||||
color = color.slice(1);
|
|
||||||
if (color.length === 3) {
|
|
||||||
color = color[0] + color[0] +
|
|
||||||
color[1] + color[1] +
|
|
||||||
color[2] + color[2];
|
|
||||||
}
|
|
||||||
const val = parseInt(color, 16);
|
|
||||||
const r = (val >> 16) & 255;
|
|
||||||
const g = (val >> 8) & 255;
|
|
||||||
const b = val & 255;
|
|
||||||
return [r, g, b];
|
|
||||||
} else {
|
|
||||||
const match = color.match(/rgb\((.*?),(.*?),(.*?)\)/);
|
|
||||||
if (match) {
|
|
||||||
return [
|
|
||||||
parseInt(match[1]),
|
|
||||||
parseInt(match[2]),
|
|
||||||
parseInt(match[3]),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return [0, 0, 0];
|
|
||||||
}
|
|
||||||
|
|
||||||
// utility to turn [red,green,blue] into #rrggbb
|
|
||||||
function rgbToColor(rgb) {
|
|
||||||
const val = (rgb[0] << 16) | (rgb[1] << 8) | rgb[2];
|
|
||||||
return '#' + (0x1000000 + val).toString(16).slice(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
class Tinter {
|
|
||||||
constructor() {
|
|
||||||
// The default colour keys to be replaced as referred to in CSS
|
|
||||||
// (should be overridden by .mx_theme_accentColor and .mx_theme_secondaryAccentColor)
|
|
||||||
this.keyRgb = [
|
|
||||||
"rgb(118, 207, 166)", // Vector Green
|
|
||||||
"rgb(234, 245, 240)", // Vector Light Green
|
|
||||||
"rgb(211, 239, 225)", // roomsublist-label-bg-color (20% Green overlaid on Light Green)
|
|
||||||
];
|
|
||||||
|
|
||||||
// Some algebra workings for calculating the tint % of Vector Green & Light Green
|
|
||||||
// x * 118 + (1 - x) * 255 = 234
|
|
||||||
// x * 118 + 255 - 255 * x = 234
|
|
||||||
// x * 118 - x * 255 = 234 - 255
|
|
||||||
// (255 - 118) x = 255 - 234
|
|
||||||
// x = (255 - 234) / (255 - 118) = 0.16
|
|
||||||
|
|
||||||
// The colour keys to be replaced as referred to in SVGs
|
|
||||||
this.keyHex = [
|
|
||||||
"#76CFA6", // Vector Green
|
|
||||||
"#EAF5F0", // Vector Light Green
|
|
||||||
"#D3EFE1", // roomsublist-label-bg-color (20% Green overlaid on Light Green)
|
|
||||||
"#FFFFFF", // white highlights of the SVGs (for switching to dark theme)
|
|
||||||
"#000000", // black lowlights of the SVGs (for switching to dark theme)
|
|
||||||
];
|
|
||||||
|
|
||||||
// track the replacement colours actually being used
|
|
||||||
// defaults to our keys.
|
|
||||||
this.colors = [
|
|
||||||
this.keyHex[0],
|
|
||||||
this.keyHex[1],
|
|
||||||
this.keyHex[2],
|
|
||||||
this.keyHex[3],
|
|
||||||
this.keyHex[4],
|
|
||||||
];
|
|
||||||
|
|
||||||
// track the most current tint request inputs (which may differ from the
|
|
||||||
// end result stored in this.colors
|
|
||||||
this.currentTint = [
|
|
||||||
undefined,
|
|
||||||
undefined,
|
|
||||||
undefined,
|
|
||||||
undefined,
|
|
||||||
undefined,
|
|
||||||
];
|
|
||||||
|
|
||||||
this.cssFixups = [
|
|
||||||
// { theme: {
|
|
||||||
// style: a style object that should be fixed up taken from a stylesheet
|
|
||||||
// attr: name of the attribute to be clobbered, e.g. 'color'
|
|
||||||
// index: ordinal of primary, secondary or tertiary
|
|
||||||
// },
|
|
||||||
// }
|
|
||||||
];
|
|
||||||
|
|
||||||
// CSS attributes to be fixed up
|
|
||||||
this.cssAttrs = [
|
|
||||||
"color",
|
|
||||||
"backgroundColor",
|
|
||||||
"borderColor",
|
|
||||||
"borderTopColor",
|
|
||||||
"borderBottomColor",
|
|
||||||
"borderLeftColor",
|
|
||||||
];
|
|
||||||
|
|
||||||
this.svgAttrs = [
|
|
||||||
"fill",
|
|
||||||
"stroke",
|
|
||||||
];
|
|
||||||
|
|
||||||
// List of functions to call when the tint changes.
|
|
||||||
this.tintables = [];
|
|
||||||
|
|
||||||
// the currently loaded theme (if any)
|
|
||||||
this.theme = undefined;
|
|
||||||
|
|
||||||
// whether to force a tint (e.g. after changing theme)
|
|
||||||
this.forceTint = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register a callback to fire when the tint changes.
|
|
||||||
* This is used to rewrite the tintable SVGs with the new tint.
|
|
||||||
*
|
|
||||||
* It's not possible to unregister a tintable callback. So this can only be
|
|
||||||
* used to register a static callback. If a set of tintables will change
|
|
||||||
* over time then the best bet is to register a single callback for the
|
|
||||||
* entire set.
|
|
||||||
*
|
|
||||||
* To ensure the tintable work happens at least once, it is also called as
|
|
||||||
* part of registration.
|
|
||||||
*
|
|
||||||
* @param {Function} tintable Function to call when the tint changes.
|
|
||||||
*/
|
|
||||||
registerTintable(tintable) {
|
|
||||||
this.tintables.push(tintable);
|
|
||||||
tintable();
|
|
||||||
}
|
|
||||||
|
|
||||||
getKeyRgb() {
|
|
||||||
return this.keyRgb;
|
|
||||||
}
|
|
||||||
|
|
||||||
tint(primaryColor, secondaryColor, tertiaryColor) {
|
|
||||||
return;
|
|
||||||
// eslint-disable-next-line no-unreachable
|
|
||||||
this.currentTint[0] = primaryColor;
|
|
||||||
this.currentTint[1] = secondaryColor;
|
|
||||||
this.currentTint[2] = tertiaryColor;
|
|
||||||
|
|
||||||
this.calcCssFixups();
|
|
||||||
|
|
||||||
if (DEBUG) {
|
|
||||||
console.log("Tinter.tint(" + primaryColor + ", " +
|
|
||||||
secondaryColor + ", " +
|
|
||||||
tertiaryColor + ")");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!primaryColor) {
|
|
||||||
primaryColor = this.keyRgb[0];
|
|
||||||
secondaryColor = this.keyRgb[1];
|
|
||||||
tertiaryColor = this.keyRgb[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!secondaryColor) {
|
|
||||||
const x = 0.16; // average weighting factor calculated from vector green & light green
|
|
||||||
const rgb = colorToRgb(primaryColor);
|
|
||||||
rgb[0] = x * rgb[0] + (1 - x) * 255;
|
|
||||||
rgb[1] = x * rgb[1] + (1 - x) * 255;
|
|
||||||
rgb[2] = x * rgb[2] + (1 - x) * 255;
|
|
||||||
secondaryColor = rgbToColor(rgb);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!tertiaryColor) {
|
|
||||||
const x = 0.19;
|
|
||||||
const rgb1 = colorToRgb(primaryColor);
|
|
||||||
const rgb2 = colorToRgb(secondaryColor);
|
|
||||||
rgb1[0] = x * rgb1[0] + (1 - x) * rgb2[0];
|
|
||||||
rgb1[1] = x * rgb1[1] + (1 - x) * rgb2[1];
|
|
||||||
rgb1[2] = x * rgb1[2] + (1 - x) * rgb2[2];
|
|
||||||
tertiaryColor = rgbToColor(rgb1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.forceTint == false &&
|
|
||||||
this.colors[0] === primaryColor &&
|
|
||||||
this.colors[1] === secondaryColor &&
|
|
||||||
this.colors[2] === tertiaryColor) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.forceTint = false;
|
|
||||||
|
|
||||||
this.colors[0] = primaryColor;
|
|
||||||
this.colors[1] = secondaryColor;
|
|
||||||
this.colors[2] = tertiaryColor;
|
|
||||||
|
|
||||||
if (DEBUG) {
|
|
||||||
console.log("Tinter.tint final: (" + primaryColor + ", " +
|
|
||||||
secondaryColor + ", " +
|
|
||||||
tertiaryColor + ")");
|
|
||||||
}
|
|
||||||
|
|
||||||
// go through manually fixing up the stylesheets.
|
|
||||||
this.applyCssFixups();
|
|
||||||
|
|
||||||
// tell all the SVGs to go fix themselves up
|
|
||||||
// we don't do this as a dispatch otherwise it will visually lag
|
|
||||||
this.tintables.forEach(function(tintable) {
|
|
||||||
tintable();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
tintSvgWhite(whiteColor) {
|
|
||||||
this.currentTint[3] = whiteColor;
|
|
||||||
|
|
||||||
if (!whiteColor) {
|
|
||||||
whiteColor = this.colors[3];
|
|
||||||
}
|
|
||||||
if (this.colors[3] === whiteColor) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.colors[3] = whiteColor;
|
|
||||||
this.tintables.forEach(function(tintable) {
|
|
||||||
tintable();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
tintSvgBlack(blackColor) {
|
|
||||||
this.currentTint[4] = blackColor;
|
|
||||||
|
|
||||||
if (!blackColor) {
|
|
||||||
blackColor = this.colors[4];
|
|
||||||
}
|
|
||||||
if (this.colors[4] === blackColor) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.colors[4] = blackColor;
|
|
||||||
this.tintables.forEach(function(tintable) {
|
|
||||||
tintable();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
setTheme(theme) {
|
|
||||||
this.theme = theme;
|
|
||||||
|
|
||||||
// update keyRgb from the current theme CSS itself, if it defines it
|
|
||||||
if (document.getElementById('mx_theme_accentColor')) {
|
|
||||||
this.keyRgb[0] = window.getComputedStyle(
|
|
||||||
document.getElementById('mx_theme_accentColor')).color;
|
|
||||||
}
|
|
||||||
if (document.getElementById('mx_theme_secondaryAccentColor')) {
|
|
||||||
this.keyRgb[1] = window.getComputedStyle(
|
|
||||||
document.getElementById('mx_theme_secondaryAccentColor')).color;
|
|
||||||
}
|
|
||||||
if (document.getElementById('mx_theme_tertiaryAccentColor')) {
|
|
||||||
this.keyRgb[2] = window.getComputedStyle(
|
|
||||||
document.getElementById('mx_theme_tertiaryAccentColor')).color;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.calcCssFixups();
|
|
||||||
this.forceTint = true;
|
|
||||||
|
|
||||||
this.tint(this.currentTint[0], this.currentTint[1], this.currentTint[2]);
|
|
||||||
|
|
||||||
if (theme === 'dark') {
|
|
||||||
// abuse the tinter to change all the SVG's #fff to #2d2d2d
|
|
||||||
// XXX: obviously this shouldn't be hardcoded here.
|
|
||||||
this.tintSvgWhite('#2d2d2d');
|
|
||||||
this.tintSvgBlack('#dddddd');
|
|
||||||
} else {
|
|
||||||
this.tintSvgWhite('#ffffff');
|
|
||||||
this.tintSvgBlack('#000000');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
calcCssFixups() {
|
|
||||||
// cache our fixups
|
|
||||||
if (this.cssFixups[this.theme]) return;
|
|
||||||
|
|
||||||
if (DEBUG) {
|
|
||||||
console.debug("calcCssFixups start for " + this.theme + " (checking " +
|
|
||||||
document.styleSheets.length +
|
|
||||||
" stylesheets)");
|
|
||||||
}
|
|
||||||
|
|
||||||
this.cssFixups[this.theme] = [];
|
|
||||||
|
|
||||||
for (let i = 0; i < document.styleSheets.length; i++) {
|
|
||||||
const ss = document.styleSheets[i];
|
|
||||||
try {
|
|
||||||
if (!ss) continue; // well done safari >:(
|
|
||||||
// Chromium apparently sometimes returns null here; unsure why.
|
|
||||||
// see $14534907369972FRXBx:matrix.org in HQ
|
|
||||||
// ...ah, it's because there's a third party extension like
|
|
||||||
// privacybadger inserting its own stylesheet in there with a
|
|
||||||
// resource:// URI or something which results in a XSS error.
|
|
||||||
// See also #vector:matrix.org/$145357669685386ebCfr:matrix.org
|
|
||||||
// ...except some browsers apparently return stylesheets without
|
|
||||||
// hrefs, which we have no choice but ignore right now
|
|
||||||
|
|
||||||
// XXX seriously? we are hardcoding the name of vector's CSS file in
|
|
||||||
// here?
|
|
||||||
//
|
|
||||||
// Why do we need to limit it to vector's CSS file anyway - if there
|
|
||||||
// are other CSS files affecting the doc don't we want to apply the
|
|
||||||
// same transformations to them?
|
|
||||||
//
|
|
||||||
// Iterating through the CSS looking for matches to hack on feels
|
|
||||||
// pretty horrible anyway. And what if the application skin doesn't use
|
|
||||||
// Vector Green as its primary color?
|
|
||||||
// --richvdh
|
|
||||||
|
|
||||||
// Yes, tinting assumes that you are using the Element skin for now.
|
|
||||||
// The right solution will be to move the CSS over to react-sdk.
|
|
||||||
// And yes, the default assets for the base skin might as well use
|
|
||||||
// Vector Green as any other colour.
|
|
||||||
// --matthew
|
|
||||||
|
|
||||||
// stylesheets we don't have permission to access (eg. ones from extensions) have a null
|
|
||||||
// href and will throw exceptions if we try to access their rules.
|
|
||||||
if (!ss.href || !ss.href.match(new RegExp('/theme-' + this.theme + '.css$'))) continue;
|
|
||||||
if (ss.disabled) continue;
|
|
||||||
if (!ss.cssRules) continue;
|
|
||||||
|
|
||||||
if (DEBUG) console.debug("calcCssFixups checking " + ss.cssRules.length + " rules for " + ss.href);
|
|
||||||
|
|
||||||
for (let j = 0; j < ss.cssRules.length; j++) {
|
|
||||||
const rule = ss.cssRules[j];
|
|
||||||
if (!rule.style) continue;
|
|
||||||
if (rule.selectorText && rule.selectorText.match(/#mx_theme/)) continue;
|
|
||||||
for (let k = 0; k < this.cssAttrs.length; k++) {
|
|
||||||
const attr = this.cssAttrs[k];
|
|
||||||
for (let l = 0; l < this.keyRgb.length; l++) {
|
|
||||||
if (rule.style[attr] === this.keyRgb[l]) {
|
|
||||||
this.cssFixups[this.theme].push({
|
|
||||||
style: rule.style,
|
|
||||||
attr: attr,
|
|
||||||
index: l,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
// Catch any random exceptions that happen here: all sorts of things can go
|
|
||||||
// wrong with this (nulls, SecurityErrors) and mostly it's for other
|
|
||||||
// stylesheets that we don't want to proces anyway. We should not propagate an
|
|
||||||
// exception out since this will cause the app to fail to start.
|
|
||||||
console.log("Failed to calculate CSS fixups for a stylesheet: " + ss.href, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (DEBUG) {
|
|
||||||
console.log("calcCssFixups end (" +
|
|
||||||
this.cssFixups[this.theme].length +
|
|
||||||
" fixups)");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
applyCssFixups() {
|
|
||||||
if (DEBUG) {
|
|
||||||
console.log("applyCssFixups start (" +
|
|
||||||
this.cssFixups[this.theme].length +
|
|
||||||
" fixups)");
|
|
||||||
}
|
|
||||||
for (let i = 0; i < this.cssFixups[this.theme].length; i++) {
|
|
||||||
const cssFixup = this.cssFixups[this.theme][i];
|
|
||||||
try {
|
|
||||||
cssFixup.style[cssFixup.attr] = this.colors[cssFixup.index];
|
|
||||||
} catch (e) {
|
|
||||||
// Firefox Quantum explodes if you manually edit the CSS in the
|
|
||||||
// inspector and then try to do a tint, as apparently all the
|
|
||||||
// fixups are then stale.
|
|
||||||
console.error("Failed to apply cssFixup in Tinter! ", e.name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (DEBUG) console.log("applyCssFixups end");
|
|
||||||
}
|
|
||||||
|
|
||||||
// XXX: we could just move this all into TintableSvg, but as it's so similar
|
|
||||||
// to the CSS fixup stuff in Tinter (just that the fixups are stored in TintableSvg)
|
|
||||||
// keeping it here for now.
|
|
||||||
calcSvgFixups(svgs) {
|
|
||||||
// go through manually fixing up SVG colours.
|
|
||||||
// we could do this by stylesheets, but keeping the stylesheets
|
|
||||||
// updated would be a PITA, so just brute-force search for the
|
|
||||||
// key colour; cache the element and apply.
|
|
||||||
|
|
||||||
if (DEBUG) console.log("calcSvgFixups start for " + svgs);
|
|
||||||
const fixups = [];
|
|
||||||
for (let i = 0; i < svgs.length; i++) {
|
|
||||||
let svgDoc;
|
|
||||||
try {
|
|
||||||
svgDoc = svgs[i].contentDocument;
|
|
||||||
} catch (e) {
|
|
||||||
let msg = 'Failed to get svg.contentDocument of ' + svgs[i].toString();
|
|
||||||
if (e.message) {
|
|
||||||
msg += e.message;
|
|
||||||
}
|
|
||||||
if (e.stack) {
|
|
||||||
msg += ' | stack: ' + e.stack;
|
|
||||||
}
|
|
||||||
console.error(msg);
|
|
||||||
}
|
|
||||||
if (!svgDoc) continue;
|
|
||||||
const tags = svgDoc.getElementsByTagName("*");
|
|
||||||
for (let j = 0; j < tags.length; j++) {
|
|
||||||
const tag = tags[j];
|
|
||||||
for (let k = 0; k < this.svgAttrs.length; k++) {
|
|
||||||
const attr = this.svgAttrs[k];
|
|
||||||
for (let l = 0; l < this.keyHex.length; l++) {
|
|
||||||
if (tag.getAttribute(attr) &&
|
|
||||||
tag.getAttribute(attr).toUpperCase() === this.keyHex[l]) {
|
|
||||||
fixups.push({
|
|
||||||
node: tag,
|
|
||||||
attr: attr,
|
|
||||||
index: l,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (DEBUG) console.log("calcSvgFixups end");
|
|
||||||
|
|
||||||
return fixups;
|
|
||||||
}
|
|
||||||
|
|
||||||
applySvgFixups(fixups) {
|
|
||||||
if (DEBUG) console.log("applySvgFixups start for " + fixups);
|
|
||||||
for (let i = 0; i < fixups.length; i++) {
|
|
||||||
const svgFixup = fixups[i];
|
|
||||||
svgFixup.node.setAttribute(svgFixup.attr, this.colors[svgFixup.index]);
|
|
||||||
}
|
|
||||||
if (DEBUG) console.log("applySvgFixups end");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (global.singletonTinter === undefined) {
|
|
||||||
global.singletonTinter = new Tinter();
|
|
||||||
}
|
|
||||||
export default global.singletonTinter;
|
|
|
@ -191,10 +191,10 @@ export default class UserActivity {
|
||||||
this.lastScreenY = event.screenY;
|
this.lastScreenY = event.screenY;
|
||||||
}
|
}
|
||||||
|
|
||||||
dis.dispatch({action: 'user_activity'});
|
dis.dispatch({ action: 'user_activity' });
|
||||||
if (!this.activeNowTimeout.isRunning()) {
|
if (!this.activeNowTimeout.isRunning()) {
|
||||||
this.activeNowTimeout.start();
|
this.activeNowTimeout.start();
|
||||||
dis.dispatch({action: 'user_activity_start'});
|
dis.dispatch({ action: 'user_activity_start' });
|
||||||
|
|
||||||
UserActivity.runTimersUntilTimeout(this.attachedActiveNowTimers, this.activeNowTimeout);
|
UserActivity.runTimersUntilTimeout(this.attachedActiveNowTimers, this.activeNowTimeout);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -14,10 +14,10 @@ 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 { Room } from "matrix-js-sdk/src/models/room";
|
||||||
import {RoomMember} from "matrix-js-sdk/src/models/room-member";
|
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
|
||||||
|
|
||||||
import {MatrixClientPeg} from "./MatrixClientPeg";
|
import { MatrixClientPeg } from "./MatrixClientPeg";
|
||||||
import { _t } from './languageHandler';
|
import { _t } from './languageHandler';
|
||||||
|
|
||||||
export function usersTypingApartFromMeAndIgnored(room: Room): RoomMember[] {
|
export function usersTypingApartFromMeAndIgnored(room: Room): RoomMember[] {
|
||||||
|
@ -61,7 +61,7 @@ export function whoIsTypingString(whoIsTyping: RoomMember[], limit: number): str
|
||||||
if (whoIsTyping.length === 0) {
|
if (whoIsTyping.length === 0) {
|
||||||
return '';
|
return '';
|
||||||
} else if (whoIsTyping.length === 1) {
|
} else if (whoIsTyping.length === 1) {
|
||||||
return _t('%(displayName)s is typing …', {displayName: whoIsTyping[0].name});
|
return _t('%(displayName)s is typing …', { displayName: whoIsTyping[0].name });
|
||||||
}
|
}
|
||||||
|
|
||||||
const names = whoIsTyping.map(m => m.name);
|
const names = whoIsTyping.map(m => m.name);
|
||||||
|
@ -73,6 +73,6 @@ export function whoIsTypingString(whoIsTyping: RoomMember[], limit: number): str
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
const lastPerson = names.pop();
|
const lastPerson = names.pop();
|
||||||
return _t('%(names)s and %(lastPerson)s are typing …', {names: names.join(', '), lastPerson: lastPerson});
|
return _t('%(names)s and %(lastPerson)s are typing …', { names: names.join(', '), lastPerson: lastPerson });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ import classNames from "classnames";
|
||||||
import * as sdk from "../index";
|
import * as sdk from "../index";
|
||||||
import Modal from "../Modal";
|
import Modal from "../Modal";
|
||||||
import { _t, _td } from "../languageHandler";
|
import { _t, _td } from "../languageHandler";
|
||||||
import {isMac, Key} from "../Keyboard";
|
import { isMac, Key } from "../Keyboard";
|
||||||
|
|
||||||
// TS: once languageHandler is TS we can probably inline this into the enum
|
// TS: once languageHandler is TS we can probably inline this into the enum
|
||||||
_td("Navigation");
|
_td("Navigation");
|
||||||
|
@ -332,7 +332,7 @@ const keyIcon: Record<string, string> = {
|
||||||
|
|
||||||
const Shortcut: React.FC<{
|
const Shortcut: React.FC<{
|
||||||
shortcut: IShortcut;
|
shortcut: IShortcut;
|
||||||
}> = ({shortcut}) => {
|
}> = ({ shortcut }) => {
|
||||||
const classes = classNames({
|
const classes = classNames({
|
||||||
"mx_KeyboardShortcutsDialog_inline": shortcut.keybinds.every(k => !k.modifiers || k.modifiers.length === 0),
|
"mx_KeyboardShortcutsDialog_inline": shortcut.keybinds.every(k => !k.modifiers || k.modifiers.length === 0),
|
||||||
});
|
});
|
||||||
|
|
|
@ -26,8 +26,8 @@ import React, {
|
||||||
Dispatch,
|
Dispatch,
|
||||||
} from "react";
|
} from "react";
|
||||||
|
|
||||||
import {Key} from "../Keyboard";
|
import { Key } from "../Keyboard";
|
||||||
import {FocusHandler, Ref} from "./roving/types";
|
import { FocusHandler, Ref } from "./roving/types";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Module to simplify implementing the Roving TabIndex accessibility technique
|
* Module to simplify implementing the Roving TabIndex accessibility technique
|
||||||
|
@ -156,13 +156,13 @@ interface IProps {
|
||||||
onKeyDown?(ev: React.KeyboardEvent, state: IState);
|
onKeyDown?(ev: React.KeyboardEvent, state: IState);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const RovingTabIndexProvider: React.FC<IProps> = ({children, handleHomeEnd, onKeyDown}) => {
|
export const RovingTabIndexProvider: React.FC<IProps> = ({ children, handleHomeEnd, onKeyDown }) => {
|
||||||
const [state, dispatch] = useReducer<Reducer<IState, IAction>>(reducer, {
|
const [state, dispatch] = useReducer<Reducer<IState, IAction>>(reducer, {
|
||||||
activeRef: null,
|
activeRef: null,
|
||||||
refs: [],
|
refs: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
const context = useMemo<IContext>(() => ({state, dispatch}), [state]);
|
const context = useMemo<IContext>(() => ({ state, dispatch }), [state]);
|
||||||
|
|
||||||
const onKeyDownHandler = useCallback((ev) => {
|
const onKeyDownHandler = useCallback((ev) => {
|
||||||
let handled = false;
|
let handled = false;
|
||||||
|
@ -196,7 +196,7 @@ export const RovingTabIndexProvider: React.FC<IProps> = ({children, handleHomeEn
|
||||||
}, [context.state, onKeyDown, handleHomeEnd]);
|
}, [context.state, onKeyDown, handleHomeEnd]);
|
||||||
|
|
||||||
return <RovingTabIndexContext.Provider value={context}>
|
return <RovingTabIndexContext.Provider value={context}>
|
||||||
{ children({onKeyDownHandler}) }
|
{ children({ onKeyDownHandler }) }
|
||||||
</RovingTabIndexContext.Provider>;
|
</RovingTabIndexContext.Provider>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -218,13 +218,13 @@ export const useRovingTabIndex = (inputRef?: Ref): [FocusHandler, boolean, Ref]
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
context.dispatch({
|
context.dispatch({
|
||||||
type: Type.Register,
|
type: Type.Register,
|
||||||
payload: {ref},
|
payload: { ref },
|
||||||
});
|
});
|
||||||
// teardown
|
// teardown
|
||||||
return () => {
|
return () => {
|
||||||
context.dispatch({
|
context.dispatch({
|
||||||
type: Type.Unregister,
|
type: Type.Unregister,
|
||||||
payload: {ref},
|
payload: { ref },
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}, []); // eslint-disable-line react-hooks/exhaustive-deps
|
}, []); // eslint-disable-line react-hooks/exhaustive-deps
|
||||||
|
@ -232,7 +232,7 @@ export const useRovingTabIndex = (inputRef?: Ref): [FocusHandler, boolean, Ref]
|
||||||
const onFocus = useCallback(() => {
|
const onFocus = useCallback(() => {
|
||||||
context.dispatch({
|
context.dispatch({
|
||||||
type: Type.SetFocus,
|
type: Type.SetFocus,
|
||||||
payload: {ref},
|
payload: { ref },
|
||||||
});
|
});
|
||||||
}, [ref, context]);
|
}, [ref, context]);
|
||||||
|
|
||||||
|
@ -241,6 +241,6 @@ export const useRovingTabIndex = (inputRef?: Ref): [FocusHandler, boolean, Ref]
|
||||||
};
|
};
|
||||||
|
|
||||||
// re-export the semantic helper components for simplicity
|
// re-export the semantic helper components for simplicity
|
||||||
export {RovingTabIndexWrapper} from "./roving/RovingTabIndexWrapper";
|
export { RovingTabIndexWrapper } from "./roving/RovingTabIndexWrapper";
|
||||||
export {RovingAccessibleButton} from "./roving/RovingAccessibleButton";
|
export { RovingAccessibleButton } from "./roving/RovingAccessibleButton";
|
||||||
export {RovingAccessibleTooltipButton} from "./roving/RovingAccessibleTooltipButton";
|
export { RovingAccessibleTooltipButton } from "./roving/RovingAccessibleTooltipButton";
|
||||||
|
|
|
@ -16,8 +16,8 @@ limitations under the License.
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import {IState, RovingTabIndexProvider} from "./RovingTabIndex";
|
import { IState, RovingTabIndexProvider } from "./RovingTabIndex";
|
||||||
import {Key} from "../Keyboard";
|
import { Key } from "../Keyboard";
|
||||||
|
|
||||||
interface IProps extends Omit<React.HTMLProps<HTMLDivElement>, "onKeyDown"> {
|
interface IProps extends Omit<React.HTMLProps<HTMLDivElement>, "onKeyDown"> {
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ interface IProps extends Omit<React.HTMLProps<HTMLDivElement>, "onKeyDown"> {
|
||||||
// This component implements the Toolbar design pattern from the WAI-ARIA Authoring Practices guidelines.
|
// This component implements the Toolbar design pattern from the WAI-ARIA Authoring Practices guidelines.
|
||||||
// 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, state: IState) => {
|
const onKeyDown = (ev: React.KeyboardEvent, state: IState) => {
|
||||||
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
|
||||||
|
@ -62,7 +62,7 @@ const Toolbar: React.FC<IProps> = ({children, ...props}) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
return <RovingTabIndexProvider handleHomeEnd={true} onKeyDown={onKeyDown}>
|
return <RovingTabIndexProvider handleHomeEnd={true} onKeyDown={onKeyDown}>
|
||||||
{({onKeyDownHandler}) => <div {...props} onKeyDown={onKeyDownHandler} role="toolbar">
|
{({ onKeyDownHandler }) => <div {...props} onKeyDown={onKeyDownHandler} role="toolbar">
|
||||||
{ children }
|
{ children }
|
||||||
</div>}
|
</div>}
|
||||||
</RovingTabIndexProvider>;
|
</RovingTabIndexProvider>;
|
||||||
|
|
|
@ -23,7 +23,7 @@ interface IProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Semantic component for representing a role=group for grouping menu radios/checkboxes
|
// Semantic component for representing a role=group for grouping menu radios/checkboxes
|
||||||
export const MenuGroup: React.FC<IProps> = ({children, label, ...props}) => {
|
export const MenuGroup: React.FC<IProps> = ({ children, label, ...props }) => {
|
||||||
return <div {...props} role="group" aria-label={label}>
|
return <div {...props} role="group" aria-label={label}>
|
||||||
{ children }
|
{ children }
|
||||||
</div>;
|
</div>;
|
||||||
|
|
|
@ -27,7 +27,7 @@ interface IProps extends React.ComponentProps<typeof AccessibleButton> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Semantic component for representing a role=menuitem
|
// Semantic component for representing a role=menuitem
|
||||||
export const MenuItem: React.FC<IProps> = ({children, label, tooltip, ...props}) => {
|
export const MenuItem: React.FC<IProps> = ({ children, label, tooltip, ...props }) => {
|
||||||
const ariaLabel = props["aria-label"] || label;
|
const ariaLabel = props["aria-label"] || label;
|
||||||
|
|
||||||
if (tooltip) {
|
if (tooltip) {
|
||||||
|
|
|
@ -26,7 +26,7 @@ interface IProps extends React.ComponentProps<typeof AccessibleButton> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Semantic component for representing a role=menuitemcheckbox
|
// Semantic component for representing a role=menuitemcheckbox
|
||||||
export const MenuItemCheckbox: React.FC<IProps> = ({children, label, active, disabled, ...props}) => {
|
export const MenuItemCheckbox: React.FC<IProps> = ({ children, label, active, disabled, ...props }) => {
|
||||||
return (
|
return (
|
||||||
<AccessibleButton
|
<AccessibleButton
|
||||||
{...props}
|
{...props}
|
||||||
|
|
|
@ -26,7 +26,7 @@ interface IProps extends React.ComponentProps<typeof AccessibleButton> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Semantic component for representing a role=menuitemradio
|
// Semantic component for representing a role=menuitemradio
|
||||||
export const MenuItemRadio: React.FC<IProps> = ({children, label, active, disabled, ...props}) => {
|
export const MenuItemRadio: React.FC<IProps> = ({ children, label, active, disabled, ...props }) => {
|
||||||
return (
|
return (
|
||||||
<AccessibleButton
|
<AccessibleButton
|
||||||
{...props}
|
{...props}
|
||||||
|
|
|
@ -18,7 +18,7 @@ limitations under the License.
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import {Key} from "../../Keyboard";
|
import { Key } from "../../Keyboard";
|
||||||
import StyledCheckbox from "../../components/views/elements/StyledCheckbox";
|
import StyledCheckbox from "../../components/views/elements/StyledCheckbox";
|
||||||
|
|
||||||
interface IProps extends React.ComponentProps<typeof StyledCheckbox> {
|
interface IProps extends React.ComponentProps<typeof StyledCheckbox> {
|
||||||
|
@ -28,7 +28,7 @@ interface IProps extends React.ComponentProps<typeof StyledCheckbox> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Semantic component for representing a styled role=menuitemcheckbox
|
// Semantic component for representing a styled role=menuitemcheckbox
|
||||||
export const StyledMenuItemCheckbox: React.FC<IProps> = ({children, label, onChange, onClose, ...props}) => {
|
export const StyledMenuItemCheckbox: React.FC<IProps> = ({ children, label, onChange, onClose, ...props }) => {
|
||||||
const onKeyDown = (e: React.KeyboardEvent) => {
|
const onKeyDown = (e: React.KeyboardEvent) => {
|
||||||
if (e.key === Key.ENTER || e.key === Key.SPACE) {
|
if (e.key === Key.ENTER || e.key === Key.SPACE) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
|
|
@ -18,7 +18,7 @@ limitations under the License.
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import {Key} from "../../Keyboard";
|
import { Key } from "../../Keyboard";
|
||||||
import StyledRadioButton from "../../components/views/elements/StyledRadioButton";
|
import StyledRadioButton from "../../components/views/elements/StyledRadioButton";
|
||||||
|
|
||||||
interface IProps extends React.ComponentProps<typeof StyledRadioButton> {
|
interface IProps extends React.ComponentProps<typeof StyledRadioButton> {
|
||||||
|
@ -28,7 +28,7 @@ interface IProps extends React.ComponentProps<typeof StyledRadioButton> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Semantic component for representing a styled role=menuitemradio
|
// Semantic component for representing a styled role=menuitemradio
|
||||||
export const StyledMenuItemRadio: React.FC<IProps> = ({children, label, onChange, onClose, ...props}) => {
|
export const StyledMenuItemRadio: React.FC<IProps> = ({ children, label, onChange, onClose, ...props }) => {
|
||||||
const onKeyDown = (e: React.KeyboardEvent) => {
|
const onKeyDown = (e: React.KeyboardEvent) => {
|
||||||
if (e.key === Key.ENTER || e.key === Key.SPACE) {
|
if (e.key === Key.ENTER || e.key === Key.SPACE) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
|
|
@ -17,15 +17,15 @@ limitations under the License.
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import AccessibleButton from "../../components/views/elements/AccessibleButton";
|
import AccessibleButton from "../../components/views/elements/AccessibleButton";
|
||||||
import {useRovingTabIndex} from "../RovingTabIndex";
|
import { useRovingTabIndex } from "../RovingTabIndex";
|
||||||
import {Ref} from "./types";
|
import { Ref } from "./types";
|
||||||
|
|
||||||
interface IProps extends Omit<React.ComponentProps<typeof AccessibleButton>, "onFocus" | "inputRef" | "tabIndex"> {
|
interface IProps extends Omit<React.ComponentProps<typeof AccessibleButton>, "onFocus" | "inputRef" | "tabIndex"> {
|
||||||
inputRef?: Ref;
|
inputRef?: Ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wrapper to allow use of useRovingTabIndex for simple AccessibleButtons outside of React Functional Components.
|
// Wrapper to allow use of useRovingTabIndex for simple AccessibleButtons outside of React Functional Components.
|
||||||
export const RovingAccessibleButton: React.FC<IProps> = ({inputRef, ...props}) => {
|
export const RovingAccessibleButton: React.FC<IProps> = ({ inputRef, ...props }) => {
|
||||||
const [onFocus, isActive, ref] = useRovingTabIndex(inputRef);
|
const [onFocus, isActive, ref] = useRovingTabIndex(inputRef);
|
||||||
return <AccessibleButton {...props} onFocus={onFocus} inputRef={ref} tabIndex={isActive ? 0 : -1} />;
|
return <AccessibleButton {...props} onFocus={onFocus} inputRef={ref} tabIndex={isActive ? 0 : -1} />;
|
||||||
};
|
};
|
||||||
|
|
|
@ -17,8 +17,8 @@ limitations under the License.
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import AccessibleTooltipButton from "../../components/views/elements/AccessibleTooltipButton";
|
import AccessibleTooltipButton from "../../components/views/elements/AccessibleTooltipButton";
|
||||||
import {useRovingTabIndex} from "../RovingTabIndex";
|
import { useRovingTabIndex } from "../RovingTabIndex";
|
||||||
import {Ref} from "./types";
|
import { Ref } from "./types";
|
||||||
|
|
||||||
type ATBProps = React.ComponentProps<typeof AccessibleTooltipButton>;
|
type ATBProps = React.ComponentProps<typeof AccessibleTooltipButton>;
|
||||||
interface IProps extends Omit<ATBProps, "onFocus" | "inputRef" | "tabIndex"> {
|
interface IProps extends Omit<ATBProps, "onFocus" | "inputRef" | "tabIndex"> {
|
||||||
|
@ -26,7 +26,7 @@ interface IProps extends Omit<ATBProps, "onFocus" | "inputRef" | "tabIndex"> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wrapper to allow use of useRovingTabIndex for simple AccessibleTooltipButtons outside of React Functional Components.
|
// Wrapper to allow use of useRovingTabIndex for simple AccessibleTooltipButtons outside of React Functional Components.
|
||||||
export const RovingAccessibleTooltipButton: React.FC<IProps> = ({inputRef, ...props}) => {
|
export const RovingAccessibleTooltipButton: React.FC<IProps> = ({ inputRef, ...props }) => {
|
||||||
const [onFocus, isActive, ref] = useRovingTabIndex(inputRef);
|
const [onFocus, isActive, ref] = useRovingTabIndex(inputRef);
|
||||||
return <AccessibleTooltipButton {...props} onFocus={onFocus} inputRef={ref} tabIndex={isActive ? 0 : -1} />;
|
return <AccessibleTooltipButton {...props} onFocus={onFocus} inputRef={ref} tabIndex={isActive ? 0 : -1} />;
|
||||||
};
|
};
|
||||||
|
|
|
@ -16,8 +16,8 @@ limitations under the License.
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import {useRovingTabIndex} from "../RovingTabIndex";
|
import { useRovingTabIndex } from "../RovingTabIndex";
|
||||||
import {FocusHandler, Ref} from "./types";
|
import { FocusHandler, Ref } from "./types";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
inputRef?: Ref;
|
inputRef?: Ref;
|
||||||
|
@ -29,7 +29,7 @@ interface IProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wrapper to allow use of useRovingTabIndex outside of React Functional Components.
|
// Wrapper to allow use of useRovingTabIndex outside of React Functional Components.
|
||||||
export const RovingTabIndexWrapper: React.FC<IProps> = ({children, inputRef}) => {
|
export const RovingTabIndexWrapper: React.FC<IProps> = ({ children, inputRef }) => {
|
||||||
const [onFocus, isActive, ref] = useRovingTabIndex(inputRef);
|
const [onFocus, isActive, ref] = useRovingTabIndex(inputRef);
|
||||||
return children({onFocus, isActive, ref});
|
return children({ onFocus, isActive, ref });
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {RefObject} from "react";
|
import { RefObject } from "react";
|
||||||
|
|
||||||
export type Ref = RefObject<HTMLElement>;
|
export type Ref = RefObject<HTMLElement>;
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ import { Room } from "matrix-js-sdk/src/models/room";
|
||||||
import { EventTimeline } from "matrix-js-sdk/src/models/event-timeline";
|
import { EventTimeline } from "matrix-js-sdk/src/models/event-timeline";
|
||||||
|
|
||||||
import dis from "../dispatcher/dispatcher";
|
import dis from "../dispatcher/dispatcher";
|
||||||
import {ActionPayload} from "../dispatcher/payloads";
|
import { ActionPayload } from "../dispatcher/payloads";
|
||||||
|
|
||||||
// TODO: migrate from sync_state to MatrixActions.sync so that more js-sdk events
|
// TODO: migrate from sync_state to MatrixActions.sync so that more js-sdk events
|
||||||
// become dispatches in the same place.
|
// become dispatches in the same place.
|
||||||
|
|
|
@ -112,7 +112,7 @@ export default class RoomListActions {
|
||||||
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||||
console.error("Failed to remove tag " + oldTag + " from room: " + err);
|
console.error("Failed to remove tag " + oldTag + " from room: " + err);
|
||||||
Modal.createTrackedDialog('Failed to remove tag from room', '', ErrorDialog, {
|
Modal.createTrackedDialog('Failed to remove tag from room', '', ErrorDialog, {
|
||||||
title: _t('Failed to remove tag %(tagName)s from room', {tagName: oldTag}),
|
title: _t('Failed to remove tag %(tagName)s from room', { tagName: oldTag }),
|
||||||
description: ((err && err.message) ? err.message : _t('Operation failed')),
|
description: ((err && err.message) ? err.message : _t('Operation failed')),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -132,7 +132,7 @@ export default class RoomListActions {
|
||||||
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||||
console.error("Failed to add tag " + newTag + " to room: " + err);
|
console.error("Failed to add tag " + newTag + " to room: " + err);
|
||||||
Modal.createTrackedDialog('Failed to add tag to room', '', ErrorDialog, {
|
Modal.createTrackedDialog('Failed to add tag to room', '', ErrorDialog, {
|
||||||
title: _t('Failed to add tag %(tagName)s to room', {tagName: newTag}),
|
title: _t('Failed to add tag %(tagName)s to room', { tagName: newTag }),
|
||||||
description: ((err && err.message) ? err.message : _t('Operation failed')),
|
description: ((err && err.message) ? err.message : _t('Operation failed')),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -53,11 +53,11 @@ export default class TagOrderActions {
|
||||||
Analytics.trackEvent('TagOrderActions', 'commitTagOrdering');
|
Analytics.trackEvent('TagOrderActions', 'commitTagOrdering');
|
||||||
return matrixClient.setAccountData(
|
return matrixClient.setAccountData(
|
||||||
'im.vector.web.tag_ordering',
|
'im.vector.web.tag_ordering',
|
||||||
{tags, removedTags, _storeId: storeId},
|
{ tags, removedTags, _storeId: storeId },
|
||||||
);
|
);
|
||||||
}, () => {
|
}, () => {
|
||||||
// For an optimistic update
|
// For an optimistic update
|
||||||
return {tags, removedTags};
|
return { tags, removedTags };
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,11 +100,11 @@ export default class TagOrderActions {
|
||||||
Analytics.trackEvent('TagOrderActions', 'removeTag');
|
Analytics.trackEvent('TagOrderActions', 'removeTag');
|
||||||
return matrixClient.setAccountData(
|
return matrixClient.setAccountData(
|
||||||
'im.vector.web.tag_ordering',
|
'im.vector.web.tag_ordering',
|
||||||
{tags, removedTags, _storeId: storeId},
|
{ tags, removedTags, _storeId: storeId },
|
||||||
);
|
);
|
||||||
}, () => {
|
}, () => {
|
||||||
// For an optimistic update
|
// For an optimistic update
|
||||||
return {removedTags};
|
return { removedTags };
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,9 +51,9 @@ export function asyncAction(id: string, fn: () => Promise<any>, pendingFn: () =>
|
||||||
request: typeof pendingFn === 'function' ? pendingFn() : undefined,
|
request: typeof pendingFn === 'function' ? pendingFn() : undefined,
|
||||||
});
|
});
|
||||||
fn().then((result) => {
|
fn().then((result) => {
|
||||||
dispatch({action: id + '.success', result});
|
dispatch({ action: id + '.success', result });
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
dispatch({action: id + '.failure', err});
|
dispatch({ action: id + '.failure', err });
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
return new AsyncActionPayload(helper);
|
return new AsyncActionPayload(helper);
|
||||||
|
|
|
@ -22,8 +22,8 @@ import { _t } from '../../../../languageHandler';
|
||||||
|
|
||||||
import SettingsStore from "../../../../settings/SettingsStore";
|
import SettingsStore from "../../../../settings/SettingsStore";
|
||||||
import EventIndexPeg from "../../../../indexing/EventIndexPeg";
|
import EventIndexPeg from "../../../../indexing/EventIndexPeg";
|
||||||
import {Action} from "../../../../dispatcher/actions";
|
import { Action } from "../../../../dispatcher/actions";
|
||||||
import {SettingLevel} from "../../../../settings/SettingLevel";
|
import { SettingLevel } from "../../../../settings/SettingLevel";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allows the user to disable the Event Index.
|
* Allows the user to disable the Event Index.
|
||||||
|
|
|
@ -21,9 +21,9 @@ import SdkConfig from '../../../../SdkConfig';
|
||||||
import SettingsStore from "../../../../settings/SettingsStore";
|
import SettingsStore from "../../../../settings/SettingsStore";
|
||||||
|
|
||||||
import Modal from '../../../../Modal';
|
import Modal from '../../../../Modal';
|
||||||
import {formatBytes, formatCountLong} from "../../../../utils/FormattingUtils";
|
import { formatBytes, formatCountLong } from "../../../../utils/FormattingUtils";
|
||||||
import EventIndexPeg from "../../../../indexing/EventIndexPeg";
|
import EventIndexPeg from "../../../../indexing/EventIndexPeg";
|
||||||
import {SettingLevel} from "../../../../settings/SettingLevel";
|
import { SettingLevel } from "../../../../settings/SettingLevel";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
onFinished: (confirmed: boolean) => void;
|
onFinished: (confirmed: boolean) => void;
|
||||||
|
@ -139,7 +139,7 @@ export default class ManageEventIndexDialog extends React.Component<IProps, ISta
|
||||||
};
|
};
|
||||||
|
|
||||||
private onCrawlerSleepTimeChange = (e) => {
|
private onCrawlerSleepTimeChange = (e) => {
|
||||||
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);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -15,15 +15,15 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, {createRef} from 'react';
|
import React, { createRef } from 'react';
|
||||||
import FileSaver from 'file-saver';
|
import FileSaver from 'file-saver';
|
||||||
import * as sdk from '../../../../index';
|
import * as sdk from '../../../../index';
|
||||||
import {MatrixClientPeg} from '../../../../MatrixClientPeg';
|
import { MatrixClientPeg } from '../../../../MatrixClientPeg';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import {_t, _td} from '../../../../languageHandler';
|
import { _t, _td } from '../../../../languageHandler';
|
||||||
import { accessSecretStorage } from '../../../../SecurityManager';
|
import { accessSecretStorage } from '../../../../SecurityManager';
|
||||||
import AccessibleButton from "../../../../components/views/elements/AccessibleButton";
|
import AccessibleButton from "../../../../components/views/elements/AccessibleButton";
|
||||||
import {copyNode} from "../../../../utils/strings";
|
import { copyNode } from "../../../../utils/strings";
|
||||||
import PassphraseField from "../../../../components/views/auth/PassphraseField";
|
import PassphraseField from "../../../../components/views/auth/PassphraseField";
|
||||||
|
|
||||||
const PHASE_PASSPHRASE = 0;
|
const PHASE_PASSPHRASE = 0;
|
||||||
|
@ -152,11 +152,11 @@ export default class CreateKeyBackupDialog extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
_onOptOutClick = () => {
|
_onOptOutClick = () => {
|
||||||
this.setState({phase: PHASE_OPTOUT_CONFIRM});
|
this.setState({ phase: PHASE_OPTOUT_CONFIRM });
|
||||||
}
|
}
|
||||||
|
|
||||||
_onSetUpClick = () => {
|
_onSetUpClick = () => {
|
||||||
this.setState({phase: PHASE_PASSPHRASE});
|
this.setState({ phase: PHASE_PASSPHRASE });
|
||||||
}
|
}
|
||||||
|
|
||||||
_onSkipPassPhraseClick = async () => {
|
_onSkipPassPhraseClick = async () => {
|
||||||
|
@ -179,7 +179,7 @@ export default class CreateKeyBackupDialog extends React.PureComponent {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setState({phase: PHASE_PASSPHRASE_CONFIRM});
|
this.setState({ phase: PHASE_PASSPHRASE_CONFIRM });
|
||||||
};
|
};
|
||||||
|
|
||||||
_onPassPhraseConfirmNextClick = async (e) => {
|
_onPassPhraseConfirmNextClick = async (e) => {
|
||||||
|
@ -370,21 +370,21 @@ export default class CreateKeyBackupDialog extends React.PureComponent {
|
||||||
if (this.state.copied) {
|
if (this.state.copied) {
|
||||||
introText = _t(
|
introText = _t(
|
||||||
"Your Security Key has been <b>copied to your clipboard</b>, paste it to:",
|
"Your Security Key has been <b>copied to your clipboard</b>, paste it to:",
|
||||||
{}, {b: s => <b>{s}</b>},
|
{}, { b: s => <b>{s}</b> },
|
||||||
);
|
);
|
||||||
} else if (this.state.downloaded) {
|
} else if (this.state.downloaded) {
|
||||||
introText = _t(
|
introText = _t(
|
||||||
"Your Security Key is in your <b>Downloads</b> folder.",
|
"Your Security Key is in your <b>Downloads</b> folder.",
|
||||||
{}, {b: s => <b>{s}</b>},
|
{}, { b: s => <b>{s}</b> },
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
|
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
|
||||||
return <div>
|
return <div>
|
||||||
{introText}
|
{introText}
|
||||||
<ul>
|
<ul>
|
||||||
<li>{_t("<b>Print it</b> and store it somewhere safe", {}, {b: s => <b>{s}</b>})}</li>
|
<li>{_t("<b>Print it</b> and store it somewhere safe", {}, { b: s => <b>{s}</b> })}</li>
|
||||||
<li>{_t("<b>Save it</b> on a USB key or backup drive", {}, {b: s => <b>{s}</b>})}</li>
|
<li>{_t("<b>Save it</b> on a USB key or backup drive", {}, { b: s => <b>{s}</b> })}</li>
|
||||||
<li>{_t("<b>Copy it</b> to your personal cloud storage", {}, {b: s => <b>{s}</b>})}</li>
|
<li>{_t("<b>Copy it</b> to your personal cloud storage", {}, { b: s => <b>{s}</b> })}</li>
|
||||||
</ul>
|
</ul>
|
||||||
<DialogButtons primaryButton={_t("Continue")}
|
<DialogButtons primaryButton={_t("Continue")}
|
||||||
onPrimaryButtonClick={this._createBackup}
|
onPrimaryButtonClick={this._createBackup}
|
||||||
|
|
|
@ -15,16 +15,16 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, {createRef} from 'react';
|
import React, { createRef } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import * as sdk from '../../../../index';
|
import * as sdk from '../../../../index';
|
||||||
import {MatrixClientPeg} from '../../../../MatrixClientPeg';
|
import { MatrixClientPeg } from '../../../../MatrixClientPeg';
|
||||||
import FileSaver from 'file-saver';
|
import FileSaver from 'file-saver';
|
||||||
import {_t, _td} from '../../../../languageHandler';
|
import { _t, _td } from '../../../../languageHandler';
|
||||||
import Modal from '../../../../Modal';
|
import Modal from '../../../../Modal';
|
||||||
import { promptForBackupPassphrase } from '../../../../SecurityManager';
|
import { promptForBackupPassphrase } from '../../../../SecurityManager';
|
||||||
import {copyNode} from "../../../../utils/strings";
|
import { copyNode } from "../../../../utils/strings";
|
||||||
import {SSOAuthEntry} from "../../../../components/views/auth/InteractiveAuthEntryComponents";
|
import { SSOAuthEntry } from "../../../../components/views/auth/InteractiveAuthEntryComponents";
|
||||||
import PassphraseField from "../../../../components/views/auth/PassphraseField";
|
import PassphraseField from "../../../../components/views/auth/PassphraseField";
|
||||||
import StyledRadioButton from '../../../../components/views/elements/StyledRadioButton';
|
import StyledRadioButton from '../../../../components/views/elements/StyledRadioButton';
|
||||||
import AccessibleButton from "../../../../components/views/elements/AccessibleButton";
|
import AccessibleButton from "../../../../components/views/elements/AccessibleButton";
|
||||||
|
@ -155,7 +155,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
|
||||||
backupSigStatus,
|
backupSigStatus,
|
||||||
};
|
};
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.setState({phase: PHASE_LOADERROR});
|
this.setState({ phase: PHASE_LOADERROR });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -385,7 +385,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
_onLoadRetryClick = () => {
|
_onLoadRetryClick = () => {
|
||||||
this.setState({phase: PHASE_LOADING});
|
this.setState({ phase: PHASE_LOADING });
|
||||||
this._fetchBackupInfo();
|
this._fetchBackupInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -394,11 +394,11 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
_onCancelClick = () => {
|
_onCancelClick = () => {
|
||||||
this.setState({phase: PHASE_CONFIRM_SKIP});
|
this.setState({ phase: PHASE_CONFIRM_SKIP });
|
||||||
}
|
}
|
||||||
|
|
||||||
_onGoBackClick = () => {
|
_onGoBackClick = () => {
|
||||||
this.setState({phase: PHASE_CHOOSE_KEY_PASSPHRASE});
|
this.setState({ phase: PHASE_CHOOSE_KEY_PASSPHRASE });
|
||||||
}
|
}
|
||||||
|
|
||||||
_onPassPhraseNextClick = async (e) => {
|
_onPassPhraseNextClick = async (e) => {
|
||||||
|
@ -412,7 +412,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setState({phase: PHASE_PASSPHRASE_CONFIRM});
|
this.setState({ phase: PHASE_PASSPHRASE_CONFIRM });
|
||||||
};
|
};
|
||||||
|
|
||||||
_onPassPhraseConfirmNextClick = async (e) => {
|
_onPassPhraseConfirmNextClick = async (e) => {
|
||||||
|
|
|
@ -15,7 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import FileSaver from 'file-saver';
|
import FileSaver from 'file-saver';
|
||||||
import React, {createRef} from 'react';
|
import React, { createRef } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { _t } from '../../../../languageHandler';
|
import { _t } from '../../../../languageHandler';
|
||||||
|
|
||||||
|
@ -55,11 +55,11 @@ export default class ExportE2eKeysDialog extends React.Component {
|
||||||
|
|
||||||
const passphrase = this._passphrase1.current.value;
|
const passphrase = this._passphrase1.current.value;
|
||||||
if (passphrase !== this._passphrase2.current.value) {
|
if (passphrase !== this._passphrase2.current.value) {
|
||||||
this.setState({errStr: _t('Passphrases must match')});
|
this.setState({ errStr: _t('Passphrases must match') });
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!passphrase) {
|
if (!passphrase) {
|
||||||
this.setState({errStr: _t('Passphrase must not be empty')});
|
this.setState({ errStr: _t('Passphrase must not be empty') });
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, {createRef} from 'react';
|
import React, { createRef } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import { MatrixClient } from 'matrix-js-sdk/src/client';
|
import { MatrixClient } from 'matrix-js-sdk/src/client';
|
||||||
|
|
|
@ -18,12 +18,12 @@ limitations under the License.
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import * as sdk from "../../../../index";
|
import * as sdk from "../../../../index";
|
||||||
import {MatrixClientPeg} from '../../../../MatrixClientPeg';
|
import { MatrixClientPeg } from '../../../../MatrixClientPeg';
|
||||||
import dis from "../../../../dispatcher/dispatcher";
|
import dis from "../../../../dispatcher/dispatcher";
|
||||||
import { _t } from "../../../../languageHandler";
|
import { _t } from "../../../../languageHandler";
|
||||||
import Modal from "../../../../Modal";
|
import Modal from "../../../../Modal";
|
||||||
import RestoreKeyBackupDialog from "../../../../components/views/dialogs/security/RestoreKeyBackupDialog";
|
import RestoreKeyBackupDialog from "../../../../components/views/dialogs/security/RestoreKeyBackupDialog";
|
||||||
import {Action} from "../../../../dispatcher/actions";
|
import { Action } from "../../../../dispatcher/actions";
|
||||||
|
|
||||||
export default class NewRecoveryMethodDialog extends React.PureComponent {
|
export default class NewRecoveryMethodDialog extends React.PureComponent {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
|
|
@ -21,7 +21,7 @@ import * as sdk from "../../../../index";
|
||||||
import dis from "../../../../dispatcher/dispatcher";
|
import dis from "../../../../dispatcher/dispatcher";
|
||||||
import { _t } from "../../../../languageHandler";
|
import { _t } from "../../../../languageHandler";
|
||||||
import Modal from "../../../../Modal";
|
import Modal from "../../../../Modal";
|
||||||
import {Action} from "../../../../dispatcher/actions";
|
import { Action } from "../../../../dispatcher/actions";
|
||||||
|
|
||||||
export default class RecoveryMethodRemovedDialog extends React.PureComponent {
|
export default class RecoveryMethodRemovedDialog extends React.PureComponent {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
|
|
@ -17,7 +17,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import type {ICompletion, ISelectionRange} from './Autocompleter';
|
import type { ICompletion, ISelectionRange } from './Autocompleter';
|
||||||
|
|
||||||
export interface ICommand {
|
export interface ICommand {
|
||||||
command: string | null;
|
command: string | null;
|
||||||
|
|
|
@ -26,7 +26,7 @@ import UserProvider from './UserProvider';
|
||||||
import EmojiProvider from './EmojiProvider';
|
import EmojiProvider from './EmojiProvider';
|
||||||
import NotifProvider from './NotifProvider';
|
import NotifProvider from './NotifProvider';
|
||||||
import { timeout } from "../utils/promise";
|
import { timeout } from "../utils/promise";
|
||||||
import AutocompleteProvider, {ICommand} from "./AutocompleteProvider";
|
import AutocompleteProvider, { ICommand } from "./AutocompleteProvider";
|
||||||
import SettingsStore from "../settings/SettingsStore";
|
import SettingsStore from "../settings/SettingsStore";
|
||||||
import SpaceProvider from "./SpaceProvider";
|
import SpaceProvider from "./SpaceProvider";
|
||||||
|
|
||||||
|
|
|
@ -18,12 +18,12 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {_t} from '../languageHandler';
|
import { _t } from '../languageHandler';
|
||||||
import AutocompleteProvider from './AutocompleteProvider';
|
import AutocompleteProvider from './AutocompleteProvider';
|
||||||
import QueryMatcher from './QueryMatcher';
|
import QueryMatcher from './QueryMatcher';
|
||||||
import {TextualCompletion} from './Components';
|
import { TextualCompletion } from './Components';
|
||||||
import {ICompletion, ISelectionRange} from "./Autocompleter";
|
import { ICompletion, ISelectionRange } from "./Autocompleter";
|
||||||
import {Command, Commands, CommandMap} from '../SlashCommands';
|
import { Command, Commands, CommandMap } from '../SlashCommands';
|
||||||
|
|
||||||
const COMMAND_RE = /(^\/\w*)(?: .*)?/g;
|
const COMMAND_RE = /(^\/\w*)(?: .*)?/g;
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ export default class CommandProvider extends AutocompleteProvider {
|
||||||
super(COMMAND_RE);
|
super(COMMAND_RE);
|
||||||
this.matcher = new QueryMatcher(Commands, {
|
this.matcher = new QueryMatcher(Commands, {
|
||||||
keys: ['command', 'args', 'description'],
|
keys: ['command', 'args', 'description'],
|
||||||
funcs: [({aliases}) => aliases.join(" ")], // aliases
|
funcs: [({ aliases }) => aliases.join(" ")], // aliases
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ export default class CommandProvider extends AutocompleteProvider {
|
||||||
force?: boolean,
|
force?: boolean,
|
||||||
limit = -1,
|
limit = -1,
|
||||||
): Promise<ICompletion[]> {
|
): Promise<ICompletion[]> {
|
||||||
const {command, range} = this.getCurrentCommand(query, selection);
|
const { command, range } = this.getCurrentCommand(query, selection);
|
||||||
if (!command) return [];
|
if (!command) return [];
|
||||||
|
|
||||||
let matches = [];
|
let matches = [];
|
||||||
|
@ -68,7 +68,6 @@ export default class CommandProvider extends AutocompleteProvider {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return matches.filter(cmd => cmd.isEnabled()).map((result) => {
|
return matches.filter(cmd => cmd.isEnabled()).map((result) => {
|
||||||
let completion = result.getCommand() + ' ';
|
let completion = result.getCommand() + ' ';
|
||||||
const usedAlias = result.aliases.find(alias => `/${alias}` === command[1]);
|
const usedAlias = result.aliases.find(alias => `/${alias}` === command[1]);
|
||||||
|
|
|
@ -19,15 +19,15 @@ import React from 'react';
|
||||||
import Group from "matrix-js-sdk/src/models/group";
|
import Group from "matrix-js-sdk/src/models/group";
|
||||||
import { _t } from '../languageHandler';
|
import { _t } from '../languageHandler';
|
||||||
import AutocompleteProvider from './AutocompleteProvider';
|
import AutocompleteProvider from './AutocompleteProvider';
|
||||||
import {MatrixClientPeg} from '../MatrixClientPeg';
|
import { MatrixClientPeg } from '../MatrixClientPeg';
|
||||||
import QueryMatcher from './QueryMatcher';
|
import QueryMatcher from './QueryMatcher';
|
||||||
import {PillCompletion} from './Components';
|
import { PillCompletion } from './Components';
|
||||||
import * as sdk from '../index';
|
import * as sdk from '../index';
|
||||||
import {sortBy} from "lodash";
|
import { sortBy } from "lodash";
|
||||||
import {makeGroupPermalink} from "../utils/permalinks/Permalinks";
|
import { makeGroupPermalink } from "../utils/permalinks/Permalinks";
|
||||||
import {ICompletion, ISelectionRange} from "./Autocompleter";
|
import { ICompletion, ISelectionRange } from "./Autocompleter";
|
||||||
import FlairStore from "../stores/FlairStore";
|
import FlairStore from "../stores/FlairStore";
|
||||||
import {mediaFromMxc} from "../customisations/Media";
|
import { mediaFromMxc } from "../customisations/Media";
|
||||||
|
|
||||||
const COMMUNITY_REGEX = /\B\+\S*/g;
|
const COMMUNITY_REGEX = /\B\+\S*/g;
|
||||||
|
|
||||||
|
@ -66,11 +66,11 @@ export default class CommunityProvider extends AutocompleteProvider {
|
||||||
|
|
||||||
const cli = MatrixClientPeg.get();
|
const cli = MatrixClientPeg.get();
|
||||||
let completions = [];
|
let completions = [];
|
||||||
const {command, range} = this.getCurrentCommand(query, selection, force);
|
const { command, range } = this.getCurrentCommand(query, selection, force);
|
||||||
if (command) {
|
if (command) {
|
||||||
const joinedGroups = cli.getGroups().filter(({myMembership}) => myMembership === 'join');
|
const joinedGroups = cli.getGroups().filter(({ myMembership }) => myMembership === 'join');
|
||||||
|
|
||||||
const groups = (await Promise.all(joinedGroups.map(async ({groupId}) => {
|
const groups = (await Promise.all(joinedGroups.map(async ({ groupId }) => {
|
||||||
try {
|
try {
|
||||||
return FlairStore.getGroupProfileCached(cli, groupId);
|
return FlairStore.getGroupProfileCached(cli, groupId);
|
||||||
} catch (e) { // if FlairStore failed, fall back to just groupId
|
} catch (e) { // if FlairStore failed, fall back to just groupId
|
||||||
|
@ -90,7 +90,7 @@ export default class CommunityProvider extends AutocompleteProvider {
|
||||||
completions = sortBy(completions, [
|
completions = sortBy(completions, [
|
||||||
(c) => score(matchedString, c.groupId),
|
(c) => score(matchedString, c.groupId),
|
||||||
(c) => c.groupId.length,
|
(c) => c.groupId.length,
|
||||||
]).map(({avatarUrl, groupId, name}) => ({
|
]).map(({ avatarUrl, groupId, name }) => ({
|
||||||
completion: groupId,
|
completion: groupId,
|
||||||
suffix: ' ',
|
suffix: ' ',
|
||||||
type: "community",
|
type: "community",
|
||||||
|
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, {forwardRef} from 'react';
|
import React, { forwardRef } from 'react';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
|
||||||
/* These were earlier stateless functional components but had to be converted
|
/* These were earlier stateless functional components but had to be converted
|
||||||
|
@ -31,7 +31,7 @@ interface ITextualCompletionProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const TextualCompletion = forwardRef<ITextualCompletionProps, any>((props, ref) => {
|
export const TextualCompletion = forwardRef<ITextualCompletionProps, any>((props, ref) => {
|
||||||
const {title, subtitle, description, className, ...restProps} = props;
|
const { title, subtitle, description, className, ...restProps } = props;
|
||||||
return (
|
return (
|
||||||
<div {...restProps}
|
<div {...restProps}
|
||||||
className={classNames('mx_Autocomplete_Completion_block', className)}
|
className={classNames('mx_Autocomplete_Completion_block', className)}
|
||||||
|
@ -50,7 +50,7 @@ interface IPillCompletionProps extends ITextualCompletionProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const PillCompletion = forwardRef<IPillCompletionProps, any>((props, ref) => {
|
export const PillCompletion = forwardRef<IPillCompletionProps, any>((props, ref) => {
|
||||||
const {title, subtitle, description, className, children, ...restProps} = props;
|
const { title, subtitle, description, className, children, ...restProps } = props;
|
||||||
return (
|
return (
|
||||||
<div {...restProps}
|
<div {...restProps}
|
||||||
className={classNames('mx_Autocomplete_Completion_pill', className)}
|
className={classNames('mx_Autocomplete_Completion_pill', className)}
|
||||||
|
|
|
@ -20,8 +20,8 @@ import React from 'react';
|
||||||
import { _t } from '../languageHandler';
|
import { _t } from '../languageHandler';
|
||||||
import AutocompleteProvider from './AutocompleteProvider';
|
import AutocompleteProvider from './AutocompleteProvider';
|
||||||
|
|
||||||
import {TextualCompletion} from './Components';
|
import { TextualCompletion } from './Components';
|
||||||
import {ICompletion, ISelectionRange} from "./Autocompleter";
|
import { ICompletion, ISelectionRange } from "./Autocompleter";
|
||||||
|
|
||||||
const DDG_REGEX = /\/ddg\s+(.+)$/g;
|
const DDG_REGEX = /\/ddg\s+(.+)$/g;
|
||||||
const REFERRER = 'vector';
|
const REFERRER = 'vector';
|
||||||
|
@ -42,7 +42,7 @@ export default class DuckDuckGoProvider extends AutocompleteProvider {
|
||||||
force = false,
|
force = false,
|
||||||
limit = -1,
|
limit = -1,
|
||||||
): Promise<ICompletion[]> {
|
): Promise<ICompletion[]> {
|
||||||
const {command, range} = this.getCurrentCommand(query, selection);
|
const { command, range } = this.getCurrentCommand(query, selection);
|
||||||
if (!query || !command) {
|
if (!query || !command) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,9 +21,9 @@ import React from 'react';
|
||||||
import { _t } from '../languageHandler';
|
import { _t } from '../languageHandler';
|
||||||
import AutocompleteProvider from './AutocompleteProvider';
|
import AutocompleteProvider from './AutocompleteProvider';
|
||||||
import QueryMatcher from './QueryMatcher';
|
import QueryMatcher from './QueryMatcher';
|
||||||
import {PillCompletion} from './Components';
|
import { PillCompletion } from './Components';
|
||||||
import {ICompletion, ISelectionRange} from './Autocompleter';
|
import { ICompletion, ISelectionRange } from './Autocompleter';
|
||||||
import {uniq, sortBy} from 'lodash';
|
import { uniq, sortBy } from 'lodash';
|
||||||
import SettingsStore from "../settings/SettingsStore";
|
import SettingsStore from "../settings/SettingsStore";
|
||||||
import { shortcodeToUnicode } from '../HtmlUtils';
|
import { shortcodeToUnicode } from '../HtmlUtils';
|
||||||
import { EMOJI, IEmoji } from '../emoji';
|
import { EMOJI, IEmoji } from '../emoji';
|
||||||
|
@ -95,7 +95,7 @@ export default class EmojiProvider extends AutocompleteProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
let completions = [];
|
let completions = [];
|
||||||
const {command, range} = this.getCurrentCommand(query, selection);
|
const { command, range } = this.getCurrentCommand(query, selection);
|
||||||
if (command) {
|
if (command) {
|
||||||
const matchedString = command[0];
|
const matchedString = command[0];
|
||||||
completions = this.matcher.match(matchedString, limit);
|
completions = this.matcher.match(matchedString, limit);
|
||||||
|
@ -121,7 +121,7 @@ export default class EmojiProvider extends AutocompleteProvider {
|
||||||
sorters.push((c) => c._orderBy);
|
sorters.push((c) => c._orderBy);
|
||||||
completions = sortBy(uniq(completions), sorters);
|
completions = sortBy(uniq(completions), sorters);
|
||||||
|
|
||||||
completions = completions.map(({shortname}) => {
|
completions = completions.map(({ shortname }) => {
|
||||||
const unicode = shortcodeToUnicode(shortname);
|
const unicode = shortcodeToUnicode(shortname);
|
||||||
return {
|
return {
|
||||||
completion: unicode,
|
completion: unicode,
|
||||||
|
|
|
@ -19,10 +19,10 @@ import { Room } from "matrix-js-sdk/src/models/room";
|
||||||
|
|
||||||
import AutocompleteProvider from './AutocompleteProvider';
|
import AutocompleteProvider from './AutocompleteProvider';
|
||||||
import { _t } from '../languageHandler';
|
import { _t } from '../languageHandler';
|
||||||
import {MatrixClientPeg} from '../MatrixClientPeg';
|
import { MatrixClientPeg } from '../MatrixClientPeg';
|
||||||
import {PillCompletion} from './Components';
|
import { PillCompletion } from './Components';
|
||||||
import * as sdk from '../index';
|
import * as sdk from '../index';
|
||||||
import {ICompletion, ISelectionRange} from "./Autocompleter";
|
import { ICompletion, ISelectionRange } from "./Autocompleter";
|
||||||
|
|
||||||
const AT_ROOM_REGEX = /@\S*/g;
|
const AT_ROOM_REGEX = /@\S*/g;
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ export default class NotifProvider extends AutocompleteProvider {
|
||||||
|
|
||||||
if (!this.room.currentState.mayTriggerNotifOfType('room', client.credentials.userId)) return [];
|
if (!this.room.currentState.mayTriggerNotifOfType('room', client.credentials.userId)) return [];
|
||||||
|
|
||||||
const {command, range} = this.getCurrentCommand(query, selection, force);
|
const { command, range } = this.getCurrentCommand(query, selection, force);
|
||||||
if (command && command[0] && '@room'.startsWith(command[0]) && command[0].length > 1) {
|
if (command && command[0] && '@room'.startsWith(command[0]) && command[0].length > 1) {
|
||||||
return [{
|
return [{
|
||||||
completion: '@room',
|
completion: '@room',
|
||||||
|
|
|
@ -16,8 +16,8 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {at, uniq} from 'lodash';
|
import { at, uniq } from 'lodash';
|
||||||
import {removeHiddenChars} from "matrix-js-sdk/src/utils";
|
import { removeHiddenChars } from "matrix-js-sdk/src/utils";
|
||||||
|
|
||||||
interface IOptions<T extends {}> {
|
interface IOptions<T extends {}> {
|
||||||
keys: Array<string | keyof T>;
|
keys: Array<string | keyof T>;
|
||||||
|
@ -112,7 +112,7 @@ export default class QueryMatcher<T extends Object> {
|
||||||
const index = resultKey.indexOf(query);
|
const index = resultKey.indexOf(query);
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
matches.push(
|
matches.push(
|
||||||
...candidates.map((candidate) => ({index, ...candidate})),
|
...candidates.map((candidate) => ({ index, ...candidate })),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,7 +73,7 @@ export default class RoomProvider extends AutocompleteProvider {
|
||||||
limit = -1,
|
limit = -1,
|
||||||
): Promise<ICompletion[]> {
|
): Promise<ICompletion[]> {
|
||||||
let completions = [];
|
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
|
||||||
let matcherObjects = this.getRooms().reduce((aliases, room) => {
|
let matcherObjects = this.getRooms().reduce((aliases, room) => {
|
||||||
|
|
|
@ -17,7 +17,7 @@ limitations under the License.
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import { _t } from '../languageHandler';
|
import { _t } from '../languageHandler';
|
||||||
import {MatrixClientPeg} from '../MatrixClientPeg';
|
import { MatrixClientPeg } from '../MatrixClientPeg';
|
||||||
import RoomProvider from "./RoomProvider";
|
import RoomProvider from "./RoomProvider";
|
||||||
|
|
||||||
export default class SpaceProvider extends RoomProvider {
|
export default class SpaceProvider extends RoomProvider {
|
||||||
|
|
|
@ -114,7 +114,7 @@ export default class UserProvider extends AutocompleteProvider {
|
||||||
if (!this.users) this._makeUsers();
|
if (!this.users) this._makeUsers();
|
||||||
|
|
||||||
let completions = [];
|
let completions = [];
|
||||||
const {command, range} = this.getCurrentCommand(rawQuery, selection, force);
|
const { command, range } = this.getCurrentCommand(rawQuery, selection, force);
|
||||||
|
|
||||||
if (!command) return completions;
|
if (!command) return completions;
|
||||||
|
|
||||||
|
@ -158,7 +158,7 @@ export default class UserProvider extends AutocompleteProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
const currentUserId = MatrixClientPeg.get().credentials.userId;
|
const currentUserId = MatrixClientPeg.get().credentials.userId;
|
||||||
this.users = this.room.getJoinedMembers().filter(({userId}) => userId !== currentUserId);
|
this.users = this.room.getJoinedMembers().filter(({ userId }) => userId !== currentUserId);
|
||||||
this.users = this.users.concat(this.room.getMembersWithMembership("invite"));
|
this.users = this.users.concat(this.room.getMembersWithMembership("invite"));
|
||||||
|
|
||||||
this.users = sortBy(this.users, (member) => 1E20 - lastSpoken[member.userId] || 1E20);
|
this.users = sortBy(this.users, (member) => 1E20 - lastSpoken[member.userId] || 1E20);
|
||||||
|
|
|
@ -15,12 +15,12 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { HTMLAttributes } from "react";
|
import React, { HTMLAttributes, WheelEvent } from "react";
|
||||||
|
|
||||||
interface IProps extends HTMLAttributes<HTMLDivElement> {
|
interface IProps extends Omit<HTMLAttributes<HTMLDivElement>, "onScroll"> {
|
||||||
className?: string;
|
className?: string;
|
||||||
onScroll?: () => void;
|
onScroll?: (event: Event) => void;
|
||||||
onWheel?: () => void;
|
onWheel?: (event: WheelEvent) => void;
|
||||||
style?: React.CSSProperties
|
style?: React.CSSProperties
|
||||||
tabIndex?: number,
|
tabIndex?: number,
|
||||||
wrappedRef?: (ref: HTMLDivElement) => void;
|
wrappedRef?: (ref: HTMLDivElement) => void;
|
||||||
|
|
|
@ -16,13 +16,13 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, {CSSProperties, RefObject, useRef, useState} from "react";
|
import React, { CSSProperties, RefObject, useRef, useState } from "react";
|
||||||
import ReactDOM from "react-dom";
|
import ReactDOM from "react-dom";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
|
|
||||||
import {Key} from "../../Keyboard";
|
import { Key } from "../../Keyboard";
|
||||||
import {Writeable} from "../../@types/common";
|
import { Writeable } from "../../@types/common";
|
||||||
import {replaceableComponent} from "../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../utils/replaceableComponent";
|
||||||
import UIStore from "../../stores/UIStore";
|
import UIStore from "../../stores/UIStore";
|
||||||
|
|
||||||
// Shamelessly ripped off Modal.js. There's probably a better way
|
// Shamelessly ripped off Modal.js. There's probably a better way
|
||||||
|
@ -371,7 +371,7 @@ export class ContextMenu extends React.PureComponent<IProps, IState> {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={classNames("mx_ContextualMenu_wrapper", this.props.wrapperClassName)}
|
className={classNames("mx_ContextualMenu_wrapper", this.props.wrapperClassName)}
|
||||||
style={{...position, ...wrapperStyle}}
|
style={{ ...position, ...wrapperStyle }}
|
||||||
onKeyDown={this.onKeyDown}
|
onKeyDown={this.onKeyDown}
|
||||||
onContextMenu={this.onContextMenuPreventBubbling}
|
onContextMenu={this.onContextMenuPreventBubbling}
|
||||||
>
|
>
|
||||||
|
@ -399,7 +399,7 @@ export const toRightOf = (elementRect: Pick<DOMRect, "right" | "top" | "height">
|
||||||
const left = elementRect.right + window.pageXOffset + 3;
|
const left = elementRect.right + window.pageXOffset + 3;
|
||||||
let top = elementRect.top + (elementRect.height / 2) + window.pageYOffset;
|
let top = elementRect.top + (elementRect.height / 2) + window.pageYOffset;
|
||||||
top -= chevronOffset + 8; // where 8 is half the height of the chevron
|
top -= chevronOffset + 8; // where 8 is half the height of the chevron
|
||||||
return {left, top, chevronOffset};
|
return { left, top, chevronOffset };
|
||||||
};
|
};
|
||||||
|
|
||||||
// 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,
|
||||||
|
@ -498,15 +498,15 @@ export function createMenu(ElementClass, props) {
|
||||||
|
|
||||||
ReactDOM.render(menu, getOrCreateContainer());
|
ReactDOM.render(menu, getOrCreateContainer());
|
||||||
|
|
||||||
return {close: onFinished};
|
return { close: onFinished };
|
||||||
}
|
}
|
||||||
|
|
||||||
// re-export the semantic helper components for simplicity
|
// re-export the semantic helper components for simplicity
|
||||||
export {ContextMenuButton} from "../../accessibility/context_menu/ContextMenuButton";
|
export { ContextMenuButton } from "../../accessibility/context_menu/ContextMenuButton";
|
||||||
export {ContextMenuTooltipButton} from "../../accessibility/context_menu/ContextMenuTooltipButton";
|
export { ContextMenuTooltipButton } from "../../accessibility/context_menu/ContextMenuTooltipButton";
|
||||||
export {MenuGroup} from "../../accessibility/context_menu/MenuGroup";
|
export { MenuGroup } from "../../accessibility/context_menu/MenuGroup";
|
||||||
export {MenuItem} from "../../accessibility/context_menu/MenuItem";
|
export { MenuItem } from "../../accessibility/context_menu/MenuItem";
|
||||||
export {MenuItemCheckbox} from "../../accessibility/context_menu/MenuItemCheckbox";
|
export { MenuItemCheckbox } from "../../accessibility/context_menu/MenuItemCheckbox";
|
||||||
export {MenuItemRadio} from "../../accessibility/context_menu/MenuItemRadio";
|
export { MenuItemRadio } from "../../accessibility/context_menu/MenuItemRadio";
|
||||||
export {StyledMenuItemCheckbox} from "../../accessibility/context_menu/StyledMenuItemCheckbox";
|
export { StyledMenuItemCheckbox } from "../../accessibility/context_menu/StyledMenuItemCheckbox";
|
||||||
export {StyledMenuItemRadio} from "../../accessibility/context_menu/StyledMenuItemRadio";
|
export { StyledMenuItemRadio } from "../../accessibility/context_menu/StyledMenuItemRadio";
|
||||||
|
|
|
@ -21,7 +21,7 @@ import * as sdk from '../../index';
|
||||||
import dis from '../../dispatcher/dispatcher';
|
import dis from '../../dispatcher/dispatcher';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import * as FormattingUtils from '../../utils/FormattingUtils';
|
import * as FormattingUtils from '../../utils/FormattingUtils';
|
||||||
import {replaceableComponent} from "../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../utils/replaceableComponent";
|
||||||
|
|
||||||
@replaceableComponent("structures.CustomRoomTagPanel")
|
@replaceableComponent("structures.CustomRoomTagPanel")
|
||||||
class CustomRoomTagPanel extends React.Component {
|
class CustomRoomTagPanel extends React.Component {
|
||||||
|
@ -34,7 +34,7 @@ class CustomRoomTagPanel extends React.Component {
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this._tagStoreToken = CustomRoomTagStore.addListener(() => {
|
this._tagStoreToken = CustomRoomTagStore.addListener(() => {
|
||||||
this.setState({tags: CustomRoomTagStore.getSortedTags()});
|
this.setState({ tags: CustomRoomTagStore.getSortedTags() });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,7 +64,7 @@ class CustomRoomTagPanel extends React.Component {
|
||||||
|
|
||||||
class CustomRoomTagTile extends React.Component {
|
class CustomRoomTagTile extends React.Component {
|
||||||
onClick = () => {
|
onClick = () => {
|
||||||
dis.dispatch({action: 'select_custom_room_tag', tag: this.props.tag.name});
|
dis.dispatch({ action: 'select_custom_room_tag', tag: this.props.tag.name });
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|
|
@ -22,7 +22,7 @@ import request from 'browser-request';
|
||||||
import { _t } from '../../languageHandler';
|
import { _t } from '../../languageHandler';
|
||||||
import sanitizeHtml from 'sanitize-html';
|
import sanitizeHtml from 'sanitize-html';
|
||||||
import dis from '../../dispatcher/dispatcher';
|
import dis from '../../dispatcher/dispatcher';
|
||||||
import {MatrixClientPeg} from '../../MatrixClientPeg';
|
import { MatrixClientPeg } from '../../MatrixClientPeg';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import MatrixClientContext from "../../contexts/MatrixClientContext";
|
import MatrixClientContext from "../../contexts/MatrixClientContext";
|
||||||
import AutoHideScrollbar from "./AutoHideScrollbar";
|
import AutoHideScrollbar from "./AutoHideScrollbar";
|
||||||
|
|
|
@ -16,37 +16,49 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
|
|
||||||
import {Filter} from 'matrix-js-sdk/src/filter';
|
import { Filter } from 'matrix-js-sdk/src/filter';
|
||||||
|
import { EventTimelineSet } from "matrix-js-sdk/src/models/event-timeline-set";
|
||||||
|
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
||||||
|
import { Room } from 'matrix-js-sdk/src/models/room';
|
||||||
|
import { TimelineWindow } from 'matrix-js-sdk/src/timeline-window';
|
||||||
|
|
||||||
import * as sdk from '../../index';
|
import * as sdk from '../../index';
|
||||||
import {MatrixClientPeg} from '../../MatrixClientPeg';
|
import { MatrixClientPeg } from '../../MatrixClientPeg';
|
||||||
import EventIndexPeg from "../../indexing/EventIndexPeg";
|
import EventIndexPeg from "../../indexing/EventIndexPeg";
|
||||||
import { _t } from '../../languageHandler';
|
import { _t } from '../../languageHandler';
|
||||||
import BaseCard from "../views/right_panel/BaseCard";
|
import BaseCard from "../views/right_panel/BaseCard";
|
||||||
import {RightPanelPhases} from "../../stores/RightPanelStorePhases";
|
import { RightPanelPhases } from "../../stores/RightPanelStorePhases";
|
||||||
import DesktopBuildsNotice, {WarningKind} from "../views/elements/DesktopBuildsNotice";
|
import DesktopBuildsNotice, { WarningKind } from "../views/elements/DesktopBuildsNotice";
|
||||||
import {replaceableComponent} from "../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../utils/replaceableComponent";
|
||||||
|
|
||||||
|
import ResizeNotifier from '../../utils/ResizeNotifier';
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
roomId: string;
|
||||||
|
onClose: () => void;
|
||||||
|
resizeNotifier: ResizeNotifier
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IState {
|
||||||
|
timelineSet: EventTimelineSet;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Component which shows the filtered file using a TimelinePanel
|
* Component which shows the filtered file using a TimelinePanel
|
||||||
*/
|
*/
|
||||||
@replaceableComponent("structures.FilePanel")
|
@replaceableComponent("structures.FilePanel")
|
||||||
class FilePanel extends React.Component {
|
class FilePanel extends React.Component<IProps, IState> {
|
||||||
static propTypes = {
|
|
||||||
roomId: PropTypes.string.isRequired,
|
|
||||||
onClose: PropTypes.func.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
// This is used to track if a decrypted event was a live event and should be
|
// This is used to track if a decrypted event was a live event and should be
|
||||||
// added to the timeline.
|
// added to the timeline.
|
||||||
decryptingEvents = new Set();
|
private decryptingEvents = new Set<string>();
|
||||||
|
public noRoom: boolean;
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
timelineSet: null,
|
timelineSet: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
onRoomTimeline = (ev, room, toStartOfTimeline, removed, data) => {
|
private onRoomTimeline = (ev: MatrixEvent, room: Room, toStartOfTimeline: true, removed: true, data: any): void => {
|
||||||
if (room?.roomId !== this.props?.roomId) return;
|
if (room?.roomId !== this.props?.roomId) return;
|
||||||
if (toStartOfTimeline || !data || !data.liveEvent || ev.isRedacted()) return;
|
if (toStartOfTimeline || !data || !data.liveEvent || ev.isRedacted()) return;
|
||||||
|
|
||||||
|
@ -60,7 +72,7 @@ class FilePanel extends React.Component {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
onEventDecrypted = (ev, err) => {
|
private onEventDecrypted = (ev: MatrixEvent, err?: any): void => {
|
||||||
if (ev.getRoomId() !== this.props.roomId) return;
|
if (ev.getRoomId() !== this.props.roomId) return;
|
||||||
const eventId = ev.getId();
|
const eventId = ev.getId();
|
||||||
|
|
||||||
|
@ -70,7 +82,7 @@ class FilePanel extends React.Component {
|
||||||
this.addEncryptedLiveEvent(ev);
|
this.addEncryptedLiveEvent(ev);
|
||||||
};
|
};
|
||||||
|
|
||||||
addEncryptedLiveEvent(ev, toStartOfTimeline) {
|
public addEncryptedLiveEvent(ev: MatrixEvent): void {
|
||||||
if (!this.state.timelineSet) return;
|
if (!this.state.timelineSet) return;
|
||||||
|
|
||||||
const timeline = this.state.timelineSet.getLiveTimeline();
|
const timeline = this.state.timelineSet.getLiveTimeline();
|
||||||
|
@ -84,7 +96,7 @@ class FilePanel extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async componentDidMount() {
|
public async componentDidMount(): Promise<void> {
|
||||||
const client = MatrixClientPeg.get();
|
const client = MatrixClientPeg.get();
|
||||||
|
|
||||||
await this.updateTimelineSet(this.props.roomId);
|
await this.updateTimelineSet(this.props.roomId);
|
||||||
|
@ -105,7 +117,7 @@ class FilePanel extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
public componentWillUnmount(): void {
|
||||||
const client = MatrixClientPeg.get();
|
const client = MatrixClientPeg.get();
|
||||||
if (client === null) return;
|
if (client === null) return;
|
||||||
|
|
||||||
|
@ -117,7 +129,7 @@ class FilePanel extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fetchFileEventsServer(room) {
|
public async fetchFileEventsServer(room: Room): Promise<void> {
|
||||||
const client = MatrixClientPeg.get();
|
const client = MatrixClientPeg.get();
|
||||||
|
|
||||||
const filter = new Filter(client.credentials.userId);
|
const filter = new Filter(client.credentials.userId);
|
||||||
|
@ -141,7 +153,7 @@ class FilePanel extends React.Component {
|
||||||
return timelineSet;
|
return timelineSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
onPaginationRequest = (timelineWindow, direction, limit) => {
|
private onPaginationRequest = (timelineWindow: TimelineWindow, direction: string, limit: number): void => {
|
||||||
const client = MatrixClientPeg.get();
|
const client = MatrixClientPeg.get();
|
||||||
const eventIndex = EventIndexPeg.get();
|
const eventIndex = EventIndexPeg.get();
|
||||||
const roomId = this.props.roomId;
|
const roomId = this.props.roomId;
|
||||||
|
@ -159,7 +171,7 @@ class FilePanel extends React.Component {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
async updateTimelineSet(roomId: string) {
|
public async updateTimelineSet(roomId: string): Promise<void> {
|
||||||
const client = MatrixClientPeg.get();
|
const client = MatrixClientPeg.get();
|
||||||
const room = client.getRoom(roomId);
|
const room = client.getRoom(roomId);
|
||||||
const eventIndex = EventIndexPeg.get();
|
const eventIndex = EventIndexPeg.get();
|
||||||
|
@ -195,7 +207,7 @@ class FilePanel extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
public render() {
|
||||||
if (MatrixClientPeg.get().isGuest()) {
|
if (MatrixClientPeg.get().isGuest()) {
|
||||||
return <BaseCard
|
return <BaseCard
|
||||||
className="mx_FilePanel mx_RoomView_messageListWrapper"
|
className="mx_FilePanel mx_RoomView_messageListWrapper"
|
|
@ -16,7 +16,7 @@ limitations under the License.
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import {replaceableComponent} from "../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../utils/replaceableComponent";
|
||||||
|
|
||||||
@replaceableComponent("structures.GenericErrorPage")
|
@replaceableComponent("structures.GenericErrorPage")
|
||||||
export default class GenericErrorPage extends React.PureComponent {
|
export default class GenericErrorPage extends React.PureComponent {
|
||||||
|
|
|
@ -29,7 +29,7 @@ import MatrixClientContext from "../../contexts/MatrixClientContext";
|
||||||
import AutoHideScrollbar from "./AutoHideScrollbar";
|
import AutoHideScrollbar from "./AutoHideScrollbar";
|
||||||
import SettingsStore from "../../settings/SettingsStore";
|
import SettingsStore from "../../settings/SettingsStore";
|
||||||
import UserTagTile from "../views/elements/UserTagTile";
|
import UserTagTile from "../views/elements/UserTagTile";
|
||||||
import {replaceableComponent} from "../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../utils/replaceableComponent";
|
||||||
|
|
||||||
@replaceableComponent("structures.GroupFilterPanel")
|
@replaceableComponent("structures.GroupFilterPanel")
|
||||||
class GroupFilterPanel extends React.Component {
|
class GroupFilterPanel extends React.Component {
|
||||||
|
@ -85,12 +85,12 @@ class GroupFilterPanel extends React.Component {
|
||||||
onClick = e => {
|
onClick = e => {
|
||||||
// only dispatch if its not a no-op
|
// only dispatch if its not a no-op
|
||||||
if (this.state.selectedTags.length > 0) {
|
if (this.state.selectedTags.length > 0) {
|
||||||
dis.dispatch({action: 'deselect_tags'});
|
dis.dispatch({ action: 'deselect_tags' });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
onClearFilterClick = ev => {
|
onClearFilterClick = ev => {
|
||||||
dis.dispatch({action: 'deselect_tags'});
|
dis.dispatch({ action: 'deselect_tags' });
|
||||||
};
|
};
|
||||||
|
|
||||||
renderGlobalIcon() {
|
renderGlobalIcon() {
|
||||||
|
|
|
@ -18,7 +18,7 @@ limitations under the License.
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import {MatrixClientPeg} from '../../MatrixClientPeg';
|
import { MatrixClientPeg } from '../../MatrixClientPeg';
|
||||||
import * as sdk from '../../index';
|
import * as sdk from '../../index';
|
||||||
import dis from '../../dispatcher/dispatcher';
|
import dis from '../../dispatcher/dispatcher';
|
||||||
import { getHostingLink } from '../../utils/HostingLink';
|
import { getHostingLink } from '../../utils/HostingLink';
|
||||||
|
@ -34,13 +34,13 @@ import classnames from 'classnames';
|
||||||
import GroupStore from '../../stores/GroupStore';
|
import GroupStore from '../../stores/GroupStore';
|
||||||
import FlairStore from '../../stores/FlairStore';
|
import FlairStore from '../../stores/FlairStore';
|
||||||
import { showGroupAddRoomDialog } from '../../GroupAddressPicker';
|
import { showGroupAddRoomDialog } from '../../GroupAddressPicker';
|
||||||
import {makeGroupPermalink, makeUserPermalink} from "../../utils/permalinks/Permalinks";
|
import { makeGroupPermalink, makeUserPermalink } from "../../utils/permalinks/Permalinks";
|
||||||
import {Group} from "matrix-js-sdk/src/models/group";
|
import { Group } from "matrix-js-sdk/src/models/group";
|
||||||
import {sleep} from "../../utils/promise";
|
import { sleep } from "../../utils/promise";
|
||||||
import RightPanelStore from "../../stores/RightPanelStore";
|
import RightPanelStore from "../../stores/RightPanelStore";
|
||||||
import AutoHideScrollbar from "./AutoHideScrollbar";
|
import AutoHideScrollbar from "./AutoHideScrollbar";
|
||||||
import {mediaFromMxc} from "../../customisations/Media";
|
import { mediaFromMxc } from "../../customisations/Media";
|
||||||
import {replaceableComponent} from "../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../utils/replaceableComponent";
|
||||||
|
|
||||||
const LONG_DESC_PLACEHOLDER = _td(
|
const LONG_DESC_PLACEHOLDER = _td(
|
||||||
`<h1>HTML for your community's page</h1>
|
`<h1>HTML for your community's page</h1>
|
||||||
|
@ -115,7 +115,7 @@ class CategoryRoomList extends React.Component {
|
||||||
{
|
{
|
||||||
title: _t(
|
title: _t(
|
||||||
"Failed to add the following rooms to the summary of %(groupId)s:",
|
"Failed to add the following rooms to the summary of %(groupId)s:",
|
||||||
{groupId: this.props.groupId},
|
{ groupId: this.props.groupId },
|
||||||
),
|
),
|
||||||
description: errorList.join(", "),
|
description: errorList.join(", "),
|
||||||
},
|
},
|
||||||
|
@ -126,12 +126,11 @@ class CategoryRoomList extends React.Component {
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const TintableSvg = sdk.getComponent("elements.TintableSvg");
|
|
||||||
const addButton = this.props.editing ?
|
const addButton = this.props.editing ?
|
||||||
(<AccessibleButton className="mx_GroupView_featuredThings_addButton"
|
(<AccessibleButton className="mx_GroupView_featuredThings_addButton"
|
||||||
onClick={this.onAddRoomsToSummaryClicked}
|
onClick={this.onAddRoomsToSummaryClicked}
|
||||||
>
|
>
|
||||||
<TintableSvg src={require("../../../res/img/icons-create-room.svg")} width="64" height="64" />
|
<img src={require("../../../res/img/icons-create-room.svg")} width="64" height="64" />
|
||||||
<div className="mx_GroupView_featuredThings_addButton_label">
|
<div className="mx_GroupView_featuredThings_addButton_label">
|
||||||
{ _t('Add a Room') }
|
{ _t('Add a Room') }
|
||||||
</div>
|
</div>
|
||||||
|
@ -195,9 +194,9 @@ class FeaturedRoom extends React.Component {
|
||||||
{
|
{
|
||||||
title: _t(
|
title: _t(
|
||||||
"Failed to remove the room from the summary of %(groupId)s",
|
"Failed to remove the room from the summary of %(groupId)s",
|
||||||
{groupId: this.props.groupId},
|
{ groupId: this.props.groupId },
|
||||||
),
|
),
|
||||||
description: _t("The room '%(roomName)s' could not be removed from the summary.", {roomName}),
|
description: _t("The room '%(roomName)s' could not be removed from the summary.", { roomName }),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -289,7 +288,7 @@ class RoleUserList extends React.Component {
|
||||||
{
|
{
|
||||||
title: _t(
|
title: _t(
|
||||||
"Failed to add the following users to the summary of %(groupId)s:",
|
"Failed to add the following users to the summary of %(groupId)s:",
|
||||||
{groupId: this.props.groupId},
|
{ groupId: this.props.groupId },
|
||||||
),
|
),
|
||||||
description: errorList.join(", "),
|
description: errorList.join(", "),
|
||||||
},
|
},
|
||||||
|
@ -300,10 +299,9 @@ class RoleUserList extends React.Component {
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const TintableSvg = sdk.getComponent("elements.TintableSvg");
|
|
||||||
const addButton = this.props.editing ?
|
const addButton = this.props.editing ?
|
||||||
(<AccessibleButton className="mx_GroupView_featuredThings_addButton" onClick={this.onAddUsersClicked}>
|
(<AccessibleButton className="mx_GroupView_featuredThings_addButton" onClick={this.onAddUsersClicked}>
|
||||||
<TintableSvg src={require("../../../res/img/icons-create-room.svg")} width="64" height="64" />
|
<img src={require("../../../res/img/icons-create-room.svg")} width="64" height="64" />
|
||||||
<div className="mx_GroupView_featuredThings_addButton_label">
|
<div className="mx_GroupView_featuredThings_addButton_label">
|
||||||
{ _t('Add a User') }
|
{ _t('Add a User') }
|
||||||
</div>
|
</div>
|
||||||
|
@ -361,9 +359,12 @@ class FeaturedUser extends React.Component {
|
||||||
{
|
{
|
||||||
title: _t(
|
title: _t(
|
||||||
"Failed to remove a user from the summary of %(groupId)s",
|
"Failed to remove a user from the summary of %(groupId)s",
|
||||||
{groupId: this.props.groupId},
|
{ groupId: this.props.groupId },
|
||||||
|
),
|
||||||
|
description: _t(
|
||||||
|
"The user '%(displayName)s' could not be removed from the summary.",
|
||||||
|
{ displayName },
|
||||||
),
|
),
|
||||||
description: _t("The user '%(displayName)s' could not be removed from the summary.", {displayName}),
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -470,7 +471,7 @@ export default class GroupView extends React.Component {
|
||||||
// Leave settings - the user might have clicked the "Leave" button
|
// Leave settings - the user might have clicked the "Leave" button
|
||||||
this._closeSettings();
|
this._closeSettings();
|
||||||
}
|
}
|
||||||
this.setState({membershipBusy: false});
|
this.setState({ membershipBusy: false });
|
||||||
};
|
};
|
||||||
|
|
||||||
_initGroupStore(groupId, firstInit) {
|
_initGroupStore(groupId, firstInit) {
|
||||||
|
@ -491,7 +492,7 @@ export default class GroupView extends React.Component {
|
||||||
group_id: groupId,
|
group_id: groupId,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
dis.dispatch({action: 'require_registration', screen_after: {screen: `group/${groupId}`}});
|
dis.dispatch({ action: 'require_registration', screen_after: { screen: `group/${groupId}` } });
|
||||||
willDoOnboarding = true;
|
willDoOnboarding = true;
|
||||||
}
|
}
|
||||||
if (stateKey === GroupStore.STATE_KEY.Summary) {
|
if (stateKey === GroupStore.STATE_KEY.Summary) {
|
||||||
|
@ -592,7 +593,7 @@ export default class GroupView extends React.Component {
|
||||||
};
|
};
|
||||||
|
|
||||||
_closeSettings = () => {
|
_closeSettings = () => {
|
||||||
dis.dispatch({action: 'close_settings'});
|
dis.dispatch({ action: 'close_settings' });
|
||||||
};
|
};
|
||||||
|
|
||||||
_onNameChange = (value) => {
|
_onNameChange = (value) => {
|
||||||
|
@ -620,7 +621,7 @@ export default class GroupView extends React.Component {
|
||||||
const file = ev.target.files[0];
|
const file = ev.target.files[0];
|
||||||
if (!file) return;
|
if (!file) return;
|
||||||
|
|
||||||
this.setState({uploadingAvatar: true});
|
this.setState({ uploadingAvatar: true });
|
||||||
this._matrixClient.uploadContent(file).then((url) => {
|
this._matrixClient.uploadContent(file).then((url) => {
|
||||||
const newProfileForm = Object.assign(this.state.profileForm, { avatar_url: url });
|
const newProfileForm = Object.assign(this.state.profileForm, { avatar_url: url });
|
||||||
this.setState({
|
this.setState({
|
||||||
|
@ -632,7 +633,7 @@ export default class GroupView extends React.Component {
|
||||||
avatarChanged: true,
|
avatarChanged: true,
|
||||||
});
|
});
|
||||||
}).catch((e) => {
|
}).catch((e) => {
|
||||||
this.setState({uploadingAvatar: false});
|
this.setState({ uploadingAvatar: false });
|
||||||
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||||
console.error("Failed to upload avatar image", e);
|
console.error("Failed to upload avatar image", e);
|
||||||
Modal.createTrackedDialog('Failed to upload image', '', ErrorDialog, {
|
Modal.createTrackedDialog('Failed to upload image', '', ErrorDialog, {
|
||||||
|
@ -649,7 +650,7 @@ export default class GroupView extends React.Component {
|
||||||
};
|
};
|
||||||
|
|
||||||
_onSaveClick = () => {
|
_onSaveClick = () => {
|
||||||
this.setState({saving: true});
|
this.setState({ saving: true });
|
||||||
const savePromise = this.state.isUserPrivileged ? this._saveGroup() : Promise.resolve();
|
const savePromise = this.state.isUserPrivileged ? this._saveGroup() : Promise.resolve();
|
||||||
savePromise.then((result) => {
|
savePromise.then((result) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
|
@ -688,7 +689,7 @@ export default class GroupView extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
_onAcceptInviteClick = async () => {
|
_onAcceptInviteClick = async () => {
|
||||||
this.setState({membershipBusy: true});
|
this.setState({ membershipBusy: true });
|
||||||
|
|
||||||
// Wait 500ms to prevent flashing. Do this before sending a request otherwise we risk the
|
// Wait 500ms to prevent flashing. Do this before sending a request otherwise we risk the
|
||||||
// spinner disappearing after we have fetched new group data.
|
// spinner disappearing after we have fetched new group data.
|
||||||
|
@ -697,7 +698,7 @@ export default class GroupView extends React.Component {
|
||||||
GroupStore.acceptGroupInvite(this.props.groupId).then(() => {
|
GroupStore.acceptGroupInvite(this.props.groupId).then(() => {
|
||||||
// don't reset membershipBusy here: wait for the membership change to come down the sync
|
// don't reset membershipBusy here: wait for the membership change to come down the sync
|
||||||
}).catch((e) => {
|
}).catch((e) => {
|
||||||
this.setState({membershipBusy: false});
|
this.setState({ membershipBusy: false });
|
||||||
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||||
Modal.createTrackedDialog('Error accepting invite', '', ErrorDialog, {
|
Modal.createTrackedDialog('Error accepting invite', '', ErrorDialog, {
|
||||||
title: _t("Error"),
|
title: _t("Error"),
|
||||||
|
@ -707,7 +708,7 @@ export default class GroupView extends React.Component {
|
||||||
};
|
};
|
||||||
|
|
||||||
_onRejectInviteClick = async () => {
|
_onRejectInviteClick = async () => {
|
||||||
this.setState({membershipBusy: true});
|
this.setState({ membershipBusy: true });
|
||||||
|
|
||||||
// Wait 500ms to prevent flashing. Do this before sending a request otherwise we risk the
|
// Wait 500ms to prevent flashing. Do this before sending a request otherwise we risk the
|
||||||
// spinner disappearing after we have fetched new group data.
|
// spinner disappearing after we have fetched new group data.
|
||||||
|
@ -716,7 +717,7 @@ export default class GroupView extends React.Component {
|
||||||
GroupStore.leaveGroup(this.props.groupId).then(() => {
|
GroupStore.leaveGroup(this.props.groupId).then(() => {
|
||||||
// don't reset membershipBusy here: wait for the membership change to come down the sync
|
// don't reset membershipBusy here: wait for the membership change to come down the sync
|
||||||
}).catch((e) => {
|
}).catch((e) => {
|
||||||
this.setState({membershipBusy: false});
|
this.setState({ membershipBusy: false });
|
||||||
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||||
Modal.createTrackedDialog('Error rejecting invite', '', ErrorDialog, {
|
Modal.createTrackedDialog('Error rejecting invite', '', ErrorDialog, {
|
||||||
title: _t("Error"),
|
title: _t("Error"),
|
||||||
|
@ -727,11 +728,11 @@ export default class GroupView extends React.Component {
|
||||||
|
|
||||||
_onJoinClick = async () => {
|
_onJoinClick = async () => {
|
||||||
if (this._matrixClient.isGuest()) {
|
if (this._matrixClient.isGuest()) {
|
||||||
dis.dispatch({action: 'require_registration', screen_after: {screen: `group/${this.props.groupId}`}});
|
dis.dispatch({ action: 'require_registration', screen_after: { screen: `group/${this.props.groupId}` } });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setState({membershipBusy: true});
|
this.setState({ membershipBusy: true });
|
||||||
|
|
||||||
// Wait 500ms to prevent flashing. Do this before sending a request otherwise we risk the
|
// Wait 500ms to prevent flashing. Do this before sending a request otherwise we risk the
|
||||||
// spinner disappearing after we have fetched new group data.
|
// spinner disappearing after we have fetched new group data.
|
||||||
|
@ -740,7 +741,7 @@ export default class GroupView extends React.Component {
|
||||||
GroupStore.joinGroup(this.props.groupId).then(() => {
|
GroupStore.joinGroup(this.props.groupId).then(() => {
|
||||||
// don't reset membershipBusy here: wait for the membership change to come down the sync
|
// don't reset membershipBusy here: wait for the membership change to come down the sync
|
||||||
}).catch((e) => {
|
}).catch((e) => {
|
||||||
this.setState({membershipBusy: false});
|
this.setState({ membershipBusy: false });
|
||||||
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||||
Modal.createTrackedDialog('Error joining room', '', ErrorDialog, {
|
Modal.createTrackedDialog('Error joining room', '', ErrorDialog, {
|
||||||
title: _t("Error"),
|
title: _t("Error"),
|
||||||
|
@ -773,7 +774,7 @@ export default class GroupView extends React.Component {
|
||||||
title: _t("Leave Community"),
|
title: _t("Leave Community"),
|
||||||
description: (
|
description: (
|
||||||
<span>
|
<span>
|
||||||
{ _t("Leave %(groupName)s?", {groupName: this.props.groupId}) }
|
{ _t("Leave %(groupName)s?", { groupName: this.props.groupId }) }
|
||||||
{ warnings }
|
{ warnings }
|
||||||
</span>
|
</span>
|
||||||
),
|
),
|
||||||
|
@ -782,7 +783,7 @@ export default class GroupView extends React.Component {
|
||||||
onFinished: async (confirmed) => {
|
onFinished: async (confirmed) => {
|
||||||
if (!confirmed) return;
|
if (!confirmed) return;
|
||||||
|
|
||||||
this.setState({membershipBusy: true});
|
this.setState({ membershipBusy: true });
|
||||||
|
|
||||||
// Wait 500ms to prevent flashing. Do this before sending a request otherwise we risk the
|
// Wait 500ms to prevent flashing. Do this before sending a request otherwise we risk the
|
||||||
// spinner disappearing after we have fetched new group data.
|
// spinner disappearing after we have fetched new group data.
|
||||||
|
@ -791,7 +792,7 @@ export default class GroupView extends React.Component {
|
||||||
GroupStore.leaveGroup(this.props.groupId).then(() => {
|
GroupStore.leaveGroup(this.props.groupId).then(() => {
|
||||||
// don't reset membershipBusy here: wait for the membership change to come down the sync
|
// don't reset membershipBusy here: wait for the membership change to come down the sync
|
||||||
}).catch((e) => {
|
}).catch((e) => {
|
||||||
this.setState({membershipBusy: false});
|
this.setState({ membershipBusy: false });
|
||||||
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||||
Modal.createTrackedDialog('Error leaving community', '', ErrorDialog, {
|
Modal.createTrackedDialog('Error leaving community', '', ErrorDialog, {
|
||||||
title: _t("Error"),
|
title: _t("Error"),
|
||||||
|
@ -855,7 +856,6 @@ export default class GroupView extends React.Component {
|
||||||
_getRoomsNode() {
|
_getRoomsNode() {
|
||||||
const RoomDetailList = sdk.getComponent('rooms.RoomDetailList');
|
const RoomDetailList = sdk.getComponent('rooms.RoomDetailList');
|
||||||
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
|
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
|
||||||
const TintableSvg = sdk.getComponent('elements.TintableSvg');
|
|
||||||
const Spinner = sdk.getComponent('elements.Spinner');
|
const Spinner = sdk.getComponent('elements.Spinner');
|
||||||
const TooltipButton = sdk.getComponent('elements.TooltipButton');
|
const TooltipButton = sdk.getComponent('elements.TooltipButton');
|
||||||
|
|
||||||
|
@ -871,7 +871,7 @@ export default class GroupView extends React.Component {
|
||||||
onClick={this._onAddRoomsClick}
|
onClick={this._onAddRoomsClick}
|
||||||
>
|
>
|
||||||
<div className="mx_GroupView_rooms_header_addRow_button">
|
<div className="mx_GroupView_rooms_header_addRow_button">
|
||||||
<TintableSvg src={require("../../../res/img/icons-room-add.svg")} width="24" height="24" />
|
<img src={require("../../../res/img/icons-room-add.svg")} width="24" height="24" />
|
||||||
</div>
|
</div>
|
||||||
<div className="mx_GroupView_rooms_header_addRow_label">
|
<div className="mx_GroupView_rooms_header_addRow_label">
|
||||||
{ _t('Add rooms to this community') }
|
{ _t('Add rooms to this community') }
|
||||||
|
@ -1336,7 +1336,7 @@ export default class GroupView extends React.Component {
|
||||||
if (this.state.error.httpStatus === 404) {
|
if (this.state.error.httpStatus === 404) {
|
||||||
return (
|
return (
|
||||||
<div className="mx_GroupView_error">
|
<div className="mx_GroupView_error">
|
||||||
{ _t('Community %(groupId)s not found', {groupId: this.props.groupId}) }
|
{ _t('Community %(groupId)s not found', { groupId: this.props.groupId }) }
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1346,7 +1346,7 @@ export default class GroupView extends React.Component {
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div className="mx_GroupView_error">
|
<div className="mx_GroupView_error">
|
||||||
{ _t('Failed to load %(groupId)s', {groupId: this.props.groupId }) }
|
{ _t('Failed to load %(groupId)s', { groupId: this.props.groupId }) }
|
||||||
{ extraText }
|
{ extraText }
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -15,29 +15,29 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import {useContext, useState} from "react";
|
import { useContext, useState } from "react";
|
||||||
|
|
||||||
import AutoHideScrollbar from './AutoHideScrollbar';
|
import AutoHideScrollbar from './AutoHideScrollbar';
|
||||||
import {getHomePageUrl} from "../../utils/pages";
|
import { getHomePageUrl } from "../../utils/pages";
|
||||||
import {_t} from "../../languageHandler";
|
import { _t } from "../../languageHandler";
|
||||||
import SdkConfig from "../../SdkConfig";
|
import SdkConfig from "../../SdkConfig";
|
||||||
import * as sdk from "../../index";
|
import * as sdk from "../../index";
|
||||||
import dis from "../../dispatcher/dispatcher";
|
import dis from "../../dispatcher/dispatcher";
|
||||||
import {Action} from "../../dispatcher/actions";
|
import { Action } from "../../dispatcher/actions";
|
||||||
import BaseAvatar from "../views/avatars/BaseAvatar";
|
import BaseAvatar from "../views/avatars/BaseAvatar";
|
||||||
import {OwnProfileStore} from "../../stores/OwnProfileStore";
|
import { OwnProfileStore } from "../../stores/OwnProfileStore";
|
||||||
import AccessibleButton from "../views/elements/AccessibleButton";
|
import AccessibleButton from "../views/elements/AccessibleButton";
|
||||||
import {UPDATE_EVENT} from "../../stores/AsyncStore";
|
import { UPDATE_EVENT } from "../../stores/AsyncStore";
|
||||||
import {useEventEmitter} from "../../hooks/useEventEmitter";
|
import { useEventEmitter } from "../../hooks/useEventEmitter";
|
||||||
import MatrixClientContext from "../../contexts/MatrixClientContext";
|
import MatrixClientContext from "../../contexts/MatrixClientContext";
|
||||||
import MiniAvatarUploader, {AVATAR_SIZE} from "../views/elements/MiniAvatarUploader";
|
import MiniAvatarUploader, { AVATAR_SIZE } from "../views/elements/MiniAvatarUploader";
|
||||||
import Analytics from "../../Analytics";
|
import Analytics from "../../Analytics";
|
||||||
import CountlyAnalytics from "../../CountlyAnalytics";
|
import CountlyAnalytics from "../../CountlyAnalytics";
|
||||||
|
|
||||||
const onClickSendDm = () => {
|
const onClickSendDm = () => {
|
||||||
Analytics.trackEvent('home_page', 'button', 'dm');
|
Analytics.trackEvent('home_page', 'button', 'dm');
|
||||||
CountlyAnalytics.instance.track("home_page_button", { button: "dm" });
|
CountlyAnalytics.instance.track("home_page_button", { button: "dm" });
|
||||||
dis.dispatch({action: 'view_create_chat'});
|
dis.dispatch({ action: 'view_create_chat' });
|
||||||
};
|
};
|
||||||
|
|
||||||
const onClickExplore = () => {
|
const onClickExplore = () => {
|
||||||
|
@ -49,7 +49,7 @@ const onClickExplore = () => {
|
||||||
const onClickNewRoom = () => {
|
const onClickNewRoom = () => {
|
||||||
Analytics.trackEvent('home_page', 'button', 'create_room');
|
Analytics.trackEvent('home_page', 'button', 'create_room');
|
||||||
CountlyAnalytics.instance.track("home_page_button", { button: "create_room" });
|
CountlyAnalytics.instance.track("home_page_button", { button: "create_room" });
|
||||||
dis.dispatch({action: 'view_create_room'});
|
dis.dispatch({ action: 'view_create_room' });
|
||||||
};
|
};
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
|
@ -117,7 +117,6 @@ const HomePage: React.FC<IProps> = ({ justRegistered = false }) => {
|
||||||
</React.Fragment>;
|
</React.Fragment>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return <AutoHideScrollbar className="mx_HomePage mx_HomePage_default">
|
return <AutoHideScrollbar className="mx_HomePage mx_HomePage_default">
|
||||||
<div className="mx_HomePage_default_wrapper">
|
<div className="mx_HomePage_default_wrapper">
|
||||||
{ introSection }
|
{ introSection }
|
||||||
|
|
|
@ -22,7 +22,7 @@ import {
|
||||||
import { _t } from "../../languageHandler";
|
import { _t } from "../../languageHandler";
|
||||||
import { HostSignupStore } from "../../stores/HostSignupStore";
|
import { HostSignupStore } from "../../stores/HostSignupStore";
|
||||||
import SdkConfig from "../../SdkConfig";
|
import SdkConfig from "../../SdkConfig";
|
||||||
import {replaceableComponent} from "../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../utils/replaceableComponent";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
onClick?(): void;
|
onClick?(): void;
|
||||||
|
@ -35,7 +35,7 @@ export default class HostSignupAction extends React.PureComponent<IProps, IState
|
||||||
private openDialog = async () => {
|
private openDialog = async () => {
|
||||||
this.props.onClick?.();
|
this.props.onClick?.();
|
||||||
await HostSignupStore.instance.setHostSignupActive(true);
|
await HostSignupStore.instance.setHostSignupActive(true);
|
||||||
}
|
};
|
||||||
|
|
||||||
public render(): React.ReactNode {
|
public render(): React.ReactNode {
|
||||||
const hostSignupConfig = SdkConfig.get().hostSignup;
|
const hostSignupConfig = SdkConfig.get().hostSignup;
|
||||||
|
|
|
@ -17,7 +17,7 @@ limitations under the License.
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import AutoHideScrollbar from "./AutoHideScrollbar";
|
import AutoHideScrollbar from "./AutoHideScrollbar";
|
||||||
import {replaceableComponent} from "../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../utils/replaceableComponent";
|
||||||
|
|
||||||
@replaceableComponent("structures.IndicatorScrollbar")
|
@replaceableComponent("structures.IndicatorScrollbar")
|
||||||
export default class IndicatorScrollbar extends React.Component {
|
export default class IndicatorScrollbar extends React.Component {
|
||||||
|
@ -70,7 +70,6 @@ export default class IndicatorScrollbar extends React.Component {
|
||||||
this._autoHideScrollbar = autoHideScrollbar;
|
this._autoHideScrollbar = autoHideScrollbar;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
componentDidUpdate(prevProps) {
|
componentDidUpdate(prevProps) {
|
||||||
const prevLen = prevProps && prevProps.children && prevProps.children.length || 0;
|
const prevLen = prevProps && prevProps.children && prevProps.children.length || 0;
|
||||||
const curLen = this.props.children && this.props.children.length || 0;
|
const curLen = this.props.children && this.props.children.length || 0;
|
||||||
|
@ -188,8 +187,8 @@ export default class IndicatorScrollbar extends React.Component {
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
const { children, trackHorizontalOverflow, verticalScrollsHorizontally, ...otherProps } = this.props;
|
const { children, trackHorizontalOverflow, verticalScrollsHorizontally, ...otherProps } = this.props;
|
||||||
|
|
||||||
const leftIndicatorStyle = {left: this.state.leftIndicatorOffset};
|
const leftIndicatorStyle = { left: this.state.leftIndicatorOffset };
|
||||||
const rightIndicatorStyle = {right: this.state.rightIndicatorOffset};
|
const rightIndicatorStyle = { right: this.state.rightIndicatorOffset };
|
||||||
const leftOverflowIndicator = trackHorizontalOverflow
|
const leftOverflowIndicator = trackHorizontalOverflow
|
||||||
? <div className="mx_IndicatorScrollbar_leftOverflowIndicator" style={leftIndicatorStyle} /> : null;
|
? <div className="mx_IndicatorScrollbar_leftOverflowIndicator" style={leftIndicatorStyle} /> : null;
|
||||||
const rightOverflowIndicator = trackHorizontalOverflow
|
const rightOverflowIndicator = trackHorizontalOverflow
|
||||||
|
|
|
@ -15,14 +15,14 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {InteractiveAuth} from "matrix-js-sdk/src/interactive-auth";
|
import { InteractiveAuth } from "matrix-js-sdk/src/interactive-auth";
|
||||||
import React, {createRef} from 'react';
|
import React, { createRef } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import getEntryComponentForLoginType from '../views/auth/InteractiveAuthEntryComponents';
|
import getEntryComponentForLoginType from '../views/auth/InteractiveAuthEntryComponents';
|
||||||
|
|
||||||
import * as sdk from '../../index';
|
import * as sdk from '../../index';
|
||||||
import {replaceableComponent} from "../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../utils/replaceableComponent";
|
||||||
|
|
||||||
export const ERROR_USER_CANCELLED = new Error("User cancelled auth session");
|
export const ERROR_USER_CANCELLED = new Error("User cancelled auth session");
|
||||||
|
|
||||||
|
|
|
@ -40,9 +40,9 @@ import AccessibleTooltipButton from "../views/elements/AccessibleTooltipButton";
|
||||||
import { OwnProfileStore } from "../../stores/OwnProfileStore";
|
import { OwnProfileStore } from "../../stores/OwnProfileStore";
|
||||||
import RoomListNumResults from "../views/rooms/RoomListNumResults";
|
import RoomListNumResults from "../views/rooms/RoomListNumResults";
|
||||||
import LeftPanelWidget from "./LeftPanelWidget";
|
import LeftPanelWidget from "./LeftPanelWidget";
|
||||||
import {replaceableComponent} from "../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../utils/replaceableComponent";
|
||||||
import {mediaFromMxc} from "../../customisations/Media";
|
import { mediaFromMxc } from "../../customisations/Media";
|
||||||
import SpaceStore, {UPDATE_SELECTED_SPACE} from "../../stores/SpaceStore";
|
import SpaceStore, { UPDATE_SELECTED_SPACE } from "../../stores/SpaceStore";
|
||||||
import { getKeyBindingsManager, RoomListAction } from "../../KeyBindingsManager";
|
import { getKeyBindingsManager, RoomListAction } from "../../KeyBindingsManager";
|
||||||
import UIStore from "../../stores/UIStore";
|
import UIStore from "../../stores/UIStore";
|
||||||
|
|
||||||
|
@ -91,7 +91,7 @@ export default class LeftPanel extends React.Component<IProps, IState> {
|
||||||
this.bgImageWatcherRef = SettingsStore.watchSetting(
|
this.bgImageWatcherRef = SettingsStore.watchSetting(
|
||||||
"RoomList.backgroundImage", null, this.onBackgroundImageUpdate);
|
"RoomList.backgroundImage", null, this.onBackgroundImageUpdate);
|
||||||
this.groupFilterPanelWatcherRef = SettingsStore.watchSetting("TagPanel.enableTagPanel", null, () => {
|
this.groupFilterPanelWatcherRef = SettingsStore.watchSetting("TagPanel.enableTagPanel", null, () => {
|
||||||
this.setState({showGroupFilterPanel: SettingsStore.getValue("TagPanel.enableTagPanel")});
|
this.setState({ showGroupFilterPanel: SettingsStore.getValue("TagPanel.enableTagPanel") });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,7 +127,7 @@ export default class LeftPanel extends React.Component<IProps, IState> {
|
||||||
|
|
||||||
private onDialPad = () => {
|
private onDialPad = () => {
|
||||||
dis.fire(Action.OpenDialPad);
|
dis.fire(Action.OpenDialPad);
|
||||||
}
|
};
|
||||||
|
|
||||||
private onExplore = () => {
|
private onExplore = () => {
|
||||||
dis.fire(Action.ViewRoomDirectory);
|
dis.fire(Action.ViewRoomDirectory);
|
||||||
|
@ -136,12 +136,12 @@ export default class LeftPanel extends React.Component<IProps, IState> {
|
||||||
private refreshStickyHeaders = () => {
|
private refreshStickyHeaders = () => {
|
||||||
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 = () => {
|
||||||
const newVal = BreadcrumbsStore.instance.visible;
|
const newVal = BreadcrumbsStore.instance.visible;
|
||||||
if (newVal !== this.state.showBreadcrumbs) {
|
if (newVal !== this.state.showBreadcrumbs) {
|
||||||
this.setState({showBreadcrumbs: newVal});
|
this.setState({ showBreadcrumbs: newVal });
|
||||||
|
|
||||||
// Update the sticky headers too as the breadcrumbs will be popping in or out.
|
// Update the sticky headers too as the breadcrumbs will be popping in or out.
|
||||||
if (!this.listContainerRef.current) return; // ignore: no headers to sticky
|
if (!this.listContainerRef.current) return; // ignore: no headers to sticky
|
||||||
|
|
|
@ -14,19 +14,19 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, {useContext, useMemo} from "react";
|
import React, { useContext, useMemo } from "react";
|
||||||
import {Resizable} from "re-resizable";
|
import { Resizable } from "re-resizable";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
|
|
||||||
import AccessibleButton from "../views/elements/AccessibleButton";
|
import AccessibleButton from "../views/elements/AccessibleButton";
|
||||||
import {useRovingTabIndex} from "../../accessibility/RovingTabIndex";
|
import { useRovingTabIndex } from "../../accessibility/RovingTabIndex";
|
||||||
import {Key} from "../../Keyboard";
|
import { Key } from "../../Keyboard";
|
||||||
import {useLocalStorageState} from "../../hooks/useLocalStorageState";
|
import { useLocalStorageState } from "../../hooks/useLocalStorageState";
|
||||||
import MatrixClientContext from "../../contexts/MatrixClientContext";
|
import MatrixClientContext from "../../contexts/MatrixClientContext";
|
||||||
import WidgetUtils, {IWidgetEvent} from "../../utils/WidgetUtils";
|
import WidgetUtils, { IWidgetEvent } from "../../utils/WidgetUtils";
|
||||||
import {useAccountData} from "../../hooks/useAccountData";
|
import { useAccountData } from "../../hooks/useAccountData";
|
||||||
import AppTile from "../views/elements/AppTile";
|
import AppTile from "../views/elements/AppTile";
|
||||||
import {useSettingValue} from "../../hooks/useSettings";
|
import { useSettingValue } from "../../hooks/useSettings";
|
||||||
import UIStore from "../../stores/UIStore";
|
import UIStore from "../../stores/UIStore";
|
||||||
|
|
||||||
const MIN_HEIGHT = 100;
|
const MIN_HEIGHT = 100;
|
||||||
|
@ -62,14 +62,14 @@ const LeftPanelWidget: React.FC = () => {
|
||||||
let content;
|
let content;
|
||||||
if (expanded) {
|
if (expanded) {
|
||||||
content = <Resizable
|
content = <Resizable
|
||||||
size={{height} as any}
|
size={{ height } as any}
|
||||||
minHeight={MIN_HEIGHT}
|
minHeight={MIN_HEIGHT}
|
||||||
maxHeight={Math.min(UIStore.instance.windowHeight / 2, MAX_HEIGHT)}
|
maxHeight={Math.min(UIStore.instance.windowHeight / 2, MAX_HEIGHT)}
|
||||||
onResizeStop={(e, dir, ref, d) => {
|
onResizeStop={(e, dir, ref, d) => {
|
||||||
setHeight(height + d.height);
|
setHeight(height + d.height);
|
||||||
}}
|
}}
|
||||||
handleWrapperClass="mx_LeftPanelWidget_resizerHandles"
|
handleWrapperClass="mx_LeftPanelWidget_resizerHandles"
|
||||||
handleClasses={{top: "mx_LeftPanelWidget_resizerHandle"}}
|
handleClasses={{ top: "mx_LeftPanelWidget_resizerHandle" }}
|
||||||
className="mx_LeftPanelWidget_resizeBox"
|
className="mx_LeftPanelWidget_resizeBox"
|
||||||
enable={{ top: true }}
|
enable={{ top: true }}
|
||||||
>
|
>
|
||||||
|
|
|
@ -20,7 +20,7 @@ import * as React from 'react';
|
||||||
import * as PropTypes from 'prop-types';
|
import * as PropTypes from 'prop-types';
|
||||||
import { MatrixClient } from 'matrix-js-sdk/src/client';
|
import { MatrixClient } from 'matrix-js-sdk/src/client';
|
||||||
|
|
||||||
import {Key} from '../../Keyboard';
|
import { Key } from '../../Keyboard';
|
||||||
import PageTypes from '../../PageTypes';
|
import PageTypes from '../../PageTypes';
|
||||||
import MediaDeviceHandler from '../../MediaDeviceHandler';
|
import MediaDeviceHandler from '../../MediaDeviceHandler';
|
||||||
import { fixupColorFonts } from '../../utils/FontManager';
|
import { fixupColorFonts } from '../../utils/FontManager';
|
||||||
|
@ -30,7 +30,7 @@ import { IMatrixClientCreds } from '../../MatrixClientPeg';
|
||||||
import SettingsStore from "../../settings/SettingsStore";
|
import SettingsStore from "../../settings/SettingsStore";
|
||||||
|
|
||||||
import ResizeHandle from '../views/elements/ResizeHandle';
|
import ResizeHandle from '../views/elements/ResizeHandle';
|
||||||
import {Resizer, CollapseDistributor} from '../../resizer';
|
import { Resizer, CollapseDistributor } from '../../resizer';
|
||||||
import MatrixClientContext from "../../contexts/MatrixClientContext";
|
import MatrixClientContext from "../../contexts/MatrixClientContext";
|
||||||
import * as KeyboardShortcuts from "../../accessibility/KeyboardShortcuts";
|
import * as KeyboardShortcuts from "../../accessibility/KeyboardShortcuts";
|
||||||
import HomePage from "./HomePage";
|
import HomePage from "./HomePage";
|
||||||
|
@ -55,7 +55,7 @@ import HostSignupContainer from '../views/host_signup/HostSignupContainer';
|
||||||
import { getKeyBindingsManager, NavigationAction, RoomAction } from '../../KeyBindingsManager';
|
import { getKeyBindingsManager, NavigationAction, RoomAction } from '../../KeyBindingsManager';
|
||||||
import { IOpts } from "../../createRoom";
|
import { IOpts } from "../../createRoom";
|
||||||
import SpacePanel from "../views/spaces/SpacePanel";
|
import SpacePanel from "../views/spaces/SpacePanel";
|
||||||
import {replaceableComponent} from "../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../utils/replaceableComponent";
|
||||||
import CallHandler, { CallHandlerEvent } from '../../CallHandler';
|
import CallHandler, { CallHandlerEvent } from '../../CallHandler';
|
||||||
import { MatrixCall } from 'matrix-js-sdk/src/webrtc/call';
|
import { MatrixCall } from 'matrix-js-sdk/src/webrtc/call';
|
||||||
import AudioFeedArrayForCall from '../views/voip/AudioFeedArrayForCall';
|
import AudioFeedArrayForCall from '../views/voip/AudioFeedArrayForCall';
|
||||||
|
@ -232,10 +232,10 @@ class LoggedInView extends React.Component<IProps, IState> {
|
||||||
onCollapsed: (_collapsed) => {
|
onCollapsed: (_collapsed) => {
|
||||||
collapsed = _collapsed;
|
collapsed = _collapsed;
|
||||||
if (_collapsed) {
|
if (_collapsed) {
|
||||||
dis.dispatch({action: "hide_left_panel"});
|
dis.dispatch({ action: "hide_left_panel" });
|
||||||
window.localStorage.setItem("mx_lhs_size", '0');
|
window.localStorage.setItem("mx_lhs_size", '0');
|
||||||
} else {
|
} else {
|
||||||
dis.dispatch({action: "show_left_panel"});
|
dis.dispatch({ action: "show_left_panel" });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onResized: (_size) => {
|
onResized: (_size) => {
|
||||||
|
@ -272,7 +272,7 @@ class LoggedInView extends React.Component<IProps, IState> {
|
||||||
|
|
||||||
onAccountData = (event) => {
|
onAccountData = (event) => {
|
||||||
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" });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -319,7 +319,7 @@ class LoggedInView extends React.Component<IProps, IState> {
|
||||||
this.setState({
|
this.setState({
|
||||||
usageLimitDismissed: true,
|
usageLimitDismissed: true,
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
_calculateServerLimitToast(syncError: IState["syncErrorData"], usageLimitEventContent?: IUsageLimit) {
|
_calculateServerLimitToast(syncError: IState["syncErrorData"], usageLimitEventContent?: IUsageLimit) {
|
||||||
const error = syncError && syncError.error && syncError.error.errcode === "M_RESOURCE_LIMIT_EXCEEDED";
|
const error = syncError && syncError.error && syncError.error.errcode === "M_RESOURCE_LIMIT_EXCEEDED";
|
||||||
|
|
|
@ -17,7 +17,7 @@ limitations under the License.
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Resizable } from 're-resizable';
|
import { Resizable } from 're-resizable';
|
||||||
import {replaceableComponent} from "../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../utils/replaceableComponent";
|
||||||
|
|
||||||
@replaceableComponent("structures.MainSplit")
|
@replaceableComponent("structures.MainSplit")
|
||||||
export default class MainSplit extends React.Component {
|
export default class MainSplit extends React.Component {
|
||||||
|
@ -73,7 +73,7 @@ export default class MainSplit extends React.Component {
|
||||||
onResize={this._onResize}
|
onResize={this._onResize}
|
||||||
onResizeStop={this._onResizeStop}
|
onResizeStop={this._onResizeStop}
|
||||||
className="mx_RightPanel_ResizeWrapper"
|
className="mx_RightPanel_ResizeWrapper"
|
||||||
handleClasses={{left: "mx_RightPanel_ResizeHandle"}}
|
handleClasses={{ left: "mx_RightPanel_ResizeHandle" }}
|
||||||
>
|
>
|
||||||
{ panelView }
|
{ panelView }
|
||||||
</Resizable>;
|
</Resizable>;
|
||||||
|
|
|
@ -34,7 +34,6 @@ import dis from "../../dispatcher/dispatcher";
|
||||||
import Notifier from '../../Notifier';
|
import Notifier from '../../Notifier';
|
||||||
|
|
||||||
import Modal from "../../Modal";
|
import Modal from "../../Modal";
|
||||||
import Tinter from "../../Tinter";
|
|
||||||
import * as sdk from '../../index';
|
import * as sdk from '../../index';
|
||||||
import { showRoomInviteDialog, showStartChatInviteDialog } from '../../RoomInvite';
|
import { showRoomInviteDialog, showStartChatInviteDialog } from '../../RoomInvite';
|
||||||
import * as Rooms from '../../Rooms';
|
import * as Rooms from '../../Rooms';
|
||||||
|
@ -44,8 +43,8 @@ import * as Lifecycle from '../../Lifecycle';
|
||||||
import '../../stores/LifecycleStore';
|
import '../../stores/LifecycleStore';
|
||||||
import PageTypes from '../../PageTypes';
|
import PageTypes from '../../PageTypes';
|
||||||
|
|
||||||
import createRoom, {IOpts} from "../../createRoom";
|
import createRoom, { IOpts } from "../../createRoom";
|
||||||
import {_t, _td, getCurrentLanguage} from '../../languageHandler';
|
import { _t, _td, getCurrentLanguage } from '../../languageHandler';
|
||||||
import SettingsStore from "../../settings/SettingsStore";
|
import SettingsStore from "../../settings/SettingsStore";
|
||||||
import ThemeController from "../../settings/controllers/ThemeController";
|
import ThemeController from "../../settings/controllers/ThemeController";
|
||||||
import { startAnyRegistrationFlow } from "../../Registration";
|
import { startAnyRegistrationFlow } from "../../Registration";
|
||||||
|
@ -66,7 +65,7 @@ import {
|
||||||
showToast as showAnalyticsToast,
|
showToast as showAnalyticsToast,
|
||||||
hideToast as hideAnalyticsToast,
|
hideToast as hideAnalyticsToast,
|
||||||
} from "../../toasts/AnalyticsToast";
|
} from "../../toasts/AnalyticsToast";
|
||||||
import {showToast as showNotificationsToast} from "../../toasts/DesktopNotificationsToast";
|
import { showToast as showNotificationsToast } from "../../toasts/DesktopNotificationsToast";
|
||||||
import { OpenToTabPayload } from "../../dispatcher/payloads/OpenToTabPayload";
|
import { OpenToTabPayload } from "../../dispatcher/payloads/OpenToTabPayload";
|
||||||
import ErrorDialog from "../views/dialogs/ErrorDialog";
|
import ErrorDialog from "../views/dialogs/ErrorDialog";
|
||||||
import { RoomNotificationStateStore } from "../../stores/notifications/RoomNotificationStateStore";
|
import { RoomNotificationStateStore } from "../../stores/notifications/RoomNotificationStateStore";
|
||||||
|
@ -74,15 +73,15 @@ import { SettingLevel } from "../../settings/SettingLevel";
|
||||||
import { leaveRoomBehaviour } from "../../utils/membership";
|
import { leaveRoomBehaviour } from "../../utils/membership";
|
||||||
import CreateCommunityPrototypeDialog from "../views/dialogs/CreateCommunityPrototypeDialog";
|
import CreateCommunityPrototypeDialog from "../views/dialogs/CreateCommunityPrototypeDialog";
|
||||||
import ThreepidInviteStore, { IThreepidInvite, IThreepidInviteWireFormat } from "../../stores/ThreepidInviteStore";
|
import ThreepidInviteStore, { IThreepidInvite, IThreepidInviteWireFormat } from "../../stores/ThreepidInviteStore";
|
||||||
import {UIFeature} from "../../settings/UIFeature";
|
import { UIFeature } from "../../settings/UIFeature";
|
||||||
import { CommunityPrototypeStore } from "../../stores/CommunityPrototypeStore";
|
import { CommunityPrototypeStore } from "../../stores/CommunityPrototypeStore";
|
||||||
import DialPadModal from "../views/voip/DialPadModal";
|
import DialPadModal from "../views/voip/DialPadModal";
|
||||||
import { showToast as showMobileGuideToast } from '../../toasts/MobileGuideToast';
|
import { showToast as showMobileGuideToast } from '../../toasts/MobileGuideToast';
|
||||||
import { shouldUseLoginForWelcome } from "../../utils/pages";
|
import { shouldUseLoginForWelcome } from "../../utils/pages";
|
||||||
import SpaceStore from "../../stores/SpaceStore";
|
import SpaceStore from "../../stores/SpaceStore";
|
||||||
import {replaceableComponent} from "../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../utils/replaceableComponent";
|
||||||
import RoomListStore from "../../stores/room-list/RoomListStore";
|
import RoomListStore from "../../stores/room-list/RoomListStore";
|
||||||
import {RoomUpdateCause} from "../../stores/room-list/models";
|
import { RoomUpdateCause } from "../../stores/room-list/models";
|
||||||
import defaultDispatcher from "../../dispatcher/dispatcher";
|
import defaultDispatcher from "../../dispatcher/dispatcher";
|
||||||
import SecurityCustomisations from "../../customisations/Security";
|
import SecurityCustomisations from "../../customisations/Security";
|
||||||
|
|
||||||
|
@ -283,11 +282,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
|
|
||||||
this.pageChanging = false;
|
this.pageChanging = false;
|
||||||
|
|
||||||
// check we have the right tint applied for this theme.
|
|
||||||
// N.B. we don't call the whole of setTheme() here as we may be
|
|
||||||
// racing with the theme CSS download finishing from index.js
|
|
||||||
Tinter.tint();
|
|
||||||
|
|
||||||
// For PersistentElement
|
// For PersistentElement
|
||||||
this.state.resizeNotifier.on("middlePanelResized", this.dispatchTimelineResize);
|
this.state.resizeNotifier.on("middlePanelResized", this.dispatchTimelineResize);
|
||||||
|
|
||||||
|
@ -401,7 +395,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
if (SecurityCustomisations.SHOW_ENCRYPTION_SETUP_UI === false) {
|
if (SecurityCustomisations.SHOW_ENCRYPTION_SETUP_UI === false) {
|
||||||
this.onLoggedIn();
|
this.onLoggedIn();
|
||||||
} else {
|
} else {
|
||||||
this.setStateForNewView({view: Views.COMPLETE_SECURITY});
|
this.setStateForNewView({ view: Views.COMPLETE_SECURITY });
|
||||||
}
|
}
|
||||||
} else if (await cli.doesServerSupportUnstableFeature("org.matrix.e2e_cross_signing")) {
|
} else if (await cli.doesServerSupportUnstableFeature("org.matrix.e2e_cross_signing")) {
|
||||||
this.setStateForNewView({ view: Views.E2E_SETUP });
|
this.setStateForNewView({ view: Views.E2E_SETUP });
|
||||||
|
@ -454,7 +448,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
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"];
|
||||||
return {serverConfig: props};
|
return { serverConfig: props };
|
||||||
}
|
}
|
||||||
|
|
||||||
private loadSession() {
|
private loadSession() {
|
||||||
|
@ -472,9 +466,9 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
if (!loadedSession) {
|
if (!loadedSession) {
|
||||||
// fall back to showing the welcome screen... unless we have a 3pid invite pending
|
// fall back to showing the welcome screen... unless we have a 3pid invite pending
|
||||||
if (ThreepidInviteStore.instance.pickBestInvite()) {
|
if (ThreepidInviteStore.instance.pickBestInvite()) {
|
||||||
dis.dispatch({action: 'start_registration'});
|
dis.dispatch({ action: 'start_registration' });
|
||||||
} else {
|
} else {
|
||||||
dis.dispatch({action: "view_welcome_page"});
|
dis.dispatch({ action: "view_welcome_page" });
|
||||||
}
|
}
|
||||||
} else if (SettingsStore.getValue("analyticsOptIn")) {
|
} else if (SettingsStore.getValue("analyticsOptIn")) {
|
||||||
CountlyAnalytics.instance.enable(/* anonymous = */ false);
|
CountlyAnalytics.instance.enable(/* anonymous = */ false);
|
||||||
|
@ -538,7 +532,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
action: 'do_after_sync_prepared',
|
action: 'do_after_sync_prepared',
|
||||||
deferred_action: payload,
|
deferred_action: payload,
|
||||||
});
|
});
|
||||||
dis.dispatch({action: 'require_registration'});
|
dis.dispatch({ action: 'require_registration' });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -563,11 +557,11 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// redispatch the change with a more specific action
|
// redispatch the change with a more specific action
|
||||||
dis.dispatch({action: 'id_server_changed'});
|
dis.dispatch({ action: 'id_server_changed' });
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'logout':
|
case 'logout':
|
||||||
dis.dispatch({action: "hangup_all"});
|
dis.dispatch({ action: "hangup_all" });
|
||||||
Lifecycle.logout();
|
Lifecycle.logout();
|
||||||
break;
|
break;
|
||||||
case 'require_registration':
|
case 'require_registration':
|
||||||
|
@ -624,7 +618,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
MatrixClientPeg.get().leave(payload.room_id).then(() => {
|
MatrixClientPeg.get().leave(payload.room_id).then(() => {
|
||||||
modal.close();
|
modal.close();
|
||||||
if (this.state.currentRoomId === payload.room_id) {
|
if (this.state.currentRoomId === payload.room_id) {
|
||||||
dis.dispatch({action: 'view_home_page'});
|
dis.dispatch({ action: 'view_home_page' });
|
||||||
}
|
}
|
||||||
}, (err) => {
|
}, (err) => {
|
||||||
modal.close();
|
modal.close();
|
||||||
|
@ -657,7 +651,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
const tabPayload = payload as OpenToTabPayload;
|
const tabPayload = payload as OpenToTabPayload;
|
||||||
const UserSettingsDialog = sdk.getComponent("dialogs.UserSettingsDialog");
|
const UserSettingsDialog = sdk.getComponent("dialogs.UserSettingsDialog");
|
||||||
Modal.createTrackedDialog('User settings', '', UserSettingsDialog,
|
Modal.createTrackedDialog('User settings', '', UserSettingsDialog,
|
||||||
{initialTabId: tabPayload.initialTabId},
|
{ initialTabId: tabPayload.initialTabId },
|
||||||
/*className=*/null, /*isPriority=*/false, /*isStatic=*/true);
|
/*className=*/null, /*isPriority=*/false, /*isStatic=*/true);
|
||||||
|
|
||||||
// View the welcome or home page if we need something to look at
|
// View the welcome or home page if we need something to look at
|
||||||
|
@ -668,7 +662,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
this.createRoom(payload.public, payload.defaultName);
|
this.createRoom(payload.public, payload.defaultName);
|
||||||
break;
|
break;
|
||||||
case 'view_create_group': {
|
case 'view_create_group': {
|
||||||
let CreateGroupDialog = sdk.getComponent("dialogs.CreateGroupDialog")
|
let CreateGroupDialog = sdk.getComponent("dialogs.CreateGroupDialog");
|
||||||
if (SettingsStore.getValue("feature_communities_v2_prototypes")) {
|
if (SettingsStore.getValue("feature_communities_v2_prototypes")) {
|
||||||
CreateGroupDialog = CreateCommunityPrototypeDialog;
|
CreateGroupDialog = CreateCommunityPrototypeDialog;
|
||||||
}
|
}
|
||||||
|
@ -727,9 +721,9 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
// We just dispatch the page change rather than have to worry about
|
// We just dispatch the page change rather than have to worry about
|
||||||
// what the logic is for each of these branches.
|
// what the logic is for each of these branches.
|
||||||
if (this.state.page_type === PageTypes.MyGroups) {
|
if (this.state.page_type === PageTypes.MyGroups) {
|
||||||
dis.dispatch({action: 'view_last_screen'});
|
dis.dispatch({ action: 'view_last_screen' });
|
||||||
} else {
|
} else {
|
||||||
dis.dispatch({action: 'view_my_groups'});
|
dis.dispatch({ action: 'view_my_groups' });
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'hide_left_panel':
|
case 'hide_left_panel':
|
||||||
|
@ -770,7 +764,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
this.onLoggedOut();
|
this.onLoggedOut();
|
||||||
break;
|
break;
|
||||||
case 'will_start_client':
|
case 'will_start_client':
|
||||||
this.setState({ready: false}, () => {
|
this.setState({ ready: false }, () => {
|
||||||
// if the client is about to start, we are, by definition, not ready.
|
// if the client is about to start, we are, by definition, not ready.
|
||||||
// Set ready to false now, then it'll be set to true when the sync
|
// Set ready to false now, then it'll be set to true when the sync
|
||||||
// listener we set below fires.
|
// listener we set below fires.
|
||||||
|
@ -1006,7 +1000,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.notifyNewScreen('user/' + userId);
|
this.notifyNewScreen('user/' + userId);
|
||||||
this.setState({currentUserId: userId});
|
this.setState({ currentUserId: userId });
|
||||||
this.setPage(PageTypes.UserView);
|
this.setPage(PageTypes.UserView);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1131,8 +1125,14 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
description: (
|
description: (
|
||||||
<span>
|
<span>
|
||||||
{ isSpace
|
{ isSpace
|
||||||
? _t("Are you sure you want to leave the space '%(spaceName)s'?", {spaceName: roomToLeave.name})
|
? _t(
|
||||||
: _t("Are you sure you want to leave the room '%(roomName)s'?", {roomName: roomToLeave.name}) }
|
"Are you sure you want to leave the space '%(spaceName)s'?",
|
||||||
|
{ spaceName: roomToLeave.name },
|
||||||
|
)
|
||||||
|
: _t(
|
||||||
|
"Are you sure you want to leave the room '%(roomName)s'?",
|
||||||
|
{ roomName: roomToLeave.name },
|
||||||
|
)}
|
||||||
{ warnings }
|
{ warnings }
|
||||||
</span>
|
</span>
|
||||||
),
|
),
|
||||||
|
@ -1170,7 +1170,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
const errCode = err.errcode || _td("unknown error code");
|
const errCode = err.errcode || _td("unknown error code");
|
||||||
Modal.createTrackedDialog("Failed to forget room", '', ErrorDialog, {
|
Modal.createTrackedDialog("Failed to forget room", '', ErrorDialog, {
|
||||||
title: _t("Failed to forget room %(errCode)s", {errCode}),
|
title: _t("Failed to forget room %(errCode)s", { errCode }),
|
||||||
description: ((err && err.message) ? err.message : _t("Operation failed")),
|
description: ((err && err.message) ? err.message : _t("Operation failed")),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1254,7 +1254,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
if (welcomeUserRoom === null) {
|
if (welcomeUserRoom === null) {
|
||||||
// We didn't redirect to the welcome user room, so show
|
// We didn't redirect to the welcome user room, so show
|
||||||
// the homepage.
|
// the homepage.
|
||||||
dis.dispatch({action: 'view_home_page', justRegistered: true});
|
dis.dispatch({ action: 'view_home_page', justRegistered: true });
|
||||||
}
|
}
|
||||||
} else if (ThreepidInviteStore.instance.pickBestInvite()) {
|
} else if (ThreepidInviteStore.instance.pickBestInvite()) {
|
||||||
// The user has a 3pid invite pending - show them that
|
// The user has a 3pid invite pending - show them that
|
||||||
|
@ -1263,11 +1263,11 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
// HACK: This is a pretty brutal way of threading the invite back through
|
// HACK: This is a pretty brutal way of threading the invite back through
|
||||||
// our systems, but it's the safest we have for now.
|
// our systems, but it's the safest we have for now.
|
||||||
const params = ThreepidInviteStore.instance.translateToWireFormat(threepidInvite);
|
const params = ThreepidInviteStore.instance.translateToWireFormat(threepidInvite);
|
||||||
this.showScreen(`room/${threepidInvite.roomId}`, params)
|
this.showScreen(`room/${threepidInvite.roomId}`, params);
|
||||||
} else {
|
} else {
|
||||||
// The user has just logged in after registering,
|
// The user has just logged in after registering,
|
||||||
// so show the homepage.
|
// so show the homepage.
|
||||||
dis.dispatch({action: 'view_home_page', justRegistered: true});
|
dis.dispatch({ action: 'view_home_page', justRegistered: true });
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.showScreenAfterLogin();
|
this.showScreenAfterLogin();
|
||||||
|
@ -1303,9 +1303,9 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
this.viewLastRoom();
|
this.viewLastRoom();
|
||||||
} else {
|
} else {
|
||||||
if (MatrixClientPeg.get().isGuest()) {
|
if (MatrixClientPeg.get().isGuest()) {
|
||||||
dis.dispatch({action: 'view_welcome_page'});
|
dis.dispatch({ action: 'view_welcome_page' });
|
||||||
} else {
|
} else {
|
||||||
dis.dispatch({action: 'view_home_page'});
|
dis.dispatch({ action: 'view_home_page' });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1385,15 +1385,15 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
// So dispatch directly from here. Ideally we'd use a SyncStateStore that
|
// So dispatch directly from here. Ideally we'd use a SyncStateStore that
|
||||||
// would do this dispatch and expose the sync state itself (by listening to
|
// would do this dispatch and expose the sync state itself (by listening to
|
||||||
// its own dispatch).
|
// its own dispatch).
|
||||||
dis.dispatch({action: 'sync_state', prevState, state});
|
dis.dispatch({ action: 'sync_state', prevState, state });
|
||||||
|
|
||||||
if (state === "ERROR" || state === "RECONNECTING") {
|
if (state === "ERROR" || state === "RECONNECTING") {
|
||||||
if (data.error instanceof InvalidStoreError) {
|
if (data.error instanceof InvalidStoreError) {
|
||||||
Lifecycle.handleInvalidStoreError(data.error);
|
Lifecycle.handleInvalidStoreError(data.error);
|
||||||
}
|
}
|
||||||
this.setState({syncError: data.error || true});
|
this.setState({ syncError: data.error || true });
|
||||||
} else if (this.state.syncError) {
|
} else if (this.state.syncError) {
|
||||||
this.setState({syncError: null});
|
this.setState({ syncError: null });
|
||||||
}
|
}
|
||||||
|
|
||||||
this.updateStatusIndicator(state, prevState);
|
this.updateStatusIndicator(state, prevState);
|
||||||
|
@ -1567,16 +1567,12 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
key: 'verifreq_' + request.channel.transactionId,
|
key: 'verifreq_' + request.channel.transactionId,
|
||||||
title: _t("Verification requested"),
|
title: _t("Verification requested"),
|
||||||
icon: "verification",
|
icon: "verification",
|
||||||
props: {request},
|
props: { request },
|
||||||
component: sdk.getComponent("toasts.VerificationRequestToast"),
|
component: sdk.getComponent("toasts.VerificationRequestToast"),
|
||||||
priority: 90,
|
priority: 90,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// Fire the tinter right on startup to ensure the default theme is applied
|
|
||||||
// A later sync can/will correct the tint to be the right value for the user
|
|
||||||
const colorScheme = SettingsStore.getValue("roomColor");
|
|
||||||
Tinter.tint(colorScheme.primary_color, colorScheme.secondary_color);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1668,7 +1664,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
// TODO if logged in, skip SSO
|
// TODO if logged in, skip SSO
|
||||||
let cli = MatrixClientPeg.get();
|
let cli = MatrixClientPeg.get();
|
||||||
if (!cli) {
|
if (!cli) {
|
||||||
const {hsUrl, isUrl} = this.props.serverConfig;
|
const { hsUrl, isUrl } = this.props.serverConfig;
|
||||||
cli = createClient({
|
cli = createClient({
|
||||||
baseUrl: hsUrl,
|
baseUrl: hsUrl,
|
||||||
idBaseUrl: isUrl,
|
idBaseUrl: isUrl,
|
||||||
|
@ -1792,7 +1788,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
|
|
||||||
onAliasClick(event: MouseEvent, alias: string) {
|
onAliasClick(event: MouseEvent, alias: string) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
dis.dispatch({action: 'view_room', room_alias: alias});
|
dis.dispatch({ action: 'view_room', room_alias: alias });
|
||||||
}
|
}
|
||||||
|
|
||||||
onUserClick(event: MouseEvent, userId: string) {
|
onUserClick(event: MouseEvent, userId: string) {
|
||||||
|
@ -1808,7 +1804,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
|
|
||||||
onGroupClick(event: MouseEvent, groupId: string) {
|
onGroupClick(event: MouseEvent, groupId: string) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
dis.dispatch({action: 'view_group', group_id: groupId});
|
dis.dispatch({ action: 'view_group', group_id: groupId });
|
||||||
}
|
}
|
||||||
|
|
||||||
onLogoutClick(event: React.MouseEvent<HTMLAnchorElement, MouseEvent>) {
|
onLogoutClick(event: React.MouseEvent<HTMLAnchorElement, MouseEvent>) {
|
||||||
|
@ -1870,14 +1866,14 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
onSendEvent(roomId: string, event: MatrixEvent) {
|
onSendEvent(roomId: string, event: MatrixEvent) {
|
||||||
const cli = MatrixClientPeg.get();
|
const cli = MatrixClientPeg.get();
|
||||||
if (!cli) {
|
if (!cli) {
|
||||||
dis.dispatch({action: 'message_send_failed'});
|
dis.dispatch({ action: 'message_send_failed' });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
cli.sendEvent(roomId, event.getType(), event.getContent()).then(() => {
|
cli.sendEvent(roomId, event.getType(), event.getContent()).then(() => {
|
||||||
dis.dispatch({action: 'message_sent'});
|
dis.dispatch({ action: 'message_sent' });
|
||||||
}, (err) => {
|
}, (err) => {
|
||||||
dis.dispatch({action: 'message_send_failed'});
|
dis.dispatch({ action: 'message_send_failed' });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1924,7 +1920,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
onServerConfigChange = (serverConfig: ValidatedServerConfig) => {
|
onServerConfigChange = (serverConfig: ValidatedServerConfig) => {
|
||||||
this.setState({serverConfig});
|
this.setState({ serverConfig });
|
||||||
};
|
};
|
||||||
|
|
||||||
private makeRegistrationUrl = (params: {[key: string]: string}) => {
|
private makeRegistrationUrl = (params: {[key: string]: string}) => {
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -24,7 +24,7 @@ import dis from '../../dispatcher/dispatcher';
|
||||||
import AccessibleButton from '../views/elements/AccessibleButton';
|
import AccessibleButton from '../views/elements/AccessibleButton';
|
||||||
import MatrixClientContext from "../../contexts/MatrixClientContext";
|
import MatrixClientContext from "../../contexts/MatrixClientContext";
|
||||||
import AutoHideScrollbar from "./AutoHideScrollbar";
|
import AutoHideScrollbar from "./AutoHideScrollbar";
|
||||||
import {replaceableComponent} from "../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../utils/replaceableComponent";
|
||||||
import BetaCard from "../views/beta/BetaCard";
|
import BetaCard from "../views/beta/BetaCard";
|
||||||
|
|
||||||
@replaceableComponent("structures.MyGroups")
|
@replaceableComponent("structures.MyGroups")
|
||||||
|
@ -41,19 +41,19 @@ export default class MyGroups extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
_onCreateGroupClick = () => {
|
_onCreateGroupClick = () => {
|
||||||
dis.dispatch({action: 'view_create_group'});
|
dis.dispatch({ action: 'view_create_group' });
|
||||||
};
|
};
|
||||||
|
|
||||||
_fetch() {
|
_fetch() {
|
||||||
this.context.getJoinedGroups().then((result) => {
|
this.context.getJoinedGroups().then((result) => {
|
||||||
this.setState({groups: result.groups, error: null});
|
this.setState({ groups: result.groups, error: null });
|
||||||
}, (err) => {
|
}, (err) => {
|
||||||
if (err.errcode === 'M_GUEST_ACCESS_FORBIDDEN') {
|
if (err.errcode === 'M_GUEST_ACCESS_FORBIDDEN') {
|
||||||
// Indicate that the guest isn't in any groups (which should be true)
|
// Indicate that the guest isn't in any groups (which should be true)
|
||||||
this.setState({groups: [], error: null});
|
this.setState({ groups: [], error: null });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.setState({groups: null, error: err});
|
this.setState({ groups: null, error: err });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,7 +123,7 @@ export default class MyGroups extends React.Component {
|
||||||
</div>
|
</div>
|
||||||
{/*<div className="mx_MyGroups_joinBox mx_MyGroups_headerCard">
|
{/*<div className="mx_MyGroups_joinBox mx_MyGroups_headerCard">
|
||||||
<AccessibleButton className='mx_MyGroups_headerCard_button' onClick={this._onJoinGroupClick}>
|
<AccessibleButton className='mx_MyGroups_headerCard_button' onClick={this._onJoinGroupClick}>
|
||||||
<TintableSvg src={require("../../../res/img/icons-create-room.svg")} width="50" height="50" />
|
<img src={require("../../../res/img/icons-create-room.svg")} width="50" height="50" />
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
<div className="mx_MyGroups_headerCard_content">
|
<div className="mx_MyGroups_headerCard_content">
|
||||||
<div className="mx_MyGroups_headerCard_header">
|
<div className="mx_MyGroups_headerCard_header">
|
||||||
|
|
|
@ -18,7 +18,7 @@ import * as React from "react";
|
||||||
import { ComponentClass } from "../../@types/common";
|
import { ComponentClass } from "../../@types/common";
|
||||||
import NonUrgentToastStore from "../../stores/NonUrgentToastStore";
|
import NonUrgentToastStore from "../../stores/NonUrgentToastStore";
|
||||||
import { UPDATE_EVENT } from "../../stores/AsyncStore";
|
import { UPDATE_EVENT } from "../../stores/AsyncStore";
|
||||||
import {replaceableComponent} from "../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../utils/replaceableComponent";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@ export default class NonUrgentToastContainer extends React.PureComponent<IProps,
|
||||||
}
|
}
|
||||||
|
|
||||||
private onUpdateToasts = () => {
|
private onUpdateToasts = () => {
|
||||||
this.setState({toasts: NonUrgentToastStore.instance.components});
|
this.setState({ toasts: NonUrgentToastStore.instance.components });
|
||||||
};
|
};
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
|
|
|
@ -22,6 +22,7 @@ import BaseCard from "../views/right_panel/BaseCard";
|
||||||
import { replaceableComponent } from "../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../utils/replaceableComponent";
|
||||||
import TimelinePanel from "./TimelinePanel";
|
import TimelinePanel from "./TimelinePanel";
|
||||||
import Spinner from "../views/elements/Spinner";
|
import Spinner from "../views/elements/Spinner";
|
||||||
|
import { TileShape } from "../views/rooms/EventTile";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
onClose(): void;
|
onClose(): void;
|
||||||
|
@ -48,7 +49,7 @@ export default class NotificationPanel extends React.PureComponent<IProps> {
|
||||||
manageReadMarkers={false}
|
manageReadMarkers={false}
|
||||||
timelineSet={timelineSet}
|
timelineSet={timelineSet}
|
||||||
showUrlPreview={false}
|
showUrlPreview={false}
|
||||||
tileShape="notif"
|
tileShape={TileShape.Notif}
|
||||||
empty={emptyState}
|
empty={emptyState}
|
||||||
alwaysShowTimestamps={true}
|
alwaysShowTimestamps={true}
|
||||||
/>
|
/>
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue