mirror of
https://github.com/vector-im/hydrogen-web.git
synced 2024-11-20 03:25:52 +01:00
separate view and model for WorldReadableRoom out of UnknownRoom
- UnknownRoomViewModel now receives a promise using which it can display a spinner to the user indicating we are checking whether the preview is possible for this room and updates the model to WorldReadableRoomViewModel - kind is now changed to "preview" for WorldReadableRooms - data stored is now deleted when navigating away to another room by clicking on it
This commit is contained in:
parent
654cdf0317
commit
07cce3857a
@ -77,10 +77,24 @@ export class RoomViewModelObservable extends ObservableValue {
|
||||
} else if (status & RoomStatus.Archived) {
|
||||
return await this._sessionViewModel._createArchivedRoomViewModel(this.id);
|
||||
} else {
|
||||
return this._sessionViewModel._createUnknownRoomViewModel(this.id);
|
||||
return this._sessionViewModel._createUnknownRoomViewModel(this.id, this._isWorldReadablePromise());
|
||||
}
|
||||
}
|
||||
|
||||
async _isWorldReadablePromise() {
|
||||
const {session} = this._sessionViewModel._client;
|
||||
const isWorldReadable = await session.isWorldReadableRoom(this.id);
|
||||
if (isWorldReadable) {
|
||||
const vm = await this._sessionViewModel._createWorldReadableRoomViewModel(this.id);
|
||||
if (vm) {
|
||||
this.get()?.dispose();
|
||||
this.set(vm);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
dispose() {
|
||||
if (this._statusSubscription) {
|
||||
this._statusSubscription = this._statusSubscription();
|
||||
|
@ -18,6 +18,7 @@ limitations under the License.
|
||||
import {LeftPanelViewModel} from "./leftpanel/LeftPanelViewModel.js";
|
||||
import {RoomViewModel} from "./room/RoomViewModel.js";
|
||||
import {UnknownRoomViewModel} from "./room/UnknownRoomViewModel.js";
|
||||
import {WorldReadableRoomViewModel} from "./room/WorldReadableRoomViewModel.js";
|
||||
import {InviteViewModel} from "./room/InviteViewModel.js";
|
||||
import {RoomBeingCreatedViewModel} from "./room/RoomBeingCreatedViewModel.js";
|
||||
import {LightboxViewModel} from "./room/LightboxViewModel.js";
|
||||
@ -231,12 +232,20 @@ export class SessionViewModel extends ViewModel {
|
||||
return null;
|
||||
}
|
||||
|
||||
async _createUnknownRoomViewModel(roomIdOrAlias) {
|
||||
const roomVM = new UnknownRoomViewModel(this.childOptions({
|
||||
_createUnknownRoomViewModel(roomIdOrAlias, isWorldReadablePromise) {
|
||||
return new UnknownRoomViewModel(this.childOptions({
|
||||
roomIdOrAlias,
|
||||
session: this._client.session,
|
||||
isWorldReadablePromise: isWorldReadablePromise
|
||||
}));
|
||||
void roomVM.load();
|
||||
}
|
||||
|
||||
async _createWorldReadableRoomViewModel(roomIdOrAlias) {
|
||||
const roomVM = new WorldReadableRoomViewModel(this.childOptions({
|
||||
room: await this._client.session.loadWorldReadableRoom(roomIdOrAlias),
|
||||
session: this._client.session,
|
||||
}));
|
||||
roomVM.load();
|
||||
return roomVM;
|
||||
}
|
||||
|
||||
|
@ -41,7 +41,7 @@ export class RoomViewModel extends ErrorReportViewModel {
|
||||
this._composerVM = null;
|
||||
if (room.isArchived) {
|
||||
this._composerVM = this.track(new ArchivedViewModel(this.childOptions({archivedRoom: room})));
|
||||
} else {
|
||||
} else if (!room.isWorldReadable) {
|
||||
this._recreateComposerOnPowerLevelChange();
|
||||
}
|
||||
this._clearUnreadTimout = null;
|
||||
@ -218,7 +218,7 @@ export class RoomViewModel extends ErrorReportViewModel {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
_sendMessage(message, replyingTo) {
|
||||
return this.logAndCatch("RoomViewModel.sendMessage", async log => {
|
||||
let success = false;
|
||||
|
@ -15,24 +15,21 @@ limitations under the License.
|
||||
*/
|
||||
|
||||
import {ViewModel} from "../../ViewModel";
|
||||
import {TimelineViewModel} from "./timeline/TimelineViewModel";
|
||||
import {tileClassForEntry as defaultTileClassForEntry} from "./timeline/tiles/index";
|
||||
import {getAvatarHttpUrl} from "../../avatar";
|
||||
|
||||
export class UnknownRoomViewModel extends ViewModel {
|
||||
constructor(options) {
|
||||
super(options);
|
||||
const {roomIdOrAlias, session} = options;
|
||||
const {roomIdOrAlias, session, isWorldReadablePromise} = options;
|
||||
this._session = session;
|
||||
this.roomIdOrAlias = roomIdOrAlias;
|
||||
this._error = null;
|
||||
this._busy = false;
|
||||
this._worldReadable = false; // won't know until load() finishes with isWorldReadableRoom() call
|
||||
this._checkingPreviewCapability = false; // won't know until load() finishes with isWorldReadableRoom() call
|
||||
}
|
||||
|
||||
get room() {
|
||||
return this._room;
|
||||
this.checkingPreviewCapability = true;
|
||||
isWorldReadablePromise.then(() => {
|
||||
this.checkingPreviewCapability = false;
|
||||
this.emitChange('checkingPreviewCapability');
|
||||
})
|
||||
}
|
||||
|
||||
get error() {
|
||||
@ -61,49 +58,7 @@ export class UnknownRoomViewModel extends ViewModel {
|
||||
return this._busy;
|
||||
}
|
||||
|
||||
get checkingPreviewCapability() {
|
||||
return this._checkingPreviewCapability;
|
||||
}
|
||||
|
||||
get kind() {
|
||||
return this._worldReadable ? "worldReadableRoom" : "unknown";
|
||||
}
|
||||
|
||||
get timelineViewModel() {
|
||||
return this._timelineVM;
|
||||
}
|
||||
|
||||
avatarUrl(size) {
|
||||
return getAvatarHttpUrl(this._room.avatarUrl, size, this.platform, this._room.mediaRepository);
|
||||
}
|
||||
|
||||
async load() {
|
||||
this._checkingPreviewCapability = true;
|
||||
this._worldReadable = await this._session.isWorldReadableRoom(this.roomIdOrAlias);
|
||||
this._checkingPreviewCapability = false;
|
||||
|
||||
if (!this._worldReadable) {
|
||||
this.emitChange("checkingPreviewCapability");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
this._room = await this._session.loadWorldReadableRoom(this.roomIdOrAlias);
|
||||
const timeline = await this._room.openTimeline();
|
||||
this._tileOptions = this.childOptions({
|
||||
roomVM: this,
|
||||
timeline,
|
||||
tileClassForEntry: defaultTileClassForEntry,
|
||||
});
|
||||
this._timelineVM = this.track(new TimelineViewModel(this.childOptions({
|
||||
tileOptions: this._tileOptions,
|
||||
timeline,
|
||||
})));
|
||||
this.emitChange("timelineViewModel");
|
||||
} catch (err) {
|
||||
console.error(`room.openTimeline(): ${err.message}:\n${err.stack}`);
|
||||
this._timelineError = err;
|
||||
this.emitChange("error");
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
47
src/domain/session/room/WorldReadableRoomViewModel.js
Normal file
47
src/domain/session/room/WorldReadableRoomViewModel.js
Normal file
@ -0,0 +1,47 @@
|
||||
import {RoomViewModel} from "./RoomViewModel";
|
||||
|
||||
export class WorldReadableRoomViewModel extends RoomViewModel {
|
||||
constructor(options) {
|
||||
options.room.isWorldReadable = true;
|
||||
super(options);
|
||||
this._room = options.room;
|
||||
this._session = options.session;
|
||||
this._error = null;
|
||||
this._busy = false;
|
||||
}
|
||||
|
||||
get kind() {
|
||||
return "preview";
|
||||
}
|
||||
|
||||
get busy() {
|
||||
return this._busy;
|
||||
}
|
||||
|
||||
async join() {
|
||||
this._busy = true;
|
||||
this.emitChange("busy");
|
||||
try {
|
||||
const roomId = await this._session.joinRoom(this._room.id);
|
||||
// navigate to roomId if we were at the alias
|
||||
// so we're subscribed to the right room status
|
||||
// and we'll switch to the room view model once
|
||||
// the join is synced
|
||||
this.navigation.push("room", roomId);
|
||||
// keep busy on true while waiting for the join to sync
|
||||
} catch (err) {
|
||||
this._error = err;
|
||||
this._busy = false;
|
||||
this.emitChange("error");
|
||||
}
|
||||
}
|
||||
|
||||
dispose() {
|
||||
super.dispose();
|
||||
|
||||
// if joining the room, _busy would be true and in that case don't delete records
|
||||
if (!this._busy) {
|
||||
void this._session.deleteWorldReadableRoomData(this._room.id);
|
||||
}
|
||||
}
|
||||
}
|
@ -668,7 +668,8 @@ export class Session {
|
||||
mediaRepository: this._mediaRepository,
|
||||
pendingEvents: [],
|
||||
user: this._user,
|
||||
platform: this._platform
|
||||
platform: this._platform,
|
||||
roomStateHandler: this._roomStateHandler
|
||||
});
|
||||
}
|
||||
|
||||
@ -1106,15 +1107,13 @@ export class Session {
|
||||
const response = await this._hsApi.messages(roomId, options, {log}).response();
|
||||
log.set("/messages endpoint response", response);
|
||||
|
||||
await this.deleteWorldReadableRoomData(roomId, log);
|
||||
|
||||
const txn = await this._storage.readWriteTxn([
|
||||
this._storage.storeNames.timelineFragments,
|
||||
this._storage.storeNames.timelineEvents,
|
||||
]);
|
||||
|
||||
// clear old records for this room
|
||||
txn.timelineFragments.removeAllForRoom(roomId);
|
||||
txn.timelineEvents.removeAllForRoom(roomId);
|
||||
|
||||
// insert fragment and event records for this room
|
||||
const fragment = {
|
||||
roomId: roomId,
|
||||
@ -1140,6 +1139,21 @@ export class Session {
|
||||
});
|
||||
}
|
||||
|
||||
async deleteWorldReadableRoomData(roomId, log = null) {
|
||||
return this._platform.logger.wrapOrRun(log, "deleteWorldReadableRoomData", async log => {
|
||||
log.set("id", roomId);
|
||||
|
||||
const txn = await this._storage.readWriteTxn([
|
||||
this._storage.storeNames.timelineFragments,
|
||||
this._storage.storeNames.timelineEvents,
|
||||
]);
|
||||
|
||||
// clear old records for this room
|
||||
txn.timelineFragments.removeAllForRoom(roomId);
|
||||
txn.timelineEvents.removeAllForRoom(roomId);
|
||||
});
|
||||
}
|
||||
|
||||
joinRoom(roomIdOrAlias, log = null) {
|
||||
return this._platform.logger.wrapOrRun(log, "joinRoom", async log => {
|
||||
const body = await this._hsApi.joinIdOrAlias(roomIdOrAlias, {log}).response();
|
||||
@ -1147,7 +1161,7 @@ export class Session {
|
||||
});
|
||||
}
|
||||
|
||||
isWorldReadableRoom(roomIdOrAlias, log = null) {
|
||||
async isWorldReadableRoom(roomIdOrAlias, log = null) {
|
||||
return this._platform.logger.wrapOrRun(log, "isWorldReadableRoom", async log => {
|
||||
try {
|
||||
let roomId;
|
||||
|
@ -18,6 +18,7 @@ limitations under the License.
|
||||
import {LeftPanelView} from "./leftpanel/LeftPanelView.js";
|
||||
import {RoomView} from "./room/RoomView.js";
|
||||
import {UnknownRoomView} from "./room/UnknownRoomView.js";
|
||||
import {WorldReadableRoomView} from "./room/WorldReadableRoomView.js";
|
||||
import {RoomBeingCreatedView} from "./room/RoomBeingCreatedView.js";
|
||||
import {InviteView} from "./room/InviteView.js";
|
||||
import {LightboxView} from "./room/LightboxView.js";
|
||||
@ -60,6 +61,8 @@ export class SessionView extends TemplateView {
|
||||
return new RoomView(vm.currentRoomViewModel, viewClassForTile);
|
||||
} else if (vm.currentRoomViewModel.kind === "roomBeingCreated") {
|
||||
return new RoomBeingCreatedView(vm.currentRoomViewModel);
|
||||
} else if (vm.currentRoomViewModel.kind === "preview") {
|
||||
return new WorldReadableRoomView(vm.currentRoomViewModel);
|
||||
} else {
|
||||
return new UnknownRoomView(vm.currentRoomViewModel);
|
||||
}
|
||||
|
@ -14,78 +14,28 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import {InlineTemplateView, TemplateView} from "../../general/TemplateView";
|
||||
import {AvatarView} from "../../AvatarView";
|
||||
import {TimelineView} from "./TimelineView";
|
||||
import {TimelineLoadingView} from "./TimelineLoadingView";
|
||||
import {TemplateView} from "../../general/TemplateView";
|
||||
import {spinner} from "../../common.js";
|
||||
import {viewClassForTile} from "./common";
|
||||
|
||||
export class UnknownRoomView extends TemplateView {
|
||||
|
||||
constructor(vm) {
|
||||
super(vm);
|
||||
}
|
||||
|
||||
render(t, vm) {
|
||||
return t.mapView(vm => vm.kind, kind => {
|
||||
const unknownRoomView = new InlineTemplateView(vm, (t, m) => {
|
||||
return t.main({className: "UnknownRoomView middle"}, t.div([
|
||||
t.h2([
|
||||
vm.i18n`You are currently not in ${vm.roomIdOrAlias}.`,
|
||||
t.br(),
|
||||
vm.i18n`Want to join it?`
|
||||
]),
|
||||
t.button({
|
||||
className: "button-action primary",
|
||||
onClick: () => vm.join(),
|
||||
disabled: vm => vm.busy,
|
||||
}, vm.i18n`Join room`),
|
||||
t.br(),
|
||||
t.if(vm => vm.checkingPreviewCapability, t => t.div({className: "checkingPreviewCapability"}, [
|
||||
spinner(t),
|
||||
t.p(vm.i18n`Checking preview capability...`)
|
||||
])),
|
||||
t.if(vm => vm.error, t => t.p({className: "error"}, vm.error))
|
||||
]));
|
||||
});
|
||||
return kind === 'worldReadableRoom' ? new WorldReadableRoomView(vm) : unknownRoomView;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class WorldReadableRoomView extends InlineTemplateView {
|
||||
|
||||
constructor(value, render) {
|
||||
super(value, render);
|
||||
}
|
||||
|
||||
render(t, vm) {
|
||||
return t.main({className: "RoomView WorldReadableRoomView middle"}, [
|
||||
t.div({className: "RoomHeader middle-header"}, [
|
||||
t.view(new AvatarView(vm, 32)),
|
||||
t.div({className: "room-description"}, [
|
||||
t.h2(vm => vm.room.name),
|
||||
]),
|
||||
return t.main({className: "UnknownRoomView middle"}, t.div([
|
||||
t.h2([
|
||||
vm.i18n`You are currently not in ${vm.roomIdOrAlias}.`,
|
||||
t.br(),
|
||||
vm.i18n`Want to join it?`
|
||||
]),
|
||||
t.div({className: "RoomView_body"}, [
|
||||
t.div({className: "RoomView_error"}, [
|
||||
t.if(vm => vm.error, t => t.div(
|
||||
[
|
||||
t.p({}, vm => vm.error),
|
||||
t.button({className: "RoomView_error_closerButton", onClick: evt => vm.dismissError(evt)})
|
||||
])
|
||||
)]),
|
||||
t.mapView(vm => vm.timelineViewModel, timelineViewModel => {
|
||||
return timelineViewModel ?
|
||||
new TimelineView(timelineViewModel, viewClassForTile) :
|
||||
new TimelineLoadingView(vm); // vm is just needed for i18n
|
||||
}),
|
||||
t.div({className: "WorldReadableRoomComposerView"}, [
|
||||
t.h3(vm => vm.i18n`Join the room to participate`),
|
||||
t.button({className: "joinRoomButton", onClick: () => vm.join()}, vm.i18n`Join Room`)
|
||||
])
|
||||
])
|
||||
]);
|
||||
t.button({
|
||||
className: "button-action primary",
|
||||
onClick: () => vm.join(),
|
||||
disabled: vm => vm.busy,
|
||||
}, vm.i18n`Join room`),
|
||||
t.br(),
|
||||
t.if(vm => vm.checkingPreviewCapability, t => t.div({className: "checkingPreviewCapability"}, [
|
||||
spinner(t),
|
||||
t.p(vm.i18n`Checking preview capability...`)
|
||||
])),
|
||||
t.if(vm => vm.error, t => t.p({className: "error"}, vm.error))
|
||||
]));
|
||||
}
|
||||
}
|
||||
|
44
src/platform/web/ui/session/room/WorldReadableRoomView.js
Normal file
44
src/platform/web/ui/session/room/WorldReadableRoomView.js
Normal file
@ -0,0 +1,44 @@
|
||||
import {TemplateView} from "../../general/TemplateView";
|
||||
import {TimelineView} from "./TimelineView";
|
||||
import {viewClassForTile} from "./common";
|
||||
import {TimelineLoadingView} from "./TimelineLoadingView";
|
||||
import {AvatarView} from "../../AvatarView";
|
||||
|
||||
export class WorldReadableRoomView extends TemplateView {
|
||||
|
||||
constructor(vm) {
|
||||
super(vm);
|
||||
}
|
||||
|
||||
render(t, vm) {
|
||||
return t.div({className: "RoomView WorldReadableRoomView middle"}, [
|
||||
t.div({className: "RoomHeader middle-header"}, [
|
||||
t.view(new AvatarView(vm, 32)),
|
||||
t.div({className: "room-description"}, [
|
||||
t.h2(vm => vm.room.name),
|
||||
]),
|
||||
]),
|
||||
t.div({className: "RoomView_body"}, [
|
||||
t.div({className: "RoomView_error"}, [
|
||||
t.if(vm => vm.error, t => t.div([
|
||||
t.p({}, vm => vm.error),
|
||||
t.button({className: "RoomView_error_closerButton", onClick: evt => vm.dismissError(evt)})
|
||||
]))
|
||||
]),
|
||||
t.mapView(vm => vm.timelineViewModel, timelineViewModel => {
|
||||
return timelineViewModel ?
|
||||
new TimelineView(timelineViewModel, viewClassForTile) :
|
||||
new TimelineLoadingView(vm); // vm is just needed for i18n
|
||||
}),
|
||||
t.div({className: "WorldReadableRoomComposerView"}, [
|
||||
t.h3(vm => vm.i18n`Join the room to participate`),
|
||||
t.button({
|
||||
className: "joinRoomButton",
|
||||
onClick: () => vm.join(),
|
||||
disabled: vm => vm.busy,
|
||||
}, vm.i18n`Join Room`)
|
||||
])
|
||||
])
|
||||
]);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user