Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Peeking improvements #5

Closed
wants to merge 9 commits into from
16 changes: 15 additions & 1 deletion src/domain/session/RoomViewModelObservable.js
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
15 changes: 12 additions & 3 deletions src/domain/session/SessionViewModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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;
}

Expand Down
4 changes: 2 additions & 2 deletions src/domain/session/room/RoomViewModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -218,7 +218,7 @@ export class RoomViewModel extends ErrorReportViewModel {
}
}
}

_sendMessage(message, replyingTo) {
return this.logAndCatch("RoomViewModel.sendMessage", async log => {
let success = false;
Expand Down
59 changes: 7 additions & 52 deletions src/domain/session/room/UnknownRoomViewModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down Expand Up @@ -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 changes: 47 additions & 0 deletions src/domain/session/room/WorldReadableRoomViewModel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import {RoomViewModel} from "./RoomViewModel";

export class WorldReadableRoomViewModel extends RoomViewModel {
constructor(options) {
options.room.isWorldReadable = true;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@psrpinto Do you think this is fine or it warrants the need of creating a WorldReadableRoom like ArchivedRoom just because we need to differentiate between the room instance of a regular room and WorldReadable room in RoomViewModel?

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);
}
}
}
26 changes: 20 additions & 6 deletions src/matrix/Session.js
Original file line number Diff line number Diff line change
Expand Up @@ -668,7 +668,8 @@ export class Session {
mediaRepository: this._mediaRepository,
pendingEvents: [],
user: this._user,
platform: this._platform
platform: this._platform,
roomStateHandler: this._roomStateHandler
});
}

Expand Down Expand Up @@ -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,
Expand All @@ -1140,14 +1139,29 @@ 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();
return body.room_id;
});
}

isWorldReadableRoom(roomIdOrAlias, log = null) {
async isWorldReadableRoom(roomIdOrAlias, log = null) {
return this._platform.logger.wrapOrRun(log, "isWorldReadableRoom", async log => {
try {
let roomId;
Expand Down
3 changes: 3 additions & 0 deletions src/platform/web/ui/session/SessionView.js
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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);
}
Expand Down
86 changes: 18 additions & 68 deletions src/platform/web/ui/session/room/UnknownRoomView.js
Original file line number Diff line number Diff line change
Expand Up @@ -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))
]));
}
}
Loading