From 6ea5dc7b7c550a9edd2c79735c8bba8883841a4e Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Fri, 24 Apr 2020 22:14:41 +0100 Subject: [PATCH 1/7] Change the look of the spinner --- res/css/_common.scss | 4 ++ res/css/views/elements/_InlineSpinner.scss | 8 ++++ res/css/views/elements/_Spinner.scss | 10 +++++ res/img/spinner.svg | 3 ++ src/components/structures/MessagePanel.js | 2 +- src/components/views/elements/AppTile.js | 4 +- .../views/elements/InlineSpinner.js | 10 ++++- .../views/elements/MessageSpinner.js | 35 ----------------- src/components/views/elements/Spinner.js | 38 ++++++++++++------- src/components/views/messages/MAudioBody.js | 3 +- src/components/views/messages/MImageBody.js | 8 +--- src/components/views/messages/MVideoBody.js | 3 +- 12 files changed, 67 insertions(+), 61 deletions(-) create mode 100644 res/img/spinner.svg delete mode 100644 src/components/views/elements/MessageSpinner.js diff --git a/res/css/_common.scss b/res/css/_common.scss index cf48358a4e..c087df04cb 100644 --- a/res/css/_common.scss +++ b/res/css/_common.scss @@ -428,6 +428,10 @@ input[type=text]:focus, input[type=password]:focus, textarea:focus { border-radius: 8px; padding: 0px; box-shadow: none; + + /* Don't show scroll-bars on spinner dialogs */ + overflow-x: hidden; + overflow-y: hidden; } // TODO: Review mx_GeneralButton usage to see if it can use a different class diff --git a/res/css/views/elements/_InlineSpinner.scss b/res/css/views/elements/_InlineSpinner.scss index 612b6209c6..561b6cfb82 100644 --- a/res/css/views/elements/_InlineSpinner.scss +++ b/res/css/views/elements/_InlineSpinner.scss @@ -21,4 +21,12 @@ limitations under the License. .mx_InlineSpinner img { margin: 0px 6px; vertical-align: -3px; + + animation: spin 1s linear infinite; +} + +@keyframes spin { + 100% { + transform: rotate(360deg); + } } diff --git a/res/css/views/elements/_Spinner.scss b/res/css/views/elements/_Spinner.scss index 01b4f23c2c..db9f54b56c 100644 --- a/res/css/views/elements/_Spinner.scss +++ b/res/css/views/elements/_Spinner.scss @@ -23,6 +23,16 @@ limitations under the License. flex: 1; } +.mx_Spinner img { + animation: spin 1s linear infinite; +} + +@keyframes spin { + 100% { + transform: rotate(360deg); + } +} + .mx_MatrixChat_middlePanel .mx_Spinner { height: auto; } diff --git a/res/img/spinner.svg b/res/img/spinner.svg new file mode 100644 index 0000000000..a18140c7e2 --- /dev/null +++ b/res/img/spinner.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/components/structures/MessagePanel.js b/src/components/structures/MessagePanel.js index d11fee6360..481741dfd2 100644 --- a/src/components/structures/MessagePanel.js +++ b/src/components/structures/MessagePanel.js @@ -770,7 +770,7 @@ export default class MessagePanel extends React.Component { topSpinner =
  • ; } if (this.props.forwardPaginating) { - bottomSpinner =
  • ; + bottomSpinner =
  • ; } const style = this.props.hidden ? { display: 'none' } : {}; diff --git a/src/components/views/elements/AppTile.js b/src/components/views/elements/AppTile.js index 9129b8fe48..60cd1a2eba 100644 --- a/src/components/views/elements/AppTile.js +++ b/src/components/views/elements/AppTile.js @@ -29,7 +29,7 @@ import { _t } from '../../../languageHandler'; import * as sdk from '../../../index'; import AppPermission from './AppPermission'; import AppWarning from './AppWarning'; -import MessageSpinner from './MessageSpinner'; +import Spinner from './Spinner'; import WidgetUtils from '../../../utils/WidgetUtils'; import dis from '../../../dispatcher/dispatcher'; import ActiveWidgetStore from '../../../stores/ActiveWidgetStore'; @@ -740,7 +740,7 @@ export default class AppTile extends React.Component { if (this.props.show) { const loadingElement = (
    - +
    ); if (!this.state.hasPermissionToLoad) { diff --git a/src/components/views/elements/InlineSpinner.js b/src/components/views/elements/InlineSpinner.js index ad70471d89..4842cba0c6 100644 --- a/src/components/views/elements/InlineSpinner.js +++ b/src/components/views/elements/InlineSpinner.js @@ -16,6 +16,7 @@ limitations under the License. import React from "react"; import createReactClass from 'create-react-class'; +import {_t} from "../../../languageHandler"; export default createReactClass({ displayName: 'InlineSpinner', @@ -24,10 +25,17 @@ export default createReactClass({ const w = this.props.w || 16; const h = this.props.h || 16; const imgClass = this.props.imgClassName || ""; + const alt = this.props.alt || _t("Loading..."); return (
    - + {alt}
    ); }, diff --git a/src/components/views/elements/MessageSpinner.js b/src/components/views/elements/MessageSpinner.js deleted file mode 100644 index 1775fdd4d7..0000000000 --- a/src/components/views/elements/MessageSpinner.js +++ /dev/null @@ -1,35 +0,0 @@ -/* -Copyright 2017 Vector Creations Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -import React from 'react'; -import createReactClass from 'create-react-class'; - -export default createReactClass({ - displayName: 'MessageSpinner', - - render: function() { - const w = this.props.w || 32; - const h = this.props.h || 32; - const imgClass = this.props.imgClassName || ""; - const msg = this.props.msg || "Loading..."; - return ( -
    -
    { msg }
      - -
    - ); - }, -}); diff --git a/src/components/views/elements/Spinner.js b/src/components/views/elements/Spinner.js index b1fe97d5d2..3d5697c72e 100644 --- a/src/components/views/elements/Spinner.js +++ b/src/components/views/elements/Spinner.js @@ -16,19 +16,29 @@ limitations under the License. */ import React from "react"; -import createReactClass from 'create-react-class'; +import PropTypes from "prop-types"; +import {_t} from "../../../languageHandler"; -export default createReactClass({ - displayName: 'Spinner', +const Spinner = ({w = 32, h = 32, imgClassName, alt, message}) => { + return ( +
    + { message &&
    { message}
     
    } + {alt +
    + ); +}; +Spinner.propTypes = { + w: PropTypes.number, + h: PropTypes.number, + imgClassName: PropTypes.string, + alt: PropTypes.string, + message: PropTypes.node, +}; - render: function() { - const w = this.props.w || 32; - const h = this.props.h || 32; - const imgClass = this.props.imgClassName || ""; - return ( -
    - -
    - ); - }, -}); +export default Spinner; diff --git a/src/components/views/messages/MAudioBody.js b/src/components/views/messages/MAudioBody.js index a642936fec..421ec8fc47 100644 --- a/src/components/views/messages/MAudioBody.js +++ b/src/components/views/messages/MAudioBody.js @@ -22,6 +22,7 @@ import MFileBody from './MFileBody'; import {MatrixClientPeg} from '../../../MatrixClientPeg'; import { decryptFile } from '../../../utils/DecryptFile'; import { _t } from '../../../languageHandler'; +import InlineSpinner from '../elements/InlineSpinner'; export default class MAudioBody extends React.Component { constructor(props) { @@ -94,7 +95,7 @@ export default class MAudioBody extends React.Component { // Not sure how tall the audio player is so not sure how tall it should actually be. return ( - {content.body} + ); } diff --git a/src/components/views/messages/MImageBody.js b/src/components/views/messages/MImageBody.js index ad238a728e..4d12dcf5d7 100644 --- a/src/components/views/messages/MImageBody.js +++ b/src/components/views/messages/MImageBody.js @@ -26,6 +26,7 @@ import { decryptFile } from '../../../utils/DecryptFile'; import { _t } from '../../../languageHandler'; import SettingsStore from "../../../settings/SettingsStore"; import MatrixClientContext from "../../../contexts/MatrixClientContext"; +import InlineSpinner from '../elements/InlineSpinner'; export default class MImageBody extends React.Component { static propTypes = { @@ -365,12 +366,7 @@ export default class MImageBody extends React.Component { // e2e image hasn't been decrypted yet if (content.file !== undefined && this.state.decryptedUrl === null) { - placeholder = {content.body}; + placeholder = ; } else if (!this.state.imgLoaded) { // Deliberately, getSpinner is left unimplemented here, MStickerBody overides placeholder = this.getPlaceholder(); diff --git a/src/components/views/messages/MVideoBody.js b/src/components/views/messages/MVideoBody.js index 03f345e042..1fba9d2ead 100644 --- a/src/components/views/messages/MVideoBody.js +++ b/src/components/views/messages/MVideoBody.js @@ -23,6 +23,7 @@ import {MatrixClientPeg} from '../../../MatrixClientPeg'; import { decryptFile } from '../../../utils/DecryptFile'; import { _t } from '../../../languageHandler'; import SettingsStore from "../../../settings/SettingsStore"; +import InlineSpinner from '../elements/InlineSpinner'; export default createReactClass({ displayName: 'MVideoBody', @@ -147,7 +148,7 @@ export default createReactClass({ return (
    - {content.body} +
    ); From 87f961df3f99feb0cbcc784a65550bbdbf42c4c5 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Fri, 26 Jun 2020 00:00:30 +0100 Subject: [PATCH 2/7] Put behind a labs flag --- res/css/views/elements/_Spinner.scss | 2 +- .../views/elements/InlineSpinner.js | 15 +++++++++-- src/components/views/elements/Spinner.js | 27 +++++++++++++------ src/i18n/strings/en_EN.json | 1 + src/settings/Settings.js | 6 +++++ 5 files changed, 40 insertions(+), 11 deletions(-) diff --git a/res/css/views/elements/_Spinner.scss b/res/css/views/elements/_Spinner.scss index db9f54b56c..6966a60e52 100644 --- a/res/css/views/elements/_Spinner.scss +++ b/res/css/views/elements/_Spinner.scss @@ -23,7 +23,7 @@ limitations under the License. flex: 1; } -.mx_Spinner img { +.mx_Spinner_spin img { animation: spin 1s linear infinite; } diff --git a/src/components/views/elements/InlineSpinner.js b/src/components/views/elements/InlineSpinner.js index 4842cba0c6..dba2479d57 100644 --- a/src/components/views/elements/InlineSpinner.js +++ b/src/components/views/elements/InlineSpinner.js @@ -17,6 +17,7 @@ limitations under the License. import React from "react"; import createReactClass from 'create-react-class'; import {_t} from "../../../languageHandler"; +import SettingsStore from "../../../settings/SettingsStore"; export default createReactClass({ displayName: 'InlineSpinner', @@ -27,10 +28,20 @@ export default createReactClass({ const imgClass = this.props.imgClassName || ""; const alt = this.props.alt || _t("Loading..."); + let divClass; + let imageSource; + if (SettingsStore.isFeatureEnabled('feature_new_spinner')) { + divClass = "mx_InlineSpinner mx_Spinner_spin"; + imageSource = require("../../../../res/img/spinner.svg"); + } else { + divClass = "mx_InlineSpinner"; + imageSource = require("../../../../res/img/spinner.gif"); + } + return ( -
    +
    { + let divClass; + let imageSource; + if (SettingsStore.isFeatureEnabled('feature_new_spinner')) { + divClass = "mx_Spinner mx_Spinner_spin"; + imageSource = require("../../../../res/img/spinner.svg"); + } else { + divClass = "mx_Spinner"; + imageSource = require("../../../../res/img/spinner.gif"); + } + return ( -
    +
    { message &&
    { message}
     
    } - {alt + {alt
    ); }; diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 4970a650db..ae44d59c59 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -427,6 +427,7 @@ "Sorry, your homeserver is too old to participate in this room.": "Sorry, your homeserver is too old to participate in this room.", "Please contact your homeserver administrator.": "Please contact your homeserver administrator.", "Failed to join room": "Failed to join room", + "New spinner design": "New spinner design", "Font scaling": "Font scaling", "Message Pinning": "Message Pinning", "Custom user status messages": "Custom user status messages", diff --git a/src/settings/Settings.js b/src/settings/Settings.js index f19b827307..820329f6c6 100644 --- a/src/settings/Settings.js +++ b/src/settings/Settings.js @@ -97,6 +97,12 @@ export const SETTINGS = { // // not use this for new settings. // invertedSettingName: "my-negative-setting", // }, + "feature_new_spinner": { + isFeature: true, + displayName: _td("New spinner design"), + supportedLevels: LEVELS_FEATURE, + default: false, + }, "feature_font_scaling": { isFeature: true, displayName: _td("Font scaling"), From b00d822bc0782c07622068af8edc2672fce934e0 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Fri, 26 Jun 2020 01:18:02 +0100 Subject: [PATCH 3/7] Remove alt, use aria-label --- src/components/views/elements/InlineSpinner.js | 3 +-- src/components/views/elements/Spinner.js | 5 ++--- src/components/views/messages/MAudioBody.js | 2 +- src/components/views/messages/MImageBody.js | 2 +- src/components/views/messages/MVideoBody.js | 2 +- 5 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/components/views/elements/InlineSpinner.js b/src/components/views/elements/InlineSpinner.js index dba2479d57..ad88868790 100644 --- a/src/components/views/elements/InlineSpinner.js +++ b/src/components/views/elements/InlineSpinner.js @@ -26,7 +26,6 @@ export default createReactClass({ const w = this.props.w || 16; const h = this.props.h || 16; const imgClass = this.props.imgClassName || ""; - const alt = this.props.alt || _t("Loading..."); let divClass; let imageSource; @@ -45,7 +44,7 @@ export default createReactClass({ width={w} height={h} className={imgClass} - alt={alt} + aria-label={_t("Loading...")} />
    ); diff --git a/src/components/views/elements/Spinner.js b/src/components/views/elements/Spinner.js index c192f7d499..ee4351fed6 100644 --- a/src/components/views/elements/Spinner.js +++ b/src/components/views/elements/Spinner.js @@ -20,7 +20,7 @@ import PropTypes from "prop-types"; import {_t} from "../../../languageHandler"; import SettingsStore from "../../../settings/SettingsStore"; -const Spinner = ({w = 32, h = 32, imgClassName, alt, message}) => { +const Spinner = ({w = 32, h = 32, imgClassName, message}) => { let divClass; let imageSource; if (SettingsStore.isFeatureEnabled('feature_new_spinner')) { @@ -39,7 +39,7 @@ const Spinner = ({w = 32, h = 32, imgClassName, alt, message}) => { width={w} height={h} className={imgClassName} - alt={alt || _t("Loading...")} + aria-label={_t("Loading...")} />
    ); @@ -48,7 +48,6 @@ Spinner.propTypes = { w: PropTypes.number, h: PropTypes.number, imgClassName: PropTypes.string, - alt: PropTypes.string, message: PropTypes.node, }; diff --git a/src/components/views/messages/MAudioBody.js b/src/components/views/messages/MAudioBody.js index 421ec8fc47..37f85a108f 100644 --- a/src/components/views/messages/MAudioBody.js +++ b/src/components/views/messages/MAudioBody.js @@ -95,7 +95,7 @@ export default class MAudioBody extends React.Component { // Not sure how tall the audio player is so not sure how tall it should actually be. return ( - + ); } diff --git a/src/components/views/messages/MImageBody.js b/src/components/views/messages/MImageBody.js index 4d12dcf5d7..c92ae475bf 100644 --- a/src/components/views/messages/MImageBody.js +++ b/src/components/views/messages/MImageBody.js @@ -366,7 +366,7 @@ export default class MImageBody extends React.Component { // e2e image hasn't been decrypted yet if (content.file !== undefined && this.state.decryptedUrl === null) { - placeholder = ; + placeholder = ; } else if (!this.state.imgLoaded) { // Deliberately, getSpinner is left unimplemented here, MStickerBody overides placeholder = this.getPlaceholder(); diff --git a/src/components/views/messages/MVideoBody.js b/src/components/views/messages/MVideoBody.js index 1fba9d2ead..fdc04deffc 100644 --- a/src/components/views/messages/MVideoBody.js +++ b/src/components/views/messages/MVideoBody.js @@ -148,7 +148,7 @@ export default createReactClass({ return (
    - +
    ); From 228a6adfdf17f4b3a8d8c81649f8f7c050280c63 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Fri, 26 Jun 2020 09:27:33 +0100 Subject: [PATCH 4/7] indentation --- src/components/views/elements/Spinner.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/components/views/elements/Spinner.js b/src/components/views/elements/Spinner.js index ee4351fed6..08ba0cf921 100644 --- a/src/components/views/elements/Spinner.js +++ b/src/components/views/elements/Spinner.js @@ -34,13 +34,13 @@ const Spinner = ({w = 32, h = 32, imgClassName, message}) => { return (
    { message &&
    { message}
     
    } - +
    ); }; From a2e33a23861da421c21bd5e51eab8d501038a416 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Fri, 26 Jun 2020 09:41:18 +0100 Subject: [PATCH 5/7] Prevent old InlineSpinner gif from spinning --- res/css/views/elements/_InlineSpinner.scss | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/res/css/views/elements/_InlineSpinner.scss b/res/css/views/elements/_InlineSpinner.scss index 561b6cfb82..bdd879b23d 100644 --- a/res/css/views/elements/_InlineSpinner.scss +++ b/res/css/views/elements/_InlineSpinner.scss @@ -18,15 +18,7 @@ limitations under the License. display: inline; } -.mx_InlineSpinner img { +.mx_InlineSpinner_spin img { margin: 0px 6px; vertical-align: -3px; - - animation: spin 1s linear infinite; -} - -@keyframes spin { - 100% { - transform: rotate(360deg); - } -} +} \ No newline at end of file From 96e4b938b2c65d2a87cae1da2c74fa337ce3e47f Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Fri, 26 Jun 2020 09:42:44 +0100 Subject: [PATCH 6/7] Don't modify the size of the MessagePanel spinner --- src/components/structures/MessagePanel.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/structures/MessagePanel.js b/src/components/structures/MessagePanel.js index 481741dfd2..d11fee6360 100644 --- a/src/components/structures/MessagePanel.js +++ b/src/components/structures/MessagePanel.js @@ -770,7 +770,7 @@ export default class MessagePanel extends React.Component { topSpinner =
  • ; } if (this.props.forwardPaginating) { - bottomSpinner =
  • ; + bottomSpinner =
  • ; } const style = this.props.hidden ? { display: 'none' } : {}; From e790a31f09e09c9c3046416ff72cd06e8829aa30 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Fri, 26 Jun 2020 09:44:47 +0100 Subject: [PATCH 7/7] Include newline at end of _InlineSpinner.scss --- res/css/views/elements/_InlineSpinner.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/css/views/elements/_InlineSpinner.scss b/res/css/views/elements/_InlineSpinner.scss index bdd879b23d..6b91e45923 100644 --- a/res/css/views/elements/_InlineSpinner.scss +++ b/res/css/views/elements/_InlineSpinner.scss @@ -21,4 +21,4 @@ limitations under the License. .mx_InlineSpinner_spin img { margin: 0px 6px; vertical-align: -3px; -} \ No newline at end of file +}