more fixes, timeline is showing again

This commit is contained in:
Bruno Windels 2019-06-02 14:59:30 +02:00
parent a1e527ccbc
commit e339cb7321
15 changed files with 46 additions and 17 deletions

View file

@ -45,6 +45,10 @@
flex: 1; flex: 1;
overflow-y: scroll; overflow-y: scroll;
} }
.RoomView_error {
color: red;
}
</style> </style>
</head> </head>
<body> <body>

View file

@ -16,8 +16,9 @@ export default class RoomViewModel extends EventEmitter {
try { try {
this._timeline = await this._room.openTimeline(); this._timeline = await this._room.openTimeline();
this._timelineVM = new TimelineViewModel(this._timeline); this._timelineVM = new TimelineViewModel(this._timeline);
this.emit("change", "timelineEntries"); this.emit("change", "timelineViewModel");
} catch (err) { } catch (err) {
console.error(`room.openTimeline(): ${err.message}:\n${err.stack}`);
this._timelineError = err; this._timelineError = err;
this.emit("change", "error"); this.emit("change", "error");
} }

View file

@ -22,10 +22,11 @@ export default class TilesCollection extends BaseObservableList {
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);
// if (currentTile) here? if (currentTile) {
this._tiles.push(currentTile); this._tiles.push(currentTile);
} }
} }
}
let prevTile = null; let prevTile = null;
for (let tile of this._tiles) { for (let tile of this._tiles) {
if (prevTile) { if (prevTile) {
@ -145,4 +146,8 @@ export default class TilesCollection extends BaseObservableList {
[Symbol.iterator]() { [Symbol.iterator]() {
return this._tiles.values(); return this._tiles.values();
} }
get length() {
return this._tiles.length;
}
} }

View file

@ -4,10 +4,11 @@ export default class TextTile extends MessageTile {
get label() { get label() {
const content = this._getContent(); const content = this._getContent();
const body = content && content.body; const body = content && content.body;
if (this._entry.type() === "m.emote") { const sender = this._entry.event.sender;
return `* ${this._entry.event.sender} ${body}`; if (this._entry.type === "m.emote") {
return `* ${sender} ${body}`;
} else { } else {
return body; return `${sender}: ${body}`;
} }
} }
} }

View file

@ -88,6 +88,6 @@ export default async function main(label, button, container) {
label.innerText = "sync stopped"; label.innerText = "sync stopped";
}); });
} catch(err) { } catch(err) {
console.error(err); console.error(`${err.message}:\n${err.stack}`);
} }
} }

View file

@ -20,7 +20,7 @@ export default class Timeline {
/** @package */ /** @package */
async load() { async load() {
const entries = this._timelineReader.readFromEnd(100); const entries = await this._timelineReader.readFromEnd(100);
this._entriesList.setManySorted(entries); this._entriesList.setManySorted(entries);
} }

View file

@ -1,4 +1,5 @@
//entries can be sorted, first by fragment, then by entry index. //entries can be sorted, first by fragment, then by entry index.
import EventKey from "../EventKey.js";
export default class BaseEntry { export default class BaseEntry {
constructor(fragmentIdComparer) { constructor(fragmentIdComparer) {
@ -21,4 +22,8 @@ export default class BaseEntry {
return this._fragmentIdComparer.compare(this.fragmentId, otherEntry.fragmentId); return this._fragmentIdComparer.compare(this.fragmentId, otherEntry.fragmentId);
} }
} }
asEventKey() {
return new EventKey(this.fragmentId, this.entryIndex);
}
} }

View file

