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/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/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index da416142f8..519b39d436 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -1902,27 +1902,22 @@ export default createReactClass({ const cli = MatrixClientPeg.get(); // We're checking `isCryptoAvailable` here instead of `isCryptoEnabled` // because the client hasn't been started yet. - if (!isCryptoAvailable()) { + const cryptoAvailable = isCryptoAvailable(); + if (!cryptoAvailable) { this._onLoggedIn(); } - // Test for the master cross-signing key in SSSS as a quick proxy for - // whether cross-signing has been set up on the account. We can't - // really continue until we know whether it's there or not so retry - // if this fails. - let masterKeyInStorage; - while (masterKeyInStorage === undefined) { - try { - masterKeyInStorage = !!await cli.getAccountDataFromServer("m.cross_signing.master"); - } catch (e) { - if (e.errcode === "M_NOT_FOUND") { - masterKeyInStorage = false; - } else { - console.warn("Secret storage account data check failed: retrying...", e); - } - } + this.setState({ pendingInitialSync: true }); + await this.firstSyncPromise.promise; + + if (!cryptoAvailable) { + this.setState({ pendingInitialSync: false }); + return setLoggedInPromise; } + // Test for the master cross-signing key in SSSS as a quick proxy for + // whether cross-signing has been set up on the account. + const masterKeyInStorage = !!cli.getAccountData("m.cross_signing.master"); if (masterKeyInStorage) { // Auto-enable cross-signing for the new session when key found in // secret storage. @@ -1939,6 +1934,7 @@ export default createReactClass({ } else { this._onLoggedIn(); } + this.setState({ pendingInitialSync: false }); return setLoggedInPromise; }, @@ -2060,6 +2056,7 @@ export default createReactClass({ const Login = sdk.getComponent('structures.auth.Login'); view = ( ); }, @@ -629,9 +635,11 @@ export default createReactClass({ render: function() { const Loader = sdk.getComponent("elements.Spinner"); + const InlineSpinner = sdk.getComponent("elements.InlineSpinner"); const AuthHeader = sdk.getComponent("auth.AuthHeader"); const AuthBody = sdk.getComponent("auth.AuthBody"); - const loader = this.isBusy() ?
: null; + const loader = this.isBusy() && !this.state.busyLoggingIn ? +
: null; const errorText = this.state.errorText; @@ -658,9 +666,28 @@ export default createReactClass({ ); } + let footer; + if (this.props.isSyncing || this.state.busyLoggingIn) { + footer =
+
+ + { this.props.isSyncing ? _t("Syncing...") : _t("Signing In...") } +
+ { this.props.isSyncing &&
+ {_t("If you've joined lots of rooms, this might take a while")} +
} +
; + } else { + footer = ( + + { _t('Create account') } + + ); + } + return ( - +

{_t('Sign in')} @@ -670,9 +697,7 @@ export default createReactClass({ { serverDeadSection } { this.renderServerComponent() } { this.renderLoginComponentForStep() } - - { _t('Create account') } - + { footer } ); diff --git a/src/components/views/auth/AuthHeader.js b/src/components/views/auth/AuthHeader.js index 133fd41359..6e787ba77c 100644 --- a/src/components/views/auth/AuthHeader.js +++ b/src/components/views/auth/AuthHeader.js @@ -16,12 +16,17 @@ limitations under the License. */ import React from 'react'; +import PropTypes from 'prop-types'; import createReactClass from 'create-react-class'; import * as sdk from '../../../index'; export default createReactClass({ displayName: 'AuthHeader', + propTypes: { + disableLanguageSelector: PropTypes.bool, + }, + render: function() { const AuthHeaderLogo = sdk.getComponent('auth.AuthHeaderLogo'); const LanguageSelector = sdk.getComponent('views.auth.LanguageSelector'); @@ -29,7 +34,7 @@ export default createReactClass({ return (
- +
); }, diff --git a/src/components/views/auth/LanguageSelector.js b/src/components/views/auth/LanguageSelector.js index 99578d4504..83db5d225b 100644 --- a/src/components/views/auth/LanguageSelector.js +++ b/src/components/views/auth/LanguageSelector.js @@ -28,12 +28,14 @@ function onChange(newLang) { } } -export default function LanguageSelector() { +export default function LanguageSelector({disabled}) { if (SdkConfig.get()['disable_login_language_selector']) return
; const LanguageDropdown = sdk.getComponent('views.elements.LanguageDropdown'); - return ; } diff --git a/src/components/views/auth/PasswordLogin.js b/src/components/views/auth/PasswordLogin.js index e64b8360c3..aeaa91845b 100644 --- a/src/components/views/auth/PasswordLogin.js +++ b/src/components/views/auth/PasswordLogin.js @@ -23,6 +23,7 @@ import * as sdk from '../../../index'; import { _t } from '../../../languageHandler'; import SdkConfig from '../../../SdkConfig'; import {ValidatedServerConfig} from "../../../utils/AutoDiscoveryUtils"; +import AccessibleButton from "../elements/AccessibleButton"; /** * A pure UI component which displays a username/password form. @@ -44,6 +45,7 @@ export default class PasswordLogin extends React.Component { loginIncorrect: PropTypes.bool, disableSubmit: PropTypes.bool, serverConfig: PropTypes.instanceOf(ValidatedServerConfig).isRequired, + busy: PropTypes.bool, }; static defaultProps = { @@ -265,12 +267,16 @@ export default class PasswordLogin extends React.Component { if (this.props.onForgotPasswordClick) { forgotPasswordJsx = {_t('Not sure of your password? Set a new one', {}, { - a: sub => - {sub} - , + a: sub => ( + + {sub} + + ), })} ; } @@ -332,11 +338,11 @@ export default class PasswordLogin extends React.Component { disabled={this.props.disableSubmit} /> {forgotPasswordJsx} - + /> }
); diff --git a/src/components/views/elements/LanguageDropdown.js b/src/components/views/elements/LanguageDropdown.js index 18a7e95e85..e37109caff 100644 --- a/src/components/views/elements/LanguageDropdown.js +++ b/src/components/views/elements/LanguageDropdown.js @@ -114,6 +114,7 @@ export default class LanguageDropdown extends React.Component { searchEnabled={true} value={value} label={_t("Language Dropdown")} + disabled={this.props.disabled} > { options } ; diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 3c5be84f20..84c172ea4d 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -2102,6 +2102,9 @@ "Error: Problem communicating with the given homeserver.": "Error: Problem communicating with the given homeserver.", "Can't connect to homeserver via HTTP when an HTTPS URL is in your browser bar. Either use HTTPS or enable unsafe scripts.": "Can't connect to homeserver via HTTP when an HTTPS URL is in your browser bar. Either use HTTPS or enable unsafe scripts.", "Can't connect to homeserver - please check your connectivity, ensure your homeserver's SSL certificate is trusted, and that a browser extension is not blocking requests.": "Can't connect to homeserver - please check your connectivity, ensure your homeserver's SSL certificate is trusted, and that a browser extension is not blocking requests.", + "Syncing...": "Syncing...", + "Signing In...": "Signing In...", + "If you've joined lots of rooms, this might take a while": "If you've joined lots of rooms, this might take a while", "Create account": "Create account", "Failed to fetch avatar URL": "Failed to fetch avatar URL", "Set a display name:": "Set a display name:",