forked from mystiq/hydrogen-web
more fixes, timeline is showing again
This commit is contained in:
parent
a1e527ccbc
commit
e339cb7321
15 changed files with 46 additions and 17 deletions
|
@ -45,6 +45,10 @@
|
||||||
flex: 1;
|
flex: 1;
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.RoomView_error {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
|
@ -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");
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,8 +22,9 @@ 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;
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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});
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -34,4 +34,11 @@ export default class BaseObservableList extends BaseObservableCollection {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Symbol.iterator]() {
|
||||||
|
throw new Error("unimplemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
get length() {
|
||||||
|
throw new Error("unimplemented");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 = () => {
|
||||||
|
|
|
@ -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); }
|
||||||
|
|
Loading…
Reference in a new issue