From 7d22bbc00f49356cd5fec3565a19376ef8b0ef05 Mon Sep 17 00:00:00 2001 From: Bryan Kok Date: Sat, 17 Oct 2020 23:52:18 +0800 Subject: [PATCH 001/457] Trim spurious whitespace of nicknames --- src/components/views/settings/ProfileSettings.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/components/views/settings/ProfileSettings.js b/src/components/views/settings/ProfileSettings.js index 92851ccaa0..294f80acd1 100644 --- a/src/components/views/settings/ProfileSettings.js +++ b/src/components/views/settings/ProfileSettings.js @@ -77,10 +77,12 @@ export default class ProfileSettings extends React.Component { const client = MatrixClientPeg.get(); const newState = {}; + const displayName = this.state.displayName.trim(); try { if (this.state.originalDisplayName !== this.state.displayName) { - await client.setDisplayName(this.state.displayName); - newState.originalDisplayName = this.state.displayName; + await client.setDisplayName(displayName); + newState.originalDisplayName = displayName; + newState.displayName = displayName; } if (this.state.avatarFile) { From fcbaea640daf3a036d55cb1bda5d7fed552c2d4e Mon Sep 17 00:00:00 2001 From: Bryan Kok Date: Sun, 18 Oct 2020 14:36:50 +0800 Subject: [PATCH 002/457] Trim room names changed through the UI --- src/components/views/room_settings/RoomProfileSettings.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/components/views/room_settings/RoomProfileSettings.js b/src/components/views/room_settings/RoomProfileSettings.js index ca09c3093a..b894663c16 100644 --- a/src/components/views/room_settings/RoomProfileSettings.js +++ b/src/components/views/room_settings/RoomProfileSettings.js @@ -95,10 +95,11 @@ export default class RoomProfileSettings extends React.Component { const newState = {}; // TODO: What do we do about errors? - + const displayName = this.state.displayName.trim(); if (this.state.originalDisplayName !== this.state.displayName) { - await client.setRoomName(this.props.roomId, this.state.displayName); - newState.originalDisplayName = this.state.displayName; + await client.setRoomName(this.props.roomId, displayName); + newState.originalDisplayName = displayName; + newState.displayName = displayName; } if (this.state.avatarFile) { From 2f988bc97fc1e414bd70149ac5f77301a3ef2833 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Thu, 26 Nov 2020 13:51:03 +0100 Subject: [PATCH 003/457] Added UI --- .../views/settings/SpellCheckSettings.tsx | 111 ++++++++++++++++++ .../tabs/user/GeneralUserSettingsTab.js | 18 +++ 2 files changed, 129 insertions(+) create mode 100644 src/components/views/settings/SpellCheckSettings.tsx diff --git a/src/components/views/settings/SpellCheckSettings.tsx b/src/components/views/settings/SpellCheckSettings.tsx new file mode 100644 index 0000000000..1bdcd882c9 --- /dev/null +++ b/src/components/views/settings/SpellCheckSettings.tsx @@ -0,0 +1,111 @@ +/* +Copyright 2019 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import React from 'react'; +import LanguageDropdown from "../../../components/views/elements/LanguageDropdown"; +import AccessibleButton from "../../../components/views/elements/AccessibleButton"; +import {_t} from "../../../languageHandler"; + +interface ExistingSpellCheckLanguageIProps { + language: string, + onRemoved(language: string), +}; + +interface SpellCheckLanguagesIProps { + languages: Array, + onLanguagesChange(languages: Array), +}; + +interface SpellCheckLanguagesIState { + newLanguage: string, +} + +export class ExistingSpellCheckLanguage extends React.Component { + _onRemove = (e) => { + e.stopPropagation(); + e.preventDefault(); + + return this.props.onRemoved(this.props.language); + }; + + render() { + return ( +
+ {this.props.language} + + {_t("Remove")} + +
+ ); + } +} + +export default class SpellCheckLanguages extends React.Component { + constructor(props) { + super(props); + this.state = { + newLanguage: "", + } + } + + _onRemoved = (language) => { + const languages = this.props.languages.filter((e) => e !== language); + this.props.onLanguagesChange(languages); + }; + + _onAddClick = (e) => { + e.stopPropagation(); + e.preventDefault(); + + const language = this.state.newLanguage; + + if (!language) return; + if (this.props.languages.includes(language)) return; + + this.props.languages.push(language) + this.props.onLanguagesChange(this.props.languages); + }; + + _onNewLanguageChange = (language: string) => { + if (this.state.newLanguage === language) return; + this.setState({newLanguage: language}); + }; + + render() { + const existingSpellCheckLanguages = this.props.languages.map((e) => { + return ; + }); + + let addButton = ( + + {_t("Add")} + + ); + + return ( +
+ {existingSpellCheckLanguages} +
+ + {addButton} + +
+ ); + }; +} diff --git a/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js b/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js index 35285351ab..6d04d83047 100644 --- a/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js +++ b/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js @@ -22,6 +22,7 @@ import ProfileSettings from "../../ProfileSettings"; import * as languageHandler from "../../../../../languageHandler"; import SettingsStore from "../../../../../settings/SettingsStore"; import LanguageDropdown from "../../../elements/LanguageDropdown"; +import SpellCheckSettings from "../../SpellCheckSettings" import AccessibleButton from "../../../elements/AccessibleButton"; import DeactivateAccountDialog from "../../../dialogs/DeactivateAccountDialog"; import PropTypes from "prop-types"; @@ -49,6 +50,7 @@ export default class GeneralUserSettingsTab extends React.Component { this.state = { language: languageHandler.getCurrentLanguage(), + spellCheckLanguages: [], haveIdServer: Boolean(MatrixClientPeg.get().getIdentityServerUrl()), serverSupportsSeparateAddAndBind: null, idServerHasUnsignedTerms: false, @@ -182,6 +184,10 @@ export default class GeneralUserSettingsTab extends React.Component { PlatformPeg.get().reload(); }; + _onSpellCheckLanguagesChange = (languages) => { + this.setState({spellCheckLanguages: languages}) + }; + _onPasswordChangeError = (err) => { // TODO: Figure out a design that doesn't involve replacing the current dialog let errMsg = err.error || ""; @@ -303,6 +309,17 @@ export default class GeneralUserSettingsTab extends React.Component { ); } + _renderSpellCheckSection() { + return ( +
+ {_t("Spell checking")} + +
+ ); + } + _renderDiscoverySection() { const SetIdServer = sdk.getComponent("views.settings.SetIdServer"); @@ -409,6 +426,7 @@ export default class GeneralUserSettingsTab extends React.Component { {this._renderProfileSection()} {this._renderAccountSection()} {this._renderLanguageSection()} + {this._renderSpellCheckSection()} { discoverySection } {this._renderIntegrationManagerSection() /* Has its own title */} { accountManagementSection } From 051368eaab50e4a7d6f2ce554ddff0ed957bb965 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Thu, 26 Nov 2020 13:53:22 +0100 Subject: [PATCH 004/457] Fix i18n --- src/i18n/strings/en_EN.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 0d50128f32..7fbcc1a350 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1109,6 +1109,7 @@ "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.", + "Add": "Add", "Error encountered (%(errorDetail)s).": "Error encountered (%(errorDetail)s).", "Checking for an update...": "Checking for an update...", "No update available.": "No update available.", @@ -1140,6 +1141,7 @@ "Set a new account password...": "Set a new account password...", "Account": "Account", "Language and region": "Language and region", + "Spell checking": "Spell checking", "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!", @@ -1337,7 +1339,6 @@ "Invalid Email Address": "Invalid Email Address", "This doesn't appear to be a valid email address": "This doesn't appear to be a valid email address", "Unable to add email address": "Unable to add email address", - "Add": "Add", "We've sent you an email to verify your address. Please follow the instructions there and then click the button below.": "We've sent you an email to verify your address. Please follow the instructions there and then click the button below.", "Email Address": "Email Address", "Remove %(phone)s?": "Remove %(phone)s?", From 557e650a2c2e2eb24584f21bd4175e69cc7500a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Sat, 28 Nov 2020 19:37:49 +0100 Subject: [PATCH 005/457] Added spell-check-languages setting --- src/settings/Settings.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/settings/Settings.ts b/src/settings/Settings.ts index 31e133be72..409cd293d2 100644 --- a/src/settings/Settings.ts +++ b/src/settings/Settings.ts @@ -402,6 +402,10 @@ export const SETTINGS: {[setting: string]: ISetting} = { supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG, default: "en", }, + "spell-check-languages": { + supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG, + default: [], + }, "breadcrumb_rooms": { // not really a setting supportedLevels: [SettingLevel.ACCOUNT], From 43daec03e24820a485f97da0b5cb0311f137e729 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Sat, 28 Nov 2020 19:38:52 +0100 Subject: [PATCH 006/457] Added setSpellCheckLanguages() method --- src/languageHandler.tsx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/languageHandler.tsx b/src/languageHandler.tsx index b61f57d4b3..9b9e304294 100644 --- a/src/languageHandler.tsx +++ b/src/languageHandler.tsx @@ -346,6 +346,13 @@ export function setLanguage(preferredLangs: string | string[]) { }); } +export function setSpellCheckLanguages(preferredLangs: string[]) { + const plaf = PlatformPeg.get(); + if (plaf) { + plaf.setLanguage(preferredLangs); + } +} + export function getAllLanguagesFromJson() { return getLangsJson().then((langsObject) => { const langs = []; From 5e4f9907cf87e02b41791ce729b38d7474dcbf01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Sat, 28 Nov 2020 19:39:09 +0100 Subject: [PATCH 007/457] Added persistance --- .../views/settings/tabs/user/GeneralUserSettingsTab.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js b/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js index 6d04d83047..585f4fd5b7 100644 --- a/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js +++ b/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js @@ -50,7 +50,7 @@ export default class GeneralUserSettingsTab extends React.Component { this.state = { language: languageHandler.getCurrentLanguage(), - spellCheckLanguages: [], + spellCheckLanguages: SettingsStore.getValue("spell-check-languages", null, /*excludeDefault=*/true), haveIdServer: Boolean(MatrixClientPeg.get().getIdentityServerUrl()), serverSupportsSeparateAddAndBind: null, idServerHasUnsignedTerms: false, @@ -185,7 +185,9 @@ export default class GeneralUserSettingsTab extends React.Component { }; _onSpellCheckLanguagesChange = (languages) => { + SettingsStore.setValue("spell-check-languages", null, SettingLevel.DEVICE, languages); this.setState({spellCheckLanguages: languages}) + PlatformPeg.get().reload(); }; _onPasswordChangeError = (err) => { From f0bbed0c44270f8411c0ce0f4ee0cf08142a1c1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Sun, 29 Nov 2020 12:17:07 +0100 Subject: [PATCH 008/457] Allow default value --- .../views/settings/tabs/user/GeneralUserSettingsTab.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js b/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js index 585f4fd5b7..68a16463b0 100644 --- a/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js +++ b/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js @@ -50,7 +50,7 @@ export default class GeneralUserSettingsTab extends React.Component { this.state = { language: languageHandler.getCurrentLanguage(), - spellCheckLanguages: SettingsStore.getValue("spell-check-languages", null, /*excludeDefault=*/true), + spellCheckLanguages: SettingsStore.getValue("spell-check-languages", null, false), haveIdServer: Boolean(MatrixClientPeg.get().getIdentityServerUrl()), serverSupportsSeparateAddAndBind: null, idServerHasUnsignedTerms: false, From 8f40cd39fda1ee83ec6b177ba7935f913ed5a45b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Sun, 29 Nov 2020 12:29:05 +0100 Subject: [PATCH 009/457] Added styling --- res/css/_components.scss | 1 + .../views/settings/_SpellCheckLanguages.scss | 36 +++++++++++++++++++ .../views/settings/SpellCheckSettings.tsx | 9 +++-- .../tabs/user/GeneralUserSettingsTab.js | 7 ++-- 4 files changed, 44 insertions(+), 9 deletions(-) create mode 100644 res/css/views/settings/_SpellCheckLanguages.scss diff --git a/res/css/_components.scss b/res/css/_components.scss index 445ed70ff4..1eb4b91a31 100644 --- a/res/css/_components.scss +++ b/res/css/_components.scss @@ -207,6 +207,7 @@ @import "./views/settings/_DevicesPanel.scss"; @import "./views/settings/_E2eAdvancedPanel.scss"; @import "./views/settings/_EmailAddresses.scss"; +@import "./views/settings/_SpellCheckLanguages.scss"; @import "./views/settings/_IntegrationManager.scss"; @import "./views/settings/_Notifications.scss"; @import "./views/settings/_PhoneNumbers.scss"; diff --git a/res/css/views/settings/_SpellCheckLanguages.scss b/res/css/views/settings/_SpellCheckLanguages.scss new file mode 100644 index 0000000000..734f669f0e --- /dev/null +++ b/res/css/views/settings/_SpellCheckLanguages.scss @@ -0,0 +1,36 @@ +/* +Copyright 2019 New Vector Ltd +Copyright 2019 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +.mx_ExistingSpellCheckLanguage { + display: flex; + align-items: center; + margin-bottom: 5px; +} + +.mx_ExistingSpellCheckLanguage_language { + flex: 1; + margin-right: 10px; +} + +.mx_GeneralUserSettingsTab_spellCheckLanguageInput { + margin-top: 1em; + margin-bottom: 1em; +} + +.mx_SpellCheckLanguages { + @mixin mx_Settings_fullWidthField; +} \ No newline at end of file diff --git a/src/components/views/settings/SpellCheckSettings.tsx b/src/components/views/settings/SpellCheckSettings.tsx index 1bdcd882c9..befd98112e 100644 --- a/src/components/views/settings/SpellCheckSettings.tsx +++ b/src/components/views/settings/SpellCheckSettings.tsx @@ -43,8 +43,8 @@ export class ExistingSpellCheckLanguage extends React.Component - {this.props.language} +
+ {this.props.language} {_t("Remove")} @@ -96,10 +96,9 @@ export default class SpellCheckLanguages extends React.Component +
{existingSpellCheckLanguages} -
+ diff --git a/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js b/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js index 68a16463b0..258ff6d318 100644 --- a/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js +++ b/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js @@ -313,11 +313,10 @@ export default class GeneralUserSettingsTab extends React.Component { _renderSpellCheckSection() { return ( -
+
{_t("Spell checking")} - +
); } From 7609f2004e6a004c22e0da189f58cee823bf4468 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Sun, 29 Nov 2020 13:22:50 +0100 Subject: [PATCH 010/457] Added newline to end --- res/css/views/settings/_SpellCheckLanguages.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/css/views/settings/_SpellCheckLanguages.scss b/res/css/views/settings/_SpellCheckLanguages.scss index 734f669f0e..ddfa0bf9e0 100644 --- a/res/css/views/settings/_SpellCheckLanguages.scss +++ b/res/css/views/settings/_SpellCheckLanguages.scss @@ -33,4 +33,4 @@ limitations under the License. .mx_SpellCheckLanguages { @mixin mx_Settings_fullWidthField; -} \ No newline at end of file +} From ead00dcdede9e6a24904599baba39bc91de0681a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Sun, 29 Nov 2020 14:46:09 +0100 Subject: [PATCH 011/457] Set spell-check languages without reloading --- .../views/settings/tabs/user/GeneralUserSettingsTab.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js b/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js index 258ff6d318..ad7e04d677 100644 --- a/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js +++ b/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js @@ -187,7 +187,11 @@ export default class GeneralUserSettingsTab extends React.Component { _onSpellCheckLanguagesChange = (languages) => { SettingsStore.setValue("spell-check-languages", null, SettingLevel.DEVICE, languages); this.setState({spellCheckLanguages: languages}) - PlatformPeg.get().reload(); + + const plaf = PlatformPeg.get(); + if (plaf) { + plaf.setLanguage(languages); + } }; _onPasswordChangeError = (err) => { From 38080c5b2bccafb7dae5c9737e69ad7f295f1d7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Sun, 29 Nov 2020 20:46:47 +0100 Subject: [PATCH 012/457] Added getAvailableSpellCheckLanguages() methods --- src/BasePlatform.ts | 4 ++++ src/languageHandler.tsx | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/src/BasePlatform.ts b/src/BasePlatform.ts index 0a1f06f0b3..9ac35092a7 100644 --- a/src/BasePlatform.ts +++ b/src/BasePlatform.ts @@ -237,6 +237,10 @@ export default abstract class BasePlatform { setLanguage(preferredLangs: string[]) {} + getAvailableSpellCheckLanguages(): Promise | null { + return null; + } + protected getSSOCallbackUrl(fragmentAfterLogin: string): URL { const url = new URL(window.location.href); url.hash = fragmentAfterLogin || ""; diff --git a/src/languageHandler.tsx b/src/languageHandler.tsx index 9b9e304294..b827e83ded 100644 --- a/src/languageHandler.tsx +++ b/src/languageHandler.tsx @@ -353,6 +353,11 @@ export function setSpellCheckLanguages(preferredLangs: string[]) { } } +export async function getAvailableSpellCheckLanguages(): Promise { + const plaf = PlatformPeg.get(); + return plaf.getAvailableSpellCheckLanguages(); +} + export function getAllLanguagesFromJson() { return getLangsJson().then((langsObject) => { const langs = []; From 5d9f5ba979d3fc89bf6eec5ad2f319bea7168aec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Mon, 30 Nov 2020 08:35:51 +0100 Subject: [PATCH 013/457] Fix indentation --- src/components/views/elements/LanguageDropdown.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/views/elements/LanguageDropdown.js b/src/components/views/elements/LanguageDropdown.js index e37109caff..03ec456af5 100644 --- a/src/components/views/elements/LanguageDropdown.js +++ b/src/components/views/elements/LanguageDropdown.js @@ -100,10 +100,10 @@ export default class LanguageDropdown extends React.Component { let language = SettingsStore.getValue("language", null, /*excludeDefault:*/true); let value = null; if (language) { - value = this.props.value || language; + value = this.props.value || language; } else { - language = navigator.language || navigator.userLanguage; - value = this.props.value || language; + language = navigator.language || navigator.userLanguage; + value = this.props.value || language; } return Date: Tue, 1 Dec 2020 16:59:02 +0100 Subject: [PATCH 014/457] Change label --- .../views/settings/tabs/user/GeneralUserSettingsTab.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js b/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js index ad7e04d677..8d06ea3b36 100644 --- a/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js +++ b/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js @@ -318,7 +318,7 @@ export default class GeneralUserSettingsTab extends React.Component { _renderSpellCheckSection() { return (
- {_t("Spell checking")} + {_t("Spell check dictionaries")}
From cf61d50df40614a45c36c0d9886c3583ca69513e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Tue, 1 Dec 2020 16:59:21 +0100 Subject: [PATCH 015/457] Added SpellCheckLanguagesDropdown --- .../elements/SpellCheckLanguagesDropdown.tsx | 125 ++++++++++++++++++ .../views/settings/SpellCheckSettings.tsx | 4 +- 2 files changed, 127 insertions(+), 2 deletions(-) create mode 100644 src/components/views/elements/SpellCheckLanguagesDropdown.tsx diff --git a/src/components/views/elements/SpellCheckLanguagesDropdown.tsx b/src/components/views/elements/SpellCheckLanguagesDropdown.tsx new file mode 100644 index 0000000000..db158fa3dd --- /dev/null +++ b/src/components/views/elements/SpellCheckLanguagesDropdown.tsx @@ -0,0 +1,125 @@ +/* +Copyright 2017 Marcel Radzio (MTRNord) +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 PropTypes from 'prop-types'; + +import Dropdown from "../../views/elements/Dropdown" +import PlatformPeg from "../../../PlatformPeg"; +import * as sdk from '../../../index'; +import * as languageHandler from '../../../languageHandler'; +import SettingsStore from "../../../settings/SettingsStore"; +import { _t } from "../../../languageHandler"; + +function languageMatchesSearchQuery(query, language) { + if (language.label.toUpperCase().includes(query.toUpperCase())) return true; + if (language.value.toUpperCase() === query.toUpperCase()) return true; + return false; +} + +interface SpellCheckLanguagesDropdownIProps { + className: string, + value: string, + onOptionChange(language: string), +}; + +interface SpellCheckLanguagesDropdownIState { + searchQuery: string, + languages: any, +} + +export default class SpellCheckLanguagesDropdown extends React.Component { + constructor(props) { + super(props); + this._onSearchChange = this._onSearchChange.bind(this); + + this.state = { + searchQuery: '', + languages: null, + }; + } + + componentDidMount() { + languageHandler.getAvailableSpellCheckLanguages().then((languages) => { + languages.sort(function(a, b) { + if (a < b) return -1; + if (a > b) return 1; + return 0; + }); + var langs = []; + languages.forEach((language) => { + langs.push({ + label: language, + value: language, + }) + }) + this.setState({languages: langs}); + }).catch((e) => { + this.setState({languages: ['en']}); + }); + } + + _onSearchChange(search) { + this.setState({ + searchQuery: search, + }); + } + + render() { + if (this.state.languages === null) { + const Spinner = sdk.getComponent('elements.Spinner'); + return ; + } + + let displayedLanguages; + if (this.state.searchQuery) { + displayedLanguages = this.state.languages.filter((lang) => { + return languageMatchesSearchQuery(this.state.searchQuery, lang); + }); + } else { + displayedLanguages = this.state.languages; + } + + const options = displayedLanguages.map((language) => { + return
+ { language.label } +
; + }); + + // default value here too, otherwise we need to handle null / undefined; + // values between mounting and the initial value propgating + let language = SettingsStore.getValue("language", null, /*excludeDefault:*/true); + let value = null; + if (language) { + value = this.props.value || language; + } else { + language = navigator.language || navigator.userLanguage; + value = this.props.value || language; + } + + return + { options } + ; + } +} diff --git a/src/components/views/settings/SpellCheckSettings.tsx b/src/components/views/settings/SpellCheckSettings.tsx index befd98112e..37476d5f34 100644 --- a/src/components/views/settings/SpellCheckSettings.tsx +++ b/src/components/views/settings/SpellCheckSettings.tsx @@ -15,7 +15,7 @@ limitations under the License. */ import React from 'react'; -import LanguageDropdown from "../../../components/views/elements/LanguageDropdown"; +import SpellCheckLanguagesDropdown from "../../../components/views/elements/SpellCheckLanguagesDropdown"; import AccessibleButton from "../../../components/views/elements/AccessibleButton"; import {_t} from "../../../languageHandler"; @@ -99,7 +99,7 @@ export default class SpellCheckLanguages extends React.Component {existingSpellCheckLanguages} - {addButton} From a6d6af1a937fb6bc6cec2e320fbff453bef3c680 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Tue, 1 Dec 2020 17:19:45 +0100 Subject: [PATCH 016/457] Added defaults --- src/settings/Settings.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/settings/Settings.ts b/src/settings/Settings.ts index 409cd293d2..c83dbab897 100644 --- a/src/settings/Settings.ts +++ b/src/settings/Settings.ts @@ -404,7 +404,7 @@ export const SETTINGS: {[setting: string]: ISetting} = { }, "spell-check-languages": { supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG, - default: [], + default: ["en"], }, "breadcrumb_rooms": { // not really a setting From e9203d75715dbd6a677849dbb83a3d4706b2e6e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Tue, 1 Dec 2020 17:21:23 +0100 Subject: [PATCH 017/457] Removed unnecessary imports --- src/components/views/elements/SpellCheckLanguagesDropdown.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/components/views/elements/SpellCheckLanguagesDropdown.tsx b/src/components/views/elements/SpellCheckLanguagesDropdown.tsx index db158fa3dd..5e0fe3132c 100644 --- a/src/components/views/elements/SpellCheckLanguagesDropdown.tsx +++ b/src/components/views/elements/SpellCheckLanguagesDropdown.tsx @@ -16,10 +16,8 @@ limitations under the License. */ import React from 'react'; -import PropTypes from 'prop-types'; import Dropdown from "../../views/elements/Dropdown" -import PlatformPeg from "../../../PlatformPeg"; import * as sdk from '../../../index'; import * as languageHandler from '../../../languageHandler'; import SettingsStore from "../../../settings/SettingsStore"; From 8287f197f40869941d402e45da87c88d19514545 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Tue, 1 Dec 2020 19:49:31 +0100 Subject: [PATCH 018/457] Fix i18n --- 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 282c1ce686..9ccd0e1e75 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1149,7 +1149,7 @@ "Set a new account password...": "Set a new account password...", "Account": "Account", "Language and region": "Language and region", - "Spell checking": "Spell checking", + "Spell check dictionaries": "Spell check dictionaries", "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!", From 44a363f188fb95927fff942b4c6b5a3914dbe31d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Tue, 1 Dec 2020 20:16:48 +0100 Subject: [PATCH 019/457] Fix default value --- src/settings/Settings.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/settings/Settings.ts b/src/settings/Settings.ts index c83dbab897..3540767a99 100644 --- a/src/settings/Settings.ts +++ b/src/settings/Settings.ts @@ -404,7 +404,7 @@ export const SETTINGS: {[setting: string]: ISetting} = { }, "spell-check-languages": { supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG, - default: ["en"], + default: ["en-US"], }, "breadcrumb_rooms": { // not really a setting From 3c2bb6e4f6d19e337d902613adbddf42fcba2f3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Tue, 1 Dec 2020 20:17:24 +0100 Subject: [PATCH 020/457] Cleanup --- src/BasePlatform.ts | 2 ++ .../views/settings/tabs/user/GeneralUserSettingsTab.js | 5 +---- src/languageHandler.tsx | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/BasePlatform.ts b/src/BasePlatform.ts index 9ac35092a7..2af2ea51c5 100644 --- a/src/BasePlatform.ts +++ b/src/BasePlatform.ts @@ -237,6 +237,8 @@ export default abstract class BasePlatform { setLanguage(preferredLangs: string[]) {} + setSpellCheckLanguages(preferredLangs: string[]) {} + getAvailableSpellCheckLanguages(): Promise | null { return null; } diff --git a/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js b/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js index 8d06ea3b36..6ed887d749 100644 --- a/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js +++ b/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js @@ -188,10 +188,7 @@ export default class GeneralUserSettingsTab extends React.Component { SettingsStore.setValue("spell-check-languages", null, SettingLevel.DEVICE, languages); this.setState({spellCheckLanguages: languages}) - const plaf = PlatformPeg.get(); - if (plaf) { - plaf.setLanguage(languages); - } + languageHandler.setSpellCheckLanguages(languages); }; _onPasswordChangeError = (err) => { diff --git a/src/languageHandler.tsx b/src/languageHandler.tsx index b827e83ded..38d3c8347a 100644 --- a/src/languageHandler.tsx +++ b/src/languageHandler.tsx @@ -349,7 +349,7 @@ export function setLanguage(preferredLangs: string | string[]) { export function setSpellCheckLanguages(preferredLangs: string[]) { const plaf = PlatformPeg.get(); if (plaf) { - plaf.setLanguage(preferredLangs); + plaf.setSpellCheckLanguages(preferredLangs); } } From db5bc0cb7ade92fc056283af639e3c782d384e4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Tue, 1 Dec 2020 20:36:25 +0100 Subject: [PATCH 021/457] Fix formatting --- .../elements/SpellCheckLanguagesDropdown.tsx | 7 ++++--- .../views/settings/SpellCheckSettings.tsx | 17 +++++++++-------- .../tabs/user/GeneralUserSettingsTab.js | 6 +++--- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/components/views/elements/SpellCheckLanguagesDropdown.tsx b/src/components/views/elements/SpellCheckLanguagesDropdown.tsx index 5e0fe3132c..53c3f310b7 100644 --- a/src/components/views/elements/SpellCheckLanguagesDropdown.tsx +++ b/src/components/views/elements/SpellCheckLanguagesDropdown.tsx @@ -33,14 +33,15 @@ interface SpellCheckLanguagesDropdownIProps { className: string, value: string, onOptionChange(language: string), -}; +} interface SpellCheckLanguagesDropdownIState { searchQuery: string, languages: any, } -export default class SpellCheckLanguagesDropdown extends React.Component { +export default class SpellCheckLanguagesDropdown extends React.Component { constructor(props) { super(props); this._onSearchChange = this._onSearchChange.bind(this); @@ -58,7 +59,7 @@ export default class SpellCheckLanguagesDropdown extends React.Component b) return 1; return 0; }); - var langs = []; + const langs = []; languages.forEach((language) => { langs.push({ label: language, diff --git a/src/components/views/settings/SpellCheckSettings.tsx b/src/components/views/settings/SpellCheckSettings.tsx index 37476d5f34..bfe0774570 100644 --- a/src/components/views/settings/SpellCheckSettings.tsx +++ b/src/components/views/settings/SpellCheckSettings.tsx @@ -22,12 +22,12 @@ import {_t} from "../../../languageHandler"; interface ExistingSpellCheckLanguageIProps { language: string, onRemoved(language: string), -}; +} interface SpellCheckLanguagesIProps { languages: Array, onLanguagesChange(languages: Array), -}; +} interface SpellCheckLanguagesIState { newLanguage: string, @@ -71,7 +71,7 @@ export default class SpellCheckLanguages extends React.Component; }); - let addButton = ( + const addButton = ( {_t("Add")} @@ -99,12 +99,13 @@ export default class SpellCheckLanguages extends React.Component {existingSpellCheckLanguages} - + {addButton}
); - }; + } } diff --git a/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js b/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js index 6ed887d749..95a8abbb24 100644 --- a/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js +++ b/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js @@ -22,7 +22,7 @@ import ProfileSettings from "../../ProfileSettings"; import * as languageHandler from "../../../../../languageHandler"; import SettingsStore from "../../../../../settings/SettingsStore"; import LanguageDropdown from "../../../elements/LanguageDropdown"; -import SpellCheckSettings from "../../SpellCheckSettings" +import SpellCheckSettings from "../../SpellCheckSettings"; import AccessibleButton from "../../../elements/AccessibleButton"; import DeactivateAccountDialog from "../../../dialogs/DeactivateAccountDialog"; import PropTypes from "prop-types"; @@ -186,8 +186,8 @@ export default class GeneralUserSettingsTab extends React.Component { _onSpellCheckLanguagesChange = (languages) => { SettingsStore.setValue("spell-check-languages", null, SettingLevel.DEVICE, languages); - this.setState({spellCheckLanguages: languages}) - + this.setState({spellCheckLanguages: languages}); + languageHandler.setSpellCheckLanguages(languages); }; From bab541a652e402c1aede8caa00b22b13a2adb0c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Wed, 2 Dec 2020 20:14:58 +0100 Subject: [PATCH 022/457] Hide spell-check settings if not using Electron --- src/BasePlatform.ts | 8 ++++++++ .../views/settings/tabs/user/GeneralUserSettingsTab.js | 5 ++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/BasePlatform.ts b/src/BasePlatform.ts index 2af2ea51c5..54d15675cb 100644 --- a/src/BasePlatform.ts +++ b/src/BasePlatform.ts @@ -128,6 +128,14 @@ export default abstract class BasePlatform { hideUpdateToast(); } + /** + * Return true if platform supports multi-language + * spell-checking, otherwise false. + */ + supportsMultiLanguageSpellCheck(): boolean { + return false; + } + /** * Returns true if the platform supports displaying * notifications, otherwise false. diff --git a/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js b/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js index 95a8abbb24..4d1210dc40 100644 --- a/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js +++ b/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js @@ -400,6 +400,9 @@ export default class GeneralUserSettingsTab extends React.Component { } render() { + const plaf = PlatformPeg.get(); + const supportsMultiLanguageSpellCheck = plaf.supportsMultiLanguageSpellCheck() ? true : false; + const discoWarning = this.state.requiredPolicyInfo.hasTerms ? Date: Thu, 3 Dec 2020 11:50:08 +0100 Subject: [PATCH 023/457] Simplifie --- .../views/settings/tabs/user/GeneralUserSettingsTab.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js b/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js index 4d1210dc40..febbcc8e36 100644 --- a/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js +++ b/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js @@ -401,7 +401,7 @@ export default class GeneralUserSettingsTab extends React.Component { render() { const plaf = PlatformPeg.get(); - const supportsMultiLanguageSpellCheck = plaf.supportsMultiLanguageSpellCheck() ? true : false; + const supportsMultiLanguageSpellCheck = plaf.supportsMultiLanguageSpellCheck(); const discoWarning = this.state.requiredPolicyInfo.hasTerms ? Date: Thu, 3 Dec 2020 11:50:20 +0100 Subject: [PATCH 024/457] Added in if statement --- src/languageHandler.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/languageHandler.tsx b/src/languageHandler.tsx index 38d3c8347a..985719fce7 100644 --- a/src/languageHandler.tsx +++ b/src/languageHandler.tsx @@ -355,7 +355,9 @@ export function setSpellCheckLanguages(preferredLangs: string[]) { export async function getAvailableSpellCheckLanguages(): Promise { const plaf = PlatformPeg.get(); - return plaf.getAvailableSpellCheckLanguages(); + if (plaf) { + return plaf.getAvailableSpellCheckLanguages(); + } } export function getAllLanguagesFromJson() { From 89bc4435945bfb207355cf5e5e290925f7d7f7aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Wed, 16 Dec 2020 16:02:27 +0100 Subject: [PATCH 025/457] Fix file drop UI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- res/css/structures/_MainSplit.scss | 2 +- res/css/structures/_RoomView.scss | 13 +++++-------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/res/css/structures/_MainSplit.scss b/res/css/structures/_MainSplit.scss index ad1656efbb..3de68b000d 100644 --- a/res/css/structures/_MainSplit.scss +++ b/res/css/structures/_MainSplit.scss @@ -22,7 +22,7 @@ limitations under the License. } .mx_MainSplit > .mx_RightPanel_ResizeWrapper { - padding: 5px; + padding: 0 5px 5px 5px; // margin left to not allow the handle to not encroach on the space for the scrollbar margin-left: 8px; height: calc(100vh - 51px); // height of .mx_RoomHeader.light-panel diff --git a/res/css/structures/_RoomView.scss b/res/css/structures/_RoomView.scss index 572c7166d2..0a70b027ae 100644 --- a/res/css/structures/_RoomView.scss +++ b/res/css/structures/_RoomView.scss @@ -23,24 +23,21 @@ limitations under the License. .mx_RoomView_fileDropTarget { min-width: 0px; width: 100%; + height: 100%; + + margin-left: 6.25px; + font-size: $font-18px; text-align: center; pointer-events: none; - padding-left: 12px; - padding-right: 12px; - margin-left: -12px; - border-top-left-radius: 10px; border-top-right-radius: 10px; background-color: $droptarget-bg-color; - border: 2px #e1dddd solid; - border-bottom: none; + position: absolute; - top: 52px; - bottom: 0px; z-index: 3000; } From 41e2ffdf0df43104ef171b690b344a6e22b286f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Wed, 16 Dec 2020 19:51:49 +0100 Subject: [PATCH 026/457] Added background MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- res/css/structures/_RoomView.scss | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/res/css/structures/_RoomView.scss b/res/css/structures/_RoomView.scss index 0a70b027ae..9292a400bc 100644 --- a/res/css/structures/_RoomView.scss +++ b/res/css/structures/_RoomView.scss @@ -39,13 +39,19 @@ limitations under the License. position: absolute; z-index: 3000; + + display: flex; + justify-content: center; + align-items: center; } .mx_RoomView_fileDropTargetLabel { - top: 50%; - width: 100%; - margin-top: -50px; position: absolute; + + border-radius: 10px; + padding: 10px; + + background-color: $menu-bg-color; } .mx_RoomView_auxPanel { From da97d18332c5740499913506b0e059e5b4c7616c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Wed, 16 Dec 2020 21:33:05 +0100 Subject: [PATCH 027/457] Added a comment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- res/css/structures/_RoomView.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/res/css/structures/_RoomView.scss b/res/css/structures/_RoomView.scss index 9292a400bc..dd63be3a11 100644 --- a/res/css/structures/_RoomView.scss +++ b/res/css/structures/_RoomView.scss @@ -25,6 +25,7 @@ limitations under the License. width: 100%; height: 100%; + // This is an ugly fix for centering this element margin-left: 6.25px; font-size: $font-18px; From dcb30b72b0ed1adc6fb075ee9cc26ca0338177bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Thu, 17 Dec 2020 13:25:22 +0100 Subject: [PATCH 028/457] Fix left panel resizer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- res/css/structures/_MainSplit.scss | 32 ++++++++++++++++---------- res/css/structures/_RoomView.scss | 12 ++++++---- src/components/structures/RoomView.tsx | 28 +++++++++++----------- 3 files changed, 43 insertions(+), 29 deletions(-) diff --git a/res/css/structures/_MainSplit.scss b/res/css/structures/_MainSplit.scss index 3de68b000d..6875ef12e0 100644 --- a/res/css/structures/_MainSplit.scss +++ b/res/css/structures/_MainSplit.scss @@ -22,22 +22,30 @@ limitations under the License. } .mx_MainSplit > .mx_RightPanel_ResizeWrapper { - padding: 0 5px 5px 5px; - // margin left to not allow the handle to not encroach on the space for the scrollbar - margin-left: 8px; + padding: 0 5px 5px 0px; height: calc(100vh - 51px); // height of .mx_RoomHeader.light-panel + + .mx_RightPanel_ResizeHandle { + width: 9px; + } &:hover .mx_RightPanel_ResizeHandle { - // Need to use important to override element style attributes - // set by re-resizable - top: 50% !important; - transform: translate(0, -50%); + &::before { + position: absolute; + left: 6px; + top: 50%; + transform: translate(0, -50%); - height: 64px !important; // to match width of the ones on roomlist - width: 4px !important; - border-radius: 4px !important; + height: 64px; + width: 4px; + border-radius: 4px; - background-color: $primary-fg-color; - opacity: 0.8; + content: ' '; + + background-color: $primary-fg-color; + opacity: 0.8; + + margin-left: -10px; + } } } diff --git a/res/css/structures/_RoomView.scss b/res/css/structures/_RoomView.scss index dd63be3a11..0a12a86c33 100644 --- a/res/css/structures/_RoomView.scss +++ b/res/css/structures/_RoomView.scss @@ -25,9 +25,6 @@ limitations under the License. width: 100%; height: 100%; - // This is an ugly fix for centering this element - margin-left: 6.25px; - font-size: $font-18px; text-align: center; @@ -120,16 +117,23 @@ limitations under the License. height: 50px; } -.mx_RoomView_body { +.mx_RoomView_container { position: relative; //for .mx_RoomView_auxPanel_fullHeight display: flex; flex-direction: column; +} + +.mx_RoomView_body { + display: flex; + flex-direction: column; flex: 1; min-width: 0; .mx_RoomView_messagePanel, .mx_RoomView_messagePanelSpinner, .mx_RoomView_messagePanelSearchSpinner { order: 2; } + + margin-right: 10px; } .mx_RoomView_body .mx_RoomView_timeline { diff --git a/src/components/structures/RoomView.tsx b/src/components/structures/RoomView.tsx index 0ee847fbc9..3d62c06e4b 100644 --- a/src/components/structures/RoomView.tsx +++ b/src/components/structures/RoomView.tsx @@ -2003,22 +2003,24 @@ export default class RoomView extends React.Component { appsShown={this.state.showApps} /> -
+
{auxPanel} -
- {topUnreadMessagesBar} - {jumpToBottom} - {messagePanel} - {searchResultsPanel} -
-
-
-
- {statusBar} +
+
+ {topUnreadMessagesBar} + {jumpToBottom} + {messagePanel} + {searchResultsPanel}
+
+
+
+ {statusBar} +
+
+ {previewBar} + {messageComposer}
- {previewBar} - {messageComposer}
From e70dee08d0ea7b303a51fb807929376b2dad79dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Thu, 17 Dec 2020 19:50:59 +0100 Subject: [PATCH 029/457] Fix flickering MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- src/components/structures/RoomView.tsx | 42 ++++++++++++++++++++------ 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/src/components/structures/RoomView.tsx b/src/components/structures/RoomView.tsx index 3d62c06e4b..67f9663597 100644 --- a/src/components/structures/RoomView.tsx +++ b/src/components/structures/RoomView.tsx @@ -187,6 +187,7 @@ export interface IState { rejecting?: boolean; rejectError?: Error; hasPinnedWidgets?: boolean; + dragCounter: number; } export default class RoomView extends React.Component { @@ -237,6 +238,7 @@ export default class RoomView extends React.Component { canReply: false, useIRCLayout: SettingsStore.getValue("useIRCLayout"), matrixClientIsReady: this.context && this.context.isInitialSyncComplete(), + dragCounter: 0, }; this.dispatcherRef = dis.register(this.onAction); @@ -525,8 +527,8 @@ export default class RoomView extends React.Component { if (!roomView.ondrop) { roomView.addEventListener('drop', this.onDrop); roomView.addEventListener('dragover', this.onDragOver); - roomView.addEventListener('dragleave', this.onDragLeaveOrEnd); - roomView.addEventListener('dragend', this.onDragLeaveOrEnd); + roomView.addEventListener('dragenter', this.onDragEnter); + roomView.addEventListener('dragleave', this.onDragLeave); } } @@ -1108,6 +1110,31 @@ export default class RoomView extends React.Component { this.updateTopUnreadMessagesBar(); }; + private onDragEnter = ev => { + ev.stopPropagation(); + ev.preventDefault(); + + this.setState({ + dragCounter: this.state.dragCounter + 1, + draggingFile: true, + }); + }; + + private onDragLeave = ev => { + ev.stopPropagation(); + ev.preventDefault(); + + this.setState({ + dragCounter: this.state.dragCounter - 1, + }); + + if (this.state.dragCounter == 0) { + this.setState({ + draggingFile: false, + }); + } + }; + private onDragOver = ev => { ev.stopPropagation(); ev.preventDefault(); @@ -1115,7 +1142,6 @@ export default class RoomView extends React.Component { ev.dataTransfer.dropEffect = 'none'; if (ev.dataTransfer.types.includes("Files") || ev.dataTransfer.types.includes("application/x-moz-file")) { - this.setState({ draggingFile: true }); ev.dataTransfer.dropEffect = 'copy'; } }; @@ -1126,14 +1152,12 @@ export default class RoomView extends React.Component { ContentMessages.sharedInstance().sendContentListToRoom( ev.dataTransfer.files, this.state.room.roomId, this.context, ); - this.setState({ draggingFile: false }); dis.fire(Action.FocusComposer); - }; - private onDragLeaveOrEnd = ev => { - ev.stopPropagation(); - ev.preventDefault(); - this.setState({ draggingFile: false }); + this.setState({ + draggingFile: false, + dragCounter: this.state.dragCounter - 1, + }); }; private injectSticker(url, info, text) { From 044e02b06ad46b417d3aa8fc33f24c1374fdcb56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Thu, 17 Dec 2020 20:16:53 +0100 Subject: [PATCH 030/457] Remove spaces in empty line MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- res/css/structures/_MainSplit.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/css/structures/_MainSplit.scss b/res/css/structures/_MainSplit.scss index 6875ef12e0..f05f24d0d7 100644 --- a/res/css/structures/_MainSplit.scss +++ b/res/css/structures/_MainSplit.scss @@ -24,7 +24,7 @@ limitations under the License. .mx_MainSplit > .mx_RightPanel_ResizeWrapper { padding: 0 5px 5px 0px; height: calc(100vh - 51px); // height of .mx_RoomHeader.light-panel - + .mx_RightPanel_ResizeHandle { width: 9px; } From 365d252d3f0eb64755f502318c95f855a4404f56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Thu, 17 Dec 2020 20:25:12 +0100 Subject: [PATCH 031/457] Fix removing event listeners MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- src/components/structures/RoomView.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/structures/RoomView.tsx b/src/components/structures/RoomView.tsx index 67f9663597..d910940a73 100644 --- a/src/components/structures/RoomView.tsx +++ b/src/components/structures/RoomView.tsx @@ -572,8 +572,8 @@ export default class RoomView extends React.Component { const roomView = this.roomView.current; roomView.removeEventListener('drop', this.onDrop); roomView.removeEventListener('dragover', this.onDragOver); - roomView.removeEventListener('dragleave', this.onDragLeaveOrEnd); - roomView.removeEventListener('dragend', this.onDragLeaveOrEnd); + roomView.removeEventListener('dragenter', this.onDragEnter); + roomView.removeEventListener('dragleave', this.onDragLeave); } dis.unregister(this.dispatcherRef); if (this.context) { From 5d7e45e6cf85e14f4143923f7e29642f97965fc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Thu, 17 Dec 2020 20:29:33 +0100 Subject: [PATCH 032/457] Added dragCounter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- src/contexts/RoomContext.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/contexts/RoomContext.ts b/src/contexts/RoomContext.ts index 082dcc4e6b..1b9097e337 100644 --- a/src/contexts/RoomContext.ts +++ b/src/contexts/RoomContext.ts @@ -42,6 +42,7 @@ const RoomContext = createContext({ canReply: false, useIRCLayout: false, matrixClientIsReady: false, + dragCounter: 0, }); RoomContext.displayName = "RoomContext"; export default RoomContext; From d589c6100069c5ddae0c7372760c63d40ecd84ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Sat, 9 Jan 2021 09:09:14 +0100 Subject: [PATCH 033/457] Added send message button MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- res/css/views/rooms/_MessageComposer.scss | 5 +++++ src/components/views/rooms/MessageComposer.js | 14 ++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/res/css/views/rooms/_MessageComposer.scss b/res/css/views/rooms/_MessageComposer.scss index 71c0db947e..897167f745 100644 --- a/res/css/views/rooms/_MessageComposer.scss +++ b/res/css/views/rooms/_MessageComposer.scss @@ -239,6 +239,7 @@ limitations under the License. mask-image: url('$(res)/img/element-icons/call/video-call.svg'); } + .mx_MessageComposer_emoji::before { mask-image: url('$(res)/img/element-icons/room/composer/emoji.svg'); } @@ -247,6 +248,10 @@ limitations under the License. mask-image: url('$(res)/img/element-icons/room/composer/sticker.svg'); } +.mx_MessageComposer_sendMessage::before { + mask-image: url('$(res)/img/element-icons/call/video-call.svg'); +} + .mx_MessageComposer_formatting { cursor: pointer; margin: 0 11px; diff --git a/src/components/views/rooms/MessageComposer.js b/src/components/views/rooms/MessageComposer.js index 4ddff8f4b0..86ad3ddbdd 100644 --- a/src/components/views/rooms/MessageComposer.js +++ b/src/components/views/rooms/MessageComposer.js @@ -393,6 +393,10 @@ export default class MessageComposer extends React.Component { }); } + sendMessage = () => { + this.messageComposerInput._sendMessage(); + } + render() { const controls = [ this.state.me ? : null, @@ -450,6 +454,16 @@ export default class MessageComposer extends React.Component { ); } } + + if (true) { + controls.push(( + + )); + } } else if (this.state.tombstone) { const replacementRoomId = this.state.tombstone.getContent()['replacement_room']; From c64b2a585f3c2d1e75392657995d6b1813250f32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Sat, 9 Jan 2021 09:17:40 +0100 Subject: [PATCH 034/457] Added option to disable send button MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- src/components/views/rooms/MessageComposer.js | 2 +- .../views/settings/tabs/user/PreferencesUserSettingsTab.js | 1 + src/settings/Settings.ts | 5 +++++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/components/views/rooms/MessageComposer.js b/src/components/views/rooms/MessageComposer.js index 86ad3ddbdd..315b1b78c7 100644 --- a/src/components/views/rooms/MessageComposer.js +++ b/src/components/views/rooms/MessageComposer.js @@ -455,7 +455,7 @@ export default class MessageComposer extends React.Component { } } - if (true) { + if (SettingsStore.getValue("MessageComposerInput.sendButton")) { controls.push(( Date: Sat, 9 Jan 2021 09:18:10 +0100 Subject: [PATCH 035/457] i18n 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 ++ 1 file changed, 2 insertions(+) diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index ac18ccb23e..6baccf95de 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -799,6 +799,7 @@ "Show typing notifications": "Show typing notifications", "Use Command + Enter to send a message": "Use Command + Enter to send a message", "Use Ctrl + Enter to send a message": "Use Ctrl + Enter to send a message", + "Show send message button": "Show send message button", "Automatically replace plain text Emoji": "Automatically replace plain text Emoji", "Mirror local video feed": "Mirror local video feed", "Enable Community Filter Panel": "Enable Community Filter Panel", @@ -1412,6 +1413,7 @@ "Send a reply…": "Send a reply…", "Send an encrypted message…": "Send an encrypted message…", "Send a message…": "Send a message…", + "Send message": "Send message", "The conversation continues here.": "The conversation continues here.", "This room has been replaced and is no longer active.": "This room has been replaced and is no longer active.", "You do not have permission to post to this room": "You do not have permission to post to this room", From 4538274e74938294f840abcae070ac75d052d311 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Sat, 9 Jan 2021 09:25:29 +0100 Subject: [PATCH 036/457] Added send message icon MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- res/css/views/rooms/_MessageComposer.scss | 2 +- res/img/element-icons/send-message.svg | 54 +++++++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 res/img/element-icons/send-message.svg diff --git a/res/css/views/rooms/_MessageComposer.scss b/res/css/views/rooms/_MessageComposer.scss index 897167f745..8c2a997490 100644 --- a/res/css/views/rooms/_MessageComposer.scss +++ b/res/css/views/rooms/_MessageComposer.scss @@ -249,7 +249,7 @@ limitations under the License. } .mx_MessageComposer_sendMessage::before { - mask-image: url('$(res)/img/element-icons/call/video-call.svg'); + mask-image: url('$(res)/img/element-icons/send-message.svg'); } .mx_MessageComposer_formatting { diff --git a/res/img/element-icons/send-message.svg b/res/img/element-icons/send-message.svg new file mode 100644 index 0000000000..2e74745e21 --- /dev/null +++ b/res/img/element-icons/send-message.svg @@ -0,0 +1,54 @@ + + + + + + image/svg+xml + + + + + + + + + From 263f2136502c657c4dcbb07674e965576ad562ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Sat, 9 Jan 2021 09:27:02 +0100 Subject: [PATCH 037/457] Remove an empty line MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- res/css/views/rooms/_MessageComposer.scss | 1 - 1 file changed, 1 deletion(-) diff --git a/res/css/views/rooms/_MessageComposer.scss b/res/css/views/rooms/_MessageComposer.scss index 8c2a997490..8b34318f1d 100644 --- a/res/css/views/rooms/_MessageComposer.scss +++ b/res/css/views/rooms/_MessageComposer.scss @@ -239,7 +239,6 @@ limitations under the License. mask-image: url('$(res)/img/element-icons/call/video-call.svg'); } - .mx_MessageComposer_emoji::before { mask-image: url('$(res)/img/element-icons/room/composer/emoji.svg'); } From 7d120f7183eef575f16d78b1e9b4fdfabf7d2848 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Sat, 9 Jan 2021 09:33:11 +0100 Subject: [PATCH 038/457] Simplifie svg MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- res/img/element-icons/send-message.svg | 55 +------------------------- 1 file changed, 2 insertions(+), 53 deletions(-) diff --git a/res/img/element-icons/send-message.svg b/res/img/element-icons/send-message.svg index 2e74745e21..ce35bf8bc8 100644 --- a/res/img/element-icons/send-message.svg +++ b/res/img/element-icons/send-message.svg @@ -1,54 +1,3 @@ - - - - - - image/svg+xml - - - - - - - - + + From 9f1113b3bd47295d1e6f0d2e897bcb93773a06cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Sat, 16 Jan 2021 16:35:50 +0100 Subject: [PATCH 039/457] Watch setting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- src/components/views/rooms/MessageComposer.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/components/views/rooms/MessageComposer.js b/src/components/views/rooms/MessageComposer.js index 315b1b78c7..a18dded04f 100644 --- a/src/components/views/rooms/MessageComposer.js +++ b/src/components/views/rooms/MessageComposer.js @@ -263,6 +263,7 @@ export default class MessageComposer extends React.Component { tombstone: this._getRoomTombstone(), canSendMessages: this.props.room.maySendMessage(), showCallButtons: SettingsStore.getValue("showCallButtonsInComposer"), + showSendButton: SettingsStore.getValue("MessageComposerInput.sendButton"), hasConference: WidgetStore.instance.doesRoomHaveConference(this.props.room), joinedConference: WidgetStore.instance.isJoinedToConferenceIn(this.props.room), }; @@ -280,6 +281,12 @@ export default class MessageComposer extends React.Component { } }; + onSendButtonChanged = () => { + this.setState({ + showSendButton: SettingsStore.getValue("MessageComposerInput.sendButton"), + }); + } + _onWidgetUpdate = () => { this.setState({hasConference: WidgetStore.instance.doesRoomHaveConference(this.props.room)}); }; @@ -292,6 +299,8 @@ export default class MessageComposer extends React.Component { this.dispatcherRef = dis.register(this.onAction); MatrixClientPeg.get().on("RoomState.events", this._onRoomStateEvents); this._waitForOwnMember(); + this.showSendButtonRef = SettingsStore.watchSetting( + "MessageComposerInput.sendButton", null, this.onSendButtonChanged); } _waitForOwnMember() { @@ -317,6 +326,7 @@ export default class MessageComposer extends React.Component { WidgetStore.instance.removeListener(UPDATE_EVENT, this._onWidgetUpdate); ActiveWidgetStore.removeListener('update', this._onActiveWidgetUpdate); dis.unregister(this.dispatcherRef); + SettingsStore.unwatchSetting(this.showSendButtonRef); } _onRoomStateEvents(ev, state) { @@ -455,7 +465,7 @@ export default class MessageComposer extends React.Component { } } - if (SettingsStore.getValue("MessageComposerInput.sendButton")) { + if (this.state.showSendButton) { controls.push(( Date: Sat, 16 Jan 2021 16:37:50 +0100 Subject: [PATCH 040/457] Rename setting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- src/components/views/rooms/MessageComposer.js | 6 +++--- .../views/settings/tabs/user/PreferencesUserSettingsTab.js | 2 +- src/settings/Settings.ts | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/components/views/rooms/MessageComposer.js b/src/components/views/rooms/MessageComposer.js index a18dded04f..1e43aa6652 100644 --- a/src/components/views/rooms/MessageComposer.js +++ b/src/components/views/rooms/MessageComposer.js @@ -263,7 +263,7 @@ export default class MessageComposer extends React.Component { tombstone: this._getRoomTombstone(), canSendMessages: this.props.room.maySendMessage(), showCallButtons: SettingsStore.getValue("showCallButtonsInComposer"), - showSendButton: SettingsStore.getValue("MessageComposerInput.sendButton"), + showSendButton: SettingsStore.getValue("MessageComposerInput.showSendButton"), hasConference: WidgetStore.instance.doesRoomHaveConference(this.props.room), joinedConference: WidgetStore.instance.isJoinedToConferenceIn(this.props.room), }; @@ -283,7 +283,7 @@ export default class MessageComposer extends React.Component { onSendButtonChanged = () => { this.setState({ - showSendButton: SettingsStore.getValue("MessageComposerInput.sendButton"), + showSendButton: SettingsStore.getValue("MessageComposerInput.showSendButton"), }); } @@ -300,7 +300,7 @@ export default class MessageComposer extends React.Component { MatrixClientPeg.get().on("RoomState.events", this._onRoomStateEvents); this._waitForOwnMember(); this.showSendButtonRef = SettingsStore.watchSetting( - "MessageComposerInput.sendButton", null, this.onSendButtonChanged); + "MessageComposerInput.showSendButton", null, this.onSendButtonChanged); } _waitForOwnMember() { diff --git a/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.js b/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.js index 31971b7167..eff0824d59 100644 --- a/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.js +++ b/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.js @@ -34,7 +34,7 @@ export default class PreferencesUserSettingsTab extends React.Component { 'MessageComposerInput.suggestEmoji', 'sendTypingNotifications', 'MessageComposerInput.ctrlEnterToSend', - `MessageComposerInput.sendButton`, + `MessageComposerInput.showSendButton`, ]; static TIMELINE_SETTINGS = [ diff --git a/src/settings/Settings.ts b/src/settings/Settings.ts index 50d0f919e6..2d8385240c 100644 --- a/src/settings/Settings.ts +++ b/src/settings/Settings.ts @@ -336,7 +336,7 @@ export const SETTINGS: {[setting: string]: ISetting} = { displayName: isMac ? _td("Use Command + Enter to send a message") : _td("Use Ctrl + Enter to send a message"), default: false, }, - "MessageComposerInput.sendButton": { + "MessageComposerInput.showSendButton": { supportedLevels: LEVELS_ACCOUNT_SETTINGS, displayName: _td("Show send message button"), default: false, From c9f5c90047e0140da31050d97d0f831bf50858c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Sat, 16 Jan 2021 16:43:47 +0100 Subject: [PATCH 041/457] Rename method MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- src/components/views/rooms/MessageComposer.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/views/rooms/MessageComposer.js b/src/components/views/rooms/MessageComposer.js index 1e43aa6652..9683c4c79e 100644 --- a/src/components/views/rooms/MessageComposer.js +++ b/src/components/views/rooms/MessageComposer.js @@ -281,7 +281,7 @@ export default class MessageComposer extends React.Component { } }; - onSendButtonChanged = () => { + onShowSendButtonChanged = () => { this.setState({ showSendButton: SettingsStore.getValue("MessageComposerInput.showSendButton"), }); @@ -300,7 +300,7 @@ export default class MessageComposer extends React.Component { MatrixClientPeg.get().on("RoomState.events", this._onRoomStateEvents); this._waitForOwnMember(); this.showSendButtonRef = SettingsStore.watchSetting( - "MessageComposerInput.showSendButton", null, this.onSendButtonChanged); + "MessageComposerInput.showSendButton", null, this.onShowSendButtonChanged); } _waitForOwnMember() { From 5de92b68d954ba3f997f2d5713d954ee05303b2e Mon Sep 17 00:00:00 2001 From: Will Hunt Date: Wed, 27 Jan 2021 11:39:57 +0000 Subject: [PATCH 042/457] Show a specific error for hs_disabled --- src/components/structures/LoggedInView.tsx | 2 +- src/components/structures/RoomStatusBar.js | 4 ++++ src/components/structures/auth/Login.tsx | 3 +++ src/components/structures/auth/Registration.tsx | 1 + src/toasts/ServerLimitToast.tsx | 1 + src/utils/ErrorUtils.js | 1 + 6 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/components/structures/LoggedInView.tsx b/src/components/structures/LoggedInView.tsx index 70ec2b7033..508b7f05e7 100644 --- a/src/components/structures/LoggedInView.tsx +++ b/src/components/structures/LoggedInView.tsx @@ -94,7 +94,7 @@ interface IProps { interface IUsageLimit { // eslint-disable-next-line camelcase - limit_type: "monthly_active_user" | string; + limit_type: "monthly_active_user" | "hs_disabled" | string; // eslint-disable-next-line camelcase admin_contact?: string; } diff --git a/src/components/structures/RoomStatusBar.js b/src/components/structures/RoomStatusBar.js index c1c4ad6292..aa4bceba74 100644 --- a/src/components/structures/RoomStatusBar.js +++ b/src/components/structures/RoomStatusBar.js @@ -195,6 +195,10 @@ export default class RoomStatusBar extends React.Component { "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.", ), + 'hs_disabled': _td( + "Your message wasn't sent because this homeserver has been blocked by it's administrator. " + + "Please contact your service administrator to continue using the service.", + ), '': _td( "Your message wasn't sent because this homeserver has exceeded a resource limit. " + "Please contact your service administrator to continue using the service.", diff --git a/src/components/structures/auth/Login.tsx b/src/components/structures/auth/Login.tsx index 606aeb44ab..a9fd363763 100644 --- a/src/components/structures/auth/Login.tsx +++ b/src/components/structures/auth/Login.tsx @@ -218,6 +218,9 @@ export default class LoginComponent extends React.PureComponent 'monthly_active_user': _td( "This homeserver has hit its Monthly Active User limit.", ), + 'hs_blocked': _td( + "This homeserver has been blocked by it's administrator.", + ), '': _td( "This homeserver has exceeded one of its resource limits.", ), diff --git a/src/components/structures/auth/Registration.tsx b/src/components/structures/auth/Registration.tsx index 095f3d3433..f9d338902c 100644 --- a/src/components/structures/auth/Registration.tsx +++ b/src/components/structures/auth/Registration.tsx @@ -276,6 +276,7 @@ export default class Registration extends React.Component { response.data.admin_contact, { 'monthly_active_user': _td("This homeserver has hit its Monthly Active User limit."), + 'hs_blocked': _td("This homeserver has been blocked by it's administrator."), '': _td("This homeserver has exceeded one of its resource limits."), }, ); diff --git a/src/toasts/ServerLimitToast.tsx b/src/toasts/ServerLimitToast.tsx index d35140be3d..9dbe8c05f1 100644 --- a/src/toasts/ServerLimitToast.tsx +++ b/src/toasts/ServerLimitToast.tsx @@ -26,6 +26,7 @@ const TOAST_KEY = "serverlimit"; export const showToast = (limitType: string, adminContact?: string, syncError?: boolean) => { const errorText = messageForResourceLimitError(limitType, adminContact, { 'monthly_active_user': _td("Your homeserver has exceeded its user limit."), + 'hs_blocked': _td("This homeserver has been blocked by it's administrator."), '': _td("Your homeserver has exceeded one of its resource limits."), }); const contactText = messageForResourceLimitError(limitType, adminContact, { diff --git a/src/utils/ErrorUtils.js b/src/utils/ErrorUtils.js index f0a4d7c49e..2c6acd5503 100644 --- a/src/utils/ErrorUtils.js +++ b/src/utils/ErrorUtils.js @@ -62,6 +62,7 @@ export function messageForSyncError(err) { err.data.admin_contact, { 'monthly_active_user': _td("This homeserver has hit its Monthly Active User limit."), + 'hs_blocked': _td("This homeserver has been blocked by its administrator."), '': _td("This homeserver has exceeded one of its resource limits."), }, ); From 27724a93d28d7945e49f94b5fa1158095bd84d8d Mon Sep 17 00:00:00 2001 From: Will Hunt Date: Wed, 27 Jan 2021 11:42:36 +0000 Subject: [PATCH 043/457] new strings --- src/i18n/strings/en_EN.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 8d047ea3f1..e55ab581ca 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -650,6 +650,7 @@ "Unexpected error resolving identity server configuration": "Unexpected error resolving identity server configuration", "The message you are trying to send is too large.": "The message you are trying to send is too large.", "This homeserver has hit its Monthly Active User limit.": "This homeserver has hit its Monthly Active User limit.", + "This homeserver has been blocked by its administrator.": "This homeserver has been blocked by its administrator.", "This homeserver has exceeded one of its resource limits.": "This homeserver has exceeded one of its resource limits.", "Please contact your service administrator to continue using the service.": "Please contact your service administrator to continue using the service.", "Unable to connect to Homeserver. Retrying...": "Unable to connect to Homeserver. Retrying...", @@ -727,6 +728,7 @@ "Enable desktop notifications": "Enable desktop notifications", "Enable": "Enable", "Your homeserver has exceeded its user limit.": "Your homeserver has exceeded its user limit.", + "This homeserver has been blocked by it's administrator.": "This homeserver has been blocked by it's administrator.", "Your homeserver has exceeded one of its resource limits.": "Your homeserver has exceeded one of its resource limits.", "Contact your server admin.": "Contact your server admin.", "Warning": "Warning", @@ -2471,6 +2473,7 @@ "Filter rooms and people": "Filter rooms and people", "You can't send any messages until you review and agree to our terms and conditions.": "You can't send any messages until you review and agree to our terms and conditions.", "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.": "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.", + "Your message wasn't sent because this homeserver has been blocked by it's administrator. Please contact your service administrator to continue using the service.": "Your message wasn't sent because this homeserver has been blocked by it's administrator. Please contact your service administrator to continue using the service.", "Your message wasn't sent because this homeserver has exceeded a resource limit. Please contact your service administrator to continue using the service.": "Your message wasn't sent because this homeserver has exceeded a resource limit. Please contact your service administrator to continue using the service.", "%(count)s of your messages have not been sent.|other": "Some of your messages have not been sent.", "%(count)s of your messages have not been sent.|one": "Your message was not sent.", From cc38bcf333bc9fdd7d8ebc7d0b4d06330ba7e359 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Sat, 6 Feb 2021 15:09:21 +0100 Subject: [PATCH 044/457] Display room name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- src/components/views/elements/Pill.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/elements/Pill.js b/src/components/views/elements/Pill.js index daa4cb70e2..f1527c48b1 100644 --- a/src/components/views/elements/Pill.js +++ b/src/components/views/elements/Pill.js @@ -226,7 +226,7 @@ class Pill extends React.Component { case Pill.TYPE_ROOM_MENTION: { const room = this.state.room; if (room) { - linkText = resource; + linkText = room.name; if (this.props.shouldShowPillAvatar) { avatar = ; } From ffc0230ab4eb3902bdd6e22280f78c8b0870ba54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Sat, 6 Feb 2021 19:09:34 +0100 Subject: [PATCH 045/457] Use resource as a fallback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is useful mainly for the tests they would otherwise fail as there is no room name to display while the tests are run. Signed-off-by: Šimon Brandner --- src/components/views/elements/Pill.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/elements/Pill.js b/src/components/views/elements/Pill.js index f1527c48b1..cbbe562754 100644 --- a/src/components/views/elements/Pill.js +++ b/src/components/views/elements/Pill.js @@ -226,7 +226,7 @@ class Pill extends React.Component { case Pill.TYPE_ROOM_MENTION: { const room = this.state.room; if (room) { - linkText = room.name; + linkText = room.name || resource; if (this.props.shouldShowPillAvatar) { avatar = ; } From 33979b335446bf16bd02815ae88de7241540ed74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Fri, 12 Feb 2021 08:18:27 +0100 Subject: [PATCH 046/457] Added a tooltip MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- src/components/views/elements/Pill.js | 39 +++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/src/components/views/elements/Pill.js b/src/components/views/elements/Pill.js index cbbe562754..5b3189f389 100644 --- a/src/components/views/elements/Pill.js +++ b/src/components/views/elements/Pill.js @@ -26,6 +26,7 @@ import FlairStore from "../../../stores/FlairStore"; import {getPrimaryPermalinkEntity, parseAppLocalLink} from "../../../utils/permalinks/Permalinks"; import MatrixClientContext from "../../../contexts/MatrixClientContext"; import {Action} from "../../../dispatcher/actions"; +import Tooltip from './Tooltip'; class Pill extends React.Component { static roomNotifPos(text) { @@ -68,6 +69,8 @@ class Pill extends React.Component { group: null, // The room related to the room pill room: null, + // Is the user hovering the pill + hover: false, }; // TODO: [REACT-WARNING] Replace with appropriate lifecycle event @@ -154,6 +157,18 @@ class Pill extends React.Component { this._unmounted = true; } + onMouseOver = () => { + this.setState({ + hover: true, + }); + }; + + onMouseLeave = () => { + this.setState({ + hover: false, + }); + }; + doProfileLookup(userId, member) { MatrixClientPeg.get().getProfileInfo(userId).then((resp) => { if (this._unmounted) { @@ -256,16 +271,36 @@ class Pill extends React.Component { }); if (this.state.pillType) { + const {yOffset} = this.props; + + let tip; + if (this.state.hover) { + tip = ; + } + return { this.props.inMessage ? - + { avatar } { linkText } : - + { avatar } { linkText } } + {tip} ; } else { // Deliberately render nothing if the URL isn't recognised From a975de22efca2302aa5302b5d0142aafd235a701 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Fri, 12 Feb 2021 11:27:14 +0100 Subject: [PATCH 047/457] Fixed buggy tooltip MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- src/components/views/elements/Pill.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/views/elements/Pill.js b/src/components/views/elements/Pill.js index 5b3189f389..68a87d40b9 100644 --- a/src/components/views/elements/Pill.js +++ b/src/components/views/elements/Pill.js @@ -290,6 +290,7 @@ class Pill extends React.Component { > { avatar } { linkText } + { tip } : { avatar } { linkText } + { tip } } - {tip} ; } else { // Deliberately render nothing if the URL isn't recognised From a075568e895c0e2b3e9e83c710cbc9c510b488bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Fri, 12 Feb 2021 11:34:09 +0100 Subject: [PATCH 048/457] Fixed tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the previous commits I have removed the native title/tooltip so it needs to be removed from the tests as well Signed-off-by: Šimon Brandner --- test/components/views/messages/TextualBody-test.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/components/views/messages/TextualBody-test.js b/test/components/views/messages/TextualBody-test.js index d5b80b6756..a596825c09 100644 --- a/test/components/views/messages/TextualBody-test.js +++ b/test/components/views/messages/TextualBody-test.js @@ -208,7 +208,7 @@ describe("", () => { const content = wrapper.find(".mx_EventTile_body"); expect(content.html()).toBe('' + 'Hey ' + - '' + + '' + 'Member' + ''); @@ -267,8 +267,8 @@ describe("", () => { expect(content.html()).toBe( '' + 'A ' + '!ZxbRYPQXDXKGmDnJNg:example.com with vias', From cb5237a18be0bf17eede4768f8978dfc44e7c609 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Fri, 12 Feb 2021 14:21:07 +0100 Subject: [PATCH 049/457] Display room name instead of alias MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- src/editor/parts.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/editor/parts.ts b/src/editor/parts.ts index 8a7ccfcb7b..67f6a2c0c5 100644 --- a/src/editor/parts.ts +++ b/src/editor/parts.ts @@ -329,8 +329,8 @@ class NewlinePart extends BasePart implements IBasePart { } class RoomPillPart extends PillPart { - constructor(displayAlias, private room: Room) { - super(displayAlias, displayAlias); + constructor(resourceId: string, label: string, private room: Room) { + super(resourceId, label); } setAvatar(node: HTMLElement) { @@ -357,6 +357,10 @@ class RoomPillPart extends PillPart { } class AtRoomPillPart extends RoomPillPart { + constructor(text: string, room: Room) { + super(text, text, room); + } + get type(): IPillPart["type"] { return Type.AtRoomPill; } @@ -521,7 +525,7 @@ export class PartCreator { r.getAltAliases().includes(alias); }); } - return new RoomPillPart(alias, room); + return new RoomPillPart(alias, room ? room.name : alias, room); } atRoomPill(text: string) { From d8a9b84af94fac4321d700a9c9bfee29763e7fd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Fri, 12 Feb 2021 14:28:39 +0100 Subject: [PATCH 050/457] Don't show tooltip if there is nothing to display MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We do this because resource is undefined for @room Signed-off-by: Šimon Brandner --- src/components/views/elements/Pill.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/elements/Pill.js b/src/components/views/elements/Pill.js index 68a87d40b9..c6806c289e 100644 --- a/src/components/views/elements/Pill.js +++ b/src/components/views/elements/Pill.js @@ -274,7 +274,7 @@ class Pill extends React.Component { const {yOffset} = this.props; let tip; - if (this.state.hover) { + if (this.state.hover && resource) { tip = ; } From 17f09d3b7a4eb800d0d2076cc906500aeb914cc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Fri, 12 Feb 2021 15:16:07 +0100 Subject: [PATCH 051/457] Added onIsEmptyChanged prop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- src/components/views/rooms/SendMessageComposer.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/components/views/rooms/SendMessageComposer.js b/src/components/views/rooms/SendMessageComposer.js index 553fb44c04..99761ec8ba 100644 --- a/src/components/views/rooms/SendMessageComposer.js +++ b/src/components/views/rooms/SendMessageComposer.js @@ -117,6 +117,7 @@ export default class SendMessageComposer extends React.Component { placeholder: PropTypes.string, permalinkCreator: PropTypes.object.isRequired, replyToEvent: PropTypes.object, + onIsEmptyChanged: PropTypes.func, }; static contextType = MatrixClientContext; @@ -534,10 +535,15 @@ export default class SendMessageComposer extends React.Component { } } + onChange = () => { + this.props.onIsEmptyChanged(this.model.isEmpty); + } + render() { return (
Date: Fri, 12 Feb 2021 15:35:04 +0100 Subject: [PATCH 052/457] Extract send button into a function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- src/components/views/rooms/MessageComposer.js | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/src/components/views/rooms/MessageComposer.js b/src/components/views/rooms/MessageComposer.js index 9683c4c79e..0ea5d80c92 100644 --- a/src/components/views/rooms/MessageComposer.js +++ b/src/components/views/rooms/MessageComposer.js @@ -50,6 +50,22 @@ ComposerAvatar.propTypes = { me: PropTypes.object.isRequired, }; +function SendButton(props) { + return ( +
+ +
+ ); +} + +SendButton.propTypes = { + onClick: PropTypes.func.isRequired, +}; + function CallButton(props) { const onVoiceCallClick = (ev) => { dis.dispatch({ @@ -466,13 +482,9 @@ export default class MessageComposer extends React.Component { } if (this.state.showSendButton) { - controls.push(( - - )); + controls.push( + , + ); } } else if (this.state.tombstone) { const replacementRoomId = this.state.tombstone.getContent()['replacement_room']; From 42a48ee27d8e902e7f4835d8e221ae530af76570 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Fri, 12 Feb 2021 15:39:54 +0100 Subject: [PATCH 053/457] Added composerEmpty property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- src/components/views/rooms/MessageComposer.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/components/views/rooms/MessageComposer.js b/src/components/views/rooms/MessageComposer.js index 0ea5d80c92..8c13fa4dc8 100644 --- a/src/components/views/rooms/MessageComposer.js +++ b/src/components/views/rooms/MessageComposer.js @@ -282,6 +282,7 @@ export default class MessageComposer extends React.Component { showSendButton: SettingsStore.getValue("MessageComposerInput.showSendButton"), hasConference: WidgetStore.instance.doesRoomHaveConference(this.props.room), joinedConference: WidgetStore.instance.isJoinedToConferenceIn(this.props.room), + composerEmpty: true, }; } @@ -423,6 +424,12 @@ export default class MessageComposer extends React.Component { this.messageComposerInput._sendMessage(); } + onIsEmptyChanged = (isEmpty) => { + this.setState({ + composerEmpty: isEmpty, + }); + } + render() { const controls = [ this.state.me ? : null, @@ -448,6 +455,7 @@ export default class MessageComposer extends React.Component { resizeNotifier={this.props.resizeNotifier} permalinkCreator={this.props.permalinkCreator} replyToEvent={this.props.replyToEvent} + onIsEmptyChanged={this.onIsEmptyChanged} />, , , From 50b0a78132298fb906976b4f1e2824f1195c1fb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Fri, 12 Feb 2021 15:41:43 +0100 Subject: [PATCH 054/457] Renamed composerEmpty to isComposerEmpty MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- src/components/views/rooms/MessageComposer.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/views/rooms/MessageComposer.js b/src/components/views/rooms/MessageComposer.js index 8c13fa4dc8..7918243631 100644 --- a/src/components/views/rooms/MessageComposer.js +++ b/src/components/views/rooms/MessageComposer.js @@ -282,7 +282,7 @@ export default class MessageComposer extends React.Component { showSendButton: SettingsStore.getValue("MessageComposerInput.showSendButton"), hasConference: WidgetStore.instance.doesRoomHaveConference(this.props.room), joinedConference: WidgetStore.instance.isJoinedToConferenceIn(this.props.room), - composerEmpty: true, + isComposerEmpty: true, }; } @@ -426,7 +426,7 @@ export default class MessageComposer extends React.Component { onIsEmptyChanged = (isEmpty) => { this.setState({ - composerEmpty: isEmpty, + isComposerEmpty: isEmpty, }); } From 35c0cb99d04690f2465f7b4eb69aa5b006ccd7e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Fri, 12 Feb 2021 15:42:30 +0100 Subject: [PATCH 055/457] Use isComposerEmpty for send button MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- src/components/views/rooms/MessageComposer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/rooms/MessageComposer.js b/src/components/views/rooms/MessageComposer.js index 7918243631..61d61b8f42 100644 --- a/src/components/views/rooms/MessageComposer.js +++ b/src/components/views/rooms/MessageComposer.js @@ -489,7 +489,7 @@ export default class MessageComposer extends React.Component { } } - if (this.state.showSendButton) { + if (!this.state.isComposerEmpty) { controls.push( , ); From ba2c68819f9d2108efb6d44ff1afe73397b4feae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Fri, 12 Feb 2021 15:42:59 +0100 Subject: [PATCH 056/457] Removed showSendButton setting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- src/components/views/rooms/MessageComposer.js | 10 ---------- .../settings/tabs/user/PreferencesUserSettingsTab.js | 1 - src/settings/Settings.ts | 5 ----- 3 files changed, 16 deletions(-) diff --git a/src/components/views/rooms/MessageComposer.js b/src/components/views/rooms/MessageComposer.js index 61d61b8f42..f6fc8af55d 100644 --- a/src/components/views/rooms/MessageComposer.js +++ b/src/components/views/rooms/MessageComposer.js @@ -279,7 +279,6 @@ export default class MessageComposer extends React.Component { tombstone: this._getRoomTombstone(), canSendMessages: this.props.room.maySendMessage(), showCallButtons: SettingsStore.getValue("showCallButtonsInComposer"), - showSendButton: SettingsStore.getValue("MessageComposerInput.showSendButton"), hasConference: WidgetStore.instance.doesRoomHaveConference(this.props.room), joinedConference: WidgetStore.instance.isJoinedToConferenceIn(this.props.room), isComposerEmpty: true, @@ -298,12 +297,6 @@ export default class MessageComposer extends React.Component { } }; - onShowSendButtonChanged = () => { - this.setState({ - showSendButton: SettingsStore.getValue("MessageComposerInput.showSendButton"), - }); - } - _onWidgetUpdate = () => { this.setState({hasConference: WidgetStore.instance.doesRoomHaveConference(this.props.room)}); }; @@ -316,8 +309,6 @@ export default class MessageComposer extends React.Component { this.dispatcherRef = dis.register(this.onAction); MatrixClientPeg.get().on("RoomState.events", this._onRoomStateEvents); this._waitForOwnMember(); - this.showSendButtonRef = SettingsStore.watchSetting( - "MessageComposerInput.showSendButton", null, this.onShowSendButtonChanged); } _waitForOwnMember() { @@ -343,7 +334,6 @@ export default class MessageComposer extends React.Component { WidgetStore.instance.removeListener(UPDATE_EVENT, this._onWidgetUpdate); ActiveWidgetStore.removeListener('update', this._onActiveWidgetUpdate); dis.unregister(this.dispatcherRef); - SettingsStore.unwatchSetting(this.showSendButtonRef); } _onRoomStateEvents(ev, state) { diff --git a/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.js b/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.js index eff0824d59..4d8493401e 100644 --- a/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.js +++ b/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.js @@ -34,7 +34,6 @@ export default class PreferencesUserSettingsTab extends React.Component { 'MessageComposerInput.suggestEmoji', 'sendTypingNotifications', 'MessageComposerInput.ctrlEnterToSend', - `MessageComposerInput.showSendButton`, ]; static TIMELINE_SETTINGS = [ diff --git a/src/settings/Settings.ts b/src/settings/Settings.ts index 2d8385240c..b239b809fe 100644 --- a/src/settings/Settings.ts +++ b/src/settings/Settings.ts @@ -336,11 +336,6 @@ export const SETTINGS: {[setting: string]: ISetting} = { displayName: isMac ? _td("Use Command + Enter to send a message") : _td("Use Ctrl + Enter to send a message"), default: false, }, - "MessageComposerInput.showSendButton": { - supportedLevels: LEVELS_ACCOUNT_SETTINGS, - displayName: _td("Show send message button"), - default: false, - }, "MessageComposerInput.autoReplaceEmoji": { supportedLevels: LEVELS_ACCOUNT_SETTINGS, displayName: _td('Automatically replace plain text Emoji'), From daff94ecbcdfb1592c483112289412296c8720b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Fri, 12 Feb 2021 15:47:33 +0100 Subject: [PATCH 057/457] i18n 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 | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 6baccf95de..27ec207dda 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -799,7 +799,6 @@ "Show typing notifications": "Show typing notifications", "Use Command + Enter to send a message": "Use Command + Enter to send a message", "Use Ctrl + Enter to send a message": "Use Ctrl + Enter to send a message", - "Show send message button": "Show send message button", "Automatically replace plain text Emoji": "Automatically replace plain text Emoji", "Mirror local video feed": "Mirror local video feed", "Enable Community Filter Panel": "Enable Community Filter Panel", @@ -1404,6 +1403,7 @@ "Invited": "Invited", "Filter room members": "Filter room members", "%(userName)s (power %(powerLevelNumber)s)": "%(userName)s (power %(powerLevelNumber)s)", + "Send message": "Send message", "Voice call": "Voice call", "Video call": "Video call", "Hangup": "Hangup", @@ -1413,7 +1413,6 @@ "Send a reply…": "Send a reply…", "Send an encrypted message…": "Send an encrypted message…", "Send a message…": "Send a message…", - "Send message": "Send message", "The conversation continues here.": "The conversation continues here.", "This room has been replaced and is no longer active.": "This room has been replaced and is no longer active.", "You do not have permission to post to this room": "You do not have permission to post to this room", From b26951714938a40a73f23c77db44d4a2b98769bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Fri, 12 Feb 2021 15:52:42 +0100 Subject: [PATCH 058/457] Removed wrapper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- src/components/views/rooms/MessageComposer.js | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/components/views/rooms/MessageComposer.js b/src/components/views/rooms/MessageComposer.js index f6fc8af55d..a78cf323c6 100644 --- a/src/components/views/rooms/MessageComposer.js +++ b/src/components/views/rooms/MessageComposer.js @@ -52,13 +52,11 @@ ComposerAvatar.propTypes = { function SendButton(props) { return ( -
- -
+ ); } From 97f5b6920c8d25588390aa6ff2c6f9dd54b379e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Fri, 12 Feb 2021 16:48:46 +0100 Subject: [PATCH 059/457] Check if the method is defined before calling it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- src/components/views/rooms/SendMessageComposer.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/views/rooms/SendMessageComposer.js b/src/components/views/rooms/SendMessageComposer.js index ca27141c02..9a14e33d05 100644 --- a/src/components/views/rooms/SendMessageComposer.js +++ b/src/components/views/rooms/SendMessageComposer.js @@ -538,7 +538,9 @@ export default class SendMessageComposer extends React.Component { } onChange = () => { - this.props.onIsEmptyChanged(this.model.isEmpty); + if (this.props.onIsEmptyChanged) { + this.props.onIsEmptyChanged(this.model.isEmpty); + } } render() { From 130e4f7bfddffb48d35a4a5a5adaf090d889905b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Fri, 12 Feb 2021 17:06:02 +0100 Subject: [PATCH 060/457] Added some styling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- res/css/views/rooms/_MessageComposer.scss | 26 +++++++++++++++++-- src/components/views/rooms/MessageComposer.js | 2 +- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/res/css/views/rooms/_MessageComposer.scss b/res/css/views/rooms/_MessageComposer.scss index 8b34318f1d..c24e4912d4 100644 --- a/res/css/views/rooms/_MessageComposer.scss +++ b/res/css/views/rooms/_MessageComposer.scss @@ -247,8 +247,30 @@ limitations under the License. mask-image: url('$(res)/img/element-icons/room/composer/sticker.svg'); } -.mx_MessageComposer_sendMessage::before { - mask-image: url('$(res)/img/element-icons/send-message.svg'); +.mx_MessageComposer_sendMessage { + cursor: pointer; + position: relative; + margin-right: 6px; + width: 32px; + height: 32px; + border-radius: 100%; + background-color: $button-bg-color; + + &:before { + position: absolute; + height: 16px; + width: 16px; + top: 8px; + left: 9px; + + mask-image: url('$(res)/img/element-icons/send-message.svg'); + mask-repeat: no-repeat; + mask-size: contain; + mask-position: center; + + background-color: $button-fg-color; + content: ''; + } } .mx_MessageComposer_formatting { diff --git a/src/components/views/rooms/MessageComposer.js b/src/components/views/rooms/MessageComposer.js index d023d334c3..d70f273be2 100644 --- a/src/components/views/rooms/MessageComposer.js +++ b/src/components/views/rooms/MessageComposer.js @@ -53,7 +53,7 @@ ComposerAvatar.propTypes = { function SendButton(props) { return ( From 3983c15302772ebfd3bc04670bf4d3dd7b7b1762 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Fri, 12 Feb 2021 17:11:24 +0100 Subject: [PATCH 061/457] Delint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- res/css/views/rooms/_MessageComposer.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/css/views/rooms/_MessageComposer.scss b/res/css/views/rooms/_MessageComposer.scss index c24e4912d4..2789ffdfb7 100644 --- a/res/css/views/rooms/_MessageComposer.scss +++ b/res/css/views/rooms/_MessageComposer.scss @@ -256,7 +256,7 @@ limitations under the License. border-radius: 100%; background-color: $button-bg-color; - &:before { + &::before { position: absolute; height: 16px; width: 16px; From f420c8598516b4f939b7ab90f5fa263db2aaa94a Mon Sep 17 00:00:00 2001 From: Jaiwanth Date: Mon, 15 Feb 2021 19:13:09 +0530 Subject: [PATCH 062/457] Added invite option to room's context menu Signed-off-by: Jaiwanth --- res/css/views/rooms/_RoomTile.scss | 4 ++++ src/components/views/rooms/RoomTile.tsx | 17 ++++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/res/css/views/rooms/_RoomTile.scss b/res/css/views/rooms/_RoomTile.scss index 8eca3f1efa..377b207490 100644 --- a/res/css/views/rooms/_RoomTile.scss +++ b/res/css/views/rooms/_RoomTile.scss @@ -188,6 +188,10 @@ limitations under the License. .mx_RoomTile_iconSettings::before { mask-image: url('$(res)/img/element-icons/settings.svg'); } + + .mx_RoomTile_iconInvite::before { + mask-image: url('$(res)/img/element-icons/room/invite.svg'); + } .mx_RoomTile_iconSignOut::before { mask-image: url('$(res)/img/element-icons/leave.svg'); diff --git a/src/components/views/rooms/RoomTile.tsx b/src/components/views/rooms/RoomTile.tsx index 835447dc18..3a34a0daaa 100644 --- a/src/components/views/rooms/RoomTile.tsx +++ b/src/components/views/rooms/RoomTile.tsx @@ -331,6 +331,17 @@ export default class RoomTile extends React.PureComponent { this.setState({generalMenuPosition: null}); // hide the menu }; + private onInviteClick = (ev: ButtonEvent) => { + ev.preventDefault(); + ev.stopPropagation(); + + dis.dispatch({ + action: 'view_invite', + roomId: this.props.room.roomId, + }); + this.setState({generalMenuPosition: null}); // hide the menu + }; + private async saveNotifState(ev: ButtonEvent, newState: Volume) { ev.preventDefault(); ev.stopPropagation(); @@ -470,7 +481,11 @@ export default class RoomTile extends React.PureComponent { label={lowPriorityLabel} iconClassName="mx_RoomTile_iconArrowDown" /> - + Date: Mon, 15 Feb 2021 20:52:19 +0530 Subject: [PATCH 063/457] Check whether user has permission to invite Signed-off-by: Jaiwanth --- res/css/views/rooms/_RoomTile.scss | 2 +- src/components/views/rooms/RoomTile.tsx | 22 +++++++++++++++++----- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/res/css/views/rooms/_RoomTile.scss b/res/css/views/rooms/_RoomTile.scss index 377b207490..72d29dfd4c 100644 --- a/res/css/views/rooms/_RoomTile.scss +++ b/res/css/views/rooms/_RoomTile.scss @@ -188,7 +188,7 @@ limitations under the License. .mx_RoomTile_iconSettings::before { mask-image: url('$(res)/img/element-icons/settings.svg'); } - + .mx_RoomTile_iconInvite::before { mask-image: url('$(res)/img/element-icons/room/invite.svg'); } diff --git a/src/components/views/rooms/RoomTile.tsx b/src/components/views/rooms/RoomTile.tsx index 3a34a0daaa..f168235335 100644 --- a/src/components/views/rooms/RoomTile.tsx +++ b/src/components/views/rooms/RoomTile.tsx @@ -462,6 +462,16 @@ export default class RoomTile extends React.PureComponent { const isLowPriority = roomTags.includes(DefaultTagID.LowPriority); const lowPriorityLabel = _t("Low Priority"); + const inRoom = this.props.room && this.props.room.getMyMembership() === "join"; + const userId = MatrixClientPeg.get().getUserId(); + let canInvite = inRoom; + const powerLevels = this.props.room.currentState + .getStateEvents("m.room.power_levels", "") + ?.getContent(); + const me = this.props.room.getMember(userId); + if (powerLevels && me && powerLevels.invite > me.powerLevel) { + canInvite = false; + } contextMenu = { label={lowPriorityLabel} iconClassName="mx_RoomTile_iconArrowDown" /> - + {canInvite ? ( + + ) : null} Date: Tue, 16 Feb 2021 18:59:22 +0530 Subject: [PATCH 064/457] Update src/components/views/rooms/RoomTile.tsx --- src/components/views/rooms/RoomTile.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/rooms/RoomTile.tsx b/src/components/views/rooms/RoomTile.tsx index f168235335..3894f557fc 100644 --- a/src/components/views/rooms/RoomTile.tsx +++ b/src/components/views/rooms/RoomTile.tsx @@ -462,7 +462,7 @@ export default class RoomTile extends React.PureComponent { const isLowPriority = roomTags.includes(DefaultTagID.LowPriority); const lowPriorityLabel = _t("Low Priority"); - const inRoom = this.props.room && this.props.room.getMyMembership() === "join"; + const inRoom = this.props.room.getMyMembership() === "join"; const userId = MatrixClientPeg.get().getUserId(); let canInvite = inRoom; const powerLevels = this.props.room.currentState From 21b9ab9d8595ffbdb881e8c4e4ae33d9829d0dcb Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Tue, 16 Feb 2021 15:17:51 -0700 Subject: [PATCH 065/457] Add an optional config option to make the welcome page the login page This is commonly requested by deployments with custom setups or those using SSO. Instead of having them all ship the same welcome.html with redirect code in it, we can offer a built-in redirect. Note that this doesn't actually redirect and instead just replaces the view. This is to make the change less invasive as otherwise it involves changing the routing layers. --- src/components/structures/MatrixChat.tsx | 6 ++++-- src/utils/{pages.js => pages.ts} | 17 +++++++++++------ 2 files changed, 15 insertions(+), 8 deletions(-) rename src/utils/{pages.js => pages.ts} (68%) diff --git a/src/components/structures/MatrixChat.tsx b/src/components/structures/MatrixChat.tsx index 5045e44182..35e08e8d37 100644 --- a/src/components/structures/MatrixChat.tsx +++ b/src/components/structures/MatrixChat.tsx @@ -82,6 +82,7 @@ import {UIFeature} from "../../settings/UIFeature"; import { CommunityPrototypeStore } from "../../stores/CommunityPrototypeStore"; import DialPadModal from "../views/voip/DialPadModal"; import { showToast as showMobileGuideToast } from '../../toasts/MobileGuideToast'; +import { shouldUseLoginForWelcome } from "../../utils/pages"; /** constants for MatrixChat.state.view */ export enum Views { @@ -1988,7 +1989,7 @@ export default class MatrixChat extends React.PureComponent {
); } - } else if (this.state.view === Views.WELCOME) { + } else if (this.state.view === Views.WELCOME && !shouldUseLoginForWelcome(SdkConfig.get())) { const Welcome = sdk.getComponent('auth.Welcome'); view = ; } else if (this.state.view === Views.REGISTER && SettingsStore.getValue(UIFeature.Registration)) { @@ -2020,7 +2021,8 @@ export default class MatrixChat extends React.PureComponent { {...this.getServerProperties()} /> ); - } else if (this.state.view === Views.LOGIN) { + } else if (this.state.view === Views.LOGIN + || (this.state.view === Views.WELCOME && shouldUseLoginForWelcome(SdkConfig.get()))) { const showPasswordReset = SettingsStore.getValue(UIFeature.PasswordReset); const Login = sdk.getComponent('structures.auth.Login'); view = ( diff --git a/src/utils/pages.js b/src/utils/pages.ts similarity index 68% rename from src/utils/pages.js rename to src/utils/pages.ts index d63ca3f2c7..bae76be29d 100644 --- a/src/utils/pages.js +++ b/src/utils/pages.ts @@ -1,5 +1,5 @@ /* -Copyright 2019 New Vector Ltd +Copyright 2019, 2021 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -14,12 +14,12 @@ See the License for the specific language governing permissions and limitations under the License. */ -export function getHomePageUrl(appConfig) { +import { ConfigOptions } from "../SdkConfig"; + +export function getHomePageUrl(appConfig: ConfigOptions): string | null { const pagesConfig = appConfig.embeddedPages; - let pageUrl = null; - if (pagesConfig) { - pageUrl = pagesConfig.homeUrl; - } + let pageUrl = pagesConfig?.homeUrl; + if (!pageUrl) { // This is a deprecated config option for the home page // (despite the name, given we also now have a welcome @@ -29,3 +29,8 @@ export function getHomePageUrl(appConfig) { return pageUrl; } + +export function shouldUseLoginForWelcome(appConfig: ConfigOptions): boolean { + const pagesConfig = appConfig.embeddedPages; + return pagesConfig?.loginForWelcome === true; +} From 9420cc35cc885b1284701eeae7ebe555dae98425 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Wed, 17 Feb 2021 13:22:19 +0100 Subject: [PATCH 066/457] Added a key MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- src/components/views/rooms/MessageComposer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/rooms/MessageComposer.js b/src/components/views/rooms/MessageComposer.js index d70f273be2..cd1a51245e 100644 --- a/src/components/views/rooms/MessageComposer.js +++ b/src/components/views/rooms/MessageComposer.js @@ -483,7 +483,7 @@ export default class MessageComposer extends React.Component { if (!this.state.isComposerEmpty) { controls.push( - , + , ); } } else if (this.state.tombstone) { From a7847f25147c8a42f5dad47a4b313bd52df932bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Wed, 17 Feb 2021 13:25:53 +0100 Subject: [PATCH 067/457] onIsEmptyChanged() -> onChange() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- src/components/views/rooms/MessageComposer.js | 7 ++++--- src/components/views/rooms/SendMessageComposer.js | 6 ++---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/components/views/rooms/MessageComposer.js b/src/components/views/rooms/MessageComposer.js index cd1a51245e..d70cb5c786 100644 --- a/src/components/views/rooms/MessageComposer.js +++ b/src/components/views/rooms/MessageComposer.js @@ -415,9 +415,10 @@ export default class MessageComposer extends React.Component { this.messageComposerInput._sendMessage(); } - onIsEmptyChanged = (isEmpty) => { + onChange = () => { + if (!this.messageComposerInput) return; this.setState({ - isComposerEmpty: isEmpty, + isComposerEmpty: this.messageComposerInput.model.isEmpty, }); } @@ -446,7 +447,7 @@ export default class MessageComposer extends React.Component { resizeNotifier={this.props.resizeNotifier} permalinkCreator={this.props.permalinkCreator} replyToEvent={this.props.replyToEvent} - onIsEmptyChanged={this.onIsEmptyChanged} + onChange={this.onChange} />, , , diff --git a/src/components/views/rooms/SendMessageComposer.js b/src/components/views/rooms/SendMessageComposer.js index 9a14e33d05..657d67aee2 100644 --- a/src/components/views/rooms/SendMessageComposer.js +++ b/src/components/views/rooms/SendMessageComposer.js @@ -117,7 +117,7 @@ export default class SendMessageComposer extends React.Component { placeholder: PropTypes.string, permalinkCreator: PropTypes.object.isRequired, replyToEvent: PropTypes.object, - onIsEmptyChanged: PropTypes.func, + onChange: PropTypes.func, }; static contextType = MatrixClientContext; @@ -538,9 +538,7 @@ export default class SendMessageComposer extends React.Component { } onChange = () => { - if (this.props.onIsEmptyChanged) { - this.props.onIsEmptyChanged(this.model.isEmpty); - } + if (this.props.onChange) this.props.onChange(); } render() { From 86fe5f778d3eb413621d87ab720fbf32206855c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Wed, 17 Feb 2021 13:32:48 +0100 Subject: [PATCH 068/457] Use modal as a param MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- src/components/views/rooms/MessageComposer.js | 5 ++--- src/components/views/rooms/SendMessageComposer.js | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/components/views/rooms/MessageComposer.js b/src/components/views/rooms/MessageComposer.js index d70cb5c786..819f9749e7 100644 --- a/src/components/views/rooms/MessageComposer.js +++ b/src/components/views/rooms/MessageComposer.js @@ -415,10 +415,9 @@ export default class MessageComposer extends React.Component { this.messageComposerInput._sendMessage(); } - onChange = () => { - if (!this.messageComposerInput) return; + onChange = (model) => { this.setState({ - isComposerEmpty: this.messageComposerInput.model.isEmpty, + isComposerEmpty: model.isEmpty, }); } diff --git a/src/components/views/rooms/SendMessageComposer.js b/src/components/views/rooms/SendMessageComposer.js index 657d67aee2..068627455d 100644 --- a/src/components/views/rooms/SendMessageComposer.js +++ b/src/components/views/rooms/SendMessageComposer.js @@ -538,7 +538,7 @@ export default class SendMessageComposer extends React.Component { } onChange = () => { - if (this.props.onChange) this.props.onChange(); + if (this.props.onChange) this.props.onChange(this.model); } render() { From 5de99c7708c58b2808d288160ce8fb69f4f5027c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Thu, 18 Feb 2021 19:40:24 +0100 Subject: [PATCH 069/457] Fix licenses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- res/css/views/settings/_SpellCheckLanguages.scss | 3 +-- src/components/views/elements/SpellCheckLanguagesDropdown.tsx | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/res/css/views/settings/_SpellCheckLanguages.scss b/res/css/views/settings/_SpellCheckLanguages.scss index ddfa0bf9e0..bb322c983f 100644 --- a/res/css/views/settings/_SpellCheckLanguages.scss +++ b/res/css/views/settings/_SpellCheckLanguages.scss @@ -1,6 +1,5 @@ /* -Copyright 2019 New Vector Ltd -Copyright 2019 The Matrix.org Foundation C.I.C. +Copyright 2021 Šimon Brandner Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/src/components/views/elements/SpellCheckLanguagesDropdown.tsx b/src/components/views/elements/SpellCheckLanguagesDropdown.tsx index 53c3f310b7..029d162573 100644 --- a/src/components/views/elements/SpellCheckLanguagesDropdown.tsx +++ b/src/components/views/elements/SpellCheckLanguagesDropdown.tsx @@ -1,6 +1,5 @@ /* -Copyright 2017 Marcel Radzio (MTRNord) -Copyright 2017 Vector Creations Ltd. +Copyright 2021 Šimon Brandner Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. From ed02503462d93e43659bddd3280a19a0b31e26f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Thu, 18 Feb 2021 19:41:19 +0100 Subject: [PATCH 070/457] Fix one more license MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- src/components/views/settings/SpellCheckSettings.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/settings/SpellCheckSettings.tsx b/src/components/views/settings/SpellCheckSettings.tsx index bfe0774570..d08f263b5f 100644 --- a/src/components/views/settings/SpellCheckSettings.tsx +++ b/src/components/views/settings/SpellCheckSettings.tsx @@ -1,5 +1,5 @@ /* -Copyright 2019 New Vector Ltd +Copyright 2021 Šimon Brandner Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. From 2ebc1252cbbfc9731dc412947287ef5e4c9ce460 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Thu, 18 Feb 2021 19:54:54 +0100 Subject: [PATCH 071/457] Removed unnecessary functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- .../elements/SpellCheckLanguagesDropdown.tsx | 37 ++++++++++--------- .../tabs/user/GeneralUserSettingsTab.js | 6 ++- src/languageHandler.tsx | 14 ------- 3 files changed, 25 insertions(+), 32 deletions(-) diff --git a/src/components/views/elements/SpellCheckLanguagesDropdown.tsx b/src/components/views/elements/SpellCheckLanguagesDropdown.tsx index 029d162573..c647f6e410 100644 --- a/src/components/views/elements/SpellCheckLanguagesDropdown.tsx +++ b/src/components/views/elements/SpellCheckLanguagesDropdown.tsx @@ -18,7 +18,7 @@ import React from 'react'; import Dropdown from "../../views/elements/Dropdown" import * as sdk from '../../../index'; -import * as languageHandler from '../../../languageHandler'; +import PlatformPeg from "../../../PlatformPeg"; import SettingsStore from "../../../settings/SettingsStore"; import { _t } from "../../../languageHandler"; @@ -52,23 +52,26 @@ export default class SpellCheckLanguagesDropdown extends React.Component { - languages.sort(function(a, b) { - if (a < b) return -1; - if (a > b) return 1; - return 0; - }); - const langs = []; - languages.forEach((language) => { - langs.push({ - label: language, - value: language, + const plaf = PlatformPeg.get(); + if (plaf) { + plaf.getAvailableSpellCheckLanguages().then((languages) => { + languages.sort(function(a, b) { + if (a < b) return -1; + if (a > b) return 1; + return 0; + }); + const langs = []; + languages.forEach((language) => { + langs.push({ + label: language, + value: language, + }) }) - }) - this.setState({languages: langs}); - }).catch((e) => { - this.setState({languages: ['en']}); - }); + this.setState({languages: langs}); + }).catch((e) => { + this.setState({languages: ['en']}); + }); + } } _onSearchChange(search) { diff --git a/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js b/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js index febbcc8e36..e87dca88c8 100644 --- a/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js +++ b/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js @@ -188,7 +188,10 @@ export default class GeneralUserSettingsTab extends React.Component { SettingsStore.setValue("spell-check-languages", null, SettingLevel.DEVICE, languages); this.setState({spellCheckLanguages: languages}); - languageHandler.setSpellCheckLanguages(languages); + const plaf = PlatformPeg.get(); + if (plaf) { + plaf.setSpellCheckLanguages(languages); + } }; _onPasswordChangeError = (err) => { @@ -402,6 +405,7 @@ export default class GeneralUserSettingsTab extends React.Component { render() { const plaf = PlatformPeg.get(); const supportsMultiLanguageSpellCheck = plaf.supportsMultiLanguageSpellCheck(); + console.log("LOG", supportsMultiLanguageSpellCheck); const discoWarning = this.state.requiredPolicyInfo.hasTerms ? { - const plaf = PlatformPeg.get(); - if (plaf) { - return plaf.getAvailableSpellCheckLanguages(); - } -} - export function getAllLanguagesFromJson() { return getLangsJson().then((langsObject) => { const langs = []; From 305d64cda88aebef8e2a0e799606224baeac4dc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Thu, 18 Feb 2021 20:09:39 +0100 Subject: [PATCH 072/457] Removed log MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- .../views/settings/tabs/user/GeneralUserSettingsTab.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js b/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js index e87dca88c8..41597604e9 100644 --- a/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js +++ b/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js @@ -405,7 +405,6 @@ export default class GeneralUserSettingsTab extends React.Component { render() { const plaf = PlatformPeg.get(); const supportsMultiLanguageSpellCheck = plaf.supportsMultiLanguageSpellCheck(); - console.log("LOG", supportsMultiLanguageSpellCheck); const discoWarning = this.state.requiredPolicyInfo.hasTerms ? Date: Thu, 18 Feb 2021 20:12:48 +0100 Subject: [PATCH 073/457] Use getSpellCheckLanguages() instead of a setting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- src/BasePlatform.ts | 4 ++++ .../settings/tabs/user/GeneralUserSettingsTab.js | 11 ++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/BasePlatform.ts b/src/BasePlatform.ts index fe655371a5..9d7077097b 100644 --- a/src/BasePlatform.ts +++ b/src/BasePlatform.ts @@ -250,6 +250,10 @@ export default abstract class BasePlatform { setSpellCheckLanguages(preferredLangs: string[]) {} + getSpellCheckLanguages(): Promise | null { + return null; + } + getAvailableSpellCheckLanguages(): Promise | null { return null; } diff --git a/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js b/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js index 41597604e9..3936864215 100644 --- a/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js +++ b/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js @@ -50,7 +50,7 @@ export default class GeneralUserSettingsTab extends React.Component { this.state = { language: languageHandler.getCurrentLanguage(), - spellCheckLanguages: SettingsStore.getValue("spell-check-languages", null, false), + spellCheckLanguages: [], haveIdServer: Boolean(MatrixClientPeg.get().getIdentityServerUrl()), serverSupportsSeparateAddAndBind: null, idServerHasUnsignedTerms: false, @@ -87,6 +87,15 @@ export default class GeneralUserSettingsTab extends React.Component { this._getThreepidState(); } + async componentDidMount() { + const plaf = PlatformPeg.get(); + if (plaf) { + this.setState({ + spellCheckLanguages: await plaf.getSpellCheckLanguages(), + }); + } + } + componentWillUnmount() { dis.unregister(this.dispatcherRef); } From 5a6e393fa2c6344a00efc14ab4eb17fc6a258a64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Thu, 18 Feb 2021 20:13:55 +0100 Subject: [PATCH 074/457] Removed spell-check-languages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- .../views/settings/tabs/user/GeneralUserSettingsTab.js | 1 - src/settings/Settings.ts | 4 ---- 2 files changed, 5 deletions(-) diff --git a/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js b/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js index 3936864215..b17ab18c39 100644 --- a/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js +++ b/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js @@ -194,7 +194,6 @@ export default class GeneralUserSettingsTab extends React.Component { }; _onSpellCheckLanguagesChange = (languages) => { - SettingsStore.setValue("spell-check-languages", null, SettingLevel.DEVICE, languages); this.setState({spellCheckLanguages: languages}); const plaf = PlatformPeg.get(); diff --git a/src/settings/Settings.ts b/src/settings/Settings.ts index b486f0fbf8..ca5e2f1d04 100644 --- a/src/settings/Settings.ts +++ b/src/settings/Settings.ts @@ -424,10 +424,6 @@ export const SETTINGS: {[setting: string]: ISetting} = { supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG, default: "en", }, - "spell-check-languages": { - supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG, - default: ["en-US"], - }, "breadcrumb_rooms": { // not really a setting supportedLevels: [SettingLevel.ACCOUNT], From e3f08adacb082ef0f6e72e7b20adc494a86aae5f Mon Sep 17 00:00:00 2001 From: RiotRobot Date: Wed, 24 Feb 2021 17:27:56 +0000 Subject: [PATCH 075/457] Upgrade matrix-js-sdk to 9.8.0-rc.1 --- package.json | 2 +- yarn.lock | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index d4f931d811..7b4e577406 100644 --- a/package.json +++ b/package.json @@ -80,7 +80,7 @@ "katex": "^0.12.0", "linkifyjs": "^2.1.9", "lodash": "^4.17.20", - "matrix-js-sdk": "github:matrix-org/matrix-js-sdk#develop", + "matrix-js-sdk": "9.8.0-rc.1", "matrix-widget-api": "^0.1.0-beta.13", "minimist": "^1.2.5", "pako": "^2.0.3", diff --git a/yarn.lock b/yarn.lock index 01450908cc..bef26e27b4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5572,9 +5572,10 @@ mathml-tag-names@^2.1.3: resolved "https://registry.yarnpkg.com/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz#4ddadd67308e780cf16a47685878ee27b736a0a3" integrity sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg== -"matrix-js-sdk@github:matrix-org/matrix-js-sdk#develop": - version "9.7.0" - resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/c82bc35202f93efa2cb9b27b140f83df37c64ab2" +matrix-js-sdk@9.8.0-rc.1: + version "9.8.0-rc.1" + resolved "https://registry.yarnpkg.com/matrix-js-sdk/-/matrix-js-sdk-9.8.0-rc.1.tgz#229122583bec5971f22a423a4a40d749e07602d9" + integrity sha512-Tmo5cdyBBgYcMZMaAavEvtdCsEwr5sYE0RLd6etLOSTxmGRSYpqKvvKQqGsYrogmZYNbx9nNZYYYV2aJkCKcQg== dependencies: "@babel/runtime" "^7.12.5" another-json "^0.2.0" From 364f24851355fe0b1a716cd5973bbc19cf575d7a Mon Sep 17 00:00:00 2001 From: RiotRobot Date: Wed, 24 Feb 2021 17:32:53 +0000 Subject: [PATCH 076/457] Prepare changelog for v3.15.0-rc.1 --- CHANGELOG.md | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c87f1c62e6..e727adabfa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,65 @@ +Changes in [3.15.0-rc.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.15.0-rc.1) (2021-02-24) +=============================================================================================================== +[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.14.0...v3.15.0-rc.1) + + * Upgrade to JS SDK 9.8.0-rc.1 + * Translations update from Weblate + [\#5683](https://github.com/matrix-org/matrix-react-sdk/pull/5683) + * Fix object diffing when objects have different keys + [\#5681](https://github.com/matrix-org/matrix-react-sdk/pull/5681) + * Add if it's missing + [\#5673](https://github.com/matrix-org/matrix-react-sdk/pull/5673) + * Add email only if the verification is complete + [\#5629](https://github.com/matrix-org/matrix-react-sdk/pull/5629) + * Fix portrait videocalls + [\#5676](https://github.com/matrix-org/matrix-react-sdk/pull/5676) + * Tweak code block icon positions + [\#5643](https://github.com/matrix-org/matrix-react-sdk/pull/5643) + * Revert "Improve URL preview formatting and image upload thumbnail size" + [\#5677](https://github.com/matrix-org/matrix-react-sdk/pull/5677) + * Fix context menu leaving visible area + [\#5644](https://github.com/matrix-org/matrix-react-sdk/pull/5644) + * Jitsi conferences names, take 3 + [\#5675](https://github.com/matrix-org/matrix-react-sdk/pull/5675) + * Update isUserOnDarkTheme to take use_system_theme in account + [\#5670](https://github.com/matrix-org/matrix-react-sdk/pull/5670) + * Discard some dead code + [\#5665](https://github.com/matrix-org/matrix-react-sdk/pull/5665) + * Add developer tool to explore and edit settings + [\#5664](https://github.com/matrix-org/matrix-react-sdk/pull/5664) + * Use and create new room helpers + [\#5663](https://github.com/matrix-org/matrix-react-sdk/pull/5663) + * Clear message previews when the maximum limit is reached for history + [\#5661](https://github.com/matrix-org/matrix-react-sdk/pull/5661) + * VoIP virtual rooms, mk II + [\#5639](https://github.com/matrix-org/matrix-react-sdk/pull/5639) + * Disable chat effects when reduced motion preferred + [\#5660](https://github.com/matrix-org/matrix-react-sdk/pull/5660) + * Improve URL preview formatting and image upload thumbnail size + [\#5637](https://github.com/matrix-org/matrix-react-sdk/pull/5637) + * Fix border radius when the panel is collapsed + [\#5641](https://github.com/matrix-org/matrix-react-sdk/pull/5641) + * Use a more generic layout setting - useIRCLayout → layout + [\#5571](https://github.com/matrix-org/matrix-react-sdk/pull/5571) + * Remove redundant lockOrigin parameter from usercontent + [\#5657](https://github.com/matrix-org/matrix-react-sdk/pull/5657) + * Set ICE candidate pool size option + [\#5655](https://github.com/matrix-org/matrix-react-sdk/pull/5655) + * Prepare to encrypt when a call arrives + [\#5654](https://github.com/matrix-org/matrix-react-sdk/pull/5654) + * Use config for host signup branding + [\#5650](https://github.com/matrix-org/matrix-react-sdk/pull/5650) + * Use randomly generated conference names for Jitsi + [\#5649](https://github.com/matrix-org/matrix-react-sdk/pull/5649) + * Modified regex to account for an immediate new line after slash commands + [\#5647](https://github.com/matrix-org/matrix-react-sdk/pull/5647) + * Fix codeblock scrollbar color for non-Firefox + [\#5642](https://github.com/matrix-org/matrix-react-sdk/pull/5642) + * Fix codeblock scrollbar colors + [\#5630](https://github.com/matrix-org/matrix-react-sdk/pull/5630) + * Added loading and disabled the button while searching for server + [\#5634](https://github.com/matrix-org/matrix-react-sdk/pull/5634) + Changes in [3.14.0](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.14.0) (2021-02-16) ===================================================================================================== [Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.14.0-rc.1...v3.14.0) From 8860c8bfe7b48cbfb230f28e81d48ea7f474e3f4 Mon Sep 17 00:00:00 2001 From: RiotRobot Date: Wed, 24 Feb 2021 17:32:54 +0000 Subject: [PATCH 077/457] v3.15.0-rc.1 --- package.json | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 7b4e577406..f49b99831f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "matrix-react-sdk", - "version": "3.14.0", + "version": "3.15.0-rc.1", "description": "SDK for matrix.org using React", "author": "matrix.org", "repository": { @@ -27,7 +27,7 @@ "matrix-gen-i18n": "scripts/gen-i18n.js", "matrix-prune-i18n": "scripts/prune-i18n.js" }, - "main": "./src/index.js", + "main": "./lib/index.js", "matrix_src_main": "./src/index.js", "matrix_lib_main": "./lib/index.js", "matrix_lib_typings": "./lib/index.d.ts", @@ -189,5 +189,6 @@ "transformIgnorePatterns": [ "/node_modules/(?!matrix-js-sdk).+$" ] - } + }, + "typings": "./lib/index.d.ts" } From 7030c636f07c32c3616eeddba64e0a0c8dfc6587 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Thu, 25 Feb 2021 15:18:54 +0000 Subject: [PATCH 078/457] Initial Space Store for keeping track of space hierarchies from sync --- src/@types/global.d.ts | 2 + src/stores/SpaceStore.tsx | 462 ++++++++++++++++++ .../notifications/SpaceNotificationState.ts | 82 ++++ 3 files changed, 546 insertions(+) create mode 100644 src/stores/SpaceStore.tsx create mode 100644 src/stores/notifications/SpaceNotificationState.ts diff --git a/src/@types/global.d.ts b/src/@types/global.d.ts index 28f22780a2..4aa6df5488 100644 --- a/src/@types/global.d.ts +++ b/src/@types/global.d.ts @@ -38,6 +38,7 @@ import UserActivity from "../UserActivity"; import {ModalWidgetStore} from "../stores/ModalWidgetStore"; import { WidgetLayoutStore } from "../stores/widgets/WidgetLayoutStore"; import VoipUserMapper from "../VoipUserMapper"; +import {SpaceStoreClass} from "../stores/SpaceStore"; declare global { interface Window { @@ -68,6 +69,7 @@ declare global { mxUserActivity: UserActivity; mxModalWidgetStore: ModalWidgetStore; mxVoipUserMapper: VoipUserMapper; + mxSpaceStore: SpaceStoreClass; } interface Document { diff --git a/src/stores/SpaceStore.tsx b/src/stores/SpaceStore.tsx new file mode 100644 index 0000000000..d675879138 --- /dev/null +++ b/src/stores/SpaceStore.tsx @@ -0,0 +1,462 @@ +/* +Copyright 2021 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 {throttle, sortBy} from "lodash"; +import {EventType} from "matrix-js-sdk/src/@types/event"; +import {Room} from "matrix-js-sdk/src/models/room"; +import {MatrixEvent} from "matrix-js-sdk/src/models/event"; + +import {AsyncStoreWithClient} from "./AsyncStoreWithClient"; +import defaultDispatcher from "../dispatcher/dispatcher"; +import {ActionPayload} from "../dispatcher/payloads"; +import RoomListStore from "./room-list/RoomListStore"; +import SettingsStore from "../settings/SettingsStore"; +import DMRoomMap from "../utils/DMRoomMap"; +import {FetchRoomFn} from "./notifications/ListNotificationState"; +import {SpaceNotificationState} from "./notifications/SpaceNotificationState"; +import {RoomNotificationStateStore} from "./notifications/RoomNotificationStateStore"; +import {DefaultTagID} from "./room-list/models"; +import {EnhancedMap, mapDiff} from "../utils/maps"; +import {setHasDiff} from "../utils/sets"; +import {objectDiff} from "../utils/objects"; +import {arrayHasDiff} from "../utils/arrays"; + +type SpaceKey = string | symbol; + +interface IState {} + +const ACTIVE_SPACE_LS_KEY = "mx_active_space"; + +export const HOME_SPACE = Symbol("home-space"); + +export const UPDATE_TOP_LEVEL_SPACES = Symbol("top-level-spaces"); +export const UPDATE_SELECTED_SPACE = Symbol("selected-space"); +// Space Room ID/HOME_SPACE will be emitted when a Space's children change + +const partitionSpacesAndRooms = (arr: Room[]): [Room[], Room[]] => { // [spaces, rooms] + return arr.reduce((result, room: Room) => { + result[room.isSpaceRoom() ? 0 : 1].push(room); + return result; + }, [[], []]); +}; + +const getOrder = (ev: MatrixEvent): string | null => { + const content = ev.getContent(); + if (typeof content.order === "string" && Array.from(content.order).every((c: string) => { + const charCode = c.charCodeAt(0); + return charCode >= 0x20 && charCode <= 0x7F; + })) { + return content.order; + } + return null; +} + +const getRoomFn: FetchRoomFn = (room: Room) => { + return RoomNotificationStateStore.instance.getRoomState(room); +}; + +export class SpaceStoreClass extends AsyncStoreWithClient { + constructor() { + super(defaultDispatcher, {}); + } + + // The spaces representing the roots of the various tree-like hierarchies + private rootSpaces: Room[] = []; + // The list of rooms not present in any currently joined spaces + private orphanedRooms = new Set(); + // Map from room ID to set of spaces which list it as a child + private parentMap = new EnhancedMap>(); + // Map from space key to SpaceNotificationState instance representing that space + private notificationStateMap = new Map(); + // Map from space key to Set of room IDs that should be shown as part of that space's filter + private spaceFilteredRooms = new Map>(); + // The space currently selected in the Space Panel - if null then `Home` is selected + private _activeSpace?: Room = null; + + public get spacePanelSpaces(): Room[] { + return this.rootSpaces; + } + + public get activeSpace(): Room | null { + return this._activeSpace || null; + } + + public setActiveSpace(space: Room | null) { + if (space === this.activeSpace) return; + + this._activeSpace = space; + this.emit(UPDATE_SELECTED_SPACE, this.activeSpace); + + // persist space selected + if (space) { + window.localStorage.setItem(ACTIVE_SPACE_LS_KEY, space.roomId); + } else { + window.localStorage.removeItem(ACTIVE_SPACE_LS_KEY); + } + } + + public addRoomToSpace(space: Room, roomId: string, via: string[], autoJoin = false) { + return this.matrixClient.sendStateEvent(space.roomId, EventType.SpaceChild, { + via, + auto_join: autoJoin, + }, roomId); + } + + private getChildren(spaceId: string): Room[] { + const room = this.matrixClient?.getRoom(spaceId); + const childEvents = room?.currentState.getStateEvents(EventType.SpaceChild).filter(ev => ev.getContent()?.via); + return sortBy(childEvents, getOrder) + .map(ev => this.matrixClient.getRoom(ev.getStateKey())) + .filter(room => room?.getMyMembership() === "join") || []; + } + + public getChildRooms(spaceId: string): Room[] { + return this.getChildren(spaceId).filter(r => !r.isSpaceRoom()); + } + + public getChildSpaces(spaceId: string): Room[] { + return this.getChildren(spaceId).filter(r => r.isSpaceRoom()); + } + + public getParents(roomId: string, canonicalOnly = false): Room[] { + const room = this.matrixClient?.getRoom(roomId); + return room?.currentState.getStateEvents(EventType.SpaceParent) + .filter(ev => { + const content = ev.getContent(); + if (!content?.via) return false; + // TODO apply permissions check to verify that the parent mapping is valid + if (canonicalOnly && !content?.canonical) return false; + return true; + }) + .map(ev => this.matrixClient.getRoom(ev.getStateKey())) + .filter(Boolean) || []; + } + + public getCanonicalParent(roomId: string): Room | null { + const parents = this.getParents(roomId, true); + return sortBy(parents, r => r.roomId)?.[0] || null; + } + + public getSpaces = () => { + return this.matrixClient.getRooms().filter(r => r.isSpaceRoom() && r.getMyMembership() === "join"); + }; + + public getSpaceFilteredRoomIds = (space: Room | null): Set => { + return this.spaceFilteredRooms.get(space?.roomId || HOME_SPACE) || new Set(); + }; + + public rebuild = throttle(() => { // exported for tests + const visibleRooms = this.matrixClient.getVisibleRooms(); + + // Sort spaces by room ID to force the loop breaking to be deterministic + const spaces = sortBy(this.getSpaces(), space => space.roomId); + const unseenChildren = new Set([...visibleRooms, ...spaces]); + + const backrefs = new EnhancedMap>(); + + // TODO handle cleaning up links when a Space is removed + spaces.forEach(space => { + const children = this.getChildren(space.roomId); + children.forEach(child => { + unseenChildren.delete(child); + + backrefs.getOrCreate(child.roomId, new Set()).add(space.roomId); + }); + }); + + const [rootSpaces, orphanedRooms] = partitionSpacesAndRooms(Array.from(unseenChildren)); + + // untested algorithm to handle full-cycles + const detachedNodes = new Set(spaces); + + const markTreeChildren = (rootSpace: Room, unseen: Set) => { + const stack = [rootSpace]; + while (stack.length) { + const op = stack.pop(); + unseen.delete(op); + this.getChildSpaces(op.roomId).forEach(space => { + if (unseen.has(space)) { + stack.push(space); + } + }); + } + }; + + rootSpaces.forEach(rootSpace => { + markTreeChildren(rootSpace, detachedNodes); + }); + + // Handle spaces forming fully cyclical relationships. + // In order, assume each detachedNode is a root unless it has already + // been claimed as the child of prior detached node. + // Work from a copy of the detachedNodes set as it will be mutated as part of this operation. + Array.from(detachedNodes).forEach(detachedNode => { + if (!detachedNodes.has(detachedNode)) return; + // declare this detached node a new root, find its children, without ever looping back to it + detachedNodes.delete(detachedNode); + rootSpaces.push(detachedNode); + markTreeChildren(detachedNode, detachedNodes); + + // TODO only consider a detached node a root space if it has no *parents other than the ones forming cycles + }); + + // TODO neither of these handle an A->B->C->A with an additional C->D + // detachedNodes.forEach(space => { + // rootSpaces.push(space); + // }); + + this.orphanedRooms = new Set(orphanedRooms); + this.rootSpaces = rootSpaces; + this.parentMap = backrefs; + + // if the currently selected space no longer exists, remove its selection + if (this._activeSpace && detachedNodes.has(this._activeSpace)) { + this.setActiveSpace(null); + } + + this.onRoomsUpdate(); // TODO only do this if a change has happened + this.emit(UPDATE_TOP_LEVEL_SPACES, this.spacePanelSpaces); + }, 100, {trailing: true, leading: true}); + + onSpaceUpdate = () => { + this.rebuild(); + } + + private showInHomeSpace = (room: Room) => { + return !this.parentMap.get(room.roomId)?.size // put all orphaned rooms in the Home Space + || DMRoomMap.shared().getUserIdForRoomId(room.roomId) // put all DMs in the Home Space + || RoomListStore.instance.getTagsForRoom(room).includes(DefaultTagID.Favourite) // show all favourites + }; + + // Update a given room due to its tag changing (e.g DM-ness or Fav-ness) + // This can only change whether it shows up in the HOME_SPACE or not + private onRoomUpdate = (room: Room) => { + if (this.showInHomeSpace(room)) { + this.spaceFilteredRooms.get(HOME_SPACE)?.add(room.roomId); + this.emit(HOME_SPACE); + } else if (!this.orphanedRooms.has(room.roomId)) { + this.spaceFilteredRooms.get(HOME_SPACE)?.delete(room.roomId); + this.emit(HOME_SPACE); + } + }; + + private onRoomsUpdate = throttle(() => { + // TODO resolve some updates as deltas + const visibleRooms = this.matrixClient.getVisibleRooms(); + + const oldFilteredRooms = this.spaceFilteredRooms; + this.spaceFilteredRooms = new Map(); + + // put all invites (rooms & spaces) in the Home Space + const invites = this.matrixClient.getRooms().filter(r => r.getMyMembership() === "invite"); + this.spaceFilteredRooms.set(HOME_SPACE, new Set(invites.map(room => room.roomId))); + + visibleRooms.forEach(room => { + if (this.showInHomeSpace(room)) { + this.spaceFilteredRooms.get(HOME_SPACE).add(room.roomId); + } + }); + + this.rootSpaces.forEach(s => { + // traverse each space tree in DFS to build up the supersets as you go up, + // reusing results from like subtrees. + const fn = (spaceId: string, parentPath: Set): Set => { + if (parentPath.has(spaceId)) return; // prevent cycles + + // reuse existing results if multiple similar branches exist + if (this.spaceFilteredRooms.has(spaceId)) { + return this.spaceFilteredRooms.get(spaceId); + } + + const [childSpaces, childRooms] = partitionSpacesAndRooms(this.getChildren(spaceId)); + const roomIds = new Set(childRooms.map(r => r.roomId)); + const space = this.matrixClient?.getRoom(spaceId); + + // Add relevant DMs + space?.getJoinedMembers().forEach(member => { + DMRoomMap.shared().getDMRoomsForUserId(member.userId).forEach(roomId => { + roomIds.add(roomId); + }); + }); + + const newPath = new Set(parentPath).add(spaceId); + childSpaces.forEach(childSpace => { + fn(childSpace.roomId, newPath)?.forEach(roomId => { + roomIds.add(roomId); + }); + }); + this.spaceFilteredRooms.set(spaceId, roomIds); + return roomIds; + }; + + fn(s.roomId, new Set()); + }); + + const diff = mapDiff(oldFilteredRooms, this.spaceFilteredRooms); + // filter out keys which changed by reference only by checking whether the sets differ + const changed = diff.changed.filter(k => setHasDiff(oldFilteredRooms.get(k), this.spaceFilteredRooms.get(k))); + [...diff.added, ...diff.removed, ...changed].forEach(k => { + this.emit(k); + }); + + this.spaceFilteredRooms.forEach((roomIds, s) => { + // Update NotificationStates + const rooms = this.matrixClient.getRooms().filter(room => roomIds.has(room.roomId)); + this.getNotificationState(s)?.setRooms(rooms); + }); + }, 100, {trailing: true, leading: true}); + + private onRoom = (room: Room) => { + if (room?.isSpaceRoom()) { + this.onSpaceUpdate(); + this.emit(room.roomId); + } else { + // this.onRoomUpdate(room); + this.onRoomsUpdate(); + } + }; + + private onRoomState = (ev: MatrixEvent) => { + const room = this.matrixClient.getRoom(ev.getRoomId()); + if (!room) return; + + if (ev.getType() === EventType.SpaceChild && room.isSpaceRoom()) { + this.onSpaceUpdate(); + this.emit(room.roomId); + } else if (ev.getType() === EventType.SpaceParent) { + // TODO rebuild the space parent and not the room - check permissions? + // TODO confirm this after implementing parenting behaviour + if (room.isSpaceRoom()) { + this.onSpaceUpdate(); + } else { + this.onRoomUpdate(room); + } + this.emit(room.roomId); + } + }; + + private onRoomAccountData = (ev: MatrixEvent, room: Room, lastEvent: MatrixEvent) => { + if (ev.getType() === EventType.Tag && !room.isSpaceRoom()) { + // If the room was in favourites and now isn't or the opposite then update its position in the trees + if (!!ev.getContent()[DefaultTagID.Favourite] !== !!lastEvent.getContent()[DefaultTagID.Favourite]) { + this.onRoomUpdate(room); + } + } + } + + private onAccountData = (ev: MatrixEvent, lastEvent: MatrixEvent) => { + if (ev.getType() === EventType.Direct) { + const lastContent = lastEvent.getContent(); + const content = ev.getContent(); + + const diff = objectDiff>(lastContent, content); + // filter out keys which changed by reference only by checking whether the sets differ + const changed = diff.changed.filter(k => arrayHasDiff(lastContent[k], content[k])); + // DM tag changes, refresh relevant rooms + new Set([...diff.added, ...diff.removed, ...changed]).forEach(roomId => { + const room = this.matrixClient?.getRoom(roomId); + if (room) { + this.onRoomUpdate(room); + } + }); + } + }; + + protected async onNotReady() { + if (!SettingsStore.getValue("feature_spaces")) return; + if (this.matrixClient) { + this.matrixClient.removeListener("Room", this.onRoom); + this.matrixClient.removeListener("Room.myMembership", this.onRoom); + this.matrixClient.removeListener("RoomState.events", this.onRoomState); + this.matrixClient.removeListener("Room.accountData", this.onRoomAccountData); + this.matrixClient.removeListener("accountData", this.onAccountData); + } + await this.reset({}); + } + + protected async onReady() { + if (!SettingsStore.getValue("feature_spaces")) return; + this.matrixClient.on("Room", this.onRoom); + this.matrixClient.on("Room.myMembership", this.onRoom); + this.matrixClient.on("RoomState.events", this.onRoomState); + this.matrixClient.on("Room.accountData", this.onRoomAccountData); + this.matrixClient.on("accountData", this.onAccountData); + + await this.onSpaceUpdate(); // trigger an initial update + + // restore selected state from last session if any and still valid + const lastSpaceId = window.localStorage.getItem(ACTIVE_SPACE_LS_KEY); + if (lastSpaceId) { + const space = this.rootSpaces.find(s => s.roomId === lastSpaceId); + if (space) { + this.setActiveSpace(space); + } + } + } + + protected async onAction(payload: ActionPayload) { + switch (payload.action) { + case "view_room": { + const room = this.matrixClient?.getRoom(payload.room_id); + + if (room?.getMyMembership() === "join") { + if (room.isSpaceRoom()) { + this.setActiveSpace(room); + } else if (!this.spaceFilteredRooms.get(this._activeSpace?.roomId || HOME_SPACE).has(room.roomId)) { + // TODO maybe reverse these first 2 clauses once space panel active is fixed + let parent = this.rootSpaces.find(s => this.spaceFilteredRooms.get(s.roomId)?.has(room.roomId)); + if (!parent) { + parent = this.getCanonicalParent(room.roomId); + } + if (!parent) { + const parents = Array.from(this.parentMap.get(room.roomId) || []); + parent = parents.find(p => this.matrixClient.getRoom(p)); + } + if (parent) { + this.setActiveSpace(parent); + } + } + } + break; + } + case "after_leave_room": + if (this._activeSpace && payload.room_id === this._activeSpace.roomId) { + this.setActiveSpace(null); + } + break; + } + } + + public getNotificationState(key: SpaceKey): SpaceNotificationState { + if (this.notificationStateMap.has(key)) { + return this.notificationStateMap.get(key); + } + + const state = new SpaceNotificationState(key, getRoomFn); + this.notificationStateMap.set(key, state); + return state; + } +} + +export default class SpaceStore { + private static internalInstance = new SpaceStoreClass(); + + public static get instance(): SpaceStoreClass { + return SpaceStore.internalInstance; + } +} + +window.mxSpaceStore = SpaceStore.instance; diff --git a/src/stores/notifications/SpaceNotificationState.ts b/src/stores/notifications/SpaceNotificationState.ts new file mode 100644 index 0000000000..61a9701a07 --- /dev/null +++ b/src/stores/notifications/SpaceNotificationState.ts @@ -0,0 +1,82 @@ +/* +Copyright 2021 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 { Room } from "matrix-js-sdk/src/models/room"; + +import { NotificationColor } from "./NotificationColor"; +import { arrayDiff } from "../../utils/arrays"; +import { RoomNotificationState } from "./RoomNotificationState"; +import { NOTIFICATION_STATE_UPDATE, NotificationState } from "./NotificationState"; +import { FetchRoomFn } from "./ListNotificationState"; + +export class SpaceNotificationState extends NotificationState { + private rooms: Room[] = []; + private states: { [spaceId: string]: RoomNotificationState } = {}; + + constructor(private spaceId: string | symbol, private getRoomFn: FetchRoomFn) { + super(); + } + + public get symbol(): string { + return null; // This notification state doesn't support symbols + } + + public setRooms(rooms: Room[]) { + const oldRooms = this.rooms; + const diff = arrayDiff(oldRooms, rooms); + this.rooms = rooms; + for (const oldRoom of diff.removed) { + const state = this.states[oldRoom.roomId]; + if (!state) continue; // We likely just didn't have a badge (race condition) + delete this.states[oldRoom.roomId]; + state.off(NOTIFICATION_STATE_UPDATE, this.onRoomNotificationStateUpdate); + } + for (const newRoom of diff.added) { + const state = this.getRoomFn(newRoom); + state.on(NOTIFICATION_STATE_UPDATE, this.onRoomNotificationStateUpdate); + this.states[newRoom.roomId] = state; + } + + this.calculateTotalState(); + } + + public destroy() { + super.destroy(); + for (const state of Object.values(this.states)) { + state.off(NOTIFICATION_STATE_UPDATE, this.onRoomNotificationStateUpdate); + } + this.states = {}; + } + + private onRoomNotificationStateUpdate = () => { + this.calculateTotalState(); + }; + + private calculateTotalState() { + const snapshot = this.snapshot(); + + this._count = 0; + this._color = NotificationColor.None; + for (const state of Object.values(this.states)) { + this._count += state.count; + this._color = Math.max(this.color, state.color); + } + + // finally, publish an update if needed + this.emitIfUpdated(snapshot); + } +} + From ad85764a8e3d1025c76db29e9f53ba690ac2eb4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Thu, 25 Feb 2021 18:23:32 +0100 Subject: [PATCH 079/457] Fix timeline expansion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- res/css/structures/_MainSplit.scss | 1 + res/css/structures/_RoomView.scss | 1 + 2 files changed, 2 insertions(+) diff --git a/res/css/structures/_MainSplit.scss b/res/css/structures/_MainSplit.scss index f05f24d0d7..9597083e9c 100644 --- a/res/css/structures/_MainSplit.scss +++ b/res/css/structures/_MainSplit.scss @@ -19,6 +19,7 @@ limitations under the License. flex-direction: row; min-width: 0; height: 100%; + justify-content: space-between; } .mx_MainSplit > .mx_RightPanel_ResizeWrapper { diff --git a/res/css/structures/_RoomView.scss b/res/css/structures/_RoomView.scss index cd8c640132..5240a0650f 100644 --- a/res/css/structures/_RoomView.scss +++ b/res/css/structures/_RoomView.scss @@ -121,6 +121,7 @@ limitations under the License. position: relative; //for .mx_RoomView_auxPanel_fullHeight display: flex; flex-direction: column; + width: 100%; } .mx_RoomView_body { From aa4ec9fca1a65202306ee77d705b15f1782de188 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Thu, 25 Feb 2021 18:27:52 +0100 Subject: [PATCH 080/457] Make $droptarget-bg-color more opaque MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- res/themes/light/css/_light.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/themes/light/css/_light.scss b/res/themes/light/css/_light.scss index 1c89d83c01..ea7b0472e0 100644 --- a/res/themes/light/css/_light.scss +++ b/res/themes/light/css/_light.scss @@ -68,7 +68,7 @@ $groupFilterPanel-bg-color: rgba(232, 232, 232, 0.77); $plinth-bg-color: $secondary-accent-color; // used by RoomDropTarget -$droptarget-bg-color: rgba(255,255,255,0.5); +$droptarget-bg-color: rgba(255,255,255,0.95); // used by AddressSelector $selected-color: $secondary-accent-color; From 8551855a5626d06e6feda6f849f50b26af85a194 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Thu, 25 Feb 2021 18:30:14 +0100 Subject: [PATCH 081/457] Add $droptarget-bg-color to the dark theme MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- res/themes/dark/css/_dark.scss | 3 +++ 1 file changed, 3 insertions(+) diff --git a/res/themes/dark/css/_dark.scss b/res/themes/dark/css/_dark.scss index a878aa3cdd..f6f415ce70 100644 --- a/res/themes/dark/css/_dark.scss +++ b/res/themes/dark/css/_dark.scss @@ -42,6 +42,9 @@ $preview-bar-bg-color: $header-panel-bg-color; $groupFilterPanel-bg-color: rgba(38, 39, 43, 0.82); $inverted-bg-color: $base-color; +// used by RoomDropTarget +$droptarget-bg-color: rgba(21,25,30,0.95); + // used by AddressSelector $selected-color: $room-highlight-color; From a3001f77e46e7c3ac3479a70eb56db312c6f1361 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Thu, 25 Feb 2021 18:30:39 +0100 Subject: [PATCH 082/457] Remove rounded corners of the drop area MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- res/css/structures/_RoomView.scss | 3 --- 1 file changed, 3 deletions(-) diff --git a/res/css/structures/_RoomView.scss b/res/css/structures/_RoomView.scss index 5240a0650f..e80ac062b6 100644 --- a/res/css/structures/_RoomView.scss +++ b/res/css/structures/_RoomView.scss @@ -30,9 +30,6 @@ limitations under the License. pointer-events: none; - border-top-left-radius: 10px; - border-top-right-radius: 10px; - background-color: $droptarget-bg-color; position: absolute; From 26b70b62280b7f4fa21c6287faf20a309a399abe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Thu, 25 Feb 2021 18:32:04 +0100 Subject: [PATCH 083/457] Remove label background MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- res/css/structures/_RoomView.scss | 5 ----- 1 file changed, 5 deletions(-) diff --git a/res/css/structures/_RoomView.scss b/res/css/structures/_RoomView.scss index e80ac062b6..8ba31fac20 100644 --- a/res/css/structures/_RoomView.scss +++ b/res/css/structures/_RoomView.scss @@ -42,11 +42,6 @@ limitations under the License. .mx_RoomView_fileDropTargetLabel { position: absolute; - - border-radius: 10px; - padding: 10px; - - background-color: $menu-bg-color; } .mx_RoomView_auxPanel { From 6a7340e8be3844881b1c114d74687983b9c0ba20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Thu, 25 Feb 2021 18:46:48 +0100 Subject: [PATCH 084/457] Use new upload icon MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- res/img/upload-big.svg | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/res/img/upload-big.svg b/res/img/upload-big.svg index 6099c2e976..9a6a265fdb 100644 --- a/res/img/upload-big.svg +++ b/res/img/upload-big.svg @@ -1,19 +1,3 @@ - - - - icons_upload_drop - Created with bin/sketchtool. - - - - - - - - - - - - - + + From 1c48804d96c3cdda150e38e2d520a2268dd5728e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Thu, 25 Feb 2021 19:28:08 +0100 Subject: [PATCH 085/457] Remove unnecessary class MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- res/css/structures/_RoomView.scss | 4 ---- src/components/views/rooms/AuxPanel.tsx | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/res/css/structures/_RoomView.scss b/res/css/structures/_RoomView.scss index 8ba31fac20..28d8d1e196 100644 --- a/res/css/structures/_RoomView.scss +++ b/res/css/structures/_RoomView.scss @@ -40,10 +40,6 @@ limitations under the License. align-items: center; } -.mx_RoomView_fileDropTargetLabel { - position: absolute; -} - .mx_RoomView_auxPanel { min-width: 0px; width: 100%; diff --git a/src/components/views/rooms/AuxPanel.tsx b/src/components/views/rooms/AuxPanel.tsx index 7966643084..543a50d59f 100644 --- a/src/components/views/rooms/AuxPanel.tsx +++ b/src/components/views/rooms/AuxPanel.tsx @@ -156,7 +156,7 @@ export default class AuxPanel extends React.Component { if (this.props.draggingFile) { fileDropTarget = (
-
+

{ _t("Drop file here to upload") } From 43e1144ae7ca7eff08c1666b4a179ba828d41432 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Thu, 25 Feb 2021 19:36:55 +0100 Subject: [PATCH 086/457] Don't use TintableSVG MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This seemed to have caused a little lag and it was unnecessary Signed-off-by: Šimon Brandner --- src/components/views/rooms/AuxPanel.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/components/views/rooms/AuxPanel.tsx b/src/components/views/rooms/AuxPanel.tsx index 543a50d59f..c9150d588f 100644 --- a/src/components/views/rooms/AuxPanel.tsx +++ b/src/components/views/rooms/AuxPanel.tsx @@ -150,14 +150,12 @@ export default class AuxPanel extends React.Component { } render() { - const TintableSvg = sdk.getComponent("elements.TintableSvg"); - let fileDropTarget = null; if (this.props.draggingFile) { fileDropTarget = (
- +
{ _t("Drop file here to upload") }
From 7277c285a9326928555e05766ee3ce33603de18d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Thu, 25 Feb 2021 20:10:38 +0100 Subject: [PATCH 087/457] Fix weird crash MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- src/components/views/rooms/AuxPanel.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/rooms/AuxPanel.tsx b/src/components/views/rooms/AuxPanel.tsx index c9150d588f..cc3408476c 100644 --- a/src/components/views/rooms/AuxPanel.tsx +++ b/src/components/views/rooms/AuxPanel.tsx @@ -155,7 +155,7 @@ export default class AuxPanel extends React.Component { fileDropTarget = (
- +
{ _t("Drop file here to upload") }
From 49ea9a4788243346b20fcf5b4b79f46a7c3a80ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Thu, 25 Feb 2021 20:10:58 +0100 Subject: [PATCH 088/457] Remove sdk import MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- src/components/views/rooms/AuxPanel.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/views/rooms/AuxPanel.tsx b/src/components/views/rooms/AuxPanel.tsx index cc3408476c..59ea8e237a 100644 --- a/src/components/views/rooms/AuxPanel.tsx +++ b/src/components/views/rooms/AuxPanel.tsx @@ -17,7 +17,6 @@ limitations under the License. import React from 'react'; import {MatrixClientPeg} from "../../../MatrixClientPeg"; import { Room } from 'matrix-js-sdk/src/models/room' -import * as sdk from '../../../index'; import dis from "../../../dispatcher/dispatcher"; import * as ObjectUtils from '../../../ObjectUtils'; import AppsDrawer from './AppsDrawer'; From 563620484df6fa79f666ef72f414838cf0e342f1 Mon Sep 17 00:00:00 2001 From: Robin Townsend Date: Thu, 25 Feb 2021 14:39:20 -0500 Subject: [PATCH 089/457] Support replying with a message command Signed-off-by: Robin Townsend --- src/SlashCommands.tsx | 28 +++++++----- .../views/rooms/SendMessageComposer.js | 44 +++++++++++++------ 2 files changed, 47 insertions(+), 25 deletions(-) diff --git a/src/SlashCommands.tsx b/src/SlashCommands.tsx index 6b5f261374..06468c135e 100644 --- a/src/SlashCommands.tsx +++ b/src/SlashCommands.tsx @@ -20,6 +20,7 @@ limitations under the License. import * as React from 'react'; +import { ContentHelpers } from 'matrix-js-sdk'; import {MatrixClientPeg} from './MatrixClientPeg'; import dis from './dispatcher/dispatcher'; import * as sdk from './index'; @@ -126,10 +127,10 @@ export class Command { return this.getCommand() + " " + this.args; } - run(roomId: string, args: string, cmd: string) { + run(roomId: string, args: string) { // if it has no runFn then its an ignored/nop command (autocomplete only) e.g `/me` if (!this.runFn) return reject(_t("Command error")); - return this.runFn.bind(this)(roomId, args, cmd); + return this.runFn.bind(this)(roomId, args); } getUsage() { @@ -163,7 +164,7 @@ export const Commands = [ if (args) { message = message + ' ' + args; } - return success(MatrixClientPeg.get().sendTextMessage(roomId, message)); + return success(ContentHelpers.makeTextMessage(message)); }, category: CommandCategories.messages, }), @@ -176,7 +177,7 @@ export const Commands = [ if (args) { message = message + ' ' + args; } - return success(MatrixClientPeg.get().sendTextMessage(roomId, message)); + return success(ContentHelpers.makeTextMessage(message)); }, category: CommandCategories.messages, }), @@ -189,7 +190,7 @@ export const Commands = [ if (args) { message = message + ' ' + args; } - return success(MatrixClientPeg.get().sendTextMessage(roomId, message)); + return success(ContentHelpers.makeTextMessage(message)); }, category: CommandCategories.messages, }), @@ -202,7 +203,7 @@ export const Commands = [ if (args) { message = message + ' ' + args; } - return success(MatrixClientPeg.get().sendTextMessage(roomId, message)); + return success(ContentHelpers.makeTextMessage(message)); }, category: CommandCategories.messages, }), @@ -211,7 +212,7 @@ export const Commands = [ args: '', description: _td('Sends a message as plain text, without interpreting it as markdown'), runFn: function(roomId, messages) { - return success(MatrixClientPeg.get().sendTextMessage(roomId, messages)); + return success(ContentHelpers.makeTextMessage(messages)); }, category: CommandCategories.messages, }), @@ -220,7 +221,7 @@ export const Commands = [ args: '', description: _td('Sends a message as html, without interpreting it as markdown'), runFn: function(roomId, messages) { - return success(MatrixClientPeg.get().sendHtmlMessage(roomId, messages, messages)); + return success(ContentHelpers.makeHtmlMessage(messages, messages)); }, category: CommandCategories.messages, }), @@ -966,7 +967,7 @@ export const Commands = [ args: '', runFn: function(roomId, args) { if (!args) return reject(this.getUserId()); - return success(MatrixClientPeg.get().sendHtmlMessage(roomId, args, textToHtmlRainbow(args))); + return success(ContentHelpers.makeHtmlMessage(args, textToHtmlRainbow(args))); }, category: CommandCategories.messages, }), @@ -976,7 +977,7 @@ export const Commands = [ args: '', runFn: function(roomId, args) { if (!args) return reject(this.getUserId()); - return success(MatrixClientPeg.get().sendHtmlEmote(roomId, args, textToHtmlRainbow(args))); + return success(ContentHelpers.makeHtmlEmote(args, textToHtmlRainbow(args))); }, category: CommandCategories.messages, }), @@ -1201,10 +1202,13 @@ export function parseCommandString(input: string) { * processing the command, or 'promise' if a request was sent out. * Returns null if the input didn't match a command. */ -export function getCommand(roomId: string, input: string) { +export function getCommand(input: string) { const {cmd, args} = parseCommandString(input); if (CommandMap.has(cmd) && CommandMap.get(cmd).isEnabled()) { - return () => CommandMap.get(cmd).run(roomId, args, cmd); + return { + cmd: CommandMap.get(cmd), + args, + }; } } diff --git a/src/components/views/rooms/SendMessageComposer.js b/src/components/views/rooms/SendMessageComposer.js index 62c474e417..d1482c0df6 100644 --- a/src/components/views/rooms/SendMessageComposer.js +++ b/src/components/views/rooms/SendMessageComposer.js @@ -33,7 +33,7 @@ import ReplyThread from "../elements/ReplyThread"; import {parseEvent} from '../../../editor/deserialize'; import {findEditableEvent} from '../../../utils/EventUtils'; import SendHistoryManager from "../../../SendHistoryManager"; -import {getCommand} from '../../../SlashCommands'; +import {CommandCategories, getCommand} from '../../../SlashCommands'; import * as sdk from '../../../index'; import Modal from '../../../Modal'; import {_t, _td} from '../../../languageHandler'; @@ -287,15 +287,22 @@ export default class SendMessageComposer extends React.Component { } return text + part.text; }, ""); - return [getCommand(this.props.room.roomId, commandText), commandText]; + const {cmd, args} = getCommand(commandText); + return [cmd, args, commandText]; } - async _runSlashCommand(fn) { - const cmd = fn(); - let error = cmd.error; - if (cmd.promise) { + async _runSlashCommand(cmd, args) { + const result = cmd.run(this.props.room.roomId, args); + let messageContent; + let error = result.error; + if (result.promise) { try { - await cmd.promise; + if (cmd.category === CommandCategories.messages) { + // The command returns a modified message that we need to pass on + messageContent = await result.promise; + } else { + await result.promise; + } } catch (err) { error = err; } @@ -304,7 +311,7 @@ export default class SendMessageComposer extends React.Component { console.error("Command failure: %s", error); const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); // assume the error is a server error when the command is async - const isServerError = !!cmd.promise; + const isServerError = !!result.promise; const title = isServerError ? _td("Server error") : _td("Command error"); let errText; @@ -322,6 +329,7 @@ export default class SendMessageComposer extends React.Component { }); } else { console.log("Command success."); + if (messageContent) return messageContent; } } @@ -330,13 +338,22 @@ export default class SendMessageComposer extends React.Component { return; } + const replyToEvent = this.props.replyToEvent; let shouldSend = true; + let content; if (!containsEmote(this.model) && this._isSlashCommand()) { - const [cmd, commandText] = this._getSlashCommand(); + const [cmd, args, commandText] = this._getSlashCommand(); if (cmd) { - shouldSend = false; - this._runSlashCommand(cmd); + if (cmd.category === CommandCategories.messages) { + content = await this._runSlashCommand(cmd, args); + if (replyToEvent) { + addReplyToMessageContent(content, replyToEvent, this.props.permalinkCreator); + } + } else { + this._runSlashCommand(cmd, args); + shouldSend = false; + } } else { // ask the user if their unknown command should be sent as a message const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog"); @@ -371,11 +388,12 @@ export default class SendMessageComposer extends React.Component { this._sendQuickReaction(); } - const replyToEvent = this.props.replyToEvent; if (shouldSend) { const startTime = CountlyAnalytics.getTimestamp(); const {roomId} = this.props.room; - const content = createMessageContent(this.model, this.props.permalinkCreator, replyToEvent); + if (!content) { + content = createMessageContent(this.model, this.props.permalinkCreator, replyToEvent); + } // don't bother sending an empty message if (!content.body.trim()) return; From dba52fb5b1411fcc03e2df5db85f1f94601a0337 Mon Sep 17 00:00:00 2001 From: Robin Townsend Date: Thu, 25 Feb 2021 16:01:46 -0500 Subject: [PATCH 090/457] Autocomplete invited users Signed-off-by: Robin Townsend --- src/autocomplete/UserProvider.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/autocomplete/UserProvider.tsx b/src/autocomplete/UserProvider.tsx index 32eea55b0b..7fc01daef9 100644 --- a/src/autocomplete/UserProvider.tsx +++ b/src/autocomplete/UserProvider.tsx @@ -155,6 +155,7 @@ export default class UserProvider extends AutocompleteProvider { const currentUserId = MatrixClientPeg.get().credentials.userId; this.users = this.room.getJoinedMembers().filter(({userId}) => userId !== currentUserId); + this.users = this.users.concat(this.room.getMembersWithMembership("invite")); this.users = sortBy(this.users, (member) => 1E20 - lastSpoken[member.userId] || 1E20); From 1a7f9091b4fc41eac6d5cc1b71d1dbe61f5d7f0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Fri, 26 Feb 2021 07:51:03 +0100 Subject: [PATCH 091/457] Animate icon size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- res/css/structures/_RoomView.scss | 12 ++++++++++++ src/components/views/rooms/AuxPanel.tsx | 10 +++++----- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/res/css/structures/_RoomView.scss b/res/css/structures/_RoomView.scss index 28d8d1e196..d5caee5e8b 100644 --- a/res/css/structures/_RoomView.scss +++ b/res/css/structures/_RoomView.scss @@ -36,10 +36,22 @@ limitations under the License. z-index: 3000; display: flex; + flex-direction: column; justify-content: center; align-items: center; } +@keyframes mx_RoomView_fileDropTarget_image_animation { + from {width: 0px;} + to {width: 32px;} +} + +.mx_RoomView_fileDropTarget_image { + animation: mx_RoomView_fileDropTarget_image_animation; + animation-duration: 0.5s; + margin-bottom: 16px; +} + .mx_RoomView_auxPanel { min-width: 0px; width: 100%; diff --git a/src/components/views/rooms/AuxPanel.tsx b/src/components/views/rooms/AuxPanel.tsx index 59ea8e237a..b3ef8c3cc8 100644 --- a/src/components/views/rooms/AuxPanel.tsx +++ b/src/components/views/rooms/AuxPanel.tsx @@ -153,11 +153,11 @@ export default class AuxPanel extends React.Component { if (this.props.draggingFile) { fileDropTarget = (
-
- -
- { _t("Drop file here to upload") } -
+ + { _t("Drop file here to upload") }
); } From f0c26846c75559e5be013eb25ebe5f54b4f6e264 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Fri, 26 Feb 2021 08:11:58 +0100 Subject: [PATCH 092/457] Fix formatting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- res/css/structures/_RoomView.scss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/res/css/structures/_RoomView.scss b/res/css/structures/_RoomView.scss index d5caee5e8b..2c3fb2b32b 100644 --- a/res/css/structures/_RoomView.scss +++ b/res/css/structures/_RoomView.scss @@ -42,8 +42,8 @@ limitations under the License. } @keyframes mx_RoomView_fileDropTarget_image_animation { - from {width: 0px;} - to {width: 32px;} + from {width: 0px;} + to {width: 32px;} } .mx_RoomView_fileDropTarget_image { From 172cc01f7d3dcba08235a621cff118efe3e76d83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Fri, 26 Feb 2021 08:12:10 +0100 Subject: [PATCH 093/457] Add background animation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- res/css/structures/_RoomView.scss | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/res/css/structures/_RoomView.scss b/res/css/structures/_RoomView.scss index 2c3fb2b32b..5870e107c6 100644 --- a/res/css/structures/_RoomView.scss +++ b/res/css/structures/_RoomView.scss @@ -20,6 +20,12 @@ limitations under the License. flex-direction: column; } + +@keyframes mx_RoomView_fileDropTarget_animation { + from {opacity: 0;} + to {opacity: 0.95;} +} + .mx_RoomView_fileDropTarget { min-width: 0px; width: 100%; @@ -30,7 +36,8 @@ limitations under the License. pointer-events: none; - background-color: $droptarget-bg-color; + background-color: $primary-bg-color; + opacity: 0.95; position: absolute; z-index: 3000; @@ -39,6 +46,9 @@ limitations under the License. flex-direction: column; justify-content: center; align-items: center; + + animation: mx_RoomView_fileDropTarget_animation; + animation-duration: 0.5s; } @keyframes mx_RoomView_fileDropTarget_image_animation { From 3e0558f4d97bc618cc8e6d71f411370e894d642f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Fri, 26 Feb 2021 08:12:38 +0100 Subject: [PATCH 094/457] Remove droptarget colors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- res/themes/dark/css/_dark.scss | 3 --- res/themes/light/css/_light.scss | 3 --- 2 files changed, 6 deletions(-) diff --git a/res/themes/dark/css/_dark.scss b/res/themes/dark/css/_dark.scss index f6f415ce70..a878aa3cdd 100644 --- a/res/themes/dark/css/_dark.scss +++ b/res/themes/dark/css/_dark.scss @@ -42,9 +42,6 @@ $preview-bar-bg-color: $header-panel-bg-color; $groupFilterPanel-bg-color: rgba(38, 39, 43, 0.82); $inverted-bg-color: $base-color; -// used by RoomDropTarget -$droptarget-bg-color: rgba(21,25,30,0.95); - // used by AddressSelector $selected-color: $room-highlight-color; diff --git a/res/themes/light/css/_light.scss b/res/themes/light/css/_light.scss index ea7b0472e0..c92e491ca2 100644 --- a/res/themes/light/css/_light.scss +++ b/res/themes/light/css/_light.scss @@ -67,9 +67,6 @@ $groupFilterPanel-bg-color: rgba(232, 232, 232, 0.77); // used by RoomDirectory permissions $plinth-bg-color: $secondary-accent-color; -// used by RoomDropTarget -$droptarget-bg-color: rgba(255,255,255,0.95); - // used by AddressSelector $selected-color: $secondary-accent-color; From 49ea83edb93dfa0e6f572aeac002adaaa0370fc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Fri, 26 Feb 2021 08:14:27 +0100 Subject: [PATCH 095/457] i18n 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 | 1 - 1 file changed, 1 deletion(-) diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 5bbbdf60b5..9af8ccc172 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1381,7 +1381,6 @@ "Remove %(phone)s?": "Remove %(phone)s?", "A text message has been sent to +%(msisdn)s. Please enter the verification code it contains.": "A text message has been sent to +%(msisdn)s. Please enter the verification code it contains.", "Phone Number": "Phone Number", - "Drop File Here": "Drop File Here", "Drop file here to upload": "Drop file here to upload", "This user has not verified all of their sessions.": "This user has not verified all of their sessions.", "You have not verified this user.": "You have not verified this user.", From e90ae2ea7596bff850cf4014c1109f93234132b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Fri, 26 Feb 2021 08:18:05 +0100 Subject: [PATCH 096/457] Delint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- res/css/structures/_RoomView.scss | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/res/css/structures/_RoomView.scss b/res/css/structures/_RoomView.scss index 5870e107c6..5e8d84ff32 100644 --- a/res/css/structures/_RoomView.scss +++ b/res/css/structures/_RoomView.scss @@ -22,8 +22,12 @@ limitations under the License. @keyframes mx_RoomView_fileDropTarget_animation { - from {opacity: 0;} - to {opacity: 0.95;} + from { + opacity: 0; + } + to { + opacity: 0.95; + } } .mx_RoomView_fileDropTarget { @@ -52,8 +56,12 @@ limitations under the License. } @keyframes mx_RoomView_fileDropTarget_image_animation { - from {width: 0px;} - to {width: 32px;} + from { + width: 0px; + } + to { + width: 32px; + } } .mx_RoomView_fileDropTarget_image { From 819a0b013fda927bea3197e458741f4f4f85a271 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Fri, 26 Feb 2021 11:08:31 +0100 Subject: [PATCH 097/457] min-width MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We need to allow the container to be smaller Signed-off-by: Šimon Brandner --- res/css/structures/_RoomView.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/res/css/structures/_RoomView.scss b/res/css/structures/_RoomView.scss index 5e8d84ff32..28591ad7a4 100644 --- a/res/css/structures/_RoomView.scss +++ b/res/css/structures/_RoomView.scss @@ -140,6 +140,7 @@ limitations under the License. display: flex; flex-direction: column; width: 100%; + min-width: 0; } .mx_RoomView_body { From 0d6a9fce67d24f441a62e140a2a73f669b959cbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Fri, 26 Feb 2021 11:12:14 +0100 Subject: [PATCH 098/457] Remove weird styling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- src/components/structures/RoomView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/structures/RoomView.tsx b/src/components/structures/RoomView.tsx index ff09af454e..42eafe5bdc 100644 --- a/src/components/structures/RoomView.tsx +++ b/src/components/structures/RoomView.tsx @@ -2058,7 +2058,7 @@ export default class RoomView extends React.Component { appsShown={this.state.showApps} /> -
+
{auxPanel}
From 11c5aa02d290739fff31bfa8365fe76562032594 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Fri, 26 Feb 2021 11:19:45 +0100 Subject: [PATCH 099/457] Remove mx_RoomView_container MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- res/css/structures/_MainSplit.scss | 1 + res/css/structures/_RoomView.scss | 8 ------- src/components/structures/RoomView.tsx | 30 ++++++++++++-------------- 3 files changed, 15 insertions(+), 24 deletions(-) diff --git a/res/css/structures/_MainSplit.scss b/res/css/structures/_MainSplit.scss index 9597083e9c..5fa62e921d 100644 --- a/res/css/structures/_MainSplit.scss +++ b/res/css/structures/_MainSplit.scss @@ -20,6 +20,7 @@ limitations under the License. min-width: 0; height: 100%; justify-content: space-between; + min-height: 0; } .mx_MainSplit > .mx_RightPanel_ResizeWrapper { diff --git a/res/css/structures/_RoomView.scss b/res/css/structures/_RoomView.scss index 28591ad7a4..b3dab5f992 100644 --- a/res/css/structures/_RoomView.scss +++ b/res/css/structures/_RoomView.scss @@ -135,14 +135,6 @@ limitations under the License. height: 50px; } -.mx_RoomView_container { - position: relative; //for .mx_RoomView_auxPanel_fullHeight - display: flex; - flex-direction: column; - width: 100%; - min-width: 0; -} - .mx_RoomView_body { display: flex; flex-direction: column; diff --git a/src/components/structures/RoomView.tsx b/src/components/structures/RoomView.tsx index 42eafe5bdc..be2f81a176 100644 --- a/src/components/structures/RoomView.tsx +++ b/src/components/structures/RoomView.tsx @@ -2058,24 +2058,22 @@ export default class RoomView extends React.Component { appsShown={this.state.showApps} /> -
+
{auxPanel} -
-
- {topUnreadMessagesBar} - {jumpToBottom} - {messagePanel} - {searchResultsPanel} -
-
-
-
- {statusBar} -
-
- {previewBar} - {messageComposer} +
+ {topUnreadMessagesBar} + {jumpToBottom} + {messagePanel} + {searchResultsPanel}
+
+
+
+ {statusBar} +
+
+ {previewBar} + {messageComposer}
From 9a5ba072ba0f551dc618cdf8bfb7afba004d01fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Fri, 26 Feb 2021 11:23:58 +0100 Subject: [PATCH 100/457] Fix auxPanel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- src/components/structures/RoomView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/structures/RoomView.tsx b/src/components/structures/RoomView.tsx index be2f81a176..5b79f23e0b 100644 --- a/src/components/structures/RoomView.tsx +++ b/src/components/structures/RoomView.tsx @@ -2059,8 +2059,8 @@ export default class RoomView extends React.Component { />
- {auxPanel}
+ {auxPanel} {topUnreadMessagesBar} {jumpToBottom} {messagePanel} From 3bed37463fea1ff1a7c86ef5fe9a0a123e06008f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Fri, 26 Feb 2021 11:38:05 +0100 Subject: [PATCH 101/457] Remove unnecessary code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- res/css/structures/_MainSplit.scss | 1 - 1 file changed, 1 deletion(-) diff --git a/res/css/structures/_MainSplit.scss b/res/css/structures/_MainSplit.scss index 5fa62e921d..2d9ea2729c 100644 --- a/res/css/structures/_MainSplit.scss +++ b/res/css/structures/_MainSplit.scss @@ -19,7 +19,6 @@ limitations under the License. flex-direction: row; min-width: 0; height: 100%; - justify-content: space-between; min-height: 0; } From f21aedc6cf38d741de183fa1d158d7f7de673699 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 26 Feb 2021 10:23:09 +0000 Subject: [PATCH 102/457] Add Space Panel with Room List filtering --- res/css/_components.scss | 1 + res/css/structures/_LeftPanel.scss | 22 +- res/css/structures/_SpacePanel.scss | 237 ++++++++++++++++++ res/img/element-icons/expand-space-panel.svg | 4 + res/themes/light/css/_mods.scss | 4 + src/components/structures/LeftPanel.tsx | 23 +- src/components/views/avatars/RoomAvatar.tsx | 2 +- src/components/views/spaces/SpacePanel.tsx | 212 ++++++++++++++++ .../views/spaces/SpaceTreeLevel.tsx | 184 ++++++++++++++ src/i18n/strings/en_EN.json | 4 +- src/stores/room-list/RoomListStore.ts | 23 +- src/stores/room-list/SpaceWatcher.ts | 39 +++ src/stores/room-list/algorithms/Algorithm.ts | 3 + .../room-list/filters/SpaceFilterCondition.ts | 69 +++++ 14 files changed, 796 insertions(+), 31 deletions(-) create mode 100644 res/css/structures/_SpacePanel.scss create mode 100644 res/img/element-icons/expand-space-panel.svg create mode 100644 src/components/views/spaces/SpacePanel.tsx create mode 100644 src/components/views/spaces/SpaceTreeLevel.tsx create mode 100644 src/stores/room-list/SpaceWatcher.ts create mode 100644 src/stores/room-list/filters/SpaceFilterCondition.ts diff --git a/res/css/_components.scss b/res/css/_components.scss index 006bac09c9..29b5262826 100644 --- a/res/css/_components.scss +++ b/res/css/_components.scss @@ -27,6 +27,7 @@ @import "./structures/_RoomView.scss"; @import "./structures/_ScrollPanel.scss"; @import "./structures/_SearchBox.scss"; +@import "./structures/_SpacePanel.scss"; @import "./structures/_TabbedView.scss"; @import "./structures/_ToastContainer.scss"; @import "./structures/_UploadBar.scss"; diff --git a/res/css/structures/_LeftPanel.scss b/res/css/structures/_LeftPanel.scss index 168590502d..f1f27014ee 100644 --- a/res/css/structures/_LeftPanel.scss +++ b/res/css/structures/_LeftPanel.scss @@ -15,6 +15,7 @@ limitations under the License. */ $groupFilterPanelWidth: 56px; // only applies in this file, used for calculations +$roomListCollapsedWidth: 68px; .mx_LeftPanel { background-color: $roomlist-bg-color; @@ -37,18 +38,12 @@ $groupFilterPanelWidth: 56px; // only applies in this file, used for calculation // GroupFilterPanel handles its own CSS } - &:not(.mx_LeftPanel_hasGroupFilterPanel) { - .mx_LeftPanel_roomListContainer { - width: 100%; - } - } - // Note: The 'room list' in this context is actually everything that isn't the tag // panel, such as the menu options, breadcrumbs, filtering, etc .mx_LeftPanel_roomListContainer { - width: calc(100% - $groupFilterPanelWidth); background-color: $roomlist-bg-color; - + flex: 1 0 0; + min-width: 0; // Create another flexbox (this time a column) for the room list components display: flex; flex-direction: column; @@ -168,17 +163,10 @@ $groupFilterPanelWidth: 56px; // only applies in this file, used for calculation // These styles override the defaults for the minimized (66px) layout &.mx_LeftPanel_minimized { min-width: unset; - - // We have to forcefully set the width to override the resizer's style attribute. - &.mx_LeftPanel_hasGroupFilterPanel { - width: calc(68px + $groupFilterPanelWidth) !important; - } - &:not(.mx_LeftPanel_hasGroupFilterPanel) { - width: 68px !important; - } + width: unset !important; .mx_LeftPanel_roomListContainer { - width: 68px; + width: $roomListCollapsedWidth; .mx_LeftPanel_userHeader { flex-direction: row; diff --git a/res/css/structures/_SpacePanel.scss b/res/css/structures/_SpacePanel.scss new file mode 100644 index 0000000000..8de85f95ef --- /dev/null +++ b/res/css/structures/_SpacePanel.scss @@ -0,0 +1,237 @@ +/* +Copyright 2021 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. +*/ + +$topLevelHeight: 32px; +$nestedHeight: 24px; +$gutterSize: 21px; +$activeStripeSize: 4px; + +.mx_SpacePanel { + flex: 0 0 auto; + background-color: $groupFilterPanel-bg-color; + padding: 0; + margin: 0; + + // Create another flexbox so the Panel fills the container + display: flex; + flex-direction: column; + overflow-y: auto; + + .mx_SpacePanel_spaceTreeWrapper { + flex: 1; + } + + .mx_SpacePanel_toggleCollapse { + flex: 0 0 auto; + width: 40px; + height: 40px; + mask-position: center; + mask-size: 32px; + mask-repeat: no-repeat; + margin-left: $gutterSize; + margin-bottom: 12px; + background-color: $roomlist-header-color; + mask-image: url('$(res)/img/element-icons/expand-space-panel.svg'); + + &.expanded { + transform: scaleX(-1); + } + } + + ul { + margin: 0; + list-style: none; + padding: 0; + padding-left: 16px; + } + + .mx_AutoHideScrollbar { + padding: 16px 12px 16px 0; + } + + .mx_SpaceButton_toggleCollapse { + cursor: pointer; + } + + .mx_SpaceItem { + position: relative; + } + + .mx_SpaceItem.collapsed { + & > .mx_SpaceButton > .mx_SpaceButton_toggleCollapse { + transform: rotate(-90deg); + } + + & > .mx_SpaceTreeLevel { + display: none; + } + } + + .mx_SpaceItem:not(.hasSubSpaces) > .mx_SpaceButton { + margin-left: $gutterSize; + + &.mx_SpaceButton_active { + &::before { + left: -$gutterSize; + } + } + } + + .mx_SpaceButton { + border-radius: 8px; + position: relative; + margin-bottom: 16px; + display: flex; + align-items: center; + + .mx_SpaceButton_name { + flex: 1; + margin-left: 8px; + white-space: nowrap; + display: block; + max-width: 150px; + text-overflow: ellipsis; + overflow: hidden; + + font-size: $font-14px; + line-height: $font-18px; + } + + .mx_SpaceButton_toggleCollapse { + width: calc($gutterSize - $activeStripeSize); + margin-left: 1px; + height: 20px; + mask-position: center; + mask-size: 20px; + mask-repeat: no-repeat; + background-color: $roomlist-header-color; + mask-image: url('$(res)/img/feather-customised/chevron-down.svg'); + } + + &.mx_SpaceButton_active { + &::before { + position: absolute; + content: ''; + width: $activeStripeSize; + top: 0; + left: 0; + bottom: 0; + background-color: $accent-color; + border-radius: 0 4px 4px 0; + } + } + + .mx_SpaceButton_avatarPlaceholder { + width: $topLevelHeight; + min-width: $topLevelHeight; + height: $topLevelHeight; + border-radius: 8px; + + &::before { + position: absolute; + content: ''; + width: $topLevelHeight; + height: $topLevelHeight; + top: 0; + left: 0; + mask-position: center; + mask-repeat: no-repeat; + mask-size: 18px; + } + } + + &.mx_SpaceButton_home .mx_SpaceButton_avatarPlaceholder { + background-color: #ffffff; + + &::before { + background-color: #3f3d3d; + mask-image: url('$(res)/img/element-icons/home.svg'); + } + } + + &.mx_SpaceButton_newCancel .mx_SpaceButton_avatarPlaceholder { + background-color: $icon-button-color; + + &::before { + transform: rotate(45deg); + } + } + + .mx_BaseAvatar_image { + border-radius: 8px; + } + } + + .mx_SpacePanel_badgeContainer { + height: 16px; + // don't set width so that it takes no space when there is no badge to show + margin: auto 0; // vertically align + + // Create a flexbox to make aligning dot badges easier + display: flex; + align-items: center; + + .mx_NotificationBadge { + margin: 0 2px; // centering + } + + .mx_NotificationBadge_dot { + // make the smaller dot occupy the same width for centering + margin-left: 7px; + margin-right: 7px; + } + } + + &.collapsed { + .mx_SpaceButton { + .mx_SpacePanel_badgeContainer { + position: absolute; + right: -8px; + top: -4px; + } + } + } + + &:not(.collapsed) { + .mx_SpaceButton:hover, + .mx_SpaceButton:focus-within, + .mx_SpaceButton_hasMenuOpen { + // Hide the badge container on hover because it'll be a menu button + .mx_SpacePanel_badgeContainer { + width: 0; + height: 0; + display: none; + } + } + } + + /* root space buttons are bigger and not indented */ + & > .mx_AutoHideScrollbar { + & > .mx_SpaceButton { + height: $topLevelHeight; + + &.mx_SpaceButton_active::before { + height: $topLevelHeight; + } + } + + & > ul { + padding-left: 0; + } + } +} diff --git a/res/img/element-icons/expand-space-panel.svg b/res/img/element-icons/expand-space-panel.svg new file mode 100644 index 0000000000..11232acd58 --- /dev/null +++ b/res/img/element-icons/expand-space-panel.svg @@ -0,0 +1,4 @@ + + + + diff --git a/res/themes/light/css/_mods.scss b/res/themes/light/css/_mods.scss index 30aaeedf8f..fbca58dfb1 100644 --- a/res/themes/light/css/_mods.scss +++ b/res/themes/light/css/_mods.scss @@ -16,6 +16,10 @@ backdrop-filter: blur($groupFilterPanel-background-blur-amount); } + .mx_SpacePanel { + backdrop-filter: blur($groupFilterPanel-background-blur-amount); + } + .mx_LeftPanel .mx_LeftPanel_roomListContainer { backdrop-filter: blur($roomlist-background-blur-amount); } diff --git a/src/components/structures/LeftPanel.tsx b/src/components/structures/LeftPanel.tsx index 4445ff3ff8..82dd9443cc 100644 --- a/src/components/structures/LeftPanel.tsx +++ b/src/components/structures/LeftPanel.tsx @@ -39,6 +39,7 @@ import { OwnProfileStore } from "../../stores/OwnProfileStore"; import { MatrixClientPeg } from "../../MatrixClientPeg"; import RoomListNumResults from "../views/rooms/RoomListNumResults"; import LeftPanelWidget from "./LeftPanelWidget"; +import SpacePanel from "../views/spaces/SpacePanel"; interface IProps { isMinimized: boolean; @@ -388,12 +389,19 @@ export default class LeftPanel extends React.Component { } public render(): React.ReactNode { - const groupFilterPanel = !this.state.showGroupFilterPanel ? null : ( -
- - {SettingsStore.getValue("feature_custom_tags") ? : null} -
- ); + let leftLeftPanel; + // Currently TagPanel.enableTagPanel is disabled when Legacy Communities are disabled so for now + // ignore it and force the rendering of SpacePanel if that Labs flag is enabled. + if (SettingsStore.getValue("feature_spaces")) { + leftLeftPanel = ; + } else if (this.state.showGroupFilterPanel) { + leftLeftPanel = ( +
+ + {SettingsStore.getValue("feature_custom_tags") ? : null} +
+ ); + } const roomList = { const containerClasses = classNames({ "mx_LeftPanel": true, - "mx_LeftPanel_hasGroupFilterPanel": !!groupFilterPanel, "mx_LeftPanel_minimized": this.props.isMinimized, }); @@ -417,7 +424,7 @@ export default class LeftPanel extends React.Component { return (
- {groupFilterPanel} + {leftLeftPanel}