forked from mystiq/hydrogen-web
support updates originating from tile, and removing tile on update
This commit is contained in:
parent
422cca746b
commit
64f126ba68
6 changed files with 83 additions and 21 deletions
|
@ -9,6 +9,13 @@ export default class TilesCollection extends BaseObservableList {
|
|||
this._tiles = null;
|
||||
this._entrySubscription = null;
|
||||
this._tileCreator = tileCreator;
|
||||
this._emitSpontanousUpdate = this._emitSpontanousUpdate.bind(this);
|
||||
}
|
||||
|
||||
_emitSpontanousUpdate(tile, params) {
|
||||
const entry = tile.lowerEntry;
|
||||
const tileIdx = this._findTileIdx(entry);
|
||||
this.emitUpdate(tileIdx, tile, params);
|
||||
}
|
||||
|
||||
onSubscribeFirst() {
|
||||
|
@ -21,7 +28,7 @@ export default class TilesCollection extends BaseObservableList {
|
|||
let currentTile = null;
|
||||
for (let entry of this._entries) {
|
||||
if (!currentTile || !currentTile.tryIncludeEntry(entry)) {
|
||||
currentTile = this._tileCreator(entry);
|
||||
currentTile = this._tileCreator(entry, this._emitSpontanousUpdate);
|
||||
if (currentTile) {
|
||||
this._tiles.push(currentTile);
|
||||
}
|
||||
|
@ -86,7 +93,7 @@ export default class TilesCollection extends BaseObservableList {
|
|||
return;
|
||||
}
|
||||
|
||||
const newTile = this._tileCreator(entry);
|
||||
const newTile = this._tileCreator(entry, this._emitSpontanousUpdate);
|
||||
if (newTile) {
|
||||
prevTile && prevTile.updateNextSibling(newTile);
|
||||
nextTile && nextTile.updatePreviousSibling(newTile);
|
||||
|
@ -101,9 +108,12 @@ export default class TilesCollection extends BaseObservableList {
|
|||
const tileIdx = this._findTileIdx(entry);
|
||||
const tile = this._findTileAtIdx(entry, tileIdx);
|
||||
if (tile) {
|
||||
const newParams = tile.updateEntry(entry, params);
|
||||
if (newParams) {
|
||||
this.emitUpdate(tileIdx, tile, newParams);
|
||||
const action = tile.updateEntry(entry, params);
|
||||
if (action.shouldRemove) {
|
||||
this._removeTile(tileIdx, tile);
|
||||
}
|
||||
if (action.shouldUpdate) {
|
||||
this.emitUpdate(tileIdx, tile, action.updateParams);
|
||||
}
|
||||
}
|
||||
// technically we should handle adding a tile here as well
|
||||
|
@ -119,6 +129,15 @@ export default class TilesCollection extends BaseObservableList {
|
|||
// merge with neighbours? ... hard to imagine use case for this ...
|
||||
}
|
||||
|
||||
_removeTile(tileIdx, tile) {
|
||||
const prevTile = this._getTileAtIdx(tileIdx - 1);
|
||||
const nextTile = this._getTileAtIdx(tileIdx + 1);
|
||||
this._tiles.splice(tileIdx, 1);
|
||||
prevTile && prevTile.updateNextSibling(nextTile);
|
||||
nextTile && nextTile.updatePreviousSibling(prevTile);
|
||||
this.emitRemove(tileIdx, tile);
|
||||
}
|
||||
|
||||
// would also be called when unloading a part of the timeline
|
||||
onRemove(index, entry) {
|
||||
const tileIdx = this._findTileIdx(entry);
|
||||
|
@ -126,12 +145,7 @@ export default class TilesCollection extends BaseObservableList {
|
|||
if (tile) {
|
||||
const removeTile = tile.removeEntry(entry);
|
||||
if (removeTile) {
|
||||
const prevTile = this._getTileAtIdx(tileIdx - 1);
|
||||
const nextTile = this._getTileAtIdx(tileIdx + 1);
|
||||
this._tiles.splice(tileIdx, 1);
|
||||
prevTile && prevTile.updateNextSibling(nextTile);
|
||||
nextTile && nextTile.updatePreviousSibling(prevTile);
|
||||
this.emitRemove(tileIdx, tile);
|
||||
this._removeTile(tileIdx, tile);
|
||||
} else {
|
||||
this.emitUpdate(tileIdx, tile);
|
||||
}
|
||||
|
@ -140,7 +154,8 @@ export default class TilesCollection extends BaseObservableList {
|
|||
|
||||
onMove(fromIdx, toIdx, value) {
|
||||
// this ... cannot happen in the timeline?
|
||||
// should be sorted by sortKey and sortKey is immutable
|
||||
// perhaps we can use this event to support a local echo (in a different fragment)
|
||||
// to be moved to the key of the remote echo, so we don't loose state ... ?
|
||||
}
|
||||
|
||||
[Symbol.iterator]() {
|
||||
|
|
31
src/domain/session/room/timeline/UpdateAction.js
Normal file
31
src/domain/session/room/timeline/UpdateAction.js
Normal file
|
@ -0,0 +1,31 @@
|
|||
export default class UpdateAction {
|
||||
constructor(remove, update, updateParams) {
|
||||
this._remove = remove;
|
||||
this._update = update;
|
||||
this._updateParams = updateParams;
|
||||
}
|
||||
|
||||
get shouldRemove() {
|
||||
return this._remove;
|
||||
}
|
||||
|
||||
get shouldUpdate() {
|
||||
return this._update;
|
||||
}
|
||||
|
||||
get updateParams() {
|
||||
return this._updateParams;
|
||||
}
|
||||
|
||||
static Remove() {
|
||||
return new UpdateAction(true, false, null);
|
||||
}
|
||||
|
||||
static Update(newParams) {
|
||||
return new UpdateAction(false, true, newParams);
|
||||
}
|
||||
|
||||
static Nothing() {
|
||||
return new UpdateAction(false, false, null);
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
import SimpleTile from "./SimpleTile.js";
|
||||
import UpdateAction from "../UpdateAction.js";
|
||||
|
||||
export default class GapTile extends SimpleTile {
|
||||
constructor(options, timeline) {
|
||||
|
@ -12,20 +13,28 @@ export default class GapTile extends SimpleTile {
|
|||
// prevent doing this twice
|
||||
if (!this._loading) {
|
||||
this._loading = true;
|
||||
// this._emitUpdate("isLoading");
|
||||
this.emitUpdate("isLoading");
|
||||
try {
|
||||
await this._timeline.fillGap(this._entry, 10);
|
||||
} catch (err) {
|
||||
console.error(`timeline.fillGap(): ${err.message}:\n${err.stack}`);
|
||||
this._error = err;
|
||||
// this._emitUpdate("error");
|
||||
this.emitUpdate("error");
|
||||
} finally {
|
||||
this._loading = false;
|
||||
// this._emitUpdate("isLoading");
|
||||
this.emitUpdate("isLoading");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateEntry(entry) {
|
||||
if (!entry.isGap) {
|
||||
return UpdateAction.Remove();
|
||||
} else {
|
||||
return UpdateAction.Nothing();
|
||||
}
|
||||
}
|
||||
|
||||
get shape() {
|
||||
return "gap";
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import UpdateAction from "../UpdateAction.js";
|
||||
|
||||
export default class SimpleTile {
|
||||
constructor({entry, emitUpdate}) {
|
||||
this._entry = entry;
|
||||
|
@ -6,6 +8,7 @@ export default class SimpleTile {
|
|||
// view model props for all subclasses
|
||||
// hmmm, could also do instanceof ... ?
|
||||
get shape() {
|
||||
return null;
|
||||
// "gap" | "message" | "image" | ... ?
|
||||
}
|
||||
|
||||
|
@ -28,15 +31,18 @@ export default class SimpleTile {
|
|||
return this._entry;
|
||||
}
|
||||
|
||||
emitUpdate(paramName) {
|
||||
this._emitUpdate(this, paramName);
|
||||
}
|
||||
|
||||
// TilesCollection contract
|
||||
compareEntry(entry) {
|
||||
return this._entry.compare(entry);
|
||||
}
|
||||
|
||||
// update received for already included (falls within sort keys) entry
|
||||
updateEntry(entry) {
|
||||
// return names of props updated, or true for all, or null for no changes caused
|
||||
return true;
|
||||
updateEntry() {
|
||||
return UpdateAction.Nothing();
|
||||
}
|
||||
|
||||
// return whether the tile should be removed
|
||||
|
|
|
@ -5,8 +5,8 @@ import LocationTile from "./tiles/LocationTile.js";
|
|||
import RoomNameTile from "./tiles/RoomNameTile.js";
|
||||
import RoomMemberTile from "./tiles/RoomMemberTile.js";
|
||||
|
||||
export default function ({timeline, emitUpdate}) {
|
||||
return function tilesCreator(entry) {
|
||||
export default function ({timeline}) {
|
||||
return function tilesCreator(entry, emitUpdate) {
|
||||
const options = {entry, emitUpdate};
|
||||
if (entry.isGap) {
|
||||
return new GapTile(options, timeline);
|
||||
|
|
|
@ -17,7 +17,8 @@ export default class TimelineTile {
|
|||
|
||||
unmount() {}
|
||||
|
||||
update() {}
|
||||
update(vm, paramName) {
|
||||
}
|
||||
}
|
||||
|
||||
function renderTile(tile) {
|
||||
|
|
Loading…
Reference in a new issue