diff --git a/CHANGELOG.md b/CHANGELOG.md index 2cc850822e..b2e1f1af0d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,159 @@ +Changes in [2.9.0](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v2.9.0) (2020-07-03) +=================================================================================================== +[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v2.9.0-rc.1...v2.9.0) + + * Upgrade to JS SDK 7.1.0 + * Remove duplicate compact settings, handle device level updates + [\#4889](https://github.com/matrix-org/matrix-react-sdk/pull/4889) + +Changes in [2.9.0-rc.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v2.9.0-rc.1) (2020-07-01) +============================================================================================================= +[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v2.8.1...v2.9.0-rc.1) + + * Upgrade to JS SDK 7.1.0-rc.1 + * Update from Weblate + [\#4869](https://github.com/matrix-org/matrix-react-sdk/pull/4869) + * Fix a number of proliferation issues in the new room list + [\#4828](https://github.com/matrix-org/matrix-react-sdk/pull/4828) + * Fix jumping to read marker for events without tiles + [\#4860](https://github.com/matrix-org/matrix-react-sdk/pull/4860) + * De-duplicate rooms from the room autocomplete provider + [\#4859](https://github.com/matrix-org/matrix-react-sdk/pull/4859) + * Add file upload button to recovery key input + [\#4847](https://github.com/matrix-org/matrix-react-sdk/pull/4847) + * Implement new design on security setup & login + [\#4831](https://github.com/matrix-org/matrix-react-sdk/pull/4831) + * Fix /join slash command via servers including room id as a via + [\#4856](https://github.com/matrix-org/matrix-react-sdk/pull/4856) + * Add Generic Expiring Toast and timing hooks + [\#4855](https://github.com/matrix-org/matrix-react-sdk/pull/4855) + * Fix Room Custom Sounds regression and make ProgressBar relevant again + [\#4846](https://github.com/matrix-org/matrix-react-sdk/pull/4846) + * Including start_sso and start_cas in redirect loop prevention + [\#4854](https://github.com/matrix-org/matrix-react-sdk/pull/4854) + * Clean up TODO comments for new room list + [\#4850](https://github.com/matrix-org/matrix-react-sdk/pull/4850) + * Show timestamp of redaction on hover + [\#4622](https://github.com/matrix-org/matrix-react-sdk/pull/4622) + * Remove the DM button from new room tiles + [\#4849](https://github.com/matrix-org/matrix-react-sdk/pull/4849) + * Hide room list show less button if it would do nothing + [\#4848](https://github.com/matrix-org/matrix-react-sdk/pull/4848) + * Improve message preview copy in new room list + [\#4823](https://github.com/matrix-org/matrix-react-sdk/pull/4823) + * Allow the tag panel to be disabled in the new room list + [\#4844](https://github.com/matrix-org/matrix-react-sdk/pull/4844) + * Make the whole user row clickable in the new room list + [\#4843](https://github.com/matrix-org/matrix-react-sdk/pull/4843) + * Add a new spinner design behind a labs flag + [\#4842](https://github.com/matrix-org/matrix-react-sdk/pull/4842) + * ts-ignore because something is made of fail + [\#4845](https://github.com/matrix-org/matrix-react-sdk/pull/4845) + * Fix Welcome.html CAS and SSO URLs not working + [\#4838](https://github.com/matrix-org/matrix-react-sdk/pull/4838) + * More small tweaks in preparation for Notifications rework + [\#4835](https://github.com/matrix-org/matrix-react-sdk/pull/4835) + * Iterate on the new room list resize handle + [\#4840](https://github.com/matrix-org/matrix-react-sdk/pull/4840) + * Update sublists for new hover states + [\#4837](https://github.com/matrix-org/matrix-react-sdk/pull/4837) + * Tweak parts of the new room list design + [\#4839](https://github.com/matrix-org/matrix-react-sdk/pull/4839) + * Implement new resize handle for dogfooding + [\#4836](https://github.com/matrix-org/matrix-react-sdk/pull/4836) + * Hide app badge count for hidden upgraded rooms (non-highlight) + [\#4834](https://github.com/matrix-org/matrix-react-sdk/pull/4834) + * Move compact modern layout checkbox to 'advanced' + [\#4822](https://github.com/matrix-org/matrix-react-sdk/pull/4822) + * Allow the user to resize the new sublists to 1 tile + [\#4825](https://github.com/matrix-org/matrix-react-sdk/pull/4825) + * Make LoggedInView a real component because it uses shouldComponentUpdate + [\#4832](https://github.com/matrix-org/matrix-react-sdk/pull/4832) + * Small tweaks in preparation for Notifications rework + [\#4829](https://github.com/matrix-org/matrix-react-sdk/pull/4829) + * Remove extraneous debug from the new left panel + [\#4826](https://github.com/matrix-org/matrix-react-sdk/pull/4826) + * Fix icons in the new user menu not showing up + [\#4824](https://github.com/matrix-org/matrix-react-sdk/pull/4824) + * Fix sticky room disappearing/jumping in search results + [\#4817](https://github.com/matrix-org/matrix-react-sdk/pull/4817) + * Show cross-signing / secret storage reset button in more cases + [\#4821](https://github.com/matrix-org/matrix-react-sdk/pull/4821) + * Use theme-capable icons in the user menu + [\#4819](https://github.com/matrix-org/matrix-react-sdk/pull/4819) + * Font support in custom themes + [\#4814](https://github.com/matrix-org/matrix-react-sdk/pull/4814) + * Decrease margin between new sublists + [\#4816](https://github.com/matrix-org/matrix-react-sdk/pull/4816) + * Update profile information in User Menu and truncate where needed + [\#4818](https://github.com/matrix-org/matrix-react-sdk/pull/4818) + * Fix MessageActionBar in irc layout + [\#4802](https://github.com/matrix-org/matrix-react-sdk/pull/4802) + * Mark messages with a black shield if the megolm session isn't trusted + [\#4797](https://github.com/matrix-org/matrix-react-sdk/pull/4797) + * Custom font selection + [\#4761](https://github.com/matrix-org/matrix-react-sdk/pull/4761) + * Use the correct timeline reference for message previews + [\#4812](https://github.com/matrix-org/matrix-react-sdk/pull/4812) + * Fix read receipt handling in the new room list + [\#4811](https://github.com/matrix-org/matrix-react-sdk/pull/4811) + * Improve unread/badge states in new room list (mk II) + [\#4805](https://github.com/matrix-org/matrix-react-sdk/pull/4805) + * Only fire setting changes for changed settings + [\#4803](https://github.com/matrix-org/matrix-react-sdk/pull/4803) + * Trigger room-specific watchers whenever a higher level change happens + [\#4804](https://github.com/matrix-org/matrix-react-sdk/pull/4804) + * Have the theme switcher set the device-level theme to match settings + [\#4810](https://github.com/matrix-org/matrix-react-sdk/pull/4810) + * Fix layout of minimized view for new room list + [\#4808](https://github.com/matrix-org/matrix-react-sdk/pull/4808) + * Fix sticky headers over/under extending themselves in the new room list + [\#4809](https://github.com/matrix-org/matrix-react-sdk/pull/4809) + * Update read receipt remainder for internal font size change + [\#4806](https://github.com/matrix-org/matrix-react-sdk/pull/4806) + * Fix some appearance tab crash and implement style nits + [\#4801](https://github.com/matrix-org/matrix-react-sdk/pull/4801) + * Add message preview for font slider + [\#4770](https://github.com/matrix-org/matrix-react-sdk/pull/4770) + * Add layout options to the appearance tab + [\#4773](https://github.com/matrix-org/matrix-react-sdk/pull/4773) + * Update from Weblate + [\#4800](https://github.com/matrix-org/matrix-react-sdk/pull/4800) + * Support accounts with cross signing but no SSSS + [\#4717](https://github.com/matrix-org/matrix-react-sdk/pull/4717) + * Look for existing verification requests after login + [\#4762](https://github.com/matrix-org/matrix-react-sdk/pull/4762) + * Add a checkpoint to index newly encrypted rooms. + [\#4611](https://github.com/matrix-org/matrix-react-sdk/pull/4611) + * Add support to paginate search results when using Seshat. + [\#4705](https://github.com/matrix-org/matrix-react-sdk/pull/4705) + * User versions in the event index. + [\#4788](https://github.com/matrix-org/matrix-react-sdk/pull/4788) + * Fix crash when filtering new room list too fast + [\#4796](https://github.com/matrix-org/matrix-react-sdk/pull/4796) + * hide search results from unknown rooms + [\#4795](https://github.com/matrix-org/matrix-react-sdk/pull/4795) + * Mark the new room list as ready for general testing + [\#4794](https://github.com/matrix-org/matrix-react-sdk/pull/4794) + * Extend QueryMatcher's sorting heuristic + [\#4784](https://github.com/matrix-org/matrix-react-sdk/pull/4784) + * Lint ts semicolons (aka. The great semicolon migration) + [\#4791](https://github.com/matrix-org/matrix-react-sdk/pull/4791) + * Revert "Use recovery keys over passphrases" + [\#4790](https://github.com/matrix-org/matrix-react-sdk/pull/4790) + * Clear `top` when not sticking headers to the top + [\#4783](https://github.com/matrix-org/matrix-react-sdk/pull/4783) + * Don't show a 'show less' button when it's impossible to collapse + [\#4785](https://github.com/matrix-org/matrix-react-sdk/pull/4785) + * Fix show less/more button occluding the list automatically + [\#4786](https://github.com/matrix-org/matrix-react-sdk/pull/4786) + * Improve room switching in the new room list + [\#4787](https://github.com/matrix-org/matrix-react-sdk/pull/4787) + * Remove labs option to cache 'passphrase' + [\#4789](https://github.com/matrix-org/matrix-react-sdk/pull/4789) + * Remove escape backslashes in non-Markdown messages + [\#4694](https://github.com/matrix-org/matrix-react-sdk/pull/4694) + Changes in [2.8.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v2.8.1) (2020-06-29) =================================================================================================== [Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v2.8.0...v2.8.1) diff --git a/package.json b/package.json index e8719520c4..41ba3f47c1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "matrix-react-sdk", - "version": "2.8.1", + "version": "2.9.0", "description": "SDK for matrix.org using React", "author": "matrix.org", "repository": { diff --git a/res/css/_common.scss b/res/css/_common.scss index c087df04cb..6e70618142 100644 --- a/res/css/_common.scss +++ b/res/css/_common.scss @@ -319,7 +319,7 @@ input[type=text]:focus, input[type=password]:focus, textarea:focus { } .mx_Dialog_titleImage { - vertical-align: middle; + vertical-align: sub; width: 25px; height: 25px; margin-left: -2px; @@ -588,27 +588,16 @@ input[type=text]:focus, input[type=password]:focus, textarea:focus { // A context menu that largely fits the | [icon] [label] | format. .mx_IconizedContextMenu { - // Put 20px of padding around the whole menu. We do this instead of a - // simple `padding: 20px` rule so the horizontal rules added by the - // optionLists is rendered correctly (full width). - > * { - padding-left: 20px; - padding-right: 20px; - - &:first-child { - padding-top: 20px; - } - - &:last-child { - padding-bottom: 16px; - } - } + min-width: 146px; .mx_IconizedContextMenu_optionList { + & > * { + padding-left: 20px; + padding-right: 20px; + } + // the notFirst class is for cases where the optionList might be under a header of sorts. &:nth-child(n + 2), .mx_IconizedContextMenu_optionList_notFirst { - margin-top: 12px; - // This is a bit of a hack when we could just use a simple border-top property, // however we have a (kinda) good reason for doing it this way: we need opacity. // To get the right color, we need an opacity modifier which means we have to work @@ -631,72 +620,76 @@ input[type=text]:focus, input[type=password]:focus, textarea:focus { } } - ul { - list-style: none; - margin: 0; - padding: 0; + // round the top corners of the top button for the hover effect to be bounded + &:first-child .mx_AccessibleButton:first-child { + border-radius: 4px 4px 0 0; // radius matches .mx_ContextualMenu + } - li { - margin: 0; - padding: 12px 0 0; + // round the bottom corners of the bottom button for the hover effect to be bounded + &:last-child .mx_AccessibleButton:last-child { + border-radius: 0 0 4px 4px; // radius matches .mx_ContextualMenu + } - .mx_AccessibleButton { - text-decoration: none; - color: $primary-fg-color; - font-size: $font-15px; - line-height: $font-24px; + .mx_AccessibleButton { + // pad the inside of the button so that the hover background is padded too + padding-top: 12px; + padding-bottom: 12px; + text-decoration: none; + color: $primary-fg-color; + font-size: $font-15px; + line-height: $font-24px; - // Create a flexbox to more easily define the list items - display: flex; - align-items: center; + // Create a flexbox to more easily define the list items + display: flex; + align-items: center; - img, .mx_IconizedContextMenu_icon { // icons - width: 16px; - min-width: 16px; - max-width: 16px; - } + &:hover { + background-color: $menu-selected-color; + } - span:last-child { // labels - padding-left: 14px; - width: 100%; - flex: 1; + img, .mx_IconizedContextMenu_icon { // icons + width: 16px; + min-width: 16px; + max-width: 16px; + } - // Ellipsize any text overflow - text-overflow: ellipsis; - overflow: hidden; - white-space: nowrap; - } - } + span.mx_IconizedContextMenu_label { // labels + padding-left: 14px; + width: 100%; + flex: 1; + + // Ellipsize any text overflow + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; } } } &.mx_IconizedContextMenu_compact { - > * { - padding-left: 11px; - padding-right: 16px; - - &:first-child { - padding-top: 13px; - } - - &:last-child { - padding-bottom: 13px; - } - } - - .mx_IconizedContextMenu_optionList { - &:nth-child(n + 2), .mx_IconizedContextMenu_optionList_notFirst { - margin-top: 10px; - - li:first-child { - padding-top: 10px; - } - } - - li:first-child { - padding-top: 0; - } + .mx_IconizedContextMenu_optionList > * { + padding: 8px 16px 8px 11px; } } } + +@define-mixin ProgressBarColour $colour { + color: $colour; + &::-moz-progress-bar { + background-color: $colour; + } + &::-webkit-progress-value { + background-color: $colour; + } +} + +@define-mixin ProgressBarBorderRadius $radius { + border-radius: $radius; + &::-moz-progress-bar { + border-radius: $radius; + } + &::-webkit-progress-bar, + &::-webkit-progress-value { + border-radius: $radius; + } +} diff --git a/res/css/_components.scss b/res/css/_components.scss index afc40ca0d6..8288cf34f6 100644 --- a/res/css/_components.scss +++ b/res/css/_components.scss @@ -49,6 +49,7 @@ @import "./views/auth/_ServerTypeSelector.scss"; @import "./views/auth/_Welcome.scss"; @import "./views/avatars/_BaseAvatar.scss"; +@import "./views/avatars/_DecoratedRoomAvatar.scss"; @import "./views/avatars/_MemberStatusMessageAvatar.scss"; @import "./views/context_menus/_MessageContextMenu.scss"; @import "./views/context_menus/_RoomTileContextMenu.scss"; diff --git a/res/css/structures/_LeftPanel2.scss b/res/css/structures/_LeftPanel2.scss index ef71718142..a03aaa0087 100644 --- a/res/css/structures/_LeftPanel2.scss +++ b/res/css/structures/_LeftPanel2.scss @@ -71,7 +71,8 @@ $tagPanelWidth: 70px; // only applies in this file, used for calculations .mx_LeftPanel2_breadcrumbsContainer { width: 100%; - overflow: hidden; + overflow-y: hidden; + overflow-x: scroll; margin-top: 8px; } } diff --git a/res/css/structures/_UserMenu.scss b/res/css/structures/_UserMenu.scss index bbb1e1cc7b..c958b9eacd 100644 --- a/res/css/structures/_UserMenu.scss +++ b/res/css/structures/_UserMenu.scss @@ -86,6 +86,8 @@ limitations under the License. .mx_UserMenu_contextMenu_redRow { .mx_AccessibleButton { + padding-top: 16px; + padding-bottom: 16px; color: $warning-color !important; // !important to override styles from context menu } @@ -95,6 +97,8 @@ limitations under the License. } .mx_UserMenu_contextMenu_header { + padding: 20px; + // Create a flexbox to organize the header a bit easier display: flex; align-items: center; diff --git a/res/css/views/auth/_PassphraseField.scss b/res/css/views/auth/_PassphraseField.scss index d1b8c47d00..bf8e7f4438 100644 --- a/res/css/views/auth/_PassphraseField.scss +++ b/res/css/views/auth/_PassphraseField.scss @@ -18,16 +18,6 @@ $PassphraseStrengthHigh: $accent-color; $PassphraseStrengthMedium: $username-variant5-color; $PassphraseStrengthLow: $notice-primary-color; -@define-mixin ProgressBarColour $colour { - color: $colour; - &::-moz-progress-bar { - background-color: $colour; - } - &::-webkit-progress-value { - background-color: $colour; - } -} - progress.mx_PassphraseField_progress { appearance: none; width: 100%; @@ -36,15 +26,7 @@ progress.mx_PassphraseField_progress { position: absolute; top: -12px; - border-radius: 2px; - &::-moz-progress-bar { - border-radius: 2px; - } - &::-webkit-progress-bar, - &::-webkit-progress-value { - border-radius: 2px; - } - + @mixin ProgressBarBorderRadius "2px"; @mixin ProgressBarColour $PassphraseStrengthLow; &[value="2"], &[value="3"] { @mixin ProgressBarColour $PassphraseStrengthMedium; diff --git a/res/css/views/avatars/_DecoratedRoomAvatar.scss b/res/css/views/avatars/_DecoratedRoomAvatar.scss new file mode 100644 index 0000000000..b500d44a43 --- /dev/null +++ b/res/css/views/avatars/_DecoratedRoomAvatar.scss @@ -0,0 +1,34 @@ +/* +Copyright 2020 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// XXX: We shouldn't be using TemporaryTile anywhere - delete it. +.mx_DecoratedRoomAvatar, .mx_TemporaryTile { + position: relative; + + .mx_RoomTileIcon { + position: absolute; + bottom: 0; + right: 0; + } + + .mx_NotificationBadge { + position: absolute; + top: 0; + right: 0; + height: 18px; + width: 18px; + } +} diff --git a/res/css/views/dialogs/secretstorage/_AccessSecretStorageDialog.scss b/res/css/views/dialogs/secretstorage/_AccessSecretStorageDialog.scss index db11e91bdb..63d0ca555d 100644 --- a/res/css/views/dialogs/secretstorage/_AccessSecretStorageDialog.scss +++ b/res/css/views/dialogs/secretstorage/_AccessSecretStorageDialog.scss @@ -15,20 +15,79 @@ See the License for the specific language governing permissions and limitations under the License. */ +.mx_AccessSecretStorageDialog_titleWithIcon::before { + content: ''; + display: inline-block; + width: 24px; + height: 24px; + margin-right: 8px; + position: relative; + top: 5px; + background-color: $primary-fg-color; +} + +.mx_AccessSecretStorageDialog_secureBackupTitle::before { + mask-image: url('$(res)/img/feather-customised/secure-backup.svg'); +} + +.mx_AccessSecretStorageDialog_securePhraseTitle::before { + mask-image: url('$(res)/img/feather-customised/secure-phrase.svg'); +} + .mx_AccessSecretStorageDialog_keyStatus { height: 30px; } -.mx_AccessSecretStorageDialog_primaryContainer { - /* FIXME: plinth colour in new theme(s). background-color: $accent-color; */ - padding: 20px; -} - -.mx_AccessSecretStorageDialog_passPhraseInput, -.mx_AccessSecretStorageDialog_recoveryKeyInput { +.mx_AccessSecretStorageDialog_passPhraseInput { width: 300px; border: 1px solid $accent-color; border-radius: 5px; padding: 10px; } +.mx_AccessSecretStorageDialog_recoveryKeyEntry { + display: flex; + align-items: center; +} + +.mx_AccessSecretStorageDialog_recoveryKeyEntry_textInput { + flex-grow: 1; +} + +.mx_AccessSecretStorageDialog_recoveryKeyEntry_entryControlSeparatorText { + margin: 16px; +} + +.mx_AccessSecretStorageDialog_recoveryKeyFeedback { + &::before { + content: ""; + display: inline-block; + vertical-align: bottom; + width: 20px; + height: 20px; + mask-repeat: no-repeat; + mask-position: center; + mask-size: 20px; + margin-right: 5px; + } +} + +.mx_AccessSecretStorageDialog_recoveryKeyFeedback_valid { + color: $input-valid-border-color; + &::before { + mask-image: url('$(res)/img/feather-customised/check.svg'); + background-color: $input-valid-border-color; + } +} + +.mx_AccessSecretStorageDialog_recoveryKeyFeedback_invalid { + color: $input-invalid-border-color; + &::before { + mask-image: url('$(res)/img/feather-customised/x.svg'); + background-color: $input-invalid-border-color; + } +} + +.mx_AccessSecretStorageDialog_recoveryKeyEntry_fileInput { + display: none; +} diff --git a/res/css/views/dialogs/secretstorage/_CreateSecretStorageDialog.scss b/res/css/views/dialogs/secretstorage/_CreateSecretStorageDialog.scss index 63e5a3de09..d30803b1f0 100644 --- a/res/css/views/dialogs/secretstorage/_CreateSecretStorageDialog.scss +++ b/res/css/views/dialogs/secretstorage/_CreateSecretStorageDialog.scss @@ -48,6 +48,29 @@ limitations under the License. margin-bottom: 1em; } +.mx_CreateSecretStorageDialog_titleWithIcon::before { + content: ''; + display: inline-block; + width: 24px; + height: 24px; + margin-right: 8px; + position: relative; + top: 5px; + background-color: $primary-fg-color; +} + +.mx_CreateSecretStorageDialog_secureBackupTitle::before { + mask-image: url('$(res)/img/feather-customised/secure-backup.svg'); +} + +.mx_CreateSecretStorageDialog_securePhraseTitle::before { + mask-image: url('$(res)/img/feather-customised/secure-phrase.svg'); +} + +.mx_CreateSecretStorageDialog_centeredTitle, .mx_CreateSecretStorageDialog_centeredBody { + text-align: center; +} + .mx_CreateSecretStorageDialog_primaryContainer { /* FIXME: plinth colour in new theme(s). background-color: $accent-color; */ padding-top: 20px; @@ -59,6 +82,36 @@ limitations under the License. display: block; } +.mx_CreateSecretStorageDialog_primaryContainer .mx_RadioButton { + margin-bottom: 16px; + padding: 11px; +} + +.mx_CreateSecretStorageDialog_optionTitle { + color: $dialog-title-fg-color; + font-weight: 600; + font-size: $font-18px; + padding-bottom: 10px; +} + +.mx_CreateSecretStorageDialog_optionIcon { + display: inline-block; + width: 24px; + height: 24px; + margin-right: 8px; + position: relative; + top: 5px; + background-color: $primary-fg-color; +} + +.mx_CreateSecretStorageDialog_optionIcon_securePhrase { + mask-image: url('$(res)/img/feather-customised/secure-phrase.svg'); +} + +.mx_CreateSecretStorageDialog_optionIcon_secureBackup { + mask-image: url('$(res)/img/feather-customised/secure-backup.svg'); +} + .mx_CreateSecretStorageDialog_passPhraseContainer { display: flex; align-items: flex-start; @@ -73,33 +126,42 @@ limitations under the License. margin-left: 20px; } -.mx_CreateSecretStorageDialog_recoveryKeyHeader { - margin-bottom: 1em; -} - .mx_CreateSecretStorageDialog_recoveryKeyContainer { - display: flex; + width: 380px; + margin-left: auto; + margin-right: auto; } .mx_CreateSecretStorageDialog_recoveryKey { - width: 262px; + font-weight: bold; + text-align: center; padding: 20px; color: $info-plinth-fg-color; background-color: $info-plinth-bg-color; - margin-right: 12px; + border-radius: 6px; + word-spacing: 1em; + margin-bottom: 20px; } .mx_CreateSecretStorageDialog_recoveryKeyButtons { - flex: 1; display: flex; + justify-content: space-between; align-items: center; } .mx_CreateSecretStorageDialog_recoveryKeyButtons .mx_AccessibleButton { - margin-right: 10px; -} - -.mx_CreateSecretStorageDialog_recoveryKeyButtons button { - flex: 1; + width: 160px; + padding-left: 0px; + padding-right: 0px; white-space: nowrap; } + +.mx_CreateSecretStorageDialog_continueSpinner { + margin-top: 33px; + text-align: right; +} + +.mx_CreateSecretStorageDialog_continueSpinner img { + width: 20px; + height: 20px; +} diff --git a/res/css/views/elements/_ProgressBar.scss b/res/css/views/elements/_ProgressBar.scss index a3fee232d0..e49d85af04 100644 --- a/res/css/views/elements/_ProgressBar.scss +++ b/res/css/views/elements/_ProgressBar.scss @@ -1,5 +1,5 @@ /* -Copyright 2015, 2016 OpenMarket Ltd +Copyright 2020 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -14,12 +14,26 @@ See the License for the specific language governing permissions and limitations under the License. */ -.mx_ProgressBar { - height: 5px; - border: 1px solid $progressbar-color; -} +progress.mx_ProgressBar { + height: 4px; + width: 60px; + border-radius: 10px; + overflow: hidden; + appearance: none; + border: 0; -.mx_ProgressBar_fill { - height: 100%; - background-color: $progressbar-color; + @mixin ProgressBarBorderRadius "10px"; + @mixin ProgressBarColour $accent-color; + ::-webkit-progress-value { + transition: width 1s; + } + ::-moz-progress-bar { + transition: padding-bottom 1s; + padding-bottom: var(--value); + transform-origin: 0 0; + transform: rotate(-90deg) translateX(-15px); + padding-left: 15px; + + height: 0; + } } diff --git a/res/css/views/elements/_StyledRadioButton.scss b/res/css/views/elements/_StyledRadioButton.scss index c2edb359dc..ffa1337ebb 100644 --- a/res/css/views/elements/_StyledRadioButton.scss +++ b/res/css/views/elements/_StyledRadioButton.scss @@ -25,13 +25,14 @@ limitations under the License. position: relative; display: flex; - align-items: center; + align-items: baseline; flex-grow: 1; - > span { + > .mx_RadioButton_content { flex-grow: 1; display: flex; + flex-direction: column; margin-left: 8px; margin-right: 8px; @@ -105,3 +106,12 @@ limitations under the License. } } } + +.mx_RadioButton_outlined { + border: 1px solid $input-darker-bg-color; + border-radius: 8px; +} + +.mx_RadioButton_checked { + border-color: $accent-color; +} diff --git a/res/css/views/elements/_Tooltip.scss b/res/css/views/elements/_Tooltip.scss index 73ac9b3558..d67928bf83 100644 --- a/res/css/views/elements/_Tooltip.scss +++ b/res/css/views/elements/_Tooltip.scss @@ -55,7 +55,7 @@ limitations under the License. border-radius: 4px; box-shadow: 4px 4px 12px 0 $menu-box-shadow-color; background-color: $menu-bg-color; - z-index: 4000; // Higher than dialogs so tooltips can be used in dialogs + z-index: 6000; // Higher than context menu so tooltips can be used everywhere padding: 10px; pointer-events: none; line-height: $font-14px; diff --git a/res/css/views/rooms/_RoomBreadcrumbs2.scss b/res/css/views/rooms/_RoomBreadcrumbs2.scss index dd9581069c..6e5a5fbb16 100644 --- a/res/css/views/rooms/_RoomBreadcrumbs2.scss +++ b/res/css/views/rooms/_RoomBreadcrumbs2.scss @@ -51,3 +51,18 @@ limitations under the License. height: 32px; } } + +.mx_RoomBreadcrumbs2_Tooltip { + margin-left: -42px; + margin-top: -42px; + + &.mx_Tooltip { + background-color: $tagpanel-bg-color; + color: $accent-fg-color; + border: 0; + + .mx_Tooltip_chevron { + display: none; + } + } +} diff --git a/res/css/views/rooms/_RoomSublist2.scss b/res/css/views/rooms/_RoomSublist2.scss index e86bf9fbe4..2ec959d472 100644 --- a/res/css/views/rooms/_RoomSublist2.scss +++ b/res/css/views/rooms/_RoomSublist2.scss @@ -102,7 +102,7 @@ limitations under the License. // Apply the width and margin to the badge so the container doesn't occupy dead space .mx_NotificationBadge { - width: 16px; + // Do not set a width so the badges get properly sized margin-left: 8px; // same as menu+aux buttons } } @@ -288,6 +288,7 @@ limitations under the License. } &.mx_RoomSublist2_hasMenuOpen, + &:not(.mx_RoomSublist2_minimized) > .mx_RoomSublist2_headerContainer:focus-within, &:not(.mx_RoomSublist2_minimized) > .mx_RoomSublist2_headerContainer:hover { .mx_RoomSublist2_menuButton { visibility: visible; @@ -399,3 +400,7 @@ limitations under the License. margin-top: 8px; } } + +.mx_RoomSublist2_addRoomTooltip { + margin-top: -3px; +} diff --git a/res/css/views/rooms/_RoomTile2.scss b/res/css/views/rooms/_RoomTile2.scss index 2845068de3..7b606ab947 100644 --- a/res/css/views/rooms/_RoomTile2.scss +++ b/res/css/views/rooms/_RoomTile2.scss @@ -23,27 +23,23 @@ limitations under the License. // The tile is also a flexbox row itself display: flex; - flex-wrap: wrap; - &.mx_RoomTile2_selected, &:hover, &.mx_RoomTile2_hasMenuOpen { + &.mx_RoomTile2_selected, + &:hover, + &:focus-within, + &.mx_RoomTile2_hasMenuOpen { background-color: $roomtile2-selected-bg-color; border-radius: 32px; } - .mx_RoomTile2_avatarContainer { + .mx_DecoratedRoomAvatar, .mx_RoomTile2_avatarContainer { margin-right: 8px; - position: relative; - - .mx_RoomTileIcon { - position: absolute; - bottom: 0; - right: 0; - } } .mx_RoomTile2_nameContainer { flex-grow: 1; - max-width: calc(100% - 58px); // 32px avatar, 18px badge area, 8px margin on avatar + min-width: 0; // allow flex to shrink it + margin-right: 8px; // spacing to buttons/badges // Create a new column layout flexbox for the name parts display: flex; @@ -81,31 +77,44 @@ limitations under the License. } } - .mx_RoomTile2_badgeContainer { - width: 18px; - height: 32px; - - // Create another flexbox row because it's super easy to position the badge at - // the end this way. - display: flex; - align-items: center; - justify-content: center; + .mx_RoomTile2_menuButton { + margin-left: 4px; // spacing between buttons } - // The menu button is hidden by default - // TODO: [Notifications] Use mx_RoomTile2_notificationsButton, similar to the following approach: - // https://github.com/matrix-org/matrix-react-sdk/blob/2180a56074f3698fc0241c309a72ba6cad802d1c/res/css/views/rooms/_RoomSublist2.scss#L48-L76 - // You'll need to do the same down below on the &:hover selector for the tile. - // See https://github.com/vector-im/riot-web/issues/13961. - // ... also remove this 5 line TODO comment. + .mx_RoomTile2_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 + position: relative; // fixes badge alignment in some scenarios + + // Create a flexbox to make aligning dot badges easier + display: flex; + align-items: center; + + .mx_NotificationBadge { + margin-right: 2px; // centering + } + + .mx_NotificationBadge_dot { + // make the smaller dot occupy the same width for centering + margin-left: 5px; + margin-right: 7px; + } + } + + // The context menu buttons are hidden by default .mx_RoomTile2_menuButton, .mx_RoomTile2_notificationsButton { - width: 0; - height: 0; - visibility: hidden; + width: 20px; + min-width: 20px; // yay flex + height: 20px; + margin: auto 0; position: relative; + display: none; &::before { + top: 2px; + left: 2px; content: ''; width: 16px; height: 16px; @@ -117,25 +126,29 @@ limitations under the License. } } + // If the room has an overriden notification setting then we always show the notifications menu button + .mx_RoomTile2_notificationsButton.mx_RoomTile2_notificationsButton_show { + display: block; + } + .mx_RoomTile2_menuButton::before { - top: 8px; - left: -1px; // this is off-center to align it with the badges mask-image: url('$(res)/img/feather-customised/more-horizontal.svg'); } &:not(.mx_RoomTile2_minimized) { - &:hover, &.mx_RoomTile2_hasMenuOpen { + &:hover, + &:focus-within, + &.mx_RoomTile2_hasMenuOpen { // Hide the badge container on hover because it'll be a menu button .mx_RoomTile2_badgeContainer { width: 0; height: 0; - visibility: hidden; + display: none; } + .mx_RoomTile2_notificationsButton, .mx_RoomTile2_menuButton { - width: 18px; - height: 32px; - visibility: visible; + display: block; } } } @@ -145,19 +158,29 @@ limitations under the License. align-items: center; position: relative; - .mx_RoomTile2_avatarContainer { + .mx_DecoratedRoomAvatar, .mx_RoomTile2_avatarContainer { margin-right: 0; } - - .mx_RoomTile2_badgeContainer { - position: absolute; - top: 0; - right: 0; - height: 18px; - } } } +// We use these both in context menus and the room tiles +.mx_RoomTile2_iconBell::before { + mask-image: url('$(res)/img/feather-customised/bell.svg'); +} +.mx_RoomTile2_iconBellDot::before { + mask-image: url('$(res)/img/feather-customised/bell-notification.custom.svg'); +} +.mx_RoomTile2_iconBellCrossed::before { + mask-image: url('$(res)/img/feather-customised/bell-crossed.svg'); +} +.mx_RoomTile2_iconBellMentions::before { + mask-image: url('$(res)/img/feather-customised/bell-mentions.custom.svg'); +} +.mx_RoomTile2_iconCheck::before { + mask-image: url('$(res)/img/feather-customised/check.svg'); +} + .mx_RoomTile2_contextMenu { .mx_RoomTile2_contextMenu_redRow { .mx_AccessibleButton { @@ -169,6 +192,16 @@ limitations under the License. } } + .mx_RoomTile2_contextMenu_activeRow { + &.mx_AccessibleButton, .mx_AccessibleButton { + color: $accent-color !important; // !important to override styles from context menu + } + + .mx_IconizedContextMenu_icon::before { + background-color: $accent-color; + } + } + .mx_IconizedContextMenu_icon { position: relative; width: 16px; diff --git a/res/css/views/settings/tabs/user/_AppearanceUserSettingsTab.scss b/res/css/views/settings/tabs/user/_AppearanceUserSettingsTab.scss index d724b164e5..94983a60bf 100644 --- a/res/css/views/settings/tabs/user/_AppearanceUserSettingsTab.scss +++ b/res/css/views/settings/tabs/user/_AppearanceUserSettingsTab.scss @@ -193,6 +193,10 @@ limitations under the License. .mx_EventTile_content { margin-right: 0; } + + &.mx_AppearanceUserSettingsTab_Layout_RadioButton_selected { + border-color: $accent-color; + } } .mx_RadioButton { diff --git a/res/img/feather-customised/bell-crossed.svg b/res/img/feather-customised/bell-crossed.svg new file mode 100644 index 0000000000..3ca24662b9 --- /dev/null +++ b/res/img/feather-customised/bell-crossed.svg @@ -0,0 +1,4 @@ + diff --git a/res/img/feather-customised/bell-mentions.custom.svg b/res/img/feather-customised/bell-mentions.custom.svg new file mode 100644 index 0000000000..fcc02f337f --- /dev/null +++ b/res/img/feather-customised/bell-mentions.custom.svg @@ -0,0 +1,3 @@ + diff --git a/res/img/feather-customised/bell-notification.custom.svg b/res/img/feather-customised/bell-notification.custom.svg new file mode 100644 index 0000000000..7bfd551f97 --- /dev/null +++ b/res/img/feather-customised/bell-notification.custom.svg @@ -0,0 +1,5 @@ + diff --git a/res/img/feather-customised/bell.svg b/res/img/feather-customised/bell.svg new file mode 100644 index 0000000000..b6bc5ec502 --- /dev/null +++ b/res/img/feather-customised/bell.svg @@ -0,0 +1,3 @@ + diff --git a/res/img/feather-customised/secure-backup.svg b/res/img/feather-customised/secure-backup.svg new file mode 100644 index 0000000000..c06f93c1fe --- /dev/null +++ b/res/img/feather-customised/secure-backup.svg @@ -0,0 +1,11 @@ + diff --git a/res/img/feather-customised/secure-phrase.svg b/res/img/feather-customised/secure-phrase.svg new file mode 100644 index 0000000000..eb13d3f048 --- /dev/null +++ b/res/img/feather-customised/secure-phrase.svg @@ -0,0 +1,11 @@ + diff --git a/src/SlashCommands.tsx b/src/SlashCommands.tsx index 7ebdc4ee3b..f667c47b3c 100644 --- a/src/SlashCommands.tsx +++ b/src/SlashCommands.tsx @@ -495,8 +495,7 @@ export const Commands = [ }); return success(); } else if (params[0][0] === '!') { - const roomId = params[0]; - const viaServers = params.splice(0); + const [roomId, ...viaServers] = params; dis.dispatch({ action: 'view_room', diff --git a/src/async-components/views/dialogs/secretstorage/CreateSecretStorageDialog.js b/src/async-components/views/dialogs/secretstorage/CreateSecretStorageDialog.js index d7b79c2cfa..4cef817a38 100644 --- a/src/async-components/views/dialogs/secretstorage/CreateSecretStorageDialog.js +++ b/src/async-components/views/dialogs/secretstorage/CreateSecretStorageDialog.js @@ -26,20 +26,27 @@ import { promptForBackupPassphrase } from '../../../../CrossSigningManager'; import {copyNode} from "../../../../utils/strings"; import {SSOAuthEntry} from "../../../../components/views/auth/InteractiveAuthEntryComponents"; import PassphraseField from "../../../../components/views/auth/PassphraseField"; +import StyledRadioButton from '../../../../components/views/elements/StyledRadioButton'; +import AccessibleButton from "../../../../components/views/elements/AccessibleButton"; +import DialogButtons from "../../../../components/views/elements/DialogButtons"; +import InlineSpinner from "../../../../components/views/elements/InlineSpinner"; const PHASE_LOADING = 0; const PHASE_LOADERROR = 1; -const PHASE_MIGRATE = 2; -const PHASE_PASSPHRASE = 3; -const PHASE_PASSPHRASE_CONFIRM = 4; -const PHASE_SHOWKEY = 5; -const PHASE_KEEPITSAFE = 6; -const PHASE_STORING = 7; -const PHASE_DONE = 8; -const PHASE_CONFIRM_SKIP = 9; +const PHASE_CHOOSE_KEY_PASSPHRASE = 2; +const PHASE_MIGRATE = 3; +const PHASE_PASSPHRASE = 4; +const PHASE_PASSPHRASE_CONFIRM = 5; +const PHASE_SHOWKEY = 6; +const PHASE_STORING = 8; +const PHASE_CONFIRM_SKIP = 10; const PASSWORD_MIN_SCORE = 4; // So secure, many characters, much complex, wow, etc, etc. +// these end up as strings from being values in the radio buttons, so just use strings +const CREATE_STORAGE_OPTION_KEY = 'key'; +const CREATE_STORAGE_OPTION_PASSPHRASE = 'passphrase'; + /* * Walks the user through the process of creating a passphrase to guard Secure * Secret Storage in account data. @@ -70,6 +77,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent { passPhraseConfirm: '', copied: false, downloaded: false, + setPassphrase: false, backupInfo: null, backupSigStatus: null, // does the server offer a UI auth flow with just m.login.password @@ -77,8 +85,8 @@ export default class CreateSecretStorageDialog extends React.PureComponent { canUploadKeysWithPasswordOnly: null, accountPassword: props.accountPassword || "", accountPasswordCorrect: null, - // status of the key backup toggle switch - useKeyBackup: true, + + passPhraseKeySelected: CREATE_STORAGE_OPTION_KEY, }; this._passphraseField = createRef(); @@ -110,7 +118,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent { ); const { force } = this.props; - const phase = (backupInfo && !force) ? PHASE_MIGRATE : PHASE_PASSPHRASE; + const phase = (backupInfo && !force) ? PHASE_MIGRATE : PHASE_CHOOSE_KEY_PASSPHRASE; this.setState({ phase, @@ -152,14 +160,33 @@ export default class CreateSecretStorageDialog extends React.PureComponent { if (this.state.phase === PHASE_MIGRATE) this._fetchBackupInfo(); } + _onKeyPassphraseChange = e => { + this.setState({ + passPhraseKeySelected: e.target.value, + }); + } + _collectRecoveryKeyNode = (n) => { this._recoveryKeyNode = n; } - _onUseKeyBackupChange = (enabled) => { - this.setState({ - useKeyBackup: enabled, - }); + _onChooseKeyPassphraseFormSubmit = async () => { + if (this.state.passPhraseKeySelected === CREATE_STORAGE_OPTION_KEY) { + this._recoveryKey = + await MatrixClientPeg.get().createRecoveryKeyFromPassphrase(); + this.setState({ + copied: false, + downloaded: false, + setPassphrase: false, + phase: PHASE_SHOWKEY, + }); + } else { + this.setState({ + copied: false, + downloaded: false, + phase: PHASE_PASSPHRASE, + }); + } } _onMigrateFormSubmit = (e) => { @@ -176,7 +203,6 @@ export default class CreateSecretStorageDialog extends React.PureComponent { if (successful) { this.setState({ copied: true, - phase: PHASE_KEEPITSAFE, }); } } @@ -189,7 +215,6 @@ export default class CreateSecretStorageDialog extends React.PureComponent { this.setState({ downloaded: true, - phase: PHASE_KEEPITSAFE, }); } @@ -259,22 +284,15 @@ export default class CreateSecretStorageDialog extends React.PureComponent { await cli.bootstrapSecretStorage({ authUploadDeviceSigningKeys: this._doBootstrapUIAuth, createSecretStorageKey: async () => this._recoveryKey, - setupNewKeyBackup: this.state.useKeyBackup, + setupNewKeyBackup: true, setupNewSecretStorage: true, }); - if (!this.state.useKeyBackup && this.state.backupInfo) { - // If the user is resetting their cross-signing keys and doesn't want - // key backup (but had it enabled before), delete the key backup as it's - // no longer valid. - console.log("Deleting invalid key backup (secrets have been reset; key backup not requested)"); - await cli.deleteKeyBackupVersion(this.state.backupInfo.version); - } } else { await cli.bootstrapSecretStorage({ authUploadDeviceSigningKeys: this._doBootstrapUIAuth, createSecretStorageKey: async () => this._recoveryKey, keyBackupInfo: this.state.backupInfo, - setupNewKeyBackup: !this.state.backupInfo && this.state.useKeyBackup, + setupNewKeyBackup: !this.state.backupInfo, getKeyBackupPassphrase: () => { // We may already have the backup key if we earlier went // through the restore backup path, so pass it along @@ -286,9 +304,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent { }, }); } - this.setState({ - phase: PHASE_DONE, - }); + this.props.onFinished(true); } catch (e) { if (this.state.canUploadKeysWithPasswordOnly && e.httpStatus === 401 && e.data.flows) { this.setState({ @@ -342,22 +358,16 @@ export default class CreateSecretStorageDialog extends React.PureComponent { this._fetchBackupInfo(); } - _onSkipSetupClick = () => { + _onShowKeyContinueClick = () => { + this._bootstrapSecretStorage(); + } + + _onCancelClick = () => { this.setState({phase: PHASE_CONFIRM_SKIP}); } - _onSetUpClick = () => { - this.setState({phase: PHASE_PASSPHRASE}); - } - - _onSkipPassPhraseClick = async () => { - this._recoveryKey = - await MatrixClientPeg.get().createRecoveryKeyFromPassphrase(); - this.setState({ - copied: false, - downloaded: false, - phase: PHASE_SHOWKEY, - }); + _onGoBackClick = () => { + this.setState({phase: PHASE_CHOOSE_KEY_PASSPHRASE}); } _onPassPhraseNextClick = async (e) => { @@ -384,6 +394,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent { this.setState({ copied: false, downloaded: false, + setPassphrase: true, phase: PHASE_SHOWKEY, }); } @@ -397,12 +408,6 @@ export default class CreateSecretStorageDialog extends React.PureComponent { }); } - _onKeepItSafeBackClick = () => { - this.setState({ - phase: PHASE_SHOWKEY, - }); - } - _onPassPhraseValidate = (result) => { this.setState({ passPhraseValid: result.valid, @@ -427,13 +432,55 @@ export default class CreateSecretStorageDialog extends React.PureComponent { }); } + _renderPhaseChooseKeyPassphrase() { + return
; + } + _renderPhaseMigrate() { // TODO: This is a temporary screen so people who have the labs flag turned on and // click the button are aware they're making a change to their account. // Once we're confident enough in this (and it's supported enough) we can do // it automatically. // https://github.com/vector-im/riot-web/issues/11696 - const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); const Field = sdk.getComponent('views.elements.Field'); let authPrompt; @@ -446,7 +493,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent { label={_t("Password")} value={this.state.accountPassword} onChange={this._onAccountPasswordChange} - flagInvalid={this.state.accountPasswordCorrect === false} + forceValidity={this.state.accountPasswordCorrect === false ? false : null} autoFocus={true} /> ; @@ -474,7 +521,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent { hasCancel={false} primaryDisabled={this.state.canUploadKeysWithPasswordOnly && !this.state.accountPassword} > - - -