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._tiles = null;
|
||||||
this._entrySubscription = null;
|
this._entrySubscription = null;
|
||||||
this._tileCreator = tileCreator;
|
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() {
|
onSubscribeFirst() {
|
||||||
|
@ -21,7 +28,7 @@ export default class TilesCollection extends BaseObservableList {
|
||||||
let currentTile = null;
|
let currentTile = null;
|
||||||
for (let entry of this._entries) {
|
for (let entry of this._entries) {
|
||||||
if (!currentTile || !currentTile.tryIncludeEntry(entry)) {
|
if (!currentTile || !currentTile.tryIncludeEntry(entry)) {
|
||||||
currentTile = this._tileCreator(entry);
|
currentTile = this._tileCreator(entry, this._emitSpontanousUpdate);
|
||||||
if (currentTile) {
|
if (currentTile) {
|
||||||
this._tiles.push(currentTile);
|
this._tiles.push(currentTile);
|
||||||
}
|
}
|
||||||
|
@ -86,7 +93,7 @@ export default class TilesCollection extends BaseObservableList {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const newTile = this._tileCreator(entry);
|
const newTile = this._tileCreator(entry, this._emitSpontanousUpdate);
|
||||||
if (newTile) {
|
if (newTile) {
|
||||||
prevTile && prevTile.updateNextSibling(newTile);
|
prevTile && prevTile.updateNextSibling(newTile);
|
||||||
nextTile && nextTile.updatePreviousSibling(newTile);
|
nextTile && nextTile.updatePreviousSibling(newTile);
|
||||||
|
@ -101,9 +108,12 @@ export default class TilesCollection extends BaseObservableList {
|
||||||
const tileIdx = this._findTileIdx(entry);
|
const tileIdx = this._findTileIdx(entry);
|
||||||
const tile = this._findTileAtIdx(entry, tileIdx);
|
const tile = this._findTileAtIdx(entry, tileIdx);
|
||||||
if (tile) {
|
if (tile) {
|
||||||
const newParams = tile.updateEntry(entry, params);
|
const action = tile.updateEntry(entry, params);
|
||||||
if (newParams) {
|
if (action.shouldRemove) {
|
||||||
this.emitUpdate(tileIdx, tile, newParams);
|
this._removeTile(tileIdx, tile);
|
||||||
|
}
|
||||||
|
if (action.shouldUpdate) {
|
||||||
|
this.emitUpdate(tileIdx, tile, action.updateParams);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// technically we should handle adding a tile here as well
|
// 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 ...
|
// 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
|
// would also be called when unloading a part of the timeline
|
||||||
onRemove(index, entry) {
|
onRemove(index, entry) {
|
||||||
const tileIdx = this._findTileIdx(entry);
|
const tileIdx = this._findTileIdx(entry);
|
||||||
|
@ -126,12 +145,7 @@ export default class TilesCollection extends BaseObservableList {
|
||||||
if (tile) {
|
if (tile) {
|
||||||
const removeTile = tile.removeEntry(entry);
|
const removeTile = tile.removeEntry(entry);
|
||||||
if (removeTile) {
|
if (removeTile) {
|
||||||
const prevTile = this._getTileAtIdx(tileIdx - 1);
|
this._removeTile(tileIdx, tile);
|
||||||
const nextTile = this._getTileAtIdx(tileIdx + 1);
|
|
||||||
this._tiles.splice(tileIdx, 1);
|
|
||||||
prevTile && prevTile.updateNextSibling(nextTile);
|
|
||||||
nextTile && nextTile.updatePreviousSibling(prevTile);
|
|
||||||
this.emitRemove(tileIdx, tile);
|
|
||||||
} else {
|
} else {
|
||||||
this.emitUpdate(tileIdx, tile);
|
this.emitUpdate(tileIdx, tile);
|
||||||
}
|
}
|
||||||
|
@ -140,7 +154,8 @@ export default class TilesCollection extends BaseObservableList {
|
||||||
|
|
||||||
onMove(fromIdx, toIdx, value) {
|
onMove(fromIdx, toIdx, value) {
|
||||||
// this ... cannot happen in the timeline?
|
// 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]() {
|
[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 SimpleTile from "./SimpleTile.js";
|
||||||
|
import UpdateAction from "../UpdateAction.js";
|
||||||
|
|
||||||
export default class GapTile extends SimpleTile {
|
export default class GapTile extends SimpleTile {
|
||||||
constructor(options, timeline) {
|
constructor(options, timeline) {
|
||||||
|
@ -12,20 +13,28 @@ export default class GapTile extends SimpleTile {
|
||||||
// prevent doing this twice
|
// prevent doing this twice
|
||||||
if (!this._loading) {
|
if (!this._loading) {
|
||||||
this._loading = true;
|
this._loading = true;
|
||||||
// this._emitUpdate("isLoading");
|
this.emitUpdate("isLoading");
|
||||||
try {
|
try {
|
||||||
await this._timeline.fillGap(this._entry, 10);
|
await this._timeline.fillGap(this._entry, 10);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(`timeline.fillGap(): ${err.message}:\n${err.stack}`);
|
console.error(`timeline.fillGap(): ${err.message}:\n${err.stack}`);
|
||||||
this._error = err;
|
this._error = err;
|
||||||
// this._emitUpdate("error");
|
this.emitUpdate("error");
|
||||||
} finally {
|
} finally {
|
||||||
this._loading = false;
|
this._loading = false;
|
||||||
// this._emitUpdate("isLoading");
|
this.emitUpdate("isLoading");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateEntry(entry) {
|
||||||
|
if (!entry.isGap) {
|
||||||
|
return UpdateAction.Remove();
|
||||||
|
} else {
|
||||||
|
return UpdateAction.Nothing();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
get shape() {
|
get shape() {
|
||||||
return "gap";
|
return "gap";
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import UpdateAction from "../UpdateAction.js";
|
||||||
|
|
||||||
export default class SimpleTile {
|
export default class SimpleTile {
|
||||||
constructor({entry, emitUpdate}) {
|
constructor({entry, emitUpdate}) {
|
||||||
this._entry = entry;
|
this._entry = entry;
|
||||||
|
@ -6,6 +8,7 @@ export default class SimpleTile {
|
||||||
// view model props for all subclasses
|
// view model props for all subclasses
|
||||||
// hmmm, could also do instanceof ... ?
|
// hmmm, could also do instanceof ... ?
|
||||||
get shape() {
|
get shape() {
|
||||||
|
return null;
|
||||||
// "gap" | "message" | "image" | ... ?
|
// "gap" | "message" | "image" | ... ?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,15 +31,18 @@ export default class SimpleTile {
|
||||||
return this._entry;
|
return this._entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
emitUpdate(paramName) {
|
||||||
|
this._emitUpdate(this, paramName);
|
||||||
|
}
|
||||||
|
|
||||||
// TilesCollection contract
|
// TilesCollection contract
|
||||||
compareEntry(entry) {
|
compareEntry(entry) {
|
||||||
return this._entry.compare(entry);
|
return this._entry.compare(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
// update received for already included (falls within sort keys) entry
|
// update received for already included (falls within sort keys) entry
|
||||||
updateEntry(entry) {
|
updateEntry() {
|
||||||
// return names of props updated, or true for all, or null for no changes caused
|
return UpdateAction.Nothing();
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// return whether the tile should be removed
|
// return whether the tile should be removed
|
||||||
|
|
|
@ -5,8 +5,8 @@ import LocationTile from "./tiles/LocationTile.js";
|
||||||
import RoomNameTile from "./tiles/RoomNameTile.js";
|
import RoomNameTile from "./tiles/RoomNameTile.js";
|
||||||
import RoomMemberTile from "./tiles/RoomMemberTile.js";
|
import RoomMemberTile from "./tiles/RoomMemberTile.js";
|
||||||
|
|
||||||
export default function ({timeline, emitUpdate}) {
|
export default function ({timeline}) {
|
||||||
return function tilesCreator(entry) {
|
return function tilesCreator(entry, emitUpdate) {
|
||||||
const options = {entry, emitUpdate};
|
const options = {entry, emitUpdate};
|
||||||
if (entry.isGap) {
|
if (entry.isGap) {
|
||||||
return new GapTile(options, timeline);
|
return new GapTile(options, timeline);
|
||||||
|
|
|
@ -17,7 +17,8 @@ export default class TimelineTile {
|
||||||
|
|
||||||
unmount() {}
|
unmount() {}
|
||||||
|
|
||||||
update() {}
|
update(vm, paramName) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderTile(tile) {
|
function renderTile(tile) {
|
||||||
|
|
Reference in a new issue