From 5445db2a42719d809f65d49f74ecb923dbfdad0d Mon Sep 17 00:00:00 2001 From: Bruno Windels <274386+bwindels@users.noreply.github.com> Date: Fri, 8 Apr 2022 12:52:30 +0200 Subject: [PATCH] allow injecting the tilesCreator from the Root/Session/RoomViewModel this changes the API slightly to be more future-proof, as we'll expose it in the SDK now. The function now returns a SimpleTile constructor, rather than an instance. This allows us to test if an entry would render in the timeline without creating a tile, which is something we might want in the matrix layer later on. The function is now called tileClassForEntry, analogue to what we do in TimelineView. --- src/domain/session/room/RoomViewModel.js | 20 ++-- .../room/timeline/ReactionsViewModel.js | 2 +- .../session/room/timeline/TilesCollection.js | 31 ++++-- .../room/timeline/TimelineViewModel.js | 4 +- .../room/timeline/tiles/BaseMediaTile.js | 4 +- .../room/timeline/tiles/BaseMessageTile.js | 22 +++-- .../room/timeline/tiles/BaseTextTile.js | 4 +- .../room/timeline/tiles/EncryptedEventTile.js | 4 +- .../session/room/timeline/tiles/FileTile.js | 4 +- .../session/room/timeline/tiles/GapTile.js | 10 +- .../session/room/timeline/tiles/ImageTile.js | 4 +- .../room/timeline/tiles/RoomMemberTile.js | 14 +-- .../session/room/timeline/tiles/SimpleTile.js | 4 +- .../session/room/timeline/tiles/index.ts | 94 +++++++++++++++++++ .../session/room/timeline/tilesCreator.js | 81 ---------------- src/platform/web/main.js | 3 + src/platform/web/ui/session/room/common.ts | 2 +- 17 files changed, 174 insertions(+), 133 deletions(-) create mode 100644 src/domain/session/room/timeline/tiles/index.ts delete mode 100644 src/domain/session/room/timeline/tilesCreator.js diff --git a/src/domain/session/room/RoomViewModel.js b/src/domain/session/room/RoomViewModel.js index 71060728..9c3f468e 100644 --- a/src/domain/session/room/RoomViewModel.js +++ b/src/domain/session/room/RoomViewModel.js @@ -18,17 +18,17 @@ limitations under the License. import {TimelineViewModel} from "./timeline/TimelineViewModel.js"; import {ComposerViewModel} from "./ComposerViewModel.js" import {avatarInitials, getIdentifierColorNumber, getAvatarHttpUrl} from "../../avatar"; -import {tilesCreator} from "./timeline/tilesCreator.js"; import {ViewModel} from "../../ViewModel"; import {imageToInfo} from "../common.js"; export class RoomViewModel extends ViewModel { constructor(options) { super(options); - const {room} = options; + const {room, tileClassForEntry} = options; this._room = room; this._timelineVM = null; - this._tilesCreator = null; + this._tileClassForEntry = tileClassForEntry; + this._tileOptions = undefined; this._onRoomChange = this._onRoomChange.bind(this); this._timelineError = null; this._sendError = null; @@ -46,12 +46,13 @@ export class RoomViewModel extends ViewModel { this._room.on("change", this._onRoomChange); try { const timeline = await this._room.openTimeline(); - this._tilesCreator = tilesCreator(this.childOptions({ + this._tileOptions = this.childOptions({ roomVM: this, timeline, - })); + tileClassForEntry: this._tileClassForEntry, + }); this._timelineVM = this.track(new TimelineViewModel(this.childOptions({ - tilesCreator: this._tilesCreator, + tileOptions: this._tileOptions, timeline, }))); this.emitChange("timelineViewModel"); @@ -161,7 +162,12 @@ export class RoomViewModel extends ViewModel { } _createTile(entry) { - return this._tilesCreator(entry); + if (this._tileOptions) { + const Tile = this._tileOptions.tileClassForEntry(entry); + if (Tile) { + return new Tile(entry, this._tileOptions); + } + } } async _sendMessage(message, replyingTo) { diff --git a/src/domain/session/room/timeline/ReactionsViewModel.js b/src/domain/session/room/timeline/ReactionsViewModel.js index 4f366af0..1977b6f4 100644 --- a/src/domain/session/room/timeline/ReactionsViewModel.js +++ b/src/domain/session/room/timeline/ReactionsViewModel.js @@ -222,7 +222,7 @@ export function tests() { }; const tiles = new MappedList(timeline.entries, entry => { if (entry.eventType === "m.room.message") { - return new BaseMessageTile({entry, roomVM: {room}, timeline, platform: {logger}}); + return new BaseMessageTile(entry, {roomVM: {room}, timeline, platform: {logger}}); } return null; }, (tile, params, entry) => tile?.updateEntry(entry, params, function () {})); diff --git a/src/domain/session/room/timeline/TilesCollection.js b/src/domain/session/room/timeline/TilesCollection.js index 33ae4472..75af5b09 100644 --- a/src/domain/session/room/timeline/TilesCollection.js +++ b/src/domain/session/room/timeline/TilesCollection.js @@ -18,20 +18,27 @@ import {BaseObservableList} from "../../../../observable/list/BaseObservableList import {sortedIndex} from "../../../../utils/sortedIndex"; // maps 1..n entries to 0..1 tile. Entries are what is stored in the timeline, either an event or fragmentboundary -// for now, tileCreator should be stable in whether it returns a tile or not. +// for now, tileClassForEntry should be stable in whether it returns a tile or not. // e.g. the decision to create a tile or not should be based on properties // not updated later on (e.g. event type) // also see big comment in onUpdate export class TilesCollection extends BaseObservableList { - constructor(entries, tileCreator) { + constructor(entries, tileOptions) { super(); this._entries = entries; this._tiles = null; this._entrySubscription = null; - this._tileCreator = tileCreator; + this._tileOptions = tileOptions; this._emitSpontanousUpdate = this._emitSpontanousUpdate.bind(this); } + _createTile(entry) { + const Tile = this._tileOptions.tileClassForEntry(entry); + if (Tile) { + return new Tile(entry, this._tileOptions); + } + } + _emitSpontanousUpdate(tile, params) { const entry = tile.lowerEntry; const tileIdx = this._findTileIdx(entry); @@ -48,7 +55,7 @@ export class TilesCollection extends BaseObservableList { let currentTile = null; for (let entry of this._entries) { if (!currentTile || !currentTile.tryIncludeEntry(entry)) { - currentTile = this._tileCreator(entry); + currentTile = this._createTile(entry); if (currentTile) { this._tiles.push(currentTile); } @@ -121,7 +128,7 @@ export class TilesCollection extends BaseObservableList { return; } - const newTile = this._tileCreator(entry); + const newTile = this._createTile(entry); if (newTile) { if (prevTile) { prevTile.updateNextSibling(newTile); @@ -150,9 +157,9 @@ export class TilesCollection extends BaseObservableList { const tileIdx = this._findTileIdx(entry); const tile = this._findTileAtIdx(entry, tileIdx); if (tile) { - const action = tile.updateEntry(entry, params, this._tileCreator); + const action = tile.updateEntry(entry, params); if (action.shouldReplace) { - const newTile = this._tileCreator(entry); + const newTile = this._createTile(entry); if (newTile) { this._replaceTile(tileIdx, tile, newTile, action.updateParams); newTile.setUpdateEmit(this._emitSpontanousUpdate); @@ -303,7 +310,10 @@ export function tests() { } } const entries = new ObservableArray([{n: 5}, {n: 10}]); - const tiles = new TilesCollection(entries, entry => new UpdateOnSiblingTile(entry)); + const tileOptions = { + tileClassForEntry: entry => UpdateOnSiblingTile, + }; + const tiles = new TilesCollection(entries, tileOptions); let receivedAdd = false; tiles.subscribe({ onAdd(idx, tile) { @@ -326,7 +336,10 @@ export function tests() { } } const entries = new ObservableArray([{n: 5}, {n: 10}, {n: 15}]); - const tiles = new TilesCollection(entries, entry => new UpdateOnSiblingTile(entry)); + const tileOptions = { + tileClassForEntry: entry => UpdateOnSiblingTile, + }; + const tiles = new TilesCollection(entries, tileOptions); const events = []; tiles.subscribe({ onUpdate(idx, tile) { diff --git a/src/domain/session/room/timeline/TimelineViewModel.js b/src/domain/session/room/timeline/TimelineViewModel.js index 2408146d..cf36fce4 100644 --- a/src/domain/session/room/timeline/TimelineViewModel.js +++ b/src/domain/session/room/timeline/TimelineViewModel.js @@ -37,9 +37,9 @@ import {ViewModel} from "../../../ViewModel"; export class TimelineViewModel extends ViewModel { constructor(options) { super(options); - const {timeline, tilesCreator} = options; + const {timeline, tileOptions} = options; this._timeline = this.track(timeline); - this._tiles = new TilesCollection(timeline.entries, tilesCreator); + this._tiles = new TilesCollection(timeline.entries, tileOptions); this._startTile = null; this._endTile = null; this._topLoadingPromise = null; diff --git a/src/domain/session/room/timeline/tiles/BaseMediaTile.js b/src/domain/session/room/timeline/tiles/BaseMediaTile.js index a927d766..0ba5b9a9 100644 --- a/src/domain/session/room/timeline/tiles/BaseMediaTile.js +++ b/src/domain/session/room/timeline/tiles/BaseMediaTile.js @@ -21,8 +21,8 @@ const MAX_HEIGHT = 300; const MAX_WIDTH = 400; export class BaseMediaTile extends BaseMessageTile { - constructor(options) { - super(options); + constructor(entry, options) { + super(entry, options); this._decryptedThumbnail = null; this._decryptedFile = null; this._isVisible = false; diff --git a/src/domain/session/room/timeline/tiles/BaseMessageTile.js b/src/domain/session/room/timeline/tiles/BaseMessageTile.js index 3385a587..03cc16ba 100644 --- a/src/domain/session/room/timeline/tiles/BaseMessageTile.js +++ b/src/domain/session/room/timeline/tiles/BaseMessageTile.js @@ -19,8 +19,8 @@ import {ReactionsViewModel} from "../ReactionsViewModel.js"; import {getIdentifierColorNumber, avatarInitials, getAvatarHttpUrl} from "../../../../avatar"; export class BaseMessageTile extends SimpleTile { - constructor(options) { - super(options); + constructor(entry, options) { + super(entry, options); this._date = this._entry.timestamp ? new Date(this._entry.timestamp) : null; this._isContinuation = false; this._reactions = null; @@ -28,7 +28,7 @@ export class BaseMessageTile extends SimpleTile { if (this._entry.annotations || this._entry.pendingAnnotations) { this._updateReactions(); } - this._updateReplyTileIfNeeded(options.tilesCreator, undefined); + this._updateReplyTileIfNeeded(undefined); } notifyVisible() { @@ -122,23 +122,27 @@ export class BaseMessageTile extends SimpleTile { } } - updateEntry(entry, param, tilesCreator) { - const action = super.updateEntry(entry, param, tilesCreator); + updateEntry(entry, param) { + const action = super.updateEntry(entry, param); if (action.shouldUpdate) { this._updateReactions(); } - this._updateReplyTileIfNeeded(tilesCreator, param); + this._updateReplyTileIfNeeded(param); return action; } - _updateReplyTileIfNeeded(tilesCreator, param) { + _updateReplyTileIfNeeded(param) { const replyEntry = this._entry.contextEntry; if (replyEntry) { // this is an update to contextEntry used for replyPreview - const action = this._replyTile?.updateEntry(replyEntry, param, tilesCreator); + const action = this._replyTile?.updateEntry(replyEntry, param); if (action?.shouldReplace || !this._replyTile) { this.disposeTracked(this._replyTile); - this._replyTile = tilesCreator(replyEntry); + const tileClassForEntry = this._options.tileClassForEntry; + const ReplyTile = tileClassForEntry(replyEntry); + if (ReplyTile) { + this._replyTile = new ReplyTile(replyEntry, this._options); + } } if(action?.shouldUpdate) { this._replyTile?.emitChange(); diff --git a/src/domain/session/room/timeline/tiles/BaseTextTile.js b/src/domain/session/room/timeline/tiles/BaseTextTile.js index 164443e3..8e78c95f 100644 --- a/src/domain/session/room/timeline/tiles/BaseTextTile.js +++ b/src/domain/session/room/timeline/tiles/BaseTextTile.js @@ -21,8 +21,8 @@ import {createEnum} from "../../../../../utils/enum"; export const BodyFormat = createEnum("Plain", "Html"); export class BaseTextTile extends BaseMessageTile { - constructor(options) { - super(options); + constructor(entry, options) { + super(entry, options); this._messageBody = null; this._format = null } diff --git a/src/domain/session/room/timeline/tiles/EncryptedEventTile.js b/src/domain/session/room/timeline/tiles/EncryptedEventTile.js index 50f507eb..b96e2d85 100644 --- a/src/domain/session/room/timeline/tiles/EncryptedEventTile.js +++ b/src/domain/session/room/timeline/tiles/EncryptedEventTile.js @@ -18,8 +18,8 @@ import {BaseTextTile} from "./BaseTextTile.js"; import {UpdateAction} from "../UpdateAction.js"; export class EncryptedEventTile extends BaseTextTile { - updateEntry(entry, params, tilesCreator) { - const parentResult = super.updateEntry(entry, params, tilesCreator); + updateEntry(entry, params) { + const parentResult = super.updateEntry(entry, params); // event got decrypted, recreate the tile and replace this one with it if (entry.eventType !== "m.room.encrypted") { // the "shape" parameter trigger tile recreation in TimelineView diff --git a/src/domain/session/room/timeline/tiles/FileTile.js b/src/domain/session/room/timeline/tiles/FileTile.js index 1007d28c..3f7b539b 100644 --- a/src/domain/session/room/timeline/tiles/FileTile.js +++ b/src/domain/session/room/timeline/tiles/FileTile.js @@ -20,8 +20,8 @@ import {formatSize} from "../../../../../utils/formatSize"; import {SendStatus} from "../../../../../matrix/room/sending/PendingEvent.js"; export class FileTile extends BaseMessageTile { - constructor(options) { - super(options); + constructor(entry, options) { + super(entry, options); this._downloadError = null; this._downloading = false; } diff --git a/src/domain/session/room/timeline/tiles/GapTile.js b/src/domain/session/room/timeline/tiles/GapTile.js index df0cedd9..6caa4b9b 100644 --- a/src/domain/session/room/timeline/tiles/GapTile.js +++ b/src/domain/session/room/timeline/tiles/GapTile.js @@ -18,8 +18,8 @@ import {SimpleTile} from "./SimpleTile.js"; import {UpdateAction} from "../UpdateAction.js"; export class GapTile extends SimpleTile { - constructor(options) { - super(options); + constructor(entry, options) { + super(entry, options); this._loading = false; this._error = null; this._isAtTop = true; @@ -81,8 +81,8 @@ export class GapTile extends SimpleTile { this._siblingChanged = true; } - updateEntry(entry, params, tilesCreator) { - super.updateEntry(entry, params, tilesCreator); + updateEntry(entry, params) { + super.updateEntry(entry, params); if (!entry.isGap) { return UpdateAction.Remove(); } else { @@ -125,7 +125,7 @@ export function tests() { tile.updateEntry(newEntry); } }; - const tile = new GapTile({entry: new FragmentBoundaryEntry(fragment, true), roomVM: {room}}); + const tile = new GapTile(new FragmentBoundaryEntry(fragment, true), {roomVM: {room}}); await tile.fill(); await tile.fill(); await tile.fill(); diff --git a/src/domain/session/room/timeline/tiles/ImageTile.js b/src/domain/session/room/timeline/tiles/ImageTile.js index eae2b926..dd959b28 100644 --- a/src/domain/session/room/timeline/tiles/ImageTile.js +++ b/src/domain/session/room/timeline/tiles/ImageTile.js @@ -18,8 +18,8 @@ limitations under the License. import {BaseMediaTile} from "./BaseMediaTile.js"; export class ImageTile extends BaseMediaTile { - constructor(options) { - super(options); + constructor(entry, options) { + super(entry, options); this._lightboxUrl = this.urlCreator.urlForSegments([ // ensure the right room is active if in grid view this.navigation.segment("room", this._room.id), diff --git a/src/domain/session/room/timeline/tiles/RoomMemberTile.js b/src/domain/session/room/timeline/tiles/RoomMemberTile.js index ce41f031..ca9cd9b7 100644 --- a/src/domain/session/room/timeline/tiles/RoomMemberTile.js +++ b/src/domain/session/room/timeline/tiles/RoomMemberTile.js @@ -66,23 +66,25 @@ export class RoomMemberTile extends SimpleTile { export function tests() { return { "user removes display name": (assert) => { - const tile = new RoomMemberTile({ - entry: { + const tile = new RoomMemberTile( + { prevContent: {displayname: "foo", membership: "join"}, content: {membership: "join"}, stateKey: "foo@bar.com", }, - }); + {} + ); assert.strictEqual(tile.announcement, "foo@bar.com removed their name (foo)"); }, "user without display name sets a new display name": (assert) => { - const tile = new RoomMemberTile({ - entry: { + const tile = new RoomMemberTile( + { prevContent: {membership: "join"}, content: {displayname: "foo", membership: "join" }, stateKey: "foo@bar.com", }, - }); + {} + ); assert.strictEqual(tile.announcement, "foo@bar.com changed their name to foo"); }, }; diff --git a/src/domain/session/room/timeline/tiles/SimpleTile.js b/src/domain/session/room/timeline/tiles/SimpleTile.js index af2b0e12..b8a7121e 100644 --- a/src/domain/session/room/timeline/tiles/SimpleTile.js +++ b/src/domain/session/room/timeline/tiles/SimpleTile.js @@ -19,9 +19,9 @@ import {ViewModel} from "../../../../ViewModel"; import {SendStatus} from "../../../../../matrix/room/sending/PendingEvent.js"; export class SimpleTile extends ViewModel { - constructor(options) { + constructor(entry, options) { super(options); - this._entry = options.entry; + this._entry = entry; } // view model props for all subclasses // hmmm, could also do instanceof ... ? diff --git a/src/domain/session/room/timeline/tiles/index.ts b/src/domain/session/room/timeline/tiles/index.ts new file mode 100644 index 00000000..242bea2f --- /dev/null +++ b/src/domain/session/room/timeline/tiles/index.ts @@ -0,0 +1,94 @@ +/* +Copyright 2020 Bruno Windels + +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 {GapTile} from "./GapTile.js"; +import {TextTile} from "./TextTile.js"; +import {RedactedTile} from "./RedactedTile.js"; +import {ImageTile} from "./ImageTile.js"; +import {VideoTile} from "./VideoTile.js"; +import {FileTile} from "./FileTile.js"; +import {LocationTile} from "./LocationTile.js"; +import {RoomNameTile} from "./RoomNameTile.js"; +import {RoomMemberTile} from "./RoomMemberTile.js"; +import {EncryptedEventTile} from "./EncryptedEventTile.js"; +import {EncryptionEnabledTile} from "./EncryptionEnabledTile.js"; +import {MissingAttachmentTile} from "./MissingAttachmentTile.js"; + +import type {SimpleTile} from "./SimpleTile.js"; +import type {Room} from "../../../../../matrix/room/Room"; +import type {Timeline} from "../../../../../matrix/room/timeline/Timeline"; +import type {FragmentBoundaryEntry} from "../../../../../matrix/room/timeline/entries/FragmentBoundaryEntry"; +import type {EventEntry} from "../../../../../matrix/room/timeline/entries/EventEntry"; +import type {PendingEventEntry} from "../../../../../matrix/room/timeline/entries/PendingEventEntry"; +import type {Options as ViewModelOptions} from "../../../../ViewModel"; + +export type TimelineEntry = FragmentBoundaryEntry | EventEntry | PendingEventEntry; +export type TileClassForEntryFn = (entry: TimelineEntry) => TileConstructor | undefined; +export type Options = ViewModelOptions & { + room: Room, + timeline: Timeline + tileClassForEntry: TileClassForEntryFn; +}; +export type TileConstructor = new (entry: TimelineEntry, options: Options) => SimpleTile; + +export function tileClassForEntry(entry: TimelineEntry): TileConstructor | undefined { + if (entry.isGap) { + return GapTile; + } else if (entry.isPending && entry.pendingEvent.isMissingAttachments) { + return MissingAttachmentTile; + } else if (entry.eventType) { + switch (entry.eventType) { + case "m.room.message": { + if (entry.isRedacted) { + return RedactedTile; + } + const content = entry.content; + const msgtype = content && content.msgtype; + switch (msgtype) { + case "m.text": + case "m.notice": + case "m.emote": + return TextTile; + case "m.image": + return ImageTile; + case "m.video": + return VideoTile; + case "m.file": + return FileTile; + case "m.location": + return LocationTile; + default: + // unknown msgtype not rendered + return undefined; + } + } + case "m.room.name": + return RoomNameTile; + case "m.room.member": + return RoomMemberTile; + case "m.room.encrypted": + if (entry.isRedacted) { + return RedactedTile; + } + return EncryptedEventTile; + case "m.room.encryption": + return EncryptionEnabledTile; + default: + // unknown type not rendered + return undefined; + } + } +} diff --git a/src/domain/session/room/timeline/tilesCreator.js b/src/domain/session/room/timeline/tilesCreator.js deleted file mode 100644 index dc9a850e..00000000 --- a/src/domain/session/room/timeline/tilesCreator.js +++ /dev/null @@ -1,81 +0,0 @@ -/* -Copyright 2020 Bruno Windels - -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 {GapTile} from "./tiles/GapTile.js"; -import {TextTile} from "./tiles/TextTile.js"; -import {RedactedTile} from "./tiles/RedactedTile.js"; -import {ImageTile} from "./tiles/ImageTile.js"; -import {VideoTile} from "./tiles/VideoTile.js"; -import {FileTile} from "./tiles/FileTile.js"; -import {LocationTile} from "./tiles/LocationTile.js"; -import {RoomNameTile} from "./tiles/RoomNameTile.js"; -import {RoomMemberTile} from "./tiles/RoomMemberTile.js"; -import {EncryptedEventTile} from "./tiles/EncryptedEventTile.js"; -import {EncryptionEnabledTile} from "./tiles/EncryptionEnabledTile.js"; -import {MissingAttachmentTile} from "./tiles/MissingAttachmentTile.js"; - -export function tilesCreator(baseOptions) { - const tilesCreator = function tilesCreator(entry, emitUpdate) { - const options = Object.assign({entry, emitUpdate, tilesCreator}, baseOptions); - if (entry.isGap) { - return new GapTile(options); - } else if (entry.isPending && entry.pendingEvent.isMissingAttachments) { - return new MissingAttachmentTile(options); - } else if (entry.eventType) { - switch (entry.eventType) { - case "m.room.message": { - if (entry.isRedacted) { - return new RedactedTile(options); - } - const content = entry.content; - const msgtype = content && content.msgtype; - switch (msgtype) { - case "m.text": - case "m.notice": - case "m.emote": - return new TextTile(options); - case "m.image": - return new ImageTile(options); - case "m.video": - return new VideoTile(options); - case "m.file": - return new FileTile(options); - case "m.location": - return new LocationTile(options); - default: - // unknown msgtype not rendered - return null; - } - } - case "m.room.name": - return new RoomNameTile(options); - case "m.room.member": - return new RoomMemberTile(options); - case "m.room.encrypted": - if (entry.isRedacted) { - return new RedactedTile(options); - } - return new EncryptedEventTile(options); - case "m.room.encryption": - return new EncryptionEnabledTile(options); - default: - // unknown type not rendered - return null; - } - } - }; - return tilesCreator; -} diff --git a/src/platform/web/main.js b/src/platform/web/main.js index 1729c17c..9e1ca85e 100644 --- a/src/platform/web/main.js +++ b/src/platform/web/main.js @@ -18,6 +18,7 @@ limitations under the License. // import {RecordRequester, ReplayRequester} from "./matrix/net/request/replay"; import {RootViewModel} from "../../domain/RootViewModel.js"; import {createNavigation, createRouter} from "../../domain/navigation/index.js"; +import {tileClassForEntry} from "../../domain/session/room/timeline/tiles/index"; // Don't use a default export here, as we use multiple entries during legacy build, // which does not support default exports, // see https://github.com/rollup/plugins/tree/master/packages/multi-entry @@ -42,6 +43,8 @@ export async function main(platform) { // so we call it that in the view models urlCreator: urlRouter, navigation, + // which tiles are supported by the timeline + tileClassForEntry }); await vm.load(); platform.createAndMountRootView(vm); diff --git a/src/platform/web/ui/session/room/common.ts b/src/platform/web/ui/session/room/common.ts index 87997cc4..201f14d0 100644 --- a/src/platform/web/ui/session/room/common.ts +++ b/src/platform/web/ui/session/room/common.ts @@ -48,6 +48,6 @@ export function viewClassForEntry(vm: SimpleTile): TileViewConstructor { case "redacted": return RedactedView; default: - throw new Error(`Tiles of shape "${vm.shape}" are not supported, check the tilesCreator function in the view model`); + throw new Error(`Tiles of shape "${vm.shape}" are not supported, check the tileClassForEntry function in the view model`); } }