forked from mystiq/hydrogen-web
move switching room view models to a dedicated observable
based on the observing the room status
This commit is contained in:
parent
6bb8e2fa43
commit
6c58c61da9
4 changed files with 196 additions and 122 deletions
|
@ -15,7 +15,6 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {ViewModel} from "../ViewModel.js";
|
import {ViewModel} from "../ViewModel.js";
|
||||||
import {removeRoomFromPath} from "../navigation/index.js";
|
|
||||||
|
|
||||||
function dedupeSparse(roomIds) {
|
function dedupeSparse(roomIds) {
|
||||||
return roomIds.map((id, idx) => {
|
return roomIds.map((id, idx) => {
|
||||||
|
@ -33,10 +32,9 @@ export class RoomGridViewModel extends ViewModel {
|
||||||
|
|
||||||
this._width = options.width;
|
this._width = options.width;
|
||||||
this._height = options.height;
|
this._height = options.height;
|
||||||
this._createRoomViewModel = options.createRoomViewModel;
|
this._createRoomViewModelObservable = options.createRoomViewModelObservable;
|
||||||
this._selectedIndex = 0;
|
this._selectedIndex = 0;
|
||||||
this._viewModels = [];
|
this._viewModelsObservables = [];
|
||||||
this._refreshRoomViewModel = this._refreshRoomViewModel.bind(this);
|
|
||||||
this._setupNavigation();
|
this._setupNavigation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,38 +53,17 @@ export class RoomGridViewModel extends ViewModel {
|
||||||
this.track(focusedRoom.subscribe(roomId => {
|
this.track(focusedRoom.subscribe(roomId => {
|
||||||
if (roomId) {
|
if (roomId) {
|
||||||
// as the room will be in the "rooms" observable
|
// as the room will be in the "rooms" observable
|
||||||
// (monitored by the parent vm) as well,
|
// (monitored by the parent vmo) as well,
|
||||||
// we only change the focus here and trust
|
// we only change the focus here and trust
|
||||||
// setRoomIds to have created the vm already
|
// setRoomIds to have created the vmo already
|
||||||
this._setFocusRoom(roomId);
|
this._setFocusRoom(roomId);
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
// initial focus for a room is set by initializeRoomIdsAndTransferVM
|
// initial focus for a room is set by initializeRoomIdsAndTransferVM
|
||||||
}
|
}
|
||||||
|
|
||||||
_refreshRoomViewModel(roomId) {
|
|
||||||
const index = this._viewModels.findIndex(vm => vm?.id === roomId);
|
|
||||||
if (index === -1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this._viewModels[index] = this.disposeTracked(this._viewModels[index]);
|
|
||||||
// this will create a RoomViewModel because the invite is already
|
|
||||||
// removed from the collection (see Invite.afterSync)
|
|
||||||
const roomVM = this._createRoomViewModel(roomId, this._refreshRoomViewModel);
|
|
||||||
if (roomVM) {
|
|
||||||
this._viewModels[index] = this.track(roomVM);
|
|
||||||
if (this.focusIndex === index) {
|
|
||||||
roomVM.focus();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// close room id
|
|
||||||
this.navigation.applyPath(removeRoomFromPath(this.navigation.path, roomId));
|
|
||||||
}
|
|
||||||
this.emitChange();
|
|
||||||
}
|
|
||||||
|
|
||||||
roomViewModelAt(i) {
|
roomViewModelAt(i) {
|
||||||
return this._viewModels[i];
|
return this._viewModelsObservables[i]?.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
get focusIndex() {
|
get focusIndex() {
|
||||||
|
@ -105,9 +82,9 @@ export class RoomGridViewModel extends ViewModel {
|
||||||
if (index === this._selectedIndex) {
|
if (index === this._selectedIndex) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const vm = this._viewModels[index];
|
const vmo = this._viewModelsObservables[index];
|
||||||
if (vm) {
|
if (vmo) {
|
||||||
this.navigation.push("room", vm.id);
|
this.navigation.push("room", vmo.id);
|
||||||
} else {
|
} else {
|
||||||
this.navigation.push("empty-grid-tile", index);
|
this.navigation.push("empty-grid-tile", index);
|
||||||
}
|
}
|
||||||
|
@ -120,7 +97,8 @@ export class RoomGridViewModel extends ViewModel {
|
||||||
if (existingRoomVM) {
|
if (existingRoomVM) {
|
||||||
const index = roomIds.indexOf(existingRoomVM.id);
|
const index = roomIds.indexOf(existingRoomVM.id);
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
this._viewModels[index] = this.track(existingRoomVM);
|
this._viewModelsObservables[index] = this.track(existingRoomVM);
|
||||||
|
existingRoomVM.subscribe(viewModel => this._refreshRoomViewModel(viewModel));
|
||||||
transfered = true;
|
transfered = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -128,7 +106,7 @@ export class RoomGridViewModel extends ViewModel {
|
||||||
// now all view models exist, set the focus to the selected room
|
// now all view models exist, set the focus to the selected room
|
||||||
const focusedRoom = this.navigation.path.get("room");
|
const focusedRoom = this.navigation.path.get("room");
|
||||||
if (focusedRoom) {
|
if (focusedRoom) {
|
||||||
const index = this._viewModels.findIndex(vm => vm && vm.id === focusedRoom.value);
|
const index = this._viewModelsObservables.findIndex(vmo => vmo && vmo.id === focusedRoom.value);
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
this._selectedIndex = index;
|
this._selectedIndex = index;
|
||||||
}
|
}
|
||||||
|
@ -143,17 +121,17 @@ export class RoomGridViewModel extends ViewModel {
|
||||||
const len = this._height * this._width;
|
const len = this._height * this._width;
|
||||||
for (let i = 0; i < len; i += 1) {
|
for (let i = 0; i < len; i += 1) {
|
||||||
const newId = roomIds[i];
|
const newId = roomIds[i];
|
||||||
const vm = this._viewModels[i];
|
const vmo = this._viewModelsObservables[i];
|
||||||
// did anything change?
|
// did anything change?
|
||||||
if ((!vm && newId) || (vm && vm.id !== newId)) {
|
if ((!vmo && newId) || (vmo && vmo.id !== newId)) {
|
||||||
if (vm) {
|
if (vmo) {
|
||||||
this._viewModels[i] = this.disposeTracked(vm);
|
this._viewModelsObservables[i] = this.disposeTracked(vmo);
|
||||||
}
|
}
|
||||||
if (newId) {
|
if (newId) {
|
||||||
const newVM = this._createRoomViewModel(newId, this._refreshRoomViewModel);
|
const vmo = this._createRoomViewModelObservable(newId);
|
||||||
if (newVM) {
|
this._viewModelsObservables[i] = this.track(vmo);
|
||||||
this._viewModels[i] = this.track(newVM);
|
vmo.subscribe(viewModel => this._refreshRoomViewModel(viewModel));
|
||||||
}
|
vmo.initialize();
|
||||||
}
|
}
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
|
@ -164,14 +142,20 @@ export class RoomGridViewModel extends ViewModel {
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_refreshRoomViewModel(viewModel) {
|
||||||
|
this.emitChange();
|
||||||
|
viewModel?.focus();
|
||||||
|
}
|
||||||
|
|
||||||
/** called from SessionViewModel */
|
/** called from SessionViewModel */
|
||||||
releaseRoomViewModel(roomId) {
|
releaseRoomViewModel(roomId) {
|
||||||
const index = this._viewModels.findIndex(vm => vm && vm.id === roomId);
|
const index = this._viewModelsObservables.findIndex(vmo => vmo && vmo.id === roomId);
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
const vm = this._viewModels[index];
|
const vmo = this._viewModelsObservables[index];
|
||||||
this.untrack(vm);
|
this.untrack(vmo);
|
||||||
this._viewModels[index] = null;
|
vmo.unsubscribeAll();
|
||||||
return vm;
|
this._viewModelsObservables[index] = null;
|
||||||
|
return vmo;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,13 +164,13 @@ export class RoomGridViewModel extends ViewModel {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this._selectedIndex = idx;
|
this._selectedIndex = idx;
|
||||||
const vm = this._viewModels[this._selectedIndex];
|
const vmo = this._viewModelsObservables[this._selectedIndex];
|
||||||
vm?.focus();
|
vmo?.get()?.focus();
|
||||||
this.emitChange("focusIndex");
|
this.emitChange("focusIndex");
|
||||||
}
|
}
|
||||||
|
|
||||||
_setFocusRoom(roomId) {
|
_setFocusRoom(roomId) {
|
||||||
const index = this._viewModels.findIndex(vm => vm?.id === roomId);
|
const index = this._viewModelsObservables.findIndex(vmo => vmo?.id === roomId);
|
||||||
if (index >= 0) {
|
if (index >= 0) {
|
||||||
this._setFocusIndex(index);
|
this._setFocusIndex(index);
|
||||||
}
|
}
|
||||||
|
@ -194,6 +178,8 @@ export class RoomGridViewModel extends ViewModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
import {createNavigation} from "../navigation/index.js";
|
import {createNavigation} from "../navigation/index.js";
|
||||||
|
import {ObservableValue} from "../../observable/ObservableValue.js";
|
||||||
|
|
||||||
export function tests() {
|
export function tests() {
|
||||||
class RoomVMMock {
|
class RoomVMMock {
|
||||||
constructor(id) {
|
constructor(id) {
|
||||||
|
@ -209,6 +195,12 @@ export function tests() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class RoomViewModelObservableMock extends ObservableValue {
|
||||||
|
async initialize() {}
|
||||||
|
dispose() { this.get()?.dispose(); }
|
||||||
|
get id() { return this.get()?.id; }
|
||||||
|
}
|
||||||
|
|
||||||
function createNavigationForRoom(rooms, room) {
|
function createNavigationForRoom(rooms, room) {
|
||||||
const navigation = createNavigation();
|
const navigation = createNavigation();
|
||||||
navigation.applyPath(navigation.pathFrom([
|
navigation.applyPath(navigation.pathFrom([
|
||||||
|
@ -233,7 +225,7 @@ export function tests() {
|
||||||
"initialize with duplicate set of rooms": assert => {
|
"initialize with duplicate set of rooms": assert => {
|
||||||
const navigation = createNavigationForRoom(["c", "a", "b", undefined, "a"], "a");
|
const navigation = createNavigationForRoom(["c", "a", "b", undefined, "a"], "a");
|
||||||
const gridVM = new RoomGridViewModel({
|
const gridVM = new RoomGridViewModel({
|
||||||
createRoomViewModel: id => new RoomVMMock(id),
|
createRoomViewModelObservable: id => new RoomViewModelObservableMock(new RoomVMMock(id)),
|
||||||
navigation,
|
navigation,
|
||||||
width: 3,
|
width: 3,
|
||||||
height: 2,
|
height: 2,
|
||||||
|
@ -250,12 +242,12 @@ export function tests() {
|
||||||
"transfer room view model": assert => {
|
"transfer room view model": assert => {
|
||||||
const navigation = createNavigationForRoom(["a"], "a");
|
const navigation = createNavigationForRoom(["a"], "a");
|
||||||
const gridVM = new RoomGridViewModel({
|
const gridVM = new RoomGridViewModel({
|
||||||
createRoomViewModel: () => assert.fail("no vms should be created"),
|
createRoomViewModelObservable: () => assert.fail("no vms should be created"),
|
||||||
navigation,
|
navigation,
|
||||||
width: 3,
|
width: 3,
|
||||||
height: 2,
|
height: 2,
|
||||||
});
|
});
|
||||||
const existingRoomVM = new RoomVMMock("a");
|
const existingRoomVM = new RoomViewModelObservableMock(new RoomVMMock("a"));
|
||||||
const transfered = gridVM.initializeRoomIdsAndTransferVM(navigation.path.get("rooms").value, existingRoomVM);
|
const transfered = gridVM.initializeRoomIdsAndTransferVM(navigation.path.get("rooms").value, existingRoomVM);
|
||||||
assert.equal(transfered, true);
|
assert.equal(transfered, true);
|
||||||
assert.equal(gridVM.focusIndex, 0);
|
assert.equal(gridVM.focusIndex, 0);
|
||||||
|
@ -264,12 +256,12 @@ export function tests() {
|
||||||
"reject transfer for non-matching room view model": assert => {
|
"reject transfer for non-matching room view model": assert => {
|
||||||
const navigation = createNavigationForRoom(["a"], "a");
|
const navigation = createNavigationForRoom(["a"], "a");
|
||||||
const gridVM = new RoomGridViewModel({
|
const gridVM = new RoomGridViewModel({
|
||||||
createRoomViewModel: id => new RoomVMMock(id),
|
createRoomViewModelObservable: id => new RoomViewModelObservableMock(new RoomVMMock(id)),
|
||||||
navigation,
|
navigation,
|
||||||
width: 3,
|
width: 3,
|
||||||
height: 2,
|
height: 2,
|
||||||
});
|
});
|
||||||
const existingRoomVM = new RoomVMMock("f");
|
const existingRoomVM = new RoomViewModelObservableMock(new RoomVMMock("f"));
|
||||||
const transfered = gridVM.initializeRoomIdsAndTransferVM(navigation.path.get("rooms").value, existingRoomVM);
|
const transfered = gridVM.initializeRoomIdsAndTransferVM(navigation.path.get("rooms").value, existingRoomVM);
|
||||||
assert.equal(transfered, false);
|
assert.equal(transfered, false);
|
||||||
assert.equal(gridVM.focusIndex, 0);
|
assert.equal(gridVM.focusIndex, 0);
|
||||||
|
@ -278,7 +270,7 @@ export function tests() {
|
||||||
"created & released room view model is not disposed": assert => {
|
"created & released room view model is not disposed": assert => {
|
||||||
const navigation = createNavigationForRoom(["a"], "a");
|
const navigation = createNavigationForRoom(["a"], "a");
|
||||||
const gridVM = new RoomGridViewModel({
|
const gridVM = new RoomGridViewModel({
|
||||||
createRoomViewModel: id => new RoomVMMock(id),
|
createRoomViewModelObservable: id => new RoomViewModelObservableMock(new RoomVMMock(id)),
|
||||||
navigation,
|
navigation,
|
||||||
width: 3,
|
width: 3,
|
||||||
height: 2,
|
height: 2,
|
||||||
|
@ -287,27 +279,27 @@ export function tests() {
|
||||||
assert.equal(transfered, false);
|
assert.equal(transfered, false);
|
||||||
const releasedVM = gridVM.releaseRoomViewModel("a");
|
const releasedVM = gridVM.releaseRoomViewModel("a");
|
||||||
gridVM.dispose();
|
gridVM.dispose();
|
||||||
assert.equal(releasedVM.disposed, false);
|
assert.equal(releasedVM.get().disposed, false);
|
||||||
},
|
},
|
||||||
"transfered & released room view model is not disposed": assert => {
|
"transfered & released room view model is not disposed": assert => {
|
||||||
const navigation = createNavigationForRoom([undefined, "a"], "a");
|
const navigation = createNavigationForRoom([undefined, "a"], "a");
|
||||||
const gridVM = new RoomGridViewModel({
|
const gridVM = new RoomGridViewModel({
|
||||||
createRoomViewModel: () => assert.fail("no vms should be created"),
|
createRoomViewModelObservable: () => assert.fail("no vms should be created"),
|
||||||
navigation,
|
navigation,
|
||||||
width: 3,
|
width: 3,
|
||||||
height: 2,
|
height: 2,
|
||||||
});
|
});
|
||||||
const existingRoomVM = new RoomVMMock("a");
|
const existingRoomVM = new RoomViewModelObservableMock(new RoomVMMock("a"));
|
||||||
const transfered = gridVM.initializeRoomIdsAndTransferVM(navigation.path.get("rooms").value, existingRoomVM);
|
const transfered = gridVM.initializeRoomIdsAndTransferVM(navigation.path.get("rooms").value, existingRoomVM);
|
||||||
assert.equal(transfered, true);
|
assert.equal(transfered, true);
|
||||||
const releasedVM = gridVM.releaseRoomViewModel("a");
|
const releasedVM = gridVM.releaseRoomViewModel("a");
|
||||||
gridVM.dispose();
|
gridVM.dispose();
|
||||||
assert.equal(releasedVM.disposed, false);
|
assert.equal(releasedVM.get().disposed, false);
|
||||||
},
|
},
|
||||||
"try release non-existing room view model is": assert => {
|
"try release non-existing room view model is": assert => {
|
||||||
const navigation = createNavigationForEmptyTile([undefined, "b"], 3);
|
const navigation = createNavigationForEmptyTile([undefined, "b"], 3);
|
||||||
const gridVM = new RoomGridViewModel({
|
const gridVM = new RoomGridViewModel({
|
||||||
createRoomViewModel: id => new RoomVMMock(id),
|
createRoomViewModelObservable: id => new RoomViewModelObservableMock(new RoomVMMock(id)),
|
||||||
navigation,
|
navigation,
|
||||||
width: 3,
|
width: 3,
|
||||||
height: 2,
|
height: 2,
|
||||||
|
@ -319,7 +311,7 @@ export function tests() {
|
||||||
"initial focus is set to empty tile": assert => {
|
"initial focus is set to empty tile": assert => {
|
||||||
const navigation = createNavigationForEmptyTile(["a"], 1);
|
const navigation = createNavigationForEmptyTile(["a"], 1);
|
||||||
const gridVM = new RoomGridViewModel({
|
const gridVM = new RoomGridViewModel({
|
||||||
createRoomViewModel: id => new RoomVMMock(id),
|
createRoomViewModelObservable: id => new RoomViewModelObservableMock(new RoomVMMock(id)),
|
||||||
navigation,
|
navigation,
|
||||||
width: 3,
|
width: 3,
|
||||||
height: 2,
|
height: 2,
|
||||||
|
@ -331,7 +323,7 @@ export function tests() {
|
||||||
"change room ids after creation": assert => {
|
"change room ids after creation": assert => {
|
||||||
const navigation = createNavigationForRoom(["a", "b"], "a");
|
const navigation = createNavigationForRoom(["a", "b"], "a");
|
||||||
const gridVM = new RoomGridViewModel({
|
const gridVM = new RoomGridViewModel({
|
||||||
createRoomViewModel: id => new RoomVMMock(id),
|
createRoomViewModelObservable: id => new RoomViewModelObservableMock(new RoomVMMock(id)),
|
||||||
navigation,
|
navigation,
|
||||||
width: 3,
|
width: 3,
|
||||||
height: 2,
|
height: 2,
|
||||||
|
|
81
src/domain/session/RoomViewModelObservable.js
Normal file
81
src/domain/session/RoomViewModelObservable.js
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
/*
|
||||||
|
Copyright 2021 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 {ObservableValue} from "../../observable/ObservableValue.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
Depending on the status of a room (invited, joined, archived, or none),
|
||||||
|
we want to show a different view with a different view model
|
||||||
|
when showing a room. Furthermore, this logic is needed both in the
|
||||||
|
single room view and in the grid view. So this logic is extracted here,
|
||||||
|
and this observable updates with the right view model as the status for
|
||||||
|
a room changes.
|
||||||
|
|
||||||
|
To not have to track the subscription manually in the SessionViewModel and
|
||||||
|
the RoomGridViewModel, all subscriptions are removed in the dispose method.
|
||||||
|
Only when transferring a RoomViewModelObservable between the SessionViewModel
|
||||||
|
and RoomGridViewModel, unsubscribeAll should be called prior to doing
|
||||||
|
the transfer, so either parent view model don't keep getting updates for
|
||||||
|
the now transferred child view model.
|
||||||
|
|
||||||
|
This is also why there is an explicit initialize method, see comment there.
|
||||||
|
*/
|
||||||
|
export class RoomViewModelObservable extends ObservableValue {
|
||||||
|
constructor(sessionViewModel, roomId) {
|
||||||
|
super(null);
|
||||||
|
this._sessionViewModel = sessionViewModel;
|
||||||
|
this.id = roomId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Separate initialize method rather than doing this onSubscribeFirst because
|
||||||
|
we don't want to run this again when transferring this value between
|
||||||
|
SessionViewModel and RoomGridViewModel, as onUnsubscribeLast and onSubscribeFirst
|
||||||
|
are called in that case.
|
||||||
|
*/
|
||||||
|
async initialize() {
|
||||||
|
const {session} = this._sessionViewModel._sessionContainer;
|
||||||
|
this._statusObservable = await session.observeRoomStatus(this.id);
|
||||||
|
this.set(await this._statusToViewModel(this._statusObservable.get()));
|
||||||
|
this._statusObservable.subscribe(async status => {
|
||||||
|
this.set(await this._statusToViewModel(status));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async _statusToViewModel(status) {
|
||||||
|
if (status.invited) {
|
||||||
|
return this._sessionViewModel._createInviteViewModel(this.id);
|
||||||
|
} else if (status.joined) {
|
||||||
|
return this._sessionViewModel._createRoomViewModel(this.id);
|
||||||
|
} else if (status.archived) {
|
||||||
|
if (!this.get() || this.get().kind !== "room") {
|
||||||
|
return await this._sessionViewModel._createArchivedRoomViewModel(this.id);
|
||||||
|
} else {
|
||||||
|
// reuse existing Room
|
||||||
|
return this.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
dispose() {
|
||||||
|
if (this._statusSubscription) {
|
||||||
|
this._statusSubscription = this._statusSubscription();
|
||||||
|
}
|
||||||
|
this.unsubscribeAll();
|
||||||
|
this.get()?.dispose();
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,7 +15,6 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {removeRoomFromPath} from "../navigation/index.js";
|
|
||||||
import {LeftPanelViewModel} from "./leftpanel/LeftPanelViewModel.js";
|
import {LeftPanelViewModel} from "./leftpanel/LeftPanelViewModel.js";
|
||||||
import {RoomViewModel} from "./room/RoomViewModel.js";
|
import {RoomViewModel} from "./room/RoomViewModel.js";
|
||||||
import {InviteViewModel} from "./room/InviteViewModel.js";
|
import {InviteViewModel} from "./room/InviteViewModel.js";
|
||||||
|
@ -24,6 +23,7 @@ import {SessionStatusViewModel} from "./SessionStatusViewModel.js";
|
||||||
import {RoomGridViewModel} from "./RoomGridViewModel.js";
|
import {RoomGridViewModel} from "./RoomGridViewModel.js";
|
||||||
import {SettingsViewModel} from "./settings/SettingsViewModel.js";
|
import {SettingsViewModel} from "./settings/SettingsViewModel.js";
|
||||||
import {ViewModel} from "../ViewModel.js";
|
import {ViewModel} from "../ViewModel.js";
|
||||||
|
import {RoomViewModelObservable} from "./RoomViewModelObservable.js";
|
||||||
|
|
||||||
export class SessionViewModel extends ViewModel {
|
export class SessionViewModel extends ViewModel {
|
||||||
constructor(options) {
|
constructor(options) {
|
||||||
|
@ -40,10 +40,8 @@ export class SessionViewModel extends ViewModel {
|
||||||
rooms: this._sessionContainer.session.rooms
|
rooms: this._sessionContainer.session.rooms
|
||||||
})));
|
})));
|
||||||
this._settingsViewModel = null;
|
this._settingsViewModel = null;
|
||||||
this._currentRoomViewModel = null;
|
this._roomViewModelObservable = null;
|
||||||
this._gridViewModel = null;
|
this._gridViewModel = null;
|
||||||
this._refreshRoomViewModel = this._refreshRoomViewModel.bind(this);
|
|
||||||
this._createRoomViewModel = this._createRoomViewModel.bind(this);
|
|
||||||
this._setupNavigation();
|
this._setupNavigation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,7 +88,7 @@ export class SessionViewModel extends ViewModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
get activeMiddleViewModel() {
|
get activeMiddleViewModel() {
|
||||||
return this._currentRoomViewModel || this._gridViewModel || this._settingsViewModel;
|
return this._roomViewModelObservable?.get() || this._gridViewModel || this._settingsViewModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
get roomGridViewModel() {
|
get roomGridViewModel() {
|
||||||
|
@ -110,7 +108,7 @@ export class SessionViewModel extends ViewModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
get currentRoomViewModel() {
|
get currentRoomViewModel() {
|
||||||
return this._currentRoomViewModel;
|
return this._roomViewModelObservable?.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
_updateGrid(roomIds) {
|
_updateGrid(roomIds) {
|
||||||
|
@ -121,12 +119,14 @@ export class SessionViewModel extends ViewModel {
|
||||||
this._gridViewModel = this.track(new RoomGridViewModel(this.childOptions({
|
this._gridViewModel = this.track(new RoomGridViewModel(this.childOptions({
|
||||||
width: 3,
|
width: 3,
|
||||||
height: 2,
|
height: 2,
|
||||||
createRoomViewModel: this._createRoomViewModel,
|
createRoomViewModelObservable: roomId => new RoomViewModelObservable(this, roomId),
|
||||||
})));
|
})));
|
||||||
if (this._gridViewModel.initializeRoomIdsAndTransferVM(roomIds, this._currentRoomViewModel)) {
|
// try to transfer the current room view model, so we don't have to reload the timeline
|
||||||
this._currentRoomViewModel = this.untrack(this._currentRoomViewModel);
|
this._roomViewModelObservable?.unsubscribeAll();
|
||||||
} else if (this._currentRoomViewModel) {
|
if (this._gridViewModel.initializeRoomIdsAndTransferVM(roomIds, this._roomViewModelObservable)) {
|
||||||
this._currentRoomViewModel = this.disposeTracked(this._currentRoomViewModel);
|
this._roomViewModelObservable = this.untrack(this._roomViewModelObservable);
|
||||||
|
} else if (this._roomViewModelObservable) {
|
||||||
|
this._roomViewModelObservable = this.disposeTracked(this._roomViewModelObservable);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this._gridViewModel.setRoomIds(roomIds);
|
this._gridViewModel.setRoomIds(roomIds);
|
||||||
|
@ -134,14 +134,12 @@ export class SessionViewModel extends ViewModel {
|
||||||
} else if (this._gridViewModel && !roomIds) {
|
} else if (this._gridViewModel && !roomIds) {
|
||||||
// closing grid, try to show focused room in grid
|
// closing grid, try to show focused room in grid
|
||||||
if (currentRoomId) {
|
if (currentRoomId) {
|
||||||
const vm = this._gridViewModel.releaseRoomViewModel(currentRoomId.value);
|
const vmo = this._gridViewModel.releaseRoomViewModel(currentRoomId.value);
|
||||||
if (vm) {
|
if (vmo) {
|
||||||
this._currentRoomViewModel = this.track(vm);
|
this._roomViewModelObservable = this.track(vmo);
|
||||||
} else {
|
this._roomViewModelObservable.subscribe(() => {
|
||||||
const newVM = this._createRoomViewModel(currentRoomId.value, this._refreshRoomViewModel);
|
this.emitChange("activeMiddleViewModel");
|
||||||
if (newVM) {
|
});
|
||||||
this._currentRoomViewModel = this.track(newVM);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this._gridViewModel = this.disposeTracked(this._gridViewModel);
|
this._gridViewModel = this.disposeTracked(this._gridViewModel);
|
||||||
|
@ -151,63 +149,59 @@ export class SessionViewModel extends ViewModel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
_createRoomViewModel(roomId) {
|
||||||
* @param {string} roomId
|
const room = this._sessionContainer.session.rooms.get(roomId);
|
||||||
* @param {function} refreshRoomViewModel passed in as an argument, because the grid needs a different impl of this
|
if (room) {
|
||||||
* @return {RoomViewModel | InviteViewModel}
|
const roomVM = new RoomViewModel(this.childOptions({
|
||||||
*/
|
room,
|
||||||
_createRoomViewModel(roomId, refreshRoomViewModel) {
|
ownUserId: this._sessionContainer.session.user.id,
|
||||||
|
}));
|
||||||
|
roomVM.load();
|
||||||
|
return roomVM;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async _createArchivedRoomViewModel(roomId) {
|
||||||
|
const room = await this._sessionContainer.session.loadArchivedRoom(roomId);
|
||||||
|
if (room) {
|
||||||
|
const roomVM = new RoomViewModel(this.childOptions({
|
||||||
|
room,
|
||||||
|
ownUserId: this._sessionContainer.session.user.id,
|
||||||
|
}));
|
||||||
|
roomVM.load();
|
||||||
|
return roomVM;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
_createInviteViewModel(roomId) {
|
||||||
const invite = this._sessionContainer.session.invites.get(roomId);
|
const invite = this._sessionContainer.session.invites.get(roomId);
|
||||||
if (invite) {
|
if (invite) {
|
||||||
return new InviteViewModel(this.childOptions({
|
return new InviteViewModel(this.childOptions({
|
||||||
invite,
|
invite,
|
||||||
mediaRepository: this._sessionContainer.session.mediaRepository,
|
mediaRepository: this._sessionContainer.session.mediaRepository,
|
||||||
refreshRoomViewModel,
|
|
||||||
}));
|
}));
|
||||||
} else {
|
|
||||||
const room = this._sessionContainer.session.rooms.get(roomId);
|
|
||||||
if (room) {
|
|
||||||
const roomVM = new RoomViewModel(this.childOptions({
|
|
||||||
room,
|
|
||||||
ownUserId: this._sessionContainer.session.user.id,
|
|
||||||
refreshRoomViewModel
|
|
||||||
}));
|
|
||||||
roomVM.load();
|
|
||||||
return roomVM;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** refresh the room view model after an internal change that needs
|
|
||||||
to change between invite, room or none state */
|
|
||||||
_refreshRoomViewModel(roomId) {
|
|
||||||
this._currentRoomViewModel = this.disposeTracked(this._currentRoomViewModel);
|
|
||||||
const roomVM = this._createRoomViewModel(roomId, this._refreshRoomViewModel);
|
|
||||||
if (roomVM) {
|
|
||||||
this._currentRoomViewModel = this.track(roomVM);
|
|
||||||
} else {
|
|
||||||
// close room id
|
|
||||||
this.navigation.applyPath(removeRoomFromPath(this.navigation.path, roomId));
|
|
||||||
}
|
|
||||||
this.emitChange("activeMiddleViewModel");
|
|
||||||
}
|
|
||||||
|
|
||||||
_updateRoom(roomId) {
|
_updateRoom(roomId) {
|
||||||
// opening a room and already open?
|
// opening a room and already open?
|
||||||
if (this._currentRoomViewModel?.id === roomId) {
|
if (this._roomViewModelObservable?.id === roomId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// close if needed
|
// close if needed
|
||||||
if (this._currentRoomViewModel) {
|
if (this._roomViewModelObservable) {
|
||||||
this._currentRoomViewModel = this.disposeTracked(this._currentRoomViewModel);
|
this._roomViewModelObservable = this.disposeTracked(this._roomViewModelObservable);
|
||||||
}
|
}
|
||||||
// and try opening again
|
const vmo = new RoomViewModelObservable(this, roomId);
|
||||||
const roomVM = this._createRoomViewModel(roomId, this._refreshRoomViewModel);
|
this._roomViewModelObservable = this.track(vmo);
|
||||||
if (roomVM) {
|
// subscription is unsubscribed in RoomViewModelObservable.dispose, and thus handled by track
|
||||||
this._currentRoomViewModel = this.track(roomVM);
|
this._roomViewModelObservable.subscribe(() => {
|
||||||
}
|
this.emitChange("activeMiddleViewModel");
|
||||||
this.emitChange("activeMiddleViewModel");
|
});
|
||||||
|
vmo.initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
_updateSettings(settingsOpen) {
|
_updateSettings(settingsOpen) {
|
||||||
|
|
|
@ -48,6 +48,13 @@ export class BaseObservable {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsubscribeAll() {
|
||||||
|
if (this._handlers.size !== 0) {
|
||||||
|
this._handlers.clear();
|
||||||
|
this.onUnsubscribeLast();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
get hasSubscriptions() {
|
get hasSubscriptions() {
|
||||||
return this._handlers.size !== 0;
|
return this._handlers.size !== 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue