From e13c4fdb00fb476f7f85289ca881ddddd568c331 Mon Sep 17 00:00:00 2001 From: Cadence Ember Date: Tue, 20 Oct 2020 02:05:16 +1300 Subject: [PATCH] Member data and message dates --- build/index.html | 4 ++-- build/static/Timeline.js | 47 +++++++++++++++++++++++++++++++------ build/static/room-picker.js | 13 ++++------ build/static/sync/sync.js | 19 +++++++-------- spec.js | 5 ++++ src/js/Timeline.js | 47 +++++++++++++++++++++++++++++++------ src/js/functions.js | 12 ++++++++++ src/js/room-picker.js | 13 ++++------ src/js/sync/sync.js | 19 +++++++-------- 9 files changed, 123 insertions(+), 56 deletions(-) create mode 100644 src/js/functions.js diff --git a/build/index.html b/build/index.html index 1fb6d0f..1304e78 100644 --- a/build/index.html +++ b/build/index.html @@ -5,8 +5,8 @@ - - + + Carbon diff --git a/build/static/Timeline.js b/build/static/Timeline.js index f412366..0adce82 100644 --- a/build/static/Timeline.js +++ b/build/static/Timeline.js @@ -1,7 +1,11 @@ import {ElemJS, ejs} from "./basic.js" import {Subscribable} from "./store/Subscribable.js" +import {store} from "./store/store.js" import {Anchor} from "./Anchor.js" import * as lsm from "./lsm.js" +import {resolveMxc} from "./functions.js" + +const dateFormatter = Intl.DateTimeFormat("default", {hour: "numeric", minute: "numeric", second: "numeric", day: "numeric", month: "short", year: "numeric"}) let sentIndex = 0 @@ -59,6 +63,35 @@ class Event extends ElemJS { } } +class Sender { + constructor(roomID, mxid) { + this.sender = store.rooms.get(roomID).value().members.get(mxid) + this.sender.subscribe("changeSelf", this.update.bind(this)) + this.name = new ElemJS("div").class("c-message-group__name") + this.avatar = new ElemJS("div").class("c-message-group__avatar") + this.update() + } + + update() { + if (this.sender.exists()) { + // name + this.name.text(this.sender.value().content.displayname) + + // avatar + this.avatar.clearChildren() + if (this.sender.value().content.avatar_url) { + this.avatar.child( + ejs("img").class("c-message-group__icon").attribute("src", resolveMxc(this.sender.value().content.avatar_url, 32, "crop")) + ) + } else { + this.avatar.child( + ejs("div").class("c-message-group__icon") + ) + } + } + } +} + class EventGroup extends ElemJS { constructor(reactive, list) { super("div") @@ -69,14 +102,13 @@ class EventGroup extends ElemJS { sender: list[0].data.sender, origin_server_ts: list[0].data.origin_server_ts } + this.sender = new Sender(this.reactive.id, this.data.sender) this.child( - ejs("div").class("c-message-group__avatar").child( - ejs("div").class("c-message-group__icon") - ), + this.sender.avatar, this.messages = ejs("div").class("c-message-group__messages").child( ejs("div").class("c-message-group__intro").child( - ejs("div").class("c-message-group__name").text(this.data.sender), - ejs("div").class("c-message-group__date").text(this.data.origin_server_ts) + this.sender.name, + ejs("div").class("c-message-group__date").text(dateFormatter.format(this.data.origin_server_ts)) ), ...this.list ) @@ -102,9 +134,10 @@ class EventGroup extends ElemJS { } class ReactiveTimeline extends ElemJS { - constructor(list) { + constructor(id, list) { super("div") this.class("c-event-groups") + this.id = id this.list = list this.render() } @@ -161,7 +194,7 @@ class Timeline extends Subscribable { this.id = id this.list = [] this.map = new Map() - this.reactiveTimeline = new ReactiveTimeline([]) + this.reactiveTimeline = new ReactiveTimeline(id, []) this.latest = 0 this.pending = new Set() } diff --git a/build/static/room-picker.js b/build/static/room-picker.js index 3de2ab1..e93f72d 100644 --- a/build/static/room-picker.js +++ b/build/static/room-picker.js @@ -1,16 +1,10 @@ import {q, ElemJS, ejs} from "./basic.js" import {store} from "./store/store.js" +import {SubscribeMapList} from "./store/SubscribeMapList.js" +import {SubscribeValue} from "./store/SubscribeValue.js" import {Timeline} from "./Timeline.js" import * as lsm from "./lsm.js" - -function resolveMxc(url, size, method) { - const [server, id] = url.match(/^mxc:\/\/([^/]+)\/(.*)/).slice(1) - if (size && method) { - return `${lsm.get("domain")}/_matrix/media/r0/thumbnail/${server}/${id}?width=${size}&height=${size}&method=${method}` - } else { - return `${lsm.get("domain")}/_matrix/media/r0/download/${server}/${id}` - } -} +import {resolveMxc} from "./functions.js" class ActiveGroupMarker extends ElemJS { constructor() { @@ -70,6 +64,7 @@ class Room extends ElemJS { this.data = data this.timeline = new Timeline(this.id) this.group = null + this.members = new SubscribeMapList(SubscribeValue) this.class("c-room") diff --git a/build/static/sync/sync.js b/build/static/sync/sync.js index e5a8389..54c2652 100644 --- a/build/static/sync/sync.js +++ b/build/static/sync/sync.js @@ -1,18 +1,9 @@ import {store} from "../store/store.js" import * as lsm from "../lsm.js" +import {resolveMxc} from "../functions.js" let lastBatch = null -function resolveMxc(url, size, method) { - const [server, id] = url.match(/^mxc:\/\/([^/]+)\/(.*)/).slice(1) - if (size && method) { - return `${lsm.get("domain")}/_matrix/media/r0/thumbnail/${server}/${id}?width=${size}&height=${size}&method=${method}` - } else { - return `${lsm.get("domain")}/_matrix/media/r0/download/${server}/${id}` - } -} - - function sync() { const url = new URL(`${lsm.get("domain")}/_matrix/client/r0/sync`) url.searchParams.append("access_token", lsm.get("access_token")) @@ -60,7 +51,13 @@ function manageSync(root) { if (!store.rooms.has(id)) { store.rooms.askAdd(id, room) } - const timeline = store.rooms.get(id).value().timeline + const storeRoom = store.rooms.get(id).value() + room.state.events.forEach(event => { + if (event.type === "m.room.member") { + storeRoom.members.get(event.state_key).set(event) + } + }) + const timeline = storeRoom.timeline if (room.timeline.events.length) newEvents = true timeline.updateEvents(room.timeline.events) }) diff --git a/spec.js b/spec.js index 0ebbc17..38bb96e 100644 --- a/spec.js +++ b/spec.js @@ -79,6 +79,11 @@ module.exports = [ source: "/js/chat.js", target: "/static/chat.js" }, + { + type: "js", + source: "/js/functions.js", + target: "/static/functions.js" + }, { type: "file", source: "/assets/fonts/whitney-500.woff", diff --git a/src/js/Timeline.js b/src/js/Timeline.js index f412366..0adce82 100644 --- a/src/js/Timeline.js +++ b/src/js/Timeline.js @@ -1,7 +1,11 @@ import {ElemJS, ejs} from "./basic.js" import {Subscribable} from "./store/Subscribable.js" +import {store} from "./store/store.js" import {Anchor} from "./Anchor.js" import * as lsm from "./lsm.js" +import {resolveMxc} from "./functions.js" + +const dateFormatter = Intl.DateTimeFormat("default", {hour: "numeric", minute: "numeric", second: "numeric", day: "numeric", month: "short", year: "numeric"}) let sentIndex = 0 @@ -59,6 +63,35 @@ class Event extends ElemJS { } } +class Sender { + constructor(roomID, mxid) { + this.sender = store.rooms.get(roomID).value().members.get(mxid) + this.sender.subscribe("changeSelf", this.update.bind(this)) + this.name = new ElemJS("div").class("c-message-group__name") + this.avatar = new ElemJS("div").class("c-message-group__avatar") + this.update() + } + + update() { + if (this.sender.exists()) { + // name + this.name.text(this.sender.value().content.displayname) + + // avatar + this.avatar.clearChildren() + if (this.sender.value().content.avatar_url) { + this.avatar.child( + ejs("img").class("c-message-group__icon").attribute("src", resolveMxc(this.sender.value().content.avatar_url, 32, "crop")) + ) + } else { + this.avatar.child( + ejs("div").class("c-message-group__icon") + ) + } + } + } +} + class EventGroup extends ElemJS { constructor(reactive, list) { super("div") @@ -69,14 +102,13 @@ class EventGroup extends ElemJS { sender: list[0].data.sender, origin_server_ts: list[0].data.origin_server_ts } + this.sender = new Sender(this.reactive.id, this.data.sender) this.child( - ejs("div").class("c-message-group__avatar").child( - ejs("div").class("c-message-group__icon") - ), + this.sender.avatar, this.messages = ejs("div").class("c-message-group__messages").child( ejs("div").class("c-message-group__intro").child( - ejs("div").class("c-message-group__name").text(this.data.sender), - ejs("div").class("c-message-group__date").text(this.data.origin_server_ts) + this.sender.name, + ejs("div").class("c-message-group__date").text(dateFormatter.format(this.data.origin_server_ts)) ), ...this.list ) @@ -102,9 +134,10 @@ class EventGroup extends ElemJS { } class ReactiveTimeline extends ElemJS { - constructor(list) { + constructor(id, list) { super("div") this.class("c-event-groups") + this.id = id this.list = list this.render() } @@ -161,7 +194,7 @@ class Timeline extends Subscribable { this.id = id this.list = [] this.map = new Map() - this.reactiveTimeline = new ReactiveTimeline([]) + this.reactiveTimeline = new ReactiveTimeline(id, []) this.latest = 0 this.pending = new Set() } diff --git a/src/js/functions.js b/src/js/functions.js new file mode 100644 index 0000000..da5da62 --- /dev/null +++ b/src/js/functions.js @@ -0,0 +1,12 @@ +import * as lsm from "./lsm.js" + +function resolveMxc(url, size, method) { + const [server, id] = url.match(/^mxc:\/\/([^/]+)\/(.*)/).slice(1) + if (size && method) { + return `${lsm.get("domain")}/_matrix/media/r0/thumbnail/${server}/${id}?width=${size}&height=${size}&method=${method}` + } else { + return `${lsm.get("domain")}/_matrix/media/r0/download/${server}/${id}` + } +} + +export {resolveMxc} diff --git a/src/js/room-picker.js b/src/js/room-picker.js index 3de2ab1..e93f72d 100644 --- a/src/js/room-picker.js +++ b/src/js/room-picker.js @@ -1,16 +1,10 @@ import {q, ElemJS, ejs} from "./basic.js" import {store} from "./store/store.js" +import {SubscribeMapList} from "./store/SubscribeMapList.js" +import {SubscribeValue} from "./store/SubscribeValue.js" import {Timeline} from "./Timeline.js" import * as lsm from "./lsm.js" - -function resolveMxc(url, size, method) { - const [server, id] = url.match(/^mxc:\/\/([^/]+)\/(.*)/).slice(1) - if (size && method) { - return `${lsm.get("domain")}/_matrix/media/r0/thumbnail/${server}/${id}?width=${size}&height=${size}&method=${method}` - } else { - return `${lsm.get("domain")}/_matrix/media/r0/download/${server}/${id}` - } -} +import {resolveMxc} from "./functions.js" class ActiveGroupMarker extends ElemJS { constructor() { @@ -70,6 +64,7 @@ class Room extends ElemJS { this.data = data this.timeline = new Timeline(this.id) this.group = null + this.members = new SubscribeMapList(SubscribeValue) this.class("c-room") diff --git a/src/js/sync/sync.js b/src/js/sync/sync.js index e5a8389..54c2652 100644 --- a/src/js/sync/sync.js +++ b/src/js/sync/sync.js @@ -1,18 +1,9 @@ import {store} from "../store/store.js" import * as lsm from "../lsm.js" +import {resolveMxc} from "../functions.js" let lastBatch = null -function resolveMxc(url, size, method) { - const [server, id] = url.match(/^mxc:\/\/([^/]+)\/(.*)/).slice(1) - if (size && method) { - return `${lsm.get("domain")}/_matrix/media/r0/thumbnail/${server}/${id}?width=${size}&height=${size}&method=${method}` - } else { - return `${lsm.get("domain")}/_matrix/media/r0/download/${server}/${id}` - } -} - - function sync() { const url = new URL(`${lsm.get("domain")}/_matrix/client/r0/sync`) url.searchParams.append("access_token", lsm.get("access_token")) @@ -60,7 +51,13 @@ function manageSync(root) { if (!store.rooms.has(id)) { store.rooms.askAdd(id, room) } - const timeline = store.rooms.get(id).value().timeline + const storeRoom = store.rooms.get(id).value() + room.state.events.forEach(event => { + if (event.type === "m.room.member") { + storeRoom.members.get(event.state_key).set(event) + } + }) + const timeline = storeRoom.timeline if (room.timeline.events.length) newEvents = true timeline.updateEvents(room.timeline.events) })