basic view model setup

This commit is contained in:
Bruno Windels 2022-03-17 13:04:14 +01:00
parent e482e3aeef
commit e760b8e556
6 changed files with 78 additions and 9 deletions

View File

@ -174,7 +174,7 @@ export class SessionViewModel extends ViewModel {
_createRoomViewModelInstance(roomId) {
const room = this._client.session.rooms.get(roomId);
if (room) {
const roomVM = new RoomViewModel(this.childOptions({room}));
const roomVM = new RoomViewModel(this.childOptions({room, session: this._client.session}));
roomVM.load();
return roomVM;
}

View File

@ -0,0 +1,34 @@
/*
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";
import type {GroupCall} from "../../../matrix/calls/group/GroupCall";
export class CallViewModel extends ViewModel {
private call: GroupCall;
constructor(options) {
super(options);
const {call} = options;
this.call = call;
}
get name(): string {
return this.call.name;
}
}

View File

@ -17,15 +17,18 @@ limitations under the License.
import {TimelineViewModel} from "./timeline/TimelineViewModel.js";
import {ComposerViewModel} from "./ComposerViewModel.js"
import {CallViewModel} from "./CallViewModel"
import {PickMapObservableValue} from "../../../observable/value/PickMapObservableValue";
import {avatarInitials, getIdentifierColorNumber, getAvatarHttpUrl} from "../../avatar";
import {tilesCreator} from "./timeline/tilesCreator.js";
import {ViewModel} from "../../ViewModel";
import {imageToInfo} from "../common.js";
import {LocalMedia} from "../../../matrix/calls/LocalMedia";
export class RoomViewModel extends ViewModel {
constructor(options) {
super(options);
const {room} = options;
const {room, session} = options;
this._room = room;
this._timelineVM = null;
this._tilesCreator = null;
@ -40,6 +43,19 @@ export class RoomViewModel extends ViewModel {
}
this._clearUnreadTimout = null;
this._closeUrl = this.urlCreator.urlUntilSegment("session");
// pick call for this room with lowest key
this._callObservable = new PickMapObservableValue(session.callHandler.calls.filterValues(c => c.roomId === this.roomId));
this._callViewModel = undefined;
this.track(this._callObservable.subscribe(call => {
this._callViewModel = this.disposeTracked(this._callViewModel);
if (call) {
this._callViewModel = new CallViewModel(this.childOptions({call}));
}
this.emitChange("callViewModel");
}));
if (this._callObservable.get()) {
this._callViewModel = new CallViewModel(this.childOptions({call: this._callObservable.get()}));
}
}
async load() {
@ -308,6 +324,10 @@ export class RoomViewModel extends ViewModel {
return this._composerVM;
}
get callViewModel() {
return this._callViewModel;
}
openDetailsPanel() {
let path = this.navigation.path.until("room");
path = path.with(this.navigation.segment("right-panel", true));
@ -320,6 +340,13 @@ export class RoomViewModel extends ViewModel {
this._composerVM.setReplyingTo(entry);
}
}
async startCall() {
const mediaTracks = await this.platform.mediaDevices.getMediaTracks(true, true);
const localMedia = LocalMedia.fromTracks(mediaTracks);
// this will set the callViewModel above as a call will be added to callHandler.calls
await this.session.callHandler.createCall(this.roomId, localMedia, "A call " + Math.round(this.platform.random() * 100));
}
}
function videoToInfo(video) {

View File

@ -56,7 +56,7 @@ export class GroupCall {
constructor(
id: string | undefined,
private callContent: Record<string, any> | undefined,
private readonly roomId: string,
public readonly roomId: string,
private readonly options: Options
) {
this.id = id ?? makeId("conf-");
@ -77,6 +77,10 @@ export class GroupCall {
return this.callContent?.["m.terminated"] === true;
}
get name(): string {
return this.callContent?.["m.name"];
}
async join(localMedia: LocalMedia) {
if (this._state !== GroupCallState.Created) {
return;

View File

@ -22,7 +22,7 @@ function pickLowestKey<K>(currentKey: K, newKey: K): boolean {
return newKey < currentKey;
}
export class PickMapObservable<K, V> implements IMapObserver<K, V> extends BaseObservableValue<V | undefined> {
export class PickMapObservableValue<K, V> extends BaseObservableValue<V | undefined> implements IMapObserver<K, V>{
private key?: K;
private mapSubscription?: SubscriptionHandle;
@ -34,7 +34,7 @@ export class PickMapObservable<K, V> implements IMapObserver<K, V> extends BaseO
super();
}
private trySetKey(newKey: K): boolean {
private updateKey(newKey: K): boolean {
if (this.key === undefined || this.pickKey(this.key, newKey)) {
this.key = newKey;
return true;
@ -48,7 +48,7 @@ export class PickMapObservable<K, V> implements IMapObserver<K, V> extends BaseO
}
onAdd(key: K, value:V): void {
if (this.trySetKey(key)) {
if (this.updateKey(key)) {
this.emit(this.get());
}
}
@ -60,7 +60,7 @@ export class PickMapObservable<K, V> implements IMapObserver<K, V> extends BaseO
this.key = undefined;
let changed = false;
for (const [key] of this.map) {
changed = this.trySetKey(key) || changed;
changed = this.updateKey(key) || changed;
}
if (changed) {
this.emit(this.get());
@ -71,12 +71,12 @@ export class PickMapObservable<K, V> implements IMapObserver<K, V> extends BaseO
onSubscribeFirst(): void {
this.mapSubscription = this.map.subscribe(this);
for (const [key] of this.map) {
this.trySetKey(key);
this.updateKey(key);
}
}
onUnsubscribeLast(): void {
this.mapSubscription();
this.mapSubscription!();
this.key = undefined;
}

View File

@ -52,6 +52,9 @@ export class RoomView extends TemplateView {
]),
t.div({className: "RoomView_body"}, [
t.div({className: "RoomView_error"}, vm => vm.error),
t.map(vm => vm.callViewModel, (callViewModel, t) => {
return t.p(["A call is in progress", callViewModel => callViewModel.name])
}),
t.mapView(vm => vm.timelineViewModel, timelineViewModel => {
return timelineViewModel ?
new TimelineView(timelineViewModel) :
@ -69,6 +72,7 @@ export class RoomView extends TemplateView {
const vm = this.value;
const options = [];
options.push(Menu.option(vm.i18n`Room details`, () => vm.openDetailsPanel()))
options.push(Menu.option(vm.i18n`Start call`, () => vm.startCall()))
if (vm.canLeave) {
options.push(Menu.option(vm.i18n`Leave room`, () => this._confirmToLeaveRoom()).setDestructive());
}