diff --git a/package.json b/package.json
index c9300a13ca..7ba69c4272 100644
--- a/package.json
+++ b/package.json
@@ -64,8 +64,8 @@
"create-react-class": "^15.6.0",
"diff-dom": "^4.1.3",
"diff-match-patch": "^1.0.4",
- "emojibase-data": "^4.0.2",
- "emojibase-regex": "^3.0.0",
+ "emojibase-data": "^5.0.1",
+ "emojibase-regex": "^4.0.1",
"escape-html": "^1.0.3",
"file-saver": "^1.3.3",
"filesize": "3.5.6",
@@ -89,7 +89,6 @@
"qrcode-react": "^0.1.16",
"qs": "^6.6.0",
"react": "^16.9.0",
- "react-addons-css-transition-group": "15.6.2",
"react-beautiful-dnd": "^4.0.1",
"react-dom": "^16.9.0",
"react-focus-lock": "^2.2.1",
diff --git a/res/css/_components.scss b/res/css/_components.scss
index 8706772ad9..a5dc87a952 100644
--- a/res/css/_components.scss
+++ b/res/css/_components.scss
@@ -94,6 +94,7 @@
@import "./views/elements/_AccessibleButton.scss";
@import "./views/elements/_AddressSelector.scss";
@import "./views/elements/_AddressTile.scss";
+@import "./views/elements/_ButtonPlaceholder.scss";
@import "./views/elements/_DirectorySearchBox.scss";
@import "./views/elements/_Dropdown.scss";
@import "./views/elements/_EditableItemList.scss";
@@ -133,6 +134,7 @@
@import "./views/messages/_MNoticeBody.scss";
@import "./views/messages/_MStickerBody.scss";
@import "./views/messages/_MTextBody.scss";
+@import "./views/messages/_MVideoBody.scss";
@import "./views/messages/_MessageActionBar.scss";
@import "./views/messages/_MessageTimestamp.scss";
@import "./views/messages/_MjolnirBody.scss";
diff --git a/res/css/structures/_HomePage.scss b/res/css/structures/_HomePage.scss
index 3aa80f6f59..0160cf368b 100644
--- a/res/css/structures/_HomePage.scss
+++ b/res/css/structures/_HomePage.scss
@@ -23,3 +23,84 @@ limitations under the License.
margin-left: auto;
margin-right: auto;
}
+
+.mx_HomePage_default {
+ text-align: center;
+
+ .mx_HomePage_default_wrapper {
+ padding: 25vh 0 12px;
+ }
+
+ img {
+ height: 48px;
+ }
+
+ h1 {
+ font-weight: 600;
+ font-size: $font-32px;
+ line-height: $font-44px;
+ margin-bottom: 4px;
+ }
+
+ h4 {
+ margin-top: 4px;
+ font-weight: 600;
+ font-size: $font-18px;
+ line-height: $font-25px;
+ color: $muted-fg-color;
+ }
+
+ .mx_HomePage_default_buttons {
+ margin: 80px auto 0;
+ width: fit-content;
+
+ .mx_AccessibleButton {
+ padding: 73px 8px 15px; // top: 20px top padding + 40px icon + 13px margin
+
+ width: 104px; // 120px - 2* 8px
+ margin: 0 39px; // 55px - 2* 8px
+ position: relative;
+ display: inline-block;
+ border-radius: 8px;
+ vertical-align: top;
+ word-break: break-word;
+
+ font-weight: 600;
+ font-size: $font-15px;
+ line-height: $font-20px;
+ color: $muted-fg-color;
+
+ &:hover {
+ color: $accent-color;
+ background: rgba(#03b381, 0.06);
+
+ &::before {
+ background-color: $accent-color;
+ }
+ }
+
+ &::before {
+ top: 20px;
+ left: 40px; // (120px-40px)/2
+ width: 40px;
+ height: 40px;
+
+ content: '';
+ position: absolute;
+ background-color: $muted-fg-color;
+ mask-repeat: no-repeat;
+ mask-size: contain;
+ }
+
+ &.mx_HomePage_button_sendDm::before {
+ mask-image: url('$(res)/img/feather-customised/message-circle.svg');
+ }
+ &.mx_HomePage_button_explore::before {
+ mask-image: url('$(res)/img/feather-customised/explore.svg');
+ }
+ &.mx_HomePage_button_createGroup::before {
+ mask-image: url('$(res)/img/feather-customised/group.svg');
+ }
+ }
+ }
+}
diff --git a/res/css/structures/auth/_CompleteSecurity.scss b/res/css/structures/auth/_CompleteSecurity.scss
index 3050840fe8..80e7aaada0 100644
--- a/res/css/structures/auth/_CompleteSecurity.scss
+++ b/res/css/structures/auth/_CompleteSecurity.scss
@@ -44,6 +44,7 @@ limitations under the License.
.mx_CompleteSecurity_actionRow {
display: flex;
justify-content: flex-end;
+ margin-top: $font-28px;
.mx_AccessibleButton {
margin-inline-start: 18px;
diff --git a/res/css/structures/auth/_Login.scss b/res/css/structures/auth/_Login.scss
index 4ce90cc6bd..02436833a2 100644
--- a/res/css/structures/auth/_Login.scss
+++ b/res/css/structures/auth/_Login.scss
@@ -89,3 +89,13 @@ limitations under the License.
.mx_Login_underlinedServerName {
border-bottom: 1px dashed $accent-color;
}
+
+div.mx_AccessibleButton_kind_link.mx_Login_forgot {
+ // style it as a link
+ font-size: inherit;
+ padding: 0;
+
+ &.mx_AccessibleButton_disabled {
+ cursor: not-allowed;
+ }
+}
diff --git a/res/css/views/auth/_AuthBody.scss b/res/css/views/auth/_AuthBody.scss
index 468a4b3d62..4b2d6b1bf1 100644
--- a/res/css/views/auth/_AuthBody.scss
+++ b/res/css/views/auth/_AuthBody.scss
@@ -119,6 +119,24 @@ limitations under the License.
margin-right: 0;
}
+.mx_AuthBody_paddedFooter {
+ height: 80px; // height of the submit button + register link
+ padding-top: 28px;
+ text-align: center;
+
+ .mx_AuthBody_paddedFooter_title {
+ margin-top: 16px;
+ font-size: $font-15px;
+ line-height: $font-24px;
+ }
+
+ .mx_AuthBody_paddedFooter_subtitle {
+ margin-top: 8px;
+ font-size: $font-10px;
+ line-height: $font-14px;
+ }
+}
+
.mx_AuthBody_changeFlow {
display: block;
text-align: center;
diff --git a/res/css/views/context_menus/_MessageContextMenu.scss b/res/css/views/context_menus/_MessageContextMenu.scss
index d15d566bdb..2ecb93e734 100644
--- a/res/css/views/context_menus/_MessageContextMenu.scss
+++ b/res/css/views/context_menus/_MessageContextMenu.scss
@@ -19,6 +19,7 @@ limitations under the License.
}
.mx_MessageContextMenu_field {
+ display: block;
padding: 3px 6px 3px 6px;
cursor: pointer;
white-space: nowrap;
diff --git a/res/css/views/dialogs/_CreateRoomDialog.scss b/res/css/views/dialogs/_CreateRoomDialog.scss
index c542741c30..2678f7b4ad 100644
--- a/res/css/views/dialogs/_CreateRoomDialog.scss
+++ b/res/css/views/dialogs/_CreateRoomDialog.scss
@@ -15,6 +15,8 @@ limitations under the License.
*/
.mx_CreateRoomDialog_details {
+ margin-top: 15px;
+
.mx_CreateRoomDialog_details_summary {
outline: none;
list-style: none;
@@ -71,11 +73,19 @@ limitations under the License.
}
.mx_CreateRoomDialog {
-
&.mx_Dialog_fixedWidth {
width: 450px;
}
+ .mx_Dialog_content {
+ margin-bottom: 40px;
+ }
+
+ p,
+ .mx_Field_input label {
+ color: $muted-fg-color;
+ }
+
.mx_SettingsFlag {
display: flex;
}
@@ -90,5 +100,18 @@ limitations under the License.
flex: 0 0 auto;
margin-left: 30px;
}
+
+ .mx_CreateRoomDialog_topic {
+ margin-bottom: 36px;
+ }
+
+ .mx_Dialog_content > .mx_SettingsFlag {
+ margin-top: 24px;
+ }
+
+ p {
+ margin: 0 85px 0 0;
+ font-size: $font-12px;
+ }
}
diff --git a/res/css/views/directory/_NetworkDropdown.scss b/res/css/views/directory/_NetworkDropdown.scss
index 269b507e3c..dd1892c448 100644
--- a/res/css/views/directory/_NetworkDropdown.scss
+++ b/res/css/views/directory/_NetworkDropdown.scss
@@ -35,6 +35,8 @@ limitations under the License.
border-radius: 4px;
border: 1px solid $dialog-close-fg-color;
background-color: $primary-bg-color;
+ max-height: calc(100vh - 20px); // allow 10px padding on both top and bottom
+ overflow-y: auto;
}
.mx_NetworkDropdown_menu_network {
diff --git a/res/css/views/elements/_ButtonPlaceholder.scss b/res/css/views/elements/_ButtonPlaceholder.scss
new file mode 100644
index 0000000000..858fcdecf6
--- /dev/null
+++ b/res/css/views/elements/_ButtonPlaceholder.scss
@@ -0,0 +1,24 @@
+/*
+Copyright 2020 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+.mx_ButtonPlaceholder {
+ font-size: $font-14px;
+ font-weight: 600;
+ padding: 7px 18px;
+ display: inline-block;
+ text-align: center;
+ color: $authpage-secondary-color;
+}
diff --git a/res/css/views/elements/_Dropdown.scss b/res/css/views/elements/_Dropdown.scss
index 0dd9656c9c..32a68d5252 100644
--- a/res/css/views/elements/_Dropdown.scss
+++ b/res/css/views/elements/_Dropdown.scss
@@ -33,6 +33,10 @@ limitations under the License.
user-select: none;
}
+.mx_Dropdown_input.mx_AccessibleButton_disabled {
+ cursor: not-allowed;
+}
+
.mx_Dropdown_input:focus {
border-color: $input-focused-border-color;
}
diff --git a/res/css/views/elements/_RichText.scss b/res/css/views/elements/_RichText.scss
index e3f88cc779..e01b1f8938 100644
--- a/res/css/views/elements/_RichText.scss
+++ b/res/css/views/elements/_RichText.scss
@@ -14,8 +14,11 @@
}
a.mx_Pill {
- word-break: break-all;
- display: inline;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ overflow: hidden;
+ vertical-align: text-bottom;
+ max-width: calc(100% - 1ch);
}
/* More specific to override `.markdown-body a` text-decoration */
diff --git a/res/css/views/messages/_MVideoBody.scss b/res/css/views/messages/_MVideoBody.scss
new file mode 100644
index 0000000000..3b05c53f34
--- /dev/null
+++ b/res/css/views/messages/_MVideoBody.scss
@@ -0,0 +1,22 @@
+/*
+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.
+*/
+
+span.mx_MVideoBody {
+ video.mx_MVideoBody {
+ max-width: 100%;
+ height: auto;
+ }
+}
diff --git a/res/css/views/messages/_ReactionsRowButton.scss b/res/css/views/messages/_ReactionsRowButton.scss
index 941153ca5b..fe5b081042 100644
--- a/res/css/views/messages/_ReactionsRowButton.scss
+++ b/res/css/views/messages/_ReactionsRowButton.scss
@@ -34,12 +34,17 @@ limitations under the License.
background-color: $reaction-row-button-selected-bg-color;
border-color: $reaction-row-button-selected-border-color;
}
-}
-.mx_ReactionsRowButton_content {
- max-width: 100px;
- overflow: hidden;
- white-space: nowrap;
- text-overflow: ellipsis;
- padding-right: 4px;
+ // ignore mouse events for all children, treat it as one entire hoverable entity
+ * {
+ pointer-events: none;
+ }
+
+ .mx_ReactionsRowButton_content {
+ max-width: 100px;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ padding-right: 4px;
+ }
}
diff --git a/res/css/views/rooms/_BasicMessageComposer.scss b/res/css/views/rooms/_BasicMessageComposer.scss
index cc76623a8c..e9013eb7b7 100644
--- a/res/css/views/rooms/_BasicMessageComposer.scss
+++ b/res/css/views/rooms/_BasicMessageComposer.scss
@@ -44,27 +44,29 @@ limitations under the License.
outline: none;
overflow-x: hidden;
- span.mx_UserPill, span.mx_RoomPill {
- padding-left: 21px;
- position: relative;
+ &.mx_BasicMessageComposer_input_shouldShowPillAvatar {
+ span.mx_UserPill, span.mx_RoomPill {
+ padding-left: 21px;
+ position: relative;
- // avatar psuedo element
- &::before {
- position: absolute;
- left: 2px;
- top: 2px;
- content: var(--avatar-letter);
- width: 16px;
- height: 16px;
- background: var(--avatar-background), $avatar-bg-color;
- color: $avatar-initial-color;
- background-repeat: no-repeat;
- background-size: 16px;
- border-radius: 8px;
- text-align: center;
- font-weight: normal;
- line-height: $font-16px;
- font-size: $font-10-4px;
+ // avatar psuedo element
+ &::before {
+ position: absolute;
+ left: 2px;
+ top: 2px;
+ content: var(--avatar-letter);
+ width: 16px;
+ height: 16px;
+ background: var(--avatar-background), $avatar-bg-color;
+ color: $avatar-initial-color;
+ background-repeat: no-repeat;
+ background-size: 16px;
+ border-radius: 8px;
+ text-align: center;
+ font-weight: normal;
+ line-height: $font-16px;
+ font-size: $font-10-4px;
+ }
}
}
}
diff --git a/res/css/views/rooms/_EventTile.scss b/res/css/views/rooms/_EventTile.scss
index 3c91089dc9..0dc60226b8 100644
--- a/res/css/views/rooms/_EventTile.scss
+++ b/res/css/views/rooms/_EventTile.scss
@@ -111,6 +111,7 @@ limitations under the License.
}
.mx_EventTile_line, .mx_EventTile_reply {
+ clear: both;
position: relative;
padding-left: 65px; /* left gutter */
padding-top: 4px;
diff --git a/res/css/views/rooms/_RoomTile.scss b/res/css/views/rooms/_RoomTile.scss
index 7be2a4e3d4..de018bf178 100644
--- a/res/css/views/rooms/_RoomTile.scss
+++ b/res/css/views/rooms/_RoomTile.scss
@@ -24,6 +24,20 @@ limitations under the License.
margin: 0;
padding: 0 8px 0 10px;
position: relative;
+
+ .mx_RoomTile_menuButton {
+ display: none;
+ flex: 0 0 16px;
+ height: 16px;
+ background-image: url('$(res)/img/icon_context.svg');
+ background-repeat: no-repeat;
+ background-position: center;
+ }
+
+ .mx_UserOnlineDot {
+ display: block;
+ margin-right: 5px;
+ }
}
.mx_RoomTile:focus {
@@ -31,15 +45,6 @@ limitations under the License.
background-color: $roomtile-focused-bg-color;
}
-.mx_RoomTile_menuButton {
- display: none;
- flex: 0 0 16px;
- height: 16px;
- background-image: url('$(res)/img/icon_context.svg');
- background-repeat: no-repeat;
- background-position: center;
-}
-
.mx_RoomTile_tooltip {
display: inline-block;
position: relative;
@@ -151,7 +156,10 @@ limitations under the License.
}
.mx_RoomTile_menuButton {
- display: none; //no design for this for now
+ display: none; // no design for this for now
+ }
+ .mx_UserOnlineDot {
+ display: none; // no design for this for now
}
}
@@ -164,6 +172,9 @@ limitations under the License.
.mx_RoomTile_menuButton {
display: block;
}
+ .mx_UserOnlineDot {
+ display: none;
+ }
}
.mx_RoomTile_unreadNotify .mx_RoomTile_badge,
diff --git a/res/css/views/rooms/_UserOnlineDot.scss b/res/css/views/rooms/_UserOnlineDot.scss
index 339e5cc48a..f9da8648ed 100644
--- a/res/css/views/rooms/_UserOnlineDot.scss
+++ b/res/css/views/rooms/_UserOnlineDot.scss
@@ -17,7 +17,7 @@ limitations under the License.
.mx_UserOnlineDot {
border-radius: 50%;
background-color: $accent-color;
- height: 5px;
- width: 5px;
+ height: 6px;
+ width: 6px;
display: inline-block;
}
diff --git a/res/css/views/verification/_VerificationShowSas.scss b/res/css/views/verification/_VerificationShowSas.scss
index 6e26943640..af003112f7 100644
--- a/res/css/views/verification/_VerificationShowSas.scss
+++ b/res/css/views/verification/_VerificationShowSas.scss
@@ -61,3 +61,21 @@ limitations under the License.
.mx_VerificationShowSas_emojiSas_break {
flex-basis: 100%;
}
+
+.mx_VerificationShowSas {
+ .mx_Dialog_buttons {
+ // this is more specific than the DialogButtons css so gets preference
+ button.mx_VerificationShowSas_matchButton {
+ color: $accent-color;
+ background-color: $accent-bg-color;
+ border: none;
+ }
+
+ // this is more specific than the DialogButtons css so gets preference
+ button.mx_VerificationShowSas_noMatchButton {
+ color: $notice-primary-color;
+ background-color: $notice-primary-bg-color;
+ border: none;
+ }
+ }
+}
diff --git a/res/img/feather-customised/explore.svg b/res/img/feather-customised/explore.svg
new file mode 100644
index 0000000000..45be889bb7
--- /dev/null
+++ b/res/img/feather-customised/explore.svg
@@ -0,0 +1,8 @@
+
diff --git a/res/img/feather-customised/group.svg b/res/img/feather-customised/group.svg
new file mode 100644
index 0000000000..7051860e62
--- /dev/null
+++ b/res/img/feather-customised/group.svg
@@ -0,0 +1,7 @@
+
diff --git a/res/img/feather-customised/message-circle.svg b/res/img/feather-customised/message-circle.svg
new file mode 100644
index 0000000000..acc6d2fb0f
--- /dev/null
+++ b/res/img/feather-customised/message-circle.svg
@@ -0,0 +1,3 @@
+
diff --git a/res/img/icon_person.svg b/res/img/icon_person.svg
deleted file mode 100644
index 4be70df0db..0000000000
--- a/res/img/icon_person.svg
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
diff --git a/scripts/ci/end-to-end-tests.sh b/scripts/ci/end-to-end-tests.sh
index 2f907dffa2..1233677db4 100755
--- a/scripts/ci/end-to-end-tests.sh
+++ b/scripts/ci/end-to-end-tests.sh
@@ -13,7 +13,6 @@ handle_error() {
trap 'handle_error' ERR
-
echo "--- Building Riot"
scripts/ci/layered-riot-web.sh
cd ../riot-web
diff --git a/scripts/gen-i18n.js b/scripts/gen-i18n.js
index a4d53aea2f..a1823cdf50 100755
--- a/scripts/gen-i18n.js
+++ b/scripts/gen-i18n.js
@@ -237,7 +237,7 @@ const walkOpts = {
const fullPath = path.join(root, fileStats.name);
let trs;
- if (fileStats.name.endsWith('.js') || fileStats.name.endsWith('.tsx')) {
+ if (fileStats.name.endsWith('.js') || fileStats.name.endsWith('.ts') || fileStats.name.endsWith('.tsx')) {
trs = getTranslationsJs(fullPath);
} else if (fileStats.name.endsWith('.html')) {
trs = getTranslationsOther(fullPath);
diff --git a/src/Analytics.js b/src/Analytics.js
index c96cfdefee..e55612c4f1 100644
--- a/src/Analytics.js
+++ b/src/Analytics.js
@@ -123,8 +123,8 @@ const LAST_VISIT_TS_KEY = "mx_Riot_Analytics_lvts";
function getUid() {
try {
- let data = localStorage.getItem(UID_KEY);
- if (!data) {
+ let data = localStorage && localStorage.getItem(UID_KEY);
+ if (!data && localStorage) {
localStorage.setItem(UID_KEY, data = [...Array(16)].map(() => Math.random().toString(16)[2]).join(''));
}
return data;
@@ -145,14 +145,16 @@ class Analytics {
this.firstPage = true;
this._heartbeatIntervalID = null;
- this.creationTs = localStorage.getItem(CREATION_TS_KEY);
- if (!this.creationTs) {
+ this.creationTs = localStorage && localStorage.getItem(CREATION_TS_KEY);
+ if (!this.creationTs && localStorage) {
localStorage.setItem(CREATION_TS_KEY, this.creationTs = new Date().getTime());
}
- this.lastVisitTs = localStorage.getItem(LAST_VISIT_TS_KEY);
- this.visitCount = localStorage.getItem(VISIT_COUNT_KEY) || 0;
- localStorage.setItem(VISIT_COUNT_KEY, parseInt(this.visitCount, 10) + 1);
+ this.lastVisitTs = localStorage && localStorage.getItem(LAST_VISIT_TS_KEY);
+ this.visitCount = localStorage && localStorage.getItem(VISIT_COUNT_KEY) || 0;
+ if (localStorage) {
+ localStorage.setItem(VISIT_COUNT_KEY, parseInt(this.visitCount, 10) + 1);
+ }
}
get disabled() {
diff --git a/src/BasePlatform.js b/src/BasePlatform.js
index 5d809eb28f..7214031586 100644
--- a/src/BasePlatform.js
+++ b/src/BasePlatform.js
@@ -188,4 +188,8 @@ export default class BasePlatform {
const callbackUrl = this.getSSOCallbackUrl(mxClient.getHomeserverUrl(), mxClient.getIdentityServerUrl());
window.location.href = mxClient.getSsoLoginUrl(callbackUrl.toString(), loginType); // redirect to SSO
}
+
+ onKeyDown(ev: KeyboardEvent): boolean {
+ return false; // no shortcuts implemented
+ }
}
diff --git a/src/CallHandler.js b/src/CallHandler.js
index 8284e788b4..c63bfe309a 100644
--- a/src/CallHandler.js
+++ b/src/CallHandler.js
@@ -60,12 +60,12 @@ import * as sdk from './index';
import { _t } from './languageHandler';
import Matrix from 'matrix-js-sdk';
import dis from './dispatcher';
-import SdkConfig from './SdkConfig';
import { showUnknownDeviceDialogForCalls } from './cryptodevices';
import WidgetUtils from './utils/WidgetUtils';
import WidgetEchoStore from './stores/WidgetEchoStore';
import SettingsStore, { SettingLevel } from './settings/SettingsStore';
import {generateHumanReadableId} from "./utils/NamingUtils";
+import {Jitsi} from "./widgets/Jitsi";
global.mxCalls = {
//room_id: MatrixCall
@@ -431,7 +431,7 @@ async function _startCallApp(roomId, type) {
}
const confId = `JitsiConference${generateHumanReadableId()}`;
- const jitsiDomain = SdkConfig.get()['jitsi']['preferredDomain'];
+ const jitsiDomain = Jitsi.getInstance().preferredDomain;
let widgetUrl = WidgetUtils.getLocalJitsiWrapperUrl();
diff --git a/src/CrossSigningManager.js b/src/CrossSigningManager.js
index 1bcf1ba706..c37d0f8bf5 100644
--- a/src/CrossSigningManager.js
+++ b/src/CrossSigningManager.js
@@ -51,7 +51,7 @@ async function confirmToDismiss(name) {
} else if (name === "m.cross_signing.self_signing") {
description = _t("If you cancel now, you won't complete verifying your other session.");
} else {
- description = _t("If you cancel now, you won't complete your secret storage operation.");
+ description = _t("If you cancel now, you won't complete your operation.");
}
const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog");
@@ -185,7 +185,7 @@ export async function promptForBackupPassphrase() {
const RestoreKeyBackupDialog = sdk.getComponent('dialogs.keybackup.RestoreKeyBackupDialog');
const { finished } = Modal.createTrackedDialog('Restore Backup', '', RestoreKeyBackupDialog, {
- showSummary: false, keyCallback: k => key = k,
+ showSummary: false, keyCallback: k => key = k,
}, null, /* priority = */ false, /* static = */ true);
const success = await finished;
diff --git a/src/DeviceListener.js b/src/DeviceListener.js
index ddeacedd75..3201e4af45 100644
--- a/src/DeviceListener.js
+++ b/src/DeviceListener.js
@@ -50,6 +50,7 @@ export default class DeviceListener {
MatrixClientPeg.get().on('crypto.devicesUpdated', this._onDevicesUpdated);
MatrixClientPeg.get().on('deviceVerificationChanged', this._onDeviceVerificationChanged);
MatrixClientPeg.get().on('userTrustStatusChanged', this._onUserTrustStatusChanged);
+ MatrixClientPeg.get().on('crossSigning.keysChanged', this._onCrossSingingKeysChanged);
MatrixClientPeg.get().on('accountData', this._onAccountData);
this._recheck();
}
@@ -59,6 +60,7 @@ export default class DeviceListener {
MatrixClientPeg.get().removeListener('crypto.devicesUpdated', this._onDevicesUpdated);
MatrixClientPeg.get().removeListener('deviceVerificationChanged', this._onDeviceVerificationChanged);
MatrixClientPeg.get().removeListener('userTrustStatusChanged', this._onUserTrustStatusChanged);
+ MatrixClientPeg.get().removeListener('crossSigning.keysChanged', this._onCrossSingingKeysChanged);
MatrixClientPeg.get().removeListener('accountData', this._onAccountData);
}
this._dismissed.clear();
@@ -89,9 +91,20 @@ export default class DeviceListener {
this._recheck();
}
+ _onCrossSingingKeysChanged = () => {
+ this._recheck();
+ }
+
_onAccountData = (ev) => {
- // User may have migrated SSSS to symmetric, in which case we can dismiss that toast
- if (ev.getType().startsWith('m.secret_storage.key.')) {
+ // User may have:
+ // * migrated SSSS to symmetric
+ // * uploaded keys to secret storage
+ // * completed secret storage creation
+ // which result in account data changes affecting checks below.
+ if (
+ ev.getType().startsWith('m.secret_storage.') ||
+ ev.getType().startsWith('m.cross_signing.')
+ ) {
this._recheck();
}
}
@@ -111,7 +124,7 @@ export default class DeviceListener {
const cli = MatrixClientPeg.get();
if (
- !SettingsStore.isFeatureEnabled("feature_cross_signing") ||
+ !SettingsStore.getValue("feature_cross_signing") ||
!await cli.doesServerSupportUnstableFeature("org.matrix.e2e_cross_signing")
) return;
diff --git a/src/KeyRequestHandler.js b/src/KeyRequestHandler.js
index 30f3b7d50e..ceaff0c54d 100644
--- a/src/KeyRequestHandler.js
+++ b/src/KeyRequestHandler.js
@@ -35,7 +35,7 @@ export default class KeyRequestHandler {
handleKeyRequest(keyRequest) {
// Ignore own device key requests if cross-signing lab enabled
- if (SettingsStore.isFeatureEnabled("feature_cross_signing")) {
+ if (SettingsStore.getValue("feature_cross_signing")) {
return;
}
@@ -70,7 +70,7 @@ export default class KeyRequestHandler {
handleKeyRequestCancellation(cancellation) {
// Ignore own device key requests if cross-signing lab enabled
- if (SettingsStore.isFeatureEnabled("feature_cross_signing")) {
+ if (SettingsStore.getValue("feature_cross_signing")) {
return;
}
diff --git a/src/Keyboard.ts b/src/Keyboard.ts
index 23e2bbf0d6..7040898872 100644
--- a/src/Keyboard.ts
+++ b/src/Keyboard.ts
@@ -43,6 +43,8 @@ export const Key = {
BACKTICK: "`",
SPACE: " ",
SLASH: "/",
+ SQUARE_BRACKET_LEFT: "[",
+ SQUARE_BRACKET_RIGHT: "]",
A: "a",
B: "b",
C: "c",
diff --git a/src/Lifecycle.js b/src/Lifecycle.js
index b9fbf4f1bc..1baa6c8e0c 100644
--- a/src/Lifecycle.js
+++ b/src/Lifecycle.js
@@ -40,6 +40,7 @@ import ToastStore from "./stores/ToastStore";
import {IntegrationManagers} from "./integrations/IntegrationManagers";
import {Mjolnir} from "./mjolnir/Mjolnir";
import DeviceListener from "./DeviceListener";
+import {Jitsi} from "./widgets/Jitsi";
/**
* Called at startup, to attempt to build a logged-in Matrix session. It tries
@@ -578,9 +579,6 @@ async function startMatrixClient(startSyncing=true) {
UserActivity.sharedInstance().start();
TypingStore.sharedInstance().reset(); // just in case
ToastStore.sharedInstance().reset();
- if (!SettingsStore.getValue("lowBandwidth")) {
- Presence.start();
- }
DMRoomMap.makeShared().start();
IntegrationManagers.sharedInstance().startWatching();
ActiveWidgetStore.start();
@@ -603,6 +601,14 @@ async function startMatrixClient(startSyncing=true) {
// This needs to be started after crypto is set up
DeviceListener.sharedInstance().start();
+ // Similarly, don't start sending presence updates until we've started
+ // the client
+ if (!SettingsStore.getValue("lowBandwidth")) {
+ Presence.start();
+ }
+
+ // Now that we have a MatrixClientPeg, update the Jitsi info
+ await Jitsi.getInstance().update();
// dispatch that we finished starting up to wire up any other bits
// of the matrix client that cannot be set prior to starting up.
@@ -637,6 +643,10 @@ async function _clearStorage() {
window.localStorage.clear();
}
+ if (window.sessionStorage) {
+ window.sessionStorage.clear();
+ }
+
// create a temporary client to clear out the persistent stores.
const cli = createMatrixClient({
// we'll never make any requests, so can pass a bogus HS URL
diff --git a/src/Notifier.js b/src/Notifier.js
index 36a6f13bb6..ec92840998 100644
--- a/src/Notifier.js
+++ b/src/Notifier.js
@@ -37,6 +37,18 @@ import SettingsStore, {SettingLevel} from "./settings/SettingsStore";
const MAX_PENDING_ENCRYPTED = 20;
+/*
+Override both the content body and the TextForEvent handler for specific msgtypes, in notifications.
+This is useful when the content body contains fallback text that would explain that the client can't handle a particular
+type of tile.
+*/
+const typehandlers = {
+ "m.key.verification.request": (event) => {
+ const name = (event.sender || {}).name;
+ return _t("%(name)s is requesting verification", { name });
+ },
+};
+
const Notifier = {
notifsByRoom: {},
@@ -46,6 +58,9 @@ const Notifier = {
pendingEncryptedEventIds: [],
notificationMessageForEvent: function(ev) {
+ if (typehandlers.hasOwnProperty(ev.getContent().msgtype)) {
+ return typehandlers[ev.getContent().msgtype](ev);
+ }
return TextForEvent.textForEvent(ev);
},
@@ -69,7 +84,9 @@ const Notifier = {
title = room.name;
// notificationMessageForEvent includes sender,
// but we already have the sender here
- if (ev.getContent().body) msg = ev.getContent().body;
+ if (ev.getContent().body && !typehandlers.hasOwnProperty(ev.getContent().msgtype)) {
+ msg = ev.getContent().body;
+ }
} else if (ev.getType() === 'm.room.member') {
// context is all in the message here, we don't need
// to display sender info
@@ -78,7 +95,9 @@ const Notifier = {
title = ev.sender.name + " (" + room.name + ")";
// notificationMessageForEvent includes sender,
// but we've just out sender in the title
- if (ev.getContent().body) msg = ev.getContent().body;
+ if (ev.getContent().body && !typehandlers.hasOwnProperty(ev.getContent().msgtype)) {
+ msg = ev.getContent().body;
+ }
}
if (!this.isBodyEnabled()) {
diff --git a/src/ScalarMessaging.js b/src/ScalarMessaging.js
index 2211e513c3..ca8ca103e1 100644
--- a/src/ScalarMessaging.js
+++ b/src/ScalarMessaging.js
@@ -172,6 +172,7 @@ Request:
Response:
[
{
+ // TODO: Enable support for m.widget event type (https://github.com/vector-im/riot-web/issues/13111)
type: "im.vector.modular.widgets",
state_key: "wid1",
content: {
@@ -190,6 +191,7 @@ Example:
room_id: "!foo:bar",
response: [
{
+ // TODO: Enable support for m.widget event type (https://github.com/vector-im/riot-web/issues/13111)
type: "im.vector.modular.widgets",
state_key: "wid1",
content: {
diff --git a/src/SlashCommands.tsx b/src/SlashCommands.tsx
index d60434cf97..71815dde8c 100644
--- a/src/SlashCommands.tsx
+++ b/src/SlashCommands.tsx
@@ -350,7 +350,7 @@ export const Commands = [
return success(cli.setRoomTopic(roomId, args));
}
const room = cli.getRoom(roomId);
- if (!room) return reject('Bad room ID: ' + roomId);
+ if (!room) return reject(_t("Failed to set topic"));
const topicEvents = room.currentState.getStateEvents('m.room.topic', '');
const topic = topicEvents && topicEvents.getContent().topic;
@@ -721,9 +721,10 @@ export const Commands = [
if (!isNaN(powerLevel)) {
const cli = MatrixClientPeg.get();
const room = cli.getRoom(roomId);
- if (!room) return reject('Bad room ID: ' + roomId);
+ if (!room) return reject(_t("Command failed"));
const powerLevelEvent = room.currentState.getStateEvents('m.room.power_levels', '');
+ if (!powerLevelEvent.getContent().users[args]) return reject(_t("Could not find user in room"));
return success(cli.setPowerLevel(roomId, userId, powerLevel, powerLevelEvent));
}
}
@@ -742,9 +743,10 @@ export const Commands = [
if (matches) {
const cli = MatrixClientPeg.get();
const room = cli.getRoom(roomId);
- if (!room) return reject('Bad room ID: ' + roomId);
+ if (!room) return reject(_t("Command failed"));
const powerLevelEvent = room.currentState.getStateEvents('m.room.power_levels', '');
+ if (!powerLevelEvent.getContent().users[args]) return reject(_t("Could not find user in room"));
return success(cli.setPowerLevel(roomId, args, undefined, powerLevelEvent));
}
}
@@ -914,7 +916,7 @@ export const Commands = [
// Command definitions for autocompletion ONLY:
// /me is special because its not handled by SlashCommands.js and is instead done inside the Composer classes
new Command({
- command: 'me',
+ command: "me",
args: '
{_t( "We'll store an encrypted copy of your keys on our server. " + - "Protect your backup with a passphrase to keep it secure.", + "Secure your backup with a recovery passphrase.", )}
{_t("For maximum security, this should be different from your account password.")}
@@ -307,7 +297,7 @@ export default class CreateKeyBackupDialog extends React.PureComponent { onChange={this._onPassPhraseChange} value={this.state.passPhrase} className="mx_CreateKeyBackupDialog_passPhraseInput" - placeholder={_t("Enter a passphrase...")} + placeholder={_t("Enter a recovery passphrase...")} autoFocus={true} />