diff --git a/src/domain/LoginViewModel.js b/src/domain/LoginViewModel.js index 68e1f7c6..64843209 100644 --- a/src/domain/LoginViewModel.js +++ b/src/domain/LoginViewModel.js @@ -1,5 +1,5 @@ import {EventEmitter} from "../utils/EventEmitter.js"; -import {LoadStatus} from "../matrix/SessionContainer.js"; +import {LoadStatus, LoginFailure} from "../matrix/SessionContainer.js"; import {AbortError} from "../utils/error.js"; export class LoginViewModel extends EventEmitter { @@ -8,6 +8,7 @@ export class LoginViewModel extends EventEmitter { this._createSessionContainer = createSessionContainer; this._sessionCallback = sessionCallback; this._defaultHomeServer = defaultHomeServer; + this._homeserver = null; this._sessionContainer = null; this._loadWaitHandle = null; this._loading = false; @@ -18,18 +19,24 @@ export class LoginViewModel extends EventEmitter { get passwordPlaceholder() { return "Password"; } get hsPlaceholder() { return "Your matrix homeserver"; } get defaultHomeServer() { return this._defaultHomeServer; } - get error() { return this._error; } - get loading() { return this._loading; } + get loading() {return this._loading} + + get showLoadLabel() { + return this._loading || this._sessionContainer; + } async login(username, password, homeserver) { try { this._loading = true; this.emit("change", "loading"); + this._homeserver = homeserver; this._sessionContainer = this._createSessionContainer(); this._sessionContainer.startWithLogin(homeserver, username, password); this._loadWaitHandle = this._sessionContainer.loadStatus.waitFor(s => { - this.emit("change", "loadStatus"); - return s === LoadStatus.Ready; + this.emit("change", "loadLabel"); + return s === LoadStatus.Ready || + s === LoadStatus.LoginFailed || + s === LoadStatus.Error; }); try { await this._loadWaitHandle.promise; @@ -40,8 +47,17 @@ export class LoginViewModel extends EventEmitter { } } this._loadWaitHandle = null; - this._sessionCallback(this._sessionContainer); - // wait for parent view model to switch away here + if (this._sessionContainer.loadStatus.get() === LoadStatus.Ready) { + this._sessionCallback(this._sessionContainer); + // wait for parent view model to switch away here + } else { + this._loading = false; + this.emit("change", "loading"); + if (this._sessionContainer.loadError) { + console.error(this._sessionContainer.loadError); + } + } + } catch (err) { this._error = err; this._loading = false; @@ -49,21 +65,43 @@ export class LoginViewModel extends EventEmitter { } } - get loadStatus() { - return this._sessionContainer && this._sessionContainer.loadStatus; - } - - get loadError() { - if (this._sessionContainer) { - const error = this._sessionContainer.loadError; - if (error) { - return error.message; + get loadLabel() { + if (this._error) { + return `Something went wrong: ${this._error.message}.`; + } + if (this.showLoadLabel) { + if (this._sessionContainer) { + switch (this._sessionContainer.loadStatus.get()) { + case LoadStatus.NotLoading: + return `Preparing…`; + case LoadStatus.Login: + return `Checking your login and password…`; + case LoadStatus.LoginFailed: + switch (this._sessionContainer.loginFailure) { + case LoginFailure.LoginFailure: + return `Your username and/or password don't seem to be correct.`; + case LoginFailure.Connection: + return `Can't connect to ${this._homeserver}.`; + case LoginFailure.Unknown: + return `Something went wrong while checking your login and password.`; + } + break; + case LoadStatus.Loading: + return `Loading your conversations…`; + case LoadStatus.FirstSync: + return `Getting your conversations from the server…`; + case LoadStatus.Error: + return `Something went wrong: ${this._sessionContainer.loadError.message}.`; + default: + return this._sessionContainer.loadStatus.get(); + } } + return `Preparing…`; } return null; } - async cancelLogin() { + async cancel() { if (!this._loading) { return; } @@ -81,7 +119,9 @@ export class LoginViewModel extends EventEmitter { } } - cancel() { - this._sessionCallback(); + goBack() { + if (!this._loading) { + this._sessionCallback(); + } } } diff --git a/src/ui/web/login/LoginView.js b/src/ui/web/login/LoginView.js index 9eccc062..c4b68477 100644 --- a/src/ui/web/login/LoginView.js +++ b/src/ui/web/login/LoginView.js @@ -7,9 +7,10 @@ export class LoginView extends TemplateView { } render(t, vm) { - const username = t.input({type: "text", placeholder: vm.usernamePlaceholder}); - const password = t.input({type: "password", placeholder: vm.passwordPlaceholder}); - const homeserver = t.input({type: "text", placeholder: vm.hsPlaceholder, value: vm.defaultHomeServer}); + const disabled = vm => vm.loading; + const username = t.input({type: "text", placeholder: vm.usernamePlaceholder, disabled}); + const password = t.input({type: "password", placeholder: vm.passwordPlaceholder, disabled}); + const homeserver = t.input({type: "text", placeholder: vm.hsPlaceholder, value: vm.defaultHomeServer, disabled}); return t.div({className: "LoginView form"}, [ t.h1(["Log in to your homeserver"]), t.if(vm => vm.error, t => t.div({className: "error"}, vm => vm.error)), @@ -18,10 +19,19 @@ export class LoginView extends TemplateView { t.div(homeserver), t.div(t.button({ onClick: () => vm.login(username.value, password.value, homeserver.value), - disabled: vm => vm.loading + disabled }, "Log In")), - t.div(t.button({onClick: () => vm.cancel()}, ["Pick an existing session"])), + t.div(t.button({onClick: () => vm.goBack(), disabled}, ["Pick an existing session"])), + t.if(vm => vm.showLoadLabel, renderLoadProgress), t.p(brawlGithubLink(t)) ]); } } + +function renderLoadProgress(t) { + return t.div({className: "loadProgress"}, [ + t.div({className: "spinner"}), + t.p(vm => vm.loadLabel), + t.if(vm => vm.loading, t => t.button({onClick: vm => vm.cancel()}, "Cancel login")) + ]); +}