@ -8,6 +8,7 @@ export default class SyncWriter {
this._roomId = roomId; this._roomId = roomId;
this._storage = storage; this._storage = storage;
this._fragmentIdComparer = fragmentIdComparer; this._fragmentIdComparer = fragmentIdComparer;
this._lastLiveKey = null;
} }
async load(txn) { async load(txn) {
@ -98,7 +99,6 @@ export default class SyncWriter {
// right thing to do? if the txn fails, not sure we'll continue anyways ... // right thing to do? if the txn fails, not sure we'll continue anyways ...
// only advance the key once the transaction has succeeded // only advance the key once the transaction has succeeded
txn.complete().then(() => { txn.complete().then(() => {
console.log("txn complete, setting key");
this._lastLiveKey = currentKey; this._lastLiveKey = currentKey;
}) })

View file

@ -32,9 +32,9 @@ export default class TimelineReader {
while (entries.length < amount && eventKey) { while (entries.length < amount && eventKey) {
let eventsWithinFragment; let eventsWithinFragment;
if (direction.isForward) { if (direction.isForward) {
eventsWithinFragment = timelineStore.eventsAfter(eventKey, amount); eventsWithinFragment = await timelineStore.eventsAfter(this._roomId, eventKey, amount);
} else { } else {
eventsWithinFragment = timelineStore.eventsBefore(eventKey, amount); eventsWithinFragment = await timelineStore.eventsBefore(this._roomId, eventKey, amount);
} }
const eventEntries = eventsWithinFragment.map(e => new EventEntry(e, this._fragmentIdComparer)); const eventEntries = eventsWithinFragment.map(e => new EventEntry(e, this._fragmentIdComparer));
entries = directionalConcat(entries, eventEntries, direction); entries = directionalConcat(entries, eventEntries, direction);
@ -52,7 +52,7 @@ export default class TimelineReader {
this._fragmentIdComparer.add(nextFragment); this._fragmentIdComparer.add(nextFragment);
const nextFragmentEntry = new FragmentBoundaryEntry(nextFragment, direction.isForward, this._fragmentIdComparer); const nextFragmentEntry = new FragmentBoundaryEntry(nextFragment, direction.isForward, this._fragmentIdComparer);
directionalAppend(entries, nextFragmentEntry, direction); directionalAppend(entries, nextFragmentEntry, direction);
eventKey = new EventKey(nextFragmentEntry.fragmentId, nextFragmentEntry.eventIndex); eventKey = nextFragmentEntry.asEventKey();
} else { } else {
eventKey = null; eventKey = null;
} }
@ -71,8 +71,8 @@ export default class TimelineReader {
} }
this._fragmentIdComparer.add(liveFragment); this._fragmentIdComparer.add(liveFragment);
const liveFragmentEntry = FragmentBoundaryEntry.end(liveFragment, this._fragmentIdComparer); const liveFragmentEntry = FragmentBoundaryEntry.end(liveFragment, this._fragmentIdComparer);
const eventKey = new EventKey(liveFragmentEntry.fragmentId, liveFragmentEntry.eventIndex); const eventKey = liveFragmentEntry.asEventKey();
const entries = this._readFrom(eventKey, Direction.Backward, amount, txn); const entries = await this._readFrom(eventKey, Direction.Backward, amount, txn);
entries.unshift(liveFragmentEntry); entries.unshift(liveFragmentEntry);
return entries; return entries;
} }

View file

@ -15,7 +15,7 @@ function createStores(db) {
db.createObjectStore("timelineFragments", {keyPath: ["roomId", "id"]}); db.createObjectStore("timelineFragments", {keyPath: ["roomId", "id"]});
const timelineEvents = db.createObjectStore("timelineEvents", {keyPath: ["roomId", "fragmentId", "eventIndex"]}); const timelineEvents = db.createObjectStore("timelineEvents", {keyPath: ["roomId", "fragmentId", "eventIndex"]});
timelineEvents.createIndex("byEventId", [ timelineEvents.createIndex("byEventId", [
"event.room_id", "roomId",
"event.event_id" "event.event_id"
], {unique: true}); ], {unique: true});

View file

@ -94,7 +94,7 @@ export default class Sync extends EventEmitter {
await Promise.all(promises); await Promise.all(promises);
} }
} catch(err) { } catch(err) {
console.warn("aborting syncTxn because of error", err.stack); console.warn("aborting syncTxn because of error");
// avoid corrupting state by only // avoid corrupting state by only
// storing the sync up till the point // storing the sync up till the point
// the exception occurred // the exception occurred

View file

@ -34,4 +34,11 @@ export default class BaseObservableList extends BaseObservableCollection {
} }
} }
[Symbol.iterator]() {
throw new Error("unimplemented");
}
get length() {
throw new Error("unimplemented");
}
} }

View file

@ -14,11 +14,14 @@ export default class RoomView {
mount() { mount() {
this._viewModel.on("change", this._onViewModelUpdate); this._viewModel.on("change", this._onViewModelUpdate);
this._nameLabel = html.h2(null, this._viewModel.name); this._nameLabel = html.h2(null, this._viewModel.name);
this._errorLabel = html.div({className: "RoomView_error"});
this._timelineList = new ListView({}, entry => new TimelineTile(entry)); this._timelineList = new ListView({}, entry => new TimelineTile(entry));
this._timelineList.mount(); this._timelineList.mount();
this._root = html.div({className: "RoomView"}, [ this._root = html.div({className: "RoomView"}, [
this._nameLabel, this._nameLabel,
this._errorLabel,
this._timelineList.root() this._timelineList.root()
]); ]);
@ -40,6 +43,8 @@ export default class RoomView {
} }
else if (prop === "timelineViewModel") { else if (prop === "timelineViewModel") {
this._timelineList.update({list: this._viewModel.timelineViewModel.tiles}); this._timelineList.update({list: this._viewModel.timelineViewModel.tiles});
} else if (prop === "error") {
this._errorLabel.innerText = this._viewModel.error;
} }
} }

View file

@ -23,7 +23,7 @@ export default class TimelineTile {
function renderTile(tile) { function renderTile(tile) {
switch (tile.shape) { switch (tile.shape) {
case "message": case "message":
return html.li(null, [html.strong(tile.sender), `: ${tile.label}`]); return html.li(null, tile.label);
case "gap": { case "gap": {
const button = html.button(null, (tile.isUp ? "🠝" : "🠟") + " fill gap"); const button = html.button(null, (tile.isUp ? "🠝" : "🠟") + " fill gap");
const handler = () => { const handler = () => {

View file

@ -51,3 +51,4 @@ export function main(... params) { return el("main", ... params); }
export function article(... params) { return el("article", ... params); } export function article(... params) { return el("article", ... params); }
export function aside(... params) { return el("aside", ... params); } export function aside(... params) { return el("aside", ... params); }
export function pre(... params) { return el("pre", ... params); } export function pre(... params) { return el("pre", ... params); }
export function button(... params) { return el("button", ... params); }