{ controls }
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/ReadReceiptMarker.js b/src/components/views/rooms/ReadReceiptMarker.js
index 85d443d55a..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/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..5e5de45f2f 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';
@@ -785,6 +785,7 @@ export default createReactClass({
label: _t('Rooms'),
incomingCall: incomingCallIfTaggedAs('im.vector.fake.recent'),
onAddRoom: () => {dis.dispatch({action: 'view_create_room'});},
+ addRoomLabel: _t("Create room"),
},
];
const tagSubLists = Object.keys(this.state.lists)
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/AppearanceUserSettingsTab.js b/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.js
new file mode 100644
index 0000000000..5b49dd0abd
--- /dev/null
+++ b/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.js
@@ -0,0 +1,281 @@
+/*
+Copyright 2019 New Vector Ltd
+Copyright 2019, 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 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";
+import Slider from "../../../elements/Slider";
+import AccessibleButton from "../../../elements/AccessibleButton";
+import dis from "../../../../../dispatcher/dispatcher";
+import { FontWatcher } from "../../../../../FontWatcher";
+
+export default class AppearanceUserSettingsTab extends React.Component {
+ constructor() {
+ super();
+
+ this.state = {
+ fontSize: SettingsStore.getValue("fontSize", null),
+ ...this._calculateThemeState(),
+ customThemeUrl: "",
+ customThemeMessage: {isError: false, text: ""},
+ useCustomFontSize: SettingsStore.getValue("useCustomFontSize"),
+ };
+ }
+
+ _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) => {
+ this.setState({fontSize: size});
+ SettingsStore.setValue("fontSize", null, SettingLevel.DEVICE, size);
+ };
+
+ _onValidateFontSize = ({value}) => {
+ console.log({value});
+
+ const parsedSize = parseFloat(value);
+ const min = FontWatcher.MIN_SIZE;
+ const max = FontWatcher.MAX_SIZE;
+
+ if (isNaN(parsedSize)) {
+ return {valid: false, feedback: _t("Size must be a number")};
+ }
+
+ 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("fontSize", 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 = [];
+ 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 (
+
+
{_t("Appearance")}
+ {this._renderThemeSection()}
+ {SettingsStore.isFeatureEnabled("feature_font_scaling") ? this._renderFontSection() : null}
+
+ );
+ }
+
+ _renderThemeSection() {
+ const SettingsFlag = sdk.getComponent("views.elements.SettingsFlag");
+ const LabelledToggleSwitch = sdk.getComponent("views.elements.LabelledToggleSwitch");
+
+ const themeWatcher = new ThemeWatcher();
+ let systemThemeSection;
+ if (themeWatcher.isSystemThemeSupported()) {
+ systemThemeSection =
+
+
;
+ }
+
+ let customThemeForm;
+ if (SettingsStore.isFeatureEnabled("feature_custom_themes")) {
+ let messageElement = null;
+ if (this.state.customThemeMessage.text) {
+ if (this.state.customThemeMessage.isError) {
+ messageElement =
{this.state.customThemeMessage.text}
;
+ } else {
+ messageElement =
{this.state.customThemeMessage.text}
;
+ }
+ }
+ customThemeForm = (
+
+ );
+ }
+
+ const themes = Object.entries(enumerateThemes())
+ .map(p => ({id: p[0], name: p[1]})); // convert pairs to objects for code readability
+ const builtInThemes = themes.filter(p => !p.id.startsWith("custom-"));
+ const customThemes = themes.filter(p => !builtInThemes.includes(p))
+ .sort((a, b) => a.name.localeCompare(b.name));
+ const orderedThemes = [...builtInThemes, ...customThemes];
+ return (
+
+ {_t("Theme")}
+ {systemThemeSection}
+
+ {orderedThemes.map(theme => {
+ return ;
+ })}
+
+ {customThemeForm}
+
+
+ );
+ }
+
+ _renderFontSection() {
+ const SettingsFlag = sdk.getComponent("views.elements.SettingsFlag");
+ return
+
{_t("Font size")}
+
+
Aa
+
{}}
+ disabled={this.state.useCustomFontSize}
+ />
+ Aa
+
+
this.setState({useCustomFontSize: checked})}
+ />
+ this.setState({fontSize: value.target.value})}
+ disabled={!this.state.useCustomFontSize}
+ />
+ ;
+ }
+}
diff --git a/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js b/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js
index 0f82ce3a32..c7e7ce7c2c 100644
--- a/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js
+++ b/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js
@@ -19,7 +19,6 @@ limitations under the License.
import React from 'react';
import {_t} from "../../../../../languageHandler";
import ProfileSettings from "../../ProfileSettings";
-import Field from "../../../elements/Field";
import * as languageHandler from "../../../../../languageHandler";
import {SettingLevel} from "../../../../../settings/SettingsStore";
import SettingsStore from "../../../../../settings/SettingsStore";
@@ -27,12 +26,11 @@ import LanguageDropdown from "../../../elements/LanguageDropdown";
import AccessibleButton from "../../../elements/AccessibleButton";
import DeactivateAccountDialog from "../../../dialogs/DeactivateAccountDialog";
import PropTypes from "prop-types";
-import {enumerateThemes, ThemeWatcher} from "../../../../../theme";
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";
@@ -62,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);
@@ -93,39 +88,6 @@ export default class GeneralUserSettingsTab extends React.Component {
dis.unregister(this.dispatcherRef);
}
- _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"),
- };
- }
-
_onAction = (payload) => {
if (payload.action === 'id_server_changed') {
this.setState({haveIdServer: Boolean(MatrixClientPeg.get().getIdentityServerUrl())});
@@ -219,33 +181,6 @@ export default class GeneralUserSettingsTab extends React.Component {
PlatformPeg.get().reload();
};
- _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'});
- };
-
_onPasswordChangeError = (err) => {
// TODO: Figure out a design that doesn't involve replacing the current dialog
let errMsg = err.error || "";
@@ -282,41 +217,6 @@ export default class GeneralUserSettingsTab extends React.Component {
});
};
- _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});
- };
-
_renderProfileSection() {
return (
@@ -401,77 +301,6 @@ export default class GeneralUserSettingsTab extends React.Component {
);
}
- _renderThemeSection() {
- const SettingsFlag = sdk.getComponent("views.elements.SettingsFlag");
- const LabelledToggleSwitch = sdk.getComponent("views.elements.LabelledToggleSwitch");
-
- const themeWatcher = new ThemeWatcher();
- let systemThemeSection;
- if (themeWatcher.isSystemThemeSupported()) {
- systemThemeSection =
-
-
;
- }
-
- let customThemeForm;
- if (SettingsStore.isFeatureEnabled("feature_custom_themes")) {
- let messageElement = null;
- if (this.state.customThemeMessage.text) {
- if (this.state.customThemeMessage.isError) {
- messageElement =
{this.state.customThemeMessage.text}
;
- } else {
- messageElement =
{this.state.customThemeMessage.text}
;
- }
- }
- customThemeForm = (
-
- );
- }
-
- const themes = Object.entries(enumerateThemes())
- .map(p => ({id: p[0], name: p[1]})); // convert pairs to objects for code readability
- const builtInThemes = themes.filter(p => !p.id.startsWith("custom-"));
- const customThemes = themes.filter(p => !builtInThemes.includes(p))
- .sort((a, b) => a.name.localeCompare(b.name));
- const orderedThemes = [...builtInThemes, ...customThemes];
- return (
-
- {_t("Theme")}
- {systemThemeSection}
-
- {orderedThemes.map(theme => {
- return ;
- })}
-
- {customThemeForm}
-
-
- );
- }
-
_renderDiscoverySection() {
const SetIdServer = sdk.getComponent("views.settings.SetIdServer");
@@ -560,7 +389,6 @@ export default class GeneralUserSettingsTab extends React.Component {
{this._renderProfileSection()}
{this._renderAccountSection()}
{this._renderLanguageSection()}
- {this._renderThemeSection()}
{discoWarning} {_t("Discovery")}
{this._renderDiscoverySection()}
{this._renderIntegrationManagerSection() /* Has its own title */}
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/actions.ts b/src/dispatcher/actions.ts
new file mode 100644
index 0000000000..a2f9c3efe3
--- /dev/null
+++ b/src/dispatcher/actions.ts
@@ -0,0 +1,42 @@
+/*
+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
+ // 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",
+
+ /**
+ * Open the user settings. No additional payload information required.
+ */
+ ViewUserSettings = "view_user_settings",
+}
+
diff --git a/src/dispatcher.js b/src/dispatcher/dispatcher.ts
similarity index 50%
rename from src/dispatcher.js
rename to src/dispatcher/dispatcher.ts
index 5dfaa11345..8330e5cd19 100644
--- a/src/dispatcher.js
+++ b/src/dispatcher/dispatcher.ts
@@ -1,6 +1,7 @@
/*
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.
@@ -15,25 +16,25 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-'use strict';
+import { Dispatcher } from "flux";
+import { Action } from "./actions";
+import { ActionPayload, AsyncActionPayload } from "./payloads";
-import flux from "flux";
-
-class MatrixDispatcher extends flux.Dispatcher {
+/**
+ * A dispatcher for ActionPayloads (the default within the SDK).
+ */
+export class MatrixDispatcher extends 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
+ * 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.
+ * for. Default false (async).
*/
- dispatch(payload, sync) {
- // Allow for asynchronous dispatching by accepting payloads that have the
- // type `function (dispatch) {...}`
- if (typeof payload === 'function') {
- payload((action) => {
+ dispatch(payload: T, sync = false) {
+ if (payload instanceof AsyncActionPayload) {
+ payload.fn((action: ActionPayload) => {
this.dispatch(action, sync);
});
return;
@@ -50,9 +51,24 @@ class MatrixDispatcher extends flux.Dispatcher {
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);
+ }
}
-if (global.mxDispatcher === undefined) {
- global.mxDispatcher = new MatrixDispatcher();
+export const defaultDispatcher = new MatrixDispatcher();
+
+const anyGlobal = global;
+if (!anyGlobal.mxDispatcher) {
+ anyGlobal.mxDispatcher = defaultDispatcher;
}
-export default global.mxDispatcher;
+
+export default defaultDispatcher;
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;
+ }
+}
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;
+}
diff --git a/src/i18n/strings/de_DE.json b/src/i18n/strings/de_DE.json
index 7fdaf20e40..1166e7710a 100644
--- a/src/i18n/strings/de_DE.json
+++ b/src/i18n/strings/de_DE.json
@@ -1794,7 +1794,7 @@
"Confirm adding this email address by using Single Sign On to prove your identity.": "Bestätige das Hinzufügen dieser E-Mail-Adresse mit „Single Sign-On“, um deine Identität nachzuweisen.",
"Single Sign On": "Single Sign-On",
"Confirm adding email": "Bestätige das Hinzfugen der Email-Addresse",
- "Confirm adding this phone number by using Single Sign On to prove your identity.": "Bestätige das Hinzufügen dieser Telefonnumer, indem du deine Identität mittels Single Sign-On nachweist.",
+ "Confirm adding this phone number by using Single Sign On to prove your identity.": "Bestätige das Hinzufügen dieser Telefonnummer, indem du deine Identität mittels „Single Sign-On“ nachweist.",
"Click the button below to confirm adding this phone number.": "Betätige unten die Schaltfläche um das Hinzufügen dieser Telefonnummer zu bestätigen.",
"If you cancel now, you won't complete your operation.": "Wenn du jetzt abbrichst, wirst du deinen Vorgang nicht fertigstellen.",
"%(name)s is requesting verification": "%(name)s fordert eine Verifizierung an",
@@ -2365,5 +2365,15 @@
"Activate selected button": "Ausgewählten Button aktivieren",
"Toggle right panel": "Rechtes Panel ein-/ausblenden",
"Toggle this dialog": "Diesen Dialog ein-/ausblenden",
- "Move autocomplete selection up/down": "Auto-Vervollständigung nach oben/unten verschieben"
+ "Move autocomplete selection up/down": "Auto-Vervollständigung nach oben/unten verschieben",
+ "Opens chat with the given user": "Öffnet einen Chat mit diesem Benutzer",
+ "Sends a message to the given user": "Sendet diesem Benutzer eine Nachricht",
+ "Waiting for your other session to verify…": "Warte auf die Verifikation deiner anderen Sitzungen…",
+ "You've successfully verified your device!": "Du hast dein Gerät erfolgreich verifiziert!",
+ "QR Code": "QR-Code",
+ "To continue, use Single Sign On to prove your identity.": "Zum Fortfahren, nutze Single Sign On um deine Identität zu bestätigen.",
+ "Confirm to continue": "Bestätige um fortzufahren",
+ "Click the button below to confirm your identity.": "Klicke den Button unten um deine Identität zu bestätigen.",
+ "Confirm encryption setup": "Bestätige die Einrichtung der Verschlüsselung",
+ "Click the button below to confirm setting up encryption.": "Klick die Schaltfläche unten um die Einstellungen der Verschlüsselung zu bestätigen."
}
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index 82b2a752ea..b7417762f1 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -400,6 +400,7 @@
"Sorry, your homeserver is too old to participate in this room.": "Sorry, your homeserver is too old to participate in this room.",
"Please contact your homeserver administrator.": "Please contact your homeserver administrator.",
"Failed to join room": "Failed to join room",
+ "Font scaling": "Font scaling",
"Message Pinning": "Message Pinning",
"Custom user status messages": "Custom user status messages",
"Group & filter rooms by custom tags (refresh to apply changes)": "Group & filter rooms by custom tags (refresh to apply changes)",
@@ -407,8 +408,11 @@
"Multiple integration managers": "Multiple integration managers",
"Try out new ways to ignore people (experimental)": "Try out new ways to ignore people (experimental)",
"Support adding custom themes": "Support adding custom themes",
+ "Use IRC layout": "Use IRC layout",
"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",
+ "Font size": "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",
@@ -453,6 +457,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",
@@ -746,22 +751,26 @@
"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!",
+ "Appearance": "Appearance",
+ "Custom theme URL": "Custom theme URL",
+ "Add theme": "Add theme",
+ "Theme": "Theme",
"Flair": "Flair",
"Failed to change password. Is your password correct?": "Failed to change password. Is your password correct?",
"Success": "Success",
"Your password was successfully changed. You will not receive push notifications on other sessions until you log back in to them": "Your password was successfully changed. You will not receive push notifications on other sessions until you log back in to them",
- "Invalid theme schema.": "Invalid theme schema.",
- "Error downloading theme information.": "Error downloading theme information.",
- "Theme added!": "Theme added!",
"Profile": "Profile",
"Email addresses": "Email addresses",
"Phone numbers": "Phone numbers",
"Set a new account password...": "Set a new account password...",
"Account": "Account",
"Language and region": "Language and region",
- "Custom theme URL": "Custom theme URL",
- "Add theme": "Add theme",
- "Theme": "Theme",
"Agree to the identity server (%(serverName)s) Terms of Service to allow yourself to be discoverable by email address or phone number.": "Agree to the identity server (%(serverName)s) Terms of Service to allow yourself to be discoverable by email address or phone number.",
"Account management": "Account management",
"Deactivating your account is a permanent action - be careful!": "Deactivating your account is a permanent action - be careful!",
@@ -1113,6 +1122,7 @@
"Direct Messages": "Direct Messages",
"Start chat": "Start chat",
"Rooms": "Rooms",
+ "Create room": "Create room",
"Low priority": "Low priority",
"Historical": "Historical",
"System Alerts": "System Alerts",
@@ -1494,6 +1504,7 @@
"%(oneUser)smade no changes %(count)s times|one": "%(oneUser)smade no changes",
"Power level": "Power level",
"Custom level": "Custom level",
+ "QR Code": "QR Code",
"Unable to load event that was replied to, it either does not exist or you do not have permission to view it.": "Unable to load event that was replied to, it either does not exist or you do not have permission to view it.",
"In reply to ": "In reply to ",
"Room alias": "Room alias",
@@ -1888,6 +1899,10 @@
"Your Modular server": "Your Modular server",
"Enter the location of your Modular homeserver. It may use your own domain name or be a subdomain of modular.im.": "Enter the location of your Modular homeserver. It may use your own domain name or be a subdomain of modular.im.",
"Server Name": "Server Name",
+ "Enter password": "Enter password",
+ "Nice, strong password!": "Nice, strong password!",
+ "Password is allowed, but unsafe": "Password is allowed, but unsafe",
+ "Keep going...": "Keep going...",
"The email field must not be blank.": "The email field must not be blank.",
"The username field must not be blank.": "The username field must not be blank.",
"The phone number field must not be blank.": "The phone number field must not be blank.",
@@ -1902,10 +1917,6 @@
"Use an email address to recover your account": "Use an email address to recover your account",
"Enter email address (required on this homeserver)": "Enter email address (required on this homeserver)",
"Doesn't look like a valid email address": "Doesn't look like a valid email address",
- "Enter password": "Enter password",
- "Password is allowed, but unsafe": "Password is allowed, but unsafe",
- "Nice, strong password!": "Nice, strong password!",
- "Keep going...": "Keep going...",
"Passwords don't match": "Passwords don't match",
"Other users can invite you to rooms using your contact details": "Other users can invite you to rooms using your contact details",
"Enter phone number (required on this homeserver)": "Enter phone number (required on this homeserver)",
@@ -2199,9 +2210,9 @@
"Restore": "Restore",
"You'll need to authenticate with the server to confirm the upgrade.": "You'll need to authenticate with the server to confirm the upgrade.",
"Upgrade this session to allow it to verify other sessions, granting them access to encrypted messages and marking them as trusted for other users.": "Upgrade this session to allow it to verify other sessions, granting them access to encrypted messages and marking them as trusted for other users.",
- "Great! This recovery passphrase looks strong enough.": "Great! This recovery passphrase looks strong enough.",
"Set a recovery passphrase to secure encrypted information and recover it if you log out. This should be different to your account password:": "Set a recovery passphrase to secure encrypted information and recover it if you log out. This should be different to your account password:",
"Enter a recovery passphrase": "Enter a recovery passphrase",
+ "Great! This recovery passphrase looks strong enough.": "Great! This recovery passphrase looks strong enough.",
"Back up encrypted message keys": "Back up encrypted message keys",
"Set up with a recovery key": "Set up with a recovery key",
"That matches!": "That matches!",
@@ -2229,7 +2240,6 @@
"Unable to set up secret storage": "Unable to set up secret storage",
"We'll store an encrypted copy of your keys on our server. Secure your backup with a recovery passphrase.": "We'll store an encrypted copy of your keys on our server. Secure your backup with a recovery passphrase.",
"For maximum security, this should be different from your account password.": "For maximum security, this should be different from your account password.",
- "Enter a recovery passphrase...": "Enter a recovery passphrase...",
"Please enter your recovery passphrase a second time to confirm.": "Please enter your recovery passphrase a second time to confirm.",
"Repeat your recovery passphrase...": "Repeat your recovery passphrase...",
"Your keys are being backed up (the first backup could take a few minutes).": "Your keys are being backed up (the first backup could take a few minutes).",
@@ -2285,13 +2295,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",
diff --git a/src/i18n/strings/eo.json b/src/i18n/strings/eo.json
index 9e8641a6e9..3f749ebe0f 100644
--- a/src/i18n/strings/eo.json
+++ b/src/i18n/strings/eo.json
@@ -172,12 +172,12 @@
"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",
"New Password": "Nova pasvorto",
- "Confirm password": "Konfirmi pasvorton",
+ "Confirm password": "Konfirmu pasvorton",
"Change Password": "Ŝanĝi pasvorton",
"Authentication": "Aŭtentikigo",
"Device ID": "Aparata identigilo",
@@ -298,7 +298,7 @@
"Only people who have been invited": "Nur invititaj uzantoj",
"Anyone who knows the room's link, apart from guests": "Iu ajn kun la ligilo, krom gastoj",
"Anyone who knows the room's link, including guests": "Iu ajn kun la ligilo, inkluzive gastojn",
- "Publish this room to the public in %(domain)s's room directory?": "Ĉu publikigi ĉi tiun ĉambron al la publika ĉambrujo de %(domain)s?",
+ "Publish this room to the public in %(domain)s's room directory?": "Ĉu publikigi ĉi tiun ĉambron al la publika listo de ĉambroj de %(domain)s?",
"Who can read history?": "Kiu povas legi la historion?",
"Anyone": "Iu ajn",
"Members only (since the point in time of selecting this option)": "Nur ĉambranoj (ekde ĉi tiu elekto)",
@@ -441,7 +441,7 @@
"collapse": "maletendi",
"expand": "etendi",
"Custom level": "Propra nivelo",
- "Room directory": "Ĉambra dosierujo",
+ "Room directory": "Listo de ĉambroj",
"Username not available": "Uzantonomo ne disponeblas",
"Username invalid: %(errMessage)s": "Uzantonomo ne validas: %(errMessage)s",
"Username available": "Uzantonomo disponeblas",
@@ -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",
"": "",
- "Import E2E room keys": "Enporti ĝiscele ĉifrajn ĉambrajn ŝlosilojn",
- "Cryptography": "Kriptografio",
+ "Import E2E room keys": "Enporti tutvoje ĉifrajn ĉambrajn ŝlosilojn",
+ "Cryptography": "Ĉifroteĥnikaro",
"Analytics": "Analizo",
"Riot collects anonymous analytics to allow us to improve the application.": "Riot kolektas sennomaj analizajn datumojn por helpi plibonigadon de la programo.",
"Labs": "Eksperimentaj funkcioj",
@@ -732,7 +732,7 @@
"No update available.": "Neniuj ĝisdatigoj haveblas.",
"Resend": "Resendi",
"Collecting app version information": "Kolektante informon pri versio de la aplikaĵo",
- "Delete the room alias %(alias)s and remove %(name)s from the directory?": "Ĉu forigi la ĉambran kromnomon %(alias)s kaj forigi %(name)s de la ujo?",
+ "Delete the room alias %(alias)s and remove %(name)s from the directory?": "Ĉu forigi la ĉambran kromnomon %(alias)s kaj forigi %(name)s de la listo de ĉambroj?",
"Enable notifications for this account": "Ŝalti sciigojn por tiu ĉi konto",
"Invite to this community": "Inviti al tiu ĉi komunumo",
"Messages containing keywords": "Mesaĝoj enhavantaj ŝlosilovortojn",
@@ -981,7 +981,7 @@
"Room version": "Ĉambra versio",
"Room version:": "Ĉambra versio:",
"Developer options": "Programistaj elektebloj",
- "Room Addresses": "Ĉambra adresoj",
+ "Room Addresses": "Adresoj de ĉambro",
"Change room avatar": "Ŝanĝi profilbildon de ĉambro",
"Change room name": "Ŝanĝi nomon de ĉambro",
"Change main address for the room": "Ŝanĝi ĉefan adreson de la ĉambro",
@@ -1485,7 +1485,7 @@
"Homeserver URL does not appear to be a valid Matrix homeserver": "URL por hejmservilo ŝajne ne ligas al valida hejmservilo de Matrix",
"Invalid identity server discovery response": "Nevalida eltrova respondo de identiga servilo",
"Identity server URL does not appear to be a valid identity server": "URL por identiga servilo ŝajne ne ligas al valida identiga servilo",
- "Sign in with single sign-on": "Salutu per ununura saluto",
+ "Sign in with single sign-on": "Saluti per ununura saluto",
"Failed to re-authenticate due to a homeserver problem": "Malsukcesis reaŭtentikigi pro hejmservila problemo",
"Failed to re-authenticate": "Malsukcesis reaŭtentikigi",
"Enter your password to sign in and regain access to your account.": "Enigu vian pasvorton por saluti kaj rehavi aliron al via konto.",
@@ -2400,5 +2400,14 @@
"Opens chat with the given user": "Malfermas babilon kun la uzanto",
"Sends a message to the given user": "Sendas mesaĝon al la uzanto",
"Waiting for your other session to verify…": "Atendante kontrolon de via alia salutaĵo…",
- "You've successfully verified your device!": "Vi sukcese kontrolis vian aparaton!"
+ "You've successfully verified your device!": "Vi sukcese kontrolis vian aparaton!",
+ "To continue, use Single Sign On to prove your identity.": "Por daŭrigi, pruvu vian identecon per ununura saluto.",
+ "Confirm to continue": "Konfirmu por daŭrigi",
+ "Click the button below to confirm your identity.": "Klaku sube la butonon por konfirmi vian identecon.",
+ "Confirm encryption setup": "Konfirmi agordon de ĉifrado",
+ "Click the button below to confirm setting up encryption.": "Klaku sube la butonon por konfirmi agordon de ĉifrado.",
+ "QR Code": "Rapidresponda kodo",
+ "Dismiss read marker and jump to bottom": "Forigi legomarkon kaj iri al fundo",
+ "Jump to oldest unread message": "Iri al plej malnova nelegita mesaĝo",
+ "Upload a file": "Alŝuti dosieron"
}
diff --git a/src/i18n/strings/et.json b/src/i18n/strings/et.json
index 948055c35a..3fb069055c 100644
--- a/src/i18n/strings/et.json
+++ b/src/i18n/strings/et.json
@@ -148,7 +148,7 @@
"Remove": "Eemalda",
"You should remove your personal data from identity server before disconnecting. Unfortunately, identity server is currently offline or cannot be reached.": "Sa peaksid enne ühenduse katkestamisst eemaldama isiklikud andmed id-serverist . Kahjuks id-server ei ole hetkel võrgus või pole kättesaadav.",
"We recommend that you remove your email addresses and phone numbers from the identity server before disconnecting.": "Me soovitame, et eemaldad enne ühenduse katkestamist oma e-posti aadressi ja telefoninumbrid id-serverist.",
- "Remove messages": "Kustuta sõnumid",
+ "Remove messages": "Kustuta sõnumeid",
"Unable to remove contact information": "Kontaktiinfo eemaldamine ebaõnnestus",
"Remove %(email)s?": "Eemalda %(email)s?",
"Remove %(phone)s?": "Eemalda %(phone)s?",
@@ -262,7 +262,7 @@
"Expand room list section": "Laienda jututubade loendi valikut",
"Create Account": "Loo konto",
"Sign In": "Logi sisse",
- "Send a bug report with logs": "Saada veakirjeldus koos logidega",
+ "Send a bug report with logs": "Saada veakirjeldus koos logikirjetega",
"Group & filter rooms by custom tags (refresh to apply changes)": "Rühmita ja filtreeri jututubasid kohandatud siltide alusel (muudatuste rakendamiseks värskenda vaade)",
"Try out new ways to ignore people (experimental)": "Proovi uusi kasutajate eiramise viise (katseline)",
"Uploading report": "Laen üles veakirjeldust",
@@ -334,7 +334,7 @@
"Once enabled, encryption cannot be disabled.": "Kui krüptimine on juba kasutusele võetud, siis ei saa seda enam eemaldada.",
"Encrypted": "Krüptitud",
"Who can access this room?": "Kes pääsevad ligi siia jututuppa?",
- "Who can read history?": "Kes võib lugeda ajalugu?",
+ "Who can read history?": "Kes võivad lugeda ajalugu?",
"Encrypted by an unverified session": "Krüptitud verifitseerimata sessiooni poolt",
"Messages in this room are end-to-end encrypted. Learn more & verify this user in their user profile.": "Sõnumid selles jututoas on läbivalt krüptitud. Uuri lisaks ja verifitseeri see kasutaja tema kasutajaprofiilis.",
"Encryption not enabled": "Krüptimine ei ole kasutusel",
@@ -685,7 +685,7 @@
"Room version:": "Jututoa versioon:",
"Developer options": "Valikud arendajale",
"Open Devtools": "Ava arendusvahendid",
- "Change room name": "Muuda jututoa nimi",
+ "Change room name": "Muuda jututoa nime",
"Roles & Permissions": "Rollid ja õigused",
"Room Name": "Jututoa nimi",
"Room Topic": "Jututoa teema",
@@ -1082,5 +1082,159 @@
"Send a Direct Message": "Saada otsesõnum",
"Are you sure you want to leave the room '%(roomName)s'?": "Kas oled kindel, et soovid lahkuda jututoast '%(roomName)s'?",
"Unknown error": "Teadmata viga",
- "To continue using the %(homeserverDomain)s homeserver you must review and agree to our terms and conditions.": "Selleka et jätkata koduserveri %(homeserverDomain)s kasutamist sa pead üle vaatama ja nõustuma meie kasutamistingimustega."
+ "To continue using the %(homeserverDomain)s homeserver you must review and agree to our terms and conditions.": "Selleka et jätkata koduserveri %(homeserverDomain)s kasutamist sa pead üle vaatama ja nõustuma meie kasutamistingimustega.",
+ "Permissions": "Õigused",
+ "Select the roles required to change various parts of the room": "Vali rollid, mis on vajalikud jututoa eri osade muutmiseks",
+ "Enable encryption?": "Kas võtame krüptimise kasutusele?",
+ "Once enabled, encryption for a room cannot be disabled. Messages sent in an encrypted room cannot be seen by the server, only by the participants of the room. Enabling encryption may prevent many bots and bridges from working correctly. Learn more about encryption.": "Kui kord juba kasutusele võetud, siis krüptimist enam hiljem ära lõpetada ei saa. Krüptitud sõnumeid ei saa lugeda ei vaheapealses veebiliikluses ega serveris ja vaid jututoa liikmed saavad neid lugeda. Krüptimise kasutusele võtmine takistada nii robotite kui sõnumisildade tööd. Lisateave krüptimise kohta.",
+ "Guests cannot join this room even if explicitly invited.": "Külalised ei saa selle jututoaga liituda ka siis, kui neid on otseselt kutsutud.",
+ "Click here to fix": "Parandamiseks klõpsi siia",
+ "Server error": "Serveri viga",
+ "Command error": "Käsu viga",
+ "Server unavailable, overloaded, or something else went wrong.": "Kas server pole saadaval, on üle koormatud või midagi muud läks viltu.",
+ "Unknown Command": "Tundmatu käsk",
+ "Unrecognised command: %(commandText)s": "Tundmatu käsk: %(commandText)s",
+ "Send as message": "Saada sõnumina",
+ "Failed to connect to integration manager": "Ühendus integratsioonihalduriga ei õnnestunud",
+ "You don't currently have any stickerpacks enabled": "Sul pole ühtegi kleepsupakki kasutusel",
+ "Add some now": "Lisa nüüd mõned",
+ "Stickerpack": "Kleepsupakk",
+ "Hide Stickers": "Peida kleepsud",
+ "Show Stickers": "Näita kleepse",
+ "Failed to revoke invite": "Kutse tühistamine ei õnnestunud",
+ "Could not revoke the invite. The server may be experiencing a temporary problem or you do not have sufficient permissions to revoke the invite.": "Kutse tühistamine ei õnnestunud. Serveri töös võib olla ajutine tõrge või sul pole piisavalt õigusi kutse tühistamiseks.",
+ "Revoke invite": "Tühista kutse",
+ "Invited by %(sender)s": "Kutsutud %(sender)s poolt",
+ "Jump to first unread message.": "Mine esimese lugemata sõnumi juurde.",
+ "Mark all as read": "Märgi kõik loetuks",
+ "Error updating main address": "Viga põhiaadressi uuendamisel",
+ "There was an error updating the room's main address. It may not be allowed by the server or a temporary failure occurred.": "Jututoa põhiaadressi uuendamisel tekkis viga. See kas pole serveris lubatud või tekkis mingi ajutine viga.",
+ "There was an error updating the room's alternative addresses. It may not be allowed by the server or a temporary failure occurred.": "Jututoa lisaaadressi uuendamisel tekkis viga. See kas pole serveris lubatud või tekkis mingi ajutine viga.",
+ "Error creating alias": "Viga aliase loomisel",
+ "There was an error creating that alias. It may not be allowed by the server or a temporary failure occurred.": "Aliase loomisel tekkis viga. See kas pole serveris lubatud või tekkis mingi ajutine viga.",
+ "You don't have permission to delete the alias.": "Sul pole õigusi aliase kustutamiseks.",
+ "There was an error removing that alias. It may no longer exist or a temporary error occurred.": "Selle aliase eemaldamisel tekkis viga. Teda kas pole enam olemas või tekkis mingi ajutine viga.",
+ "Error removing alias": "Viga aliase eemaldamisel",
+ "Main address": "Põhiaadress",
+ "not specified": "määratlemata",
+ "Rejecting invite …": "Hülgan kutset …",
+ "Join the conversation with an account": "Liitu vestlusega kasutades oma kontot",
+ "Sign Up": "Registreeru",
+ "Loading room preview": "Laen jututoa eelvaadet",
+ "You were kicked from %(roomName)s by %(memberName)s": "%(memberName)s müksas sind välja jututoast %(roomName)s",
+ "Reason: %(reason)s": "Põhjus: %(reason)s",
+ "Forget this room": "Unusta see jututuba",
+ "Re-join": "Liitu uuesti",
+ "You were banned from %(roomName)s by %(memberName)s": "%(memberName)s keelas sulle ligipääsu jututuppa %(roomName)s",
+ "Something went wrong with your invite to %(roomName)s": "Midagi läks viltu sinu kutsega %(roomName)s jututuppa",
+ "An error (%(errcode)s) was returned while trying to validate your invite. You could try to pass this information on to a room admin.": "Sinu kutse kontrollimisel tekkis viga (%(errcode)s). Kui võimalik, siis proovi see info edastada jututoa haldurile.",
+ "unknown error code": "tundmatu veakood",
+ "You can only join it with a working invite.": "Sa võid liituda vaid toimiva kutse alusel.",
+ "Try to join anyway": "Proovi siiski liituda",
+ "You can still join it because this is a public room.": "Kuna tegemist on avaliku jututoaga, siis võid ikkagi liituda.",
+ "Join the discussion": "Liitu vestlusega",
+ "This invite to %(roomName)s was sent to %(email)s which is not associated with your account": "See kutse jututuppa %(roomName)s saadeti e-posti aadressile %(email)s, mis ei ole seotud sinu kontoga",
+ "Link this email with your account in Settings to receive invites directly in Riot.": "Selleks et saada kutseid otse Riot'isse, seosta see e-posti aadress seadete all oma kontoga.",
+ "This invite to %(roomName)s was sent to %(email)s": "Kutse %(roomName)s jututuppa saadeti %(email)s e-posti aadressile",
+ "Use an identity server in Settings to receive invites directly in Riot.": "Selleks et saada kutseid otse Riot'isse peab seadistustes olema määratud isikutuvastusserver.",
+ "Share this email in Settings to receive invites directly in Riot.": "Selleks, et saada kutseid otse Riot'isse, jaga oma seadetes seda e-posti aadressi.",
+ "Start chatting": "Alusta vestlust",
+ "Do you want to join %(roomName)s?": "Kas sa soovid liitud jututoaga %(roomName)s?",
+ " invited you": " kutsus sind",
+ "Reject": "Hülga",
+ "You're previewing %(roomName)s. Want to join it?": "Sa vaatad jututoa %(roomName)s eelvaadet. Kas soovid sellega liituda?",
+ "%(roomName)s can't be previewed. Do you want to join it?": "Jututoal %(roomName)s puudub eelvaate võimalus. Kas sa soovid sellega liituda?",
+ "%(roomName)s does not exist.": "Jututuba %(roomName)s ei ole olemas.",
+ "This room doesn't exist. Are you sure you're at the right place?": "Seda jututuba ei ole olemas. Kas sa oled kindlasti õiges kohas?",
+ "%(roomName)s is not accessible at this time.": "Jututuba %(roomName)s ei ole parasjagu kättesaadav.",
+ "Try again later, or ask a room admin to check if you have access.": "Proovi hiljem uuesti või küsi jututoa haldurilt, kas sul on ligipääs olemas.",
+ "%(errcode)s was returned while trying to access the room. If you think you're seeing this message in error, please submit a bug report.": "Astumisel jututuppa tekkis viga %(errcode)s. Kui sa arvad, et sellise põhjusega viga ei tohiks tekkida, siis palun koosta veateade.",
+ "Never lose encrypted messages": "Ära kunagi kaota krüptitud sõnumeid",
+ "Messages in this room are secured with end-to-end encryption. Only you and the recipient(s) have the keys to read these messages.": "Sõnumid siis jututoas kasutavad läbivat krüptimist. Ainult sinul ja saaja(te)l on võtmed selliste sõnumite lugemiseks.",
+ "Securely back up your keys to avoid losing them. Learn more.": "Vältimaks nende kaotamist, varunda turvaliselt oma võtmed. Loe lisateavet.",
+ "Not now": "Mitte praegu",
+ "Don't ask me again": "Ära küsi minult uuesti",
+ "%(count)s unread messages including mentions.|other": "%(count)s lugemata sõnumit kaasa arvatud mainimised.",
+ "%(count)s unread messages.|other": "%(count)s lugemata teadet.",
+ "%(count)s unread messages.|one": "1 lugemata teade.",
+ "Unread mentions.": "Lugemata mainimised.",
+ "Unread messages.": "Lugemata sõnumid.",
+ "Add a topic": "Lisa teema",
+ "Upgrading this room will shut down the current instance of the room and create an upgraded room with the same name.": "Selle jututoa versiooni uuendamine sulgeb tema praeguse instantsi ja loob sama nimega uuendatud jututoa.",
+ "This room has already been upgraded.": "See jututuba on juba uuendatud.",
+ "This room is running room version , which this homeserver has marked as unstable.": "Selle jututoa versioon on ning see koduserver on tema märkinud ebastabiilseks.",
+ "Only room administrators will see this warning": "Vaid administraatorid näevad seda hoiatust",
+ "You can use /help
to list available commands. Did you mean to send this as a message?": "Kirjutades /help
saad vaadata käskude loendit. Või soovisid seda saata sõnumina?",
+ "Hint: Begin your message with //
to start it with a slash.": "Vihje: kui soovid alustada sõnumit kaldkriipsuga, siis kirjuta //
.",
+ "To link to this room, please add an alias.": "Viitamaks sellele jututoale, palun määra talle alias.",
+ "Only people who have been invited": "Vaid kutsutud kasutajad",
+ "Anyone who knows the room's link, apart from guests": "Kõik, kes teavad jututoa viidet, välja arvatud külalised",
+ "Anyone who knows the room's link, including guests": "Kõik, kes teavad jututoa viidet, kaasa arvatud külalised",
+ "Changes to who can read history will only apply to future messages in this room. The visibility of existing history will be unchanged.": "Kui muudad seda, kes saavad selle jututoa ajalugu lugeda, siis kehtib see vaid tulevaste sõnumite kohta. Senise ajaloo nähtavus sellega ei muutu.",
+ "Unable to revoke sharing for email address": "Ei õnnestu tagasi võtta otsust e-posti aadressi jagamise kohta",
+ "Unable to share email address": "Ei õnnestu jagada e-posti aadressi",
+ "Your email address hasn't been verified yet": "Sinu e-posti aadress pole veel verifitseeritud",
+ "Click the link in the email you received to verify and then click continue again.": "Klõpsi saabunud e-kirjas olevat verifitseerimisviidet ning seejärel klõpsi siin uuesti nuppu \"Jätka\".",
+ "Unable to verify email address.": "E-posti aadressi verifitseerimine ei õnnestunud.",
+ "Verify the link in your inbox": "Verifitseeri klõpsides viidet saabunud e-kirjas",
+ "Complete": "Valmis",
+ "Revoke": "Tühista",
+ "Share": "Jaga",
+ "Session already verified!": "Sessioon on juba verifitseeritud!",
+ "WARNING: Session already verified, but keys do NOT MATCH!": "HOIATUS: Sessioon on juba verifitseeritud, aga võtmed ei klapi!",
+ "WARNING: KEY VERIFICATION FAILED! The signing key for %(userId)s and session %(deviceId)s is \"%(fprint)s\" which does not match the provided key \"%(fingerprint)s\". This could mean your communications are being intercepted!": "HOIATUS: VÕTMETE VERIFITSEERIMINE EI ÕNNESTUNUD! Kasutaja %(userId)s ja sessiooni %(deviceId)s allkirjastamise võti on \"%(fprint)s\", aga see ei vasta antud sõrmejäljele \"%(fingerprint)s\". See võib tähendada, et sinu kasutatavad ühendused võivad olla kolmanda osapoole poolt vahelt lõigatud!",
+ "Verified key": "Verifitseeritud võti",
+ "The signing key you provided matches the signing key you received from %(userId)s's session %(deviceId)s. Session marked as verified.": "Sinu antud allkirjavõti vastab allkirjavõtmele, mille sa said kasutaja %(userId)s sessioonist %(deviceId)s. Sessioon on märgitud verifitseerituks.",
+ "Sends the given message coloured as a rainbow": "Saadab selle sõnumi vikerkaarevärvilisena",
+ "Sends the given emote coloured as a rainbow": "Saadab antud emote vikerkaarevärvides",
+ "Displays list of commands with usages and descriptions": "Näitab käskude loendit koos kirjeldustega",
+ "Logs sent": "Logikirjed saadetud",
+ "Thank you!": "Suur tänu!",
+ "Opens chat with the given user": "Avab vestluse näidatud kasutajaga",
+ "Sends a message to the given user": "Saadab sõnumi näidatud kasutajale",
+ "Short keyboard patterns are easy to guess": "Lühikesi klahvijärjestusi on lihtne ära arvata",
+ "Keyboard Shortcuts": "Kiirklahvid",
+ "This room is bridging messages to the following platforms. Learn more.": "See jututuba kasutab sõnumisildasid liidestamiseks järgmiste süsteemidega. Lisateave.",
+ "This room isn’t bridging messages to any platforms. Learn more.": "See jututuba ei kasuta sõnumisildasid liidestamiseks muude süsteemidega. Lisateave.",
+ "Bridges": "Sõnumisillad",
+ "Room Addresses": "Jututubade aadressid",
+ "Browse": "Sirvi",
+ "Change room avatar": "Muuda jututoa profiilipilti ehk avatari",
+ "Change main address for the room": "Muuda jututoa põhiaadressi",
+ "Change history visibility": "Muuda vestlusajaloo nähtavust",
+ "Change permissions": "Muuda õigusi",
+ "Change topic": "Muuda teemat",
+ "Upgrade the room": "Uuenda jututuba uue versioonini",
+ "Enable room encryption": "Võta jututoas kasutusele krüptimine",
+ "Modify widgets": "Muuda vidinaid",
+ "Default role": "Vaikimisi roll",
+ "Send messages": "Saada sõnumeid",
+ "Invite users": "Kutsu kasutajaid",
+ "Change settings": "Muuda seadistusi",
+ "Kick users": "Müksa kasutajaid välja",
+ "Ban users": "Määra kasutajatele suhtluskeeld",
+ "Notify everyone": "Teavita kõiki",
+ "No users have specific privileges in this room": "Mitte ühelgi kasutajal pole siin jututoas eelisõigusi",
+ "Privileged Users": "Eelisõigustega kasutajad",
+ "Banned users": "Suhtluskeelu saanud kasutajad",
+ "Send %(eventType)s events": "Saada %(eventType)s-sündmusi",
+ "Unable to revoke sharing for phone number": "Telefoninumbri jagamist ei õnnestunud tühistada",
+ "Unable to share phone number": "Telefoninumbri jagamine ei õnnestunud",
+ "Unable to verify phone number.": "Telefoninumbri verifitseerimine ei õnnestunud.",
+ "Incorrect verification code": "Vigane verifikatsioonikood",
+ "Please enter verification code sent via text.": "Palun sisesta verifikatsioonikood, mille said telefoni tekstisõnumina.",
+ "Verification code": "Verifikatsioonikood",
+ "Invalid Email Address": "Vigane e-posti aadress",
+ "This doesn't appear to be a valid email address": "See ei tundu olema e-posti aadressi moodi",
+ "Preparing to send logs": "Valmistun logikirjete saatmiseks",
+ "Failed to send logs: ": "Logikirjete saatmine ei õnnestunud: ",
+ "Verify session": "Verifitseeri sessioon",
+ "Use Legacy Verification (for older clients)": "Kasuta vanematüübilist verifitseerimist (vähem-moodsa klient-tarkvara jaoks)",
+ "Verify by comparing a short text string.": "Verifitseeri kasutades lühikeste sõnede võrdlemist.",
+ "Begin Verifying": "Alusta verifitseerimist",
+ "Waiting for partner to accept...": "Ootan, et teine osapool nõustuks…",
+ "Nothing appearing? Not all clients support interactive verification yet. .": "Mitte midagi ei kuvata? Kõik Matrix'i kliendid ei toeta veel interaktiivset verifitseerimist. .",
+ "Waiting for %(userId)s to confirm...": "Ootan kinnitust kasutajalt %(userId)s…",
+ "Skip": "Jäta vahele",
+ "Token incorrect": "Vigane tunnusluba"
}
diff --git a/src/i18n/strings/fi.json b/src/i18n/strings/fi.json
index e8eef891be..ae08572eb2 100644
--- a/src/i18n/strings/fi.json
+++ b/src/i18n/strings/fi.json
@@ -1282,7 +1282,7 @@
"Premium hosting for organisations Learn more": "Premium-ylläpitoa organisaatioille. Lue lisää",
"Other": "Muut",
"Find other public servers or use a custom server": "Etsi muita julkisia palvelimia tai käytä mukautettua palvelinta",
- "Please install Chrome, Firefox, or Safari for the best experience.": "Parhaan käyttökokemuksen saa Chromella, Firefoxilla tai Safarilla.",
+ "Please install Chrome, Firefox, or Safari for the best experience.": "Asenna Chrome, Firefox tai Safari, jotta kaikki toimii parhaiten.",
"HTML for your community's page
\n\n Use the long description to introduce new members to the community, or distribute\n some important links\n
\n\n You can even use 'img' tags\n
\n": "HTML-kuvaus yhteisösi etusivulle
\n\n Käytä pitkää kuvausta esitelläksesi yhteisöäsi uusille jäsenille tai jakaaksesi tärkeitä\n linkkejä\n
\n\n Voit jopa käyttää 'img'-tageja\n
\n",
"Unable to join community": "Yhteisöön liittyminen epäonnistui",
"You are an administrator of this community. You will not be able to rejoin without an invite from another administrator.": "Olet tämän yhteisön ylläpitäjä. Et voi liittyä uudelleen ilman kutsua toiselta ylläpitäjältä.",
@@ -2167,5 +2167,27 @@
"Sends a message as html, without interpreting it as markdown": "Lähettää viestin HTML-muodossa, tulkitsematta sitä Markdowniksi",
"Please supply a widget URL or embed code": "Anna sovelman osoite tai upotettava koodinpätkä",
"You signed in to a new session without verifying it:": "Olet kirjautunut uuteen istuntoon varmentamatta sitä:",
- "Verify your other session using one of the options below.": "Varmenna toinen istuntosi käyttämällä yhtä seuraavista tavoista."
+ "Verify your other session using one of the options below.": "Varmenna toinen istuntosi käyttämällä yhtä seuraavista tavoista.",
+ "Click the button below to confirm deleting these sessions.|other": "Napsauta alla olevaa painiketta vahvistaaksesi näiden istuntojen poistamisen.",
+ "Click the button below to confirm deleting these sessions.|one": "Napsauta alla olevaa painiketta vahvistaaksesi tämän istunnon poistamisen.",
+ "Backup has a signature from unknown session with ID %(deviceId)s": "Varmuuskopiossa on allekirjoitus tuntemattomasta istunnosta tunnuksella %(deviceId)s",
+ "Error downloading theme information.": "Virhe ladattaessa teematietoa.",
+ "Waiting for you to accept on your other session…": "Odotetaan, että hyväksyt toisen istunnon…",
+ "Almost there! Is your other session showing the same shield?": "Melkein valmista! Näyttääkö toinen istuntosi saman kilven?",
+ "Almost there! Is %(displayName)s showing the same shield?": "Melkein valmista! Näyttääkö %(displayName)s saman kilven?",
+ "Message deleted": "Viesti poistettu",
+ "Message deleted by %(name)s": "%(name)s poisti viestin",
+ "QR Code": "QR-koodi",
+ "To continue, use Single Sign On to prove your identity.": "Todista henkilöllisyytesi kertakirjautumisen avulla jatkaaksesi.",
+ "If they don't match, the security of your communication may be compromised.": "Jos ne eivät täsmää, viestinnän turvallisuus saattaa olla vaarantunut.",
+ "This session, or the other session": "Tämä tai toinen istunto",
+ "We recommend you change your password and recovery key in Settings immediately": "Suosittelemme, että vaihdat salasanasi ja palautusavaimesi asetuksissa välittömästi",
+ "Restoring keys from backup": "Palautetaan avaimia varmuuskopiosta",
+ "Fetching keys from server...": "Noudetaan avaimia palvelimelta...",
+ "%(completed)s of %(total)s keys restored": "%(completed)s / %(total)s avainta palautettu",
+ "Keys restored": "Avaimet palautettu",
+ "Successfully restored %(sessionCount)s keys": "%(sessionCount)s avaimen palautus onnistui",
+ "This requires the latest Riot on your other devices:": "Tämä vaatii uusimman Riotin muilla laitteillasi:",
+ "Currently indexing: %(currentRoom)s": "Indeksoidaan huonetta: %(currentRoom)s",
+ "Jump to oldest unread message": "Siirry vanhimpaan lukemattomaan viestiin"
}
diff --git a/src/i18n/strings/fr.json b/src/i18n/strings/fr.json
index 3fac2168a2..c231769f27 100644
--- a/src/i18n/strings/fr.json
+++ b/src/i18n/strings/fr.json
@@ -2431,5 +2431,9 @@
"Confirm to continue": "Confirmer pour continuer",
"Click the button below to confirm your identity.": "Cliquez sur le bouton ci-dessous pour confirmer votre identité.",
"Confirm encryption setup": "Confirmer la configuration du chiffrement",
- "Click the button below to confirm setting up encryption.": "Cliquez sur le bouton ci-dessous pour confirmer la configuration du chiffrement."
+ "Click the button below to confirm setting up encryption.": "Cliquez sur le bouton ci-dessous pour confirmer la configuration du chiffrement.",
+ "QR Code": "Code QR",
+ "Dismiss read marker and jump to bottom": "Ignorer le signet de lecture et aller en bas",
+ "Jump to oldest unread message": "Aller au plus vieux message non lu",
+ "Upload a file": "Envoyer un fichier"
}
diff --git a/src/i18n/strings/gl.json b/src/i18n/strings/gl.json
index 346dda09f2..3328292be0 100644
--- a/src/i18n/strings/gl.json
+++ b/src/i18n/strings/gl.json
@@ -698,9 +698,9 @@
"Failed to remove tag %(tagName)s from room": "Fallo ao eliminar a etiqueta %(tagName)s da sala",
"Failed to add tag %(tagName)s to room": "Fallo ao engadir a etiqueta %(tagName)s a sala",
"Key request sent.": "Petición de chave enviada.",
- "Flair": "Aura",
- "Showing flair for these communities:": "Mostrar a aura para estas comunidades:",
- "Display your community flair in rooms configured to show it.": "Mostrar a aura da súa comunidade nas salas configuradas para que a mostren.",
+ "Flair": "Popularidade",
+ "Showing flair for these communities:": "Mostrar a popularidade destas comunidades:",
+ "Display your community flair in rooms configured to show it.": "Mostrar a popularidade da túa comunidade nas salas configuradas para que a mostren.",
"Did you know: you can use communities to filter your Riot.im experience!": "Sabía que pode utilizar as comunidades para mellorar a súa experiencia con Riot.im!",
"To set up a filter, drag a community avatar over to the filter panel on the far left hand side of the screen. You can click on an avatar in the filter panel at any time to see only the rooms and people associated with that community.": "Para establecer un filtro, arrastre un avatar da comunidade sobre o panel de filtros na parte esquerda da pantalla. Pode pulsar nun avatar no panel de filtrado en calquera momento para ver só salas e xente asociada a esa comunidade.",
"Deops user with given id": "Degradar o usuario con esa ID",
@@ -822,7 +822,7 @@
"Debug logs contain application usage data including your username, the IDs or aliases of the rooms or groups you have visited and the usernames of other users. They do not contain messages.": "Os informes de depuración conteñen datos de utilización do aplicativo como o seu nome de usuario, os IDs ou alcumes de salas e grupos que vostede visitou e os nomes de usuarios doutras usuarias. Non conteñen mensaxes.",
"Unhide Preview": "Desagochar a vista previa",
"Unable to join network": "Non se puido conectar a rede",
- "You might have configured them in a client other than Riot. You cannot tune them in Riot but they still apply": "Pode que os configurase nun cliente diferente de Riot. Non pode establecelos desde Riot pero aínda así aplicaranse",
+ "You might have configured them in a client other than Riot. You cannot tune them in Riot but they still apply": "Pode que os configurases nun cliente diferente de Riot. Non podes establecelos desde Riot pero aínda así aplicaranse",
"Sorry, your browser is not able to run Riot.": "Desculpe, o seu navegador non pode executar Riot.",
"Uploaded on %(date)s by %(user)s": "Subido a %(date)s por %(user)s",
"Messages in group chats": "Mensaxes en grupos de chat",
@@ -919,5 +919,23 @@
"Your message wasn't sent because this homeserver has hit its Monthly Active User Limit. Please contact your service administrator to continue using the service.": "A súa mensaxe non foi enviada porque este servidor acadou o Límite Mensual de Usuaria Activa. Por favor contacte coa administración do servizo para continuar utilizando o servizo.",
"Your message wasn't sent because this homeserver has exceeded a resource limit. Please contact your service administrator to continue using the service.": "A súa mensaxe non foi enviada porque o servidor superou o límite de recursos. Por favor contacte coa administración do servizo para continuar utilizando o servizo.",
"Legal": "Legal",
- "Please contact your service administrator to continue using this service.": "Por favor contacte coa administración do servizo para continuar utilizando o servizo."
+ "Please contact your service administrator to continue using this service.": "Por favor contacte coa administración do servizo para continuar utilizando o servizo.",
+ "Use Single Sign On to continue": "Usar Single Sign On para continuar",
+ "Confirm adding this email address by using Single Sign On to prove your identity.": "Confirma que queres engadir este email usando Single Sign On como proba de identidade.",
+ "Single Sign On": "Single Sign On",
+ "Confirm adding email": "Confirma novo email",
+ "Click the button below to confirm adding this email address.": "Preme no botón inferior para confirmar que queres engadir o email.",
+ "Confirm": "Confirmar",
+ "Add Email Address": "Engadir email",
+ "Confirm adding this phone number by using Single Sign On to prove your identity.": "Confirma que queres engadir este teléfono usando Single Sign On como proba de identidade.",
+ "Confirm adding phone number": "Confirma a adición do teléfono",
+ "Click the button below to confirm adding this phone number.": "Preme no botón inferior para confirmar que engades este número.",
+ "Add Phone Number": "Engadir novo Número",
+ "The version of Riot": "A versión de Riot",
+ "Whether or not you're logged in (we don't record your username)": "Se estás conectada ou non (non rexistramos o teu nome de usuaria)",
+ "Whether you're using Riot on a device where touch is the primary input mechanism": "Se estás conectada utilizando Riot nun dispositivo maiormente táctil",
+ "Whether you're using Riot as an installed Progressive Web App": "Se estás a usar Riot como unha Progressive Web App instalada",
+ "Your user agent": "User Agent do navegador",
+ "The information being sent to us to help make Riot better includes:": "Información que nos envías para mellorar Riot inclúe:",
+ "Please install Chrome, Firefox, or Safari for the best experience.": "Instala Chrome, Firefox, ou Safari para ter unha mellor experiencia."
}
diff --git a/src/i18n/strings/hu.json b/src/i18n/strings/hu.json
index afad390192..17254a77db 100644
--- a/src/i18n/strings/hu.json
+++ b/src/i18n/strings/hu.json
@@ -2409,5 +2409,20 @@
"Successfully restored %(sessionCount)s keys": "Kulcsok (%(sessionCount)s) sikeresen visszaállítva",
"You signed in to a new session without verifying it:": "Ellenőrzés nélkül jelentkeztél be egy új munkamenetbe:",
"Verify your other session using one of the options below.": "Ellenőrizd a másik munkameneted a lenti lehetőségek egyikével.",
- "Invite someone using their name, username (like ), email address or share this room.": "Hívj meg valakit a nevével, felhasználónevével (mint ), e-mail címével vagy oszd meg ezt a szobát."
+ "Invite someone using their name, username (like ), email address or share this room.": "Hívj meg valakit a nevével, felhasználónevével (mint ), e-mail címével vagy oszd meg ezt a szobát.",
+ "Opens chat with the given user": "Beszélgetés megnyitása a megadott felhasználóval",
+ "Sends a message to the given user": "Üzenet küldése a megadott felhasználónak",
+ "Waiting for your other session to verify…": "A másik munkameneted ellenőrzésére várunk…",
+ "You've successfully verified your device!": "Sikeresen ellenőrizted az eszközödet!",
+ "Message deleted": "Üzenet törölve",
+ "Message deleted by %(name)s": "Üzenetet törölte: %(name)s",
+ "QR Code": "QR kód",
+ "To continue, use Single Sign On to prove your identity.": "A folytatáshoz a személyazonosságod megerősítéséhez használd az egyszeri bejelentkezést.",
+ "Confirm to continue": "Erősítsd meg a továbblépéshez",
+ "Click the button below to confirm your identity.": "A személyazonosságod megerősítéséhez kattints az alábbi gombra.",
+ "Confirm encryption setup": "Erősítsd meg a titkosítási beállításokat",
+ "Click the button below to confirm setting up encryption.": "Az alábbi gomb megnyomásával erősítsd meg, hogy megadod a titkosítási beállításokat.",
+ "Dismiss read marker and jump to bottom": "Az olvasottak jel eltűntetése és ugrás a végére",
+ "Jump to oldest unread message": "A legrégebbi olvasatlan üzenetre ugrás",
+ "Upload a file": "Fájl feltöltése"
}
diff --git a/src/i18n/strings/it.json b/src/i18n/strings/it.json
index e79db1b061..014d6015b3 100644
--- a/src/i18n/strings/it.json
+++ b/src/i18n/strings/it.json
@@ -2426,5 +2426,9 @@
"Confirm to continue": "Conferma per continuare",
"Click the button below to confirm your identity.": "Clicca il pulsante sotto per confermare la tua identità.",
"Confirm encryption setup": "Conferma impostazione cifratura",
- "Click the button below to confirm setting up encryption.": "Clicca il pulsante sotto per confermare l'impostazione della cifratura."
+ "Click the button below to confirm setting up encryption.": "Clicca il pulsante sotto per confermare l'impostazione della cifratura.",
+ "QR Code": "Codice QR",
+ "Dismiss read marker and jump to bottom": "Scarta il segno di lettura e salta alla fine",
+ "Jump to oldest unread message": "Salta al messaggio non letto più vecchio",
+ "Upload a file": "Invia un file"
}
diff --git a/src/i18n/strings/sk.json b/src/i18n/strings/sk.json
index fbecaa4845..e85732ed82 100644
--- a/src/i18n/strings/sk.json
+++ b/src/i18n/strings/sk.json
@@ -628,7 +628,7 @@
"Export room keys": "Exportovať kľúče miestností",
"This process allows you to export the keys for messages you have received in encrypted rooms to a local file. You will then be able to import the file into another Matrix client in the future, so that client will also be able to decrypt these messages.": "Tento proces vás prevedie exportom kľúčov určených na dešifrovanie správ, ktoré ste dostali v šifrovaných miestnostiach do lokálneho súboru. Tieto kľúče zo súboru môžete neskôr importovať do iného Matrix klienta, aby ste v ňom mohli dešifrovať vaše šifrované správy.",
"The exported file will allow anyone who can read it to decrypt any encrypted messages that you can see, so you should be careful to keep it secure. To help with this, you should enter a passphrase below, which will be used to encrypt the exported data. It will only be possible to import the data by using the same passphrase.": "Tento súbor umožní komukoľvek, k to má ku nemu prístup dešifrovať všetky vami viditeľné šifrované správy, mali by ste teda byť opatrní a tento súbor si bezpečne uchovať. Aby bolo toto pre vás jednoduchšie, nižšie zadajte heslo, ktorým budú údaje v súbore zašifrované. Importovať údaje zo súboru bude možné len po zadaní tohoto istého hesla.",
- "Enter passphrase": "Zadajte heslo",
+ "Enter passphrase": "Zadajte (dlhé) heslo",
"Confirm passphrase": "Potvrďte heslo",
"Export": "Exportovať",
"Import room keys": "Importovať kľúče miestností",
@@ -1519,5 +1519,17 @@
"Whether you're using Riot on a device where touch is the primary input mechanism": "Či používate Riot na zariadení, ktorého hlavným vstupným mechanizmom je dotyk (mobil, tablet,...)",
"Whether you're using Riot as an installed Progressive Web App": "Či používate Riot ako nainštalovanú Progresívnu Webovú Aplikáciu",
"Your user agent": "Identifikátor vášho prehliadača",
- "The information being sent to us to help make Riot better includes:": "Informácie, ktoré nám posielate, aby sme zlepšili Riot, zahŕňajú:"
+ "The information being sent to us to help make Riot better includes:": "Informácie, ktoré nám posielate, aby sme zlepšili Riot, zahŕňajú:",
+ "There are unknown sessions in this room: if you proceed without verifying them, it will be possible for someone to eavesdrop on your call.": "V miestnosti je neznáma relácia: pokiaľ budete pokračovať bez jej overenia, bude schopná odpočúvať váš hovor.",
+ "Review Sessions": "Overiť reláciu",
+ "If you cancel now, you won't complete verifying the other user.": "Pokiaľ teraz proces zrušíte, nedokončíte overenie druhého používateľa.",
+ "If you cancel now, you won't complete verifying your other session.": "Pokiaľ teraz proces zrušíte, nedokončíte overenie vašej druhej relácie.",
+ "If you cancel now, you won't complete your operation.": "Pokiaľ teraz proces zrušíte, nedokončíte ho.",
+ "Cancel entering passphrase?": "Zrušiť zadávanie (dlhého) hesla.",
+ "Setting up keys": "Príprava kľúčov",
+ "Verify this session": "Overiť túto reláciu",
+ "Keep recovery passphrase in memory for this session": "Ponechať (dlhé) heslo pre obnovu zálohy v pamäti pre túto reláciu",
+ "Enter recovery passphrase": "Zadajte (dlhé) heslo pre obnovu zálohy",
+ "Unable to access secret storage. Please verify that you entered the correct recovery passphrase.": "Nemožno sa dostať do tajného úložiska. Prosím, overte, že ste zadali správne (dlhé) heslo pre obnovu zálohy.",
+ "Access your secure message history and your cross-signing identity for verifying other sessions by entering your recovery passphrase.": "Získajte prístup k vašej zabezpečenej histórií správ a vašemu krížom-podpísanej identite na potvrdenie iných relácií zadaním vášho (dlhého) hesla na obnovu zálohy."
}
diff --git a/src/i18n/strings/sq.json b/src/i18n/strings/sq.json
index ee2781f445..7058ad67b0 100644
--- a/src/i18n/strings/sq.json
+++ b/src/i18n/strings/sq.json
@@ -2408,5 +2408,21 @@
"or another cross-signing capable Matrix client": "ose një tjetër klient Matrix i aftë për cross-signing), email address or share this room.": "Ftoni dikë duke përdorur emrin e tij, emrin e përdoruesit (bie fjala, ), adresën email ose duke ndarë me të këtë dhomë.",
+ "Confirm encryption setup": "Ripohoni ujdisje fshehtëzimi",
+ "Click the button below to confirm setting up encryption.": "Klikoni mbi butonin më poshtë që të ripohoni ujdisjen e fshehtëzimit.",
+ "Dismiss read marker and jump to bottom": "Mos merr parasysh piketë leximi dhe hidhu te fundi",
+ "Jump to oldest unread message": "Hidhu te mesazhi më i vjetër i palexuar",
+ "Upload a file": "Ngarkoni një kartelë"
}
diff --git a/src/i18n/strings/zh_Hans.json b/src/i18n/strings/zh_Hans.json
index dc3cc6d176..481167a645 100644
--- a/src/i18n/strings/zh_Hans.json
+++ b/src/i18n/strings/zh_Hans.json
@@ -1468,5 +1468,31 @@
"%(senderName)s placed a video call. (not supported by this browser)": "%(senderName)s 发起了视频通话。(此浏览器不支持)",
"%(senderName)s removed the rule banning users matching %(glob)s": "%(senderName)s 移除了禁止匹配 %(glob)s 的用户的规则",
"%(senderName)s removed the rule banning servers matching %(glob)s": "%(senderName)s 移除了禁止匹配 %(glob)s 的服务器的规则",
- "%(senderName)s removed a ban rule matching %(glob)s": "%(senderName)s 移除了禁止匹配 %(glob)s 的规则"
+ "%(senderName)s removed a ban rule matching %(glob)s": "%(senderName)s 移除了禁止匹配 %(glob)s 的规则",
+ "%(senderName)s removed the rule banning rooms matching %(glob)s": "%(senderName)s 删除了禁止聊天室匹配%(glob)s的规则",
+ "%(senderName)s updated an invalid ban rule": "%(senderName)s 更新了一个无效的禁止规则",
+ "%(senderName)s updated the rule banning users matching %(glob)s for %(reason)s": "%(senderName)s 更新了由于%(reason)s 而禁止用户匹配%(glob)s的规则",
+ "%(senderName)s updated the rule banning rooms matching %(glob)s for %(reason)s": "%(senderName)s 更新了由于%(reason)s而禁止聊天室匹配%(glob)s的规则",
+ "%(senderName)s updated the rule banning servers matching %(glob)s for %(reason)s": "%(senderName)s 更新了由于%(reason)s而禁止服务器匹配%(glob)s的规则",
+ "%(senderName)s updated a ban rule matching %(glob)s for %(reason)s": "%(senderName)s 更新了由于%(reason)s而禁止匹配%(glob)s的规则",
+ "%(senderName)s created a rule banning users matching %(glob)s for %(reason)s": "%(senderName)s 创建了因为%(reason)s而禁止用户匹配%(glob)s的规则",
+ "%(senderName)s created a rule banning rooms matching %(glob)s for %(reason)s": "%(senderName)s 创建了由于%(reason)s而禁止聊天室匹配%(glob)s的规则",
+ "%(senderName)s created a rule banning servers matching %(glob)s for %(reason)s": "%(senderName)s 创建了由于%(reason)s而禁止服务器匹配%(glob)s的规则",
+ "%(senderName)s created a ban rule matching %(glob)s for %(reason)s": "%(senderName)s 创建了由于%(reason)s而禁止匹配%(glob)s的股则",
+ "%(senderName)s changed a rule that was banning users matching %(oldGlob)s to matching %(newGlob)s for %(reason)s": "%(senderName)s 更改了一个由于%(reason)s而禁止用户%(oldGlob)s跟%(newGlob)s匹配的规则",
+ "%(senderName)s changed a rule that was banning rooms matching %(oldGlob)s to matching %(newGlob)s for %(reason)s": "%(senderName)s更改了一个由于%(reason)s而禁止聊天室%(oldGlob)s跟%(newGlob)s匹配的规则",
+ "%(senderName)s changed a rule that was banning servers matching %(oldGlob)s to matching %(newGlob)s for %(reason)s": "%(senderName)s 更新了一个由于%(reason)s而禁止服务器%(oldGlob)s跟%(newGlob)s匹配的规则",
+ "%(senderName)s updated a ban rule that was matching %(oldGlob)s to matching %(newGlob)s for %(reason)s": "%(senderName)s 更新了一个由于%(reason)s而禁止%(oldGlob)s跟%(newGlob)s匹配的规则",
+ "You signed in to a new session without verifying it:": "您登陆了未经过验证的新会话:",
+ "Verify your other session using one of the options below.": "使用以下选项之一验证您的其他会话。",
+ "%(name)s (%(userId)s) signed in to a new session without verifying it:": "%(name)s(%(userId)s)登陆到未验证的新会话:",
+ "Ask this user to verify their session, or manually verify it below.": "要求该用户验证其会话,或在下面手动进行验证。",
+ "Not Trusted": "不可信任",
+ "Manually Verify by Text": "手动验证文字",
+ "Interactively verify by Emoji": "通过表情符号进行交互式验证",
+ "Done": "完成",
+ "Cannot reach homeserver": "不可连接到主服务器",
+ "Ensure you have a stable internet connection, or get in touch with the server admin": "确保您的网络连接稳定,或与服务器管理员联系",
+ "Ask your Riot admin to check your config for incorrect or duplicate entries.": "跟您的Riot管理员确认您的配置不正确或重复的条目。",
+ "Cannot reach identity server": "不可连接到身份服务器"
}
diff --git a/src/i18n/strings/zh_Hant.json b/src/i18n/strings/zh_Hant.json
index 0ca6cfc586..4995eeccb0 100644
--- a/src/i18n/strings/zh_Hant.json
+++ b/src/i18n/strings/zh_Hant.json
@@ -2430,5 +2430,9 @@
"Confirm to continue": "確認以繼續",
"Click the button below to confirm your identity.": "點擊下方按鈕以確認您的身份。",
"Confirm encryption setup": "確認加密設定",
- "Click the button below to confirm setting up encryption.": "點擊下方按鈕以確認設定加密。"
+ "Click the button below to confirm setting up encryption.": "點擊下方按鈕以確認設定加密。",
+ "QR Code": "QR Code",
+ "Dismiss read marker and jump to bottom": "取消讀取標記並跳至底部",
+ "Jump to oldest unread message": "跳至最舊的未讀訊息",
+ "Upload a file": "上傳檔案"
}
diff --git a/src/indexing/EventIndex.js b/src/indexing/EventIndex.js
index 02151f8474..d372c38405 100644
--- a/src/indexing/EventIndex.js
+++ b/src/indexing/EventIndex.js
@@ -489,14 +489,20 @@ export default class EventIndex extends EventEmitter {
return object;
});
- // Create a new checkpoint so we can continue crawling the room for
- // messages.
- const newCheckpoint = {
- roomId: checkpoint.roomId,
- token: res.end,
- fullCrawl: checkpoint.fullCrawl,
- direction: checkpoint.direction,
- };
+ let newCheckpoint;
+
+ // The token can be null for some reason. Don't create a checkpoint
+ // in that case since adding it to the db will fail.
+ if (res.end) {
+ // Create a new checkpoint so we can continue crawling the room
+ // for messages.
+ newCheckpoint = {
+ roomId: checkpoint.roomId,
+ token: res.end,
+ fullCrawl: checkpoint.fullCrawl,
+ direction: checkpoint.direction,
+ };
+ }
try {
for (let i = 0; i < redactionEvents.length; i++) {
@@ -506,6 +512,15 @@ export default class EventIndex extends EventEmitter {
const eventsAlreadyAdded = await indexManager.addHistoricEvents(
events, newCheckpoint, checkpoint);
+
+ // We didn't get a valid new checkpoint from the server, nothing
+ // to do here anymore.
+ if (!newCheckpoint) {
+ console.log("EventIndex: The server didn't return a valid ",
+ "new checkpoint, not continuing the crawl.", checkpoint);
+ continue;
+ }
+
// If all events were already indexed we assume that we catched
// up with our index and don't need to crawl the room further.
// Let us delete the checkpoint in that case, otherwise push
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();
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/rageshake/submit-rageshake.ts b/src/rageshake/submit-rageshake.ts
index e5027e0d37..9f9d7898cb 100644
--- a/src/rageshake/submit-rageshake.ts
+++ b/src/rageshake/submit-rageshake.ts
@@ -133,7 +133,6 @@ export default async function sendBugReport(bugReportEndpoint: string, opts: IOp
body.append("cross_signing_supported_by_hs",
String(await client.doesServerSupportUnstableFeature("org.matrix.e2e_cross_signing")));
body.append("cross_signing_ready", String(await client.isCrossSigningReady()));
- body.append("ssss_key_needs_upgrade", String(await client.secretStorageKeyNeedsUpgrade()));
}
}
diff --git a/src/settings/Settings.js b/src/settings/Settings.js
index 5c6d843349..400012e168 100644
--- a/src/settings/Settings.js
+++ b/src/settings/Settings.js
@@ -29,6 +29,7 @@ import ThemeController from './controllers/ThemeController';
import PushToMatrixClientController from './controllers/PushToMatrixClientController';
import ReloadOnChangeController from "./controllers/ReloadOnChangeController";
import {RIGHT_PANEL_PHASES} from "../stores/RightPanelStorePhases";
+import FontSizeController from './controllers/FontSizeController';
// These are just a bunch of helper arrays to avoid copy/pasting a bunch of times
const LEVELS_ROOM_SETTINGS = ['device', 'room-device', 'room-account', 'account', 'config'];
@@ -94,6 +95,12 @@ export const SETTINGS = {
// // not use this for new settings.
// invertedSettingName: "my-negative-setting",
// },
+ "feature_font_scaling": {
+ isFeature: true,
+ displayName: _td("Font scaling"),
+ supportedLevels: LEVELS_FEATURE,
+ default: false,
+ },
"feature_pinning": {
isFeature: true,
displayName: _td("Message Pinning"),
@@ -137,6 +144,12 @@ export const SETTINGS = {
supportedLevels: LEVELS_FEATURE,
default: false,
},
+ "feature_irc_ui": {
+ supportedLevels: LEVELS_ACCOUNT_SETTINGS,
+ displayName: _td('Use IRC layout'),
+ default: false,
+ isFeature: true,
+ },
"mjolnirRooms": {
supportedLevels: ['account'],
default: [],
@@ -158,6 +171,17 @@ export const SETTINGS = {
displayName: _td("Show info about bridges in room settings"),
default: false,
},
+ "fontSize": {
+ displayName: _td("Font size"),
+ supportedLevels: LEVELS_ACCOUNT_SETTINGS,
+ default: 16,
+ controller: new FontSizeController(),
+ },
+ "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'),
@@ -519,4 +543,11 @@ export const SETTINGS = {
MatrixClient.prototype.setCryptoTrustCrossSignedDevices, true,
),
},
+ "ircDisplayNameWidth": {
+ // We specifically want to have room-device > device so that users may set a device default
+ // with a per-room override.
+ supportedLevels: ['room-device', 'device'],
+ displayName: _td("IRC display name width"),
+ default: 80,
+ },
};
diff --git a/src/settings/SettingsStore.js b/src/settings/SettingsStore.js
index 0122916bc3..4b18a27c6c 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";
@@ -370,6 +370,21 @@ export default class SettingsStore {
return SettingsStore._getFinalValue(setting, level, roomId, null, null);
}
+ /**
+ * 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) {
+ // Verify that the setting is actually a setting
+ if (!SETTINGS[settingName]) {
+ throw new Error("Setting '" + settingName + "' does not appear to be a setting.");
+ }
+
+ return SETTINGS[settingName].default;
+ }
+
static _getFinalValue(setting, level, roomId, calculatedValue, calculatedAtLevel) {
let resultingValue = calculatedValue;
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/settings/controllers/FontSizeController.js b/src/settings/controllers/FontSizeController.js
new file mode 100644
index 0000000000..3ef01ab99b
--- /dev/null
+++ b/src/settings/controllers/FontSizeController.js
@@ -0,0 +1,32 @@
+/*
+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 SettingController from "./SettingController";
+import dis from "../../dispatcher/dispatcher";
+
+export default class FontSizeController extends SettingController {
+ constructor() {
+ super();
+ }
+
+ onChange(level, roomId, newValue) {
+ // Dispatch font size change so that everything open responds to the change.
+ dis.dispatch({
+ action: "update-font-size",
+ size: 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..72b6e93443 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";
@@ -81,7 +81,7 @@ export class ThemeWatcher {
}
getEffectiveTheme() {
- // Dev note: Much of this logic is replicated in the GeneralUserSettingsTab
+ // Dev note: Much of this logic is replicated in the AppearanceUserSettingsTab
// XXX: checking the isLight flag here makes checking it in the ThemeController
// itself completely redundant since we just override the result here and we're
diff --git a/src/utils/PasswordScorer.js b/src/utils/PasswordScorer.ts
similarity index 98%
rename from src/utils/PasswordScorer.js
rename to src/utils/PasswordScorer.ts
index 9d89942bf5..d8f3b0fb96 100644
--- a/src/utils/PasswordScorer.js
+++ b/src/utils/PasswordScorer.ts
@@ -63,7 +63,7 @@ _td("Short keyboard patterns are easy to guess");
* @param {string} password Password to score
* @returns {object} Score result with `score` and `feedback` properties
*/
-export function scorePassword(password) {
+export function scorePassword(password: string) {
if (password.length === 0) return null;
const userInputs = ZXCVBN_USER_INPUTS.slice();
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/utils/units.ts b/src/utils/units.ts
new file mode 100644
index 0000000000..54dd6b0523
--- /dev/null
+++ b/src/utils/units.ts
@@ -0,0 +1,27 @@
+/*
+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.
+*/
+
+/* Simple utils for formatting style values
+ */
+
+// converts a pixel value to rem.
+export function toRem(pixelValue: number): string {
+ return pixelValue / 15 + "rem";
+}
+
+export function toPx(pixelValue: number): string {
+ return pixelValue + "px";
+}
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/messages/TextualBody-test.js b/test/components/views/messages/TextualBody-test.js
index 59671327ce..4e93b3bb64 100644
--- a/test/components/views/messages/TextualBody-test.js
+++ b/test/components/views/messages/TextualBody-test.js
@@ -206,7 +206,7 @@ describe("", () => {
'Hey ' +
'' +
'Member' +
'');
});
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';
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 0edea5433e..93118dab22 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,21 @@
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.3.tgz#2ab0d5da2e5815f94b0b9d4b95d1e5f243ab2ca7"
integrity sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==
+"@types/qrcode@^1.3.4":
+ version "1.3.4"
+ resolved "https://registry.yarnpkg.com/@types/qrcode/-/qrcode-1.3.4.tgz#984d97bb72caa558d470158701081ccb712f616b"
+ integrity sha512-aILE5yvKaqQXlY0YPMEYwK/KwdD43fwQTyagj0ffBBTQj8h//085Zp8LUrOnZ9FT69x64f5UgDo0EueY4BPAdg==
+ dependencies:
+ "@types/node" "*"
+
+"@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"
@@ -1318,6 +1346,11 @@
dependencies:
"@types/yargs-parser" "*"
+"@types/zxcvbn@^4.4.0":
+ version "4.4.0"
+ resolved "https://registry.yarnpkg.com/@types/zxcvbn/-/zxcvbn-4.4.0.tgz#fbc1d941cc6d9d37d18405c513ba6b294f89b609"
+ integrity sha512-GQLOT+SN20a+AI51y3fAimhyTF4Y0RG+YP3gf91OibIZ7CJmPFgoZi+ZR5a+vRbS01LbQosITWum4ATmJ1Z6Pg==
+
"@typescript-eslint/experimental-utils@^2.5.0":
version "2.27.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-2.27.0.tgz#801a952c10b58e486c9a0b36cf21e2aab1e9e01a"
@@ -5720,10 +5753,9 @@ mathml-tag-names@^2.0.1:
resolved "https://registry.yarnpkg.com/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz#4ddadd67308e780cf16a47685878ee27b736a0a3"
integrity sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==
-matrix-js-sdk@6.1.0:
+"matrix-js-sdk@github:matrix-org/matrix-js-sdk#develop":
version "6.1.0"
- resolved "https://registry.yarnpkg.com/matrix-js-sdk/-/matrix-js-sdk-6.1.0.tgz#c28ad67c113c4aa9c8bce409c7ba550170bdc2ee"
- integrity sha512-N+vCgxWORvhh7AGyWZlU5Z2brojbbnHnWlMkBF6JjWe6a+pfpjmRKp5/jeQpOz6yfe56sIQvU7ikBZl3JjlMiw==
+ resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/e3c6a0e1a08a3812ba988e60eb5a2a013bb27404"
dependencies:
"@babel/runtime" "^7.8.3"
another-json "^0.2.0"
@@ -6852,18 +6884,6 @@ pvutils@latest:
resolved "https://registry.yarnpkg.com/pvutils/-/pvutils-1.0.17.tgz#ade3c74dfe7178944fe44806626bd2e249d996bf"
integrity sha512-wLHYUQxWaXVQvKnwIDWFVKDJku9XDCvyhhxoq8dc5MFdIlRenyPI9eSfEtcvgHgD7FlvCyGAlWgOzRnZD99GZQ==
-qr.js@0.0.0:
- version "0.0.0"
- resolved "https://registry.yarnpkg.com/qr.js/-/qr.js-0.0.0.tgz#cace86386f59a0db8050fa90d9b6b0e88a1e364f"
- integrity sha1-ys6GOG9ZoNuAUPqQ2baw6IoeNk8=
-
-qrcode-react@^0.1.16:
- version "0.1.16"
- resolved "https://registry.yarnpkg.com/qrcode-react/-/qrcode-react-0.1.16.tgz#d064999d510ffc3e55a9ca3ffcf6c203c69f1517"
- integrity sha512-FK+QCfFqCQMSxUE1byzglERJQkwKqXYvYMCS+/Ad2zACJOfoHkHHtRqsQQPji7lfb1y1qCXLvL+3eP1hAfg8Ng==
- dependencies:
- qr.js "0.0.0"
-
qrcode@^1.4.4:
version "1.4.4"
resolved "https://registry.yarnpkg.com/qrcode/-/qrcode-1.4.4.tgz#f0c43568a7e7510a55efc3b88d9602f71963ea83"