From e33f4ba9c0e8c29cf074f566cbb69c27007f6c57 Mon Sep 17 00:00:00 2001 From: Resynth Date: Sun, 25 Oct 2020 22:04:39 +0000 Subject: [PATCH 01/24] Warn on Access Token reveal Signed-off-by: Resynth --- .../views/dialogs/AccessTokenDialog.tsx | 39 +++++++++++++++++++ .../settings/tabs/user/HelpUserSettingsTab.js | 14 ++++++- 2 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 src/components/views/dialogs/AccessTokenDialog.tsx diff --git a/src/components/views/dialogs/AccessTokenDialog.tsx b/src/components/views/dialogs/AccessTokenDialog.tsx new file mode 100644 index 0000000000..81c48f219a --- /dev/null +++ b/src/components/views/dialogs/AccessTokenDialog.tsx @@ -0,0 +1,39 @@ + /* +Copyright 2017 Vector Creations Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import React from 'react'; +import { _t } from '../../../languageHandler'; +import QuestionDialog from './QuestionDialog'; + +type IProps = Exclude< + React.ComponentProps, + "title" | "danger" | "description" + >; + +export default function AccessTokenDialog (props: IProps) { + return ( + + ); +} diff --git a/src/components/views/settings/tabs/user/HelpUserSettingsTab.js b/src/components/views/settings/tabs/user/HelpUserSettingsTab.js index 85ba22a353..585a54ff86 100644 --- a/src/components/views/settings/tabs/user/HelpUserSettingsTab.js +++ b/src/components/views/settings/tabs/user/HelpUserSettingsTab.js @@ -27,6 +27,7 @@ import * as sdk from "../../../../../"; import PlatformPeg from "../../../../../PlatformPeg"; import * as KeyboardShortcuts from "../../../../../accessibility/KeyboardShortcuts"; import UpdateCheckButton from "../../UpdateCheckButton"; +import AccessTokenDialog from '../../../dialogs/AccessTokenDialog'; export default class HelpUserSettingsTab extends React.Component { static propTypes = { @@ -148,6 +149,17 @@ export default class HelpUserSettingsTab extends React.Component { ); } + onAccessTokenSpoilerClick = async (event) => { + // React throws away the event before we can use it (we are async, after all). + event.persist(); + + // We make the user accept a scary popup to combat Social Engineering. No peeking! + await Modal.createTrackedDialog('Reveal Access Token', '', AccessTokenDialog).finished; + + // Pass it onto the handler. + this._showSpoiler(event); + } + render() { const brand = SdkConfig.get().brand; @@ -266,7 +278,7 @@ export default class HelpUserSettingsTab extends React.Component { {_t("Homeserver is")} {MatrixClientPeg.get().getHomeserverUrl()}
{_t("Identity Server is")} {MatrixClientPeg.get().getIdentityServerUrl()}
{_t("Access Token:") + ' '} - <{ _t("click to reveal") }> From ae29168e077be47a83628f10b7765d6bcc9a7a0a Mon Sep 17 00:00:00 2001 From: Resynth Date: Sun, 25 Oct 2020 22:05:44 +0000 Subject: [PATCH 02/24] Lint Signed-off-by: Resynth --- src/components/views/dialogs/AccessTokenDialog.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/views/dialogs/AccessTokenDialog.tsx b/src/components/views/dialogs/AccessTokenDialog.tsx index 81c48f219a..f95effd523 100644 --- a/src/components/views/dialogs/AccessTokenDialog.tsx +++ b/src/components/views/dialogs/AccessTokenDialog.tsx @@ -1,4 +1,4 @@ - /* +/* Copyright 2017 Vector Creations Ltd Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,7 +23,7 @@ type IProps = Exclude< "title" | "danger" | "description" >; -export default function AccessTokenDialog (props: IProps) { +export default function AccessTokenDialog(props: IProps) { return ( ); From 76edd551e5833cb1c94c1025fa069aeb79a9faa2 Mon Sep 17 00:00:00 2001 From: Resynth Date: Mon, 26 Oct 2020 00:34:14 +0000 Subject: [PATCH 03/24] Fix i18n Signed-off-by: Resynth --- src/i18n/strings/en_EN.json | 1 + 1 file changed, 1 insertion(+) diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index eda69d68ea..ad6593f704 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1585,6 +1585,7 @@ "Add a new server...": "Add a new server...", "%(networkName)s rooms": "%(networkName)s rooms", "Matrix rooms": "Matrix rooms", + "Do not reveal your Access Token to anyone, under any circumstances. Sharing your Access Token with someone would allow them to login to your account, and access your private information.": "Do not reveal your Access Token to anyone, under any circumstances. Sharing your Access Token with someone would allow them to login to your account, and access your private information.", "Matrix ID": "Matrix ID", "Matrix Room ID": "Matrix Room ID", "email address": "email address", From a3212c0477ec0fc9166a56a49a9579bae4712d5f Mon Sep 17 00:00:00 2001 From: Resynth Date: Mon, 26 Oct 2020 23:46:53 +0000 Subject: [PATCH 04/24] Fix weird formatting Signed-off-by: Resynth --- src/components/views/dialogs/AccessTokenDialog.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/views/dialogs/AccessTokenDialog.tsx b/src/components/views/dialogs/AccessTokenDialog.tsx index f95effd523..2d96d8ec20 100644 --- a/src/components/views/dialogs/AccessTokenDialog.tsx +++ b/src/components/views/dialogs/AccessTokenDialog.tsx @@ -1,5 +1,6 @@ /* Copyright 2017 Vector Creations Ltd +Copyright 2020 Resynth Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -21,7 +22,7 @@ import QuestionDialog from './QuestionDialog'; type IProps = Exclude< React.ComponentProps, "title" | "danger" | "description" - >; +>; export default function AccessTokenDialog(props: IProps) { return ( From 34fbed3fbbbbb0ffc17a15631d256b855080b1ee Mon Sep 17 00:00:00 2001 From: Qt Resynth Date: Fri, 20 Nov 2020 01:15:58 +0000 Subject: [PATCH 05/24] Update src/components/views/dialogs/AccessTokenDialog.tsx --- src/components/views/dialogs/AccessTokenDialog.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/components/views/dialogs/AccessTokenDialog.tsx b/src/components/views/dialogs/AccessTokenDialog.tsx index 2d96d8ec20..6a943eb5a8 100644 --- a/src/components/views/dialogs/AccessTokenDialog.tsx +++ b/src/components/views/dialogs/AccessTokenDialog.tsx @@ -31,9 +31,7 @@ export default function AccessTokenDialog(props: IProps) { title="Reveal Access Token" danger={true} description={_t( - "Do not reveal your Access Token to anyone, under any circumstances. " + - "Sharing your Access Token with someone would allow them to login to " + - "your account, and access your private information.", + "Your access token gives full access to your account. Do not share it with anyone." )} > ); From 0e4d656e4bfc0fd16d4628ac44668f6aa2f5ae83 Mon Sep 17 00:00:00 2001 From: Resynth Date: Fri, 20 Nov 2020 18:21:39 +0000 Subject: [PATCH 06/24] Update src/i18n/strings/en_EN.json --- src/i18n/strings/en_EN.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index ad6593f704..8005f1cdef 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1585,7 +1585,7 @@ "Add a new server...": "Add a new server...", "%(networkName)s rooms": "%(networkName)s rooms", "Matrix rooms": "Matrix rooms", - "Do not reveal your Access Token to anyone, under any circumstances. Sharing your Access Token with someone would allow them to login to your account, and access your private information.": "Do not reveal your Access Token to anyone, under any circumstances. Sharing your Access Token with someone would allow them to login to your account, and access your private information.", + "Your access token gives full access to your account. Do not share it with anyone.", "Matrix ID": "Matrix ID", "Matrix Room ID": "Matrix Room ID", "email address": "email address", From 1b48b08525f75035b9a09993124a12d442d0f2e2 Mon Sep 17 00:00:00 2001 From: Resynth Date: Fri, 20 Nov 2020 18:23:18 +0000 Subject: [PATCH 07/24] Update src/i18n/strings/en_EN.json --- src/i18n/strings/en_EN.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 8005f1cdef..a57a68e7b4 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1585,7 +1585,7 @@ "Add a new server...": "Add a new server...", "%(networkName)s rooms": "%(networkName)s rooms", "Matrix rooms": "Matrix rooms", - "Your access token gives full access to your account. Do not share it with anyone.", + "Your access token gives full access to your account. Do not share it with anyone.": "Your access token gives full access to your account. Do not share it with anyone.", "Matrix ID": "Matrix ID", "Matrix Room ID": "Matrix Room ID", "email address": "email address", From d44aab6d321d04deb6733d9ace5f54b5fe1104bf Mon Sep 17 00:00:00 2001 From: Resynth Date: Mon, 23 Nov 2020 12:57:06 +0000 Subject: [PATCH 08/24] Update src/components/views/dialogs/AccessTokenDialog.tsx Co-authored-by: Michael Telatynski <7t3chguy@googlemail.com> --- src/components/views/dialogs/AccessTokenDialog.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/dialogs/AccessTokenDialog.tsx b/src/components/views/dialogs/AccessTokenDialog.tsx index 6a943eb5a8..c0b1b929df 100644 --- a/src/components/views/dialogs/AccessTokenDialog.tsx +++ b/src/components/views/dialogs/AccessTokenDialog.tsx @@ -31,7 +31,7 @@ export default function AccessTokenDialog(props: IProps) { title="Reveal Access Token" danger={true} description={_t( - "Your access token gives full access to your account. Do not share it with anyone." + "Your access token gives full access to your account. Do not share it with anyone.", )} >
); From 6fdc7a0860131ad5be0950e6e6365d520b801785 Mon Sep 17 00:00:00 2001 From: Aaron Raimist Date: Fri, 12 Mar 2021 05:45:22 -0600 Subject: [PATCH 09/24] remove old copyright notice, this is a new file Signed-off-by: Aaron Raimist --- src/components/views/dialogs/AccessTokenDialog.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/views/dialogs/AccessTokenDialog.tsx b/src/components/views/dialogs/AccessTokenDialog.tsx index c0b1b929df..220047ac21 100644 --- a/src/components/views/dialogs/AccessTokenDialog.tsx +++ b/src/components/views/dialogs/AccessTokenDialog.tsx @@ -1,5 +1,4 @@ /* -Copyright 2017 Vector Creations Ltd Copyright 2020 Resynth Licensed under the Apache License, Version 2.0 (the "License"); From 6754a0b48388d6349c499f9c7b231bf32c0d6fa4 Mon Sep 17 00:00:00 2001 From: Aaron Raimist Date: Tue, 27 Apr 2021 19:12:20 -0500 Subject: [PATCH 10/24] Switch to
Signed-off-by: Aaron Raimist --- .../tabs/user/_HelpUserSettingsTab.scss | 31 +++++++++++++ .../views/dialogs/AccessTokenDialog.tsx | 38 ---------------- .../settings/tabs/user/HelpUserSettingsTab.js | 44 +++++++++++++------ src/i18n/strings/en_EN.json | 7 ++- 4 files changed, 64 insertions(+), 56 deletions(-) delete mode 100644 src/components/views/dialogs/AccessTokenDialog.tsx diff --git a/res/css/views/settings/tabs/user/_HelpUserSettingsTab.scss b/res/css/views/settings/tabs/user/_HelpUserSettingsTab.scss index 109edfff81..0f879d209e 100644 --- a/res/css/views/settings/tabs/user/_HelpUserSettingsTab.scss +++ b/res/css/views/settings/tabs/user/_HelpUserSettingsTab.scss @@ -22,3 +22,34 @@ limitations under the License. .mx_HelpUserSettingsTab span.mx_AccessibleButton { word-break: break-word; } + +.mx_HelpUserSettingsTab code { + word-break: break-all; + user-select: all; +} + +.mx_HelpUserSettingsTab_accessToken { + display: flex; + justify-content: space-between; + border-radius: 5px; + border: solid 1px $light-fg-color; + margin-bottom: 10px; + margin-top: 10px; + padding: 10px; +} + +.mx_HelpUserSettingsTab_accessToken_copy { + flex-shrink: 0; + cursor: pointer; + margin-left: 20px; + display: inherit; +} + +.mx_HelpUserSettingsTab_accessToken_copy > div { + mask-image: url($copy-button-url); + background-color: $message-action-bar-fg-color; + margin-left: 5px; + width: 20px; + height: 20px; + background-repeat: no-repeat; +} diff --git a/src/components/views/dialogs/AccessTokenDialog.tsx b/src/components/views/dialogs/AccessTokenDialog.tsx deleted file mode 100644 index c0b1b929df..0000000000 --- a/src/components/views/dialogs/AccessTokenDialog.tsx +++ /dev/null @@ -1,38 +0,0 @@ -/* -Copyright 2017 Vector Creations Ltd -Copyright 2020 Resynth - -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 QuestionDialog from './QuestionDialog'; - -type IProps = Exclude< - React.ComponentProps, - "title" | "danger" | "description" ->; - -export default function AccessTokenDialog(props: IProps) { - return ( - - ); -} diff --git a/src/components/views/settings/tabs/user/HelpUserSettingsTab.js b/src/components/views/settings/tabs/user/HelpUserSettingsTab.js index e52bc1a3fb..cf1a28ef76 100644 --- a/src/components/views/settings/tabs/user/HelpUserSettingsTab.js +++ b/src/components/views/settings/tabs/user/HelpUserSettingsTab.js @@ -20,6 +20,7 @@ import PropTypes from 'prop-types'; import {_t, getCurrentLanguage} from "../../../../../languageHandler"; import {MatrixClientPeg} from "../../../../../MatrixClientPeg"; import AccessibleButton from "../../../elements/AccessibleButton"; +import AccessibleTooltipButton from '../../../elements/AccessibleTooltipButton'; import SdkConfig from "../../../../../SdkConfig"; import createRoom from "../../../../../createRoom"; import Modal from "../../../../../Modal"; @@ -27,8 +28,11 @@ import * as sdk from "../../../../../"; import PlatformPeg from "../../../../../PlatformPeg"; import * as KeyboardShortcuts from "../../../../../accessibility/KeyboardShortcuts"; import UpdateCheckButton from "../../UpdateCheckButton"; -import AccessTokenDialog from '../../../dialogs/AccessTokenDialog'; import {replaceableComponent} from "../../../../../utils/replaceableComponent"; +import {copyPlaintext} from "../../../../../utils/strings"; +import * as ContextMenu from "../../../../structures/ContextMenu"; +import {toRightOf} from "../../../../structures/ContextMenu"; + @replaceableComponent("views.settings.tabs.user.HelpUserSettingsTab") export default class HelpUserSettingsTab extends React.Component { @@ -151,15 +155,18 @@ export default class HelpUserSettingsTab extends React.Component { ); } - onAccessTokenSpoilerClick = async (event) => { - // React throws away the event before we can use it (we are async, after all). - event.persist(); + onAccessTokenCopyClick = async (e) => { + e.preventDefault(); + const target = e.target; // copy target before we go async and React throws it away - // We make the user accept a scary popup to combat Social Engineering. No peeking! - await Modal.createTrackedDialog('Reveal Access Token', '', AccessTokenDialog).finished; - - // Pass it onto the handler. - this._showSpoiler(event); + const successful = await copyPlaintext(MatrixClientPeg.get().getAccessToken()); + const buttonRect = target.getBoundingClientRect(); + const GenericTextContextMenu = sdk.getComponent('context_menus.GenericTextContextMenu'); + const {close} = ContextMenu.createMenu(GenericTextContextMenu, { + ...toRightOf(buttonRect, 2), + message: successful ? _t('Copied!') : _t('Failed to copy'), + }); + target.onmouseleave = close; } render() { @@ -279,11 +286,20 @@ export default class HelpUserSettingsTab extends React.Component {
{_t("Homeserver is")} {MatrixClientPeg.get().getHomeserverUrl()}
{_t("Identity Server is")} {MatrixClientPeg.get().getIdentityServerUrl()}
- {_t("Access Token:") + ' '} - - <{ _t("click to reveal") }> - +
+
+ {_t("Access Token")}
+ { _t("Your access token gives full access to your account." + + " Do not share it with anyone." ) } +
+ {MatrixClientPeg.get().getAccessToken()} + +
+

{_t("Clear cache and reload")} diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index b110af8749..99451dabd6 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1251,8 +1251,9 @@ "olm version:": "olm version:", "Homeserver is": "Homeserver is", "Identity Server is": "Identity Server is", - "Access Token:": "Access Token:", - "click to reveal": "click to reveal", + "Access Token": "Access Token", + "Your access token gives full access to your account. Do not share it with anyone.": "Your access token gives full access to your account. Do not share it with anyone.", + "Copy": "Copy", "Clear cache and reload": "Clear cache and reload", "Labs": "Labs", "Customise your experience with experimental labs features. Learn more.": "Customise your experience with experimental labs features. Learn more.", @@ -2016,7 +2017,6 @@ "Add a new server...": "Add a new server...", "%(networkName)s rooms": "%(networkName)s rooms", "Matrix rooms": "Matrix rooms", - "Your access token gives full access to your account. Do not share it with anyone.": "Your access token gives full access to your account. Do not share it with anyone.", "Space selection": "Space selection", "Add existing rooms": "Add existing rooms", "Filter your rooms and spaces": "Filter your rooms and spaces", @@ -2336,7 +2336,6 @@ "Share Community": "Share Community", "Share Room Message": "Share Room Message", "Link to selected message": "Link to selected message", - "Copy": "Copy", "Command Help": "Command Help", "Failed to save space settings.": "Failed to save space settings.", "Space settings": "Space settings", From 626a4ccc34c902b1dc234d01ede39318f97d345b Mon Sep 17 00:00:00 2001 From: Aaron Raimist Date: Fri, 30 Apr 2021 21:45:33 -0500 Subject: [PATCH 11/24] Make warning bold, close copied tooltip on escape Signed-off-by: Aaron Raimist --- .../views/settings/tabs/user/HelpUserSettingsTab.tsx | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/components/views/settings/tabs/user/HelpUserSettingsTab.tsx b/src/components/views/settings/tabs/user/HelpUserSettingsTab.tsx index 9046c074e6..45395bd10c 100644 --- a/src/components/views/settings/tabs/user/HelpUserSettingsTab.tsx +++ b/src/components/views/settings/tabs/user/HelpUserSettingsTab.tsx @@ -60,6 +60,12 @@ export default class HelpUserSettingsTab extends React.Component }); } + componentWillUnmount() { + // if the Copied tooltip is open then get rid of it, there are ways to close the modal which wouldn't close + // the tooltip otherwise, such as pressing Escape + if (this.closeCopiedTooltip) this.closeCopiedTooltip(); + } + private onClearCacheAndReload = (e) => { if (!PlatformPeg.get()) return; @@ -168,7 +174,7 @@ export default class HelpUserSettingsTab extends React.Component ...toRightOf(buttonRect, 2), message: successful ? _t('Copied!') : _t('Failed to copy'), }); - target.onmouseleave = close; + this.closeCopiedTooltip = target.onmouseleave = close; } render() { @@ -290,8 +296,8 @@ export default class HelpUserSettingsTab extends React.Component
{_t("Access Token")}
- { _t("Your access token gives full access to your account." - + " Do not share it with anyone." ) } + {_t("Your access token gives full access to your account." + + " Do not share it with anyone." )}
{MatrixClientPeg.get().getAccessToken()} Date: Fri, 30 Apr 2021 21:54:57 -0500 Subject: [PATCH 12/24] lint Signed-off-by: Aaron Raimist --- src/components/views/settings/tabs/user/HelpUserSettingsTab.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/components/views/settings/tabs/user/HelpUserSettingsTab.tsx b/src/components/views/settings/tabs/user/HelpUserSettingsTab.tsx index 45395bd10c..3fa0be478c 100644 --- a/src/components/views/settings/tabs/user/HelpUserSettingsTab.tsx +++ b/src/components/views/settings/tabs/user/HelpUserSettingsTab.tsx @@ -42,6 +42,8 @@ interface IState { @replaceableComponent("views.settings.tabs.user.HelpUserSettingsTab") export default class HelpUserSettingsTab extends React.Component { + protected closeCopiedTooltip: () => void; + constructor(props) { super(props); From 0fe6a389d40c24deec0f9b427836df89011ae87f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Tue, 4 May 2021 12:36:22 +0200 Subject: [PATCH 13/24] Add a note about sharing your IP with P2P calls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- src/i18n/strings/en_EN.json | 2 +- src/settings/Settings.ts | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 85e8e54258..43df51981a 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -833,7 +833,7 @@ "Match system theme": "Match system theme", "Use a system font": "Use a system font", "System font name": "System font name", - "Allow Peer-to-Peer for 1:1 calls": "Allow Peer-to-Peer for 1:1 calls", + "Allow Peer-to-Peer for 1:1 calls (if you enable this, the other party might be able to see your IP address)": "Allow Peer-to-Peer for 1:1 calls (if you enable this, the other party might be able to see your IP address)", "Send analytics data": "Send analytics data", "Never send encrypted messages to unverified sessions from this session": "Never send encrypted messages to unverified sessions from this session", "Never send encrypted messages to unverified sessions in this room from this session": "Never send encrypted messages to unverified sessions in this room from this session", diff --git a/src/settings/Settings.ts b/src/settings/Settings.ts index 2a26eeac13..1497a2208d 100644 --- a/src/settings/Settings.ts +++ b/src/settings/Settings.ts @@ -438,7 +438,10 @@ export const SETTINGS: {[setting: string]: ISetting} = { }, "webRtcAllowPeerToPeer": { supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG, - displayName: _td('Allow Peer-to-Peer for 1:1 calls'), + displayName: _td( + "Allow Peer-to-Peer for 1:1 calls " + + "(if you enable this, the other party might be able to see your IP address)", + ), default: true, invertedSettingName: 'webRtcForceTURN', }, From 3eea1b836927a5bfc15313a80feb4ff5d35c1c30 Mon Sep 17 00:00:00 2001 From: Jaiwanth Date: Tue, 4 May 2021 16:42:22 +0530 Subject: [PATCH 14/24] Add cleanup functions for image view --- src/components/views/elements/ImageView.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/components/views/elements/ImageView.tsx b/src/components/views/elements/ImageView.tsx index fcacae2d39..05d487a9eb 100644 --- a/src/components/views/elements/ImageView.tsx +++ b/src/components/views/elements/ImageView.tsx @@ -114,6 +114,8 @@ export default class ImageView extends React.Component { componentWillUnmount() { this.focusLock.current.removeEventListener('wheel', this.onWheel); + window.removeEventListener("resize", this.calculateZoom); + this.image.current.removeEventListener("load", this.calculateZoom); } private calculateZoom = () => { From 48237949ad6821e61c839fff14bb86738fab0575 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 4 May 2021 16:44:29 +0100 Subject: [PATCH 15/24] Only aggregate DM notifications on the Space Panel in the Home Space --- src/stores/SpaceStore.tsx | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/stores/SpaceStore.tsx b/src/stores/SpaceStore.tsx index ec6227e45e..22307d9f2e 100644 --- a/src/stores/SpaceStore.tsx +++ b/src/stores/SpaceStore.tsx @@ -406,7 +406,19 @@ export class SpaceStoreClass extends AsyncStoreWithClient { this.spaceFilteredRooms.forEach((roomIds, s) => { // Update NotificationStates - this.getNotificationState(s)?.setRooms(visibleRooms.filter(room => roomIds.has(room.roomId))); + this.getNotificationState(s)?.setRooms(visibleRooms.filter(room => { + if (roomIds.has(room.roomId)) { + // Don't aggregate notifications for DMs except in the Home Space + if (s !== HOME_SPACE) { + return !DMRoomMap.shared().getUserIdForRoomId(room.roomId) + || RoomListStore.instance.getTagsForRoom(room).includes(DefaultTagID.Favourite); + } + + return true; + } + + return false; + })); }); }, 100, {trailing: true, leading: true}); From a94c1a90c15c5fb29c31869b3a15ddde31ece576 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Tue, 4 May 2021 20:45:15 -0600 Subject: [PATCH 16/24] Update colours and sizing for voice messages Fixes https://github.com/vector-im/element-web/issues/17162 --- .../views/rooms/_VoiceRecordComposerTile.scss | 10 ++++++---- .../voice_messages/_PlaybackContainer.scss | 15 +++++++-------- res/themes/dark/css/_dark.scss | 10 +++++----- res/themes/legacy-dark/css/_legacy-dark.scss | 8 ++++---- .../legacy-light/css/_legacy-light.scss | 12 ++++++------ res/themes/light/css/_light.scss | 19 +++++++++++-------- .../voice_messages/LiveRecordingWaveform.tsx | 7 +++---- src/voice/Playback.ts | 2 +- src/voice/VoiceRecording.ts | 2 ++ 9 files changed, 45 insertions(+), 40 deletions(-) diff --git a/res/css/views/rooms/_VoiceRecordComposerTile.scss b/res/css/views/rooms/_VoiceRecordComposerTile.scss index 15daf81672..c0775b8371 100644 --- a/res/css/views/rooms/_VoiceRecordComposerTile.scss +++ b/res/css/views/rooms/_VoiceRecordComposerTile.scss @@ -39,7 +39,7 @@ limitations under the License. width: 14px; // w&h are size of icon height: 18px; vertical-align: middle; - margin-right: 7px; // distance from left edge of waveform container (container has some margin too) + margin-right: 11px; // distance from left edge of waveform container (container has some margin too) background-color: $voice-record-icon-color; mask-repeat: no-repeat; mask-size: contain; @@ -55,7 +55,9 @@ limitations under the License. position: relative; // important for the live circle &.mx_VoiceRecordComposerTile_recording { - padding-left: 16px; // +10px for the live circle, +6px for regular padding + // We are putting the circle in this padding, so we need +10px from the regular + // padding on the left side. + padding-left: 22px; &::before { animation: recording-pulse 2s infinite; @@ -65,8 +67,8 @@ limitations under the License. width: 10px; height: 10px; position: absolute; - left: 8px; - top: 16px; // vertically center + left: 12px; // 12px from the left edge for container padding + top: 18px; // vertically center (middle align with clock) border-radius: 10px; } } diff --git a/res/css/views/voice_messages/_PlaybackContainer.scss b/res/css/views/voice_messages/_PlaybackContainer.scss index 49bd81ef81..64e8f445e1 100644 --- a/res/css/views/voice_messages/_PlaybackContainer.scss +++ b/res/css/views/voice_messages/_PlaybackContainer.scss @@ -19,8 +19,9 @@ limitations under the License. // Container for live recording and playback controls .mx_VoiceMessagePrimaryContainer { - padding: 6px; // makes us 4px taller than the send/stop button - padding-right: 5px; // there's 1px from the waveform itself, so account for that + // 7px top and bottom for visual design. 12px left & right, but the waveform (right) + // has a 1px padding on it that we want to account for. + padding: 7px 12px 7px 11px; background-color: $voice-record-waveform-bg-color; border-radius: 12px; @@ -30,11 +31,9 @@ limitations under the License. color: $voice-record-waveform-fg-color; font-size: $font-14px; + line-height: $font-24px; .mx_Waveform { - // We want the bars to be 2px shorter than the play/pause button in the waveform control - height: 28px; // default is 30px, so we're subtracting the 2px border off the bars - .mx_Waveform_bar { background-color: $voice-record-waveform-incomplete-fg-color; @@ -47,8 +46,8 @@ limitations under the License. } .mx_Clock { - padding-right: 4px; // isolate from waveform - padding-left: 8px; // isolate from live circle - width: 40px; // we're not using a monospace font, so fake it + width: 42px; // we're not using a monospace font, so fake it + padding-right: 6px; // with the fixed width this ends up as a visual 8px most of the time, as intended. + padding-left: 8px; // isolate from recording circle / play control } } diff --git a/res/themes/dark/css/_dark.scss b/res/themes/dark/css/_dark.scss index cfdda41619..334bf581f3 100644 --- a/res/themes/dark/css/_dark.scss +++ b/res/themes/dark/css/_dark.scss @@ -42,13 +42,13 @@ $preview-bar-bg-color: $header-panel-bg-color; $groupFilterPanel-bg-color: rgba(38, 39, 43, 0.82); $inverted-bg-color: $base-color; -$voice-record-stop-border-color: #6F7882; // "Quarterly" +$voice-record-stop-border-color: #6F7882; // "Quartary" $voice-record-waveform-bg-color: #394049; // "Dark Tile" -$voice-record-waveform-fg-color: $tertiary-fg-color; -$voice-record-waveform-incomplete-fg-color: #5b646d; -$voice-record-icon-color: $tertiary-fg-color; +$voice-record-waveform-fg-color: $secondary-fg-color; +$voice-record-waveform-incomplete-fg-color: #6F7882; // "Quartary" +$voice-record-icon-color: #6F7882; // "Quartary" $voice-playback-button-bg-color: $tertiary-fg-color; -$voice-playback-button-fg-color: $bg-color; +$voice-playback-button-fg-color: #21262C; // "Separator" // used by AddressSelector $selected-color: $room-highlight-color; diff --git a/res/themes/legacy-dark/css/_legacy-dark.scss b/res/themes/legacy-dark/css/_legacy-dark.scss index 6413a99ce0..6a162bbda7 100644 --- a/res/themes/legacy-dark/css/_legacy-dark.scss +++ b/res/themes/legacy-dark/css/_legacy-dark.scss @@ -127,11 +127,11 @@ $groupFilterPanel-divider-color: $roomlist-header-color; // See non-legacy dark for variable information $voice-record-stop-border-color: #6F7882; $voice-record-waveform-bg-color: #394049; -$voice-record-waveform-fg-color: $tertiary-fg-color; -$voice-record-waveform-incomplete-fg-color: #5b646d; -$voice-record-icon-color: $tertiary-fg-color; +$voice-record-waveform-fg-color: $secondary-fg-color; +$voice-record-waveform-incomplete-fg-color: #6F7882; +$voice-record-icon-color: #6F7882; $voice-playback-button-bg-color: $tertiary-fg-color; -$voice-playback-button-fg-color: $bg-color; +$voice-playback-button-fg-color: #21262C; $roomtile-preview-color: #9e9e9e; $roomtile-default-badge-bg-color: #61708b; diff --git a/res/themes/legacy-light/css/_legacy-light.scss b/res/themes/legacy-light/css/_legacy-light.scss index 2151724071..cc0f54853e 100644 --- a/res/themes/legacy-light/css/_legacy-light.scss +++ b/res/themes/legacy-light/css/_legacy-light.scss @@ -192,15 +192,15 @@ $roomsublist-skeleton-ui-bg: linear-gradient(180deg, #ffffff 0%, #ffffff00 100%) $groupFilterPanel-divider-color: $roomlist-header-color; // See non-legacy _light for variable information -$voice-record-stop-border-color: #E3E8F0; $voice-record-stop-symbol-color: #ff4b55; -$voice-record-waveform-bg-color: #E3E8F0; -$voice-record-waveform-fg-color: $muted-fg-color; -$voice-record-waveform-incomplete-fg-color: #C1C6CD; $voice-record-live-circle-color: #ff4b55; -$voice-record-icon-color: $muted-fg-color; +$voice-record-stop-border-color: #E3E8F0; +$voice-record-waveform-bg-color: #E3E8F0; +$voice-record-waveform-fg-color: $secondary-fg-color; +$voice-record-waveform-incomplete-fg-color: #C1C6CD; +$voice-record-icon-color: $tertiary-fg-color; $voice-playback-button-bg-color: $primary-bg-color; -$voice-playback-button-fg-color: $muted-fg-color; +$voice-playback-button-fg-color: $secondary-fg-color; $roomtile-preview-color: #9e9e9e; $roomtile-default-badge-bg-color: #61708b; diff --git a/res/themes/light/css/_light.scss b/res/themes/light/css/_light.scss index 1763fcdd48..193b7f816c 100644 --- a/res/themes/light/css/_light.scss +++ b/res/themes/light/css/_light.scss @@ -182,15 +182,18 @@ $roomsublist-skeleton-ui-bg: linear-gradient(180deg, #ffffff 0%, #ffffff00 100%) $groupFilterPanel-divider-color: $roomlist-header-color; -$voice-record-stop-border-color: #E3E8F0; -$voice-record-stop-symbol-color: #ff4b55; // $warning-color, but without letting people change it in themes -$voice-record-waveform-bg-color: #E3E8F0; -$voice-record-waveform-fg-color: $muted-fg-color; -$voice-record-waveform-incomplete-fg-color: #C1C6CD; -$voice-record-live-circle-color: #ff4b55; // $warning-color, but without letting people change it in themes -$voice-record-icon-color: $muted-fg-color; +// These two don't change between themes. They are the $warning-color, but we don't +// want custom themes to affect them by accident. +$voice-record-stop-symbol-color: #ff4b55; +$voice-record-live-circle-color: #ff4b55; + +$voice-record-stop-border-color: #E3E8F0; // "Separator" +$voice-record-waveform-bg-color: #E3E8F0; // "Separator" +$voice-record-waveform-fg-color: $secondary-fg-color; +$voice-record-waveform-incomplete-fg-color: #C1C6CD; // "Quartary" +$voice-record-icon-color: $tertiary-fg-color; $voice-playback-button-bg-color: $primary-bg-color; -$voice-playback-button-fg-color: $muted-fg-color; +$voice-playback-button-fg-color: $secondary-fg-color; $roomtile-preview-color: $secondary-fg-color; $roomtile-default-badge-bg-color: #61708b; diff --git a/src/components/views/voice_messages/LiveRecordingWaveform.tsx b/src/components/views/voice_messages/LiveRecordingWaveform.tsx index e7c34c9177..aab89f6ab1 100644 --- a/src/components/views/voice_messages/LiveRecordingWaveform.tsx +++ b/src/components/views/voice_messages/LiveRecordingWaveform.tsx @@ -15,12 +15,11 @@ limitations under the License. */ import React from "react"; -import {IRecordingUpdate, VoiceRecording} from "../../../voice/VoiceRecording"; +import {IRecordingUpdate, RECORDING_PLAYBACK_SAMPLES, VoiceRecording} from "../../../voice/VoiceRecording"; import {replaceableComponent} from "../../../utils/replaceableComponent"; import {arrayFastResample, arraySeed} from "../../../utils/arrays"; import {percentageOf} from "../../../utils/numbers"; import Waveform from "./Waveform"; -import {PLAYBACK_WAVEFORM_SAMPLES} from "../../../voice/Playback"; interface IProps { recorder: VoiceRecording; @@ -38,14 +37,14 @@ export default class LiveRecordingWaveform extends React.PureComponent { // The waveform and the downsample target are pretty close, so we should be fine to // do this, despite the docs on arrayFastResample. - const bars = arrayFastResample(Array.from(update.waveform), PLAYBACK_WAVEFORM_SAMPLES); + const bars = arrayFastResample(Array.from(update.waveform), RECORDING_PLAYBACK_SAMPLES); this.setState({ // The incoming data is between zero and one, but typically even screaming into a // microphone won't send you over 0.6, so we artificially adjust the gain for the diff --git a/src/voice/Playback.ts b/src/voice/Playback.ts index ca48680ebd..b2525c2719 100644 --- a/src/voice/Playback.ts +++ b/src/voice/Playback.ts @@ -29,7 +29,7 @@ export enum PlaybackState { Playing = "playing", // active progress through timeline } -export const PLAYBACK_WAVEFORM_SAMPLES = 35; +export const PLAYBACK_WAVEFORM_SAMPLES = 38; const DEFAULT_WAVEFORM = arraySeed(0, PLAYBACK_WAVEFORM_SAMPLES); export class Playback extends EventEmitter implements IDestroyable { diff --git a/src/voice/VoiceRecording.ts b/src/voice/VoiceRecording.ts index eb705200ca..62496ce3d9 100644 --- a/src/voice/VoiceRecording.ts +++ b/src/voice/VoiceRecording.ts @@ -33,6 +33,8 @@ const BITRATE = 24000; // 24kbps is pretty high quality for our use case in opus const TARGET_MAX_LENGTH = 120; // 2 minutes in seconds. Somewhat arbitrary, though longer == larger files. const TARGET_WARN_TIME_LEFT = 10; // 10 seconds, also somewhat arbitrary. +export const RECORDING_PLAYBACK_SAMPLES = 43; + export interface IRecordingUpdate { waveform: number[]; // floating points between 0 (low) and 1 (high). timeSeconds: number; // float From ed43d9257937b6e205dd939a60a453f1bd9fbefc Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Tue, 4 May 2021 20:55:35 -0600 Subject: [PATCH 17/24] Match designs more closely with +1 sample --- src/voice/Playback.ts | 2 +- src/voice/VoiceRecording.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/voice/Playback.ts b/src/voice/Playback.ts index b2525c2719..caa5241e1a 100644 --- a/src/voice/Playback.ts +++ b/src/voice/Playback.ts @@ -29,7 +29,7 @@ export enum PlaybackState { Playing = "playing", // active progress through timeline } -export const PLAYBACK_WAVEFORM_SAMPLES = 38; +export const PLAYBACK_WAVEFORM_SAMPLES = 39; const DEFAULT_WAVEFORM = arraySeed(0, PLAYBACK_WAVEFORM_SAMPLES); export class Playback extends EventEmitter implements IDestroyable { diff --git a/src/voice/VoiceRecording.ts b/src/voice/VoiceRecording.ts index 62496ce3d9..c4a0a78ce5 100644 --- a/src/voice/VoiceRecording.ts +++ b/src/voice/VoiceRecording.ts @@ -33,7 +33,7 @@ const BITRATE = 24000; // 24kbps is pretty high quality for our use case in opus const TARGET_MAX_LENGTH = 120; // 2 minutes in seconds. Somewhat arbitrary, though longer == larger files. const TARGET_WARN_TIME_LEFT = 10; // 10 seconds, also somewhat arbitrary. -export const RECORDING_PLAYBACK_SAMPLES = 43; +export const RECORDING_PLAYBACK_SAMPLES = 44; export interface IRecordingUpdate { waveform: number[]; // floating points between 0 (low) and 1 (high). From ccdc9fbef6af3e3fd674517bde732168b3e7cfa8 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Tue, 4 May 2021 21:15:22 -0600 Subject: [PATCH 18/24] Fix issue where composer styles were being applied to the timeline --- res/css/views/rooms/_VoiceRecordComposerTile.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/css/views/rooms/_VoiceRecordComposerTile.scss b/res/css/views/rooms/_VoiceRecordComposerTile.scss index c0775b8371..b87211a847 100644 --- a/res/css/views/rooms/_VoiceRecordComposerTile.scss +++ b/res/css/views/rooms/_VoiceRecordComposerTile.scss @@ -46,7 +46,7 @@ limitations under the License. mask-image: url('$(res)/img/element-icons/trashcan.svg'); } -.mx_VoiceMessagePrimaryContainer { +.mx_VoiceRecordComposerTile_recording.mx_VoiceMessagePrimaryContainer { // Note: remaining class properties are in the PlayerContainer CSS. margin: 6px; // force the composer area to put a gutter around us From 374d8c1c4c44c57df0691db531b13efcea968260 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Wed, 5 May 2021 08:43:24 +0200 Subject: [PATCH 19/24] Update link to Android SDK MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 73afe34df0..81a4a00515 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ Platform Targets: * WebRTC features (VoIP and Video calling) are only available in Chrome & Firefox. * Mobile Web is not currently a target platform - instead please use the native iOS (https://github.com/matrix-org/matrix-ios-kit) and Android - (https://github.com/matrix-org/matrix-android-sdk) SDKs. + (https://github.com/vector-im/element-android) SDKs. All code lands on the `develop` branch - `master` is only used for stable releases. **Please file PRs against `develop`!!** From 07f5b6e8c48bd11d593408b72b27e443e754288c Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 5 May 2021 11:45:12 +0100 Subject: [PATCH 20/24] Add retry mechanism and progress bar to add existing to space dialog --- .../dialogs/_AddExistingToSpaceDialog.scss | 77 ++++++++-- .../dialogs/AddExistingToSpaceDialog.tsx | 134 ++++++++++++------ src/i18n/strings/en_EN.json | 9 +- 3 files changed, 162 insertions(+), 58 deletions(-) diff --git a/res/css/views/dialogs/_AddExistingToSpaceDialog.scss b/res/css/views/dialogs/_AddExistingToSpaceDialog.scss index 84f965e6bd..c29c9791a6 100644 --- a/res/css/views/dialogs/_AddExistingToSpaceDialog.scss +++ b/res/css/views/dialogs/_AddExistingToSpaceDialog.scss @@ -101,7 +101,7 @@ limitations under the License. .mx_BaseAvatar { display: inline-flex; - margin: 5px 16px 5px 5px; + margin: auto 16px auto 5px; vertical-align: middle; } @@ -160,31 +160,32 @@ limitations under the License. } } - .mx_AddExistingToSpaceDialog_errorText { - font-weight: $font-semi-bold; - font-size: $font-12px; - line-height: $font-15px; - color: $notice-primary-color; - margin-bottom: 28px; - } - .mx_AddExistingToSpace { display: contents; } .mx_AddExistingToSpaceDialog_footer { display: flex; - margin-top: 32px; + margin-top: 20px; > span { flex-grow: 1; - font-size: $font-14px; + font-size: $font-12px; line-height: $font-15px; - font-weight: $font-semi-bold; + color: $secondary-fg-color; - .mx_AccessibleButton { - font-size: inherit; - display: inline-block; + .mx_ProgressBar { + height: 8px; + width: 100%; + + @mixin ProgressBarBorderRadius "8px"; + } + + .mx_AddExistingToSpaceDialog_progressText { + margin-top: 8px; + font-size: $font-15px; + line-height: $font-24px; + color: $primary-fg-color; } > * { @@ -192,8 +193,54 @@ limitations under the License. } } + .mx_AddExistingToSpaceDialog_error { + padding-left: 12px; + + > img { + align-self: center; + } + + .mx_AddExistingToSpaceDialog_errorHeading { + font-weight: $font-semi-bold; + font-size: $font-15px; + line-height: $font-18px; + color: $notice-primary-color; + } + + .mx_AddExistingToSpaceDialog_errorCaption { + margin-top: 4px; + font-size: $font-12px; + line-height: $font-15px; + color: $primary-fg-color; + } + } + .mx_AccessibleButton { display: inline-block; + align-self: center; + } + + .mx_AccessibleButton_kind_primary { + padding: 8px 36px; + } + + .mx_AddExistingToSpaceDialog_retryButton { + margin-left: 12px; + padding-left: 24px; + position: relative; + + &::before { + content: ''; + position: absolute; + background-color: $primary-fg-color; + mask-repeat: no-repeat; + mask-position: center; + mask-size: contain; + mask-image: url('$(res)/img/element-icons/retry.svg'); + width: 18px; + height: 18px; + left: 0; + } } .mx_AccessibleButton_kind_link { diff --git a/src/components/views/dialogs/AddExistingToSpaceDialog.tsx b/src/components/views/dialogs/AddExistingToSpaceDialog.tsx index 2253b525e0..a33248200c 100644 --- a/src/components/views/dialogs/AddExistingToSpaceDialog.tsx +++ b/src/components/views/dialogs/AddExistingToSpaceDialog.tsx @@ -29,12 +29,13 @@ import RoomAvatar from "../avatars/RoomAvatar"; import {getDisplayAliasForRoom} from "../../../Rooms"; import AccessibleButton from "../elements/AccessibleButton"; import AutoHideScrollbar from "../../structures/AutoHideScrollbar"; -import {allSettled} from "../../../utils/promise"; +import {sleep} from "../../../utils/promise"; import DMRoomMap from "../../../utils/DMRoomMap"; import {calculateRoomVia} from "../../../utils/permalinks/Permalinks"; import StyledCheckbox from "../elements/StyledCheckbox"; import MatrixClientContext from "../../../contexts/MatrixClientContext"; import {sortRooms} from "../../../stores/room-list/algorithms/tag-sorting/RecentAlgorithm"; +import ProgressBar from "../elements/ProgressBar"; interface IProps extends IDialogProps { matrixClient: MatrixClient; @@ -46,7 +47,11 @@ const Entry = ({ room, checked, onChange }) => { return ; }; @@ -104,9 +109,9 @@ export const AddExistingToSpace: React.FC = ({ space, key={room.roomId} room={room} checked={selected.has(room)} - onChange={(checked) => { + onChange={onChange ? (checked) => { onChange(checked, room); - }} + } : null} />; }) }
@@ -120,9 +125,9 @@ export const AddExistingToSpace: React.FC = ({ space, key={space.roomId} room={space} checked={selected.has(space)} - onChange={(checked) => { + onChange={onChange ? (checked) => { onChange(checked, space); - }} + } : null} />; }) }
@@ -136,9 +141,9 @@ export const AddExistingToSpace: React.FC = ({ space, key={room.roomId} room={room} checked={selected.has(room)} - onChange={(checked) => { + onChange={onChange ? (checked) => { onChange(checked, room); - }} + } : null} />; }) }
@@ -156,8 +161,8 @@ const AddExistingToSpaceDialog: React.FC = ({ matrixClient: cli, space, const existingSubspaces = SpaceStore.instance.getChildSpaces(space.roomId); const [selectedToAdd, setSelectedToAdd] = useState(new Set()); - const [busy, setBusy] = useState(false); - const [error, setError] = useState(""); + const [progress, setProgress] = useState(null); + const [error, setError] = useState(null); let spaceOptionSection; if (existingSubspaces.length > 0) { @@ -197,6 +202,82 @@ const AddExistingToSpaceDialog: React.FC = ({ matrixClient: cli, space, ; + const addRooms = async () => { + setError(null); + setProgress(0); + + let error; + + for (const room of selectedToAdd) { + const via = calculateRoomVia(room); + try { + await SpaceStore.instance.addRoomToSpace(space, room.roomId, via).catch(async e => { + if (e.errcode === "M_LIMIT_EXCEEDED") { + await sleep(e.data.retry_after_ms); + return SpaceStore.instance.addRoomToSpace(space, room.roomId, via); // retry + } + + throw e; + }); + setProgress(i => i + 1); + } catch (e) { + console.error("Failed to add rooms to space", e); + setError(error = e); + break; + } + } + + if (!error) { + onFinished(true); + } + }; + + const busy = progress !== null; + + let footer; + if (error) { + footer = <> + + + +
{ _t("Not all selected were added") }
+
{ _t("Try again") }
+
+ + + { _t("Retry") } + + ; + } else if (busy) { + footer = + +
+ { _t("Adding rooms... (%(progress)s out of %(count)s)", { + count: selectedToAdd.size, + progress, + }) } +
+
; + } else { + footer = <> + +
{ _t("Want to add a new room instead?") }
+ onCreateRoomClick(cli, space)} kind="link"> + { _t("Create a new room") } + +
+ + + { _t("Add") } + + ; + } + return = ({ matrixClient: cli, space, onFinished={onFinished} fixedWidth={false} > - { error &&
{ error }
} - { + onChange={!busy && !error ? (checked, room) => { if (checked) { selectedToAdd.add(room); } else { selectedToAdd.delete(room); } setSelectedToAdd(new Set(selectedToAdd)); - }} + } : null} />
- -
{ _t("Don't want to add an existing room?") }
- onCreateRoomClick(cli, space)} kind="link"> - { _t("Create a new room") } - -
- - { - // TODO rate limiting - setBusy(true); - try { - await allSettled(Array.from(selectedToAdd).map((room) => - SpaceStore.instance.addRoomToSpace(space, room.roomId, calculateRoomVia(room)))); - onFinished(true); - } catch (e) { - console.error("Failed to add rooms to space", e); - setError(_t("Failed to add rooms to space")); - } - setBusy(false); - }} - > - { busy ? _t("Adding...") : _t("Add") } - + { footer }
; }; diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 2e5431620d..6888148873 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -2033,10 +2033,11 @@ "Direct Messages": "Direct Messages", "Space selection": "Space selection", "Add existing rooms": "Add existing rooms", - "Don't want to add an existing room?": "Don't want to add an existing room?", + "Not all selected were added": "Not all selected were added", + "Adding rooms... (%(progress)s out of %(count)s)|other": "Adding rooms... (%(progress)s out of %(count)s)", + "Adding rooms... (%(progress)s out of %(count)s)|one": "Adding room...", + "Want to add a new room instead?": "Want to add a new room instead?", "Create a new room": "Create a new room", - "Failed to add rooms to space": "Failed to add rooms to space", - "Adding...": "Adding...", "Matrix ID": "Matrix ID", "Matrix Room ID": "Matrix Room ID", "email address": "email address", @@ -2675,6 +2676,8 @@ "Failed to create initial space rooms": "Failed to create initial space rooms", "Skip for now": "Skip for now", "Creating rooms...": "Creating rooms...", + "Failed to add rooms to space": "Failed to add rooms to space", + "Adding...": "Adding...", "What do you want to organise?": "What do you want to organise?", "Pick rooms or conversations to add. This is just a space for you, no one will be informed. You can add more later.": "Pick rooms or conversations to add. This is just a space for you, no one will be informed. You can add more later.", "Share %(name)s": "Share %(name)s", From acce9a4548c449f7347f0c077f333375b5ec253b Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 5 May 2021 11:50:55 +0100 Subject: [PATCH 21/24] Fix rounded progress bars --- res/css/views/dialogs/_AddExistingToSpaceDialog.scss | 2 +- res/css/views/elements/_ProgressBar.scss | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/res/css/views/dialogs/_AddExistingToSpaceDialog.scss b/res/css/views/dialogs/_AddExistingToSpaceDialog.scss index c29c9791a6..524f107165 100644 --- a/res/css/views/dialogs/_AddExistingToSpaceDialog.scss +++ b/res/css/views/dialogs/_AddExistingToSpaceDialog.scss @@ -178,7 +178,7 @@ limitations under the License. height: 8px; width: 100%; - @mixin ProgressBarBorderRadius "8px"; + @mixin ProgressBarBorderRadius 8px; } .mx_AddExistingToSpaceDialog_progressText { diff --git a/res/css/views/elements/_ProgressBar.scss b/res/css/views/elements/_ProgressBar.scss index 770978e921..c075ac74ff 100644 --- a/res/css/views/elements/_ProgressBar.scss +++ b/res/css/views/elements/_ProgressBar.scss @@ -21,7 +21,7 @@ progress.mx_ProgressBar { appearance: none; border: none; - @mixin ProgressBarBorderRadius "6px"; + @mixin ProgressBarBorderRadius 6px; @mixin ProgressBarColour $progressbar-fg-color; @mixin ProgressBarBgColour $progressbar-bg-color; ::-webkit-progress-value { From 886959f32df0170ad65c1a95c3f8cdd9f56e325e Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 5 May 2021 11:54:14 +0100 Subject: [PATCH 22/24] port rate limiting code over to space creation wizard's add existing rooms --- src/components/structures/SpaceRoomView.tsx | 27 ++++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/src/components/structures/SpaceRoomView.tsx b/src/components/structures/SpaceRoomView.tsx index cdf9dc02d3..a7a95d711c 100644 --- a/src/components/structures/SpaceRoomView.tsx +++ b/src/components/structures/SpaceRoomView.tsx @@ -52,7 +52,7 @@ import {useStateToggle} from "../../hooks/useStateToggle"; import SpaceStore from "../../stores/SpaceStore"; import FacePile from "../views/elements/FacePile"; import {AddExistingToSpace} from "../views/dialogs/AddExistingToSpaceDialog"; -import {allSettled} from "../../utils/promise"; +import {sleep} from "../../utils/promise"; import {calculateRoomVia} from "../../utils/permalinks/Permalinks"; interface IProps { @@ -389,15 +389,24 @@ const SpaceAddExistingRooms = ({ space, onFinished }) => { let buttonLabel = _t("Skip for now"); if (selectedToAdd.size > 0) { onClick = async () => { - // TODO rate limiting setBusy(true); - try { - await allSettled(Array.from(selectedToAdd).map((room) => - SpaceStore.instance.addRoomToSpace(space, room.roomId, calculateRoomVia(room)))); - onFinished(true); - } catch (e) { - console.error("Failed to add rooms to space", e); - setError(_t("Failed to add rooms to space")); + + for (const room of selectedToAdd) { + const via = calculateRoomVia(room); + try { + await SpaceStore.instance.addRoomToSpace(space, room.roomId, via).catch(async e => { + if (e.errcode === "M_LIMIT_EXCEEDED") { + await sleep(e.data.retry_after_ms); + return SpaceStore.instance.addRoomToSpace(space, room.roomId, via); // retry + } + + throw e; + }); + } catch (e) { + console.error("Failed to add rooms to space", e); + setError(_t("Failed to add rooms to space")); + break; + } } setBusy(false); }; From 570c082573942a65fd1cf6052d498138c97f5f15 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Wed, 5 May 2021 09:58:45 -0600 Subject: [PATCH 23/24] Promote colour to a variable I refuse to try and type this variable name freehand. --- res/themes/dark/css/_dark.scss | 7 ++++--- res/themes/light/css/_light.scss | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/res/themes/dark/css/_dark.scss b/res/themes/dark/css/_dark.scss index 334bf581f3..d31b67d4ab 100644 --- a/res/themes/dark/css/_dark.scss +++ b/res/themes/dark/css/_dark.scss @@ -9,6 +9,7 @@ $header-panel-text-primary-color: #B9BEC6; $header-panel-text-secondary-color: #c8c8cd; $text-primary-color: #ffffff; $text-secondary-color: #B9BEC6; +$quaternary-fg-color: #6F7882; $search-bg-color: #181b21; $search-placeholder-color: #61708b; $room-highlight-color: #343a46; @@ -42,11 +43,11 @@ $preview-bar-bg-color: $header-panel-bg-color; $groupFilterPanel-bg-color: rgba(38, 39, 43, 0.82); $inverted-bg-color: $base-color; -$voice-record-stop-border-color: #6F7882; // "Quartary" +$voice-record-stop-border-color: $quaternary-fg-color; $voice-record-waveform-bg-color: #394049; // "Dark Tile" $voice-record-waveform-fg-color: $secondary-fg-color; -$voice-record-waveform-incomplete-fg-color: #6F7882; // "Quartary" -$voice-record-icon-color: #6F7882; // "Quartary" +$voice-record-waveform-incomplete-fg-color: $quaternary-fg-color; +$voice-record-icon-color: $quaternary-fg-color; $voice-playback-button-bg-color: $tertiary-fg-color; $voice-playback-button-fg-color: #21262C; // "Separator" diff --git a/res/themes/light/css/_light.scss b/res/themes/light/css/_light.scss index 193b7f816c..240e78b1e2 100644 --- a/res/themes/light/css/_light.scss +++ b/res/themes/light/css/_light.scss @@ -21,6 +21,7 @@ $notice-primary-bg-color: rgba(255, 75, 85, 0.16); $primary-fg-color: #2e2f32; $secondary-fg-color: #737D8C; $tertiary-fg-color: #8D99A5; +$quaternary-fg-color: #C1C6CD; $header-panel-bg-color: #f3f8fd; // typical text (dark-on-white in light skin) @@ -190,7 +191,7 @@ $voice-record-live-circle-color: #ff4b55; $voice-record-stop-border-color: #E3E8F0; // "Separator" $voice-record-waveform-bg-color: #E3E8F0; // "Separator" $voice-record-waveform-fg-color: $secondary-fg-color; -$voice-record-waveform-incomplete-fg-color: #C1C6CD; // "Quartary" +$voice-record-waveform-incomplete-fg-color: $quaternary-fg-color; $voice-record-icon-color: $tertiary-fg-color; $voice-playback-button-bg-color: $primary-bg-color; $voice-playback-button-fg-color: $secondary-fg-color; From 39ef376a793a26efcb34576a66f3aee21976826a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Wed, 5 May 2021 18:06:42 +0200 Subject: [PATCH 24/24] Use Android SDK instead Co-authored-by: J. Ryan Stinnett --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 81a4a00515..b3e96ef001 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ Platform Targets: * WebRTC features (VoIP and Video calling) are only available in Chrome & Firefox. * Mobile Web is not currently a target platform - instead please use the native iOS (https://github.com/matrix-org/matrix-ios-kit) and Android - (https://github.com/vector-im/element-android) SDKs. + (https://github.com/matrix-org/matrix-android-sdk2) SDKs. All code lands on the `develop` branch - `master` is only used for stable releases. **Please file PRs against `develop`!!**