From 5d40d013608c75b4d6b437f2b475a530775f6180 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 2 Dec 2020 15:36:54 +0100 Subject: [PATCH] make preview useable without client list, to reuse in create link view --- src/{client => }/Platform.js | 4 +- src/Preferences.js | 2 +- src/RootView.js | 6 +- src/RootViewModel.js | 25 ++++---- src/main.js | 3 +- src/{client => open}/ClientListView.js | 0 src/{client => open}/ClientListViewModel.js | 2 +- src/{client => open}/ClientView.js | 1 + src/{client => open}/ClientViewModel.js | 19 +++--- src/open/OpenLinkView.js | 35 +++++++++++ src/open/OpenLinkViewModel.js | 64 +++++++++++++++++++++ src/{client => open}/clients/Element.js | 2 +- src/{client => open}/clients/Weechat.js | 0 src/open/clients/index.js | 25 ++++++++ src/{client => open}/types.js | 2 +- src/preview/PreviewView.js | 12 +--- src/preview/PreviewViewModel.js | 29 ++-------- 17 files changed, 165 insertions(+), 66 deletions(-) rename src/{client => }/Platform.js (92%) rename src/{client => open}/ClientListView.js (100%) rename src/{client => open}/ClientListViewModel.js (97%) rename src/{client => open}/ClientView.js (98%) rename src/{client => open}/ClientViewModel.js (89%) create mode 100644 src/open/OpenLinkView.js create mode 100644 src/open/OpenLinkViewModel.js rename src/{client => open}/clients/Element.js (98%) rename src/{client => open}/clients/Weechat.js (100%) create mode 100644 src/open/clients/index.js rename src/{client => open}/types.js (98%) diff --git a/src/client/Platform.js b/src/Platform.js similarity index 92% rename from src/client/Platform.js rename to src/Platform.js index 2b826ef..328826c 100644 --- a/src/client/Platform.js +++ b/src/Platform.js @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import {createEnum} from "../utils/enum.js"; +import {createEnum} from "./utils/enum.js"; export const Platform = createEnum( "DesktopWeb", @@ -29,7 +29,7 @@ export const Platform = createEnum( export function guessApplicablePlatforms(userAgent) { // use https://github.com/faisalman/ua-parser-js to guess, and pass as RootVM options return [Platform.DesktopWeb, Platform.Linux]; - //return [Platform.MobileWeb, Platform.iOS]; + // return [Platform.MobileWeb, Platform.Android]; } export function isWebPlatform(p) { diff --git a/src/Preferences.js b/src/Preferences.js index 19879e7..d75edc2 100644 --- a/src/Preferences.js +++ b/src/Preferences.js @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import {Platform} from "./client/Platform.js"; +import {Platform} from "./Platform.js"; export class Preferences { constructor(localStorage) { diff --git a/src/RootView.js b/src/RootView.js index c4f42a8..c55c3ab 100644 --- a/src/RootView.js +++ b/src/RootView.js @@ -15,12 +15,14 @@ limitations under the License. */ import {TemplateView} from "./utils/TemplateView.js"; -import {PreviewView} from "./preview/PreviewView.js"; +import {OpenLinkView} from "./open/OpenLinkView.js"; +import {CreateLinkView} from "./create/CreateLinkView.js"; export class RootView extends TemplateView { render(t, vm) { return t.div({className: "RootView"}, [ - t.mapView(vm => vm.previewViewModel, vm => vm ? new PreviewView(vm) : null), + t.mapView(vm => vm.openLinkViewModel, vm => vm ? new OpenLinkView(vm) : null), + t.mapView(vm => vm.createLinkViewModel, vm => vm ? new CreateLinkView(vm) : null), t.div({className: "footer"}, [ t.p(t.img({src: "images/matrix-logo.svg"})), t.p(["This invite uses ", externalLink(t, "https://matrix.org", "Matrix"), ", an open network for secure, decentralized communication."]), diff --git a/src/RootViewModel.js b/src/RootViewModel.js index 222bd0a..822b3d8 100644 --- a/src/RootViewModel.js +++ b/src/RootViewModel.js @@ -16,27 +16,29 @@ limitations under the License. import {Link} from "./Link.js"; import {ViewModel} from "./utils/ViewModel.js"; -import {PreviewViewModel} from "./preview/PreviewViewModel.js"; -import {Element} from "./client/clients/Element.js"; -import {Weechat} from "./client/clients/Weechat.js"; -import {Platform} from "./client/Platform.js"; +import {OpenLinkViewModel} from "./open/OpenLinkViewModel.js"; +import {createClients} from "./open/clients/index.js"; +import {CreateLinkViewModel} from "./create/CreateLinkViewModel.js"; +import {Platform} from "./Platform.js"; export class RootViewModel extends ViewModel { constructor(options) { super(options); this.link = null; - this.previewViewModel = null; + this.openLinkViewModel = null; + this.createLinkViewModel = null; } _updateChildVMs(oldLink) { if (this.link) { + this.createLinkViewModel = null; if (!oldLink || !oldLink.equals(this.link)) { - this.previewViewModel = new PreviewViewModel(this.childOptions({ + this.openLinkViewModel = new OpenLinkViewModel(this.childOptions({ link: this.link, consentedServers: this.link.servers, - clients: [new Element(), new Weechat()] + clients: createClients() })); - this.previewViewModel.load(); + this.openLinkViewModel.load(); } } else { this.previewViewModel = null; @@ -50,13 +52,6 @@ export class RootViewModel extends ViewModel { this._updateChildVMs(oldLink); } - get activeSection() { - if (this.previewViewModel) { - return "preview"; - } - return ""; - } - clearPreferences() { this.preferences.clear(); this._updateChildVMs(); diff --git a/src/main.js b/src/main.js index a31032c..c768282 100644 --- a/src/main.js +++ b/src/main.js @@ -2,7 +2,7 @@ import {xhrRequest} from "./utils/xhr.js"; import {RootViewModel} from "./RootViewModel.js"; import {RootView} from "./RootView.js"; import {Preferences} from "./Preferences.js"; -import {guessApplicablePlatforms} from "./client/Platform.js"; +import {guessApplicablePlatforms} from "./Platform.js"; export async function main(container) { const vm = new RootViewModel({ @@ -10,6 +10,7 @@ export async function main(container) { openLink: url => location.href = url, platforms: guessApplicablePlatforms(navigator.userAgent), preferences: new Preferences(window.localStorage), + origin: location.origin, }); vm.updateHash(location.hash); window.__rootvm = vm; diff --git a/src/client/ClientListView.js b/src/open/ClientListView.js similarity index 100% rename from src/client/ClientListView.js rename to src/open/ClientListView.js diff --git a/src/client/ClientListViewModel.js b/src/open/ClientListViewModel.js similarity index 97% rename from src/client/ClientListViewModel.js rename to src/open/ClientListViewModel.js index 04a8efe..2d34166 100644 --- a/src/client/ClientListViewModel.js +++ b/src/open/ClientListViewModel.js @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import {isWebPlatform, Platform} from "./Platform.js"; +import {isWebPlatform, Platform} from "../Platform.js"; import {Maturity} from "./types.js"; import {ClientViewModel} from "./ClientViewModel.js"; import {ViewModel} from "../utils/ViewModel.js"; diff --git a/src/client/ClientView.js b/src/open/ClientView.js similarity index 98% rename from src/client/ClientView.js rename to src/open/ClientView.js index 143365f..5382625 100644 --- a/src/client/ClientView.js +++ b/src/open/ClientView.js @@ -99,6 +99,7 @@ class InstallClientView extends TemplateView { const deepLink = t.a({ rel: "noopener noreferrer", href: vm.deepLink, + onClick: () => vm.deepLinkActivated(), }, "open it here"); children.push(t.p([`If you already have ${vm.name} installed, you can `, deepLink, "."])) } diff --git a/src/client/ClientViewModel.js b/src/open/ClientViewModel.js similarity index 89% rename from src/client/ClientViewModel.js rename to src/open/ClientViewModel.js index e202b25..8685160 100644 --- a/src/client/ClientViewModel.js +++ b/src/open/ClientViewModel.js @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import {isWebPlatform, isDesktopPlatform, Platform} from "./Platform.js"; +import {isWebPlatform, isDesktopPlatform, Platform} from "../Platform.js"; import {ViewModel} from "../utils/ViewModel.js"; export class ClientViewModel extends ViewModel { @@ -44,7 +44,7 @@ export class ClientViewModel extends ViewModel { _createActions(client, link, nativePlatform, webPlatform) { let actions = []; if (nativePlatform) { - const nativeActions = client.getInstallLinks(nativePlatform).map(installLink => { + const nativeActions = (client.getInstallLinks(nativePlatform) || []).map(installLink => { return { label: installLink.description, url: installLink.createInstallURL(link), @@ -56,12 +56,15 @@ export class ClientViewModel extends ViewModel { actions.push(...nativeActions); } if (webPlatform) { - actions.push({ - label: `Or open in ${client.getName(webPlatform)}`, - url: client.getDeepLink(webPlatform, link), - kind: "open-in-web", - activated: () => this.preferences.setClient(client.id, webPlatform), - }); + const webDeepLink = client.getDeepLink(webPlatform, link); + if (webDeepLink) { + actions.push({ + label: `Or open in ${client.getName(webPlatform)}`, + url: webDeepLink, + kind: "open-in-web", + activated: () => this.preferences.setClient(client.id, webPlatform), + }); + } } if (actions.length === 0) { actions.push({ diff --git a/src/open/OpenLinkView.js b/src/open/OpenLinkView.js new file mode 100644 index 0000000..52efe87 --- /dev/null +++ b/src/open/OpenLinkView.js @@ -0,0 +1,35 @@ +/* +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 {TemplateView} from "../utils/TemplateView.js"; +import {ClientListView} from "./ClientListView.js"; +import {PreviewView} from "../preview/PreviewView.js"; + +export class OpenLinkView extends TemplateView { + render(t, vm) { + return t.div({className: "OpenLinkView card"}, [ + t.view(new PreviewView(vm.previewViewModel)), + t.div({className: {hidden: vm => vm.previewLoading}}, [ + t.p({className: {hidden: vm => vm.clientsViewModel}}, t.button({ + className: "primary fullwidth", + onClick: () => vm.showClients() + }, vm => vm.showClientsLabel)), + t.mapView(vm => vm.clientsViewModel, childVM => childVM ? new ClientListView(childVM) : null), + t.p(["Preview provided by ", vm => vm.previewDomain]), + ]) + ]); + } +} \ No newline at end of file diff --git a/src/open/OpenLinkViewModel.js b/src/open/OpenLinkViewModel.js new file mode 100644 index 0000000..99707bb --- /dev/null +++ b/src/open/OpenLinkViewModel.js @@ -0,0 +1,64 @@ +/* +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 {ClientListViewModel} from "./ClientListViewModel.js"; +import {ClientViewModel} from "./ClientViewModel.js"; +import {PreviewViewModel} from "../preview/PreviewViewModel.js"; +import {getLabelForLinkKind} from "../Link.js"; + +export class OpenLinkViewModel extends ViewModel { + constructor(options) { + super(options); + const {clients, link, consentedServers} = options; + this._link = link; + this._clients = clients; + this.previewViewModel = new PreviewViewModel(this.childOptions({link, consentedServers})); + this.previewLoading = false; + const preferredClient = this.preferences.clientId ? clients.find(c => c.id === this.preferences.clientId) : null; + this.clientsViewModel = preferredClient ? new ClientListViewModel(this.childOptions({ + clients, + link, + client: preferredClient, + })) : null; + } + + async load() { + this.previewLoading = true; + this.emitChange(); + await this.previewViewModel.load(); + this.previewLoading = false; + this.emitChange(); + } + + get previewDomain() { + return this.previewViewModel.previewDomain; + } + + get showClientsLabel() { + return getLabelForLinkKind(this._link.kind); + } + + showClients() { + if (!this.clientsViewModel) { + this.clientsViewModel = new ClientListViewModel(this.childOptions({ + clients: this._clients, + link: this._link + })); + this.emitChange(); + } + } +} diff --git a/src/client/clients/Element.js b/src/open/clients/Element.js similarity index 98% rename from src/client/clients/Element.js rename to src/open/clients/Element.js index c0adb7d..465e44e 100644 --- a/src/client/clients/Element.js +++ b/src/open/clients/Element.js @@ -28,7 +28,7 @@ export class Element { return [ Platform.Android, Platform.iOS, Platform.Windows, Platform.macOS, Platform.Linux, - Platform.DesktopWeb, Platform.MobileWeb + Platform.DesktopWeb ]; } diff --git a/src/client/clients/Weechat.js b/src/open/clients/Weechat.js similarity index 100% rename from src/client/clients/Weechat.js rename to src/open/clients/Weechat.js diff --git a/src/open/clients/index.js b/src/open/clients/index.js new file mode 100644 index 0000000..a939543 --- /dev/null +++ b/src/open/clients/index.js @@ -0,0 +1,25 @@ +/* +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 {Element} from "./Element.js"; +import {Weechat} from "./Weechat.js"; + +export function createClients() { + return [ + new Element(), + new Weechat(), + ]; +} \ No newline at end of file diff --git a/src/client/types.js b/src/open/types.js similarity index 98% rename from src/client/types.js rename to src/open/types.js index b6fda03..443d769 100644 --- a/src/client/types.js +++ b/src/open/types.js @@ -17,7 +17,7 @@ limitations under the License. import {createEnum} from "../utils/enum.js"; export const Maturity = createEnum("Alpha", "Beta", "Stable"); export {LinkKind} from "../Link.js"; -export {Platform} from "./Platform.js"; +export {Platform} from "../Platform.js"; export class AppleStoreLink { constructor(org, appId) { diff --git a/src/preview/PreviewView.js b/src/preview/PreviewView.js index 81fb083..a80216c 100644 --- a/src/preview/PreviewView.js +++ b/src/preview/PreviewView.js @@ -15,12 +15,12 @@ limitations under the License. */ import {TemplateView} from "../utils/TemplateView.js"; -import {ClientListView} from "../client/ClientListView.js"; -import {ClientView} from "../client/ClientView.js"; +import {ClientListView} from "../open/ClientListView.js"; +import {ClientView} from "../open/ClientView.js"; export class PreviewView extends TemplateView { render(t, vm) { - return t.div({className: "PreviewView card"}, [ + return t.div({className: "PreviewView"}, [ t.h1({className: {hidden: vm => !vm.loading}}, "Loading preview…"), t.div({className: {hidden: vm => vm.loading}}, [ t.div({className: "preview"}, [ @@ -30,12 +30,6 @@ export class PreviewView extends TemplateView { t.p({className: {memberCount: true, hidden: vm => !vm.memberCount}}, [vm => vm.memberCount, " members"]), t.p({className: {topic: true, hidden: vm => !vm.topic}}, [vm => vm.topic]), ]), - t.p({className: {hidden: vm => vm.clientsViewModel}}, t.button({ - className: "primary fullwidth", - onClick: () => vm.showClients() - }, vm => vm.showClientsLabel)), - t.mapView(vm => vm.clientsViewModel, childVM => childVM ? new ClientListView(childVM) : null), - t.p(["Preview provided by ", vm => vm.previewDomain]), ]) ]); } diff --git a/src/preview/PreviewViewModel.js b/src/preview/PreviewViewModel.js index b282642..1d9f0f9 100644 --- a/src/preview/PreviewViewModel.js +++ b/src/preview/PreviewViewModel.js @@ -14,21 +14,18 @@ See the License for the specific language governing permissions and limitations under the License. */ -import {LinkKind, IdentifierKind, getLabelForLinkKind} from "../Link.js"; +import {LinkKind, IdentifierKind} from "../Link.js"; import {ViewModel} from "../utils/ViewModel.js"; import {resolveServer} from "./HomeServer.js"; -import {ClientListViewModel} from "../client/ClientListViewModel.js"; -import {ClientViewModel} from "../client/ClientViewModel.js"; +import {ClientListViewModel} from "../open/ClientListViewModel.js"; +import {ClientViewModel} from "../open/ClientViewModel.js"; export class PreviewViewModel extends ViewModel { constructor(options) { super(options); - const { link, consentedServers, clients } = options; + const { link, consentedServers } = options; this._link = link; this._consentedServers = consentedServers; - this._clients = clients; - this._preferredClient = this.preferences.clientId ? clients.find(c => c.id === this.preferences.clientId) : null; - this.loading = false; this.name = null; this.avatarUrl = null; @@ -36,13 +33,6 @@ export class PreviewViewModel extends ViewModel { this.memberCount = null; this.topic = null; this.previewDomain = null; - this.clientsViewModel = null; - this.acceptInstructions = null; - this.clientsViewModel = this._preferredClient ? new ClientListViewModel(this.childOptions({ - clients: this._clients, - client: this._preferredClient, - link: this._link, - })) : null; } async load() { @@ -97,15 +87,4 @@ export class PreviewViewModel extends ViewModel { this.topic = publicRoom?.topic; this.identifier = publicRoom?.canonical_alias || link.identifier; } - - get showClientsLabel() { - return getLabelForLinkKind(this._link.kind); - } - - showClients() { - if (!this.clientsViewModel) { - this.clientsViewModel = new ClientListViewModel(this.childOptions({clients: this._clients, link: this._link})); - this.emitChange(); - } - } } \ No newline at end of file