From 237084da7866432321ac52fcc7de74e8ec6c1075 Mon Sep 17 00:00:00 2001
From: Michael Telatynski <7t3chguy@gmail.com>
Date: Sat, 11 Apr 2020 23:46:58 +0100
Subject: [PATCH 001/196] wrap node-qrcode in a React FC and use it for
ShareDialog instead of qrcode-react
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
---
package.json | 2 +-
res/css/views/dialogs/_ShareDialog.scss | 9 +-
src/components/views/dialogs/ShareDialog.js | 4 +-
src/components/views/elements/QRCode.tsx | 50 +++++
yarn.lock | 214 ++------------------
5 files changed, 77 insertions(+), 202 deletions(-)
create mode 100644 src/components/views/elements/QRCode.tsx
diff --git a/package.json b/package.json
index 616f3f541e..02ec206ee3 100644
--- a/package.json
+++ b/package.json
@@ -86,7 +86,6 @@
"project-name-generator": "^2.1.7",
"prop-types": "^15.5.8",
"qrcode": "^1.4.4",
- "qrcode-react": "^0.1.16",
"qs": "^6.6.0",
"react": "^16.9.0",
"react-addons-css-transition-group": "15.6.2",
@@ -118,6 +117,7 @@
"@babel/register": "^7.7.4",
"@peculiar/webcrypto": "^1.0.22",
"@types/classnames": "^2.2.10",
+ "@types/qrcode": "^1.3.4",
"@types/react": "16.9",
"babel-eslint": "^10.0.3",
"babel-jest": "^24.9.0",
diff --git a/res/css/views/dialogs/_ShareDialog.scss b/res/css/views/dialogs/_ShareDialog.scss
index 9a2f67dea3..3c984bbd1b 100644
--- a/res/css/views/dialogs/_ShareDialog.scss
+++ b/res/css/views/dialogs/_ShareDialog.scss
@@ -64,12 +64,15 @@ limitations under the License.
.mx_ShareDialog_qrcode_container {
float: left;
- background-color: #ffffff;
- padding: 5px; // makes qr code more readable in dark theme
- border-radius: 5px;
height: 256px;
width: 256px;
margin-right: 64px;
+
+ img {
+ width: 100%;
+ height: 100%;
+ border-radius: 8px;
+ }
}
.mx_ShareDialog_social_container {
diff --git a/src/components/views/dialogs/ShareDialog.js b/src/components/views/dialogs/ShareDialog.js
index 1bc9decd39..a2554c3dcf 100644
--- a/src/components/views/dialogs/ShareDialog.js
+++ b/src/components/views/dialogs/ShareDialog.js
@@ -19,7 +19,7 @@ import PropTypes from 'prop-types';
import {Room, User, Group, RoomMember, MatrixEvent} from 'matrix-js-sdk';
import * as sdk from '../../../index';
import { _t } from '../../../languageHandler';
-import QRCode from 'qrcode-react';
+import QRCode from "../elements/QRCode";
import {RoomPermalinkCreator, makeGroupPermalink, makeUserPermalink} from "../../../utils/permalinks/Permalinks";
import * as ContextMenu from "../../structures/ContextMenu";
import {toRightOf} from "../../structures/ContextMenu";
@@ -213,7 +213,7 @@ export default class ShareDialog extends React.Component {
-
+
{
diff --git a/src/components/views/elements/QRCode.tsx b/src/components/views/elements/QRCode.tsx
new file mode 100644
index 0000000000..5e5db8cf93
--- /dev/null
+++ b/src/components/views/elements/QRCode.tsx
@@ -0,0 +1,50 @@
+/*
+Copyright 2020 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+import * as React from "react";
+import {toDataURL, QRCodeSegment, QRCodeToDataURLOptions} from "qrcode";
+
+import {_t} from "../../../languageHandler";
+import Spinner from "./Spinner";
+
+interface IProps extends QRCodeToDataURLOptions {
+ data: string | QRCodeSegment[];
+}
+
+const defaultOptions: QRCodeToDataURLOptions = {
+ errorCorrectionLevel: 'L', // we want it as trivial-looking as possible
+};
+
+const QRCode: React.FC = ({data, ...options}) => {
+ const [dataUri, setUri] = React.useState(null);
+ React.useEffect(() => {
+ let cancelled = false;
+ toDataURL(data, {...defaultOptions, ...options}).then(uri => {
+ if (cancelled) return;
+ setUri(uri);
+ });
+ return () => {
+ cancelled = true;
+ };
+ }, [data, options]);
+
+
+ return
{this._renderDiscoverySection()}
{this._renderIntegrationManagerSection() /* Has its own title */}
diff --git a/src/components/views/settings/tabs/user/StyleUserSettingsTab.js b/src/components/views/settings/tabs/user/StyleUserSettingsTab.js
new file mode 100644
index 0000000000..5c68f214d4
--- /dev/null
+++ b/src/components/views/settings/tabs/user/StyleUserSettingsTab.js
@@ -0,0 +1,233 @@
+/*
+Copyright 2019 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.
+*/
+
+import React from 'react';
+import {_t} from "../../../../../languageHandler";
+import SettingsStore, {SettingLevel} from "../../../../../settings/SettingsStore";
+import * as sdk from "../../../../../index";
+import {enumerateThemes, ThemeWatcher} from "../../../../../theme";
+import Field from "../../../elements/Field";
+
+export default class StyleUserSettingsTab extends React.Component {
+ constructor() {
+ super();
+
+ this.state = {
+ fontSize: SettingsStore.getValue("font_size", null),
+ ...this._calculateThemeState(),
+ customThemeUrl: "",
+ customThemeMessage: {isError: false, text: ""},
+ }
+ }
+
+ _calculateThemeState() {
+ // We have to mirror the logic from ThemeWatcher.getEffectiveTheme so we
+ // show the right values for things.
+
+ const themeChoice = SettingsStore.getValueAt(SettingLevel.ACCOUNT, "theme");
+ const systemThemeExplicit = SettingsStore.getValueAt(
+ SettingLevel.DEVICE, "use_system_theme", null, false, true);
+ const themeExplicit = SettingsStore.getValueAt(
+ SettingLevel.DEVICE, "theme", null, false, true);
+
+ // If the user has enabled system theme matching, use that.
+ if (systemThemeExplicit) {
+ return {
+ theme: themeChoice,
+ useSystemTheme: true,
+ };
+ }
+
+ // If the user has set a theme explicitly, use that (no system theme matching)
+ if (themeExplicit) {
+ return {
+ theme: themeChoice,
+ useSystemTheme: false,
+ };
+ }
+
+ // Otherwise assume the defaults for the settings
+ return {
+ theme: themeChoice,
+ useSystemTheme: SettingsStore.getValueAt(SettingLevel.DEVICE, "use_system_theme"),
+ };
+ }
+
+ _onThemeChange = (e) => {
+ const newTheme = e.target.value;
+ if (this.state.theme === newTheme) return;
+
+ // doing getValue in the .catch will still return the value we failed to set,
+ // so remember what the value was before we tried to set it so we can revert
+ const oldTheme = SettingsStore.getValue('theme');
+ SettingsStore.setValue("theme", null, SettingLevel.ACCOUNT, newTheme).catch(() => {
+ dis.dispatch({action: 'recheck_theme'});
+ this.setState({theme: oldTheme});
+ });
+ this.setState({theme: newTheme});
+ // The settings watcher doesn't fire until the echo comes back from the
+ // server, so to make the theme change immediately we need to manually
+ // do the dispatch now
+ // XXX: The local echoed value appears to be unreliable, in particular
+ // when settings custom themes(!) so adding forceTheme to override
+ // the value from settings.
+ dis.dispatch({action: 'recheck_theme', forceTheme: newTheme});
+ };
+
+ _onUseSystemThemeChanged = (checked) => {
+ this.setState({useSystemTheme: checked});
+ SettingsStore.setValue("use_system_theme", null, SettingLevel.DEVICE, checked);
+ dis.dispatch({action: 'recheck_theme'});
+ };
+
+ _onFontSizeChanged = (size) => {
+ let parsed_size = isNaN(parseInt(size))?SettingsStore.getDefaultValue("font_size"):parseFloat(size);
+ this.setState({fontSize: parsed_size})
+ SettingsStore.setValue("font_size", null, SettingLevel.DEVICE, parsed_size)
+ };
+
+ _onAddCustomTheme = async () => {
+ let currentThemes = SettingsStore.getValue("custom_themes");
+ if (!currentThemes) currentThemes = [];
+ currentThemes = currentThemes.map(c => c); // cheap clone
+
+ if (this._themeTimer) {
+ clearTimeout(this._themeTimer);
+ }
+
+ try {
+ const r = await fetch(this.state.customThemeUrl);
+ const themeInfo = await r.json();
+ if (!themeInfo || typeof(themeInfo['name']) !== 'string' || typeof(themeInfo['colors']) !== 'object') {
+ this.setState({customThemeMessage: {text: _t("Invalid theme schema."), isError: true}});
+ return;
+ }
+ currentThemes.push(themeInfo);
+ } catch (e) {
+ console.error(e);
+ this.setState({customThemeMessage: {text: _t("Error downloading theme information."), isError: true}});
+ return; // Don't continue on error
+ }
+
+ await SettingsStore.setValue("custom_themes", null, SettingLevel.ACCOUNT, currentThemes);
+ this.setState({customThemeUrl: "", customThemeMessage: {text: _t("Theme added!"), isError: false}});
+
+ this._themeTimer = setTimeout(() => {
+ this.setState({customThemeMessage: {text: "", isError: false}});
+ }, 3000);
+ };
+
+ _onCustomThemeChange = (e) => {
+ this.setState({customThemeUrl: e.target.value});
+ };
+
+ render() {
+ return (
+
{dots}
@@ -79,18 +85,24 @@ type DotIProps = {
// The label on the dot
label: string,
+
+ // Whether the slider is disabled
+ disabled: boolean;
}
class Dot extends React.Component {
render(): React.ReactNode {
- const className = "mx_Slider_dot" + (this.props.active ? " mx_Slider_dotActive" : "");
+ let className = "mx_Slider_dot"
+ if (!this.props.disabled && this.props.active) {
+ className += " mx_Slider_dotActive";
+ }
return
- {this.props.label}
-
+ {this.props.label}
+
;
}
From 1486beeaf42903fe75168a16ee3c45e7f516eb39 Mon Sep 17 00:00:00 2001
From: Jorik Schellekens
Date: Wed, 22 Apr 2020 12:02:23 +0100
Subject: [PATCH 068/196] Make slider indpendent of settings styling
---
res/css/views/elements/_Slider.scss | 2 --
1 file changed, 2 deletions(-)
diff --git a/res/css/views/elements/_Slider.scss b/res/css/views/elements/_Slider.scss
index 7e9acefa06..2132381591 100644
--- a/res/css/views/elements/_Slider.scss
+++ b/res/css/views/elements/_Slider.scss
@@ -17,8 +17,6 @@ limitations under the License.
.mx_Slider {
position: relative;
margin: 0px;
-
- @mixin mx_Settings_fullWidthField;
}
.mx_Slider_dotContainer {
From 98799611cf31b5e2036a61ecac60d9b46d4f29b1 Mon Sep 17 00:00:00 2001
From: Jorik Schellekens
Date: Wed, 22 Apr 2020 15:37:46 +0100
Subject: [PATCH 069/196] Remove padding for alignment reasons
---
res/css/views/elements/_Slider.scss | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/res/css/views/elements/_Slider.scss b/res/css/views/elements/_Slider.scss
index 2132381591..83f100ff92 100644
--- a/res/css/views/elements/_Slider.scss
+++ b/res/css/views/elements/_Slider.scss
@@ -17,6 +17,7 @@ limitations under the License.
.mx_Slider {
position: relative;
margin: 0px;
+ flex-grow: 1;
}
.mx_Slider_dotContainer {
@@ -71,7 +72,6 @@ limitations under the License.
width: 1rem;
border-radius: 50%;
background-color: $Slider-background-color;
- margin-bottom: 5px;
z-index: 0;
}
From f5d65907512971f4592f9be67d7c6ab2917ff0ef Mon Sep 17 00:00:00 2001
From: Jorik Schellekens
Date: Wed, 22 Apr 2020 16:11:01 +0100
Subject: [PATCH 070/196] Have max and min font configured in settings
---
src/components/structures/MatrixChat.js | 2 +-
src/fontSize.js | 11 ++++++-----
src/settings/Settings.js | 10 ++++++++++
3 files changed, 17 insertions(+), 6 deletions(-)
diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js
index 1845e0011d..602d85f048 100644
--- a/src/components/structures/MatrixChat.js
+++ b/src/components/structures/MatrixChat.js
@@ -266,7 +266,7 @@ export default createReactClass({
this.dispatcherRef = dis.register(this.onAction);
this._themeWatcher = new ThemeWatcher();
- this._fontWatcher = new FontWatcher(10, 20);
+ this._fontWatcher = new FontWatcher();
this._themeWatcher.start();
this._fontWatcher.start();
diff --git a/src/fontSize.js b/src/fontSize.js
index 30c69b7428..2e37921ee6 100644
--- a/src/fontSize.js
+++ b/src/fontSize.js
@@ -18,9 +18,7 @@ import dis from './dispatcher';
import SettingsStore, {SettingLevel} from './settings/SettingsStore';
export class FontWatcher {
- constructor(minSize, maxSize) {
- this._min_size = minSize;
- this._max_size = maxSize;
+ constructor() {
this._dispatcherRef = null;
}
@@ -40,8 +38,11 @@ export class FontWatcher {
};
_setRootFontSize = size => {
- let fontSize = this._min_size < size ? size : this._min_size;
- fontSize = fontSize < this._max_size ? fontSize : this._max_size;
+ const min = SettingsStore.getValue("font_size_min");
+ const max = SettingsStore.getValue("font_size_max");
+
+ const fontSize = Math.max(Math.min(max, size), min);
+
if (fontSize != size) {
SettingsStore.setValue("font_size", null, SettingLevel.Device, fontSize);
}
diff --git a/src/settings/Settings.js b/src/settings/Settings.js
index a044027baf..b144b07e84 100644
--- a/src/settings/Settings.js
+++ b/src/settings/Settings.js
@@ -177,6 +177,16 @@ export const SETTINGS = {
default: 16,
controller: new FontSizeController(),
},
+ "font_size_min": {
+ displayName: _td("Min font size"),
+ supportedLevels: LEVELS_ACCOUNT_SETTINGS,
+ default: 14,
+ },
+ "font_size_max": {
+ displayName: _td("Max font size"),
+ supportedLevels: LEVELS_ACCOUNT_SETTINGS,
+ default: 24,
+ },
"MessageComposerInput.suggestEmoji": {
supportedLevels: LEVELS_ACCOUNT_SETTINGS,
displayName: _td('Enable Emoji suggestions while typing'),
From fe175bb9a89d87307805582040e1f3295a2d0475 Mon Sep 17 00:00:00 2001
From: Jorik Schellekens
Date: Wed, 22 Apr 2020 17:31:49 +0100
Subject: [PATCH 071/196] Styling for the font slider
---
.../tabs/user/_AppearanceUserSettingsTab.scss | 20 +++++++++++++++++++
.../tabs/user/AppearanceUserSettingsTab.js | 18 +++++++++++------
2 files changed, 32 insertions(+), 6 deletions(-)
diff --git a/res/css/views/settings/tabs/user/_AppearanceUserSettingsTab.scss b/res/css/views/settings/tabs/user/_AppearanceUserSettingsTab.scss
index 8c80a35e40..e4285e248c 100644
--- a/res/css/views/settings/tabs/user/_AppearanceUserSettingsTab.scss
+++ b/res/css/views/settings/tabs/user/_AppearanceUserSettingsTab.scss
@@ -14,7 +14,27 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
+.mx_AppearanceUserSettingsTab_fontSlider,
.mx_AppearanceUserSettingsTab_themeSection .mx_Field,
.mx_AppearanceUserSettingsTab_fontScaling .mx_Field {
@mixin mx_Settings_fullWidthField;
}
+
+.mx_AppearanceUserSettingsTab_fontSlider {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ padding: 10px;
+ background: #FFFFFF;
+ border-radius: 10px;
+}
+
+.mx_AppearanceUserSettingsTab_fontSlider_smallText {
+ font-size: 15px;
+ padding-right: 10px;
+}
+
+.mx_AppearanceUserSettingsTab_fontSlider_largeText {
+ font-size: 18px;
+ padding-left: 10px;
+}
diff --git a/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.js b/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.js
index 046184da69..e1bbaab2cc 100644
--- a/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.js
+++ b/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.js
@@ -25,6 +25,7 @@ import Field from "../../../elements/Field";
import Slider from "../../../elements/Slider";
import AccessibleButton from "../../../elements/AccessibleButton";
import dis from "../../../../../dispatcher";
+import _range from "lodash/range";
export default class StyleUserSettingsTab extends React.Component {
constructor() {
@@ -225,12 +226,17 @@ export default class StyleUserSettingsTab extends React.Component {
_renderFontSection() {
return
{_t("Font size")}
- {}}
- />
+
+
Aa
+ {}}
+ disabled={false}
+ />
+
Aa
+
Date: Thu, 23 Apr 2020 10:27:41 +0100
Subject: [PATCH 072/196] Linearly interpolate between value intervals.
---
src/components/views/elements/Slider.tsx | 36 ++++++++++++++++---
.../tabs/user/AppearanceUserSettingsTab.js | 2 +-
2 files changed, 32 insertions(+), 6 deletions(-)
diff --git a/src/components/views/elements/Slider.tsx b/src/components/views/elements/Slider.tsx
index ad859bfe82..a9fc41c8cc 100644
--- a/src/components/views/elements/Slider.tsx
+++ b/src/components/views/elements/Slider.tsx
@@ -35,14 +35,40 @@ type IProps = {
}
export default class Slider extends React.Component {
+ // offset is a terrible inverse approximation.
+ // if the values represents some function f(x) = y where x is the
+ // index of the array and y = values[x] then offset(f, y) = x
+ // s.t f(x) = y.
+ // it assumes a monotonic function and interpolates linearly between
+ // y values.
+ // Offset is used for finding the location of a value on a
+ // non linear slider.
_offset(values: number[], value: number): number {
- const min = values[0];
- const max = values[values.length - 1];
+ // the index of the first number greater than value.
+ let closest = values.reduce((prev, curr) => {
+ return (value > curr ? prev + 1 : prev);
+ }, 0);
- // Clamp value between min and max
- value = Math.min(Math.max(value, min), max);
+ // Off the left
+ if (closest == 0) {
+ return 0;
+ }
+
+ // Off the right
+ if (closest == values.length) {
+ return 100;
+ }
+
+ // Now
+ const closestLessValue = values[closest - 1];
+ const closestGreaterValue = values[closest];
+
+ const intervalWidth = 1 / (values.length - 1);
+
+ const linearInterpolation = (value - closestLessValue) / (closestGreaterValue - closestLessValue)
+
+ return 100 * (closest - 1 + linearInterpolation) * intervalWidth
- return (value - min) / (max - min) * 100;
}
render(): React.ReactNode {
diff --git a/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.js b/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.js
index e1bbaab2cc..949b3bed31 100644
--- a/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.js
+++ b/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.js
@@ -229,7 +229,7 @@ export default class StyleUserSettingsTab extends React.Component {
Aa
{}}
From a16fe09d4275b64939d34f56b1720cb00ef1e93e Mon Sep 17 00:00:00 2001
From: Jorik Schellekens
Date: Thu, 23 Apr 2020 10:58:00 +0100
Subject: [PATCH 073/196] Use em to detach slider from root font-size
---
res/css/views/elements/_Slider.scss | 22 +++++++++----------
.../tabs/user/_AppearanceUserSettingsTab.scss | 1 +
src/components/views/elements/Slider.tsx | 2 +-
3 files changed, 13 insertions(+), 12 deletions(-)
diff --git a/res/css/views/elements/_Slider.scss b/res/css/views/elements/_Slider.scss
index 83f100ff92..f6982865db 100644
--- a/res/css/views/elements/_Slider.scss
+++ b/res/css/views/elements/_Slider.scss
@@ -30,30 +30,30 @@ limitations under the License.
display: flex;
box-sizing: border-box;
position: absolute;
- height: 1rem;
+ height: 1em;
width: 100%;
- padding: 0 0.5rem; // half the width of a dot.
+ padding: 0 0.5em; // half the width of a dot.
align-items: center;
}
.mx_Slider_bar > hr {
width: 100%;
- border: 0.2rem solid $Slider-background-color;
+ border: 0.2em solid $Slider-background-color;
}
.mx_Slider_selection {
display: flex;
align-items: center;
- width: calc(100% - 1rem); // 2 * half the width of a dot
- height: 1rem;
+ width: calc(100% - 1em); // 2 * half the width of a dot
+ height: 1em;
position: absolute;
}
.mx_Slider_selectionDot {
transition: left 0.25s;
position: absolute;
- width: 1.1rem;
- height: 1.1rem;
+ width: 1.1em;
+ height: 1.1em;
background-color: $Slider-selection-color;
border-radius: 50%;
box-shadow: 0 0 6px lightgrey;
@@ -63,13 +63,13 @@ limitations under the License.
.mx_Slider_selection > hr {
transition: width 0.25s;
margin: 0;
- border: 0.2rem solid $Slider-selection-color;
+ border: 0.2em solid $Slider-selection-color;
}
.mx_Slider_dot {
transition: background-color 0.2s ease-in;
- height: 1rem;
- width: 1rem;
+ height: 1em;
+ width: 1em;
border-radius: 50%;
background-color: $Slider-background-color;
z-index: 0;
@@ -89,7 +89,7 @@ limitations under the License.
// The following is a hack to center the labels without adding
// any width to the slider's dots.
.mx_Slider_labelContainer {
- width: 1rem;
+ width: 1em;
}
.mx_Slider_label {
diff --git a/res/css/views/settings/tabs/user/_AppearanceUserSettingsTab.scss b/res/css/views/settings/tabs/user/_AppearanceUserSettingsTab.scss
index e4285e248c..28a2510508 100644
--- a/res/css/views/settings/tabs/user/_AppearanceUserSettingsTab.scss
+++ b/res/css/views/settings/tabs/user/_AppearanceUserSettingsTab.scss
@@ -27,6 +27,7 @@ limitations under the License.
padding: 10px;
background: #FFFFFF;
border-radius: 10px;
+ font-size: 10px;
}
.mx_AppearanceUserSettingsTab_fontSlider_smallText {
diff --git a/src/components/views/elements/Slider.tsx b/src/components/views/elements/Slider.tsx
index a9fc41c8cc..6ec044da41 100644
--- a/src/components/views/elements/Slider.tsx
+++ b/src/components/views/elements/Slider.tsx
@@ -89,7 +89,7 @@ export default class Slider extends React.Component {
{ this.props.disabled ?
null :
;
}
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index a3051cbb91..2c3239900d 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -407,6 +407,9 @@
"Show info about bridges in room settings": "Show info about bridges in room settings",
"Show padlocks on invite only rooms": "Show padlocks on invite only rooms",
"Font size": "Font size",
+ "Min font size": "Min font size",
+ "Max font size": "Max font size",
+ "Custom font size": "Custom font size",
"Enable Emoji suggestions while typing": "Enable Emoji suggestions while typing",
"Use compact timeline layout": "Use compact timeline layout",
"Show a placeholder for removed messages": "Show a placeholder for removed messages",
diff --git a/src/settings/Settings.js b/src/settings/Settings.js
index b144b07e84..e0e34179f3 100644
--- a/src/settings/Settings.js
+++ b/src/settings/Settings.js
@@ -187,6 +187,11 @@ export const SETTINGS = {
supportedLevels: LEVELS_ACCOUNT_SETTINGS,
default: 24,
},
+ "useCustomFontSize": {
+ displayName: _td("Custom font size"),
+ supportedLevels: LEVELS_ACCOUNT_SETTINGS,
+ default: false,
+ },
"MessageComposerInput.suggestEmoji": {
supportedLevels: LEVELS_ACCOUNT_SETTINGS,
displayName: _td('Enable Emoji suggestions while typing'),
From 600a812227acafd8a15732cdabed3b6899415735 Mon Sep 17 00:00:00 2001
From: Jorik Schellekens
Date: Thu, 23 Apr 2020 12:20:10 +0100
Subject: [PATCH 078/196] Add brush icon for appearance setting tab
---
res/css/views/dialogs/_UserSettingsDialog.scss | 4 ++++
res/img/feather-customised/brush.svg | 5 +++++
src/components/views/dialogs/UserSettingsDialog.js | 2 +-
3 files changed, 10 insertions(+), 1 deletion(-)
create mode 100644 res/img/feather-customised/brush.svg
diff --git a/res/css/views/dialogs/_UserSettingsDialog.scss b/res/css/views/dialogs/_UserSettingsDialog.scss
index 4d831d7858..7adcc58c4e 100644
--- a/res/css/views/dialogs/_UserSettingsDialog.scss
+++ b/res/css/views/dialogs/_UserSettingsDialog.scss
@@ -21,6 +21,10 @@ limitations under the License.
mask-image: url('$(res)/img/feather-customised/settings.svg');
}
+.mx_UserSettingsDialog_appearanceIcon::before {
+ mask-image: url('$(res)/img/feather-customised/brush.svg');
+}
+
.mx_UserSettingsDialog_voiceIcon::before {
mask-image: url('$(res)/img/feather-customised/phone.svg');
}
diff --git a/res/img/feather-customised/brush.svg b/res/img/feather-customised/brush.svg
new file mode 100644
index 0000000000..d7f2738629
--- /dev/null
+++ b/res/img/feather-customised/brush.svg
@@ -0,0 +1,5 @@
+
diff --git a/src/components/views/dialogs/UserSettingsDialog.js b/src/components/views/dialogs/UserSettingsDialog.js
index 91ab203753..bf06b8749f 100644
--- a/src/components/views/dialogs/UserSettingsDialog.js
+++ b/src/components/views/dialogs/UserSettingsDialog.js
@@ -69,7 +69,7 @@ export default class UserSettingsDialog extends React.Component {
));
tabs.push(new Tab(
_td("Appearance"),
- "mx_userSettingsDialog_styleIcon",
+ "mx_UserSettingsDialog_appearanceIcon",
,
));
tabs.push(new Tab(
From e5cb14929602cdc71887b3e95c54f546d9ccdda0 Mon Sep 17 00:00:00 2001
From: Jorik Schellekens
Date: Thu, 23 Apr 2020 13:52:08 +0100
Subject: [PATCH 079/196] Handle fontslider input errors correctly
---
.../tabs/user/AppearanceUserSettingsTab.js | 33 ++++++++++++++++---
src/i18n/strings/en_EN.json | 3 ++
2 files changed, 31 insertions(+), 5 deletions(-)
diff --git a/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.js b/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.js
index ceb3241b8b..4144605999 100644
--- a/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.js
+++ b/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.js
@@ -101,11 +101,33 @@ export default class StyleUserSettingsTab extends React.Component {
};
_onFontSizeChanged = (size) => {
- const parsedSize = isNaN(parseInt(size)) ? SettingsStore.getDefaultValue("font_size") : parseFloat(size);
- this.setState({fontSize: parsedSize});
- SettingsStore.setValue("font_size", null, SettingLevel.DEVICE, parsedSize);
+ this.setState({fontSize: size});
+ SettingsStore.setValue("font_size", null, SettingLevel.DEVICE, size);
};
+ _onValidateFontSize = ({value}) => {
+ console.log({value});
+ this.setState({fontSize: value});
+
+ const parsedSize = parseFloat(value);
+ const min = SettingsStore.getValue("font_size_min");
+ const max = SettingsStore.getValue("font_size_max");
+
+ if (isNaN(parsedSize)) {
+ return {valid: false, feedback: _t("Size must be a number")};
+ }
+
+ console.log({min});
+ console.log({max});
+ console.log({parsedSize});
+ if (!(min <= parsedSize && parsedSize <= max)) {
+ return {valid: false, feedback: _t('Custom font size can only be between %(min)s pt and %(max)s pt', {min, max})};
+ }
+
+ SettingsStore.setValue("font_size", null, SettingLevel.DEVICE, value);
+ return {valid: true, feedback: _t('Use between %(min)s pt and %(max)s pt', {min, max})};
+ }
+
_onAddCustomTheme = async () => {
let currentThemes = SettingsStore.getValue("custom_themes");
if (!currentThemes) currentThemes = [];
@@ -247,10 +269,11 @@ export default class StyleUserSettingsTab extends React.Component {
type="text"
label={_t("Font size")}
autoComplete="off"
- placeholder={SettingsStore.getValue("font_size", null).toString()}
+ placeholder={this.state.fontSize}
value={this.state.fontSize}
id="font_size_field"
- onChange={(ev) => this._onFontSizeChanged(ev.target.value)}
+ onValidate={this._onValidateFontSize}
+ onChange={({value}) => this.setState({fontSize: value})}
disabled={!this.state.useCustomFontSize}
/>
;
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index 2c3239900d..fa3d5e3f41 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -747,6 +747,9 @@
"Use an Integration Manager to manage bots, widgets, and sticker packs.": "Use an Integration Manager to manage bots, widgets, and sticker packs.",
"Manage integrations": "Manage integrations",
"Integration Managers receive configuration data, and can modify widgets, send room invites, and set power levels on your behalf.": "Integration Managers receive configuration data, and can modify widgets, send room invites, and set power levels on your behalf.",
+ "Size must be a number": "Size must be a number",
+ "Custom font size can only be between %(min)s pt and %(max)s pt": "Custom font size can only be between %(min)s pt and %(max)s pt",
+ "Use between %(min)s pt and %(max)s pt": "Use between %(min)s pt and %(max)s pt",
"Invalid theme schema.": "Invalid theme schema.",
"Error downloading theme information.": "Error downloading theme information.",
"Theme added!": "Theme added!",
From a087f5ea400fd7a8fc7e6f207fdb15def6e4e2f3 Mon Sep 17 00:00:00 2001
From: Jorik Schellekens
Date: Thu, 23 Apr 2020 13:55:10 +0100
Subject: [PATCH 080/196] Lint
---
.../tabs/user/AppearanceUserSettingsTab.js | 14 +++++++++-----
1 file changed, 9 insertions(+), 5 deletions(-)
diff --git a/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.js b/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.js
index 4144605999..5c285d12e6 100644
--- a/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.js
+++ b/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.js
@@ -117,11 +117,11 @@ export default class StyleUserSettingsTab extends React.Component {
return {valid: false, feedback: _t("Size must be a number")};
}
- console.log({min});
- console.log({max});
- console.log({parsedSize});
if (!(min <= parsedSize && parsedSize <= max)) {
- return {valid: false, feedback: _t('Custom font size can only be between %(min)s pt and %(max)s pt', {min, max})};
+ return {
+ valid: false,
+ feedback: _t('Custom font size can only be between %(min)s pt and %(max)s pt', {min, max}),
+ };
}
SettingsStore.setValue("font_size", null, SettingLevel.DEVICE, value);
@@ -252,7 +252,11 @@ export default class StyleUserSettingsTab extends React.Component {
Aa
{}}
From 06f4eca05d51aaff8986406296ccb0844a66dfe4 Mon Sep 17 00:00:00 2001
From: Jorik Schellekens
Date: Thu, 23 Apr 2020 14:15:33 +0100
Subject: [PATCH 081/196] Background opacity
---
res/themes/light/css/_light.scss | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/res/themes/light/css/_light.scss b/res/themes/light/css/_light.scss
index b576b57778..ed7eae48f7 100644
--- a/res/themes/light/css/_light.scss
+++ b/res/themes/light/css/_light.scss
@@ -307,7 +307,7 @@ $breadcrumb-placeholder-bg-color: #e8eef5;
$user-tile-hover-bg-color: $header-panel-bg-color;
// FontSlider colors
-$font-slider-bg-color: $input-darker-bg-color;
+$font-slider-bg-color: rgba($input-darker-bg-color, 0.2);
// ***** Mixins! *****
From 4b4599c1d81b4200f41158cb8febe2fcb9121c3a Mon Sep 17 00:00:00 2001
From: Jorik Schellekens
Date: Thu, 23 Apr 2020 14:39:11 +0100
Subject: [PATCH 082/196] tslint
---
src/components/views/elements/Slider.tsx | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/components/views/elements/Slider.tsx b/src/components/views/elements/Slider.tsx
index 6ec044da41..559bdd9ce2 100644
--- a/src/components/views/elements/Slider.tsx
+++ b/src/components/views/elements/Slider.tsx
@@ -36,7 +36,7 @@ type IProps = {
export default class Slider extends React.Component {
// offset is a terrible inverse approximation.
- // if the values represents some function f(x) = y where x is the
+ // if the values represents some function f(x) = y where x is the
// index of the array and y = values[x] then offset(f, y) = x
// s.t f(x) = y.
// it assumes a monotonic function and interpolates linearly between
@@ -50,16 +50,16 @@ export default class Slider extends React.Component {
}, 0);
// Off the left
- if (closest == 0) {
+ if (closest === 0) {
return 0;
}
// Off the right
- if (closest == values.length) {
+ if (closest === values.length) {
return 100;
}
- // Now
+ // Now
const closestLessValue = values[closest - 1];
const closestGreaterValue = values[closest];
From 3962c98c9beaeee3f1685e63fe3604ed8a1a68eb Mon Sep 17 00:00:00 2001
From: Pauli Virtanen
Date: Thu, 23 Apr 2020 22:53:02 +0300
Subject: [PATCH 083/196] Ensure PersistedElements are refreshed when AuxPanel
scrolls
If the screen is not tall enough, AuxPanel starts scrolling its content.
If it contains PersistedElements, they need to be notified about
scrolling as they only listen on resize events to move their element.
Signed-off-by: Pauli Virtanen
---
src/components/views/rooms/AuxPanel.js | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/src/components/views/rooms/AuxPanel.js b/src/components/views/rooms/AuxPanel.js
index e102b0dba4..00bdb1c45a 100644
--- a/src/components/views/rooms/AuxPanel.js
+++ b/src/components/views/rooms/AuxPanel.js
@@ -141,6 +141,15 @@ export default createReactClass({
return counters;
},
+ _onScroll: function(rect) {
+ if (this.props.onResize) {
+ this.props.onResize();
+ }
+
+ /* Force refresh of PersistedElements which may be partially hidden */
+ window.dispatchEvent(new Event('resize'));
+ },
+
render: function() {
const CallView = sdk.getComponent("voip.CallView");
const TintableSvg = sdk.getComponent("elements.TintableSvg");
@@ -265,7 +274,7 @@ export default createReactClass({
}
return (
-
+
{ stateViews }
{ appsDrawer }
{ fileDropTarget }
From d690d4bed2cb1562fface956ed0c4e34e4e35c54 Mon Sep 17 00:00:00 2001
From: Pauli Virtanen
Date: Tue, 21 Apr 2020 01:19:39 +0300
Subject: [PATCH 084/196] Prevent PersistedElements overflowing scrolled areas
As the DOM element is not in reality contained inside "the parent",
it may overflow the area if the parent gets partially hidden by
scrolling etc.
To make the effect visually less annoying, emulate this by clipping to
the element wrapper. This is not a full general-purpose fix, but
improves the current situation.
Signed-off-by: Pauli Virtanen
---
res/css/views/rooms/_AppsDrawer.scss | 4 ++
.../views/elements/PersistedElement.js | 58 ++++++++++++++++++-
2 files changed, 60 insertions(+), 2 deletions(-)
diff --git a/res/css/views/rooms/_AppsDrawer.scss b/res/css/views/rooms/_AppsDrawer.scss
index 1b1bab67bc..e4743f189e 100644
--- a/res/css/views/rooms/_AppsDrawer.scss
+++ b/res/css/views/rooms/_AppsDrawer.scss
@@ -96,6 +96,10 @@ $AppsDrawerBodyHeight: 273px;
height: $AppsDrawerBodyHeight;
}
+.mx_AppTile_persistedWrapper > div {
+ height: 100%;
+}
+
.mx_AppTile_mini .mx_AppTile_persistedWrapper {
height: 114px;
}
diff --git a/src/components/views/elements/PersistedElement.js b/src/components/views/elements/PersistedElement.js
index 53f2501f19..18fa2aafef 100644
--- a/src/components/views/elements/PersistedElement.js
+++ b/src/components/views/elements/PersistedElement.js
@@ -156,16 +156,70 @@ export default class PersistedElement extends React.Component {
child.style.display = visible ? 'block' : 'none';
}
+ /*
+ * Clip element bounding rectangle to that of the parent elements.
+ * This is not a full visibility check, but prevents the persisted
+ * element from overflowing parent containers when inside a scrolled
+ * area.
+ */
+ _getClippedBoundingClientRect(element) {
+ let parentElement = element.parentElement;
+ let rect = element.getBoundingClientRect();
+
+ rect = new DOMRect(rect.left, rect.top, rect.width, rect.height);
+
+ while (parentElement) {
+ const parentRect = parentElement.getBoundingClientRect();
+
+ if (parentRect.left > rect.left) {
+ rect.width = rect.width - (parentRect.left - rect.left);
+ rect.x = parentRect.x;
+ }
+
+ if (parentRect.top > rect.top) {
+ rect.height = rect.height - (parentRect.top - rect.top);
+ rect.y = parentRect.y;
+ }
+
+ if (parentRect.right < rect.right) {
+ rect.width = rect.width - (rect.right - parentRect.right);
+ }
+
+ if (parentRect.bottom < rect.bottom) {
+ rect.height = rect.height - (rect.bottom - parentRect.bottom);
+ }
+
+ parentElement = parentElement.parentElement;
+ }
+
+ if (rect.width < 0) rect.width = 0;
+ if (rect.height < 0) rect.height = 0;
+
+ return rect;
+ }
+
updateChildPosition(child, parent) {
if (!child || !parent) return;
const parentRect = parent.getBoundingClientRect();
+ const clipRect = this._getClippedBoundingClientRect(parent);
+
+ Object.assign(child.parentElement.style, {
+ position: 'absolute',
+ top: clipRect.top + 'px',
+ left: clipRect.left + 'px',
+ width: clipRect.width + 'px',
+ height: clipRect.height + 'px',
+ overflow: "hidden",
+ });
+
Object.assign(child.style, {
position: 'absolute',
- top: parentRect.top + 'px',
- left: parentRect.left + 'px',
+ top: (parentRect.top - clipRect.top) + 'px',
+ left: (parentRect.left - clipRect.left) + 'px',
width: parentRect.width + 'px',
height: parentRect.height + 'px',
+ overflow: "hidden",
});
}
From bfba5e6cfe8e2be24a135af072a6c0b2a41dbfbb Mon Sep 17 00:00:00 2001
From: Jorik Schellekens
Date: Mon, 27 Apr 2020 16:57:38 +0100
Subject: [PATCH 085/196] Fix member info avatar size
---
src/components/views/avatars/BaseAvatar.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/components/views/avatars/BaseAvatar.js b/src/components/views/avatars/BaseAvatar.js
index a17124b9ad..cbe083f3a2 100644
--- a/src/components/views/avatars/BaseAvatar.js
+++ b/src/components/views/avatars/BaseAvatar.js
@@ -208,8 +208,8 @@ export default createReactClass({
onClick={onClick}
onError={this.onError}
style={{
- width: toRem(width),
- height: toRem(height)
+ width: {width},
+ height: {height},
}}
title={title} alt=""
inputRef={inputRef}
From a8407c9508a38b93465ab030e4d99ab8c86212ce Mon Sep 17 00:00:00 2001
From: Jorik Schellekens
Date: Tue, 28 Apr 2020 14:00:15 +0100
Subject: [PATCH 086/196] Use purecomponent
Co-Authored-By: Travis Ralston
---
src/components/views/elements/Slider.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/components/views/elements/Slider.tsx b/src/components/views/elements/Slider.tsx
index 559bdd9ce2..3dfd0c686e 100644
--- a/src/components/views/elements/Slider.tsx
+++ b/src/components/views/elements/Slider.tsx
@@ -116,7 +116,7 @@ type DotIProps = {
disabled: boolean;
}
-class Dot extends React.Component {
+class Dot extends React.PureComponent {
render(): React.ReactNode {
let className = "mx_Slider_dot"
if (!this.props.disabled && this.props.active) {
From c268b98ded295f9679ddf7eddef436a67ab86bb3 Mon Sep 17 00:00:00 2001
From: Jorik Schellekens
Date: Tue, 28 Apr 2020 14:17:50 +0100
Subject: [PATCH 087/196] Use faster lookup method
Co-Authored-By: Travis Ralston
---
.../views/settings/tabs/user/AppearanceUserSettingsTab.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.js b/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.js
index 5c285d12e6..ed7d9ef495 100644
--- a/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.js
+++ b/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.js
@@ -168,7 +168,7 @@ export default class StyleUserSettingsTab extends React.Component {
);
}
From f91613f112d2b33839f32eb5500fd3a95f796b95 Mon Sep 17 00:00:00 2001
From: Jorik Schellekens
Date: Tue, 28 Apr 2020 13:53:16 +0100
Subject: [PATCH 088/196] Remove redundent selectors.
Check _AppearanceUserSettingsTab
---
res/css/views/settings/tabs/user/_GeneralUserSettingsTab.scss | 2 --
1 file changed, 2 deletions(-)
diff --git a/res/css/views/settings/tabs/user/_GeneralUserSettingsTab.scss b/res/css/views/settings/tabs/user/_GeneralUserSettingsTab.scss
index 45aecd032f..5cc220bd33 100644
--- a/res/css/views/settings/tabs/user/_GeneralUserSettingsTab.scss
+++ b/res/css/views/settings/tabs/user/_GeneralUserSettingsTab.scss
@@ -15,8 +15,6 @@ limitations under the License.
*/
.mx_GeneralUserSettingsTab_changePassword .mx_Field,
-.mx_StyleUserSettingsTab_themeSection .mx_Field,
-.mx_StyleUserSettingsTab_fontScaling .mx_Field {
@mixin mx_Settings_fullWidthField;
}
From 137b94703aad9344b5f4ab38d4b6e7e441396ab9 Mon Sep 17 00:00:00 2001
From: Jorik Schellekens
Date: Tue, 28 Apr 2020 13:59:00 +0100
Subject: [PATCH 089/196] Lint types
---
src/components/views/elements/Slider.tsx | 24 ++++++++++++------------
1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/src/components/views/elements/Slider.tsx b/src/components/views/elements/Slider.tsx
index 3dfd0c686e..722401801c 100644
--- a/src/components/views/elements/Slider.tsx
+++ b/src/components/views/elements/Slider.tsx
@@ -16,22 +16,22 @@ limitations under the License.
import * as React from 'react';
-type IProps = {
- // A callback for the selected value
- onSelectionChange: (value: number) => void;
+interface IProps {
+ // A callback for the selected value
+ onSelectionChange: (value: number) => void;
- // The current value of the slider
- value: number;
+ // The current value of the slider
+ value: number;
- // The range and values of the slider
- // Currently only supports an ascending, constant interval range
- values: number[];
+ // The range and values of the slider
+ // Currently only supports an ascending, constant interval range
+ values: number[];
- // A function for formatting the the values
- displayFunc: (value: number) => string;
+ // A function for formatting the the values
+ displayFunc: (value: number) => string;
- // Whether the slider is disabled
- disabled: boolean;
+ // Whether the slider is disabled
+ disabled: boolean;
}
export default class Slider extends React.Component {
From 175b5e70b60f23dc446aba22da4f00d56aa2d624 Mon Sep 17 00:00:00 2001
From: Jorik Schellekens
Date: Tue, 28 Apr 2020 14:09:54 +0100
Subject: [PATCH 090/196] Lint Slider
---
src/components/views/elements/Slider.tsx | 24 +++++++++++++-----------
1 file changed, 13 insertions(+), 11 deletions(-)
diff --git a/src/components/views/elements/Slider.tsx b/src/components/views/elements/Slider.tsx
index 722401801c..6712ddd7fd 100644
--- a/src/components/views/elements/Slider.tsx
+++ b/src/components/views/elements/Slider.tsx
@@ -43,7 +43,7 @@ export default class Slider extends React.Component {
// y values.
// Offset is used for finding the location of a value on a
// non linear slider.
- _offset(values: number[], value: number): number {
+ private offset(values: number[], value: number): number {
// the index of the first number greater than value.
let closest = values.reduce((prev, curr) => {
return (value > curr ? prev + 1 : prev);
@@ -80,19 +80,21 @@ export default class Slider extends React.Component {
disabled={this.props.disabled}
/>);
- const offset = this._offset(this.props.values, this.props.value);
+ let selection = null;
+
+ if (this.props.disabled) {
+ const offset = this.offset(this.props.values, this.props.value);
+ selection =
+
+
+
+ }
return
- { this.props.disabled ?
- null :
-
-
-
-
- }
+ { selection }
{dots}
@@ -102,7 +104,7 @@ export default class Slider extends React.Component {
}
}
-type DotIProps = {
+interface IDotProps {
// Callback for behavior onclick
onClick: () => void,
@@ -116,7 +118,7 @@ type DotIProps = {
disabled: boolean;
}
-class Dot extends React.PureComponent {
+class Dot extends React.PureComponent {
render(): React.ReactNode {
let className = "mx_Slider_dot"
if (!this.props.disabled && this.props.active) {
From 57d880ca5e2bde20a030f13d3f2257fe23e654b4 Mon Sep 17 00:00:00 2001
From: Jorik Schellekens
Date: Tue, 28 Apr 2020 14:24:44 +0100
Subject: [PATCH 091/196] Use correct name and indentation
---
.../settings/tabs/user/AppearanceUserSettingsTab.js | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.js b/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.js
index ed7d9ef495..6c94a82c95 100644
--- a/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.js
+++ b/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.js
@@ -27,7 +27,7 @@ import AccessibleButton from "../../../elements/AccessibleButton";
import dis from "../../../../../dispatcher";
import _range from "lodash/range";
-export default class StyleUserSettingsTab extends React.Component {
+export default class AppearanceUserSettingsTab extends React.Component {
constructor() {
super();
@@ -231,9 +231,10 @@ export default class StyleUserSettingsTab extends React.Component {
{_t("Theme")}
{systemThemeSection}
-
{orderedThemes.map(theme => {
return ;
From 93f24f12dcf839f35231e8ca9083f670c3f626d7 Mon Sep 17 00:00:00 2001
From: Jorik Schellekens
Date: Tue, 28 Apr 2020 14:26:08 +0100
Subject: [PATCH 092/196] Match filename to class
---
src/{fontSize.js => FontWatcher.js} | 0
src/components/structures/MatrixChat.js | 2 +-
2 files changed, 1 insertion(+), 1 deletion(-)
rename src/{fontSize.js => FontWatcher.js} (100%)
diff --git a/src/fontSize.js b/src/FontWatcher.js
similarity index 100%
rename from src/fontSize.js
rename to src/FontWatcher.js
diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js
index 602d85f048..fec37472be 100644
--- a/src/components/structures/MatrixChat.js
+++ b/src/components/structures/MatrixChat.js
@@ -66,7 +66,7 @@ import { storeRoomAliasInCache } from '../../RoomAliasCache';
import { defer } from "../../utils/promise";
import ToastStore from "../../stores/ToastStore";
import * as StorageManager from "../../utils/StorageManager";
-import { FontWatcher } from '../../fontSize';
+import { FontWatcher } from '../../FontWatcher';
/** constants for MatrixChat.state.view */
export const VIEWS = {
From 9ca843fdcbc9f6d5d12dddac23a11af686cc702e Mon Sep 17 00:00:00 2001
From: Jorik Schellekens
Date: Tue, 28 Apr 2020 14:27:18 +0100
Subject: [PATCH 093/196] Correct return type in docs
Co-Authored-By: Travis Ralston
---
src/settings/SettingsStore.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/settings/SettingsStore.js b/src/settings/SettingsStore.js
index 70ea5ac57c..b6856a5a6a 100644
--- a/src/settings/SettingsStore.js
+++ b/src/settings/SettingsStore.js
@@ -373,7 +373,7 @@ export default class SettingsStore {
/**
* Gets the default value of a setting.
* @param {string} settingName The name of the setting to read the value of.
- * @return {*} The value, or null if not found
+ * @return {*} The default value
*/
static getDefaultValue(settingName, roomId = null, excludeDefault = false) {
// Verify that the setting is actually a setting
From fe326b9f08534d70c36b0484e727304e8396ba8c Mon Sep 17 00:00:00 2001
From: Jorik Schellekens
Date: Tue, 28 Apr 2020 14:30:56 +0100
Subject: [PATCH 094/196] Enfore function name capitalisation
---
src/components/structures/RoomSubList.js | 2 +-
src/components/views/avatars/BaseAvatar.js | 2 +-
src/components/views/rooms/EventTile.js | 4 ++--
src/components/views/rooms/ReadReceiptMarker.js | 2 +-
src/utils/rem.js | 2 +-
5 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/src/components/structures/RoomSubList.js b/src/components/structures/RoomSubList.js
index 1e3e15b4ec..b1e0bb9f9b 100644
--- a/src/components/structures/RoomSubList.js
+++ b/src/components/structures/RoomSubList.js
@@ -32,7 +32,7 @@ import RoomTile from "../views/rooms/RoomTile";
import LazyRenderList from "../views/elements/LazyRenderList";
import {_t} from "../../languageHandler";
import {RovingTabIndexWrapper} from "../../accessibility/RovingTabIndex";
-import toRem from "../../utils/rem";
+import {toRem} from "../../utils/rem";
// turn this on for drop & drag console debugging galore
const debug = false;
diff --git a/src/components/views/avatars/BaseAvatar.js b/src/components/views/avatars/BaseAvatar.js
index cbe083f3a2..e94a83f70b 100644
--- a/src/components/views/avatars/BaseAvatar.js
+++ b/src/components/views/avatars/BaseAvatar.js
@@ -24,7 +24,7 @@ import * as AvatarLogic from '../../../Avatar';
import SettingsStore from "../../../settings/SettingsStore";
import AccessibleButton from '../elements/AccessibleButton';
import MatrixClientContext from "../../../contexts/MatrixClientContext";
-import toRem from "../../../utils/rem";
+import {toRem} from "../../../utils/rem";
export default createReactClass({
displayName: 'BaseAvatar',
diff --git a/src/components/views/rooms/EventTile.js b/src/components/views/rooms/EventTile.js
index af14f6922c..0881fb3b67 100644
--- a/src/components/views/rooms/EventTile.js
+++ b/src/components/views/rooms/EventTile.js
@@ -34,7 +34,7 @@ import {ALL_RULE_TYPES} from "../../../mjolnir/BanList";
import * as ObjectUtils from "../../../ObjectUtils";
import MatrixClientContext from "../../../contexts/MatrixClientContext";
import {E2E_STATE} from "./E2EIcon";
-import torem from "../../../utils/rem";
+import {toRem} from "../../../utils/rem";
const eventTileTypes = {
'm.room.message': 'messages.MessageEvent',
@@ -474,7 +474,7 @@ export default createReactClass({
if (remainder > 0) {
remText = { remainder }+
+ style={{ right: "calc(" + toRem(-left) + " + " + receiptOffset + "px)" }}>{ remainder }+
;
}
}
diff --git a/src/components/views/rooms/ReadReceiptMarker.js b/src/components/views/rooms/ReadReceiptMarker.js
index 85d443d55a..20d39a7f84 100644
--- a/src/components/views/rooms/ReadReceiptMarker.js
+++ b/src/components/views/rooms/ReadReceiptMarker.js
@@ -23,7 +23,7 @@ import { _t } from '../../../languageHandler';
import {formatDate} from '../../../DateUtils';
import Velociraptor from "../../../Velociraptor";
import * as sdk from "../../../index";
-import toRem from "../../../utils/rem";
+import {toRem} from "../../../utils/rem";
let bounce = false;
try {
diff --git a/src/utils/rem.js b/src/utils/rem.js
index 1f18c9de05..6278a91aa2 100644
--- a/src/utils/rem.js
+++ b/src/utils/rem.js
@@ -15,6 +15,6 @@ limitations under the License.
*/
// converts a pixel value to rem.
-export default function(pixelVal) {
+export function toRem(pixelVal) {
return pixelVal / 15 + "rem";
}
From 1289367a6b63f8e04e53da6ae5a2ae7e5a8e5455 Mon Sep 17 00:00:00 2001
From: Jorik Schellekens
Date: Tue, 28 Apr 2020 14:31:24 +0100
Subject: [PATCH 095/196] Fix indentation
---
src/utils/rem.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/utils/rem.js b/src/utils/rem.js
index 6278a91aa2..3729b4d596 100644
--- a/src/utils/rem.js
+++ b/src/utils/rem.js
@@ -16,5 +16,5 @@ limitations under the License.
// converts a pixel value to rem.
export function toRem(pixelVal) {
- return pixelVal / 15 + "rem";
+ return pixelVal / 15 + "rem";
}
From eb72245493c1dbe163f85afbf97a26b68078e525 Mon Sep 17 00:00:00 2001
From: Jorik Schellekens
Date: Tue, 28 Apr 2020 15:19:12 +0100
Subject: [PATCH 096/196] fix syntax error
---
res/css/views/settings/tabs/user/_GeneralUserSettingsTab.scss | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/res/css/views/settings/tabs/user/_GeneralUserSettingsTab.scss b/res/css/views/settings/tabs/user/_GeneralUserSettingsTab.scss
index 5cc220bd33..0af7e30d97 100644
--- a/res/css/views/settings/tabs/user/_GeneralUserSettingsTab.scss
+++ b/res/css/views/settings/tabs/user/_GeneralUserSettingsTab.scss
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-.mx_GeneralUserSettingsTab_changePassword .mx_Field,
+.mx_GeneralUserSettingsTab_changePassword .mx_Field {
@mixin mx_Settings_fullWidthField;
}
From af8430b98aa5e47116e76ce3547da955ad18b1dd Mon Sep 17 00:00:00 2001
From: Jorik Schellekens
Date: Tue, 28 Apr 2020 15:48:54 +0100
Subject: [PATCH 097/196] Inverted boolean
---
src/components/views/elements/Slider.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/components/views/elements/Slider.tsx b/src/components/views/elements/Slider.tsx
index 6712ddd7fd..adb2a6063b 100644
--- a/src/components/views/elements/Slider.tsx
+++ b/src/components/views/elements/Slider.tsx
@@ -82,7 +82,7 @@ export default class Slider extends React.Component {
let selection = null;
- if (this.props.disabled) {
+ if (!this.props.disabled) {
const offset = this.offset(this.props.values, this.props.value);
selection =
From 4e6748416c3d68757588e563d24f516dc17880c6 Mon Sep 17 00:00:00 2001
From: Jorik Schellekens
Date: Tue, 28 Apr 2020 15:53:12 +0100
Subject: [PATCH 098/196] Fix i18n
---
src/i18n/strings/en_EN.json | 1 -
1 file changed, 1 deletion(-)
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index bff1b8f415..58226595f7 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -405,7 +405,6 @@
"Support adding custom themes": "Support adding custom themes",
"Enable cross-signing to verify per-user instead of per-session": "Enable cross-signing to verify per-user instead of per-session",
"Show info about bridges in room settings": "Show info about bridges in room settings",
- "Show padlocks on invite only rooms": "Show padlocks on invite only rooms",
"Font size": "Font size",
"Min font size": "Min font size",
"Max font size": "Max font size",
From 132a753deb787bb626b2431b7f0434debc3c1b74 Mon Sep 17 00:00:00 2001
From: Jorik Schellekens
Date: Tue, 28 Apr 2020 15:55:26 +0100
Subject: [PATCH 099/196] Lint getDefaultValue
---
src/settings/SettingsStore.js | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/settings/SettingsStore.js b/src/settings/SettingsStore.js
index b6856a5a6a..688925de40 100644
--- a/src/settings/SettingsStore.js
+++ b/src/settings/SettingsStore.js
@@ -373,9 +373,10 @@ export default class SettingsStore {
/**
* Gets the default value of a setting.
* @param {string} settingName The name of the setting to read the value of.
+ * @param {String} roomId The room ID to read the setting value in, may be null.
* @return {*} The default value
*/
- static getDefaultValue(settingName, roomId = null, excludeDefault = false) {
+ static getDefaultValue(settingName) {
// Verify that the setting is actually a setting
if (!SETTINGS[settingName]) {
throw new Error("Setting '" + settingName + "' does not appear to be a setting.");
From 2acb1663eb67473738511c3b6aa22899c9344cb3 Mon Sep 17 00:00:00 2001
From: Jorik Schellekens
Date: Wed, 29 Apr 2020 01:01:56 +0100
Subject: [PATCH 100/196] Appease the prop types
---
.../views/settings/tabs/user/AppearanceUserSettingsTab.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.js b/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.js
index 6c94a82c95..d089b4f6e0 100644
--- a/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.js
+++ b/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.js
@@ -274,8 +274,8 @@ export default class AppearanceUserSettingsTab extends React.Component {
type="text"
label={_t("Font size")}
autoComplete="off"
- placeholder={this.state.fontSize}
- value={this.state.fontSize}
+ placeholder={toString(this.state.fontSize)}
+ value={toString(this.state.fontSize)}
id="font_size_field"
onValidate={this._onValidateFontSize}
onChange={({value}) => this.setState({fontSize: value})}
From f7b3662e0b306d66feefe7ac03211165518565f7 Mon Sep 17 00:00:00 2001
From: Jorik Schellekens
Date: Wed, 29 Apr 2020 10:32:05 +0100
Subject: [PATCH 101/196] Fully appease prop types
---
.../views/settings/tabs/user/AppearanceUserSettingsTab.js | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.js b/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.js
index d089b4f6e0..6fd44b691d 100644
--- a/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.js
+++ b/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.js
@@ -107,7 +107,6 @@ export default class AppearanceUserSettingsTab extends React.Component {
_onValidateFontSize = ({value}) => {
console.log({value});
- this.setState({fontSize: value});
const parsedSize = parseFloat(value);
const min = SettingsStore.getValue("font_size_min");
@@ -274,11 +273,11 @@ export default class AppearanceUserSettingsTab extends React.Component {
type="text"
label={_t("Font size")}
autoComplete="off"
- placeholder={toString(this.state.fontSize)}
- value={toString(this.state.fontSize)}
+ placeholder={this.state.fontSize.toString()}
+ value={this.state.fontSize.toString()}
id="font_size_field"
onValidate={this._onValidateFontSize}
- onChange={({value}) => this.setState({fontSize: value})}
+ onChange={(value) => this.setState({fontSize: value.target.value})}
disabled={!this.state.useCustomFontSize}
/>
;
From bab7d5f461a6c51d142fe9ff7d5be6cd4cfd9bbb Mon Sep 17 00:00:00 2001
From: Jorik Schellekens
Date: Wed, 6 May 2020 17:25:54 +0100
Subject: [PATCH 102/196] Some lints
---
res/css/views/elements/_Slider.scss | 12 ++++++------
res/themes/light/css/_light.scss | 4 ++--
src/FontWatcher.js | 12 ++++++------
src/components/views/elements/Slider.tsx | 2 +-
.../tabs/user/AppearanceUserSettingsTab.js | 14 +++++++-------
src/settings/Settings.js | 6 +++---
6 files changed, 25 insertions(+), 25 deletions(-)
diff --git a/res/css/views/elements/_Slider.scss b/res/css/views/elements/_Slider.scss
index f6982865db..09afb58b12 100644
--- a/res/css/views/elements/_Slider.scss
+++ b/res/css/views/elements/_Slider.scss
@@ -38,7 +38,7 @@ limitations under the License.
.mx_Slider_bar > hr {
width: 100%;
- border: 0.2em solid $Slider-background-color;
+ border: 0.2em solid $slider-background-color;
}
.mx_Slider_selection {
@@ -54,7 +54,7 @@ limitations under the License.
position: absolute;
width: 1.1em;
height: 1.1em;
- background-color: $Slider-selection-color;
+ background-color: $slider-selection-color;
border-radius: 50%;
box-shadow: 0 0 6px lightgrey;
z-index: 10;
@@ -63,7 +63,7 @@ limitations under the License.
.mx_Slider_selection > hr {
transition: width 0.25s;
margin: 0;
- border: 0.2em solid $Slider-selection-color;
+ border: 0.2em solid $slider-selection-color;
}
.mx_Slider_dot {
@@ -71,19 +71,19 @@ limitations under the License.
height: 1em;
width: 1em;
border-radius: 50%;
- background-color: $Slider-background-color;
+ background-color: $slider-background-color;
z-index: 0;
}
.mx_Slider_dotActive {
- background-color: $Slider-selection-color;
+ background-color: $slider-selection-color;
}
.mx_Slider_dotValue {
display: flex;
flex-direction: column;
align-items: center;
- color: $Slider-background-color;
+ color: $slider-background-color;
}
// The following is a hack to center the labels without adding
diff --git a/res/themes/light/css/_light.scss b/res/themes/light/css/_light.scss
index ed7eae48f7..78fe2a74c5 100644
--- a/res/themes/light/css/_light.scss
+++ b/res/themes/light/css/_light.scss
@@ -263,8 +263,8 @@ $togglesw-on-color: $accent-color;
$togglesw-ball-color: #fff;
// Slider
-$Slider-selection-color: $accent-color;
-$Slider-background-color: #c1c9d6;
+$slider-selection-color: $accent-color;
+$slider-background-color: #c1c9d6;
$progressbar-color: #000;
diff --git a/src/FontWatcher.js b/src/FontWatcher.js
index 2e37921ee6..561edc4662 100644
--- a/src/FontWatcher.js
+++ b/src/FontWatcher.js
@@ -23,7 +23,7 @@ export class FontWatcher {
}
start() {
- this._setRootFontSize(SettingsStore.getValue("font_size"));
+ this._setRootFontSize(SettingsStore.getValue("fontSize"));
this._dispatcherRef = dis.register(this._onAction);
}
@@ -37,15 +37,15 @@ export class FontWatcher {
}
};
- _setRootFontSize = size => {
- const min = SettingsStore.getValue("font_size_min");
- const max = SettingsStore.getValue("font_size_max");
+ _setRootFontSize = (size) => {
+ const min = SettingsStore.getValue("fontSizeMin");
+ const max = SettingsStore.getValue("fontSizeMax");
const fontSize = Math.max(Math.min(max, size), min);
if (fontSize != size) {
- SettingsStore.setValue("font_size", null, SettingLevel.Device, fontSize);
+ SettingsStore.setValue("fontSize", null, SettingLevel.Device, fontSize);
}
document.querySelector(":root").style.fontSize = fontSize + "px";
- }
+ };
}
diff --git a/src/components/views/elements/Slider.tsx b/src/components/views/elements/Slider.tsx
index adb2a6063b..e181f0d9e3 100644
--- a/src/components/views/elements/Slider.tsx
+++ b/src/components/views/elements/Slider.tsx
@@ -47,7 +47,7 @@ export default class Slider extends React.Component {
// the index of the first number greater than value.
let closest = values.reduce((prev, curr) => {
return (value > curr ? prev + 1 : prev);
- }, 0);
+ }, 0);
// Off the left
if (closest === 0) {
diff --git a/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.js b/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.js
index 6fd44b691d..ac98664be0 100644
--- a/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.js
+++ b/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.js
@@ -32,7 +32,7 @@ export default class AppearanceUserSettingsTab extends React.Component {
super();
this.state = {
- fontSize: SettingsStore.getValue("font_size", null),
+ fontSize: SettingsStore.getValue("fontSize", null),
...this._calculateThemeState(),
customThemeUrl: "",
customThemeMessage: {isError: false, text: ""},
@@ -102,15 +102,15 @@ export default class AppearanceUserSettingsTab extends React.Component {
_onFontSizeChanged = (size) => {
this.setState({fontSize: size});
- SettingsStore.setValue("font_size", null, SettingLevel.DEVICE, size);
+ SettingsStore.setValue("fontSize", null, SettingLevel.DEVICE, size);
};
_onValidateFontSize = ({value}) => {
console.log({value});
const parsedSize = parseFloat(value);
- const min = SettingsStore.getValue("font_size_min");
- const max = SettingsStore.getValue("font_size_max");
+ const min = SettingsStore.getValue("fontSizeMin");
+ const max = SettingsStore.getValue("fontSizeMax");
if (isNaN(parsedSize)) {
return {valid: false, feedback: _t("Size must be a number")};
@@ -123,7 +123,7 @@ export default class AppearanceUserSettingsTab extends React.Component {
};
}
- SettingsStore.setValue("font_size", null, SettingLevel.DEVICE, value);
+ SettingsStore.setValue("fontSize", null, SettingLevel.DEVICE, value);
return {valid: true, feedback: _t('Use between %(min)s pt and %(max)s pt', {min, max})};
}
@@ -253,8 +253,8 @@ export default class AppearanceUserSettingsTab extends React.Component {
Aa
Date: Wed, 29 Apr 2020 14:57:45 +0100
Subject: [PATCH 103/196] add useIRCLayout setting
---
src/i18n/strings/en_EN.json | 1 +
src/settings/Settings.js | 11 +++++++++++
2 files changed, 12 insertions(+)
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index a24b2bde73..3dcba0f546 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -408,6 +408,7 @@
"Enable cross-signing to verify per-user instead of per-session": "Enable cross-signing to verify per-user instead of per-session",
"Show info about bridges in room settings": "Show info about bridges in room settings",
"Enable Emoji suggestions while typing": "Enable Emoji suggestions while typing",
+ "Use IRC layout": "Use IRC layout",
"Use compact timeline layout": "Use compact timeline layout",
"Show a placeholder for removed messages": "Show a placeholder for removed messages",
"Show join/leave messages (invites/kicks/bans unaffected)": "Show join/leave messages (invites/kicks/bans unaffected)",
diff --git a/src/settings/Settings.js b/src/settings/Settings.js
index 5c6d843349..c51bf44ee5 100644
--- a/src/settings/Settings.js
+++ b/src/settings/Settings.js
@@ -94,6 +94,12 @@ export const SETTINGS = {
// // not use this for new settings.
// invertedSettingName: "my-negative-setting",
// },
+ "feature_alternate_message_layouts": {
+ isFeature: true,
+ displayName: _td("Alternate message layouts"),
+ supportedLevels: LEVELS_FEATURE,
+ default: false,
+ },
"feature_pinning": {
isFeature: true,
displayName: _td("Message Pinning"),
@@ -164,6 +170,11 @@ export const SETTINGS = {
default: true,
invertedSettingName: 'MessageComposerInput.dontSuggestEmoji',
},
+ "useIRCLayout": {
+ supportedLevels: LEVELS_ACCOUNT_SETTINGS,
+ displayName: _td('Use IRC layout'),
+ default: false,
+ },
"useCompactLayout": {
supportedLevels: LEVELS_ACCOUNT_SETTINGS,
displayName: _td('Use compact timeline layout'),
From e0c89f6180331350485ca7331ff9e190a83a3d5f Mon Sep 17 00:00:00 2001
From: Jorik Schellekens
Date: Wed, 29 Apr 2020 15:06:38 +0100
Subject: [PATCH 104/196] Add switch between layout classes
---
src/components/structures/MessagePanel.js | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/src/components/structures/MessagePanel.js b/src/components/structures/MessagePanel.js
index 6fbfdb504b..0123d43920 100644
--- a/src/components/structures/MessagePanel.js
+++ b/src/components/structures/MessagePanel.js
@@ -117,6 +117,7 @@ export default class MessagePanel extends React.Component {
// display 'ghost' read markers that are animating away
ghostReadMarkers: [],
showTypingNotifications: SettingsStore.getValue("showTypingNotifications"),
+ useIRCLayout: SettingsStore.getValue("useIRCLayout"),
};
// opaque readreceipt info for each userId; used by ReadReceiptMarker
@@ -169,6 +170,8 @@ export default class MessagePanel extends React.Component {
this._showTypingNotificationsWatcherRef =
SettingsStore.watchSetting("showTypingNotifications", null, this.onShowTypingNotificationsChange);
+
+ this._layoutWatcherRef = SettingsStore.watchSetting("useIRCLayout", null, this.onLayoutChange);
}
componentDidMount() {
@@ -178,6 +181,7 @@ export default class MessagePanel extends React.Component {
componentWillUnmount() {
this._isMounted = false;
SettingsStore.unwatchSetting(this._showTypingNotificationsWatcherRef);
+ SettingsStore.unwatchSetting(this._layoutWatcherRef);
}
componentDidUpdate(prevProps, prevState) {
@@ -196,6 +200,12 @@ export default class MessagePanel extends React.Component {
});
};
+ onLayoutChange = () => {
+ this.setState({
+ useIRCLayout: SettingsStore.getValue("useIRCLayout"),
+ });
+ }
+
/* get the DOM node representing the given event */
getNodeForEventId(eventId) {
if (!this.eventNodes) {
@@ -779,6 +789,8 @@ export default class MessagePanel extends React.Component {
this.props.className,
{
"mx_MessagePanel_alwaysShowTimestamps": this.props.alwaysShowTimestamps,
+ "mx_IRCLayout": this.state.useIRCLayout,
+ "mx_GroupLayout": !this.state.useIRCLayout,
},
);
From c1e740a59603ae178364cac18c8ecdd5443c9df6 Mon Sep 17 00:00:00 2001
From: Jorik Schellekens
Date: Wed, 29 Apr 2020 15:07:17 +0100
Subject: [PATCH 105/196] Break out group layout settings
---
res/css/views/rooms/_EventTile.scss | 12 -------
res/css/views/rooms/_GroupLayout.scss | 52 +++++++++++++++++++++++++++
2 files changed, 52 insertions(+), 12 deletions(-)
create mode 100644 res/css/views/rooms/_GroupLayout.scss
diff --git a/res/css/views/rooms/_EventTile.scss b/res/css/views/rooms/_EventTile.scss
index 752cf982f6..b9a41c4310 100644
--- a/res/css/views/rooms/_EventTile.scss
+++ b/res/css/views/rooms/_EventTile.scss
@@ -68,11 +68,9 @@ limitations under the License.
display: inline-block; /* anti-zalgo, with overflow hidden */
overflow: hidden;
cursor: pointer;
- padding-left: 65px; /* left gutter */
padding-bottom: 0px;
padding-top: 0px;
margin: 0px;
- line-height: $font-17px;
/* the next three lines, along with overflow hidden, truncate long display names */
white-space: nowrap;
text-overflow: ellipsis;
@@ -101,12 +99,9 @@ limitations under the License.
.mx_EventTile .mx_MessageTimestamp {
display: block;
- visibility: hidden;
white-space: nowrap;
left: 0px;
- width: 46px; /* 8 + 30 (avatar) + 8 */
text-align: center;
- position: absolute;
user-select: none;
}
@@ -117,10 +112,7 @@ limitations under the License.
.mx_EventTile_line, .mx_EventTile_reply {
position: relative;
padding-left: 65px; /* left gutter */
- padding-top: 3px;
- padding-bottom: 3px;
border-radius: 4px;
- line-height: $font-22px;
}
.mx_RoomView_timeline_rr_enabled,
@@ -151,10 +143,6 @@ limitations under the License.
margin-right: 10px;
}
-.mx_EventTile_info .mx_EventTile_line {
- padding-left: 83px;
-}
-
/* HACK to override line-height which is already marked important elsewhere */
.mx_EventTile_bigEmoji.mx_EventTile_bigEmoji {
font-size: 48px !important;
diff --git a/res/css/views/rooms/_GroupLayout.scss b/res/css/views/rooms/_GroupLayout.scss
new file mode 100644
index 0000000000..6528d6c6cd
--- /dev/null
+++ b/res/css/views/rooms/_GroupLayout.scss
@@ -0,0 +1,52 @@
+/*
+Copyright 2015, 2016 OpenMarket Ltd
+Copyright 2020 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+$left-gutter: 65px;
+
+.mx_GroupLayout {
+
+ .mx_EventTile {
+ > .mx_SenderProfile {
+ line-height: $font-17px;
+ padding-left: $left-gutter;
+ }
+
+ > .mx_EventTile_line {
+ padding-left: $left-gutter;
+ }
+
+ > .mx_EventTile_avatar {
+ position: absolute;
+ }
+
+ .mx_MessageTimestamp {
+ visibility: hidden;
+ position: absolute;
+ width: 46px; /* 8 + 30 (avatar) + 8 */
+ }
+
+ .mx_EventTile_line, .mx_EventTile_reply {
+ padding-top: 3px;
+ padding-bottom: 3px;
+ line-height: $font-22px;
+ }
+ }
+
+ .mx_EventTile_info .mx_EventTile_line {
+ padding-left: 83px;
+ }
+}
From 10c8d253c86334e11c3a8582db6d63e073bcb79e Mon Sep 17 00:00:00 2001
From: Jorik Schellekens
Date: Wed, 29 Apr 2020 15:07:41 +0100
Subject: [PATCH 106/196] Create irc layout
---
res/css/views/rooms/_IRCLayout.scss | 124 ++++++++++++++++++++++
src/components/structures/MessagePanel.js | 1 +
src/components/views/rooms/EventTile.js | 30 ++++--
3 files changed, 148 insertions(+), 7 deletions(-)
create mode 100644 res/css/views/rooms/_IRCLayout.scss
diff --git a/res/css/views/rooms/_IRCLayout.scss b/res/css/views/rooms/_IRCLayout.scss
new file mode 100644
index 0000000000..6152749573
--- /dev/null
+++ b/res/css/views/rooms/_IRCLayout.scss
@@ -0,0 +1,124 @@
+/*
+Copyright 2020 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+$name-width: 50px;
+$icon-width: 14px;
+$timestamp-width: 45px;
+$right-padding: 5px;
+
+.mx_IRCLayout {
+
+ line-height: $font-22px !important;
+
+ .mx_EventTile {
+ display: flex;
+ flex-direction: row;
+ align-items: flex-start;
+
+ > * {
+ margin-right: $right-padding;
+ }
+
+ > .mx_EventTile_msgOption {
+ order: 4;
+ flex-shrink: 0;
+ }
+
+ > .mx_SenderProfile {
+ order: 2;
+ flex-shrink: 0;
+ width: $name-width;
+ text-overflow: ellipsis;
+ text-align: right;
+ display: flex;
+ align-items: center;
+ }
+
+ > .mx_EventTile_line {
+ order: 3;
+ flex-grow: 1;
+ }
+
+ > .mx_EventTile_avatar {
+ order: 1;
+ position: relative;
+ top: 0;
+ left: 0;
+ flex-shrink: 0;
+ height: 22px;
+ display: flex;
+ align-items: center;
+
+ > .mx_BaseAvatar {
+ height: 1rem;
+ width: 1rem;
+ }
+ }
+
+ .mx_MessageTimestamp {
+ font-size: $font-10px;
+ width: $timestamp-width;
+ text-align: right;
+ }
+
+ .mx_EventTile_line, .mx_EventTile_reply {
+ padding: 0;
+ }
+
+ .mx_EventTile_e2eIcon {
+ position: relative;
+ right: unset;
+ left: unset;
+ top: -2px;
+ padding: 0;
+ }
+
+ .mx_EventTile_line > * {
+ display: inline-block;
+ }
+ }
+
+ .mx_EventListSummary {
+ > .mx_EventTile_line {
+ padding-left: calc($name-width + $icon-width + $timestamp-width + 3 * $right-padding); // 15 px of padding
+ }
+ }
+
+ .mx_EventTile.mx_EventTile_info {
+ .mx_EventTile_avatar {
+ left: calc($name-width + 10px + $icon-width);
+ top: 0;
+ }
+
+ .mx_EventTile_line {
+ left: calc($name-width + 10px + $icon-width);
+ }
+
+ .mx_TextualEvent {
+ line-height: $font-22px;
+ }
+ }
+
+ .mx_EventTile_continuation:not(.mx_EventTile_info) {
+ .mx_EventTile_avatar {
+ visibility: hidden;
+ }
+
+ .mx_SenderProfile {
+ visibility: hidden;
+ }
+ }
+}
diff --git a/src/components/structures/MessagePanel.js b/src/components/structures/MessagePanel.js
index 0123d43920..80e5d17bf3 100644
--- a/src/components/structures/MessagePanel.js
+++ b/src/components/structures/MessagePanel.js
@@ -607,6 +607,7 @@ export default class MessagePanel extends React.Component {
isSelectedEvent={highlight}
getRelationsForEvent={this.props.getRelationsForEvent}
showReactions={this.props.showReactions}
+ useIRCLayout={this.state.useIRCLayout}
/>
,
diff --git a/src/components/views/rooms/EventTile.js b/src/components/views/rooms/EventTile.js
index a64fd82eb5..2da9677a17 100644
--- a/src/components/views/rooms/EventTile.js
+++ b/src/components/views/rooms/EventTile.js
@@ -206,6 +206,9 @@ export default createReactClass({
// whether to show reactions for this event
showReactions: PropTypes.bool,
+
+ // whether to use the irc layout
+ useIRCLayout: PropTypes.bool,
},
getDefaultProps: function() {
@@ -653,6 +656,8 @@ export default createReactClass({
const classes = classNames({
mx_EventTile_bubbleContainer: isBubbleMessage,
mx_EventTile: true,
+ mx_EventTile_irc: this.props.useIRCLayout,
+ mx_EventTile_group: !this.props.useIRCLayout,
mx_EventTile_isEditing: isEditing,
mx_EventTile_info: isInfoMessage,
mx_EventTile_12hr: this.props.isTwelveHour,
@@ -696,6 +701,9 @@ export default createReactClass({
// joins/parts/etc
avatarSize = 14;
needsSenderProfile = false;
+ } else if (this.props.useIRCLayout) {
+ avatarSize = 14;
+ needsSenderProfile = true;
} else if (this.props.continuation && this.props.tileShape !== "file_grid") {
// no avatar or sender profile for continuation messages
avatarSize = 0;
@@ -879,21 +887,29 @@ export default createReactClass({
this.props.permalinkCreator,
this._replyThread,
);
+
+ const linkedTimestamp =
+ { timestamp }
+ ;
+
+ const groupTimestamp = !this.props.useIRCLayout ? linkedTimestamp : null;
+ const ircTimestamp = this.props.useIRCLayout ? linkedTimestamp : null;
+
+
// tab-index=-1 to allow it to be focusable but do not add tab stop for it, primarily for screen readers
return (
);
}
diff --git a/src/components/views/auth/Welcome.js b/src/components/views/auth/Welcome.js
index 7cbcf65d3c..91ba368f70 100644
--- a/src/components/views/auth/Welcome.js
+++ b/src/components/views/auth/Welcome.js
@@ -45,7 +45,8 @@ export default class Welcome extends React.PureComponent {
idBaseUrl: isUrl,
});
const plaf = PlatformPeg.get();
- const callbackUrl = plaf.getSSOCallbackUrl(tmpClient.getHomeserverUrl(), tmpClient.getIdentityServerUrl());
+ const callbackUrl = plaf.getSSOCallbackUrl(tmpClient.getHomeserverUrl(), tmpClient.getIdentityServerUrl(),
+ this.props.fragmentAfterLogin);
return (
diff --git a/src/components/views/elements/SSOButton.js b/src/components/views/elements/SSOButton.js
index 3e0757924b..1126ae3cd7 100644
--- a/src/components/views/elements/SSOButton.js
+++ b/src/components/views/elements/SSOButton.js
@@ -21,9 +21,9 @@ import PlatformPeg from "../../../PlatformPeg";
import AccessibleButton from "./AccessibleButton";
import {_t} from "../../../languageHandler";
-const SSOButton = ({matrixClient, loginType, ...props}) => {
+const SSOButton = ({matrixClient, loginType, fragmentAfterLogin, ...props}) => {
const onClick = () => {
- PlatformPeg.get().startSingleSignOn(matrixClient, loginType);
+ PlatformPeg.get().startSingleSignOn(matrixClient, loginType, fragmentAfterLogin);
};
return (
@@ -36,6 +36,7 @@ const SSOButton = ({matrixClient, loginType, ...props}) => {
SSOButton.propTypes = {
matrixClient: PropTypes.object.isRequired, // does not use context as may use a temporary client
loginType: PropTypes.oneOf(["sso", "cas"]), // defaults to "sso" in base-apis
+ fragmentAfterLogin: PropTypes.string,
};
export default SSOButton;
From 52e3c97f8c9a2032fe92b2b4bb5fc68c0f6957b5 Mon Sep 17 00:00:00 2001
From: Michael Telatynski <7t3chguy@googlemail.com>
Date: Wed, 13 May 2020 06:36:14 +0100
Subject: [PATCH 124/196] Revert "ImageView make clicking off it easier"
---
res/css/views/elements/_ImageView.scss | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/res/css/views/elements/_ImageView.scss b/res/css/views/elements/_ImageView.scss
index 983ef074f2..0a4ed2a194 100644
--- a/res/css/views/elements/_ImageView.scss
+++ b/res/css/views/elements/_ImageView.scss
@@ -37,7 +37,7 @@ limitations under the License.
order: 2;
/* min-width hack needed for FF */
min-width: 0px;
- max-height: 90%;
+ height: 90%;
flex: 15 15 0;
display: flex;
align-items: center;
From d11923e2e3d3f4189d8848349f0ec1073ea8f91e Mon Sep 17 00:00:00 2001
From: Michael Telatynski <7t3chguy@gmail.com>
Date: Wed, 13 May 2020 10:38:32 +0100
Subject: [PATCH 125/196] Add new keyboard shortcuts for jump to unread and
upload file
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
---
src/accessibility/KeyboardShortcuts.tsx | 41 +++++++++++++++----
src/components/structures/RoomView.js | 14 ++++++-
src/components/views/rooms/MessageComposer.js | 13 +++++-
3 files changed, 57 insertions(+), 11 deletions(-)
diff --git a/src/accessibility/KeyboardShortcuts.tsx b/src/accessibility/KeyboardShortcuts.tsx
index bcbf3d6810..f527ab4a14 100644
--- a/src/accessibility/KeyboardShortcuts.tsx
+++ b/src/accessibility/KeyboardShortcuts.tsx
@@ -34,6 +34,7 @@ export enum Categories {
CALLS = "Calls",
COMPOSER = "Composer",
ROOM_LIST = "Room List",
+ ROOM = "Room",
AUTOCOMPLETE = "Autocomplete",
}
@@ -142,6 +143,34 @@ const shortcuts: Record = {
},
],
+ [Categories.ROOM]: [
+ {
+ keybinds: [{
+ key: Key.PAGE_UP,
+ }, {
+ key: Key.PAGE_DOWN,
+ }],
+ description: _td("Scroll up/down in the timeline"),
+ }, {
+ keybinds: [{
+ key: Key.ESCAPE,
+ }],
+ description: _td("Dismiss read marker and jump to bottom"),
+ }, {
+ keybinds: [{
+ modifiers: [Modifiers.SHIFT],
+ key: Key.PAGE_UP,
+ }],
+ description: _td("Jump to oldest unread message"),
+ }, {
+ keybinds: [{
+ modifiers: [CMD_OR_CTRL, Modifiers.SHIFT],
+ key: Key.U,
+ }],
+ description: _td("Upload a file"),
+ }
+ ],
+
[Categories.ROOM_LIST]: [
{
keybinds: [{
@@ -181,13 +210,6 @@ const shortcuts: Record = {
[Categories.NAVIGATION]: [
{
- keybinds: [{
- key: Key.PAGE_UP,
- }, {
- key: Key.PAGE_DOWN,
- }],
- description: _td("Scroll up/down in the timeline"),
- }, {
keybinds: [{
modifiers: [Modifiers.ALT, Modifiers.SHIFT],
key: Key.ARROW_UP,
@@ -257,10 +279,11 @@ const shortcuts: Record = {
const categoryOrder = [
Categories.COMPOSER,
- Categories.CALLS,
- Categories.ROOM_LIST,
Categories.AUTOCOMPLETE,
+ Categories.ROOM,
+ Categories.ROOM_LIST,
Categories.NAVIGATION,
+ Categories.CALLS,
];
interface IModal {
diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js
index f53929df4a..e413c33efa 100644
--- a/src/components/structures/RoomView.js
+++ b/src/components/structures/RoomView.js
@@ -41,7 +41,7 @@ import * as ObjectUtils from '../../ObjectUtils';
import * as Rooms from '../../Rooms';
import eventSearch from '../../Searching';
-import {isOnlyCtrlOrCmdKeyEvent, Key} from '../../Keyboard';
+import {isOnlyCtrlOrCmdIgnoreShiftKeyEvent, isOnlyCtrlOrCmdKeyEvent, Key} from '../../Keyboard';
import MainSplit from './MainSplit';
import RightPanel from './RightPanel';
@@ -588,6 +588,18 @@ export default createReactClass({
handled = true;
}
break;
+ case Key.PAGE_UP:
+ if (!ev.altKey && !ev.ctrlKey && ev.shiftKey && !ev.metaKey) {
+ this.jumpToReadMarker();
+ handled = true;
+ }
+ break;
+ case Key.U.toUpperCase():
+ if (isOnlyCtrlOrCmdIgnoreShiftKeyEvent(ev) && ev.shiftKey) {
+ dis.dispatch({ action: "upload_file" })
+ handled = true;
+ }
+ break;
}
if (handled) {
diff --git a/src/components/views/rooms/MessageComposer.js b/src/components/views/rooms/MessageComposer.js
index 4749742a7d..1142e91057 100644
--- a/src/components/views/rooms/MessageComposer.js
+++ b/src/components/views/rooms/MessageComposer.js
@@ -114,8 +114,19 @@ class UploadButton extends React.Component {
this.onUploadFileInputChange = this.onUploadFileInputChange.bind(this);
this._uploadInput = createRef();
+ this._dispatcherRef = dis.register(this.onAction);
}
+ componentWillUnmount() {
+ dis.unregister(this._dispatcherRef);
+ }
+
+ onAction = payload => {
+ if (payload.action === "upload_file") {
+ this.onUploadClick();
+ }
+ };
+
onUploadClick(ev) {
if (MatrixClientPeg.get().isGuest()) {
dis.dispatch({action: 'require_registration'});
@@ -128,7 +139,7 @@ class UploadButton extends React.Component {
if (ev.target.files.length === 0) return;
// take a copy so we can safely reset the value of the form control
- // (Note it is a FileList: we can't use slice or sesnible iteration).
+ // (Note it is a FileList: we can't use slice or sensible iteration).
const tfiles = [];
for (let i = 0; i < ev.target.files.length; ++i) {
tfiles.push(ev.target.files[i]);
From 0e05e6db86467c730b853c8f8d7009f2a28d8e85 Mon Sep 17 00:00:00 2001
From: Michael Telatynski <7t3chguy@gmail.com>
Date: Wed, 13 May 2020 10:40:23 +0100
Subject: [PATCH 126/196] i18n
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
---
src/i18n/strings/en_EN.json | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index b2fe409aa5..d469103897 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -2284,13 +2284,16 @@
"Cancel replying to a message": "Cancel replying to a message",
"Toggle microphone mute": "Toggle microphone mute",
"Toggle video on/off": "Toggle video on/off",
+ "Scroll up/down in the timeline": "Scroll up/down in the timeline",
+ "Dismiss read marker and jump to bottom": "Dismiss read marker and jump to bottom",
+ "Jump to oldest unread message": "Jump to oldest unread message",
+ "Upload a file": "Upload a file",
"Jump to room search": "Jump to room search",
"Navigate up/down in the room list": "Navigate up/down in the room list",
"Select room from the room list": "Select room from the room list",
"Collapse room list section": "Collapse room list section",
"Expand room list section": "Expand room list section",
"Clear room list filter field": "Clear room list filter field",
- "Scroll up/down in the timeline": "Scroll up/down in the timeline",
"Previous/next unread room or DM": "Previous/next unread room or DM",
"Previous/next room or DM": "Previous/next room or DM",
"Toggle the top left menu": "Toggle the top left menu",
From 51f59c6c327873bd796eab6bdd91f20c854a66a1 Mon Sep 17 00:00:00 2001
From: Michael Telatynski <7t3chguy@gmail.com>
Date: Wed, 13 May 2020 11:40:56 +0100
Subject: [PATCH 127/196] UserView, show Welcome page in the mid panel instead
of empty space
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
---
src/components/structures/UserView.js | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/components/structures/UserView.js b/src/components/structures/UserView.js
index 493cc136d1..694592af88 100644
--- a/src/components/structures/UserView.js
+++ b/src/components/structures/UserView.js
@@ -22,6 +22,7 @@ import {MatrixClientPeg} from "../../MatrixClientPeg";
import * as sdk from "../../index";
import Modal from '../../Modal';
import { _t } from '../../languageHandler';
+import HomePage from "./HomePage";
export default class UserView extends React.Component {
static get propTypes() {
@@ -79,7 +80,7 @@ export default class UserView extends React.Component {
const RightPanel = sdk.getComponent('structures.RightPanel');
const MainSplit = sdk.getComponent('structures.MainSplit');
const panel = ;
- return ();
+ return ();
} else {
return ();
}
From 3f04f5163a963b9193199abb340719061ae0e921 Mon Sep 17 00:00:00 2001
From: Jorik Schellekens
Date: Wed, 13 May 2020 14:04:46 +0100
Subject: [PATCH 128/196] Implement more nitpicks
- fix avatar inital aligment
- right align names
- set flair height to avatar's
- fix conditions for resizing to be more stable
---
res/css/views/rooms/_IRCLayout.scss | 13 ++++++++++++-
.../views/elements/IRCTimelineProfileResizer.tsx | 4 ++--
2 files changed, 14 insertions(+), 3 deletions(-)
diff --git a/res/css/views/rooms/_IRCLayout.scss b/res/css/views/rooms/_IRCLayout.scss
index 159cfc0aad..8d48c72f8a 100644
--- a/res/css/views/rooms/_IRCLayout.scss
+++ b/res/css/views/rooms/_IRCLayout.scss
@@ -54,6 +54,7 @@ $irc-line-height: $font-18px;
display: flex;
align-items: center;
overflow: visible;
+ justify-content: flex-end;
}
.mx_EventTile_line, .mx_EventTile_reply {
@@ -79,7 +80,7 @@ $irc-line-height: $font-18px;
height: $font-14px !important;
width: $font-14px !important;
font-size: $font-10px !important;
- line-height: $font-14px !important;
+ line-height: $font-15px !important;
}
}
@@ -188,6 +189,10 @@ $irc-line-height: $font-18px;
}
}
+ .mx_SenderProfile:hover {
+ justify-content: flex-start;
+ }
+
.mx_SenderProfile_hover:hover {
overflow: visible;
width: auto;
@@ -210,4 +215,10 @@ $irc-line-height: $font-18px;
cursor: col-resize;
z-index: 100;
}
+
+ // Need to use important to override the js provided height and width values.
+ .mx_Flair > img {
+ height: $font-14px !important;
+ width: $font-14px !important;
+ }
}
diff --git a/src/components/views/elements/IRCTimelineProfileResizer.tsx b/src/components/views/elements/IRCTimelineProfileResizer.tsx
index 80a86b2005..44ceeb9b7b 100644
--- a/src/components/views/elements/IRCTimelineProfileResizer.tsx
+++ b/src/components/views/elements/IRCTimelineProfileResizer.tsx
@@ -52,11 +52,11 @@ export default class IRCTimelineProfileResizer extends React.Component= this.props.maxWidth && offset >= 0) {
+ if (newWidth > this.props.maxWidth) {
return location;
}
From 312b616d7701e9b9f8460d210bc22a07c1253be9 Mon Sep 17 00:00:00 2001
From: Jorik Schellekens
Date: Wed, 13 May 2020 14:11:16 +0100
Subject: [PATCH 129/196] fix i18n
---
src/i18n/strings/en_EN.json | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index ca62eb44fa..37b9c1dfc8 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -453,6 +453,7 @@
"Keep recovery passphrase in memory for this session": "Keep recovery passphrase in memory for this session",
"How fast should messages be downloaded.": "How fast should messages be downloaded.",
"Manually verify all remote sessions": "Manually verify all remote sessions",
+ "IRC display name width": "IRC display name width",
"Collecting app version information": "Collecting app version information",
"Collecting logs": "Collecting logs",
"Uploading report": "Uploading report",
From 328bb7bcaf05621443c7a75ab791a9c8eb0ac884 Mon Sep 17 00:00:00 2001
From: Jorik Schellekens
Date: Wed, 13 May 2020 15:24:08 +0100
Subject: [PATCH 130/196] Remove all animations
---
res/css/_common.scss | 1 -
res/css/views/elements/_Slider.scss | 3 ---
2 files changed, 4 deletions(-)
diff --git a/res/css/_common.scss b/res/css/_common.scss
index 687a238c8e..03442ca510 100644
--- a/res/css/_common.scss
+++ b/res/css/_common.scss
@@ -19,7 +19,6 @@ limitations under the License.
@import "./_font-sizes.scss";
:root {
- transition: font-size 0.25s;
font-size: 15px;
}
diff --git a/res/css/views/elements/_Slider.scss b/res/css/views/elements/_Slider.scss
index 09afb58b12..06c3c4c98b 100644
--- a/res/css/views/elements/_Slider.scss
+++ b/res/css/views/elements/_Slider.scss
@@ -50,7 +50,6 @@ limitations under the License.
}
.mx_Slider_selectionDot {
- transition: left 0.25s;
position: absolute;
width: 1.1em;
height: 1.1em;
@@ -61,13 +60,11 @@ limitations under the License.
}
.mx_Slider_selection > hr {
- transition: width 0.25s;
margin: 0;
border: 0.2em solid $slider-selection-color;
}
.mx_Slider_dot {
- transition: background-color 0.2s ease-in;
height: 1em;
width: 1em;
border-radius: 50%;
From fea219915f4a666d73259406323b185a9d5067f6 Mon Sep 17 00:00:00 2001
From: Jorik Schellekens
Date: Wed, 13 May 2020 15:26:11 +0100
Subject: [PATCH 131/196] fix code regeression
---
.../views/settings/tabs/user/GeneralUserSettingsTab.js | 3 ---
1 file changed, 3 deletions(-)
diff --git a/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js b/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js
index 0cee29233f..21e406aa23 100644
--- a/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js
+++ b/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js
@@ -60,9 +60,6 @@ export default class GeneralUserSettingsTab extends React.Component {
emails: [],
msisdns: [],
loading3pids: true, // whether or not the emails and msisdns have been loaded
- ...this._calculateThemeState(),
- customThemeUrl: "",
- customThemeMessage: {isError: false, text: ""},
};
this.dispatcherRef = dis.register(this._onAction);
From 20ec900405721dce6faf130a20223ff4faa01ff6 Mon Sep 17 00:00:00 2001
From: Jorik Schellekens
Date: Wed, 13 May 2020 15:36:53 +0100
Subject: [PATCH 132/196] Set font range
---
.../views/settings/tabs/user/AppearanceUserSettingsTab.js | 6 +-----
src/settings/Settings.js | 4 ++--
2 files changed, 3 insertions(+), 7 deletions(-)
diff --git a/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.js b/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.js
index ac98664be0..1ccc744dc7 100644
--- a/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.js
+++ b/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.js
@@ -252,11 +252,7 @@ export default class AppearanceUserSettingsTab extends React.Component {
Aa
{}}
diff --git a/src/settings/Settings.js b/src/settings/Settings.js
index 34610c0caf..afe8d2cecc 100644
--- a/src/settings/Settings.js
+++ b/src/settings/Settings.js
@@ -174,12 +174,12 @@ export const SETTINGS = {
"fontSizeMin": {
displayName: _td("Min font size"),
supportedLevels: LEVELS_ACCOUNT_SETTINGS,
- default: 14,
+ default: 13,
},
"fontSizeMax": {
displayName: _td("Max font size"),
supportedLevels: LEVELS_ACCOUNT_SETTINGS,
- default: 24,
+ default: 20,
},
"useCustomFontSize": {
displayName: _td("Custom font size"),
From 5c2abcf1a4b7bd9cbc35dd6c297073db56eb8a52 Mon Sep 17 00:00:00 2001
From: Jorik Schellekens
Date: Wed, 13 May 2020 17:05:37 +0100
Subject: [PATCH 133/196] Show username on continuations
---
res/css/views/rooms/_IRCLayout.scss | 10 ----------
1 file changed, 10 deletions(-)
diff --git a/res/css/views/rooms/_IRCLayout.scss b/res/css/views/rooms/_IRCLayout.scss
index 8d48c72f8a..f2a616f9c9 100644
--- a/res/css/views/rooms/_IRCLayout.scss
+++ b/res/css/views/rooms/_IRCLayout.scss
@@ -157,16 +157,6 @@ $irc-line-height: $font-18px;
}
}
- .mx_EventTile_continuation:not(.mx_EventTile_info) {
- > .mx_EventTile_avatar {
- visibility: hidden;
- }
-
- > .mx_SenderProfile {
- visibility: hidden;
- }
- }
-
// Suppress highlight thing from the normal Layout.
.mx_EventTile:hover.mx_EventTile_verified .mx_EventTile_line,
.mx_EventTile:hover.mx_EventTile_unverified .mx_EventTile_line,
From fc6e5227aced6f801bc1f1ffa3c7cfc86d84ef6d Mon Sep 17 00:00:00 2001
From: Jorik Schellekens
Date: Wed, 13 May 2020 22:08:29 +0100
Subject: [PATCH 134/196] FIx roomsublist heights.
- also fiddles the font size numbers
---
res/css/structures/_TagPanel.scss | 2 +-
res/css/views/rooms/_RoomTile.scss | 3 ++-
src/components/structures/RoomSubList.js | 4 ++--
src/components/views/avatars/BaseAvatar.js | 20 +++++++++----------
src/components/views/rooms/EventTile.js | 2 +-
.../views/rooms/ReadReceiptMarker.js | 2 +-
.../tabs/user/AppearanceUserSettingsTab.js | 2 +-
src/utils/{rem.js => units.ts} | 9 ++++++++-
8 files changed, 26 insertions(+), 18 deletions(-)
rename src/utils/{rem.js => units.ts} (77%)
diff --git a/res/css/structures/_TagPanel.scss b/res/css/structures/_TagPanel.scss
index 536c88be63..1f8443e395 100644
--- a/res/css/structures/_TagPanel.scss
+++ b/res/css/structures/_TagPanel.scss
@@ -69,7 +69,7 @@ limitations under the License.
height: 100%;
}
.mx_TagPanel .mx_TagPanel_tagTileContainer > div {
- height: $font-40px;
+ height: 40px;
padding: 10px 0 9px 0;
}
diff --git a/res/css/views/rooms/_RoomTile.scss b/res/css/views/rooms/_RoomTile.scss
index 5bc7d5624d..759dce5afa 100644
--- a/res/css/views/rooms/_RoomTile.scss
+++ b/res/css/views/rooms/_RoomTile.scss
@@ -20,7 +20,7 @@ limitations under the License.
flex-direction: row;
align-items: center;
cursor: pointer;
- height: $font-34px;
+ height: 32px;
margin: 0;
padding: 0 8px 0 10px;
position: relative;
@@ -81,6 +81,7 @@ limitations under the License.
.mx_RoomTile_avatar_container {
position: relative;
+ display: flex;
}
.mx_RoomTile_avatar {
diff --git a/src/components/structures/RoomSubList.js b/src/components/structures/RoomSubList.js
index c8f9ba1713..245b5f9bea 100644
--- a/src/components/structures/RoomSubList.js
+++ b/src/components/structures/RoomSubList.js
@@ -32,7 +32,7 @@ import RoomTile from "../views/rooms/RoomTile";
import LazyRenderList from "../views/elements/LazyRenderList";
import {_t} from "../../languageHandler";
import {RovingTabIndexWrapper} from "../../accessibility/RovingTabIndex";
-import {toRem} from "../../utils/rem";
+import {toPx} from "../../utils/units";
// turn this on for drop & drag console debugging galore
const debug = false;
@@ -420,7 +420,7 @@ export default class RoomSubList extends React.PureComponent {
setHeight = (height) => {
if (this._subList.current) {
- this._subList.current.style.height = toRem(height);
+ this._subList.current.style.height = toPx(height);
}
this._updateLazyRenderHeight(height);
};
diff --git a/src/components/views/avatars/BaseAvatar.js b/src/components/views/avatars/BaseAvatar.js
index a9bee9cda0..704e6438c8 100644
--- a/src/components/views/avatars/BaseAvatar.js
+++ b/src/components/views/avatars/BaseAvatar.js
@@ -24,7 +24,7 @@ import * as AvatarLogic from '../../../Avatar';
import SettingsStore from "../../../settings/SettingsStore";
import AccessibleButton from '../elements/AccessibleButton';
import MatrixClientContext from "../../../contexts/MatrixClientContext";
-import {toRem} from "../../../utils/rem";
+import {toPx} from "../../../utils/units";
export default createReactClass({
displayName: 'BaseAvatar',
@@ -166,9 +166,9 @@ export default createReactClass({
const textNode = (
{ initialLetter }
@@ -179,8 +179,8 @@ export default createReactClass({
alt="" title={title} onError={this.onError}
aria-hidden="true"
style={{
- width: toRem(width),
- height: toRem(height)
+ width: toPx(width),
+ height: toPx(height)
}} />
);
if (onClick != null) {
@@ -210,8 +210,8 @@ export default createReactClass({
onClick={onClick}
onError={this.onError}
style={{
- width: toRem(width),
- height: toRem(height),
+ width: toPx(width),
+ height: toPx(height),
}}
title={title} alt=""
inputRef={inputRef}
@@ -224,8 +224,8 @@ export default createReactClass({
src={imageUrl}
onError={this.onError}
style={{
- width: toRem(width),
- height: toRem(height),
+ width: toPx(width),
+ height: toPx(height),
}}
title={title} alt=""
ref={inputRef}
diff --git a/src/components/views/rooms/EventTile.js b/src/components/views/rooms/EventTile.js
index 0881fb3b67..993639321a 100644
--- a/src/components/views/rooms/EventTile.js
+++ b/src/components/views/rooms/EventTile.js
@@ -34,7 +34,7 @@ import {ALL_RULE_TYPES} from "../../../mjolnir/BanList";
import * as ObjectUtils from "../../../ObjectUtils";
import MatrixClientContext from "../../../contexts/MatrixClientContext";
import {E2E_STATE} from "./E2EIcon";
-import {toRem} from "../../../utils/rem";
+import {toRem} from "../../../utils/units";
const eventTileTypes = {
'm.room.message': 'messages.MessageEvent',
diff --git a/src/components/views/rooms/ReadReceiptMarker.js b/src/components/views/rooms/ReadReceiptMarker.js
index 20d39a7f84..2fe577377d 100644
--- a/src/components/views/rooms/ReadReceiptMarker.js
+++ b/src/components/views/rooms/ReadReceiptMarker.js
@@ -23,7 +23,7 @@ import { _t } from '../../../languageHandler';
import {formatDate} from '../../../DateUtils';
import Velociraptor from "../../../Velociraptor";
import * as sdk from "../../../index";
-import {toRem} from "../../../utils/rem";
+import {toRem} from "../../../utils/units";
let bounce = false;
try {
diff --git a/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.js b/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.js
index 1ccc744dc7..63857ed9c2 100644
--- a/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.js
+++ b/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.js
@@ -252,7 +252,7 @@ export default class AppearanceUserSettingsTab extends React.Component {
Aa
{}}
diff --git a/src/utils/rem.js b/src/utils/units.ts
similarity index 77%
rename from src/utils/rem.js
rename to src/utils/units.ts
index 8784502961..54dd6b0523 100644
--- a/src/utils/rem.js
+++ b/src/utils/units.ts
@@ -14,7 +14,14 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
+/* Simple utils for formatting style values
+ */
+
// converts a pixel value to rem.
-export function toRem(pixelValue) {
+export function toRem(pixelValue: number): string {
return pixelValue / 15 + "rem";
}
+
+export function toPx(pixelValue: number): string {
+ return pixelValue + "px";
+}
From 03e090f4e6f65f71698d7ef118b491bd7ed580d0 Mon Sep 17 00:00:00 2001
From: Jorik Schellekens
Date: Wed, 13 May 2020 22:55:14 +0100
Subject: [PATCH 135/196] fix chevron
---
res/css/structures/_TopLeftMenuButton.scss | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/res/css/structures/_TopLeftMenuButton.scss b/res/css/structures/_TopLeftMenuButton.scss
index 53d44e7c24..8d2e36bcd6 100644
--- a/res/css/structures/_TopLeftMenuButton.scss
+++ b/res/css/structures/_TopLeftMenuButton.scss
@@ -43,7 +43,7 @@ limitations under the License.
margin: 0 7px;
mask: url('$(res)/img/feather-customised/dropdown-arrow.svg');
mask-repeat: no-repeat;
- width: 10px;
+ width: $font-22px;
height: 6px;
background-color: $roomsublist-label-fg-color;
}
From fa83df4bde7b317737a27a8cb24d2b44aa633750 Mon Sep 17 00:00:00 2001
From: Travis Ralston
Date: Wed, 13 May 2020 21:07:29 -0600
Subject: [PATCH 136/196] Convert dispatcher to TypeScript and replace async
usage with new class
Due to TypeScript and flux's types being annoying and highly typesafe, we need an AsyncActionPayload which intentionally doesn't use the 'action' property. This looks a bit awkward, though for the rare cases we do actually fire async actions it should be fine enough.
The call signature changes slightly for async events, therefore this commit also updates its usages for async events.
The `fire()` function is to be used in a future commit.
Remove biased comment
---
package.json | 1 +
src/actions/RoomListActions.js | 145 -----------------
src/actions/RoomListActions.ts | 151 ++++++++++++++++++
src/actions/TagOrderActions.js | 109 -------------
src/actions/TagOrderActions.ts | 112 +++++++++++++
.../{actionCreators.js => actionCreators.ts} | 14 +-
src/dispatcher.js | 58 -------
src/dispatcher.ts | 121 ++++++++++++++
tsconfig.json | 3 +-
yarn.lock | 21 +++
10 files changed, 417 insertions(+), 318 deletions(-)
delete mode 100644 src/actions/RoomListActions.js
create mode 100644 src/actions/RoomListActions.ts
delete mode 100644 src/actions/TagOrderActions.js
create mode 100644 src/actions/TagOrderActions.ts
rename src/actions/{actionCreators.js => actionCreators.ts} (80%)
delete mode 100644 src/dispatcher.js
create mode 100644 src/dispatcher.ts
diff --git a/package.json b/package.json
index 92d228a812..2258d5e3b6 100644
--- a/package.json
+++ b/package.json
@@ -118,6 +118,7 @@
"@babel/register": "^7.7.4",
"@peculiar/webcrypto": "^1.0.22",
"@types/classnames": "^2.2.10",
+ "@types/flux": "^3.1.9",
"@types/modernizr": "^3.5.3",
"@types/react": "16.9",
"babel-eslint": "^10.0.3",
diff --git a/src/actions/RoomListActions.js b/src/actions/RoomListActions.js
deleted file mode 100644
index 10a3848dda..0000000000
--- a/src/actions/RoomListActions.js
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
-Copyright 2018 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.
-*/
-
-import { asyncAction } from './actionCreators';
-import RoomListStore, {TAG_DM} from '../stores/RoomListStore';
-import Modal from '../Modal';
-import * as Rooms from '../Rooms';
-import { _t } from '../languageHandler';
-import * as sdk from '../index';
-
-const RoomListActions = {};
-
-/**
- * Creates an action thunk that will do an asynchronous request to
- * tag room.
- *
- * @param {MatrixClient} matrixClient the matrix client to set the
- * account data on.
- * @param {Room} room the room to tag.
- * @param {string} oldTag the tag to remove (unless oldTag ==== newTag)
- * @param {string} newTag the tag with which to tag the room.
- * @param {?number} oldIndex the previous position of the room in the
- * list of rooms.
- * @param {?number} newIndex the new position of the room in the list
- * of rooms.
- * @returns {function} an action thunk.
- * @see asyncAction
- */
-RoomListActions.tagRoom = function(matrixClient, room, oldTag, newTag, oldIndex, newIndex) {
- let metaData = null;
-
- // Is the tag ordered manually?
- if (newTag && !newTag.match(/^(m\.lowpriority|im\.vector\.fake\.(invite|recent|direct|archived))$/)) {
- const lists = RoomListStore.getRoomLists();
- const newList = [...lists[newTag]];
-
- newList.sort((a, b) => a.tags[newTag].order - b.tags[newTag].order);
-
- // If the room was moved "down" (increasing index) in the same list we
- // need to use the orders of the tiles with indices shifted by +1
- const offset = (
- newTag === oldTag && oldIndex < newIndex
- ) ? 1 : 0;
-
- const indexBefore = offset + newIndex - 1;
- const indexAfter = offset + newIndex;
-
- const prevOrder = indexBefore <= 0 ?
- 0 : newList[indexBefore].tags[newTag].order;
- const nextOrder = indexAfter >= newList.length ?
- 1 : newList[indexAfter].tags[newTag].order;
-
- metaData = {
- order: (prevOrder + nextOrder) / 2.0,
- };
- }
-
- return asyncAction('RoomListActions.tagRoom', () => {
- const promises = [];
- const roomId = room.roomId;
-
- // Evil hack to get DMs behaving
- if ((oldTag === undefined && newTag === TAG_DM) ||
- (oldTag === TAG_DM && newTag === undefined)
- ) {
- return Rooms.guessAndSetDMRoom(
- room, newTag === TAG_DM,
- ).catch((err) => {
- const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
- console.error("Failed to set direct chat tag " + err);
- Modal.createTrackedDialog('Failed to set direct chat tag', '', ErrorDialog, {
- title: _t('Failed to set direct chat tag'),
- description: ((err && err.message) ? err.message : _t('Operation failed')),
- });
- });
- }
-
- const hasChangedSubLists = oldTag !== newTag;
-
- // More evilness: We will still be dealing with moving to favourites/low prio,
- // but we avoid ever doing a request with TAG_DM.
- //
- // if we moved lists, remove the old tag
- if (oldTag && oldTag !== TAG_DM &&
- hasChangedSubLists
- ) {
- const promiseToDelete = matrixClient.deleteRoomTag(
- roomId, oldTag,
- ).catch(function(err) {
- const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
- console.error("Failed to remove tag " + oldTag + " from room: " + err);
- Modal.createTrackedDialog('Failed to remove tag from room', '', ErrorDialog, {
- title: _t('Failed to remove tag %(tagName)s from room', {tagName: oldTag}),
- description: ((err && err.message) ? err.message : _t('Operation failed')),
- });
- });
-
- promises.push(promiseToDelete);
- }
-
- // if we moved lists or the ordering changed, add the new tag
- if (newTag && newTag !== TAG_DM &&
- (hasChangedSubLists || metaData)
- ) {
- // metaData is the body of the PUT to set the tag, so it must
- // at least be an empty object.
- metaData = metaData || {};
-
- const promiseToAdd = matrixClient.setRoomTag(roomId, newTag, metaData).catch(function(err) {
- const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
- console.error("Failed to add tag " + newTag + " to room: " + err);
- Modal.createTrackedDialog('Failed to add tag to room', '', ErrorDialog, {
- title: _t('Failed to add tag %(tagName)s to room', {tagName: newTag}),
- description: ((err && err.message) ? err.message : _t('Operation failed')),
- });
-
- throw err;
- });
-
- promises.push(promiseToAdd);
- }
-
- return Promise.all(promises);
- }, () => {
- // For an optimistic update
- return {
- room, oldTag, newTag, metaData,
- };
- });
-};
-
-export default RoomListActions;
diff --git a/src/actions/RoomListActions.ts b/src/actions/RoomListActions.ts
new file mode 100644
index 0000000000..8ad3ad0781
--- /dev/null
+++ b/src/actions/RoomListActions.ts
@@ -0,0 +1,151 @@
+/*
+Copyright 2018 New Vector Ltd
+Copyright 2020 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+import { asyncAction } from './actionCreators';
+import RoomListStore, { TAG_DM } from '../stores/RoomListStore';
+import Modal from '../Modal';
+import * as Rooms from '../Rooms';
+import { _t } from '../languageHandler';
+import * as sdk from '../index';
+import { MatrixClient } from "matrix-js-sdk/src/client";
+import { Room } from "matrix-js-sdk/src/models/room";
+import { AsyncActionPayload } from "../dispatcher";
+
+export default class RoomListActions {
+ /**
+ * Creates an action thunk that will do an asynchronous request to
+ * tag room.
+ *
+ * @param {MatrixClient} matrixClient the matrix client to set the
+ * account data on.
+ * @param {Room} room the room to tag.
+ * @param {string} oldTag the tag to remove (unless oldTag ==== newTag)
+ * @param {string} newTag the tag with which to tag the room.
+ * @param {?number} oldIndex the previous position of the room in the
+ * list of rooms.
+ * @param {?number} newIndex the new position of the room in the list
+ * of rooms.
+ * @returns {AsyncActionPayload} an async action payload
+ * @see asyncAction
+ */
+ public static tagRoom(
+ matrixClient: MatrixClient, room: Room,
+ oldTag: string, newTag: string,
+ oldIndex: number | null, newIndex: number | null,
+ ): AsyncActionPayload {
+ let metaData = null;
+
+ // Is the tag ordered manually?
+ if (newTag && !newTag.match(/^(m\.lowpriority|im\.vector\.fake\.(invite|recent|direct|archived))$/)) {
+ const lists = RoomListStore.getRoomLists();
+ const newList = [...lists[newTag]];
+
+ newList.sort((a, b) => a.tags[newTag].order - b.tags[newTag].order);
+
+ // If the room was moved "down" (increasing index) in the same list we
+ // need to use the orders of the tiles with indices shifted by +1
+ const offset = (
+ newTag === oldTag && oldIndex < newIndex
+ ) ? 1 : 0;
+
+ const indexBefore = offset + newIndex - 1;
+ const indexAfter = offset + newIndex;
+
+ const prevOrder = indexBefore <= 0 ?
+ 0 : newList[indexBefore].tags[newTag].order;
+ const nextOrder = indexAfter >= newList.length ?
+ 1 : newList[indexAfter].tags[newTag].order;
+
+ metaData = {
+ order: (prevOrder + nextOrder) / 2.0,
+ };
+ }
+
+ return asyncAction('RoomListActions.tagRoom', () => {
+ const promises = [];
+ const roomId = room.roomId;
+
+ // Evil hack to get DMs behaving
+ if ((oldTag === undefined && newTag === TAG_DM) ||
+ (oldTag === TAG_DM && newTag === undefined)
+ ) {
+ return Rooms.guessAndSetDMRoom(
+ room, newTag === TAG_DM,
+ ).catch((err) => {
+ const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
+ console.error("Failed to set direct chat tag " + err);
+ Modal.createTrackedDialog('Failed to set direct chat tag', '', ErrorDialog, {
+ title: _t('Failed to set direct chat tag'),
+ description: ((err && err.message) ? err.message : _t('Operation failed')),
+ });
+ });
+ }
+
+ const hasChangedSubLists = oldTag !== newTag;
+
+ // More evilness: We will still be dealing with moving to favourites/low prio,
+ // but we avoid ever doing a request with TAG_DM.
+ //
+ // if we moved lists, remove the old tag
+ if (oldTag && oldTag !== TAG_DM &&
+ hasChangedSubLists
+ ) {
+ const promiseToDelete = matrixClient.deleteRoomTag(
+ roomId, oldTag,
+ ).catch(function (err) {
+ const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
+ console.error("Failed to remove tag " + oldTag + " from room: " + err);
+ Modal.createTrackedDialog('Failed to remove tag from room', '', ErrorDialog, {
+ title: _t('Failed to remove tag %(tagName)s from room', {tagName: oldTag}),
+ description: ((err && err.message) ? err.message : _t('Operation failed')),
+ });
+ });
+
+ promises.push(promiseToDelete);
+ }
+
+ // if we moved lists or the ordering changed, add the new tag
+ if (newTag && newTag !== TAG_DM &&
+ (hasChangedSubLists || metaData)
+ ) {
+ // metaData is the body of the PUT to set the tag, so it must
+ // at least be an empty object.
+ metaData = metaData || {};
+
+ const promiseToAdd = matrixClient.setRoomTag(roomId, newTag, metaData).catch(function (err) {
+ const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
+ console.error("Failed to add tag " + newTag + " to room: " + err);
+ Modal.createTrackedDialog('Failed to add tag to room', '', ErrorDialog, {
+ title: _t('Failed to add tag %(tagName)s to room', {tagName: newTag}),
+ description: ((err && err.message) ? err.message : _t('Operation failed')),
+ });
+
+ throw err;
+ });
+
+ promises.push(promiseToAdd);
+ }
+
+ return Promise.all(promises);
+ }, () => {
+ // For an optimistic update
+ return {
+ room, oldTag, newTag, metaData,
+ };
+ });
+ }
+}
diff --git a/src/actions/TagOrderActions.js b/src/actions/TagOrderActions.js
deleted file mode 100644
index a257ff16d8..0000000000
--- a/src/actions/TagOrderActions.js
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
-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.
-*/
-
-import Analytics from '../Analytics';
-import { asyncAction } from './actionCreators';
-import TagOrderStore from '../stores/TagOrderStore';
-
-const TagOrderActions = {};
-
-/**
- * Creates an action thunk that will do an asynchronous request to
- * move a tag in TagOrderStore to destinationIx.
- *
- * @param {MatrixClient} matrixClient the matrix client to set the
- * account data on.
- * @param {string} tag the tag to move.
- * @param {number} destinationIx the new position of the tag.
- * @returns {function} an action thunk that will dispatch actions
- * indicating the status of the request.
- * @see asyncAction
- */
-TagOrderActions.moveTag = function(matrixClient, tag, destinationIx) {
- // Only commit tags if the state is ready, i.e. not null
- let tags = TagOrderStore.getOrderedTags();
- let removedTags = TagOrderStore.getRemovedTagsAccountData() || [];
- if (!tags) {
- return;
- }
-
- tags = tags.filter((t) => t !== tag);
- tags = [...tags.slice(0, destinationIx), tag, ...tags.slice(destinationIx)];
-
- removedTags = removedTags.filter((t) => t !== tag);
-
- const storeId = TagOrderStore.getStoreId();
-
- return asyncAction('TagOrderActions.moveTag', () => {
- Analytics.trackEvent('TagOrderActions', 'commitTagOrdering');
- return matrixClient.setAccountData(
- 'im.vector.web.tag_ordering',
- {tags, removedTags, _storeId: storeId},
- );
- }, () => {
- // For an optimistic update
- return {tags, removedTags};
- });
-};
-
-/**
- * Creates an action thunk that will do an asynchronous request to
- * label a tag as removed in im.vector.web.tag_ordering account data.
- *
- * The reason this is implemented with new state `removedTags` is that
- * we incrementally and initially populate `tags` with groups that
- * have been joined. If we remove a group from `tags`, it will just
- * get added (as it looks like a group we've recently joined).
- *
- * NB: If we ever support adding of tags (which is planned), we should
- * take special care to remove the tag from `removedTags` when we add
- * it.
- *
- * @param {MatrixClient} matrixClient the matrix client to set the
- * account data on.
- * @param {string} tag the tag to remove.
- * @returns {function} an action thunk that will dispatch actions
- * indicating the status of the request.
- * @see asyncAction
- */
-TagOrderActions.removeTag = function(matrixClient, tag) {
- // Don't change tags, just removedTags
- const tags = TagOrderStore.getOrderedTags();
- const removedTags = TagOrderStore.getRemovedTagsAccountData() || [];
-
- if (removedTags.includes(tag)) {
- // Return a thunk that doesn't do anything, we don't even need
- // an asynchronous action here, the tag is already removed.
- return () => {};
- }
-
- removedTags.push(tag);
-
- const storeId = TagOrderStore.getStoreId();
-
- return asyncAction('TagOrderActions.removeTag', () => {
- Analytics.trackEvent('TagOrderActions', 'removeTag');
- return matrixClient.setAccountData(
- 'im.vector.web.tag_ordering',
- {tags, removedTags, _storeId: storeId},
- );
- }, () => {
- // For an optimistic update
- return {removedTags};
- });
-};
-
-export default TagOrderActions;
diff --git a/src/actions/TagOrderActions.ts b/src/actions/TagOrderActions.ts
new file mode 100644
index 0000000000..57dd0b8793
--- /dev/null
+++ b/src/actions/TagOrderActions.ts
@@ -0,0 +1,112 @@
+/*
+Copyright 2017 New Vector Ltd
+Copyright 2020 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+import Analytics from '../Analytics';
+import { asyncAction } from './actionCreators';
+import TagOrderStore from '../stores/TagOrderStore';
+import { AsyncActionPayload } from "../dispatcher";
+import { MatrixClient } from "matrix-js-sdk/src/client";
+
+export default class TagOrderActions {
+
+ /**
+ * Creates an action thunk that will do an asynchronous request to
+ * move a tag in TagOrderStore to destinationIx.
+ *
+ * @param {MatrixClient} matrixClient the matrix client to set the
+ * account data on.
+ * @param {string} tag the tag to move.
+ * @param {number} destinationIx the new position of the tag.
+ * @returns {AsyncActionPayload} an async action payload that will
+ * dispatch actions indicating the status of the request.
+ * @see asyncAction
+ */
+ public static moveTag(matrixClient: MatrixClient, tag: string, destinationIx: number): AsyncActionPayload {
+ // Only commit tags if the state is ready, i.e. not null
+ let tags = TagOrderStore.getOrderedTags();
+ let removedTags = TagOrderStore.getRemovedTagsAccountData() || [];
+ if (!tags) {
+ return;
+ }
+
+ tags = tags.filter((t) => t !== tag);
+ tags = [...tags.slice(0, destinationIx), tag, ...tags.slice(destinationIx)];
+
+ removedTags = removedTags.filter((t) => t !== tag);
+
+ const storeId = TagOrderStore.getStoreId();
+
+ return asyncAction('TagOrderActions.moveTag', () => {
+ Analytics.trackEvent('TagOrderActions', 'commitTagOrdering');
+ return matrixClient.setAccountData(
+ 'im.vector.web.tag_ordering',
+ {tags, removedTags, _storeId: storeId},
+ );
+ }, () => {
+ // For an optimistic update
+ return {tags, removedTags};
+ });
+ };
+
+ /**
+ * Creates an action thunk that will do an asynchronous request to
+ * label a tag as removed in im.vector.web.tag_ordering account data.
+ *
+ * The reason this is implemented with new state `removedTags` is that
+ * we incrementally and initially populate `tags` with groups that
+ * have been joined. If we remove a group from `tags`, it will just
+ * get added (as it looks like a group we've recently joined).
+ *
+ * NB: If we ever support adding of tags (which is planned), we should
+ * take special care to remove the tag from `removedTags` when we add
+ * it.
+ *
+ * @param {MatrixClient} matrixClient the matrix client to set the
+ * account data on.
+ * @param {string} tag the tag to remove.
+ * @returns {function} an async action payload that will dispatch
+ * actions indicating the status of the request.
+ * @see asyncAction
+ */
+ public static removeTag(matrixClient: MatrixClient, tag: string): AsyncActionPayload {
+ // Don't change tags, just removedTags
+ const tags = TagOrderStore.getOrderedTags();
+ const removedTags = TagOrderStore.getRemovedTagsAccountData() || [];
+
+ if (removedTags.includes(tag)) {
+ // Return a thunk that doesn't do anything, we don't even need
+ // an asynchronous action here, the tag is already removed.
+ return () => {
+ };
+ }
+
+ removedTags.push(tag);
+
+ const storeId = TagOrderStore.getStoreId();
+
+ return asyncAction('TagOrderActions.removeTag', () => {
+ Analytics.trackEvent('TagOrderActions', 'removeTag');
+ return matrixClient.setAccountData(
+ 'im.vector.web.tag_ordering',
+ {tags, removedTags, _storeId: storeId},
+ );
+ }, () => {
+ // For an optimistic update
+ return {removedTags};
+ });
+ }
+}
diff --git a/src/actions/actionCreators.js b/src/actions/actionCreators.ts
similarity index 80%
rename from src/actions/actionCreators.js
rename to src/actions/actionCreators.ts
index 967ce609e7..3a0132a969 100644
--- a/src/actions/actionCreators.js
+++ b/src/actions/actionCreators.ts
@@ -1,5 +1,6 @@
/*
Copyright 2017 New Vector Ltd
+Copyright 2020 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,6 +15,8 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
+import { AsyncActionPayload } from "../dispatcher";
+
/**
* Create an action thunk that will dispatch actions indicating the current
* status of the Promise returned by fn.
@@ -25,9 +28,9 @@ limitations under the License.
* @param {function?} pendingFn a function that returns an object to assign
* to the `request` key of the ${id}.pending
* payload.
- * @returns {function} an action thunk - a function that uses its single
- * argument as a dispatch function to dispatch the
- * following actions:
+ * @returns {AsyncActionPayload} an async action payload. Includes a function
+ * that uses its single argument as a dispatch function
+ * to dispatch the following actions:
* `${id}.pending` and either
* `${id}.success` or
* `${id}.failure`.
@@ -41,8 +44,8 @@ limitations under the License.
* result is the result of the promise returned by
* `fn`.
*/
-export function asyncAction(id, fn, pendingFn) {
- return (dispatch) => {
+export function asyncAction(id: string, fn: () => Promise, pendingFn: () => any): AsyncActionPayload {
+ const helper = (dispatch) => {
dispatch({
action: id + '.pending',
request:
@@ -54,4 +57,5 @@ export function asyncAction(id, fn, pendingFn) {
dispatch({action: id + '.failure', err});
});
};
+ return new AsyncActionPayload(helper);
}
diff --git a/src/dispatcher.js b/src/dispatcher.js
deleted file mode 100644
index 5dfaa11345..0000000000
--- a/src/dispatcher.js
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
-Copyright 2015, 2016 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.
-*/
-
-'use strict';
-
-import flux from "flux";
-
-class MatrixDispatcher extends flux.Dispatcher {
- /**
- * @param {Object|function} payload Required. The payload to dispatch.
- * If an Object, must contain at least an 'action' key.
- * If a function, must have the signature (dispatch) => {...}.
- * @param {boolean=} sync Optional. Pass true to dispatch
- * synchronously. This is useful for anything triggering
- * an operation that the browser requires user interaction
- * for.
- */
- dispatch(payload, sync) {
- // Allow for asynchronous dispatching by accepting payloads that have the
- // type `function (dispatch) {...}`
- if (typeof payload === 'function') {
- payload((action) => {
- this.dispatch(action, sync);
- });
- return;
- }
-
- if (sync) {
- super.dispatch(payload);
- } else {
- // Unless the caller explicitly asked for us to dispatch synchronously,
- // we always set a timeout to do this: The flux dispatcher complains
- // if you dispatch from within a dispatch, so rather than action
- // handlers having to worry about not calling anything that might
- // then dispatch, we just do dispatches asynchronously.
- setTimeout(super.dispatch.bind(this, payload), 0);
- }
- }
-}
-
-if (global.mxDispatcher === undefined) {
- global.mxDispatcher = new MatrixDispatcher();
-}
-export default global.mxDispatcher;
diff --git a/src/dispatcher.ts b/src/dispatcher.ts
new file mode 100644
index 0000000000..fce99df055
--- /dev/null
+++ b/src/dispatcher.ts
@@ -0,0 +1,121 @@
+/*
+Copyright 2015, 2016 OpenMarket Ltd
+Copyright 2017 New Vector Ltd
+Copyright 2020 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+import { Dispatcher } from "flux";
+
+export enum Action {
+ // TODO: Populate with actual actions
+}
+
+// Dispatcher actions also extend into any arbitrary string, so support that.
+export type DispatcherAction = Action | string;
+
+/**
+ * The base dispatch type exposed by our dispatcher.
+ */
+export interface ActionPayload {
+ [property: string]: any; // effectively makes this 'extends Object'
+ action: DispatcherAction;
+}
+
+/**
+ * The function the dispatcher calls when ready for an AsyncActionPayload. The
+ * single argument is used to start a dispatch. First the dispatcher calls the
+ * outer function, then when the called function is ready it calls the cb
+ * function to issue the dispatch. It may call the callback repeatedly if needed.
+ */
+export type AsyncActionFn = (cb: (action: ActionPayload) => void) => void;
+
+/**
+ * An async version of ActionPayload
+ */
+export class AsyncActionPayload implements ActionPayload {
+ /**
+ * The function the dispatcher should call.
+ */
+ public readonly fn: AsyncActionFn;
+
+ /**
+ * @deprecated Not used on AsyncActionPayload.
+ */
+ public get action(): DispatcherAction {
+ return "NOT_USED";
+ }
+
+ /**
+ * Create a new AsyncActionPayload with the given ready function.
+ * @param {AsyncActionFn} readyFn The function to be called when the
+ * dispatcher is ready.
+ */
+ public constructor(readyFn: AsyncActionFn) {
+ this.fn = readyFn;
+ }
+}
+
+/**
+ * A dispatcher for ActionPayloads (the default within the SDK).
+ */
+export class MatrixDispatcher extends Dispatcher {
+ /**
+ * Dispatches an event on the dispatcher's event bus.
+ * @param {ActionPayload} payload Required. The payload to dispatch.
+ * @param {boolean=false} sync Optional. Pass true to dispatch
+ * synchronously. This is useful for anything triggering
+ * an operation that the browser requires user interaction
+ * for. Default false (async).
+ */
+ dispatch(payload: ActionPayload, sync = false) {
+ if (payload instanceof AsyncActionPayload) {
+ payload.fn((action: ActionPayload) => {
+ this.dispatch(action, sync);
+ });
+ return;
+ }
+
+ if (sync) {
+ super.dispatch(payload);
+ } else {
+ // Unless the caller explicitly asked for us to dispatch synchronously,
+ // we always set a timeout to do this: The flux dispatcher complains
+ // if you dispatch from within a dispatch, so rather than action
+ // handlers having to worry about not calling anything that might
+ // then dispatch, we just do dispatches asynchronously.
+ setTimeout(super.dispatch.bind(this, payload), 0);
+ }
+ }
+
+ /**
+ * Shorthand for dispatch({action: Action.WHATEVER}, sync). No additional
+ * properties can be included with this version.
+ * @param {Action} action The action to dispatch.
+ * @param {boolean=false} sync Whether the dispatch should be sync or not.
+ * @see dispatch(action: ActionPayload, sync: boolean)
+ */
+ fire(action: Action, sync = false) {
+ this.dispatch({action}, sync);
+ }
+}
+
+export const defaultDispatcher = new MatrixDispatcher();
+
+const anyGlobal = global;
+if (!anyGlobal.mxDispatcher) {
+ anyGlobal.mxDispatcher = defaultDispatcher;
+}
+
+export default defaultDispatcher;
diff --git a/tsconfig.json b/tsconfig.json
index b87f640734..8a01ca335e 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -14,7 +14,8 @@
"jsx": "react",
"types": [
"node",
- "react"
+ "react",
+ "flux"
]
},
"include": [
diff --git a/yarn.lock b/yarn.lock
index 520e976b17..99a9d07c7a 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1218,6 +1218,19 @@
resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7"
integrity sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==
+"@types/fbemitter@*":
+ version "2.0.32"
+ resolved "https://registry.yarnpkg.com/@types/fbemitter/-/fbemitter-2.0.32.tgz#8ed204da0f54e9c8eaec31b1eec91e25132d082c"
+ integrity sha1-jtIE2g9U6cjq7DGx7skeJRMtCCw=
+
+"@types/flux@^3.1.9":
+ version "3.1.9"
+ resolved "https://registry.yarnpkg.com/@types/flux/-/flux-3.1.9.tgz#ddfc9641ee2e2e6cb6cd730c6a48ef82e2076711"
+ integrity sha512-bSbDf4tTuN9wn3LTGPnH9wnSSLtR5rV7UPWFpM00NJ1pSTBwCzeZG07XsZ9lBkxwngrqjDtM97PLt5IuIdCQUA==
+ dependencies:
+ "@types/fbemitter" "*"
+ "@types/react" "*"
+
"@types/glob@^7.1.1":
version "7.1.1"
resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.1.tgz#aa59a1c6e3fbc421e07ccd31a944c30eba521575"
@@ -1272,6 +1285,14 @@
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.3.tgz#2ab0d5da2e5815f94b0b9d4b95d1e5f243ab2ca7"
integrity sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==
+"@types/react@*":
+ version "16.9.35"
+ resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.35.tgz#a0830d172e8aadd9bd41709ba2281a3124bbd368"
+ integrity sha512-q0n0SsWcGc8nDqH2GJfWQWUOmZSJhXV64CjVN5SvcNti3TdEaA3AH0D8DwNmMdzjMAC/78tB8nAZIlV8yTz+zQ==
+ dependencies:
+ "@types/prop-types" "*"
+ csstype "^2.2.0"
+
"@types/react@16.9":
version "16.9.32"
resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.32.tgz#f6368625b224604148d1ddf5920e4fefbd98d383"
From 90a898d03ff5e6da0a436136de167ee1547297c5 Mon Sep 17 00:00:00 2001
From: Travis Ralston
Date: Wed, 13 May 2020 20:41:41 -0600
Subject: [PATCH 137/196] Move dispatcher into a subdirectory
We're expecting to have a whole bunch of types for the dispatched payloads, so pull the thing into a directory we can throw them in.
---
src/BasePlatform.js | 2 +-
src/CallHandler.js | 2 +-
src/ContentMessages.js | 2 +-
src/FromWidgetPostMessageApi.js | 2 +-
src/Lifecycle.js | 2 +-
src/Modal.js | 2 +-
src/Notifier.js | 2 +-
src/Presence.js | 2 +-
src/Registration.js | 2 +-
src/Resend.js | 2 +-
src/ScalarMessaging.js | 2 +-
src/SlashCommands.tsx | 2 +-
src/UserActivity.js | 2 +-
src/actions/MatrixActionCreators.js | 2 +-
src/actions/RoomListActions.ts | 2 +-
src/actions/TagOrderActions.ts | 2 +-
src/actions/actionCreators.ts | 2 +-
.../views/dialogs/eventindex/DisableEventIndexDialog.js | 2 +-
.../views/dialogs/keybackup/NewRecoveryMethodDialog.js | 2 +-
.../views/dialogs/keybackup/RecoveryMethodRemovedDialog.js | 2 +-
src/components/structures/CustomRoomTagPanel.js | 2 +-
src/components/structures/EmbeddedPage.js | 2 +-
src/components/structures/GroupView.js | 2 +-
src/components/structures/HomePage.tsx | 2 +-
src/components/structures/LeftPanel.js | 2 +-
src/components/structures/LoggedInView.tsx | 2 +-
src/components/structures/MatrixChat.tsx | 2 +-
src/components/structures/MyGroups.js | 2 +-
src/components/structures/RightPanel.js | 2 +-
src/components/structures/RoomDirectory.js | 2 +-
src/components/structures/RoomStatusBar.js | 2 +-
src/components/structures/RoomSubList.js | 2 +-
src/components/structures/RoomView.js | 2 +-
src/components/structures/SearchBox.js | 2 +-
src/components/structures/TagPanel.js | 2 +-
src/components/structures/TagPanelButtons.js | 2 +-
src/components/structures/TimelinePanel.js | 2 +-
src/components/structures/TopLeftMenuButton.js | 2 +-
src/components/structures/UploadBar.js | 2 +-
src/components/structures/auth/Registration.js | 2 +-
src/components/structures/auth/SoftLogout.js | 2 +-
src/components/views/avatars/MemberAvatar.js | 2 +-
src/components/views/context_menus/MessageContextMenu.js | 2 +-
src/components/views/context_menus/RoomTileContextMenu.js | 2 +-
src/components/views/context_menus/TagTileContextMenu.js | 2 +-
src/components/views/context_menus/TopLeftMenu.js | 2 +-
src/components/views/dialogs/AddressPickerDialog.js | 2 +-
src/components/views/dialogs/CreateGroupDialog.js | 2 +-
src/components/views/dialogs/CryptoStoreTooNewDialog.js | 2 +-
src/components/views/dialogs/DeviceVerifyDialog.js | 2 +-
src/components/views/dialogs/IntegrationsDisabledDialog.js | 2 +-
src/components/views/dialogs/InviteDialog.js | 2 +-
src/components/views/dialogs/LogoutDialog.js | 2 +-
src/components/views/dialogs/RoomSettingsDialog.js | 2 +-
src/components/views/elements/ActionButton.js | 2 +-
src/components/views/elements/AppTile.js | 2 +-
src/components/views/elements/Flair.js | 2 +-
src/components/views/elements/PersistedElement.js | 2 +-
src/components/views/elements/Pill.js | 2 +-
src/components/views/elements/ReplyThread.js | 2 +-
src/components/views/elements/TagTile.js | 2 +-
src/components/views/elements/Tooltip.js | 2 +-
src/components/views/globals/CookieBar.js | 2 +-
src/components/views/groups/GroupInviteTile.js | 2 +-
src/components/views/groups/GroupMemberInfo.js | 2 +-
src/components/views/groups/GroupMemberList.js | 2 +-
src/components/views/groups/GroupMemberTile.js | 2 +-
src/components/views/groups/GroupRoomInfo.js | 2 +-
src/components/views/groups/GroupRoomTile.js | 2 +-
src/components/views/groups/GroupTile.js | 2 +-
src/components/views/messages/MKeyVerificationRequest.js | 2 +-
src/components/views/messages/MessageActionBar.js | 2 +-
src/components/views/messages/RoomCreate.js | 2 +-
src/components/views/messages/TextualBody.js | 2 +-
src/components/views/right_panel/HeaderButtons.js | 2 +-
src/components/views/right_panel/UserInfo.js | 2 +-
src/components/views/room_settings/ColorSettings.js | 2 +-
src/components/views/room_settings/UrlPreviewSettings.js | 2 +-
src/components/views/rooms/AppsDrawer.js | 2 +-
src/components/views/rooms/AuxPanel.js | 2 +-
src/components/views/rooms/EditMessageComposer.js | 2 +-
src/components/views/rooms/EventTile.js | 2 +-
src/components/views/rooms/ForwardMessage.js | 2 +-
src/components/views/rooms/MemberInfo.js | 2 +-
src/components/views/rooms/MemberList.js | 2 +-
src/components/views/rooms/MemberTile.js | 2 +-
src/components/views/rooms/MessageComposer.js | 2 +-
src/components/views/rooms/PinnedEventTile.js | 2 +-
src/components/views/rooms/ReplyPreview.js | 2 +-
src/components/views/rooms/RoomBreadcrumbs.js | 2 +-
src/components/views/rooms/RoomDetailList.js | 2 +-
src/components/views/rooms/RoomList.js | 2 +-
src/components/views/rooms/RoomPreviewBar.js | 2 +-
src/components/views/rooms/RoomTile.js | 2 +-
src/components/views/rooms/SendMessageComposer.js | 2 +-
src/components/views/rooms/Stickerpicker.js | 2 +-
src/components/views/rooms/ThirdPartyMemberInfo.js | 2 +-
src/components/views/settings/ChangePassword.js | 2 +-
src/components/views/settings/EnableNotificationsButton.js | 2 +-
src/components/views/settings/IntegrationManager.js | 2 +-
src/components/views/settings/SetIdServer.js | 2 +-
.../views/settings/tabs/room/AdvancedRoomSettingsTab.js | 2 +-
.../views/settings/tabs/room/GeneralRoomSettingsTab.js | 2 +-
.../views/settings/tabs/user/GeneralUserSettingsTab.js | 2 +-
.../views/settings/tabs/user/SecurityUserSettingsTab.js | 2 +-
src/components/views/toasts/BulkUnverifiedSessionsToast.js | 2 +-
src/components/views/toasts/VerificationRequestToast.js | 2 +-
src/components/views/voip/CallPreview.js | 2 +-
src/components/views/voip/CallView.js | 2 +-
src/components/views/voip/IncomingCallBox.js | 2 +-
src/components/views/voip/VideoView.js | 2 +-
src/createRoom.js | 2 +-
src/cryptodevices.js | 2 +-
src/{ => dispatcher}/dispatcher.ts | 0
src/mjolnir/Mjolnir.js | 2 +-
src/settings/SettingsStore.js | 2 +-
src/settings/controllers/CustomStatusController.js | 2 +-
src/stores/CustomRoomTagStore.js | 2 +-
src/stores/GroupStore.js | 2 +-
src/stores/LifecycleStore.js | 2 +-
src/stores/RightPanelStore.js | 2 +-
src/stores/RoomListStore.js | 2 +-
src/stores/RoomViewStore.js | 2 +-
src/stores/SessionStore.js | 2 +-
src/stores/TagOrderStore.js | 2 +-
src/theme.js | 2 +-
src/utils/WidgetUtils.js | 2 +-
src/verification.js | 2 +-
test/components/views/rooms/RoomList-test.js | 2 +-
test/test-utils.js | 2 +-
130 files changed, 129 insertions(+), 129 deletions(-)
rename src/{ => dispatcher}/dispatcher.ts (100%)
diff --git a/src/BasePlatform.js b/src/BasePlatform.js
index 7214031586..46bd9150df 100644
--- a/src/BasePlatform.js
+++ b/src/BasePlatform.js
@@ -20,7 +20,7 @@ limitations under the License.
*/
import {MatrixClient} from "matrix-js-sdk";
-import dis from './dispatcher';
+import dis from './dispatcher/dispatcher';
import BaseEventIndexManager from './indexing/BaseEventIndexManager';
/**
diff --git a/src/CallHandler.js b/src/CallHandler.js
index 2bfe10850a..c95ed16eb3 100644
--- a/src/CallHandler.js
+++ b/src/CallHandler.js
@@ -59,7 +59,7 @@ import Modal from './Modal';
import * as sdk from './index';
import { _t } from './languageHandler';
import Matrix from 'matrix-js-sdk';
-import dis from './dispatcher';
+import dis from './dispatcher/dispatcher';
import { showUnknownDeviceDialogForCalls } from './cryptodevices';
import WidgetUtils from './utils/WidgetUtils';
import WidgetEchoStore from './stores/WidgetEchoStore';
diff --git a/src/ContentMessages.js b/src/ContentMessages.js
index 34379c029b..4f5a1a1220 100644
--- a/src/ContentMessages.js
+++ b/src/ContentMessages.js
@@ -18,7 +18,7 @@ limitations under the License.
'use strict';
import extend from './extend';
-import dis from './dispatcher';
+import dis from './dispatcher/dispatcher';
import {MatrixClientPeg} from './MatrixClientPeg';
import * as sdk from './index';
import { _t } from './languageHandler';
diff --git a/src/FromWidgetPostMessageApi.js b/src/FromWidgetPostMessageApi.js
index c9793d40f7..102afa6bf1 100644
--- a/src/FromWidgetPostMessageApi.js
+++ b/src/FromWidgetPostMessageApi.js
@@ -17,7 +17,7 @@ limitations under the License.
*/
import URL from 'url';
-import dis from './dispatcher';
+import dis from './dispatcher/dispatcher';
import WidgetMessagingEndpoint from './WidgetMessagingEndpoint';
import ActiveWidgetStore from './stores/ActiveWidgetStore';
import {MatrixClientPeg} from "./MatrixClientPeg";
diff --git a/src/Lifecycle.js b/src/Lifecycle.js
index 1baa6c8e0c..22c5d48317 100644
--- a/src/Lifecycle.js
+++ b/src/Lifecycle.js
@@ -26,7 +26,7 @@ import Analytics from './Analytics';
import Notifier from './Notifier';
import UserActivity from './UserActivity';
import Presence from './Presence';
-import dis from './dispatcher';
+import dis from './dispatcher/dispatcher';
import DMRoomMap from './utils/DMRoomMap';
import Modal from './Modal';
import * as sdk from './index';
diff --git a/src/Modal.js b/src/Modal.js
index de441740f1..9b9f190d58 100644
--- a/src/Modal.js
+++ b/src/Modal.js
@@ -18,7 +18,7 @@ limitations under the License.
import React from 'react';
import ReactDOM from 'react-dom';
import Analytics from './Analytics';
-import dis from './dispatcher';
+import dis from './dispatcher/dispatcher';
import {defer} from './utils/promise';
import AsyncWrapper from './AsyncWrapper';
diff --git a/src/Notifier.js b/src/Notifier.js
index ec92840998..2ffa92452b 100644
--- a/src/Notifier.js
+++ b/src/Notifier.js
@@ -21,7 +21,7 @@ import PlatformPeg from './PlatformPeg';
import * as TextForEvent from './TextForEvent';
import Analytics from './Analytics';
import * as Avatar from './Avatar';
-import dis from './dispatcher';
+import dis from './dispatcher/dispatcher';
import * as sdk from './index';
import { _t } from './languageHandler';
import Modal from './Modal';
diff --git a/src/Presence.js b/src/Presence.js
index 2fc13a090b..42bca35f96 100644
--- a/src/Presence.js
+++ b/src/Presence.js
@@ -17,7 +17,7 @@ limitations under the License.
*/
import {MatrixClientPeg} from "./MatrixClientPeg";
-import dis from "./dispatcher";
+import dis from "./dispatcher/dispatcher";
import Timer from './utils/Timer';
// Time in ms after that a user is considered as unavailable/away
diff --git a/src/Registration.js b/src/Registration.js
index ca162bac03..32c3d9cc35 100644
--- a/src/Registration.js
+++ b/src/Registration.js
@@ -20,7 +20,7 @@ limitations under the License.
* registration code.
*/
-import dis from './dispatcher';
+import dis from './dispatcher/dispatcher';
import * as sdk from './index';
import Modal from './Modal';
import { _t } from './languageHandler';
diff --git a/src/Resend.js b/src/Resend.js
index 6d6c18cf27..f5f24bffa5 100644
--- a/src/Resend.js
+++ b/src/Resend.js
@@ -16,7 +16,7 @@ limitations under the License.
*/
import {MatrixClientPeg} from './MatrixClientPeg';
-import dis from './dispatcher';
+import dis from './dispatcher/dispatcher';
import { EventStatus } from 'matrix-js-sdk';
export default class Resend {
diff --git a/src/ScalarMessaging.js b/src/ScalarMessaging.js
index 9731e42825..315c2d86f4 100644
--- a/src/ScalarMessaging.js
+++ b/src/ScalarMessaging.js
@@ -238,7 +238,7 @@ Example:
import {MatrixClientPeg} from './MatrixClientPeg';
import { MatrixEvent } from 'matrix-js-sdk';
-import dis from './dispatcher';
+import dis from './dispatcher/dispatcher';
import WidgetUtils from './utils/WidgetUtils';
import RoomViewStore from './stores/RoomViewStore';
import { _t } from './languageHandler';
diff --git a/src/SlashCommands.tsx b/src/SlashCommands.tsx
index fbb9e2eb0e..fd157b2b4c 100644
--- a/src/SlashCommands.tsx
+++ b/src/SlashCommands.tsx
@@ -21,7 +21,7 @@ limitations under the License.
import * as React from 'react';
import {MatrixClientPeg} from './MatrixClientPeg';
-import dis from './dispatcher';
+import dis from './dispatcher/dispatcher';
import * as sdk from './index';
import {_t, _td} from './languageHandler';
import Modal from './Modal';
diff --git a/src/UserActivity.js b/src/UserActivity.js
index 0d1b4d0cc0..0174aebaf5 100644
--- a/src/UserActivity.js
+++ b/src/UserActivity.js
@@ -15,7 +15,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-import dis from './dispatcher';
+import dis from './dispatcher/dispatcher';
import Timer from './utils/Timer';
// important these are larger than the timeouts of timers
diff --git a/src/actions/MatrixActionCreators.js b/src/actions/MatrixActionCreators.js
index c89ec44435..93a4fcf07c 100644
--- a/src/actions/MatrixActionCreators.js
+++ b/src/actions/MatrixActionCreators.js
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-import dis from '../dispatcher';
+import dis from '../dispatcher/dispatcher';
// TODO: migrate from sync_state to MatrixActions.sync so that more js-sdk events
// become dispatches in the same place.
diff --git a/src/actions/RoomListActions.ts b/src/actions/RoomListActions.ts
index 8ad3ad0781..0cdd3a86d8 100644
--- a/src/actions/RoomListActions.ts
+++ b/src/actions/RoomListActions.ts
@@ -23,7 +23,7 @@ import { _t } from '../languageHandler';
import * as sdk from '../index';
import { MatrixClient } from "matrix-js-sdk/src/client";
import { Room } from "matrix-js-sdk/src/models/room";
-import { AsyncActionPayload } from "../dispatcher";
+import { AsyncActionPayload } from "../dispatcher/dispatcher";
export default class RoomListActions {
/**
diff --git a/src/actions/TagOrderActions.ts b/src/actions/TagOrderActions.ts
index 57dd0b8793..fa86e3a6b1 100644
--- a/src/actions/TagOrderActions.ts
+++ b/src/actions/TagOrderActions.ts
@@ -18,7 +18,7 @@ limitations under the License.
import Analytics from '../Analytics';
import { asyncAction } from './actionCreators';
import TagOrderStore from '../stores/TagOrderStore';
-import { AsyncActionPayload } from "../dispatcher";
+import { AsyncActionPayload } from "../dispatcher/dispatcher";
import { MatrixClient } from "matrix-js-sdk/src/client";
export default class TagOrderActions {
diff --git a/src/actions/actionCreators.ts b/src/actions/actionCreators.ts
index 3a0132a969..78525a9509 100644
--- a/src/actions/actionCreators.ts
+++ b/src/actions/actionCreators.ts
@@ -15,7 +15,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-import { AsyncActionPayload } from "../dispatcher";
+import { AsyncActionPayload } from "../dispatcher/dispatcher";
/**
* Create an action thunk that will dispatch actions indicating the current
diff --git a/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.js b/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.js
index 120b086ef6..8af0bf278e 100644
--- a/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.js
+++ b/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.js
@@ -17,7 +17,7 @@ limitations under the License.
import React from 'react';
import * as sdk from '../../../../index';
import PropTypes from 'prop-types';
-import dis from "../../../../dispatcher";
+import dis from "../../../../dispatcher/dispatcher";
import { _t } from '../../../../languageHandler';
import SettingsStore, {SettingLevel} from "../../../../settings/SettingsStore";
diff --git a/src/async-components/views/dialogs/keybackup/NewRecoveryMethodDialog.js b/src/async-components/views/dialogs/keybackup/NewRecoveryMethodDialog.js
index 9e2264a960..f00f2d9c3c 100644
--- a/src/async-components/views/dialogs/keybackup/NewRecoveryMethodDialog.js
+++ b/src/async-components/views/dialogs/keybackup/NewRecoveryMethodDialog.js
@@ -19,7 +19,7 @@ import React from "react";
import PropTypes from "prop-types";
import * as sdk from "../../../../index";
import {MatrixClientPeg} from '../../../../MatrixClientPeg';
-import dis from "../../../../dispatcher";
+import dis from "../../../../dispatcher/dispatcher";
import { _t } from "../../../../languageHandler";
import Modal from "../../../../Modal";
diff --git a/src/async-components/views/dialogs/keybackup/RecoveryMethodRemovedDialog.js b/src/async-components/views/dialogs/keybackup/RecoveryMethodRemovedDialog.js
index c5222dafd5..722334cd70 100644
--- a/src/async-components/views/dialogs/keybackup/RecoveryMethodRemovedDialog.js
+++ b/src/async-components/views/dialogs/keybackup/RecoveryMethodRemovedDialog.js
@@ -18,7 +18,7 @@ limitations under the License.
import React from "react";
import PropTypes from "prop-types";
import * as sdk from "../../../../index";
-import dis from "../../../../dispatcher";
+import dis from "../../../../dispatcher/dispatcher";
import { _t } from "../../../../languageHandler";
import Modal from "../../../../Modal";
diff --git a/src/components/structures/CustomRoomTagPanel.js b/src/components/structures/CustomRoomTagPanel.js
index 6e392ea505..2753d5c4da 100644
--- a/src/components/structures/CustomRoomTagPanel.js
+++ b/src/components/structures/CustomRoomTagPanel.js
@@ -18,7 +18,7 @@ import React from 'react';
import CustomRoomTagStore from '../../stores/CustomRoomTagStore';
import AutoHideScrollbar from './AutoHideScrollbar';
import * as sdk from '../../index';
-import dis from '../../dispatcher';
+import dis from '../../dispatcher/dispatcher';
import classNames from 'classnames';
import * as FormattingUtils from '../../utils/FormattingUtils';
diff --git a/src/components/structures/EmbeddedPage.js b/src/components/structures/EmbeddedPage.js
index 0aababf030..49ba3d1227 100644
--- a/src/components/structures/EmbeddedPage.js
+++ b/src/components/structures/EmbeddedPage.js
@@ -23,7 +23,7 @@ import PropTypes from 'prop-types';
import request from 'browser-request';
import { _t } from '../../languageHandler';
import sanitizeHtml from 'sanitize-html';
-import dis from '../../dispatcher';
+import dis from '../../dispatcher/dispatcher';
import {MatrixClientPeg} from '../../MatrixClientPeg';
import classnames from 'classnames';
import MatrixClientContext from "../../contexts/MatrixClientContext";
diff --git a/src/components/structures/GroupView.js b/src/components/structures/GroupView.js
index 3b32e5c907..1311d6e4f6 100644
--- a/src/components/structures/GroupView.js
+++ b/src/components/structures/GroupView.js
@@ -21,7 +21,7 @@ import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import {MatrixClientPeg} from '../../MatrixClientPeg';
import * as sdk from '../../index';
-import dis from '../../dispatcher';
+import dis from '../../dispatcher/dispatcher';
import { getHostingLink } from '../../utils/HostingLink';
import { sanitizedHtmlNode } from '../../HtmlUtils';
import { _t, _td } from '../../languageHandler';
diff --git a/src/components/structures/HomePage.tsx b/src/components/structures/HomePage.tsx
index ddf9cd6d00..ff8d35a114 100644
--- a/src/components/structures/HomePage.tsx
+++ b/src/components/structures/HomePage.tsx
@@ -21,7 +21,7 @@ import { getHomePageUrl } from "../../utils/pages";
import { _t } from "../../languageHandler";
import SdkConfig from "../../SdkConfig";
import * as sdk from "../../index";
-import dis from "../../dispatcher";
+import dis from "../../dispatcher/dispatcher";
const onClickSendDm = () => dis.dispatch({action: 'view_create_chat'});
const onClickExplore = () => dis.dispatch({action: 'view_room_directory'});
diff --git a/src/components/structures/LeftPanel.js b/src/components/structures/LeftPanel.js
index a9cd12199b..adba858fa3 100644
--- a/src/components/structures/LeftPanel.js
+++ b/src/components/structures/LeftPanel.js
@@ -21,7 +21,7 @@ import PropTypes from 'prop-types';
import classNames from 'classnames';
import { Key } from '../../Keyboard';
import * as sdk from '../../index';
-import dis from '../../dispatcher';
+import dis from '../../dispatcher/dispatcher';
import * as VectorConferenceHandler from '../../VectorConferenceHandler';
import SettingsStore from '../../settings/SettingsStore';
import {_t} from "../../languageHandler";
diff --git a/src/components/structures/LoggedInView.tsx b/src/components/structures/LoggedInView.tsx
index 9de2aac8e9..e2aa523b8c 100644
--- a/src/components/structures/LoggedInView.tsx
+++ b/src/components/structures/LoggedInView.tsx
@@ -27,7 +27,7 @@ import PageTypes from '../../PageTypes';
import CallMediaHandler from '../../CallMediaHandler';
import { fixupColorFonts } from '../../utils/FontManager';
import * as sdk from '../../index';
-import dis from '../../dispatcher';
+import dis from '../../dispatcher/dispatcher';
import sessionStore from '../../stores/SessionStore';
import {MatrixClientPeg, MatrixClientCreds} from '../../MatrixClientPeg';
import SettingsStore from "../../settings/SettingsStore";
diff --git a/src/components/structures/MatrixChat.tsx b/src/components/structures/MatrixChat.tsx
index e553057acb..973d301420 100644
--- a/src/components/structures/MatrixChat.tsx
+++ b/src/components/structures/MatrixChat.tsx
@@ -34,7 +34,7 @@ import {MatrixClientPeg} from "../../MatrixClientPeg";
import PlatformPeg from "../../PlatformPeg";
import SdkConfig from "../../SdkConfig";
import * as RoomListSorter from "../../RoomListSorter";
-import dis from "../../dispatcher";
+import dis from "../../dispatcher/dispatcher";
import Notifier from '../../Notifier';
import Modal from "../../Modal";
diff --git a/src/components/structures/MyGroups.js b/src/components/structures/MyGroups.js
index f179cab6ad..e2a3d6e71f 100644
--- a/src/components/structures/MyGroups.js
+++ b/src/components/structures/MyGroups.js
@@ -19,7 +19,7 @@ import React from 'react';
import createReactClass from 'create-react-class';
import * as sdk from '../../index';
import { _t } from '../../languageHandler';
-import dis from '../../dispatcher';
+import dis from '../../dispatcher/dispatcher';
import AccessibleButton from '../views/elements/AccessibleButton';
import MatrixClientContext from "../../contexts/MatrixClientContext";
import AutoHideScrollbar from "./AutoHideScrollbar";
diff --git a/src/components/structures/RightPanel.js b/src/components/structures/RightPanel.js
index 34652098b3..c6c330a202 100644
--- a/src/components/structures/RightPanel.js
+++ b/src/components/structures/RightPanel.js
@@ -22,7 +22,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import * as sdk from '../../index';
-import dis from '../../dispatcher';
+import dis from '../../dispatcher/dispatcher';
import RateLimitedFunc from '../../ratelimitedfunc';
import { showGroupInviteDialog, showGroupAddRoomDialog } from '../../GroupAddressPicker';
import GroupStore from '../../stores/GroupStore';
diff --git a/src/components/structures/RoomDirectory.js b/src/components/structures/RoomDirectory.js
index 86353cd532..eb784a1083 100644
--- a/src/components/structures/RoomDirectory.js
+++ b/src/components/structures/RoomDirectory.js
@@ -20,7 +20,7 @@ import React from 'react';
import createReactClass from 'create-react-class';
import {MatrixClientPeg} from "../../MatrixClientPeg";
import * as sdk from "../../index";
-import dis from "../../dispatcher";
+import dis from "../../dispatcher/dispatcher";
import Modal from "../../Modal";
import { linkifyAndSanitizeHtml } from '../../HtmlUtils';
import PropTypes from 'prop-types';
diff --git a/src/components/structures/RoomStatusBar.js b/src/components/structures/RoomStatusBar.js
index 639f38a119..ae628fd06a 100644
--- a/src/components/structures/RoomStatusBar.js
+++ b/src/components/structures/RoomStatusBar.js
@@ -25,7 +25,7 @@ import * as sdk from '../../index';
import {MatrixClientPeg} from '../../MatrixClientPeg';
import Resend from '../../Resend';
import * as cryptodevices from '../../cryptodevices';
-import dis from '../../dispatcher';
+import dis from '../../dispatcher/dispatcher';
import {messageForResourceLimitError, messageForSendError} from '../../utils/ErrorUtils';
const STATUS_BAR_HIDDEN = 0;
diff --git a/src/components/structures/RoomSubList.js b/src/components/structures/RoomSubList.js
index 4e8e51c3cc..d1abacd2d8 100644
--- a/src/components/structures/RoomSubList.js
+++ b/src/components/structures/RoomSubList.js
@@ -20,7 +20,7 @@ limitations under the License.
import React, {createRef} from 'react';
import classNames from 'classnames';
import * as sdk from '../../index';
-import dis from '../../dispatcher';
+import dis from '../../dispatcher/dispatcher';
import * as Unread from '../../Unread';
import * as RoomNotifs from '../../RoomNotifs';
import * as FormattingUtils from '../../utils/FormattingUtils';
diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js
index f53929df4a..fc98758bda 100644
--- a/src/components/structures/RoomView.js
+++ b/src/components/structures/RoomView.js
@@ -34,7 +34,7 @@ import ContentMessages from '../../ContentMessages';
import Modal from '../../Modal';
import * as sdk from '../../index';
import CallHandler from '../../CallHandler';
-import dis from '../../dispatcher';
+import dis from '../../dispatcher/dispatcher';
import Tinter from '../../Tinter';
import rate_limited_func from '../../ratelimitedfunc';
import * as ObjectUtils from '../../ObjectUtils';
diff --git a/src/components/structures/SearchBox.js b/src/components/structures/SearchBox.js
index 0f3f8a6be9..7e9d290bce 100644
--- a/src/components/structures/SearchBox.js
+++ b/src/components/structures/SearchBox.js
@@ -19,7 +19,7 @@ import React, {createRef} from 'react';
import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import { Key } from '../../Keyboard';
-import dis from '../../dispatcher';
+import dis from '../../dispatcher/dispatcher';
import { throttle } from 'lodash';
import AccessibleButton from '../../components/views/elements/AccessibleButton';
import classNames from 'classnames';
diff --git a/src/components/structures/TagPanel.js b/src/components/structures/TagPanel.js
index 6642cce098..713ed004b0 100644
--- a/src/components/structures/TagPanel.js
+++ b/src/components/structures/TagPanel.js
@@ -22,7 +22,7 @@ import TagOrderStore from '../../stores/TagOrderStore';
import GroupActions from '../../actions/GroupActions';
import * as sdk from '../../index';
-import dis from '../../dispatcher';
+import dis from '../../dispatcher/dispatcher';
import { _t } from '../../languageHandler';
import { Droppable } from 'react-beautiful-dnd';
diff --git a/src/components/structures/TagPanelButtons.js b/src/components/structures/TagPanelButtons.js
index 93a596baa3..4b00da3cbf 100644
--- a/src/components/structures/TagPanelButtons.js
+++ b/src/components/structures/TagPanelButtons.js
@@ -17,7 +17,7 @@ limitations under the License.
import React from 'react';
import createReactClass from 'create-react-class';
import * as sdk from '../../index';
-import dis from '../../dispatcher';
+import dis from '../../dispatcher/dispatcher';
import Modal from '../../Modal';
import { _t } from '../../languageHandler';
diff --git a/src/components/structures/TimelinePanel.js b/src/components/structures/TimelinePanel.js
index 6a08cd78eb..da1369c45f 100644
--- a/src/components/structures/TimelinePanel.js
+++ b/src/components/structures/TimelinePanel.js
@@ -29,7 +29,7 @@ import {MatrixClientPeg} from "../../MatrixClientPeg";
import * as ObjectUtils from "../../ObjectUtils";
import UserActivity from "../../UserActivity";
import Modal from "../../Modal";
-import dis from "../../dispatcher";
+import dis from "../../dispatcher/dispatcher";
import * as sdk from "../../index";
import { Key } from '../../Keyboard';
import Timer from '../../utils/Timer';
diff --git a/src/components/structures/TopLeftMenuButton.js b/src/components/structures/TopLeftMenuButton.js
index ebd7aaae89..234dc661f9 100644
--- a/src/components/structures/TopLeftMenuButton.js
+++ b/src/components/structures/TopLeftMenuButton.js
@@ -22,7 +22,7 @@ import BaseAvatar from '../views/avatars/BaseAvatar';
import {MatrixClientPeg} from '../../MatrixClientPeg';
import * as Avatar from '../../Avatar';
import { _t } from '../../languageHandler';
-import dis from "../../dispatcher";
+import dis from "../../dispatcher/dispatcher";
import {ContextMenu, ContextMenuButton} from "./ContextMenu";
const AVATAR_SIZE = 28;
diff --git a/src/components/structures/UploadBar.js b/src/components/structures/UploadBar.js
index 1aec63f04e..421d1d79a7 100644
--- a/src/components/structures/UploadBar.js
+++ b/src/components/structures/UploadBar.js
@@ -19,7 +19,7 @@ import React from 'react';
import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import ContentMessages from '../../ContentMessages';
-import dis from "../../dispatcher";
+import dis from "../../dispatcher/dispatcher";
import filesize from "filesize";
import { _t } from '../../languageHandler';
diff --git a/src/components/structures/auth/Registration.js b/src/components/structures/auth/Registration.js
index 7818496e71..a30a13aceb 100644
--- a/src/components/structures/auth/Registration.js
+++ b/src/components/structures/auth/Registration.js
@@ -32,7 +32,7 @@ import * as Lifecycle from '../../../Lifecycle';
import {MatrixClientPeg} from "../../../MatrixClientPeg";
import AuthPage from "../../views/auth/AuthPage";
import Login from "../../../Login";
-import dis from "../../../dispatcher";
+import dis from "../../../dispatcher/dispatcher";
// Phases
// Show controls to configure server details
diff --git a/src/components/structures/auth/SoftLogout.js b/src/components/structures/auth/SoftLogout.js
index 08ab7e8a61..7c25767291 100644
--- a/src/components/structures/auth/SoftLogout.js
+++ b/src/components/structures/auth/SoftLogout.js
@@ -18,7 +18,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import {_t} from '../../../languageHandler';
import * as sdk from '../../../index';
-import dis from '../../../dispatcher';
+import dis from '../../../dispatcher/dispatcher';
import * as Lifecycle from '../../../Lifecycle';
import Modal from '../../../Modal';
import {MatrixClientPeg} from "../../../MatrixClientPeg";
diff --git a/src/components/views/avatars/MemberAvatar.js b/src/components/views/avatars/MemberAvatar.js
index 826aa5fddf..89314cfef7 100644
--- a/src/components/views/avatars/MemberAvatar.js
+++ b/src/components/views/avatars/MemberAvatar.js
@@ -20,7 +20,7 @@ import PropTypes from 'prop-types';
import createReactClass from 'create-react-class';
import * as Avatar from '../../../Avatar';
import * as sdk from "../../../index";
-import dis from "../../../dispatcher";
+import dis from "../../../dispatcher/dispatcher";
export default createReactClass({
displayName: 'MemberAvatar',
diff --git a/src/components/views/context_menus/MessageContextMenu.js b/src/components/views/context_menus/MessageContextMenu.js
index 70ab80e6cc..2c835e6967 100644
--- a/src/components/views/context_menus/MessageContextMenu.js
+++ b/src/components/views/context_menus/MessageContextMenu.js
@@ -23,7 +23,7 @@ import createReactClass from 'create-react-class';
import {EventStatus} from 'matrix-js-sdk';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
-import dis from '../../../dispatcher';
+import dis from '../../../dispatcher/dispatcher';
import * as sdk from '../../../index';
import { _t } from '../../../languageHandler';
import Modal from '../../../Modal';
diff --git a/src/components/views/context_menus/RoomTileContextMenu.js b/src/components/views/context_menus/RoomTileContextMenu.js
index d281656bbe..b08cf3be60 100644
--- a/src/components/views/context_menus/RoomTileContextMenu.js
+++ b/src/components/views/context_menus/RoomTileContextMenu.js
@@ -24,7 +24,7 @@ import classNames from 'classnames';
import * as sdk from '../../../index';
import { _t, _td } from '../../../languageHandler';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
-import dis from '../../../dispatcher';
+import dis from '../../../dispatcher/dispatcher';
import DMRoomMap from '../../../utils/DMRoomMap';
import * as Rooms from '../../../Rooms';
import * as RoomNotifs from '../../../RoomNotifs';
diff --git a/src/components/views/context_menus/TagTileContextMenu.js b/src/components/views/context_menus/TagTileContextMenu.js
index 7313a278cc..ff1a7f1b14 100644
--- a/src/components/views/context_menus/TagTileContextMenu.js
+++ b/src/components/views/context_menus/TagTileContextMenu.js
@@ -18,7 +18,7 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
import { _t } from '../../../languageHandler';
-import dis from '../../../dispatcher';
+import dis from '../../../dispatcher/dispatcher';
import TagOrderActions from '../../../actions/TagOrderActions';
import * as sdk from '../../../index';
import {MenuItem} from "../../structures/ContextMenu";
diff --git a/src/components/views/context_menus/TopLeftMenu.js b/src/components/views/context_menus/TopLeftMenu.js
index 4448ecd041..3ec857be2f 100644
--- a/src/components/views/context_menus/TopLeftMenu.js
+++ b/src/components/views/context_menus/TopLeftMenu.js
@@ -17,7 +17,7 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
-import dis from '../../../dispatcher';
+import dis from '../../../dispatcher/dispatcher';
import { _t } from '../../../languageHandler';
import LogoutDialog from "../dialogs/LogoutDialog";
import Modal from "../../../Modal";
diff --git a/src/components/views/dialogs/AddressPickerDialog.js b/src/components/views/dialogs/AddressPickerDialog.js
index 451ec9cfde..41a819c005 100644
--- a/src/components/views/dialogs/AddressPickerDialog.js
+++ b/src/components/views/dialogs/AddressPickerDialog.js
@@ -24,7 +24,7 @@ import createReactClass from 'create-react-class';
import { _t, _td } from '../../../languageHandler';
import * as sdk from '../../../index';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
-import dis from '../../../dispatcher';
+import dis from '../../../dispatcher/dispatcher';
import { addressTypes, getAddressType } from '../../../UserAddress.js';
import GroupStore from '../../../stores/GroupStore';
import * as Email from '../../../email';
diff --git a/src/components/views/dialogs/CreateGroupDialog.js b/src/components/views/dialogs/CreateGroupDialog.js
index d465ef26a2..10285ccee0 100644
--- a/src/components/views/dialogs/CreateGroupDialog.js
+++ b/src/components/views/dialogs/CreateGroupDialog.js
@@ -18,7 +18,7 @@ import React from 'react';
import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import * as sdk from '../../../index';
-import dis from '../../../dispatcher';
+import dis from '../../../dispatcher/dispatcher';
import { _t } from '../../../languageHandler';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
diff --git a/src/components/views/dialogs/CryptoStoreTooNewDialog.js b/src/components/views/dialogs/CryptoStoreTooNewDialog.js
index 11e202b0cc..081e84696c 100644
--- a/src/components/views/dialogs/CryptoStoreTooNewDialog.js
+++ b/src/components/views/dialogs/CryptoStoreTooNewDialog.js
@@ -16,7 +16,7 @@ limitations under the License.
import React from 'react';
import * as sdk from '../../../index';
-import dis from '../../../dispatcher';
+import dis from '../../../dispatcher/dispatcher';
import { _t } from '../../../languageHandler';
import Modal from '../../../Modal';
diff --git a/src/components/views/dialogs/DeviceVerifyDialog.js b/src/components/views/dialogs/DeviceVerifyDialog.js
index a3f9430476..51f905d542 100644
--- a/src/components/views/dialogs/DeviceVerifyDialog.js
+++ b/src/components/views/dialogs/DeviceVerifyDialog.js
@@ -25,7 +25,7 @@ import * as FormattingUtils from '../../../utils/FormattingUtils';
import { _t } from '../../../languageHandler';
import {verificationMethods} from 'matrix-js-sdk/src/crypto';
import {ensureDMExists} from "../../../createRoom";
-import dis from "../../../dispatcher";
+import dis from "../../../dispatcher/dispatcher";
import SettingsStore from '../../../settings/SettingsStore';
import {SHOW_QR_CODE_METHOD} from "matrix-js-sdk/src/crypto/verification/QRCode";
import VerificationQREmojiOptions from "../verification/VerificationQREmojiOptions";
diff --git a/src/components/views/dialogs/IntegrationsDisabledDialog.js b/src/components/views/dialogs/IntegrationsDisabledDialog.js
index 1ca638f0ab..2677963281 100644
--- a/src/components/views/dialogs/IntegrationsDisabledDialog.js
+++ b/src/components/views/dialogs/IntegrationsDisabledDialog.js
@@ -18,7 +18,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import {_t} from "../../../languageHandler";
import * as sdk from "../../../index";
-import dis from '../../../dispatcher';
+import dis from '../../../dispatcher/dispatcher';
export default class IntegrationsDisabledDialog extends React.Component {
static propTypes = {
diff --git a/src/components/views/dialogs/InviteDialog.js b/src/components/views/dialogs/InviteDialog.js
index 7cbbf8ba64..e62c417a70 100644
--- a/src/components/views/dialogs/InviteDialog.js
+++ b/src/components/views/dialogs/InviteDialog.js
@@ -27,7 +27,7 @@ import {getHttpUriForMxc} from "matrix-js-sdk/src/content-repo";
import * as Email from "../../../email";
import {getDefaultIdentityServerUrl, useDefaultIdentityServer} from "../../../utils/IdentityServerUtils";
import {abbreviateUrl} from "../../../utils/UrlUtils";
-import dis from "../../../dispatcher";
+import dis from "../../../dispatcher/dispatcher";
import IdentityAuthClient from "../../../IdentityAuthClient";
import Modal from "../../../Modal";
import {humanizeTime} from "../../../utils/humanize";
diff --git a/src/components/views/dialogs/LogoutDialog.js b/src/components/views/dialogs/LogoutDialog.js
index 23a6692b39..930acaa0b8 100644
--- a/src/components/views/dialogs/LogoutDialog.js
+++ b/src/components/views/dialogs/LogoutDialog.js
@@ -18,7 +18,7 @@ limitations under the License.
import React from 'react';
import Modal from '../../../Modal';
import * as sdk from '../../../index';
-import dis from '../../../dispatcher';
+import dis from '../../../dispatcher/dispatcher';
import { _t } from '../../../languageHandler';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
diff --git a/src/components/views/dialogs/RoomSettingsDialog.js b/src/components/views/dialogs/RoomSettingsDialog.js
index c5f807b23c..c2b98cd9f3 100644
--- a/src/components/views/dialogs/RoomSettingsDialog.js
+++ b/src/components/views/dialogs/RoomSettingsDialog.js
@@ -27,7 +27,7 @@ import NotificationSettingsTab from "../settings/tabs/room/NotificationSettingsT
import BridgeSettingsTab from "../settings/tabs/room/BridgeSettingsTab";
import * as sdk from "../../../index";
import {MatrixClientPeg} from "../../../MatrixClientPeg";
-import dis from "../../../dispatcher";
+import dis from "../../../dispatcher/dispatcher";
import SettingsStore from "../../../settings/SettingsStore";
export default class RoomSettingsDialog extends React.Component {
diff --git a/src/components/views/elements/ActionButton.js b/src/components/views/elements/ActionButton.js
index d2277bd69a..7536d66653 100644
--- a/src/components/views/elements/ActionButton.js
+++ b/src/components/views/elements/ActionButton.js
@@ -18,7 +18,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import createReactClass from 'create-react-class';
import AccessibleButton from './AccessibleButton';
-import dis from '../../../dispatcher';
+import dis from '../../../dispatcher/dispatcher';
import * as sdk from '../../../index';
import Analytics from '../../../Analytics';
diff --git a/src/components/views/elements/AppTile.js b/src/components/views/elements/AppTile.js
index 80db1718f6..527436b0e4 100644
--- a/src/components/views/elements/AppTile.js
+++ b/src/components/views/elements/AppTile.js
@@ -31,7 +31,7 @@ import AppPermission from './AppPermission';
import AppWarning from './AppWarning';
import MessageSpinner from './MessageSpinner';
import WidgetUtils from '../../../utils/WidgetUtils';
-import dis from '../../../dispatcher';
+import dis from '../../../dispatcher/dispatcher';
import ActiveWidgetStore from '../../../stores/ActiveWidgetStore';
import classNames from 'classnames';
import {IntegrationManagers} from "../../../integrations/IntegrationManagers";
diff --git a/src/components/views/elements/Flair.js b/src/components/views/elements/Flair.js
index bc657e9e91..0f06904b68 100644
--- a/src/components/views/elements/Flair.js
+++ b/src/components/views/elements/Flair.js
@@ -19,7 +19,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import FlairStore from '../../../stores/FlairStore';
-import dis from '../../../dispatcher';
+import dis from '../../../dispatcher/dispatcher';
import MatrixClientContext from "../../../contexts/MatrixClientContext";
diff --git a/src/components/views/elements/PersistedElement.js b/src/components/views/elements/PersistedElement.js
index 53f2501f19..7f9bfdebf4 100644
--- a/src/components/views/elements/PersistedElement.js
+++ b/src/components/views/elements/PersistedElement.js
@@ -20,7 +20,7 @@ import PropTypes from 'prop-types';
import ResizeObserver from 'resize-observer-polyfill';
-import dis from '../../../dispatcher';
+import dis from '../../../dispatcher/dispatcher';
// Shamelessly ripped off Modal.js. There's probably a better way
// of doing reusable widgets like dialog boxes & menus where we go and
diff --git a/src/components/views/elements/Pill.js b/src/components/views/elements/Pill.js
index 1df12738c5..3e4ddb99e8 100644
--- a/src/components/views/elements/Pill.js
+++ b/src/components/views/elements/Pill.js
@@ -18,7 +18,7 @@ limitations under the License.
import React from 'react';
import createReactClass from 'create-react-class';
import * as sdk from '../../../index';
-import dis from '../../../dispatcher';
+import dis from '../../../dispatcher/dispatcher';
import classNames from 'classnames';
import { Room, RoomMember } from 'matrix-js-sdk';
import PropTypes from 'prop-types';
diff --git a/src/components/views/elements/ReplyThread.js b/src/components/views/elements/ReplyThread.js
index eae2d13f8a..8d3a7307b9 100644
--- a/src/components/views/elements/ReplyThread.js
+++ b/src/components/views/elements/ReplyThread.js
@@ -19,7 +19,7 @@ import React from 'react';
import * as sdk from '../../../index';
import {_t} from '../../../languageHandler';
import PropTypes from 'prop-types';
-import dis from '../../../dispatcher';
+import dis from '../../../dispatcher/dispatcher';
import {wantsDateSeparator} from '../../../DateUtils';
import {MatrixEvent} from 'matrix-js-sdk';
import {makeUserPermalink, RoomPermalinkCreator} from "../../../utils/permalinks/Permalinks";
diff --git a/src/components/views/elements/TagTile.js b/src/components/views/elements/TagTile.js
index d8983ac2ea..1af681dadc 100644
--- a/src/components/views/elements/TagTile.js
+++ b/src/components/views/elements/TagTile.js
@@ -21,7 +21,7 @@ import PropTypes from 'prop-types';
import createReactClass from 'create-react-class';
import classNames from 'classnames';
import * as sdk from '../../../index';
-import dis from '../../../dispatcher';
+import dis from '../../../dispatcher/dispatcher';
import { isOnlyCtrlOrCmdIgnoreShiftKeyEvent } from '../../../Keyboard';
import * as FormattingUtils from '../../../utils/FormattingUtils';
diff --git a/src/components/views/elements/Tooltip.js b/src/components/views/elements/Tooltip.js
index fd845d9db3..4807ade3db 100644
--- a/src/components/views/elements/Tooltip.js
+++ b/src/components/views/elements/Tooltip.js
@@ -22,7 +22,7 @@ import React from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
import createReactClass from 'create-react-class';
-import dis from '../../../dispatcher';
+import dis from '../../../dispatcher/dispatcher';
import classNames from 'classnames';
const MIN_TOOLTIP_HEIGHT = 25;
diff --git a/src/components/views/globals/CookieBar.js b/src/components/views/globals/CookieBar.js
index 8774e4f1fa..bf264686d0 100644
--- a/src/components/views/globals/CookieBar.js
+++ b/src/components/views/globals/CookieBar.js
@@ -16,7 +16,7 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
-import dis from '../../../dispatcher';
+import dis from '../../../dispatcher/dispatcher';
import { _t } from '../../../languageHandler';
import * as sdk from '../../../index';
import Analytics from '../../../Analytics';
diff --git a/src/components/views/groups/GroupInviteTile.js b/src/components/views/groups/GroupInviteTile.js
index 91c930525d..bc5334f2de 100644
--- a/src/components/views/groups/GroupInviteTile.js
+++ b/src/components/views/groups/GroupInviteTile.js
@@ -20,7 +20,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import createReactClass from 'create-react-class';
import * as sdk from '../../../index';
-import dis from '../../../dispatcher';
+import dis from '../../../dispatcher/dispatcher';
import {_t} from '../../../languageHandler';
import classNames from 'classnames';
import {MatrixClientPeg} from "../../../MatrixClientPeg";
diff --git a/src/components/views/groups/GroupMemberInfo.js b/src/components/views/groups/GroupMemberInfo.js
index 9f5660386b..0d08771676 100644
--- a/src/components/views/groups/GroupMemberInfo.js
+++ b/src/components/views/groups/GroupMemberInfo.js
@@ -19,7 +19,7 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
import createReactClass from 'create-react-class';
-import dis from '../../../dispatcher';
+import dis from '../../../dispatcher/dispatcher';
import Modal from '../../../Modal';
import * as sdk from '../../../index';
import { _t } from '../../../languageHandler';
diff --git a/src/components/views/groups/GroupMemberList.js b/src/components/views/groups/GroupMemberList.js
index ca374d1309..b42e325a89 100644
--- a/src/components/views/groups/GroupMemberList.js
+++ b/src/components/views/groups/GroupMemberList.js
@@ -19,7 +19,7 @@ import React from 'react';
import createReactClass from 'create-react-class';
import { _t } from '../../../languageHandler';
import * as sdk from '../../../index';
-import dis from '../../../dispatcher';
+import dis from '../../../dispatcher/dispatcher';
import GroupStore from '../../../stores/GroupStore';
import PropTypes from 'prop-types';
import { showGroupInviteDialog } from '../../../GroupAddressPicker';
diff --git a/src/components/views/groups/GroupMemberTile.js b/src/components/views/groups/GroupMemberTile.js
index f99d5c768c..05e3f6ac2a 100644
--- a/src/components/views/groups/GroupMemberTile.js
+++ b/src/components/views/groups/GroupMemberTile.js
@@ -20,7 +20,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import createReactClass from 'create-react-class';
import * as sdk from '../../../index';
-import dis from '../../../dispatcher';
+import dis from '../../../dispatcher/dispatcher';
import { GroupMemberType } from '../../../groups';
import MatrixClientContext from "../../../contexts/MatrixClientContext";
diff --git a/src/components/views/groups/GroupRoomInfo.js b/src/components/views/groups/GroupRoomInfo.js
index 3a20de7eca..8c9b39675e 100644
--- a/src/components/views/groups/GroupRoomInfo.js
+++ b/src/components/views/groups/GroupRoomInfo.js
@@ -18,7 +18,7 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
import createReactClass from 'create-react-class';
-import dis from '../../../dispatcher';
+import dis from '../../../dispatcher/dispatcher';
import Modal from '../../../Modal';
import * as sdk from '../../../index';
import { _t } from '../../../languageHandler';
diff --git a/src/components/views/groups/GroupRoomTile.js b/src/components/views/groups/GroupRoomTile.js
index 94d143b263..fd6969a49a 100644
--- a/src/components/views/groups/GroupRoomTile.js
+++ b/src/components/views/groups/GroupRoomTile.js
@@ -18,7 +18,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import createReactClass from 'create-react-class';
import * as sdk from '../../../index';
-import dis from '../../../dispatcher';
+import dis from '../../../dispatcher/dispatcher';
import { GroupRoomType } from '../../../groups';
import MatrixClientContext from "../../../contexts/MatrixClientContext";
diff --git a/src/components/views/groups/GroupTile.js b/src/components/views/groups/GroupTile.js
index b845a83c2a..44ce69ee39 100644
--- a/src/components/views/groups/GroupTile.js
+++ b/src/components/views/groups/GroupTile.js
@@ -19,7 +19,7 @@ import PropTypes from 'prop-types';
import createReactClass from 'create-react-class';
import { Draggable, Droppable } from 'react-beautiful-dnd';
import * as sdk from '../../../index';
-import dis from '../../../dispatcher';
+import dis from '../../../dispatcher/dispatcher';
import FlairStore from '../../../stores/FlairStore';
import MatrixClientContext from "../../../contexts/MatrixClientContext";
diff --git a/src/components/views/messages/MKeyVerificationRequest.js b/src/components/views/messages/MKeyVerificationRequest.js
index f49ae1b6b1..a5b1ae26bb 100644
--- a/src/components/views/messages/MKeyVerificationRequest.js
+++ b/src/components/views/messages/MKeyVerificationRequest.js
@@ -21,7 +21,7 @@ import * as sdk from '../../../index';
import { _t } from '../../../languageHandler';
import {getNameForEventRoom, userLabelForEventRoom}
from '../../../utils/KeyVerificationStateObserver';
-import dis from "../../../dispatcher";
+import dis from "../../../dispatcher/dispatcher";
import {RIGHT_PANEL_PHASES} from "../../../stores/RightPanelStorePhases";
export default class MKeyVerificationRequest extends React.Component {
diff --git a/src/components/views/messages/MessageActionBar.js b/src/components/views/messages/MessageActionBar.js
index 0cde90e417..48b9c58cb8 100644
--- a/src/components/views/messages/MessageActionBar.js
+++ b/src/components/views/messages/MessageActionBar.js
@@ -21,7 +21,7 @@ import PropTypes from 'prop-types';
import { _t } from '../../../languageHandler';
import * as sdk from '../../../index';
-import dis from '../../../dispatcher';
+import dis from '../../../dispatcher/dispatcher';
import Modal from '../../../Modal';
import {aboveLeftOf, ContextMenu, ContextMenuButton, useContextMenu} from '../../structures/ContextMenu';
import { isContentActionable, canEditContent } from '../../../utils/EventUtils';
diff --git a/src/components/views/messages/RoomCreate.js b/src/components/views/messages/RoomCreate.js
index b5749ced97..95bc460636 100644
--- a/src/components/views/messages/RoomCreate.js
+++ b/src/components/views/messages/RoomCreate.js
@@ -19,7 +19,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import createReactClass from 'create-react-class';
-import dis from '../../../dispatcher';
+import dis from '../../../dispatcher/dispatcher';
import { RoomPermalinkCreator } from '../../../utils/permalinks/Permalinks';
import { _t } from '../../../languageHandler';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
diff --git a/src/components/views/messages/TextualBody.js b/src/components/views/messages/TextualBody.js
index 882e331675..c762b95f83 100644
--- a/src/components/views/messages/TextualBody.js
+++ b/src/components/views/messages/TextualBody.js
@@ -25,7 +25,7 @@ import * as HtmlUtils from '../../../HtmlUtils';
import {formatDate} from '../../../DateUtils';
import * as sdk from '../../../index';
import Modal from '../../../Modal';
-import dis from '../../../dispatcher';
+import dis from '../../../dispatcher/dispatcher';
import { _t } from '../../../languageHandler';
import * as ContextMenu from '../../structures/ContextMenu';
import SettingsStore from "../../../settings/SettingsStore";
diff --git a/src/components/views/right_panel/HeaderButtons.js b/src/components/views/right_panel/HeaderButtons.js
index 03b03218ee..1c66fe5828 100644
--- a/src/components/views/right_panel/HeaderButtons.js
+++ b/src/components/views/right_panel/HeaderButtons.js
@@ -19,7 +19,7 @@ limitations under the License.
*/
import React from 'react';
-import dis from '../../../dispatcher';
+import dis from '../../../dispatcher/dispatcher';
import RightPanelStore from "../../../stores/RightPanelStore";
export const HEADER_KIND_ROOM = "room";
diff --git a/src/components/views/right_panel/UserInfo.js b/src/components/views/right_panel/UserInfo.js
index 478dc90418..daf1a9490d 100644
--- a/src/components/views/right_panel/UserInfo.js
+++ b/src/components/views/right_panel/UserInfo.js
@@ -21,7 +21,7 @@ import React, {useCallback, useMemo, useState, useEffect, useContext} from 'reac
import PropTypes from 'prop-types';
import classNames from 'classnames';
import {Group, RoomMember, User} from 'matrix-js-sdk';
-import dis from '../../../dispatcher';
+import dis from '../../../dispatcher/dispatcher';
import Modal from '../../../Modal';
import * as sdk from '../../../index';
import { _t } from '../../../languageHandler';
diff --git a/src/components/views/room_settings/ColorSettings.js b/src/components/views/room_settings/ColorSettings.js
index 1e06da0cd8..1d26e956ab 100644
--- a/src/components/views/room_settings/ColorSettings.js
+++ b/src/components/views/room_settings/ColorSettings.js
@@ -19,7 +19,7 @@ import PropTypes from 'prop-types';
import createReactClass from 'create-react-class';
import Tinter from '../../../Tinter';
-import dis from '../../../dispatcher';
+import dis from '../../../dispatcher/dispatcher';
import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore";
const ROOM_COLORS = [
diff --git a/src/components/views/room_settings/UrlPreviewSettings.js b/src/components/views/room_settings/UrlPreviewSettings.js
index 5de355ebd7..16dffd857b 100644
--- a/src/components/views/room_settings/UrlPreviewSettings.js
+++ b/src/components/views/room_settings/UrlPreviewSettings.js
@@ -23,7 +23,7 @@ import createReactClass from 'create-react-class';
import * as sdk from "../../../index";
import { _t, _td } from '../../../languageHandler';
import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore";
-import dis from "../../../dispatcher";
+import dis from "../../../dispatcher/dispatcher";
import {MatrixClientPeg} from "../../../MatrixClientPeg";
diff --git a/src/components/views/rooms/AppsDrawer.js b/src/components/views/rooms/AppsDrawer.js
index b64eb33435..06dfffad30 100644
--- a/src/components/views/rooms/AppsDrawer.js
+++ b/src/components/views/rooms/AppsDrawer.js
@@ -21,7 +21,7 @@ import createReactClass from 'create-react-class';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
import AppTile from '../elements/AppTile';
import Modal from '../../../Modal';
-import dis from '../../../dispatcher';
+import dis from '../../../dispatcher/dispatcher';
import * as sdk from '../../../index';
import * as ScalarMessaging from '../../../ScalarMessaging';
import { _t } from '../../../languageHandler';
diff --git a/src/components/views/rooms/AuxPanel.js b/src/components/views/rooms/AuxPanel.js
index e102b0dba4..d6a3b156d5 100644
--- a/src/components/views/rooms/AuxPanel.js
+++ b/src/components/views/rooms/AuxPanel.js
@@ -20,7 +20,7 @@ import PropTypes from 'prop-types';
import createReactClass from 'create-react-class';
import {MatrixClientPeg} from "../../../MatrixClientPeg";
import * as sdk from '../../../index';
-import dis from "../../../dispatcher";
+import dis from "../../../dispatcher/dispatcher";
import * as ObjectUtils from '../../../ObjectUtils';
import AppsDrawer from './AppsDrawer';
import { _t } from '../../../languageHandler';
diff --git a/src/components/views/rooms/EditMessageComposer.js b/src/components/views/rooms/EditMessageComposer.js
index 8353940c90..88ed76f118 100644
--- a/src/components/views/rooms/EditMessageComposer.js
+++ b/src/components/views/rooms/EditMessageComposer.js
@@ -18,7 +18,7 @@ import React from 'react';
import * as sdk from '../../../index';
import {_t} from '../../../languageHandler';
import PropTypes from 'prop-types';
-import dis from '../../../dispatcher';
+import dis from '../../../dispatcher/dispatcher';
import EditorModel from '../../../editor/model';
import {getCaretOffsetAndText} from '../../../editor/dom';
import {htmlSerializeIfNeeded, textSerialize, containsEmote, stripEmoteCommand} from '../../../editor/serialize';
diff --git a/src/components/views/rooms/EventTile.js b/src/components/views/rooms/EventTile.js
index 33ee8a0f63..91fcacf0e5 100644
--- a/src/components/views/rooms/EventTile.js
+++ b/src/components/views/rooms/EventTile.js
@@ -25,7 +25,7 @@ import classNames from "classnames";
import { _t, _td } from '../../../languageHandler';
import * as TextForEvent from "../../../TextForEvent";
import * as sdk from "../../../index";
-import dis from '../../../dispatcher';
+import dis from '../../../dispatcher/dispatcher';
import SettingsStore from "../../../settings/SettingsStore";
import {EventStatus} from 'matrix-js-sdk';
import {formatTime} from "../../../DateUtils";
diff --git a/src/components/views/rooms/ForwardMessage.js b/src/components/views/rooms/ForwardMessage.js
index a3c00598a7..03ca32c5e6 100644
--- a/src/components/views/rooms/ForwardMessage.js
+++ b/src/components/views/rooms/ForwardMessage.js
@@ -19,7 +19,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import createReactClass from 'create-react-class';
import { _t } from '../../../languageHandler';
-import dis from '../../../dispatcher';
+import dis from '../../../dispatcher/dispatcher';
import {Key} from '../../../Keyboard';
diff --git a/src/components/views/rooms/MemberInfo.js b/src/components/views/rooms/MemberInfo.js
index 6b03000961..5d8e03a050 100644
--- a/src/components/views/rooms/MemberInfo.js
+++ b/src/components/views/rooms/MemberInfo.js
@@ -31,7 +31,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import createReactClass from 'create-react-class';
import classNames from 'classnames';
-import dis from '../../../dispatcher';
+import dis from '../../../dispatcher/dispatcher';
import Modal from '../../../Modal';
import * as sdk from '../../../index';
import { _t } from '../../../languageHandler';
diff --git a/src/components/views/rooms/MemberList.js b/src/components/views/rooms/MemberList.js
index 3779d461bb..e2d7e3f8e0 100644
--- a/src/components/views/rooms/MemberList.js
+++ b/src/components/views/rooms/MemberList.js
@@ -20,7 +20,7 @@ import React from 'react';
import createReactClass from 'create-react-class';
import { _t } from '../../../languageHandler';
import SdkConfig from '../../../SdkConfig';
-import dis from '../../../dispatcher';
+import dis from '../../../dispatcher/dispatcher';
import AutoHideScrollbar from "../../structures/AutoHideScrollbar";
import {isValid3pidInvite} from "../../../RoomInvite";
import rate_limited_func from "../../../ratelimitedfunc";
diff --git a/src/components/views/rooms/MemberTile.js b/src/components/views/rooms/MemberTile.js
index 1c609afcaa..6842e27ed3 100644
--- a/src/components/views/rooms/MemberTile.js
+++ b/src/components/views/rooms/MemberTile.js
@@ -20,7 +20,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import createReactClass from 'create-react-class';
import * as sdk from "../../../index";
-import dis from "../../../dispatcher";
+import dis from "../../../dispatcher/dispatcher";
import { _t } from '../../../languageHandler';
import { MatrixClientPeg } from "../../../MatrixClientPeg";
diff --git a/src/components/views/rooms/MessageComposer.js b/src/components/views/rooms/MessageComposer.js
index 4749742a7d..c05fe3d3a2 100644
--- a/src/components/views/rooms/MessageComposer.js
+++ b/src/components/views/rooms/MessageComposer.js
@@ -20,7 +20,7 @@ import { _t } from '../../../languageHandler';
import CallHandler from '../../../CallHandler';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
import * as sdk from '../../../index';
-import dis from '../../../dispatcher';
+import dis from '../../../dispatcher/dispatcher';
import RoomViewStore from '../../../stores/RoomViewStore';
import Stickerpicker from './Stickerpicker';
import { makeRoomPermalink } from '../../../utils/permalinks/Permalinks';
diff --git a/src/components/views/rooms/PinnedEventTile.js b/src/components/views/rooms/PinnedEventTile.js
index 28fc8fc338..924385d226 100644
--- a/src/components/views/rooms/PinnedEventTile.js
+++ b/src/components/views/rooms/PinnedEventTile.js
@@ -18,7 +18,7 @@ import React from "react";
import PropTypes from 'prop-types';
import createReactClass from 'create-react-class';
import {MatrixClientPeg} from "../../../MatrixClientPeg";
-import dis from "../../../dispatcher";
+import dis from "../../../dispatcher/dispatcher";
import AccessibleButton from "../elements/AccessibleButton";
import MessageEvent from "../messages/MessageEvent";
import MemberAvatar from "../avatars/MemberAvatar";
diff --git a/src/components/views/rooms/ReplyPreview.js b/src/components/views/rooms/ReplyPreview.js
index b28494c65a..e7cd2b4c0d 100644
--- a/src/components/views/rooms/ReplyPreview.js
+++ b/src/components/views/rooms/ReplyPreview.js
@@ -15,7 +15,7 @@ limitations under the License.
*/
import React from 'react';
-import dis from '../../../dispatcher';
+import dis from '../../../dispatcher/dispatcher';
import * as sdk from '../../../index';
import { _t } from '../../../languageHandler';
import RoomViewStore from '../../../stores/RoomViewStore';
diff --git a/src/components/views/rooms/RoomBreadcrumbs.js b/src/components/views/rooms/RoomBreadcrumbs.js
index 86c0d7ca96..fe443d720f 100644
--- a/src/components/views/rooms/RoomBreadcrumbs.js
+++ b/src/components/views/rooms/RoomBreadcrumbs.js
@@ -15,7 +15,7 @@ limitations under the License.
*/
import React, {createRef} from "react";
-import dis from "../../../dispatcher";
+import dis from "../../../dispatcher/dispatcher";
import {MatrixClientPeg} from "../../../MatrixClientPeg";
import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore";
import AccessibleButton from '../elements/AccessibleButton';
diff --git a/src/components/views/rooms/RoomDetailList.js b/src/components/views/rooms/RoomDetailList.js
index db7b86da4f..5b45cfc29a 100644
--- a/src/components/views/rooms/RoomDetailList.js
+++ b/src/components/views/rooms/RoomDetailList.js
@@ -15,7 +15,7 @@ limitations under the License.
*/
import * as sdk from '../../../index';
-import dis from '../../../dispatcher';
+import dis from '../../../dispatcher/dispatcher';
import React from 'react';
import { _t } from '../../../languageHandler';
import PropTypes from 'prop-types';
diff --git a/src/components/views/rooms/RoomList.js b/src/components/views/rooms/RoomList.js
index 289a89a206..1c59a5d8d0 100644
--- a/src/components/views/rooms/RoomList.js
+++ b/src/components/views/rooms/RoomList.js
@@ -35,7 +35,7 @@ import GroupStore from '../../../stores/GroupStore';
import RoomSubList from '../../structures/RoomSubList';
import ResizeHandle from '../elements/ResizeHandle';
import CallHandler from "../../../CallHandler";
-import dis from "../../../dispatcher";
+import dis from "../../../dispatcher/dispatcher";
import * as sdk from "../../../index";
import * as Receipt from "../../../utils/Receipt";
import {Resizer} from '../../../resizer';
diff --git a/src/components/views/rooms/RoomPreviewBar.js b/src/components/views/rooms/RoomPreviewBar.js
index fe7c57d811..30e6ae9c58 100644
--- a/src/components/views/rooms/RoomPreviewBar.js
+++ b/src/components/views/rooms/RoomPreviewBar.js
@@ -21,7 +21,7 @@ import PropTypes from 'prop-types';
import createReactClass from 'create-react-class';
import * as sdk from '../../../index';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
-import dis from '../../../dispatcher';
+import dis from '../../../dispatcher/dispatcher';
import classNames from 'classnames';
import { _t } from '../../../languageHandler';
import IdentityAuthClient from '../../../IdentityAuthClient';
diff --git a/src/components/views/rooms/RoomTile.js b/src/components/views/rooms/RoomTile.js
index 6a23fe309b..44e5ae7643 100644
--- a/src/components/views/rooms/RoomTile.js
+++ b/src/components/views/rooms/RoomTile.js
@@ -21,7 +21,7 @@ import React, {createRef} from 'react';
import PropTypes from 'prop-types';
import createReactClass from 'create-react-class';
import classNames from 'classnames';
-import dis from '../../../dispatcher';
+import dis from '../../../dispatcher/dispatcher';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
import DMRoomMap from '../../../utils/DMRoomMap';
import * as sdk from '../../../index';
diff --git a/src/components/views/rooms/SendMessageComposer.js b/src/components/views/rooms/SendMessageComposer.js
index 233bb110be..5ea979a8ef 100644
--- a/src/components/views/rooms/SendMessageComposer.js
+++ b/src/components/views/rooms/SendMessageComposer.js
@@ -16,7 +16,7 @@ limitations under the License.
*/
import React from 'react';
import PropTypes from 'prop-types';
-import dis from '../../../dispatcher';
+import dis from '../../../dispatcher/dispatcher';
import EditorModel from '../../../editor/model';
import {
htmlSerializeIfNeeded,
diff --git a/src/components/views/rooms/Stickerpicker.js b/src/components/views/rooms/Stickerpicker.js
index 9d91ab04b3..fc6e80fc61 100644
--- a/src/components/views/rooms/Stickerpicker.js
+++ b/src/components/views/rooms/Stickerpicker.js
@@ -18,7 +18,7 @@ import {_t, _td} from '../../../languageHandler';
import AppTile from '../elements/AppTile';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
import * as sdk from '../../../index';
-import dis from '../../../dispatcher';
+import dis from '../../../dispatcher/dispatcher';
import AccessibleButton from '../elements/AccessibleButton';
import WidgetUtils from '../../../utils/WidgetUtils';
import ActiveWidgetStore from '../../../stores/ActiveWidgetStore';
diff --git a/src/components/views/rooms/ThirdPartyMemberInfo.js b/src/components/views/rooms/ThirdPartyMemberInfo.js
index 3e6ed16aa4..3a7042ebd2 100644
--- a/src/components/views/rooms/ThirdPartyMemberInfo.js
+++ b/src/components/views/rooms/ThirdPartyMemberInfo.js
@@ -19,7 +19,7 @@ import PropTypes from 'prop-types';
import {MatrixClientPeg} from "../../../MatrixClientPeg";
import {MatrixEvent} from "matrix-js-sdk";
import {_t} from "../../../languageHandler";
-import dis from "../../../dispatcher";
+import dis from "../../../dispatcher/dispatcher";
import * as sdk from "../../../index";
import Modal from "../../../Modal";
import {isValid3pidInvite} from "../../../RoomInvite";
diff --git a/src/components/views/settings/ChangePassword.js b/src/components/views/settings/ChangePassword.js
index 7c88573e9c..c7eccf2145 100644
--- a/src/components/views/settings/ChangePassword.js
+++ b/src/components/views/settings/ChangePassword.js
@@ -20,7 +20,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import createReactClass from 'create-react-class';
import {MatrixClientPeg} from "../../../MatrixClientPeg";
-import dis from "../../../dispatcher";
+import dis from "../../../dispatcher/dispatcher";
import AccessibleButton from '../elements/AccessibleButton';
import { _t } from '../../../languageHandler';
import * as sdk from "../../../index";
diff --git a/src/components/views/settings/EnableNotificationsButton.js b/src/components/views/settings/EnableNotificationsButton.js
index 9ca591f30e..e4b348dfbd 100644
--- a/src/components/views/settings/EnableNotificationsButton.js
+++ b/src/components/views/settings/EnableNotificationsButton.js
@@ -17,7 +17,7 @@ limitations under the License.
import React from "react";
import createReactClass from 'create-react-class';
import Notifier from "../../../Notifier";
-import dis from "../../../dispatcher";
+import dis from "../../../dispatcher/dispatcher";
import { _t } from '../../../languageHandler';
export default createReactClass({
diff --git a/src/components/views/settings/IntegrationManager.js b/src/components/views/settings/IntegrationManager.js
index a5150e3777..fd6a62d73a 100644
--- a/src/components/views/settings/IntegrationManager.js
+++ b/src/components/views/settings/IntegrationManager.js
@@ -19,7 +19,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import * as sdk from '../../../index';
import { _t } from '../../../languageHandler';
-import dis from '../../../dispatcher';
+import dis from '../../../dispatcher/dispatcher';
import {Key} from "../../../Keyboard";
export default class IntegrationManager extends React.Component {
diff --git a/src/components/views/settings/SetIdServer.js b/src/components/views/settings/SetIdServer.js
index cb37271452..23e72e2352 100644
--- a/src/components/views/settings/SetIdServer.js
+++ b/src/components/views/settings/SetIdServer.js
@@ -21,7 +21,7 @@ import {_t} from "../../../languageHandler";
import * as sdk from '../../../index';
import {MatrixClientPeg} from "../../../MatrixClientPeg";
import Modal from '../../../Modal';
-import dis from "../../../dispatcher";
+import dis from "../../../dispatcher/dispatcher";
import { getThreepidsWithBindStatus } from '../../../boundThreepids';
import IdentityAuthClient from "../../../IdentityAuthClient";
import {abbreviateUrl, unabbreviateUrl} from "../../../utils/UrlUtils";
diff --git a/src/components/views/settings/tabs/room/AdvancedRoomSettingsTab.js b/src/components/views/settings/tabs/room/AdvancedRoomSettingsTab.js
index 9ee9c8d130..f57d5d3798 100644
--- a/src/components/views/settings/tabs/room/AdvancedRoomSettingsTab.js
+++ b/src/components/views/settings/tabs/room/AdvancedRoomSettingsTab.js
@@ -21,7 +21,7 @@ import {MatrixClientPeg} from "../../../../../MatrixClientPeg";
import * as sdk from "../../../../..";
import AccessibleButton from "../../../elements/AccessibleButton";
import Modal from "../../../../../Modal";
-import dis from "../../../../../dispatcher";
+import dis from "../../../../../dispatcher/dispatcher";
export default class AdvancedRoomSettingsTab extends React.Component {
static propTypes = {
diff --git a/src/components/views/settings/tabs/room/GeneralRoomSettingsTab.js b/src/components/views/settings/tabs/room/GeneralRoomSettingsTab.js
index 99882ae400..1f12396413 100644
--- a/src/components/views/settings/tabs/room/GeneralRoomSettingsTab.js
+++ b/src/components/views/settings/tabs/room/GeneralRoomSettingsTab.js
@@ -20,7 +20,7 @@ import {_t} from "../../../../../languageHandler";
import RoomProfileSettings from "../../../room_settings/RoomProfileSettings";
import * as sdk from "../../../../..";
import AccessibleButton from "../../../elements/AccessibleButton";
-import dis from "../../../../../dispatcher";
+import dis from "../../../../../dispatcher/dispatcher";
import MatrixClientContext from "../../../../../contexts/MatrixClientContext";
export default class GeneralRoomSettingsTab extends React.Component {
diff --git a/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js b/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js
index 867982ad2b..216bffc3ed 100644
--- a/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js
+++ b/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js
@@ -32,7 +32,7 @@ import PlatformPeg from "../../../../../PlatformPeg";
import {MatrixClientPeg} from "../../../../../MatrixClientPeg";
import * as sdk from "../../../../..";
import Modal from "../../../../../Modal";
-import dis from "../../../../../dispatcher";
+import dis from "../../../../../dispatcher/dispatcher";
import {Service, startTermsFlow} from "../../../../../Terms";
import {SERVICE_TYPES} from "matrix-js-sdk";
import IdentityAuthClient from "../../../../../IdentityAuthClient";
diff --git a/src/components/views/settings/tabs/user/SecurityUserSettingsTab.js b/src/components/views/settings/tabs/user/SecurityUserSettingsTab.js
index 5dd6475e6e..bed057f03d 100644
--- a/src/components/views/settings/tabs/user/SecurityUserSettingsTab.js
+++ b/src/components/views/settings/tabs/user/SecurityUserSettingsTab.js
@@ -25,7 +25,7 @@ import Analytics from "../../../../../Analytics";
import Modal from "../../../../../Modal";
import * as sdk from "../../../../..";
import {sleep} from "../../../../../utils/promise";
-import dis from "../../../../../dispatcher";
+import dis from "../../../../../dispatcher/dispatcher";
export class IgnoredUser extends React.Component {
static propTypes = {
diff --git a/src/components/views/toasts/BulkUnverifiedSessionsToast.js b/src/components/views/toasts/BulkUnverifiedSessionsToast.js
index 0c40e56858..99ff529c35 100644
--- a/src/components/views/toasts/BulkUnverifiedSessionsToast.js
+++ b/src/components/views/toasts/BulkUnverifiedSessionsToast.js
@@ -17,7 +17,7 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
import { _t } from '../../../languageHandler';
-import dis from "../../../dispatcher";
+import dis from "../../../dispatcher/dispatcher";
import { MatrixClientPeg } from '../../../MatrixClientPeg';
import DeviceListener from '../../../DeviceListener';
import FormButton from '../elements/FormButton';
diff --git a/src/components/views/toasts/VerificationRequestToast.js b/src/components/views/toasts/VerificationRequestToast.js
index 6447e87627..421dd7bea1 100644
--- a/src/components/views/toasts/VerificationRequestToast.js
+++ b/src/components/views/toasts/VerificationRequestToast.js
@@ -21,7 +21,7 @@ import { _t } from '../../../languageHandler';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
import {RIGHT_PANEL_PHASES} from "../../../stores/RightPanelStorePhases";
import {userLabelForEventRoom} from "../../../utils/KeyVerificationStateObserver";
-import dis from "../../../dispatcher";
+import dis from "../../../dispatcher/dispatcher";
import ToastStore from "../../../stores/ToastStore";
import Modal from "../../../Modal";
diff --git a/src/components/views/voip/CallPreview.js b/src/components/views/voip/CallPreview.js
index 049dd8a3c6..c465170950 100644
--- a/src/components/views/voip/CallPreview.js
+++ b/src/components/views/voip/CallPreview.js
@@ -20,7 +20,7 @@ import PropTypes from 'prop-types';
import createReactClass from 'create-react-class';
import RoomViewStore from '../../../stores/RoomViewStore';
import CallHandler from '../../../CallHandler';
-import dis from '../../../dispatcher';
+import dis from '../../../dispatcher/dispatcher';
import * as sdk from '../../../index';
export default createReactClass({
diff --git a/src/components/views/voip/CallView.js b/src/components/views/voip/CallView.js
index 4a5f3923e2..a0a566dfac 100644
--- a/src/components/views/voip/CallView.js
+++ b/src/components/views/voip/CallView.js
@@ -17,7 +17,7 @@ limitations under the License.
import React, {createRef} from 'react';
import PropTypes from 'prop-types';
import createReactClass from 'create-react-class';
-import dis from '../../../dispatcher';
+import dis from '../../../dispatcher/dispatcher';
import CallHandler from '../../../CallHandler';
import * as sdk from '../../../index';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
diff --git a/src/components/views/voip/IncomingCallBox.js b/src/components/views/voip/IncomingCallBox.js
index 53e829b784..bf28fa0157 100644
--- a/src/components/views/voip/IncomingCallBox.js
+++ b/src/components/views/voip/IncomingCallBox.js
@@ -19,7 +19,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import createReactClass from 'create-react-class';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
-import dis from '../../../dispatcher';
+import dis from '../../../dispatcher/dispatcher';
import { _t } from '../../../languageHandler';
import * as sdk from '../../../index';
diff --git a/src/components/views/voip/VideoView.js b/src/components/views/voip/VideoView.js
index 51be6db81d..a51ab70da9 100644
--- a/src/components/views/voip/VideoView.js
+++ b/src/components/views/voip/VideoView.js
@@ -22,7 +22,7 @@ import createReactClass from 'create-react-class';
import classNames from 'classnames';
import * as sdk from '../../../index';
-import dis from '../../../dispatcher';
+import dis from '../../../dispatcher/dispatcher';
import SettingsStore from "../../../settings/SettingsStore";
diff --git a/src/createRoom.js b/src/createRoom.js
index a39d2c2216..18fc787e1c 100644
--- a/src/createRoom.js
+++ b/src/createRoom.js
@@ -19,7 +19,7 @@ import {MatrixClientPeg} from './MatrixClientPeg';
import Modal from './Modal';
import * as sdk from './index';
import { _t } from './languageHandler';
-import dis from "./dispatcher";
+import dis from "./dispatcher/dispatcher";
import * as Rooms from "./Rooms";
import DMRoomMap from "./utils/DMRoomMap";
import {getAddressType} from "./UserAddress";
diff --git a/src/cryptodevices.js b/src/cryptodevices.js
index f56a80e1e4..86b97364f9 100644
--- a/src/cryptodevices.js
+++ b/src/cryptodevices.js
@@ -16,7 +16,7 @@ limitations under the License.
import Resend from './Resend';
import * as sdk from './index';
-import dis from './dispatcher';
+import dis from './dispatcher/dispatcher';
import Modal from './Modal';
import { _t } from './languageHandler';
diff --git a/src/dispatcher.ts b/src/dispatcher/dispatcher.ts
similarity index 100%
rename from src/dispatcher.ts
rename to src/dispatcher/dispatcher.ts
diff --git a/src/mjolnir/Mjolnir.js b/src/mjolnir/Mjolnir.js
index 5836ffd57a..9876cb1f7f 100644
--- a/src/mjolnir/Mjolnir.js
+++ b/src/mjolnir/Mjolnir.js
@@ -18,7 +18,7 @@ import {MatrixClientPeg} from "../MatrixClientPeg";
import {ALL_RULE_TYPES, BanList} from "./BanList";
import SettingsStore, {SettingLevel} from "../settings/SettingsStore";
import {_t} from "../languageHandler";
-import dis from "../dispatcher";
+import dis from "../dispatcher/dispatcher";
// TODO: Move this and related files to the js-sdk or something once finalized.
diff --git a/src/settings/SettingsStore.js b/src/settings/SettingsStore.js
index 0122916bc3..36111dd46f 100644
--- a/src/settings/SettingsStore.js
+++ b/src/settings/SettingsStore.js
@@ -24,7 +24,7 @@ import RoomSettingsHandler from "./handlers/RoomSettingsHandler";
import ConfigSettingsHandler from "./handlers/ConfigSettingsHandler";
import {_t} from '../languageHandler';
import SdkConfig from "../SdkConfig";
-import dis from '../dispatcher';
+import dis from '../dispatcher/dispatcher';
import {SETTINGS} from "./Settings";
import LocalEchoWrapper from "./handlers/LocalEchoWrapper";
import {WatchManager} from "./WatchManager";
diff --git a/src/settings/controllers/CustomStatusController.js b/src/settings/controllers/CustomStatusController.js
index 0fc6619d92..031387bb6a 100644
--- a/src/settings/controllers/CustomStatusController.js
+++ b/src/settings/controllers/CustomStatusController.js
@@ -15,7 +15,7 @@ limitations under the License.
*/
import SettingController from "./SettingController";
-import dis from "../../dispatcher";
+import dis from "../../dispatcher/dispatcher";
export default class CustomStatusController extends SettingController {
onChange(level, roomId, newValue) {
diff --git a/src/stores/CustomRoomTagStore.js b/src/stores/CustomRoomTagStore.js
index 909282c085..c67868e2c6 100644
--- a/src/stores/CustomRoomTagStore.js
+++ b/src/stores/CustomRoomTagStore.js
@@ -13,7 +13,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
-import dis from '../dispatcher';
+import dis from '../dispatcher/dispatcher';
import * as RoomNotifs from '../RoomNotifs';
import RoomListStore from './RoomListStore';
import EventEmitter from 'events';
diff --git a/src/stores/GroupStore.js b/src/stores/GroupStore.js
index 78a144f755..d4097184a1 100644
--- a/src/stores/GroupStore.js
+++ b/src/stores/GroupStore.js
@@ -18,7 +18,7 @@ import EventEmitter from 'events';
import { groupMemberFromApiObject, groupRoomFromApiObject } from '../groups';
import FlairStore from './FlairStore';
import {MatrixClientPeg} from '../MatrixClientPeg';
-import dis from '../dispatcher';
+import dis from '../dispatcher/dispatcher';
function parseMembersResponse(response) {
return response.chunk.map((apiMember) => groupMemberFromApiObject(apiMember));
diff --git a/src/stores/LifecycleStore.js b/src/stores/LifecycleStore.js
index 904f29f7b3..a12bac7dd6 100644
--- a/src/stores/LifecycleStore.js
+++ b/src/stores/LifecycleStore.js
@@ -15,7 +15,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
-import dis from '../dispatcher';
+import dis from '../dispatcher/dispatcher';
import {Store} from 'flux/utils';
const INITIAL_STATE = {
diff --git a/src/stores/RightPanelStore.js b/src/stores/RightPanelStore.js
index 3a5605ba3f..a73f3befbb 100644
--- a/src/stores/RightPanelStore.js
+++ b/src/stores/RightPanelStore.js
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-import dis from '../dispatcher';
+import dis from '../dispatcher/dispatcher';
import {pendingVerificationRequestForUser} from '../verification';
import {Store} from 'flux/utils';
import SettingsStore, {SettingLevel} from "../settings/SettingsStore";
diff --git a/src/stores/RoomListStore.js b/src/stores/RoomListStore.js
index 89edc9a8ef..d7b6759195 100644
--- a/src/stores/RoomListStore.js
+++ b/src/stores/RoomListStore.js
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import {Store} from 'flux/utils';
-import dis from '../dispatcher';
+import dis from '../dispatcher/dispatcher';
import DMRoomMap from '../utils/DMRoomMap';
import * as Unread from '../Unread';
import SettingsStore from "../settings/SettingsStore";
diff --git a/src/stores/RoomViewStore.js b/src/stores/RoomViewStore.js
index 841734dfb7..3d82d086d7 100644
--- a/src/stores/RoomViewStore.js
+++ b/src/stores/RoomViewStore.js
@@ -15,7 +15,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
-import dis from '../dispatcher';
+import dis from '../dispatcher/dispatcher';
import {Store} from 'flux/utils';
import {MatrixClientPeg} from '../MatrixClientPeg';
import * as sdk from '../index';
diff --git a/src/stores/SessionStore.js b/src/stores/SessionStore.js
index f38bc046d0..096811940c 100644
--- a/src/stores/SessionStore.js
+++ b/src/stores/SessionStore.js
@@ -14,7 +14,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
-import dis from '../dispatcher';
+import dis from '../dispatcher/dispatcher';
import {Store} from 'flux/utils';
const INITIAL_STATE = {
diff --git a/src/stores/TagOrderStore.js b/src/stores/TagOrderStore.js
index c05728e497..2acf531d86 100644
--- a/src/stores/TagOrderStore.js
+++ b/src/stores/TagOrderStore.js
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import {Store} from 'flux/utils';
-import dis from '../dispatcher';
+import dis from '../dispatcher/dispatcher';
import GroupStore from './GroupStore';
import Analytics from '../Analytics';
import * as RoomNotifs from "../RoomNotifs";
diff --git a/src/theme.js b/src/theme.js
index 2ccce81a8d..1da39d50fa 100644
--- a/src/theme.js
+++ b/src/theme.js
@@ -19,7 +19,7 @@ import {_t} from "./languageHandler";
export const DEFAULT_THEME = "light";
import Tinter from "./Tinter";
-import dis from "./dispatcher";
+import dis from "./dispatcher/dispatcher";
import SettingsStore, {SettingLevel} from "./settings/SettingsStore";
import ThemeController from "./settings/controllers/ThemeController";
diff --git a/src/utils/WidgetUtils.js b/src/utils/WidgetUtils.js
index ad4c02887e..35e23f0429 100644
--- a/src/utils/WidgetUtils.js
+++ b/src/utils/WidgetUtils.js
@@ -18,7 +18,7 @@ limitations under the License.
import {MatrixClientPeg} from '../MatrixClientPeg';
import SdkConfig from "../SdkConfig";
-import dis from '../dispatcher';
+import dis from '../dispatcher/dispatcher';
import * as url from "url";
import WidgetEchoStore from '../stores/WidgetEchoStore';
diff --git a/src/verification.js b/src/verification.js
index f488b2ebeb..289ac9544b 100644
--- a/src/verification.js
+++ b/src/verification.js
@@ -15,7 +15,7 @@ limitations under the License.
*/
import {MatrixClientPeg} from './MatrixClientPeg';
-import dis from "./dispatcher";
+import dis from "./dispatcher/dispatcher";
import Modal from './Modal';
import * as sdk from './index';
import { _t } from './languageHandler';
diff --git a/test/components/views/rooms/RoomList-test.js b/test/components/views/rooms/RoomList-test.js
index 8dc4647920..235ed61016 100644
--- a/test/components/views/rooms/RoomList-test.js
+++ b/test/components/views/rooms/RoomList-test.js
@@ -9,7 +9,7 @@ import {MatrixClientPeg} from '../../../../src/MatrixClientPeg';
import sdk from '../../../skinned-sdk';
import { DragDropContext } from 'react-beautiful-dnd';
-import dis from '../../../../src/dispatcher';
+import dis from '../../../../src/dispatcher/dispatcher';
import DMRoomMap from '../../../../src/utils/DMRoomMap.js';
import GroupStore from '../../../../src/stores/GroupStore.js';
diff --git a/test/test-utils.js b/test/test-utils.js
index d7aa9d5de9..2d7c1bd62c 100644
--- a/test/test-utils.js
+++ b/test/test-utils.js
@@ -2,7 +2,7 @@
import React from 'react';
import {MatrixClientPeg as peg} from '../src/MatrixClientPeg';
-import dis from '../src/dispatcher';
+import dis from '../src/dispatcher/dispatcher';
import {makeType} from "../src/utils/TypeUtils";
import {ValidatedServerConfig} from "../src/utils/AutoDiscoveryUtils";
import ShallowRenderer from 'react-test-renderer/shallow';
From 8c72c27da9afe371e15f2f010d61fe4608c788c1 Mon Sep 17 00:00:00 2001
From: Travis Ralston
Date: Wed, 13 May 2020 20:46:00 -0600
Subject: [PATCH 138/196] Break out actions and payloads to their own files
The definitions take up a lot of space which makes it hard to see the dispatcher class, so break them out.
---
src/actions/RoomListActions.ts | 2 +-
src/actions/TagOrderActions.ts | 2 +-
src/actions/actionCreators.ts | 2 +-
src/dispatcher/actions.ts | 23 +++++++++++++
src/dispatcher/dispatcher.ts | 51 ++---------------------------
src/dispatcher/payloads.ts | 59 ++++++++++++++++++++++++++++++++++
6 files changed, 87 insertions(+), 52 deletions(-)
create mode 100644 src/dispatcher/actions.ts
create mode 100644 src/dispatcher/payloads.ts
diff --git a/src/actions/RoomListActions.ts b/src/actions/RoomListActions.ts
index 0cdd3a86d8..eb9831ec47 100644
--- a/src/actions/RoomListActions.ts
+++ b/src/actions/RoomListActions.ts
@@ -23,7 +23,7 @@ import { _t } from '../languageHandler';
import * as sdk from '../index';
import { MatrixClient } from "matrix-js-sdk/src/client";
import { Room } from "matrix-js-sdk/src/models/room";
-import { AsyncActionPayload } from "../dispatcher/dispatcher";
+import { AsyncActionPayload } from "../dispatcher/payloads";
export default class RoomListActions {
/**
diff --git a/src/actions/TagOrderActions.ts b/src/actions/TagOrderActions.ts
index fa86e3a6b1..fa95ea1037 100644
--- a/src/actions/TagOrderActions.ts
+++ b/src/actions/TagOrderActions.ts
@@ -18,7 +18,7 @@ limitations under the License.
import Analytics from '../Analytics';
import { asyncAction } from './actionCreators';
import TagOrderStore from '../stores/TagOrderStore';
-import { AsyncActionPayload } from "../dispatcher/dispatcher";
+import { AsyncActionPayload } from "../dispatcher/payloads";
import { MatrixClient } from "matrix-js-sdk/src/client";
export default class TagOrderActions {
diff --git a/src/actions/actionCreators.ts b/src/actions/actionCreators.ts
index 78525a9509..d84868a141 100644
--- a/src/actions/actionCreators.ts
+++ b/src/actions/actionCreators.ts
@@ -15,7 +15,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-import { AsyncActionPayload } from "../dispatcher/dispatcher";
+import { AsyncActionPayload } from "../dispatcher/payloads";
/**
* Create an action thunk that will dispatch actions indicating the current
diff --git a/src/dispatcher/actions.ts b/src/dispatcher/actions.ts
new file mode 100644
index 0000000000..ff1650e4e5
--- /dev/null
+++ b/src/dispatcher/actions.ts
@@ -0,0 +1,23 @@
+/*
+Copyright 2020 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Dispatcher actions also extend into any arbitrary string, so support that.
+export type DispatcherAction = Action | string;
+
+export enum Action {
+ // TODO: Populate with actual actions
+}
+
diff --git a/src/dispatcher/dispatcher.ts b/src/dispatcher/dispatcher.ts
index fce99df055..6ef165c485 100644
--- a/src/dispatcher/dispatcher.ts
+++ b/src/dispatcher/dispatcher.ts
@@ -17,55 +17,8 @@ limitations under the License.
*/
import { Dispatcher } from "flux";
-
-export enum Action {
- // TODO: Populate with actual actions
-}
-
-// Dispatcher actions also extend into any arbitrary string, so support that.
-export type DispatcherAction = Action | string;
-
-/**
- * The base dispatch type exposed by our dispatcher.
- */
-export interface ActionPayload {
- [property: string]: any; // effectively makes this 'extends Object'
- action: DispatcherAction;
-}
-
-/**
- * The function the dispatcher calls when ready for an AsyncActionPayload. The
- * single argument is used to start a dispatch. First the dispatcher calls the
- * outer function, then when the called function is ready it calls the cb
- * function to issue the dispatch. It may call the callback repeatedly if needed.
- */
-export type AsyncActionFn = (cb: (action: ActionPayload) => void) => void;
-
-/**
- * An async version of ActionPayload
- */
-export class AsyncActionPayload implements ActionPayload {
- /**
- * The function the dispatcher should call.
- */
- public readonly fn: AsyncActionFn;
-
- /**
- * @deprecated Not used on AsyncActionPayload.
- */
- public get action(): DispatcherAction {
- return "NOT_USED";
- }
-
- /**
- * Create a new AsyncActionPayload with the given ready function.
- * @param {AsyncActionFn} readyFn The function to be called when the
- * dispatcher is ready.
- */
- public constructor(readyFn: AsyncActionFn) {
- this.fn = readyFn;
- }
-}
+import { Action } from "./actions";
+import { ActionPayload, AsyncActionPayload } from "./payloads";
/**
* A dispatcher for ActionPayloads (the default within the SDK).
diff --git a/src/dispatcher/payloads.ts b/src/dispatcher/payloads.ts
new file mode 100644
index 0000000000..fa45b30623
--- /dev/null
+++ b/src/dispatcher/payloads.ts
@@ -0,0 +1,59 @@
+/*
+Copyright 2020 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+import { DispatcherAction } from "./actions";
+
+/**
+ * The base dispatch type exposed by our dispatcher.
+ */
+export interface ActionPayload {
+ [property: string]: any; // effectively makes this 'extends Object'
+ action: DispatcherAction;
+}
+
+/**
+ * The function the dispatcher calls when ready for an AsyncActionPayload. The
+ * single argument is used to start a dispatch. First the dispatcher calls the
+ * outer function, then when the called function is ready it calls the cb
+ * function to issue the dispatch. It may call the callback repeatedly if needed.
+ */
+export type AsyncActionFn = (cb: (action: ActionPayload) => void) => void;
+
+/**
+ * An async version of ActionPayload
+ */
+export class AsyncActionPayload implements ActionPayload {
+ /**
+ * The function the dispatcher should call.
+ */
+ public readonly fn: AsyncActionFn;
+
+ /**
+ * @deprecated Not used on AsyncActionPayload.
+ */
+ public get action(): DispatcherAction {
+ return "NOT_USED";
+ }
+
+ /**
+ * Create a new AsyncActionPayload with the given ready function.
+ * @param {AsyncActionFn} readyFn The function to be called when the
+ * dispatcher is ready.
+ */
+ public constructor(readyFn: AsyncActionFn) {
+ this.fn = readyFn;
+ }
+}
From a3b4c2dfa02d1ae5ee959eaaa59e6544a0cea6d1 Mon Sep 17 00:00:00 2001
From: Travis Ralston
Date: Wed, 13 May 2020 20:48:49 -0600
Subject: [PATCH 139/196] Convert more async actions to AsyncActionPayload
---
src/actions/GroupActions.js | 34 ----------------------------------
src/actions/GroupActions.ts | 34 ++++++++++++++++++++++++++++++++++
src/actions/TagOrderActions.ts | 3 +--
src/actions/actionCreators.ts | 5 ++---
4 files changed, 37 insertions(+), 39 deletions(-)
delete mode 100644 src/actions/GroupActions.js
create mode 100644 src/actions/GroupActions.ts
diff --git a/src/actions/GroupActions.js b/src/actions/GroupActions.js
deleted file mode 100644
index 006c2da5b8..0000000000
--- a/src/actions/GroupActions.js
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
-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.
-*/
-
-import { asyncAction } from './actionCreators';
-
-const GroupActions = {};
-
-/**
- * Creates an action thunk that will do an asynchronous request to fetch
- * the groups to which a user is joined.
- *
- * @param {MatrixClient} matrixClient the matrix client to query.
- * @returns {function} an action thunk that will dispatch actions
- * indicating the status of the request.
- * @see asyncAction
- */
-GroupActions.fetchJoinedGroups = function(matrixClient) {
- return asyncAction('GroupActions.fetchJoinedGroups', () => matrixClient.getJoinedGroups());
-};
-
-export default GroupActions;
diff --git a/src/actions/GroupActions.ts b/src/actions/GroupActions.ts
new file mode 100644
index 0000000000..81470d1221
--- /dev/null
+++ b/src/actions/GroupActions.ts
@@ -0,0 +1,34 @@
+/*
+Copyright 2017 New Vector Ltd
+Copyright 2020 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+import { asyncAction } from './actionCreators';
+import { AsyncActionPayload } from "../dispatcher/payloads";
+import { MatrixClient } from "matrix-js-sdk/src/client";
+
+export default class GroupActions {
+ /**
+ * Creates an action thunk that will do an asynchronous request to fetch
+ * the groups to which a user is joined.
+ *
+ * @param {MatrixClient} matrixClient the matrix client to query.
+ * @returns {AsyncActionPayload} An async action payload.
+ * @see asyncAction
+ */
+ public static fetchJoinedGroups(matrixClient: MatrixClient): AsyncActionPayload {
+ return asyncAction('GroupActions.fetchJoinedGroups', () => matrixClient.getJoinedGroups(), null);
+ }
+}
diff --git a/src/actions/TagOrderActions.ts b/src/actions/TagOrderActions.ts
index fa95ea1037..bf1820d5d1 100644
--- a/src/actions/TagOrderActions.ts
+++ b/src/actions/TagOrderActions.ts
@@ -90,8 +90,7 @@ export default class TagOrderActions {
if (removedTags.includes(tag)) {
// Return a thunk that doesn't do anything, we don't even need
// an asynchronous action here, the tag is already removed.
- return () => {
- };
+ return new AsyncActionPayload(() => {});
}
removedTags.push(tag);
diff --git a/src/actions/actionCreators.ts b/src/actions/actionCreators.ts
index d84868a141..c789e3cd07 100644
--- a/src/actions/actionCreators.ts
+++ b/src/actions/actionCreators.ts
@@ -44,12 +44,11 @@ import { AsyncActionPayload } from "../dispatcher/payloads";
* result is the result of the promise returned by
* `fn`.
*/
-export function asyncAction(id: string, fn: () => Promise, pendingFn: () => any): AsyncActionPayload {
+export function asyncAction(id: string, fn: () => Promise, pendingFn: () => any | null): AsyncActionPayload {
const helper = (dispatch) => {
dispatch({
action: id + '.pending',
- request:
- typeof pendingFn === 'function' ? pendingFn() : undefined,
+ request: typeof pendingFn === 'function' ? pendingFn() : undefined,
});
fn().then((result) => {
dispatch({action: id + '.success', result});
From a5f3318f3bec7d66c20a862669c3c1b938b362a6 Mon Sep 17 00:00:00 2001
From: Travis Ralston
Date: Wed, 13 May 2020 21:03:12 -0600
Subject: [PATCH 140/196] Convert view_user dispatch to prove the conversion
works
This is a relatively obvious dispatch action that doesn't require a lot of complicated type definitions, so should be a good candidate to prove the thing works. If for some reason the thing stops working, we've done something wrong.
This also adds a bit of generic types to the dispatch call so we don't confuse the tsx parser by using `dis.dispatch({...})` as it thinks that's supposed to be a component. We still get type safety, and the thing remains happy with the generics approach.
---
src/SlashCommands.tsx | 8 +++--
src/components/structures/MatrixChat.tsx | 26 ++++++++---------
src/components/structures/RightPanel.js | 5 ++--
src/components/views/avatars/MemberAvatar.js | 5 ++--
src/components/views/elements/Pill.js | 3 +-
.../views/groups/GroupMemberInfo.js | 5 ++--
.../views/right_panel/GroupHeaderButtons.js | 6 ++--
.../views/right_panel/RoomHeaderButtons.js | 6 ++--
src/components/views/right_panel/UserInfo.js | 3 +-
src/components/views/rooms/MemberInfo.js | 3 +-
src/components/views/rooms/MemberTile.js | 3 +-
src/dispatcher/actions.ts | 14 +++++++++
src/dispatcher/dispatcher.ts | 2 +-
src/dispatcher/payloads/ViewUserPayload.ts | 29 +++++++++++++++++++
14 files changed, 88 insertions(+), 30 deletions(-)
create mode 100644 src/dispatcher/payloads/ViewUserPayload.ts
diff --git a/src/SlashCommands.tsx b/src/SlashCommands.tsx
index fd157b2b4c..d81da80e8d 100644
--- a/src/SlashCommands.tsx
+++ b/src/SlashCommands.tsx
@@ -41,6 +41,8 @@ import { parseFragment as parseHtml } from "parse5";
import sendBugReport from "./rageshake/submit-rageshake";
import SdkConfig from "./SdkConfig";
import { ensureDMExists } from "./createRoom";
+import { ViewUserPayload } from "./dispatcher/payloads/ViewUserPayload";
+import { Action } from "./dispatcher/actions";
// XXX: workaround for https://github.com/microsoft/TypeScript/issues/31816
interface HTMLInputEvent extends Event {
@@ -943,8 +945,10 @@ export const Commands = [
}
const member = MatrixClientPeg.get().getRoom(roomId).getMember(userId);
- dis.dispatch({
- action: 'view_user',
+ dis.dispatch({
+ action: Action.ViewUser,
+ // XXX: We should be using a real member object and not assuming what the
+ // receiver wants.
member: member || {userId},
});
return success();
diff --git a/src/components/structures/MatrixChat.tsx b/src/components/structures/MatrixChat.tsx
index 973d301420..d368b2c23a 100644
--- a/src/components/structures/MatrixChat.tsx
+++ b/src/components/structures/MatrixChat.tsx
@@ -17,12 +17,11 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-import React, {createRef} from 'react';
-import {InvalidStoreError} from "matrix-js-sdk/src/errors";
-import {RoomMember} from "matrix-js-sdk/src/models/room-member";
-import {MatrixEvent} from "matrix-js-sdk/src/models/event";
+import React, { createRef } from 'react';
+import { InvalidStoreError } from "matrix-js-sdk/src/errors";
+import { RoomMember } from "matrix-js-sdk/src/models/room-member";
+import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { isCryptoAvailable } from 'matrix-js-sdk/src/crypto';
-
// focus-visible is a Polyfill for the :focus-visible CSS pseudo-attribute used by _AccessibleButton.scss
import 'focus-visible';
// what-input helps improve keyboard accessibility
@@ -30,7 +29,7 @@ import 'what-input';
import Analytics from "../../Analytics";
import { DecryptionFailureTracker } from "../../DecryptionFailureTracker";
-import {MatrixClientPeg} from "../../MatrixClientPeg";
+import { MatrixClientPeg } from "../../MatrixClientPeg";
import PlatformPeg from "../../PlatformPeg";
import SdkConfig from "../../SdkConfig";
import * as RoomListSorter from "../../RoomListSorter";
@@ -40,7 +39,7 @@ import Notifier from '../../Notifier';
import Modal from "../../Modal";
import Tinter from "../../Tinter";
import * as sdk from '../../index';
-import { showStartChatInviteDialog, showRoomInviteDialog } from '../../RoomInvite';
+import { showRoomInviteDialog, showStartChatInviteDialog } from '../../RoomInvite';
import * as Rooms from '../../Rooms';
import linkifyMatrix from "../../linkify-matrix";
import * as Lifecycle from '../../Lifecycle';
@@ -52,21 +51,22 @@ import { getHomePageUrl } from '../../utils/pages';
import createRoom from "../../createRoom";
import KeyRequestHandler from '../../KeyRequestHandler';
import { _t, getCurrentLanguage } from '../../languageHandler';
-import SettingsStore, {SettingLevel} from "../../settings/SettingsStore";
+import SettingsStore, { SettingLevel } from "../../settings/SettingsStore";
import ThemeController from "../../settings/controllers/ThemeController";
import { startAnyRegistrationFlow } from "../../Registration.js";
import { messageForSyncError } from '../../utils/ErrorUtils';
import ResizeNotifier from "../../utils/ResizeNotifier";
-import { ValidatedServerConfig } from "../../utils/AutoDiscoveryUtils";
-import AutoDiscoveryUtils from "../../utils/AutoDiscoveryUtils";
+import AutoDiscoveryUtils, { ValidatedServerConfig } from "../../utils/AutoDiscoveryUtils";
import DMRoomMap from '../../utils/DMRoomMap';
import { countRoomsWithNotif } from '../../RoomNotifs';
import { ThemeWatcher } from "../../theme";
import { storeRoomAliasInCache } from '../../RoomAliasCache';
-import {defer, IDeferred} from "../../utils/promise";
+import { defer, IDeferred } from "../../utils/promise";
import ToastStore from "../../stores/ToastStore";
import * as StorageManager from "../../utils/StorageManager";
import type LoggedInViewType from "./LoggedInView";
+import { ViewUserPayload } from "../../dispatcher/payloads/ViewUserPayload";
+import { Action } from "../../dispatcher/actions";
/** constants for MatrixChat.state.view */
export enum Views {
@@ -1755,8 +1755,8 @@ export default class MatrixChat extends React.PureComponent {
const member = new RoomMember(null, userId);
if (!member) { return; }
- dis.dispatch({
- action: 'view_user',
+ dis.dispatch({
+ action: Action.ViewUser,
member: member,
});
}
diff --git a/src/components/structures/RightPanel.js b/src/components/structures/RightPanel.js
index c6c330a202..56cc92a8f8 100644
--- a/src/components/structures/RightPanel.js
+++ b/src/components/structures/RightPanel.js
@@ -30,6 +30,7 @@ import SettingsStore from "../../settings/SettingsStore";
import {RIGHT_PANEL_PHASES, RIGHT_PANEL_PHASES_NO_ARGS} from "../../stores/RightPanelStorePhases";
import RightPanelStore from "../../stores/RightPanelStore";
import MatrixClientContext from "../../contexts/MatrixClientContext";
+import {Action} from "../../dispatcher/actions";
export default class RightPanel extends React.Component {
static get propTypes() {
@@ -237,7 +238,7 @@ export default class RightPanel extends React.Component {
// within a room, so go back to the member panel if we were in the encryption panel,
// or the member list if we were in the member panel... phew.
dis.dispatch({
- action: "view_user",
+ action: Action.ViewUser,
member: this.state.phase === RIGHT_PANEL_PHASES.EncryptionPanel ?
this.state.member : null,
});
@@ -266,7 +267,7 @@ export default class RightPanel extends React.Component {
if (SettingsStore.getValue("feature_cross_signing")) {
const onClose = () => {
dis.dispatch({
- action: "view_user",
+ action: Action.ViewUser,
member: null,
});
};
diff --git a/src/components/views/avatars/MemberAvatar.js b/src/components/views/avatars/MemberAvatar.js
index 89314cfef7..d28d80e62a 100644
--- a/src/components/views/avatars/MemberAvatar.js
+++ b/src/components/views/avatars/MemberAvatar.js
@@ -21,6 +21,7 @@ import createReactClass from 'create-react-class';
import * as Avatar from '../../../Avatar';
import * as sdk from "../../../index";
import dis from "../../../dispatcher/dispatcher";
+import {Action} from "../../../dispatcher/actions";
export default createReactClass({
displayName: 'MemberAvatar',
@@ -33,7 +34,7 @@ export default createReactClass({
resizeMethod: PropTypes.string,
// The onClick to give the avatar
onClick: PropTypes.func,
- // Whether the onClick of the avatar should be overriden to dispatch 'view_user'
+ // Whether the onClick of the avatar should be overriden to dispatch `Action.ViewUser`
viewUserOnClick: PropTypes.bool,
title: PropTypes.string,
},
@@ -85,7 +86,7 @@ export default createReactClass({
if (viewUserOnClick) {
onClick = () => {
dis.dispatch({
- action: 'view_user',
+ action: Action.ViewUser,
member: this.props.member,
});
};
diff --git a/src/components/views/elements/Pill.js b/src/components/views/elements/Pill.js
index 3e4ddb99e8..03a1aeed85 100644
--- a/src/components/views/elements/Pill.js
+++ b/src/components/views/elements/Pill.js
@@ -26,6 +26,7 @@ import {MatrixClientPeg} from '../../../MatrixClientPeg';
import FlairStore from "../../../stores/FlairStore";
import {getPrimaryPermalinkEntity} from "../../../utils/permalinks/Permalinks";
import MatrixClientContext from "../../../contexts/MatrixClientContext";
+import {Action} from "../../../dispatcher/actions";
// For URLs of matrix.to links in the timeline which have been reformatted by
// HttpUtils transformTags to relative links. This excludes event URLs (with `[^\/]*`)
@@ -191,7 +192,7 @@ const Pill = createReactClass({
onUserPillClicked: function() {
dis.dispatch({
- action: 'view_user',
+ action: Action.ViewUser,
member: this.state.member,
});
},
diff --git a/src/components/views/groups/GroupMemberInfo.js b/src/components/views/groups/GroupMemberInfo.js
index 0d08771676..2582cab573 100644
--- a/src/components/views/groups/GroupMemberInfo.js
+++ b/src/components/views/groups/GroupMemberInfo.js
@@ -28,6 +28,7 @@ import GroupStore from '../../../stores/GroupStore';
import AccessibleButton from '../elements/AccessibleButton';
import MatrixClientContext from "../../../contexts/MatrixClientContext";
import AutoHideScrollbar from "../../structures/AutoHideScrollbar";
+import {Action} from "../../../dispatcher/actions";
export default createReactClass({
displayName: 'GroupMemberInfo',
@@ -103,7 +104,7 @@ export default createReactClass({
).then(() => {
// return to the user list
dis.dispatch({
- action: "view_user",
+ action: Action.ViewUser,
member: null,
});
}).catch((e) => {
@@ -124,7 +125,7 @@ export default createReactClass({
_onCancel: function(e) {
// Go back to the user list
dis.dispatch({
- action: "view_user",
+ action: Action.ViewUser,
member: null,
});
},
diff --git a/src/components/views/right_panel/GroupHeaderButtons.js b/src/components/views/right_panel/GroupHeaderButtons.js
index f164b6c578..33d9325433 100644
--- a/src/components/views/right_panel/GroupHeaderButtons.js
+++ b/src/components/views/right_panel/GroupHeaderButtons.js
@@ -23,6 +23,8 @@ import { _t } from '../../../languageHandler';
import HeaderButton from './HeaderButton';
import HeaderButtons, {HEADER_KIND_GROUP} from './HeaderButtons';
import {RIGHT_PANEL_PHASES} from "../../../stores/RightPanelStorePhases";
+import {Action} from "../../../dispatcher/actions";
+import {ActionPayload} from "../../../dispatcher/payloads";
const GROUP_PHASES = [
RIGHT_PANEL_PHASES.GroupMemberInfo,
@@ -40,10 +42,10 @@ export default class GroupHeaderButtons extends HeaderButtons {
this._onRoomsClicked = this._onRoomsClicked.bind(this);
}
- onAction(payload) {
+ onAction(payload: ActionPayload) {
super.onAction(payload);
- if (payload.action === "view_user") {
+ if (payload.action === Action.ViewUser) {
if (payload.member) {
this.setPhase(RIGHT_PANEL_PHASES.RoomMemberInfo, {member: payload.member});
} else {
diff --git a/src/components/views/right_panel/RoomHeaderButtons.js b/src/components/views/right_panel/RoomHeaderButtons.js
index bad89e2dbe..838727981d 100644
--- a/src/components/views/right_panel/RoomHeaderButtons.js
+++ b/src/components/views/right_panel/RoomHeaderButtons.js
@@ -23,6 +23,8 @@ import { _t } from '../../../languageHandler';
import HeaderButton from './HeaderButton';
import HeaderButtons, {HEADER_KIND_ROOM} from './HeaderButtons';
import {RIGHT_PANEL_PHASES} from "../../../stores/RightPanelStorePhases";
+import {Action} from "../../../dispatcher/actions";
+import {ActionPayload} from "../../../dispatcher/payloads";
const MEMBER_PHASES = [
RIGHT_PANEL_PHASES.RoomMemberList,
@@ -39,9 +41,9 @@ export default class RoomHeaderButtons extends HeaderButtons {
this._onNotificationsClicked = this._onNotificationsClicked.bind(this);
}
- onAction(payload) {
+ onAction(payload: ActionPayload) {
super.onAction(payload);
- if (payload.action === "view_user") {
+ if (payload.action === Action.ViewUser) {
if (payload.member) {
this.setPhase(RIGHT_PANEL_PHASES.RoomMemberInfo, {member: payload.member});
} else {
diff --git a/src/components/views/right_panel/UserInfo.js b/src/components/views/right_panel/UserInfo.js
index daf1a9490d..0392746c94 100644
--- a/src/components/views/right_panel/UserInfo.js
+++ b/src/components/views/right_panel/UserInfo.js
@@ -44,6 +44,7 @@ import {RIGHT_PANEL_PHASES} from "../../../stores/RightPanelStorePhases";
import EncryptionPanel from "./EncryptionPanel";
import { useAsyncMemo } from '../../../hooks/useAsyncMemo';
import { verifyUser, legacyVerifyUser, verifyDevice } from '../../../verification';
+import {Action} from "../../../dispatcher/actions";
const _disambiguateDevices = (devices) => {
const names = Object.create(null);
@@ -841,7 +842,7 @@ const GroupAdminToolsSection = ({children, groupId, groupMember, startUpdating,
cli.removeUserFromGroup(groupId, groupMember.userId).then(() => {
// return to the user list
dis.dispatch({
- action: "view_user",
+ action: Action.ViewUser,
member: null,
});
}).catch((e) => {
diff --git a/src/components/views/rooms/MemberInfo.js b/src/components/views/rooms/MemberInfo.js
index 5d8e03a050..ed6c4ad748 100644
--- a/src/components/views/rooms/MemberInfo.js
+++ b/src/components/views/rooms/MemberInfo.js
@@ -48,6 +48,7 @@ import E2EIcon from "./E2EIcon";
import AutoHideScrollbar from "../../structures/AutoHideScrollbar";
import {MatrixClientPeg} from "../../../MatrixClientPeg";
import MatrixClientContext from "../../../contexts/MatrixClientContext";
+import {Action} from "../../../dispatcher/actions";
export default createReactClass({
displayName: 'MemberInfo',
@@ -724,7 +725,7 @@ export default createReactClass({
onCancel: function(e) {
dis.dispatch({
- action: "view_user",
+ action: Action.ViewUser,
member: null,
});
},
diff --git a/src/components/views/rooms/MemberTile.js b/src/components/views/rooms/MemberTile.js
index 6842e27ed3..2d290564c3 100644
--- a/src/components/views/rooms/MemberTile.js
+++ b/src/components/views/rooms/MemberTile.js
@@ -23,6 +23,7 @@ import * as sdk from "../../../index";
import dis from "../../../dispatcher/dispatcher";
import { _t } from '../../../languageHandler';
import { MatrixClientPeg } from "../../../MatrixClientPeg";
+import {Action} from "../../../dispatcher/actions";
export default createReactClass({
displayName: 'MemberTile',
@@ -185,7 +186,7 @@ export default createReactClass({
onClick: function(e) {
dis.dispatch({
- action: 'view_user',
+ action: Action.ViewUser,
member: this.props.member,
});
},
diff --git a/src/dispatcher/actions.ts b/src/dispatcher/actions.ts
index ff1650e4e5..880e7e62cd 100644
--- a/src/dispatcher/actions.ts
+++ b/src/dispatcher/actions.ts
@@ -19,5 +19,19 @@ export type DispatcherAction = Action | string;
export enum Action {
// TODO: Populate with actual actions
+ // This is lazily generated as it also includes fixing a bunch of references. Work
+ // that we don't really want to take on in a giant chunk. We should always define
+ // new actions here, and ideally when we touch existing ones we take some time to
+ // define them correctly.
+
+ // When defining a new action, please use lower_scored_case with an optional class
+ // name prefix. For example, `RoomListStore.view_room` or `view_user_settings`.
+ // New definitions should also receive an accompanying interface in the payloads
+ // directory.
+
+ /**
+ * View a user's profile. Should be used with a ViewUserPayload.
+ */
+ ViewUser = "view_user",
}
diff --git a/src/dispatcher/dispatcher.ts b/src/dispatcher/dispatcher.ts
index 6ef165c485..8330e5cd19 100644
--- a/src/dispatcher/dispatcher.ts
+++ b/src/dispatcher/dispatcher.ts
@@ -32,7 +32,7 @@ export class MatrixDispatcher extends Dispatcher {
* an operation that the browser requires user interaction
* for. Default false (async).
*/
- dispatch(payload: ActionPayload, sync = false) {
+ dispatch(payload: T, sync = false) {
if (payload instanceof AsyncActionPayload) {
payload.fn((action: ActionPayload) => {
this.dispatch(action, sync);
diff --git a/src/dispatcher/payloads/ViewUserPayload.ts b/src/dispatcher/payloads/ViewUserPayload.ts
new file mode 100644
index 0000000000..ed602d4e24
--- /dev/null
+++ b/src/dispatcher/payloads/ViewUserPayload.ts
@@ -0,0 +1,29 @@
+/*
+Copyright 2020 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+import { RoomMember } from "matrix-js-sdk/src/models/room-member";
+import { ActionPayload } from "../payloads";
+import { Action } from "../actions";
+
+export interface ViewUserPayload extends ActionPayload {
+ action: Action.ViewUser,
+
+ /**
+ * The member to view. May be null or falsy to indicate that no member
+ * should be shown (hide whichever relevant components).
+ */
+ member?: RoomMember;
+}
From e4835c4b03f7f3bb1451f75a613a90a5d3b53ce9 Mon Sep 17 00:00:00 2001
From: Travis Ralston
Date: Wed, 13 May 2020 21:07:19 -0600
Subject: [PATCH 141/196] Demonstrate dis.fire() with view_user_settings
Like a5f3318f3bec7d66c20a862669c3c1b938b362a6, this proves that the new dispatcher conversion works for fire-and-forget style dispatches too. This is another obvious-if-broken and generally safe conversion to make.
Other actions which can be dispatched this way have been excluded for reasons mentioned in the Action enum's comments.
---
.../views/dialogs/eventindex/DisableEventIndexDialog.js | 3 ++-
.../views/dialogs/keybackup/NewRecoveryMethodDialog.js | 3 ++-
.../dialogs/keybackup/RecoveryMethodRemovedDialog.js | 3 ++-
src/components/structures/MatrixChat.tsx | 8 +++-----
src/components/views/context_menus/TopLeftMenu.js | 3 ++-
src/components/views/dialogs/AddressPickerDialog.js | 3 ++-
.../views/dialogs/IntegrationsDisabledDialog.js | 3 ++-
src/components/views/dialogs/InviteDialog.js | 3 ++-
src/components/views/room_settings/UrlPreviewSettings.js | 3 ++-
src/dispatcher/actions.ts | 5 +++++
10 files changed, 24 insertions(+), 13 deletions(-)
diff --git a/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.js b/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.js
index 8af0bf278e..ec4b88f759 100644
--- a/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.js
+++ b/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.js
@@ -22,6 +22,7 @@ import { _t } from '../../../../languageHandler';
import SettingsStore, {SettingLevel} from "../../../../settings/SettingsStore";
import EventIndexPeg from "../../../../indexing/EventIndexPeg";
+import {Action} from "../../../../dispatcher/actions";
/*
* Allows the user to disable the Event Index.
@@ -47,7 +48,7 @@ export default class DisableEventIndexDialog extends React.Component {
await SettingsStore.setValue('enableEventIndexing', null, SettingLevel.DEVICE, false);
await EventIndexPeg.deleteEventIndex();
this.props.onFinished();
- dis.dispatch({ action: 'view_user_settings' });
+ dis.fire(Action.ViewUserSettings);
}
render() {
diff --git a/src/async-components/views/dialogs/keybackup/NewRecoveryMethodDialog.js b/src/async-components/views/dialogs/keybackup/NewRecoveryMethodDialog.js
index f00f2d9c3c..74552a5c08 100644
--- a/src/async-components/views/dialogs/keybackup/NewRecoveryMethodDialog.js
+++ b/src/async-components/views/dialogs/keybackup/NewRecoveryMethodDialog.js
@@ -22,6 +22,7 @@ import {MatrixClientPeg} from '../../../../MatrixClientPeg';
import dis from "../../../../dispatcher/dispatcher";
import { _t } from "../../../../languageHandler";
import Modal from "../../../../Modal";
+import {Action} from "../../../../dispatcher/actions";
export default class NewRecoveryMethodDialog extends React.PureComponent {
static propTypes = {
@@ -36,7 +37,7 @@ export default class NewRecoveryMethodDialog extends React.PureComponent {
onGoToSettingsClick = () => {
this.props.onFinished();
- dis.dispatch({ action: 'view_user_settings' });
+ dis.fire(Action.ViewUserSettings);
}
onSetupClick = async () => {
diff --git a/src/async-components/views/dialogs/keybackup/RecoveryMethodRemovedDialog.js b/src/async-components/views/dialogs/keybackup/RecoveryMethodRemovedDialog.js
index 722334cd70..cda353e717 100644
--- a/src/async-components/views/dialogs/keybackup/RecoveryMethodRemovedDialog.js
+++ b/src/async-components/views/dialogs/keybackup/RecoveryMethodRemovedDialog.js
@@ -21,6 +21,7 @@ import * as sdk from "../../../../index";
import dis from "../../../../dispatcher/dispatcher";
import { _t } from "../../../../languageHandler";
import Modal from "../../../../Modal";
+import {Action} from "../../../../dispatcher/actions";
export default class RecoveryMethodRemovedDialog extends React.PureComponent {
static propTypes = {
@@ -29,7 +30,7 @@ export default class RecoveryMethodRemovedDialog extends React.PureComponent {
onGoToSettingsClick = () => {
this.props.onFinished();
- dis.dispatch({ action: 'view_user_settings' });
+ dis.fire(Action.ViewUserSettings);
}
onSetupClick = () => {
diff --git a/src/components/structures/MatrixChat.tsx b/src/components/structures/MatrixChat.tsx
index d368b2c23a..cf0388c490 100644
--- a/src/components/structures/MatrixChat.tsx
+++ b/src/components/structures/MatrixChat.tsx
@@ -107,7 +107,7 @@ export enum Views {
// re-dispatched. NOTE: some actions are non-trivial and would require
// re-factoring to be included in this list in future.
const ONBOARDING_FLOW_STARTERS = [
- 'view_user_settings',
+ Action.ViewUserSettings,
'view_create_chat',
'view_create_room',
'view_create_group',
@@ -613,7 +613,7 @@ export default class MatrixChat extends React.PureComponent {
case 'view_indexed_room':
this.viewIndexedRoom(payload.roomIndex);
break;
- case 'view_user_settings': {
+ case Action.ViewUserSettings: {
const UserSettingsDialog = sdk.getComponent("dialogs.UserSettingsDialog");
Modal.createTrackedDialog('User settings', '', UserSettingsDialog, {},
/*className=*/null, /*isPriority=*/false, /*isStatic=*/true);
@@ -1621,9 +1621,7 @@ export default class MatrixChat extends React.PureComponent {
action: 'view_create_room',
});
} else if (screen === 'settings') {
- dis.dispatch({
- action: 'view_user_settings',
- });
+ dis.fire(Action.ViewUserSettings);
} else if (screen === 'welcome') {
dis.dispatch({
action: 'view_welcome_page',
diff --git a/src/components/views/context_menus/TopLeftMenu.js b/src/components/views/context_menus/TopLeftMenu.js
index 3ec857be2f..ec99c63724 100644
--- a/src/components/views/context_menus/TopLeftMenu.js
+++ b/src/components/views/context_menus/TopLeftMenu.js
@@ -27,6 +27,7 @@ import {MatrixClientPeg} from '../../../MatrixClientPeg';
import {MenuItem} from "../../structures/ContextMenu";
import * as sdk from "../../../index";
import {getHomePageUrl} from "../../../utils/pages";
+import {Action} from "../../../dispatcher/actions";
export default class TopLeftMenu extends React.Component {
static propTypes = {
@@ -134,7 +135,7 @@ export default class TopLeftMenu extends React.Component {
}
openSettings() {
- dis.dispatch({action: 'view_user_settings'});
+ dis.fire(Action.ViewUserSettings);
this.closeMenu();
}
diff --git a/src/components/views/dialogs/AddressPickerDialog.js b/src/components/views/dialogs/AddressPickerDialog.js
index 41a819c005..8ddd89dc65 100644
--- a/src/components/views/dialogs/AddressPickerDialog.js
+++ b/src/components/views/dialogs/AddressPickerDialog.js
@@ -33,6 +33,7 @@ import { getDefaultIdentityServerUrl, useDefaultIdentityServer } from '../../../
import { abbreviateUrl } from '../../../utils/UrlUtils';
import {sleep} from "../../../utils/promise";
import {Key} from "../../../Keyboard";
+import {Action} from "../../../dispatcher/actions";
const TRUNCATE_QUERY_LIST = 40;
const QUERY_USER_DIRECTORY_DEBOUNCE_MS = 200;
@@ -615,7 +616,7 @@ export default createReactClass({
onManageSettingsClick(e) {
e.preventDefault();
- dis.dispatch({ action: 'view_user_settings' });
+ dis.fire(Action.ViewUserSettings);
this.onCancel();
},
diff --git a/src/components/views/dialogs/IntegrationsDisabledDialog.js b/src/components/views/dialogs/IntegrationsDisabledDialog.js
index 2677963281..7c996fbeab 100644
--- a/src/components/views/dialogs/IntegrationsDisabledDialog.js
+++ b/src/components/views/dialogs/IntegrationsDisabledDialog.js
@@ -19,6 +19,7 @@ import PropTypes from 'prop-types';
import {_t} from "../../../languageHandler";
import * as sdk from "../../../index";
import dis from '../../../dispatcher/dispatcher';
+import {Action} from "../../../dispatcher/actions";
export default class IntegrationsDisabledDialog extends React.Component {
static propTypes = {
@@ -31,7 +32,7 @@ export default class IntegrationsDisabledDialog extends React.Component {
_onOpenSettingsClick = () => {
this.props.onFinished();
- dis.dispatch({action: "view_user_settings"});
+ dis.fire(Action.ViewUserSettings);
};
render() {
diff --git a/src/components/views/dialogs/InviteDialog.js b/src/components/views/dialogs/InviteDialog.js
index e62c417a70..1e624f7545 100644
--- a/src/components/views/dialogs/InviteDialog.js
+++ b/src/components/views/dialogs/InviteDialog.js
@@ -36,6 +36,7 @@ import {inviteMultipleToRoom} from "../../../RoomInvite";
import SettingsStore from '../../../settings/SettingsStore';
import RoomListStore, {TAG_DM} from "../../../stores/RoomListStore";
import {Key} from "../../../Keyboard";
+import {Action} from "../../../dispatcher/actions";
export const KIND_DM = "dm";
export const KIND_INVITE = "invite";
@@ -902,7 +903,7 @@ export default class InviteDialog extends React.PureComponent {
_onManageSettingsClick = (e) => {
e.preventDefault();
- dis.dispatch({ action: 'view_user_settings' });
+ dis.fire(Action.ViewUserSettings);
this.props.onFinished();
};
diff --git a/src/components/views/room_settings/UrlPreviewSettings.js b/src/components/views/room_settings/UrlPreviewSettings.js
index 16dffd857b..cd00e5048c 100644
--- a/src/components/views/room_settings/UrlPreviewSettings.js
+++ b/src/components/views/room_settings/UrlPreviewSettings.js
@@ -25,6 +25,7 @@ import { _t, _td } from '../../../languageHandler';
import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore";
import dis from "../../../dispatcher/dispatcher";
import {MatrixClientPeg} from "../../../MatrixClientPeg";
+import {Action} from "../../../dispatcher/actions";
export default createReactClass({
@@ -37,7 +38,7 @@ export default createReactClass({
_onClickUserSettings: (e) => {
e.preventDefault();
e.stopPropagation();
- dis.dispatch({action: 'view_user_settings'});
+ dis.fire(Action.ViewUserSettings);
},
render: function() {
diff --git a/src/dispatcher/actions.ts b/src/dispatcher/actions.ts
index 880e7e62cd..a2f9c3efe3 100644
--- a/src/dispatcher/actions.ts
+++ b/src/dispatcher/actions.ts
@@ -33,5 +33,10 @@ export enum Action {
* View a user's profile. Should be used with a ViewUserPayload.
*/
ViewUser = "view_user",
+
+ /**
+ * Open the user settings. No additional payload information required.
+ */
+ ViewUserSettings = "view_user_settings",
}
From d1c6f3099c0fbcbb8e2d94f19660a99d8a378c2b Mon Sep 17 00:00:00 2001
From: Michael Telatynski <7t3chguy@gmail.com>
Date: Thu, 14 May 2020 11:20:06 +0100
Subject: [PATCH 142/196] move styling to QRCode scss
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
---
res/css/_components.scss | 1 +
res/css/views/dialogs/_ShareDialog.scss | 6 ------
res/css/views/elements/_QRCode.scss | 21 +++++++++++++++++++++
3 files changed, 22 insertions(+), 6 deletions(-)
create mode 100644 res/css/views/elements/_QRCode.scss
diff --git a/res/css/_components.scss b/res/css/_components.scss
index 428a28ac3a..c05e2cabc6 100644
--- a/res/css/_components.scss
+++ b/res/css/_components.scss
@@ -108,6 +108,7 @@
@import "./views/elements/_ManageIntegsButton.scss";
@import "./views/elements/_PowerSelector.scss";
@import "./views/elements/_ProgressBar.scss";
+@import "./views/elements/_QRCode.scss";
@import "./views/elements/_ReplyThread.scss";
@import "./views/elements/_ResizeHandle.scss";
@import "./views/elements/_RichText.scss";
diff --git a/res/css/views/dialogs/_ShareDialog.scss b/res/css/views/dialogs/_ShareDialog.scss
index 3c984bbd1b..e08469ec6d 100644
--- a/res/css/views/dialogs/_ShareDialog.scss
+++ b/res/css/views/dialogs/_ShareDialog.scss
@@ -67,12 +67,6 @@ limitations under the License.
height: 256px;
width: 256px;
margin-right: 64px;
-
- img {
- width: 100%;
- height: 100%;
- border-radius: 8px;
- }
}
.mx_ShareDialog_social_container {
diff --git a/res/css/views/elements/_QRCode.scss b/res/css/views/elements/_QRCode.scss
new file mode 100644
index 0000000000..96d9114b54
--- /dev/null
+++ b/res/css/views/elements/_QRCode.scss
@@ -0,0 +1,21 @@
+/*
+Copyright 2020 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+.mx_QRCode {
+ img {
+ border-radius: 8px;
+ }
+}
From 4c7d7032755f7a3e144efe696e5e60279b876fdf Mon Sep 17 00:00:00 2001
From: Michael Telatynski <7t3chguy@gmail.com>
Date: Thu, 14 May 2020 11:20:27 +0100
Subject: [PATCH 143/196] Reuse QRCode for VerificationQRCode and specify
widths
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
---
src/components/views/dialogs/ShareDialog.tsx | 2 +-
src/components/views/elements/QRCode.tsx | 9 ++---
.../elements/crypto/VerificationQRCode.js | 36 ++++---------------
3 files changed, 13 insertions(+), 34 deletions(-)
diff --git a/src/components/views/dialogs/ShareDialog.tsx b/src/components/views/dialogs/ShareDialog.tsx
index 3924fd42ec..271f754fd2 100644
--- a/src/components/views/dialogs/ShareDialog.tsx
+++ b/src/components/views/dialogs/ShareDialog.tsx
@@ -221,7 +221,7 @@ export default class ShareDialog extends React.PureComponent {
-
+
{ socials.map((social) => (
diff --git a/src/components/views/elements/QRCode.tsx b/src/components/views/elements/QRCode.tsx
index 9c867058c0..f70ab48fa3 100644
--- a/src/components/views/elements/QRCode.tsx
+++ b/src/components/views/elements/QRCode.tsx
@@ -16,19 +16,21 @@ limitations under the License.
import * as React from "react";
import {toDataURL, QRCodeSegment, QRCodeToDataURLOptions} from "qrcode";
+import classNames from "classnames";
import {_t} from "../../../languageHandler";
import Spinner from "./Spinner";
interface IProps extends QRCodeToDataURLOptions {
data: string | QRCodeSegment[];
+ className?: string;
}
const defaultOptions: QRCodeToDataURLOptions = {
errorCorrectionLevel: 'L', // we want it as trivial-looking as possible
};
-const QRCode: React.FC = ({data, ...options}) => {
+const QRCode: React.FC = ({data, className, ...options}) => {
const [dataUri, setUri] = React.useState(null);
React.useEffect(() => {
let cancelled = false;
@@ -39,10 +41,9 @@ const QRCode: React.FC = ({data, ...options}) => {
return () => {
cancelled = true;
};
- }, [data, options]);
+ }, [JSON.stringify(data), options]);
-
- return
+ return
{ dataUri ? : }
;
};
diff --git a/src/components/views/elements/crypto/VerificationQRCode.js b/src/components/views/elements/crypto/VerificationQRCode.js
index 08cd0c772e..3bbfb004c6 100644
--- a/src/components/views/elements/crypto/VerificationQRCode.js
+++ b/src/components/views/elements/crypto/VerificationQRCode.js
@@ -17,8 +17,7 @@ limitations under the License.
import React from "react";
import PropTypes from "prop-types";
import {replaceableComponent} from "../../../../utils/replaceableComponent";
-import Spinner from "../Spinner";
-import * as QRCode from "qrcode";
+import QRCode from "../QRCode";
@replaceableComponent("views.elements.crypto.VerificationQRCode")
export default class VerificationQRCode extends React.PureComponent {
@@ -26,33 +25,12 @@ export default class VerificationQRCode extends React.PureComponent {
qrCodeData: PropTypes.object.isRequired,
};
- constructor(props) {
- super(props);
- this.state = {
- dataUri: null,
- };
- this.generateQrCode();
- }
-
- componentDidUpdate(prevProps): void {
- if (JSON.stringify(this.props) === JSON.stringify(prevProps)) return; // No prop change
-
- this.generateQRCode();
- }
-
- async generateQrCode() {
- // Now actually assemble the QR code's data URI
- const uri = await QRCode.toDataURL([{data: this.props.qrCodeData.buffer, mode: 'byte'}], {
- errorCorrectionLevel: 'L', // we want it as trivial-looking as possible
- });
- this.setState({dataUri: uri});
- }
-
render() {
- if (!this.state.dataUri) {
- return
;
- }
-
- return ;
+ return (
+
+ );
}
}
From edba204408483ad41db5abaeb04768e945a233a5 Mon Sep 17 00:00:00 2001
From: Michael Telatynski <7t3chguy@gmail.com>
Date: Thu, 14 May 2020 13:04:30 +0100
Subject: [PATCH 144/196] accept and linkify local domains like those from mDNS
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
---
src/linkify-matrix.js | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/linkify-matrix.js b/src/linkify-matrix.js
index ee9f703136..77c62ce84d 100644
--- a/src/linkify-matrix.js
+++ b/src/linkify-matrix.js
@@ -44,7 +44,7 @@ function matrixLinkify(linkify) {
const S_HASH = S_START.jump(TT.POUND);
const S_HASH_NAME = new linkify.parser.State();
const S_HASH_NAME_COLON = new linkify.parser.State();
- const S_HASH_NAME_COLON_DOMAIN = new linkify.parser.State();
+ const S_HASH_NAME_COLON_DOMAIN = new linkify.parser.State(ROOMALIAS);
const S_HASH_NAME_COLON_DOMAIN_DOT = new linkify.parser.State();
const S_ROOMALIAS = new linkify.parser.State(ROOMALIAS);
const S_ROOMALIAS_COLON = new linkify.parser.State();
@@ -92,7 +92,7 @@ function matrixLinkify(linkify) {
const S_AT = S_START.jump(TT.AT);
const S_AT_NAME = new linkify.parser.State();
const S_AT_NAME_COLON = new linkify.parser.State();
- const S_AT_NAME_COLON_DOMAIN = new linkify.parser.State();
+ const S_AT_NAME_COLON_DOMAIN = new linkify.parser.State(USERID);
const S_AT_NAME_COLON_DOMAIN_DOT = new linkify.parser.State();
const S_USERID = new linkify.parser.State(USERID);
const S_USERID_COLON = new linkify.parser.State();
@@ -138,7 +138,7 @@ function matrixLinkify(linkify) {
const S_PLUS = S_START.jump(TT.PLUS);
const S_PLUS_NAME = new linkify.parser.State();
const S_PLUS_NAME_COLON = new linkify.parser.State();
- const S_PLUS_NAME_COLON_DOMAIN = new linkify.parser.State();
+ const S_PLUS_NAME_COLON_DOMAIN = new linkify.parser.State(GROUPID);
const S_PLUS_NAME_COLON_DOMAIN_DOT = new linkify.parser.State();
const S_GROUPID = new linkify.parser.State(GROUPID);
const S_GROUPID_COLON = new linkify.parser.State();
From cae28b48d6ed5de74e676e2a216637f5e73619d7 Mon Sep 17 00:00:00 2001
From: Travis Ralston
Date: Thu, 14 May 2020 09:43:34 -0600
Subject: [PATCH 145/196] Remove debugging that causes email addresses to load
forever
This was left in by accident for https://github.com/matrix-org/matrix-react-sdk/pull/4557
---
.../views/settings/tabs/user/GeneralUserSettingsTab.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js b/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js
index 867982ad2b..0f82ce3a32 100644
--- a/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js
+++ b/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js
@@ -348,7 +348,7 @@ export default class GeneralUserSettingsTab extends React.Component {
// For newer homeservers with separate 3PID add and bind methods (MSC2290),
// there is no such concern, so we can always show the HS account 3PIDs.
if (this.state.haveIdServer || this.state.serverSupportsSeparateAddAndBind === true) {
- const emails = this.state.loading3pids || true
+ const emails = this.state.loading3pids
?
:
Date: Thu, 14 May 2020 15:57:39 +0000
Subject: [PATCH 146/196] Translated using Weblate (Esperanto)
Currently translated at 100.0% (2308 of 2308 strings)
Translation: Riot Web/matrix-react-sdk
Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/eo/
---
src/i18n/strings/eo.json | 19 ++++++++++++-------
1 file changed, 12 insertions(+), 7 deletions(-)
diff --git a/src/i18n/strings/eo.json b/src/i18n/strings/eo.json
index 9e8641a6e9..11239303f8 100644
--- a/src/i18n/strings/eo.json
+++ b/src/i18n/strings/eo.json
@@ -172,7 +172,7 @@
"New passwords don't match": "Novaj pasvortoj ne akordas",
"Passwords can't be empty": "Pasvortoj ne povas esti malplenaj",
"Continue": "Daŭrigi",
- "Export E2E room keys": "Elporti ĝiscele ĉifrajn ŝlosilojn de la ĉambro",
+ "Export E2E room keys": "Elporti tutvoje ĉifrajn ŝlosilojn de la ĉambro",
"Do you want to set an email address?": "Ĉu vi volas agordi retpoŝtadreson?",
"Current password": "Nuna pasvorto",
"Password": "Pasvorto",
@@ -538,8 +538,8 @@
"Are you sure you want to leave the room '%(roomName)s'?": "Ĉu vi certe volas forlasi la ĉambron '%(roomName)s'?",
"Failed to leave room": "Malsukcesis forlasi la ĉambron",
"Signed Out": "Adiaŭinta",
- "Old cryptography data detected": "Malnovaj kriptografiaj datumoj troviĝis",
- "Data from an older version of Riot has been detected. This will have caused end-to-end cryptography to malfunction in the older version. End-to-end encrypted messages exchanged recently whilst using the older version may not be decryptable in this version. This may also cause messages exchanged with this version to fail. If you experience problems, log out and back in again. To retain message history, export and re-import your keys.": "Datumoj el malnova versio de Riot troviĝis. Ĉi tio malfunkciigos ĝiscelan ĉifradon en la malnova versio. Ĝiscele ĉifritaj mesaĝoj interŝanĝitaj freŝtempe per la malnova versio eble ne malĉifreblos. Tio povas kaŭzi malsukceson ankaŭ al mesaĝoj interŝanĝitaj kun tiu ĉi versio. Se vin trafos problemoj, adiaŭu kaj resalutu. Por reteni mesaĝan historion, elportu kaj reenportu viajn ŝlosilojn.",
+ "Old cryptography data detected": "Malnovaj datumoj de ĉifroteĥnikaro troviĝis",
+ "Data from an older version of Riot has been detected. This will have caused end-to-end cryptography to malfunction in the older version. End-to-end encrypted messages exchanged recently whilst using the older version may not be decryptable in this version. This may also cause messages exchanged with this version to fail. If you experience problems, log out and back in again. To retain message history, export and re-import your keys.": "Datumoj el malnova versio de Riot troviĝis. Ĉi tio malfunkciigos tutvojan ĉifradon en la malnova versio. Tutvoje ĉifritaj mesaĝoj interŝanĝitaj freŝtempe per la malnova versio eble ne malĉifreblos. Tio povas kaŭzi malsukceson ankaŭ al mesaĝoj interŝanĝitaj kun tiu ĉi versio. Se vin trafos problemoj, adiaŭu kaj resalutu. Por reteni mesaĝan historion, elportu kaj reenportu viajn ŝlosilojn.",
"Logout": "Adiaŭi",
"Your Communities": "Viaj komunumoj",
"Error whilst fetching joined communities": "Akirado de viaj komunumoj eraris",
@@ -576,8 +576,8 @@
"Success": "Sukceso",
"Unable to remove contact information": "Ne povas forigi kontaktajn informojn",
"": "