diff --git a/src/open/OpenDefaultViewModel.js b/src/open/OpenDefaultViewModel.js new file mode 100644 index 0000000..b187046 --- /dev/null +++ b/src/open/OpenDefaultViewModel.js @@ -0,0 +1,67 @@ +/* +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. +*/ + +import {ViewModel} from "../utils/ViewModel.js"; +import {getMatchingPlatforms, selectPlatforms} from "./clients/index.js"; + +export class OpenDefaultViewModel extends ViewModel { + constructor(options) { + super(options); + const {client, link, openLinkVM, proposedPlatform, webPlatform} = options; + this._client = client; + this._link = link; + this._openLinkVM = openLinkVM; + this._proposedPlatform = proposedPlatform; + this._webPlatform = webPlatform; + } + + get name() { + return this._client?.name; + } + + get openingDefault() { + return !this._client; + } + + get autoRedirect() { + // Only auto-redirect when a preferred client hasn't been set. + return this.openingDefault; + } + + get webDeepLink() { + return this._client && this._webPlatform && this._client.getDeepLink(this._webPlatform); + } + + close() { + this._openLinkVM.closeDefault(); + } + + tryOpenLink() { + this._trying = true; + // TODO actually try opening link + this.setTimeout(() => { + if (this.autoRedirect) { + // We're about to be closed so don't + // bother with visual updates. + this.close(); + } else { + this._trying = false; + this.emitChange(); + } + }, 1000); + this.emitChange(); + } +} diff --git a/src/open/OpenLinkView.js b/src/open/OpenLinkView.js index d545885..b859b06 100644 --- a/src/open/OpenLinkView.js +++ b/src/open/OpenLinkView.js @@ -22,17 +22,20 @@ import {ServerConsentView} from "./ServerConsentView.js"; export class OpenLinkView extends TemplateView { render(t, vm) { return t.div({className: "OpenLinkView card"}, [ - t.map(vm => vm.tryingLink, tryingLink => tryingLink ? - t.view(new TryingLinkView(vm)) : - t.mapView(vm => vm.previewViewModel, previewVM => previewVM ? - new ShowLinkView(vm) : - new ServerConsentView(vm.serverConsentViewModel) - ), - ), + t.mapView(vm => [ vm.openDefaultViewModel, vm.previewViewModel ], ([openDefaultVM, previewVM]) => { + if (openDefaultVM) { + return new TryingLinkView(openDefaultVM) + } else if (previewVM) { + return new ShowLinkView(vm); + } else { + return new ServerConsentView(vm.serverConsentViewModel); + } + }), ]); } } + class TryingLinkView extends TemplateView { render (t, vm) { return t.div({ className: "OpeningClientView" }, [ diff --git a/src/open/OpenLinkViewModel.js b/src/open/OpenLinkViewModel.js index 2fd4129..97fdac4 100644 --- a/src/open/OpenLinkViewModel.js +++ b/src/open/OpenLinkViewModel.js @@ -18,9 +18,11 @@ import {ViewModel} from "../utils/ViewModel.js"; import {ClientListViewModel} from "./ClientListViewModel.js"; import {ClientViewModel} from "./ClientViewModel.js"; import {PreviewViewModel} from "../preview/PreviewViewModel.js"; +import {OpenDefaultViewModel} from "./OpenDefaultViewModel.js"; import {ServerConsentViewModel} from "./ServerConsentViewModel.js"; import {getLabelForLinkKind} from "../Link.js"; import {orderedUnique} from "../utils/unique.js"; +import {getMatchingPlatforms, selectPlatforms} from "./clients/index.js"; export class OpenLinkViewModel extends ViewModel { constructor(options) { @@ -28,12 +30,53 @@ export class OpenLinkViewModel extends ViewModel { const {clients, link} = options; this._link = link; this._clients = clients; + this.openDefaultViewModel = null; this.serverConsentViewModel = null; this.previewViewModel = null; this.clientsViewModel = null; this.previewLoading = false; this.tryingLink = false; - this._tryLink(); + if (!this._tryOpenDefault()) { + this._activeOpen(); + } + } + + _tryOpenDefault() { + const client = this._getPreferredClient(); + let proposedPlatform = null; + let webPlatform = null; + if (client) { + const matchingPlatforms = getMatchingPlatforms(client, this.platforms); + const selectedPlatforms = selectPlatforms(matchingPlatforms, this.preferences.platform); + if (selectedPlatforms.proposedPlatform !== selectedPlatforms.nativePlatform) { + // Do not auto-open web applications + return false; + } + proposedPlatform = selectedPlatforms.proposedPlatform; + webPlatform = selectedPlatforms.webPlatform; + + if (!client.getDeepLink(proposedPlatform, this._link)) { + // Client doesn't support deep links. We can't open it. + return false; + } + } + this.openDefaultViewModel = new OpenDefaultViewModel(this.childOptions({ + client, + link: this._link, + openLinkVM: this, + proposedPlatform, + webPlatform, + })); + this.openDefaultViewModel.tryOpenLink(); + return true; + } + + closeDefault() { + this.openDefaultViewModel = null; + this._activeOpen(); + } + + _activeOpen() { if (this.preferences.homeservers === null) { this._showServerConsent(); } else { @@ -41,18 +84,6 @@ export class OpenLinkViewModel extends ViewModel { } } - _tryLink() { - const matrixUrl = this._link.toMatrixUrl() - if (matrixUrl) { - this.tryingLink = true; - this.setTimeout(() => { - this.tryingLink = false; - this.emitChange(); - }, 1000); - this.openLink(matrixUrl); - } - } - _showServerConsent() { let servers = []; if (this.preferences.homeservers) { @@ -67,11 +98,16 @@ export class OpenLinkViewModel extends ViewModel { this._showLink(); } })); + this.emitChange(); + } + + _getPreferredClient() { + const clientId = this.preferences.clientId || this._link.clientId; + return clientId ? this._clients.find(c => c.id === clientId) : null; } async _showLink() { - const clientId = this.preferences.clientId || this._link.clientId; - const preferredClient = clientId ? this._clients.find(c => c.id === clientId) : null; + const preferredClient = this._getPreferredClient(); this.clientsViewModel = new ClientListViewModel(this.childOptions({ clients: this._clients, link: this._link,