diff --git a/.eslintignore.errorfiles b/.eslintignore.errorfiles index ffc3b21181..db12611ade 100644 --- a/.eslintignore.errorfiles +++ b/.eslintignore.errorfiles @@ -14,9 +14,7 @@ src/components/views/elements/AddressSelector.js src/components/views/elements/DirectorySearchBox.js src/components/views/elements/MemberEventListSummary.js src/components/views/elements/UserSelector.js -src/components/views/globals/MatrixToolbar.js src/components/views/globals/NewVersionBar.js -src/components/views/globals/UpdateCheckBar.js src/components/views/messages/MFileBody.js src/components/views/messages/TextualBody.js src/components/views/room_settings/ColorSettings.js diff --git a/code_style.md b/code_style.md index 01c1f37146..fe04d2cc3d 100644 --- a/code_style.md +++ b/code_style.md @@ -4,7 +4,7 @@ Matrix JavaScript/ECMAScript Style Guide The intention of this guide is to make Matrix's JavaScript codebase clean, consistent with other popular JavaScript styles and consistent with the rest of the Matrix codebase. For reference, the Matrix Python style guide can be found -at https://github.com/matrix-org/synapse/blob/master/docs/code_style.rst +at https://github.com/matrix-org/synapse/blob/master/docs/code_style.md This document reflects how we would like Matrix JavaScript code to look, with acknowledgement that a significant amount of code is written to older @@ -17,7 +17,7 @@ writing in modern ECMAScript and using a transpile step to generate the file that applications can then include. There are significant benefits in being able to use modern ECMAScript, although the tooling for doing so can be awkward for library code, especially with regard to translating source maps and line -number throgh from the original code to the final application. +number through from the original code to the final application. General Style ------------- diff --git a/res/css/_common.scss b/res/css/_common.scss index 03442ca510..ebeeb381e6 100644 --- a/res/css/_common.scss +++ b/res/css/_common.scss @@ -335,6 +335,9 @@ input[type=text]:focus, input[type=password]:focus, textarea:focus { .mx_Dialog_header.mx_Dialog_headerWithButton > .mx_Dialog_title { text-align: center; } +.mx_Dialog_header.mx_Dialog_headerWithCancel > .mx_Dialog_title { + margin-right: 20px; // leave space for the 'X' cancel button +} .mx_Dialog_title.danger { color: $warning-color; diff --git a/res/css/_components.scss b/res/css/_components.scss index 44c63b9df7..eefe0f009b 100644 --- a/res/css/_components.scss +++ b/res/css/_components.scss @@ -116,6 +116,7 @@ @import "./views/elements/_RoomAliasField.scss"; @import "./views/elements/_Slider.scss"; @import "./views/elements/_Spinner.scss"; +@import "./views/elements/_StyledCheckbox.scss"; @import "./views/elements/_SyntaxHighlight.scss"; @import "./views/elements/_TextWithTooltip.scss"; @import "./views/elements/_ToggleSwitch.scss"; @@ -123,7 +124,6 @@ @import "./views/elements/_TooltipButton.scss"; @import "./views/elements/_Validation.scss"; @import "./views/emojipicker/_EmojiPicker.scss"; -@import "./views/globals/_MatrixToolbar.scss"; @import "./views/groups/_GroupPublicityToggle.scss"; @import "./views/groups/_GroupRoomList.scss"; @import "./views/groups/_GroupUserSettings.scss"; @@ -202,6 +202,7 @@ @import "./views/settings/_ProfileSettings.scss"; @import "./views/settings/_SetIdServer.scss"; @import "./views/settings/_SetIntegrationManager.scss"; +@import "./views/settings/_UpdateCheckButton.scss"; @import "./views/settings/tabs/_SettingsTab.scss"; @import "./views/settings/tabs/room/_GeneralRoomSettingsTab.scss"; @import "./views/settings/tabs/room/_RolesRoomSettingsTab.scss"; diff --git a/res/css/_font-sizes.scss b/res/css/_font-sizes.scss index 76a9b16425..2d7ab67e40 100644 --- a/res/css/_font-sizes.scss +++ b/res/css/_font-sizes.scss @@ -15,6 +15,7 @@ limitations under the License. */ $font-1px: 0.067rem; +$font-1-5px: 0.100rem; $font-2px: 0.133rem; $font-3px: 0.200rem; $font-4px: 0.267rem; diff --git a/res/css/structures/_MatrixChat.scss b/res/css/structures/_MatrixChat.scss index c5a5d50068..05c703ab6d 100644 --- a/res/css/structures/_MatrixChat.scss +++ b/res/css/structures/_MatrixChat.scss @@ -41,10 +41,6 @@ limitations under the License. height: 40px; } -.mx_MatrixChat_toolbarShowing { - height: auto; -} - .mx_MatrixChat { width: 100%; height: 100%; diff --git a/res/css/structures/_NotificationPanel.scss b/res/css/structures/_NotificationPanel.scss index 44205b1f01..561ab1446f 100644 --- a/res/css/structures/_NotificationPanel.scss +++ b/res/css/structures/_NotificationPanel.scss @@ -63,6 +63,10 @@ limitations under the License. padding-left: 32px; padding-top: 8px; position: relative; + + a { + display: flex; + } } .mx_NotificationPanel .mx_EventTile_roomName a, diff --git a/res/css/views/dialogs/_GroupAddressPicker.scss b/res/css/views/dialogs/_GroupAddressPicker.scss index 20a7cc1047..5fa18931f0 100644 --- a/res/css/views/dialogs/_GroupAddressPicker.scss +++ b/res/css/views/dialogs/_GroupAddressPicker.scss @@ -18,8 +18,3 @@ limitations under the License. margin-top: 10px; display: flex; } - -.mx_GroupAddressPicker_checkboxContainer input[type="checkbox"] { - /* Stop flex from shrinking the checkbox */ - width: 20px; -} diff --git a/res/css/views/elements/_StyledCheckbox.scss b/res/css/views/elements/_StyledCheckbox.scss new file mode 100644 index 0000000000..14081f1e99 --- /dev/null +++ b/res/css/views/elements/_StyledCheckbox.scss @@ -0,0 +1,66 @@ +/* +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_Checkbox { + $size: $font-16px; + $border-size: $font-1-5px; + $border-radius: $font-4px; + + display: flex; + align-items: flex-start; + + input[type=checkbox] { + display: none; + + & + label { + display: flex; + align-items: center; + + flex-grow: 1; + } + + & + label > .mx_Checkbox_background { + display: inline-flex; + position: relative; + + flex-shrink: 0; + + height: $size; + width: $size; + size: 0.5rem; + + border: $border-size solid rgba($muted-fg-color, 0.5); + box-sizing: border-box; + border-radius: $border-radius; + + img { + height: 100%; + width: 100%; + filter: invert(100%); + } + } + + &:checked + label > .mx_Checkbox_background { + background: $accent-color; + border-color: $accent-color; + } + + & + label > *:not(.mx_Checkbox_background) { + margin-left: 10px; + } + } +} diff --git a/res/css/views/globals/_MatrixToolbar.scss b/res/css/views/globals/_MatrixToolbar.scss deleted file mode 100644 index 07b92a7235..0000000000 --- a/res/css/views/globals/_MatrixToolbar.scss +++ /dev/null @@ -1,69 +0,0 @@ -/* -Copyright 2015, 2016 OpenMarket 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. -*/ - -.mx_MatrixToolbar { - background-color: $accent-color; - color: $accent-fg-color; - - display: flex; - align-items: center; -} - -.mx_MatrixToolbar_warning { - margin-left: 16px; - margin-right: 8px; - margin-top: -2px; -} - -.mx_MatrixToolbar_info { - padding-left: 16px; - padding-right: 8px; - background-color: $info-bg-color; -} - -.mx_MatrixToolbar_error { - padding-left: 16px; - padding-right: 8px; - background-color: $warning-bg-color; -} - -.mx_MatrixToolbar_content { - flex: 1; -} - -.mx_MatrixToolbar_link { - color: $accent-fg-color !important; - text-decoration: underline !important; - cursor: pointer; -} - -.mx_MatrixToolbar_clickable { - cursor: pointer; -} - -.mx_MatrixToolbar_close { - cursor: pointer; -} - -.mx_MatrixToolbar_close img { - display: block; - float: right; - margin-right: 10px; -} - -.mx_MatrixToolbar_action { - margin-right: 16px; -} diff --git a/res/css/views/rooms/_AppsDrawer.scss b/res/css/views/rooms/_AppsDrawer.scss index e4743f189e..1b1bab67bc 100644 --- a/res/css/views/rooms/_AppsDrawer.scss +++ b/res/css/views/rooms/_AppsDrawer.scss @@ -96,10 +96,6 @@ $AppsDrawerBodyHeight: 273px; height: $AppsDrawerBodyHeight; } -.mx_AppTile_persistedWrapper > div { - height: 100%; -} - .mx_AppTile_mini .mx_AppTile_persistedWrapper { height: 114px; } diff --git a/res/css/views/rooms/_GroupLayout.scss b/res/css/views/rooms/_GroupLayout.scss index 928ea75a79..af12cce5d6 100644 --- a/res/css/views/rooms/_GroupLayout.scss +++ b/res/css/views/rooms/_GroupLayout.scss @@ -53,79 +53,79 @@ $left-gutter: 65px; /* Compact layout overrides */ .mx_MatrixChat_useCompactLayout { - .mx_EventTile { - padding-top: 4px; - } - - .mx_EventTile.mx_EventTile_info { - // same as the padding for non-compact .mx_EventTile.mx_EventTile_info - padding-top: 0px; - font-size: $font-13px; - .mx_EventTile_line, .mx_EventTile_reply { - line-height: $font-20px; - } - .mx_EventTile_avatar { - top: 4px; - } - } - - .mx_EventTile .mx_SenderProfile { - font-size: $font-13px; - } - - .mx_EventTile.mx_EventTile_emote { - // add a bit more space for emotes so that avatars don't collide - padding-top: 8px; - .mx_EventTile_avatar { - top: 2px; - } - .mx_EventTile_line, .mx_EventTile_reply { - padding-top: 0px; - padding-bottom: 1px; - } - } - - .mx_EventTile.mx_EventTile_emote.mx_EventTile_continuation { - padding-top: 0; - .mx_EventTile_line, .mx_EventTile_reply { - padding-top: 0px; - padding-bottom: 0px; - } - } - .mx_EventTile_line, .mx_EventTile_reply { padding-top: 0px; padding-bottom: 0px; } - .mx_EventTile_avatar { - top: 2px; - } + .mx_EventTile { + padding-top: 4px; - .mx_EventTile_e2eIcon { - top: 3px; - } + &.mx_EventTile_info { + // same as the padding for non-compact .mx_EventTile.mx_EventTile_info + padding-top: 0px; + font-size: $font-13px; + .mx_EventTile_line, .mx_EventTile_reply { + line-height: $font-20px; + } + .mx_EventTile_avatar { + top: 4px; + } + } - .mx_EventTile_readAvatars { - top: 27px; - } + .mx_SenderProfile { + font-size: $font-13px; + } - .mx_EventTile_continuation .mx_EventTile_readAvatars, - .mx_EventTile_emote .mx_EventTile_readAvatars { - top: 5px; - } + &.mx_EventTile_emote { + // add a bit more space for emotes so that avatars don't collide + padding-top: 8px; + .mx_EventTile_avatar { + top: 2px; + } + .mx_EventTile_line, .mx_EventTile_reply { + padding-top: 0px; + padding-bottom: 1px; + } + } - .mx_EventTile_info .mx_EventTile_readAvatars { - top: 4px; + &.mx_EventTile_emote.mx_EventTile_continuation { + padding-top: 0; + .mx_EventTile_line, .mx_EventTile_reply { + padding-top: 0px; + padding-bottom: 0px; + } + } + + .mx_EventTile_avatar { + top: 2px; + } + + .mx_EventTile_e2eIcon { + top: 3px; + } + + .mx_EventTile_readAvatars { + top: 27px; + } + + .mx_EventTile_continuation .mx_EventTile_readAvatars, + .mx_EventTile_emote .mx_EventTile_readAvatars { + top: 5px; + } + + .mx_EventTile_info .mx_EventTile_readAvatars { + top: 4px; + } + + .mx_EventTile_content .markdown-body { + p, ul, ol, dl, blockquote, pre, table { + margin-bottom: 4px; // 1/4 of the non-compact margin-bottom + } + } } .mx_RoomView_MessageList h2 { margin-top: 6px; } - - .mx_EventTile_content .markdown-body { - p, ul, ol, dl, blockquote, pre, table { - margin-bottom: 4px; // 1/4 of the non-compact margin-bottom - } - } } diff --git a/res/css/views/settings/_UpdateCheckButton.scss b/res/css/views/settings/_UpdateCheckButton.scss new file mode 100644 index 0000000000..f35a023ac1 --- /dev/null +++ b/res/css/views/settings/_UpdateCheckButton.scss @@ -0,0 +1,23 @@ +/* +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_UpdateCheckButton_summary { + margin-left: 16px; + + .mx_AccessibleButton_kind_link { + padding: 0; + } +} diff --git a/src/@types/common.ts b/src/@types/common.ts new file mode 100644 index 0000000000..26e5317aa3 --- /dev/null +++ b/src/@types/common.ts @@ -0,0 +1,19 @@ +/* +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. +*/ + +// Based on https://stackoverflow.com/a/53229857/3532235 +export type Without = {[P in Exclude] ? : never} +export type XOR = (T | U) extends object ? (Without & U) | (Without & T) : T | U; diff --git a/src/BasePlatform.ts b/src/BasePlatform.ts index ed04c67803..c5f58f7f0c 100644 --- a/src/BasePlatform.ts +++ b/src/BasePlatform.ts @@ -21,6 +21,19 @@ import {MatrixClient} from "matrix-js-sdk/src/client"; import dis from './dispatcher/dispatcher'; import BaseEventIndexManager from './indexing/BaseEventIndexManager'; import {ActionPayload} from "./dispatcher/payloads"; +import {CheckUpdatesPayload} from "./dispatcher/payloads/CheckUpdatesPayload"; +import {Action} from "./dispatcher/actions"; +import {hideToast as hideUpdateToast} from "./toasts/UpdateToast"; + +export enum UpdateCheckStatus { + Checking = "CHECKING", + Error = "ERROR", + NotAvailable = "NOTAVAILABLE", + Downloading = "DOWNLOADING", + Ready = "READY", +} + +const UPDATE_DEFER_KEY = "mx_defer_update"; /** * Base class for classes that provide platform-specific functionality @@ -56,6 +69,53 @@ export default abstract class BasePlatform { this.errorDidOccur = errorDidOccur; } + /** + * Whether we can call checkForUpdate on this platform build + */ + async canSelfUpdate(): Promise { + return false; + } + + startUpdateCheck() { + hideUpdateToast(); + localStorage.removeItem(UPDATE_DEFER_KEY); + dis.dispatch({ + action: Action.CheckUpdates, + status: UpdateCheckStatus.Checking, + }); + } + + /** + * Update the currently running app to the latest available version + * and replace this instance of the app with the new version. + */ + installUpdate() { + } + + /** + * Check if the version update has been deferred and that deferment is still in effect + * @param newVersion the version string to check + */ + protected shouldShowUpdate(newVersion: string): boolean { + try { + const [version, deferUntil] = JSON.parse(localStorage.getItem(UPDATE_DEFER_KEY)); + return newVersion !== version || Date.now() > deferUntil; + } catch (e) { + return true; + } + } + + /** + * Ignore the pending update and don't prompt about this version + * until the next morning (8am). + */ + deferUpdate(newVersion: string) { + const date = new Date(Date.now() + 24 * 60 * 60 * 1000); + date.setHours(8, 0, 0, 0); // set to next 8am + localStorage.setItem(UPDATE_DEFER_KEY, JSON.stringify([newVersion, date.getTime()])); + hideUpdateToast(); + } + /** * Returns true if the platform supports displaying * notifications, otherwise false. diff --git a/src/ContentMessages.tsx b/src/ContentMessages.tsx index bf9435914c..249ad8381c 100644 --- a/src/ContentMessages.tsx +++ b/src/ContentMessages.tsx @@ -27,6 +27,7 @@ import Modal from './Modal'; import RoomViewStore from './stores/RoomViewStore'; import encrypt from "browser-encrypt-attachment"; import extractPngChunks from "png-chunks-extract"; +import Spinner from "./components/views/elements/Spinner"; // Polyfill for Canvas.toBlob API using Canvas.toDataURL import "blueimp-canvas-to-blob"; @@ -399,7 +400,11 @@ export default class ContentMessages { if (!shouldUpload) return; } - await this.ensureMediaConfigFetched(); + if (!this.mediaConfig) { // hot-path optimization to not flash a spinner if we don't need to + const modal = Modal.createDialog(Spinner, null, 'mx_Dialog_spinner'); + await this.ensureMediaConfigFetched(); + modal.close(); + } const tooBigFiles = []; const okFiles = []; diff --git a/src/GroupAddressPicker.js b/src/GroupAddressPicker.js index 2928137f9d..e7ae3217bb 100644 --- a/src/GroupAddressPicker.js +++ b/src/GroupAddressPicker.js @@ -22,6 +22,7 @@ import { _t } from './languageHandler'; import {MatrixClientPeg} from './MatrixClientPeg'; import GroupStore from './stores/GroupStore'; import {allSettled} from "./utils/promise"; +import StyledCheckbox from './components/views/elements/StyledCheckbox'; export function showGroupInviteDialog(groupId) { return new Promise((resolve, reject) => { @@ -61,12 +62,12 @@ export function showGroupAddRoomDialog(groupId) {
{ _t("Which rooms would you like to add to this community?") }
; - const checkboxContainer = ; + const checkboxContainer = + { _t("Show these rooms to non-members on the community page and room list?") } + ; const AddressPickerDialog = sdk.getComponent("dialogs.AddressPickerDialog"); Modal.createTrackedDialog('Add Rooms to Group', '', AddressPickerDialog, { diff --git a/src/PasswordReset.js b/src/PasswordReset.js index 320599f6d9..9472ddc633 100644 --- a/src/PasswordReset.js +++ b/src/PasswordReset.js @@ -84,8 +84,14 @@ export default class PasswordReset { try { await this.client.setPassword({ + // Note: Though this sounds like a login type for identity servers only, it + // has a dual purpose of being used for homeservers too. type: "m.login.email.identity", + // TODO: Remove `threepid_creds` once servers support proper UIA + // See https://github.com/matrix-org/synapse/issues/5665 + // See https://github.com/matrix-org/matrix-doc/issues/2220 threepid_creds: creds, + threepidCreds: creds, }, this.password); } catch (err) { if (err.httpStatus === 401) { diff --git a/src/async-components/views/dialogs/secretstorage/CreateSecretStorageDialog.js b/src/async-components/views/dialogs/secretstorage/CreateSecretStorageDialog.js index e6ab07c449..d7b79c2cfa 100644 --- a/src/async-components/views/dialogs/secretstorage/CreateSecretStorageDialog.js +++ b/src/async-components/views/dialogs/secretstorage/CreateSecretStorageDialog.js @@ -201,7 +201,8 @@ export default class CreateSecretStorageDialog extends React.PureComponent { type: 'm.id.user', user: MatrixClientPeg.get().getUserId(), }, - // https://github.com/matrix-org/synapse/issues/5665 + // TODO: Remove `user` once servers support proper UIA + // See https://github.com/matrix-org/synapse/issues/5665 user: MatrixClientPeg.get().getUserId(), password: this.state.accountPassword, }); diff --git a/src/components/structures/LoggedInView.tsx b/src/components/structures/LoggedInView.tsx index 06ba3e49c9..1ad38c6f04 100644 --- a/src/components/structures/LoggedInView.tsx +++ b/src/components/structures/LoggedInView.tsx @@ -81,7 +81,6 @@ interface IProps { currentRoomId: string; ConferenceHandler?: object; collapseLhs: boolean; - checkingForUpdate: boolean; config: { piwik: { policyUrl: string; @@ -177,15 +176,6 @@ class LoggedInView extends React.PureComponent { this._loadResizerPreferences(); } - componentDidUpdate(prevProps, prevState) { - // attempt to guess when a banner was opened or closed - if ( - (prevProps.checkingForUpdate !== this.props.checkingForUpdate) - ) { - this.props.resizeNotifier.notifyBannersChanged(); - } - } - componentWillUnmount() { document.removeEventListener('keydown', this._onNativeKeyDown, false); this._matrixClient.removeListener("accountData", this.onAccountData); @@ -617,7 +607,6 @@ class LoggedInView extends React.PureComponent { const GroupView = sdk.getComponent('structures.GroupView'); const MyGroups = sdk.getComponent('structures.MyGroups'); const ToastContainer = sdk.getComponent('structures.ToastContainer'); - const UpdateCheckBar = sdk.getComponent('globals.UpdateCheckBar'); let pageElement; @@ -661,15 +650,7 @@ class LoggedInView extends React.PureComponent { break; } - let topBar; - if (this.props.checkingForUpdate) { - topBar = ; - } - let bodyClasses = 'mx_MatrixChat'; - if (topBar) { - bodyClasses += ' mx_MatrixChat_toolbarShowing'; - } if (this.state.useCompactLayout) { bodyClasses += ' mx_MatrixChat_useCompactLayout'; } @@ -684,7 +665,6 @@ class LoggedInView extends React.PureComponent { onMouseDown={this._onMouseDown} onMouseUp={this._onMouseUp} > - { topBar }
diff --git a/src/components/structures/MatrixChat.tsx b/src/components/structures/MatrixChat.tsx index b70d6ed3eb..058a7ba50b 100644 --- a/src/components/structures/MatrixChat.tsx +++ b/src/components/structures/MatrixChat.tsx @@ -173,7 +173,6 @@ interface IState { leftDisabled: boolean; middleDisabled: boolean; // the right panel's disabled state is tracked in its store. - checkingForUpdate?: string; // updateCheckStatusEnum // Parameters used in the registration dance with the IS register_client_secret?: string; register_session_id?: string; @@ -226,8 +225,6 @@ export default class MatrixChat extends React.PureComponent { leftDisabled: false, middleDisabled: false, - checkingForUpdate: null, - hideToSRUsers: false, syncError: null, // If the current syncing status is ERROR, the error object, otherwise null. @@ -720,9 +717,6 @@ export default class MatrixChat extends React.PureComponent { case 'client_started': this.onClientStarted(); break; - case 'check_updates': - this.setState({ checkingForUpdate: payload.value }); - break; case 'send_event': this.onSendEvent(payload.room_id, payload.event); break; diff --git a/src/components/structures/MessagePanel.js b/src/components/structures/MessagePanel.js index 93e4668f66..2069255ea2 100644 --- a/src/components/structures/MessagePanel.js +++ b/src/components/structures/MessagePanel.js @@ -108,6 +108,9 @@ export default class MessagePanel extends React.Component { // whether to show reactions for an event showReactions: PropTypes.bool, + + // whether to use the irc layout + useIRCLayout: PropTypes.bool, }; // Force props to be loaded for useIRCLayout @@ -119,7 +122,6 @@ export default class MessagePanel extends React.Component { // display 'ghost' read markers that are animating away ghostReadMarkers: [], showTypingNotifications: SettingsStore.getValue("showTypingNotifications"), - useIRCLayout: this.useIRCLayout(SettingsStore.getValue("feature_irc_ui")), }; // opaque readreceipt info for each userId; used by ReadReceiptMarker @@ -172,8 +174,6 @@ export default class MessagePanel extends React.Component { this._showTypingNotificationsWatcherRef = SettingsStore.watchSetting("showTypingNotifications", null, this.onShowTypingNotificationsChange); - - this._layoutWatcherRef = SettingsStore.watchSetting("feature_irc_ui", null, this.onLayoutChange); } componentDidMount() { @@ -183,7 +183,6 @@ export default class MessagePanel extends React.Component { componentWillUnmount() { this._isMounted = false; SettingsStore.unwatchSetting(this._showTypingNotificationsWatcherRef); - SettingsStore.unwatchSetting(this._layoutWatcherRef); } componentDidUpdate(prevProps, prevState) { @@ -202,17 +201,6 @@ export default class MessagePanel extends React.Component { }); }; - onLayoutChange = () => { - this.setState({ - useIRCLayout: this.useIRCLayout(SettingsStore.getValue("feature_irc_ui")), - }); - } - - useIRCLayout(ircLayoutSelected) { - // if room is null we are not in a normal room list - return ircLayoutSelected && this.props.room; - } - /* get the DOM node representing the given event */ getNodeForEventId(eventId) { if (!this.eventNodes) { @@ -614,7 +602,7 @@ export default class MessagePanel extends React.Component { isSelectedEvent={highlight} getRelationsForEvent={this.props.getRelationsForEvent} showReactions={this.props.showReactions} - useIRCLayout={this.state.useIRCLayout} + useIRCLayout={this.props.useIRCLayout} /> , @@ -797,8 +785,6 @@ export default class MessagePanel extends React.Component { this.props.className, { "mx_MessagePanel_alwaysShowTimestamps": this.props.alwaysShowTimestamps, - "mx_IRCLayout": this.state.useIRCLayout, - "mx_GroupLayout": !this.state.useIRCLayout, }, ); @@ -813,11 +799,11 @@ export default class MessagePanel extends React.Component { } let ircResizer = null; - if (this.state.useIRCLayout) { + if (this.props.useIRCLayout) { ircResizer = ; } diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index 39cd497098..c87f4cc4dd 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -165,6 +165,8 @@ export default createReactClass({ canReact: false, canReply: false, + useIRCLayout: SettingsStore.getValue("feature_irc_ui"), + matrixClientIsReady: this.context && this.context.isInitialSyncComplete(), }; }, @@ -195,6 +197,8 @@ export default createReactClass({ this._roomView = createRef(); this._searchResultsPanel = createRef(); + + this._layoutWatcherRef = SettingsStore.watchSetting("feature_irc_ui", null, this.onLayoutChange); }, _onReadReceiptsChange: function() { @@ -535,6 +539,14 @@ export default createReactClass({ // no need to do this as Dir & Settings are now overlays. It just burnt CPU. // console.log("Tinter.tint from RoomView.unmount"); // Tinter.tint(); // reset colourscheme + + SettingsStore.unwatchSetting(this._layoutWatcherRef); + }, + + onLayoutChange: function() { + this.setState({ + useIRCLayout: SettingsStore.getValue("feature_irc_ui"), + }); }, _onRightPanelStoreUpdate: function() { @@ -1996,6 +2008,13 @@ export default createReactClass({ highlightedEventId = this.state.initialEventId; } + const messagePanelClassNames = classNames( + "mx_RoomView_messagePanel", + { + "mx_IRCLayout": this.state.useIRCLayout, + "mx_GroupLayout": !this.state.useIRCLayout, + }); + // console.info("ShowUrlPreview for %s is %s", this.state.room.roomId, this.state.showUrlPreview); const messagePanel = ( ); let topUnreadMessagesBar = null; diff --git a/src/components/structures/TagPanelButtons.js b/src/components/structures/TagPanelButtons.js deleted file mode 100644 index 4b00da3cbf..0000000000 --- a/src/components/structures/TagPanelButtons.js +++ /dev/null @@ -1,59 +0,0 @@ -/* -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 createReactClass from 'create-react-class'; -import * as sdk from '../../index'; -import dis from '../../dispatcher/dispatcher'; -import Modal from '../../Modal'; -import { _t } from '../../languageHandler'; - -const TagPanelButtons = createReactClass({ - displayName: 'TagPanelButtons', - - - componentDidMount: function() { - this._dispatcherRef = dis.register(this._onAction); - }, - - componentWillUnmount() { - if (this._dispatcherRef) { - dis.unregister(this._dispatcherRef); - this._dispatcherRef = null; - } - }, - - _onAction(payload) { - if (payload.action === "show_redesign_feedback_dialog") { - const RedesignFeedbackDialog = - sdk.getComponent("views.dialogs.RedesignFeedbackDialog"); - Modal.createTrackedDialog('Report bugs & give feedback', '', RedesignFeedbackDialog); - } - }, - - render() { - const GroupsButton = sdk.getComponent('elements.GroupsButton'); - const ActionButton = sdk.getComponent("elements.ActionButton"); - - return (
- - -
); - }, -}); -export default TagPanelButtons; diff --git a/src/components/structures/TimelinePanel.js b/src/components/structures/TimelinePanel.js index da1369c45f..95dc42fcee 100644 --- a/src/components/structures/TimelinePanel.js +++ b/src/components/structures/TimelinePanel.js @@ -112,6 +112,9 @@ const TimelinePanel = createReactClass({ // whether to show reactions for an event showReactions: PropTypes.bool, + + // whether to use the irc layout + useIRCLayout: PropTypes.bool, }, statics: { @@ -1447,6 +1450,7 @@ const TimelinePanel = createReactClass({ getRelationsForEvent={this.getRelationsForEvent} editState={this.state.editState} showReactions={this.props.showReactions} + useIRCLayout={this.props.useIRCLayout} /> ); }, diff --git a/src/components/structures/auth/Registration.js b/src/components/structures/auth/Registration.js index 7be88f9d44..6349614d72 100644 --- a/src/components/structures/auth/Registration.js +++ b/src/components/structures/auth/Registration.js @@ -247,9 +247,8 @@ export default createReactClass({ // do SSO instead. If we've already started the UI Auth process though, we don't // need to. if (!this.state.doingUIAuth) { - await this._makeRegisterRequest({}); - // This should never succeed since we specified an empty - // auth object. + await this._makeRegisterRequest(null); + // This should never succeed since we specified no auth object. console.log("Expecting 401 from register request but got success!"); } } catch (e) { diff --git a/src/components/views/auth/InteractiveAuthEntryComponents.js b/src/components/views/auth/InteractiveAuthEntryComponents.js index 655452fcee..f6bc1b8ae7 100644 --- a/src/components/views/auth/InteractiveAuthEntryComponents.js +++ b/src/components/views/auth/InteractiveAuthEntryComponents.js @@ -355,6 +355,7 @@ export const TermsAuthEntry = createReactClass({ allChecked = allChecked && checked; checkboxes.push( + // XXX: replace with StyledCheckbox