add basic preferences

This commit is contained in:
Bruno Windels 2020-12-01 12:06:37 +01:00
parent fcf1087eaf
commit c1bc2546fd
6 changed files with 80 additions and 15 deletions

55
src/Preferences.js Normal file
View file

@ -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;
}
}

View file

@ -27,6 +27,8 @@ export class RootView extends TemplateView {
t.ul({className: "links"}, [ 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", "GitHub project")),
t.li(externalLink(t, "https://github.com/matrix-org/matrix.to/tree/main/src/clients", "Add your app")), 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")),
]) ])
]) ])
]); ]);

View file

@ -18,6 +18,7 @@ import {Link} from "./Link.js";
import {ViewModel} from "./utils/ViewModel.js"; import {ViewModel} from "./utils/ViewModel.js";
import {PreviewViewModel} from "./preview/PreviewViewModel.js"; import {PreviewViewModel} from "./preview/PreviewViewModel.js";
import {Element} from "./client/clients/Element.js"; import {Element} from "./client/clients/Element.js";
import {Platform} from "./client/Platform.js";
export class RootViewModel extends ViewModel { export class RootViewModel extends ViewModel {
constructor(options) { constructor(options) {
@ -33,8 +34,6 @@ export class RootViewModel extends ViewModel {
this.previewViewModel = new PreviewViewModel(this.childOptions({ this.previewViewModel = new PreviewViewModel(this.childOptions({
link: this.link, link: this.link,
consentedServers: this.link.servers, consentedServers: this.link.servers,
// preferredClient: element,
// preferredPlatform: this.platforms[0],
clients: [element] clients: [element]
})); }));
this.previewViewModel.load(); this.previewViewModel.load();
@ -57,4 +56,13 @@ export class RootViewModel extends ViewModel {
} }
return ""; return "";
} }
clearPreferences() {
this.preferences.clear();
this._updateChildVMs();
}
get hasPreferences() {
return this.preferences.canClear;
}
} }

View file

@ -1,6 +1,7 @@
import {xhrRequest} from "./utils/xhr.js"; import {xhrRequest} from "./utils/xhr.js";
import {RootViewModel} from "./RootViewModel.js"; import {RootViewModel} from "./RootViewModel.js";
import {RootView} from "./RootView.js"; import {RootView} from "./RootView.js";
import {Preferences} from "./Preferences.js";
import {guessApplicablePlatforms} from "./client/Platform.js"; import {guessApplicablePlatforms} from "./client/Platform.js";
export async function main(container) { export async function main(container) {
@ -8,6 +9,7 @@ export async function main(container) {
request: xhrRequest, request: xhrRequest,
openLink: url => location.href = url, openLink: url => location.href = url,
platforms: guessApplicablePlatforms(navigator.userAgent), platforms: guessApplicablePlatforms(navigator.userAgent),
preferences: new Preferences(window.localStorage),
}); });
vm.updateHash(location.hash); vm.updateHash(location.hash);
window.__rootvm = vm; window.__rootvm = vm;

View file

@ -18,20 +18,16 @@ import {LinkKind} from "../Link.js";
import {ViewModel} from "../utils/ViewModel.js"; import {ViewModel} from "../utils/ViewModel.js";
import {resolveServer} from "./HomeServer.js"; import {resolveServer} from "./HomeServer.js";
import {ClientListViewModel} from "../client/ClientListViewModel.js"; import {ClientListViewModel} from "../client/ClientListViewModel.js";
import {ClientViewModel} from "../client/ClientViewModel.js";
export class PreviewViewModel extends ViewModel { export class PreviewViewModel extends ViewModel {
constructor(options) { constructor(options) {
super(options); super(options);
const { const { link, consentedServers, clients } = options;
link, consentedServers,
preferredClient, preferredPlatform, clients
} = options;
this._link = link; this._link = link;
this._consentedServers = consentedServers; this._consentedServers = consentedServers;
this._preferredClient = preferredClient;
// used to differentiate web from native if a client supports both
this._preferredPlatform = preferredPlatform;
this._clients = clients; this._clients = clients;
this._preferredClient = this.preferences.clientId ? clients.find(c => c.id === this.preferences.clientId) : null;
this.loading = false; this.loading = false;
this.name = null; this.name = null;
@ -39,6 +35,7 @@ export class PreviewViewModel extends ViewModel {
this.previewDomain = null; this.previewDomain = null;
this.clientsViewModel = null; this.clientsViewModel = null;
this.acceptInstructions = null; this.acceptInstructions = null;
this.missingClientViewModel = null;
} }
async load() { async load() {
@ -76,7 +73,7 @@ export class PreviewViewModel extends ViewModel {
get acceptLabel() { get acceptLabel() {
if (this._preferredClient) { if (this._preferredClient) {
return `Open in ${this._preferredClient.getName(this._preferredPlatform)}`; return `Open in ${this._preferredClient.getName(this.preferences.platform)}`;
} else { } else {
return "Choose app"; return "Choose app";
} }
@ -84,17 +81,16 @@ export class PreviewViewModel extends ViewModel {
accept() { accept() {
if (this._preferredClient) { if (this._preferredClient) {
if (this._preferredClient.getLinkSupport(this._preferredPlatform, this._link)) { if (this._preferredClient.getLinkSupport(this.preferences.platform, this._link)) {
const deepLink = this._preferredClient.getDeepLink(this._preferredPlatform, this._link); const deepLink = this._preferredClient.getDeepLink(this.preferences.platform, this._link);
this.openLink(deepLink); this.openLink(deepLink);
// show "looks like you don't have the native app installed"
const protocol = new URL(deepLink).protocol; const protocol = new URL(deepLink).protocol;
const isWebProtocol = protocol === "http:" || protocol === "https:"; const isWebProtocol = protocol === "http:" || protocol === "https:";
if (!isWebProtocol) { if (!isWebProtocol) {
this.missingClientViewModel = new ClientViewModel(this.childOptions({client: this._preferredClient, link: this._link})); this.missingClientViewModel = new ClientViewModel(this.childOptions({client: this._preferredClient, link: this._link}));
} }
} else { } else {
this.acceptInstructions = this._preferredClient.getLinkInstructions(this._preferredPlatform, this._link); this.acceptInstructions = this._preferredClient.getLinkInstructions(this.preferences.platform, this._link);
} }
} else { } else {
this.clientsViewModel = new ClientListViewModel(this.childOptions({clients: this._clients, link: this._link})); this.clientsViewModel = new ClientListViewModel(this.childOptions({clients: this._clients, link: this._link}));

View file

@ -63,12 +63,14 @@ export class ViewModel extends EventEmitter {
get request() { return this._options.request; } get request() { return this._options.request; }
get openLink() { return this._options.openLink; } get openLink() { return this._options.openLink; }
get platforms() { return this._options.platforms; } get platforms() { return this._options.platforms; }
get preferences() { return this._options.preferences; }
childOptions(options = {}) { childOptions(options = {}) {
return Object.assign({ return Object.assign({
request: this.request, request: this.request,
openLink: this.openLink, openLink: this.openLink,
platforms: this.platforms, platforms: this.platforms,
preferences: this.preferences,
}, options); }, options);
} }
} }