diff --git a/src/Preferences.js b/src/Preferences.js new file mode 100644 index 0000000..19879e7 --- /dev/null +++ b/src/Preferences.js @@ -0,0 +1,55 @@ +/* +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 {Platform} from "./client/Platform.js"; + +export class Preferences { + constructor(localStorage) { + this._localStorage = localStorage; + this.clientId = null; + // used to differentiate web from native if a client supports both + this.platform = null; + this.homeservers = []; + + const prefsStr = localStorage.getItem("preferred_client"); + if (prefsStr) { + const {id, platform} = JSON.parse(prefsStr); + this.clientId = id; + this.platform = Platform[platform]; + } + } + + setClient(id, platform) { + this.clientId = id; + platform = Platform[platform]; + this.platform = platform; + this._localStorage.setItem("preferred_client", JSON.stringify({id, platform})); + } + + setHomeservers(homeservers) { + + } + + clear() { + this._localStorage.removeItem("preferred_client"); + this.clientId = null; + this.platform = null; + } + + get canClear() { + return !!this.clientId || !!this.platform; + } +} \ No newline at end of file diff --git a/src/RootView.js b/src/RootView.js index b5a9cca..c4f42a8 100644 --- a/src/RootView.js +++ b/src/RootView.js @@ -27,6 +27,8 @@ export class RootView extends TemplateView { t.ul({className: "links"}, [ t.li(externalLink(t, "https://github.com/matrix-org/matrix.to", "GitHub project")), t.li(externalLink(t, "https://github.com/matrix-org/matrix.to/tree/main/src/clients", "Add your app")), + t.li({className: {hidden: vm => !vm.hasPreferences}}, + t.button({className: "text", onClick: () => vm.clearPreferences()}, "Clear preferences")), ]) ]) ]); diff --git a/src/RootViewModel.js b/src/RootViewModel.js index 9c1a43a..dc41435 100644 --- a/src/RootViewModel.js +++ b/src/RootViewModel.js @@ -18,6 +18,7 @@ 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 {Platform} from "./client/Platform.js"; export class RootViewModel extends ViewModel { constructor(options) { @@ -33,8 +34,6 @@ export class RootViewModel extends ViewModel { this.previewViewModel = new PreviewViewModel(this.childOptions({ link: this.link, consentedServers: this.link.servers, - // preferredClient: element, - // preferredPlatform: this.platforms[0], clients: [element] })); this.previewViewModel.load(); @@ -57,4 +56,13 @@ export class RootViewModel extends ViewModel { } return ""; } -} \ No newline at end of file + + clearPreferences() { + this.preferences.clear(); + this._updateChildVMs(); + } + + get hasPreferences() { + return this.preferences.canClear; + } +} diff --git a/src/main.js b/src/main.js index de41b5d..a31032c 100644 --- a/src/main.js +++ b/src/main.js @@ -1,6 +1,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"; export async function main(container) { @@ -8,6 +9,7 @@ export async function main(container) { request: xhrRequest, openLink: url => location.href = url, platforms: guessApplicablePlatforms(navigator.userAgent), + preferences: new Preferences(window.localStorage), }); vm.updateHash(location.hash); window.__rootvm = vm; diff --git a/src/preview/PreviewViewModel.js b/src/preview/PreviewViewModel.js index 919e01b..74aac1f 100644 --- a/src/preview/PreviewViewModel.js +++ b/src/preview/PreviewViewModel.js @@ -18,20 +18,16 @@ import {LinkKind} 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"; export class PreviewViewModel extends ViewModel { constructor(options) { super(options); - const { - link, consentedServers, - preferredClient, preferredPlatform, clients - } = options; + const { link, consentedServers, clients } = options; this._link = link; this._consentedServers = consentedServers; - this._preferredClient = preferredClient; - // used to differentiate web from native if a client supports both - this._preferredPlatform = preferredPlatform; this._clients = clients; + this._preferredClient = this.preferences.clientId ? clients.find(c => c.id === this.preferences.clientId) : null; this.loading = false; this.name = null; @@ -39,6 +35,7 @@ export class PreviewViewModel extends ViewModel { this.previewDomain = null; this.clientsViewModel = null; this.acceptInstructions = null; + this.missingClientViewModel = null; } async load() { @@ -76,7 +73,7 @@ export class PreviewViewModel extends ViewModel { get acceptLabel() { if (this._preferredClient) { - return `Open in ${this._preferredClient.getName(this._preferredPlatform)}`; + return `Open in ${this._preferredClient.getName(this.preferences.platform)}`; } else { return "Choose app"; } @@ -84,17 +81,16 @@ export class PreviewViewModel extends ViewModel { accept() { if (this._preferredClient) { - if (this._preferredClient.getLinkSupport(this._preferredPlatform, this._link)) { - const deepLink = this._preferredClient.getDeepLink(this._preferredPlatform, this._link); + if (this._preferredClient.getLinkSupport(this.preferences.platform, this._link)) { + const deepLink = this._preferredClient.getDeepLink(this.preferences.platform, this._link); this.openLink(deepLink); - // show "looks like you don't have the native app installed" const protocol = new URL(deepLink).protocol; const isWebProtocol = protocol === "http:" || protocol === "https:"; if (!isWebProtocol) { this.missingClientViewModel = new ClientViewModel(this.childOptions({client: this._preferredClient, link: this._link})); } } else { - this.acceptInstructions = this._preferredClient.getLinkInstructions(this._preferredPlatform, this._link); + this.acceptInstructions = this._preferredClient.getLinkInstructions(this.preferences.platform, this._link); } } else { this.clientsViewModel = new ClientListViewModel(this.childOptions({clients: this._clients, link: this._link})); diff --git a/src/utils/ViewModel.js b/src/utils/ViewModel.js index 3cc34f2..40507f6 100644 --- a/src/utils/ViewModel.js +++ b/src/utils/ViewModel.js @@ -63,12 +63,14 @@ export class ViewModel extends EventEmitter { get request() { return this._options.request; } get openLink() { return this._options.openLink; } get platforms() { return this._options.platforms; } + get preferences() { return this._options.preferences; } childOptions(options = {}) { return Object.assign({ request: this.request, openLink: this.openLink, platforms: this.platforms, + preferences: this.preferences, }, options); } } \ No newline at end of file