This commit is contained in:
Bruno Windels 2020-10-16 18:06:20 +02:00
parent 41d624a1ae
commit 974f77a71d
11 changed files with 197 additions and 7 deletions

View file

@ -125,7 +125,10 @@ export class RootViewModel extends ViewModel {
_showSession(sessionContainer) {
this._setSection(() => {
this._sessionViewModel = new SessionViewModel(this.childOptions({sessionContainer}));
this._sessionViewModel = new SessionViewModel(this.childOptions({
sessionContainer,
updateService: this.getOption("updateService")
}));
this._sessionViewModel.start();
});
}

View file

@ -34,6 +34,11 @@ export class ViewModel extends EventEmitter {
return Object.assign({navigation, urlCreator, clock}, explicitOptions);
}
// makes it easier to pass through dependencies of a sub-view model
getOption(name) {
return this._options[name];
}
track(disposable) {
if (!this.disposables) {
this.disposables = new Disposables();

View file

@ -19,6 +19,7 @@ import {LeftPanelViewModel} from "./leftpanel/LeftPanelViewModel.js";
import {RoomViewModel} from "./room/RoomViewModel.js";
import {SessionStatusViewModel} from "./SessionStatusViewModel.js";
import {RoomGridViewModel} from "./RoomGridViewModel.js";
import {SettingsViewModel} from "./SettingsViewModel.js";
import {ViewModel} from "../ViewModel.js";
export class SessionViewModel extends ViewModel {
@ -34,6 +35,7 @@ export class SessionViewModel extends ViewModel {
this._leftPanelViewModel = this.track(new LeftPanelViewModel(this.childOptions({
rooms: this._sessionContainer.session.rooms
})));
this._settingsViewModel = null;
this._currentRoomViewModel = null;
this._gridViewModel = null;
this._setupNavigation();
@ -53,12 +55,18 @@ export class SessionViewModel extends ViewModel {
// this gives us the active room
this.track(currentRoomId.subscribe(roomId => {
if (!this._gridViewModel) {
this._openRoom(roomId);
this._updateRoom(roomId);
}
}));
if (currentRoomId.get() && !this._gridViewModel) {
this._openRoom(currentRoomId.get());
if (!this._gridViewModel) {
this._updateRoom(currentRoomId.get());
}
const settings = this.navigation.observe("settings");
this.track(settings.subscribe(settingsOpen => {
this._updateSettings(settingsOpen);
}));
this._updateSettings(settings.get());
}
get id() {
@ -74,6 +82,8 @@ export class SessionViewModel extends ViewModel {
return this._currentRoomViewModel.id;
} else if (this._gridViewModel) {
return "roomgrid";
} else if (this._settingsViewModel) {
return "settings";
}
return "placeholder";
}
@ -90,6 +100,10 @@ export class SessionViewModel extends ViewModel {
return this._sessionStatusViewModel;
}
get settingsViewModel() {
return this._settingsViewModel;
}
get roomList() {
return this._roomList;
}
@ -148,7 +162,7 @@ export class SessionViewModel extends ViewModel {
return roomVM;
}
_openRoom(roomId) {
_updateRoom(roomId) {
if (!roomId) {
if (this._currentRoomViewModel) {
this._currentRoomViewModel = this.disposeTracked(this._currentRoomViewModel);
@ -167,4 +181,17 @@ export class SessionViewModel extends ViewModel {
}
this.emitChange("currentRoom");
}
_updateSettings(settingsOpen) {
if (this._settingsViewModel) {
this._settingsViewModel = this.disposeTracked(this._settingsViewModel);
}
if (settingsOpen) {
this._settingsViewModel = this.track(new SettingsViewModel(this.childOptions({
updateService: this.getOption("updateService"),
session: this._sessionContainer.session
})));
}
this.emitChange("activeSection");
}
}

View file

@ -0,0 +1,65 @@
/*
Copyright 2020 Bruno Windels <bruno@windels.cloud>
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 "../ViewModel.js";
export class SettingsViewModel extends ViewModel {
constructor(options) {
super(options);
this._updateService = options.updateService;
this._session = options.session;
this._closeUrl = this.urlCreator.urlUntilSegment("session");
}
get closeUrl() {
return this._closeUrl;
}
get fingerprintKey() {
const key = this._session.fingerprintKey;
const partLength = 4;
const partCount = Math.ceil(key.length / partLength);
let formattedKey = "";
for (let i = 0; i < partCount; i += 1) {
formattedKey += (formattedKey.length ? " " : "") + key.slice(i * partLength, (i + 1) * partLength);
}
return formattedKey;
}
get deviceId() {
return this._session.deviceId;
}
get userId() {
return this._session.userId;
}
get version() {
if (this._updateService) {
return `${this._updateService.version} (${this._updateService.buildHash})`;
}
return "development version";
}
checkForUpdate() {
this._updateService?.checkForUpdate();
}
get showUpdateButton() {
return !!this._updateService;
}
}

View file

@ -45,12 +45,17 @@ export class LeftPanelViewModel extends ViewModel {
this._currentTileVM = null;
this._setupNavigation();
this._closeUrl = this.urlCreator.urlForSegment("session");
this._settingsUrl = this.urlCreator.urlForSegment("settings");
}
get closeUrl() {
return this._closeUrl;
}
get settingsUrl() {
return this._settingsUrl;
}
_setupNavigation() {
const roomObservable = this.navigation.observe("room");
this.track(roomObservable.subscribe(roomId => this._open(roomId)));

View file

@ -77,6 +77,18 @@ export class Session {
this.needsSessionBackup = new ObservableValue(false);
}
get fingerprintKey() {
return this._e2eeAccount?.identityKeys.ed25519;
}
get deviceId() {
return this._sessionInfo.deviceId;
}
get userId() {
return this._sessionInfo.userId;
}
// called once this._e2eeAccount is assigned
_setupEncryption() {
console.log("loaded e2ee account with keys", this._e2eeAccount.identityKeys);

View file

@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M19.3625 9.2875C19.5625 9.8125 20.075 10.1625 20.6375 10.1625C21.3875 10.1625 22 10.775 22 11.525V12.475C22 13.225 21.3875 13.8375 20.6375 13.8375C20.075 13.8375 19.5625 14.1875 19.3625 14.7125C19.346 14.7538 19.3294 14.7958 19.3128 14.838C19.2538 14.9876 19.1932 15.1413 19.125 15.2875C18.8875 15.8 19 16.4 19.4 16.8C19.9375 17.325 19.9375 18.1875 19.4 18.725L18.725 19.4C18.2 19.9375 17.3375 19.9375 16.8 19.4C16.4125 19 15.8 18.8875 15.2875 19.125C15.1 19.2125 14.9125 19.2875 14.7125 19.3625C14.1875 19.5625 13.8375 20.075 13.8375 20.6375C13.8375 21.3875 13.225 22 12.475 22H11.525C10.775 22 10.1625 21.3875 10.1625 20.6375C10.1625 20.075 9.8125 19.5625 9.2875 19.3625C9.24617 19.346 9.20423 19.3294 9.16195 19.3128C9.01243 19.2538 8.85867 19.1932 8.7125 19.125C8.2 18.8875 7.6 19 7.2 19.4C6.675 19.9375 5.8125 19.9375 5.275 19.4L4.6 18.725C4.0625 18.2 4.0625 17.3375 4.6 16.8C5 16.4125 5.1125 15.8 4.875 15.2875C4.7875 15.1 4.7125 14.9125 4.6375 14.7125C4.4375 14.1875 3.925 13.8375 3.3625 13.8375C2.6125 13.8375 2 13.225 2 12.475V11.525C2 10.775 2.6125 10.1625 3.3625 10.1625C3.925 10.1625 4.4375 9.8125 4.6375 9.2875C4.67694 9.16129 4.72634 9.04005 4.77627 8.91751C4.80546 8.84587 4.83483 8.77379 4.8625 8.7C5.1 8.1875 4.9875 7.5875 4.5875 7.1875C4.05 6.6625 4.05 5.8 4.5875 5.2625L5.275 4.6C5.8 4.0625 6.6625 4.0625 7.2 4.6C7.5875 5 8.2 5.1125 8.7125 4.875C8.9 4.7875 9.0875 4.7 9.2875 4.6375C9.8125 4.4375 10.1625 3.925 10.1625 3.3625C10.1625 2.6125 10.775 2 11.525 2H12.475C13.225 2 13.8375 2.6125 13.8375 3.3625C13.8375 3.9375 14.1875 4.4375 14.7125 4.6375C14.7538 4.65403 14.7958 4.67056 14.838 4.68723C14.9876 4.74617 15.1413 4.80679 15.2875 4.875C15.8 5.1125 16.4 5 16.8 4.6C17.325 4.0625 18.1875 4.0625 18.725 4.6L19.4 5.275C19.9375 5.8 19.9375 6.6625 19.4 7.2C19 7.5875 18.8875 8.2 19.125 8.7125C19.2125 8.9 19.2875 9.0875 19.3625 9.2875ZM12 17C9.2375 17 7 14.7625 7 12C7 9.2375 9.2375 7 12 7C14.7625 7 17 9.2375 17 12C17 14.7625 14.7625 17 12 17Z" fill="#8D99A5"/>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View file

@ -132,12 +132,17 @@ a.button-action {
background-repeat: no-repeat;
border: none;
border-radius: 100%;
display: block;
}
.button-utility.grid {
background-image: url('icons/enable-grid.svg');
}
.button-utility.settings {
background-image: url('icons/settings.svg');
}
.button-utility.grid.on {
background-image: url('icons/disable-grid.svg');
}
@ -541,3 +546,25 @@ ul.Timeline > li.messageStatus .message-container > p {
.GapView > :not(:first-child) {
margin-left: 12px;
}
.Settings {
flex: 1;
}
.Settings .row .label {
font-weight: 600;
}
.Settings .row.key .content {
font-family: monospace;
}
.Settings .row {
margin: 12px;
display: flex;
flex-wrap: wrap;
}
.Settings .row .label {
flex: 0 0 200px;
}

View file

@ -152,6 +152,14 @@ export class ServiceWorkerHandler {
this._registration.update();
}
get version() {
return window.HYDROGEN_VERSION;
}
get buildHash() {
return window.HYDROGEN_GLOBAL_HASH;
}
async preventConcurrentSessionAccess(sessionId) {
return this._sendAndWaitForReply("closeSession", {sessionId});
}

View file

@ -38,6 +38,8 @@ export class SessionView extends TemplateView {
return new RoomGridView(vm.roomGridViewModel);
case "placeholder":
return new StaticView(t => t.div({className: "room-placeholder"}, t.h2(vm.i18n`Choose a room on the left side.`)));
case "settings":
return new SettingsView(vm.settingsViewModel);
default: //room id
return new RoomView(vm.currentRoomViewModel);
}
@ -46,3 +48,35 @@ export class SessionView extends TemplateView {
]);
}
}
class SettingsView extends TemplateView {
render(t, vm) {
let version = vm.version;
if (vm.showUpdateButton) {
version = t.span([
vm.version,
t.button({onClick: () => vm.checkForUpdate()}, vm.i18n`Check for updates`)
]);
}
const row = (label, content, extraClass = "") => {
return t.div({className: `row ${extraClass}`}, [
t.div({className: "label"}, label),
t.div({className: "content"}, content),
]);
};
return t.div({className: "Settings"}, [
t.div({className: "header"}, [
t.a({className: "button-utility close-room", href: vm.closeUrl, title: vm.i18n`Close room`}),
t.h2("Settings")
]),
t.div([
row(vm.i18n`User ID`, vm.userId),
row(vm.i18n`Session ID`, vm.deviceId),
row(vm.i18n`Session key`, vm.fingerprintKey, "key"),
row(vm.i18n`Version`, version),
])
]);
}
}

View file

@ -57,7 +57,7 @@ export class LeftPanelView extends TemplateView {
vm.i18n`Enable grid layout`;
};
const utilitiesRow = t.div({className: "utilities"}, [
t.a({className: "button-utility close-session", href: vm.closeUrl}),
t.a({className: "button-utility close-session", href: vm.closeUrl, "aria-label": vm.i18n`Back to account list`, title: vm.i18n`Back to account list`}),
t.view(new FilterField({
i18n: vm.i18n,
label: vm.i18n`Filter rooms…`,
@ -75,7 +75,8 @@ export class LeftPanelView extends TemplateView {
},
title: gridButtonLabel,
"aria-label": gridButtonLabel
})
}),
t.a({className: "button-utility settings", href: vm.settingsUrl, "aria-label": vm.i18n`Settings`, title: vm.i18n`Settings`}),
]);
return t.div({className: "LeftPanel"}, [