diff --git a/src/domain/LoginViewModel.js b/src/domain/LoginViewModel.js index c0bea189..1b52e1a5 100644 --- a/src/domain/LoginViewModel.js +++ b/src/domain/LoginViewModel.js @@ -46,7 +46,7 @@ export class LoginViewModel extends ViewModel { if (this._loadViewModel) { this._loadViewModel = this.disposeTracked(this._loadViewModel); } - this._loadViewModel = this.track(new SessionLoadViewModel({ + this._loadViewModel = this.track(new SessionLoadViewModel(this.childOptions({ createAndStartSessionContainer: () => { this._sessionContainer = this._createSessionContainer(); this._sessionContainer.startWithLogin(homeserver, username, password); @@ -58,7 +58,7 @@ export class LoginViewModel extends ViewModel { this._ready(sessionContainer); }, homeserver, - })); + }))); this._loadViewModel.start(); this.emitChange("loadViewModel"); this._loadViewModelSubscription = this.track(this._loadViewModel.disposableOn("change", () => { diff --git a/src/domain/RootViewModel.js b/src/domain/RootViewModel.js index f6e566e3..fca8d779 100644 --- a/src/domain/RootViewModel.js +++ b/src/domain/RootViewModel.js @@ -35,10 +35,10 @@ export class RootViewModel extends ViewModel { async load() { this.track(this.navigation.observe("login").subscribe(() => this._applyNavigation())); this.track(this.navigation.observe("session").subscribe(() => this._applyNavigation())); - this._applyNavigation(this.urlCreator.getLastUrl()); + this._applyNavigation(true); } - async _applyNavigation(restoreUrlIfAtDefault) { + async _applyNavigation(shouldRestoreLastUrl) { const isLogin = this.navigation.observe("login").get(); const sessionId = this.navigation.observe("session").get(); if (isLogin) { @@ -67,9 +67,7 @@ export class RootViewModel extends ViewModel { } } else { try { - if (restoreUrlIfAtDefault) { - this.urlCreator.pushUrl(restoreUrlIfAtDefault); - } else { + if (!(shouldRestoreLastUrl && this.urlCreator.tryRestoreLastUrl())) { const sessionInfos = await this.platform.sessionInfoStorage.getAll(); if (sessionInfos.length === 0) { this.navigation.push("login"); @@ -126,14 +124,14 @@ export class RootViewModel extends ViewModel { _showSessionLoader(sessionId) { this._setSection(() => { - this._sessionLoadViewModel = new SessionLoadViewModel({ + this._sessionLoadViewModel = new SessionLoadViewModel(this.childOptions({ createAndStartSessionContainer: () => { const sessionContainer = this._createSessionContainer(); sessionContainer.startWithExistingSession(sessionId); return sessionContainer; }, ready: sessionContainer => this._showSession(sessionContainer) - }); + })); this._sessionLoadViewModel.start(); }); } diff --git a/src/domain/SessionLoadViewModel.js b/src/domain/SessionLoadViewModel.js index d8736077..0b785e47 100644 --- a/src/domain/SessionLoadViewModel.js +++ b/src/domain/SessionLoadViewModel.js @@ -28,6 +28,7 @@ export class SessionLoadViewModel extends ViewModel { this._deleteSessionOnCancel = deleteSessionOnCancel; this._loading = false; this._error = null; + this.backUrl = this.urlCreator.urlForSegment("session", true); } async start() { diff --git a/src/domain/navigation/URLRouter.js b/src/domain/navigation/URLRouter.js index 36a1c244..b38791a0 100644 --- a/src/domain/navigation/URLRouter.js +++ b/src/domain/navigation/URLRouter.js @@ -23,12 +23,24 @@ export class URLRouter { this._subscription = null; this._pathSubscription = null; this._isApplyingUrl = false; + this._defaultSessionId = this._getLastSessionId(); + } + + _getLastSessionId() { + const navPath = this._urlAsNavPath(this._history.getLastUrl() || ""); + const sessionId = navPath.get("session")?.value; + if (typeof sessionId === "string") { + return sessionId; + } + return null; } attach() { this._subscription = this._history.subscribe(url => this._applyUrl(url)); + // subscribe to path before applying initial url + // so redirects in _applyNavPathToHistory are reflected in url bar + this._pathSubscription = this._navigation.pathObservable.subscribe(path => this._applyNavPathToHistory(path)); this._applyUrl(this._history.get()); - this._pathSubscription = this._navigation.pathObservable.subscribe(path => this._applyNavigationPath(path)); } dispose() { @@ -36,7 +48,7 @@ export class URLRouter { this._pathSubscription = this._pathSubscription(); } - _applyNavigationPath(path) { + _applyNavPathToHistory(path) { const url = this.urlForPath(path); if (url !== this._history.get()) { if (this._isApplyingUrl) { @@ -48,10 +60,8 @@ export class URLRouter { } } - _applyUrl(url) { - const urlPath = this._history.urlAsPath(url) - const navPath = this._navigation.pathFrom(this._parseUrlPath(urlPath, this._navigation.path)); - // this will cause _applyNavigationPath to be called, + _applyNavPathToNavigation(navPath) { + // this will cause _applyNavPathToHistory to be called, // so set a flag whether this request came from ourselves // (in which case it is a redirect if the url does not match the current one) this._isApplyingUrl = true; @@ -59,12 +69,27 @@ export class URLRouter { this._isApplyingUrl = false; } + _urlAsNavPath(url) { + const urlPath = this._history.urlAsPath(url); + return this._navigation.pathFrom(this._parseUrlPath(urlPath, this._navigation.path, this._defaultSessionId)); + } + + _applyUrl(url) { + const navPath = this._urlAsNavPath(url); + this._applyNavPathToNavigation(navPath); + } + pushUrl(url) { this._history.pushUrl(url); } - getLastUrl() { - return this._history.getLastUrl(); + tryRestoreLastUrl() { + const lastNavPath = this._urlAsNavPath(this._history.getLastUrl() || ""); + if (lastNavPath.segments.length !== 0) { + this._applyNavPathToNavigation(navPath); + return true; + } + return false; } urlForSegments(segments) { diff --git a/src/domain/navigation/index.js b/src/domain/navigation/index.js index 5de73aef..3a9b4a07 100644 --- a/src/domain/navigation/index.js +++ b/src/domain/navigation/index.js @@ -85,7 +85,7 @@ function roomsSegmentWithRoom(rooms, roomId, path) { } } -export function parseUrlPath(urlPath, currentNavPath) { +export function parseUrlPath(urlPath, currentNavPath, defaultSessionId) { // substr(1) to take of initial / const parts = urlPath.substr(1).split("/"); const iterator = parts[Symbol.iterator](); @@ -113,6 +113,14 @@ export function parseUrlPath(urlPath, currentNavPath) { segments.push(roomsSegmentWithRoom(rooms, roomId, currentNavPath)); } segments.push(new Segment("room", roomId)); + } else if (type === "last-session") { + let sessionSegment = currentNavPath.get("session"); + if (typeof sessionSegment?.value !== "string" && defaultSessionId) { + sessionSegment = new Segment("session", defaultSessionId); + } + if (sessionSegment) { + segments.push(sessionSegment); + } } else { // might be undefined, which will be turned into true by Segment const value = iterator.next().value; diff --git a/src/platform/web/ui/css/themes/element/theme.css b/src/platform/web/ui/css/themes/element/theme.css index 706bd90d..c6c18445 100644 --- a/src/platform/web/ui/css/themes/element/theme.css +++ b/src/platform/web/ui/css/themes/element/theme.css @@ -215,6 +215,10 @@ a.button-action { text-align: center; } +.SessionLoadView { + padding-top: 16px; +} + @media screen and (min-width: 600px) { .PreSessionScreen { box-shadow: 0px 6px 32px rgba(0, 0, 0, 0.1); diff --git a/src/platform/web/ui/login/SessionLoadView.js b/src/platform/web/ui/login/SessionLoadView.js index 30489335..6837cf21 100644 --- a/src/platform/web/ui/login/SessionLoadView.js +++ b/src/platform/web/ui/login/SessionLoadView.js @@ -22,9 +22,10 @@ export class SessionLoadView extends TemplateView { return t.div({className: "PreSessionScreen"}, [ t.div({className: "logo"}), t.div({className: "SessionLoadView"}, [ - t.h1(vm.i18n`Loading…`), t.view(new SessionLoadStatusView(vm)) - ]) + ]), + t.div({className: {"button-row": true, hidden: vm => vm.loading}}, + t.a({className: "button-action primary", href: vm.backUrl}, vm.i18n`Go back`)) ]); } }