diff --git a/src/domain/session/RoomGridViewModel.js b/src/domain/session/RoomGridViewModel.js index b9b62153..535d454a 100644 --- a/src/domain/session/RoomGridViewModel.js +++ b/src/domain/session/RoomGridViewModel.js @@ -32,10 +32,11 @@ export class RoomGridViewModel extends ViewModel { this._width = options.width; this._height = options.height; - this._createRoomViewModel = options.createRoomViewModel; + this._createRoomOrInviteViewModel = options.createRoomOrInviteViewModel; this._selectedIndex = 0; this._viewModels = []; + this._replaceInviteWithRoom = this._replaceInviteWithRoom.bind(this); this._setupNavigation(); } @@ -63,6 +64,24 @@ export class RoomGridViewModel extends ViewModel { // initial focus for a room is set by initializeRoomIdsAndTransferVM } + _replaceInviteWithRoom(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._createRoomOrInviteViewModel(roomId, this._replaceInviteWithRoom); + if (roomVM) { + this._viewModels[index] = this.track(roomVM); + if (this.focusIndex === index) { + roomVM.focus(); + } + } + this.emitChange(); + } + roomViewModelAt(i) { return this._viewModels[i]; } @@ -128,7 +147,7 @@ export class RoomGridViewModel extends ViewModel { this._viewModels[i] = this.disposeTracked(vm); } if (newId) { - const newVM = this._createRoomViewModel(newId); + const newVM = this._createRoomOrInviteViewModel(newId, this._replaceInviteWithRoom); if (newVM) { this._viewModels[i] = this.track(newVM); } @@ -211,7 +230,7 @@ export function tests() { "initialize with duplicate set of rooms": assert => { const navigation = createNavigationForRoom(["c", "a", "b", undefined, "a"], "a"); const gridVM = new RoomGridViewModel({ - createRoomViewModel: id => new RoomVMMock(id), + createRoomOrInviteViewModel: id => new RoomVMMock(id), navigation, width: 3, height: 2, @@ -228,7 +247,7 @@ export function tests() { "transfer room view model": assert => { const navigation = createNavigationForRoom(["a"], "a"); const gridVM = new RoomGridViewModel({ - createRoomViewModel: () => assert.fail("no vms should be created"), + createRoomOrInviteViewModel: () => assert.fail("no vms should be created"), navigation, width: 3, height: 2, @@ -242,7 +261,7 @@ export function tests() { "reject transfer for non-matching room view model": assert => { const navigation = createNavigationForRoom(["a"], "a"); const gridVM = new RoomGridViewModel({ - createRoomViewModel: id => new RoomVMMock(id), + createRoomOrInviteViewModel: id => new RoomVMMock(id), navigation, width: 3, height: 2, @@ -256,7 +275,7 @@ export function tests() { "created & released room view model is not disposed": assert => { const navigation = createNavigationForRoom(["a"], "a"); const gridVM = new RoomGridViewModel({ - createRoomViewModel: id => new RoomVMMock(id), + createRoomOrInviteViewModel: id => new RoomVMMock(id), navigation, width: 3, height: 2, @@ -270,7 +289,7 @@ export function tests() { "transfered & released room view model is not disposed": assert => { const navigation = createNavigationForRoom([undefined, "a"], "a"); const gridVM = new RoomGridViewModel({ - createRoomViewModel: () => assert.fail("no vms should be created"), + createRoomOrInviteViewModel: () => assert.fail("no vms should be created"), navigation, width: 3, height: 2, @@ -285,7 +304,7 @@ export function tests() { "try release non-existing room view model is": assert => { const navigation = createNavigationForEmptyTile([undefined, "b"], 3); const gridVM = new RoomGridViewModel({ - createRoomViewModel: id => new RoomVMMock(id), + createRoomOrInviteViewModel: id => new RoomVMMock(id), navigation, width: 3, height: 2, @@ -297,7 +316,7 @@ export function tests() { "initial focus is set to empty tile": assert => { const navigation = createNavigationForEmptyTile(["a"], 1); const gridVM = new RoomGridViewModel({ - createRoomViewModel: id => new RoomVMMock(id), + createRoomOrInviteViewModel: id => new RoomVMMock(id), navigation, width: 3, height: 2, @@ -309,7 +328,7 @@ export function tests() { "change room ids after creation": assert => { const navigation = createNavigationForRoom(["a", "b"], "a"); const gridVM = new RoomGridViewModel({ - createRoomViewModel: id => new RoomVMMock(id), + createRoomOrInviteViewModel: id => new RoomVMMock(id), navigation, width: 3, height: 2, diff --git a/src/domain/session/SessionViewModel.js b/src/domain/session/SessionViewModel.js index 2f7e341e..4992c9e2 100644 --- a/src/domain/session/SessionViewModel.js +++ b/src/domain/session/SessionViewModel.js @@ -15,8 +15,10 @@ See the License for the specific language governing permissions and limitations under the License. */ +import {removeRoomFromPath} from "../navigation/index.js"; import {LeftPanelViewModel} from "./leftpanel/LeftPanelViewModel.js"; import {RoomViewModel} from "./room/RoomViewModel.js"; +import {InviteViewModel} from "./room/InviteViewModel.js"; import {LightboxViewModel} from "./room/LightboxViewModel.js"; import {SessionStatusViewModel} from "./SessionStatusViewModel.js"; import {RoomGridViewModel} from "./RoomGridViewModel.js"; @@ -39,6 +41,8 @@ export class SessionViewModel extends ViewModel { this._settingsViewModel = null; this._currentRoomViewModel = null; this._gridViewModel = null; + this._replaceInviteWithRoom = this._replaceInviteWithRoom.bind(this); + this._createRoomOrInviteViewModel = this._createRoomOrInviteViewModel.bind(this); this._setupNavigation(); } @@ -84,15 +88,8 @@ export class SessionViewModel extends ViewModel { this._sessionStatusViewModel.start(); } - get activeSection() { - if (this._currentRoomViewModel) { - return this._currentRoomViewModel.id; - } else if (this._gridViewModel) { - return "roomgrid"; - } else if (this._settingsViewModel) { - return "settings"; - } - return "placeholder"; + get activeMiddleViewModel() { + return this._currentRoomViewModel || this._gridViewModel || this._settingsViewModel; } get roomGridViewModel() { @@ -127,7 +124,7 @@ export class SessionViewModel extends ViewModel { this._gridViewModel = this.track(new RoomGridViewModel(this.childOptions({ width: 3, height: 2, - createRoomViewModel: roomId => this._createRoomViewModel(roomId), + createRoomOrInviteViewModel: this._createRoomOrInviteViewModel, }))); if (this._gridViewModel.initializeRoomIdsAndTransferVM(roomIds, this._currentRoomViewModel)) { this._currentRoomViewModel = this.untrack(this._currentRoomViewModel); @@ -138,6 +135,7 @@ export class SessionViewModel extends ViewModel { this._gridViewModel.setRoomIds(roomIds); } } else if (this._gridViewModel && !roomIds) { + // closing grid, try to show focused room in grid if (currentRoomId) { const vm = this._gridViewModel.releaseRoomViewModel(currentRoomId.value); if (vm) { @@ -152,7 +150,7 @@ export class SessionViewModel extends ViewModel { this._gridViewModel = this.disposeTracked(this._gridViewModel); } if (changed) { - this.emitChange("activeSection"); + this.emitChange("activeMiddleViewModel"); } } @@ -169,11 +167,50 @@ export class SessionViewModel extends ViewModel { return roomVM; } + _createInviteViewModel(roomId, replaceInviteWithRoom) { + const invite = this._sessionContainer.session.invites.get(roomId); + if (!invite) { + return null; + } + return new InviteViewModel(this.childOptions({ + invite, + mediaRepository: this._sessionContainer.session.mediaRepository, + closeCallback: accepted => this._closeInvite(roomId, accepted, replaceInviteWithRoom), + })); + } + + _createRoomOrInviteViewModel(roomId, replaceInviteWithRoom) { + const inviteVM = this._createInviteViewModel(roomId, replaceInviteWithRoom); + if (inviteVM) { + return inviteVM; + } + return this._createRoomViewModel(roomId); + } + + _closeInvite(roomId, accepted, replaceInviteWithRoom) { + if (accepted) { + replaceInviteWithRoom(roomId); + } else { + // close invite + this.navigation.applyPath(removeRoomFromPath(this.navigation.path, roomId)); + } + } + + _replaceInviteWithRoom(roomId) { + this._currentRoomViewModel = this.disposeTracked(this._currentRoomViewModel); + const roomVM = this._createRoomViewModel(roomId); + if (roomVM) { + this._currentRoomViewModel = this.track(roomVM); + } + this.emitChange("activeMiddleViewModel"); + } + _updateRoom(roomId) { if (!roomId) { + // closing invite or room view? if (this._currentRoomViewModel) { this._currentRoomViewModel = this.disposeTracked(this._currentRoomViewModel); - this.emitChange("currentRoom"); + this.emitChange("activeMiddleViewModel"); } return; } @@ -182,11 +219,11 @@ export class SessionViewModel extends ViewModel { return; } this._currentRoomViewModel = this.disposeTracked(this._currentRoomViewModel); - const roomVM = this._createRoomViewModel(roomId); + const roomVM = this._createRoomOrInviteViewModel(roomId, this._replaceInviteWithRoom); if (roomVM) { this._currentRoomViewModel = this.track(roomVM); } - this.emitChange("currentRoom"); + this.emitChange("activeMiddleViewModel"); } _updateSettings(settingsOpen) { @@ -199,7 +236,7 @@ export class SessionViewModel extends ViewModel { }))); this._settingsViewModel.load(); } - this.emitChange("activeSection"); + this.emitChange("activeMiddleViewModel"); } _updateLightbox(eventId) { diff --git a/src/platform/web/ui/session/SessionView.js b/src/platform/web/ui/session/SessionView.js index fa7a492a..e05d97ad 100644 --- a/src/platform/web/ui/session/SessionView.js +++ b/src/platform/web/ui/session/SessionView.js @@ -34,16 +34,15 @@ export class SessionView extends TemplateView { }, [ t.view(new SessionStatusView(vm.sessionStatusViewModel)), t.view(new LeftPanelView(vm.leftPanelViewModel)), - t.mapView(vm => vm.activeSection, activeSection => { - switch (activeSection) { - case "roomgrid": - 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 + t.mapView(vm => vm.activeMiddleViewModel, () => { + if (vm.roomGridViewModel) { + return new RoomGridView(vm.roomGridViewModel); + } else if (vm.settingsViewModel) { + return new SettingsView(vm.settingsViewModel); + } else if (vm.currentRoomViewModel) { return new RoomView(vm.currentRoomViewModel); + } else { + return new StaticView(t => t.div({className: "room-placeholder"}, t.h2(vm.i18n`Choose a room on the left side.`))); } }), t.mapView(vm => vm.lightboxViewModel, lightboxViewModel => lightboxViewModel ? new LightboxView(lightboxViewModel) : null)