From ac6320c12c86787a5d044c06674ed4ab09d385da Mon Sep 17 00:00:00 2001 From: Cadence Ember Date: Thu, 15 Oct 2020 22:06:41 +1300 Subject: [PATCH] Sync with matrix and populate rooms list --- build.js | 25 +++++--- build/index.html | 7 ++- build/static/lsm.js | 11 ++++ build/static/main.css | 6 +- build/static/room-picker.js | 80 ++++++++++++++++++++++---- build/static/store/SubscribeMapList.js | 6 +- build/static/store/SubscribeSet.js | 50 ++++++++++++++++ build/static/store/store.js | 2 + build/static/sync/sync.js | 62 ++++++++++++++++++++ spec.js | 43 ++++++++++++-- src/home.pug | 3 +- src/js/lsm.js | 11 ++++ src/js/room-picker.js | 80 ++++++++++++++++++++++---- src/js/store/SubscribeMapList.js | 6 +- src/js/store/SubscribeSet.js | 50 ++++++++++++++++ src/js/store/store.js | 2 + src/js/sync/sync.js | 62 ++++++++++++++++++++ src/sass/components/rooms.sass | 6 +- 18 files changed, 465 insertions(+), 47 deletions(-) create mode 100644 build/static/lsm.js create mode 100644 build/static/store/SubscribeSet.js create mode 100644 build/static/sync/sync.js create mode 100644 src/js/lsm.js create mode 100644 src/js/store/SubscribeSet.js create mode 100644 src/js/sync/sync.js diff --git a/build.js b/build.js index 22e9f5b..869f1c0 100644 --- a/build.js +++ b/build.js @@ -80,29 +80,36 @@ function runHint(filename, source) { hint(source, { esversion: 9, undef: true, - unused: true, + // unused: true, loopfunc: true, - globals: ["require", "console", "URLSearchParams", "L"], - strict: "global", - browser: true + globals: ["console", "URLSearchParams"], + browser: true, + asi: true, }) const result = hint.data() - if (result.errors && result.errors.length) { + let problems = 0 + if (result.errors) { for (const error of result.errors) { if (error.evidence) { const text = error.evidence.replace(/\t/g, " ") + if ([ + "W014" + ].includes(error.code)) continue let type = error.code.startsWith("W") ? chalk.yellow("warning") : chalk.red("error") console.log(`hint: ${type} in ${filename}`) console.log(` ${error.line}:${error.character}: ${error.reason} (${error.code})`) console.log(chalk.gray( " " - + text.slice(0, error.character) - + chalk.inverse(text.substr(error.character, 1)) - + text.slice(error.character+1) + + text.slice(0, error.character) + + chalk.inverse(text.substr(error.character, 1)) + + text.slice(error.character+1) )) + problems++ } } - console.log(`hint: ${chalk.cyan(result.errors.length+" problems")} in ${filename}`) + } + if (problems) { + console.log(`hint: ${chalk.cyan(problems+" problems")} in ${filename}`) } else { console.log(`hint: ${chalk.green("ok")} for ${filename}`) } diff --git a/build/index.html b/build/index.html index fe38608..07eb256 100644 --- a/build/index.html +++ b/build/index.html @@ -2,10 +2,11 @@ - + - + + Carbon @@ -32,7 +33,7 @@
Cadence
at 4:20 pm
-
the second button is for rooms (gonna call them "channels to make discord users happy) that are not in a group (which will be most rooms - few people set up groups because they're so annoying, and many communities of people only need a single chatroom)
+
the second button is for rooms (gonna call them "channels" to make discord users happy) that are not in a group (which will be most rooms - few people set up groups because they're so annoying, and many communities of people only need a single chatroom)
for now, please assume that current groups ("groups v1") will not be recognised by this client at all
so yeah, press the second button, you see all the ungrouped channels
diff --git a/build/static/lsm.js b/build/static/lsm.js new file mode 100644 index 0000000..7338343 --- /dev/null +++ b/build/static/lsm.js @@ -0,0 +1,11 @@ +function get(name) { + return localStorage.getItem(name) +} + +function set(name, value) { + return localStorage.setItem(name, value) +} + +window.lsm = {get, set} + +export {get, set} diff --git a/build/static/main.css b/build/static/main.css index fa3314b..7064538 100644 --- a/build/static/main.css +++ b/build/static/main.css @@ -29,7 +29,7 @@ body { background-color: #2f3135; padding: 8px; width: 240px; - font-size: 20px; + font-size: 18px; font-weight: 500; overflow-y: auto; scrollbar-width: thin; @@ -54,11 +54,13 @@ body { .c-room__icon { width: 32px; height: 32px; - background-color: #bbb; margin-right: 8px; border-radius: 50%; flex-shrink: 0; } +.c-room__icon--no-icon { + background-color: #bbb; +} .c-room__name { white-space: nowrap; overflow: hidden; diff --git a/build/static/room-picker.js b/build/static/room-picker.js index 9099473..7d19236 100644 --- a/build/static/room-picker.js +++ b/build/static/room-picker.js @@ -1,5 +1,15 @@ import {q, ElemJS, ejs} from "./basic.js" import {store} from "./store/store.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}` + } +} class ActiveGroupMarker extends ElemJS { constructor() { @@ -51,19 +61,47 @@ class Group extends ElemJS { } class Room extends ElemJS { - constructor(key, data) { + constructor(id, data) { super("div") + this.id = id this.data = data this.class("c-room") - this.child( - ejs("div").class("c-room__icon"), - ejs("div").class("c-room__name").text(this.data.name) - ) this.on("click", this.onClick.bind(this)) store.activeRoom.subscribe("changeSelf", this.render.bind(this)) + + this.render() + } + + getName() { + let name = this.data.state.events.find(e => e.type === "m.room.name") + if (name) { + name = name.content.name + } else { + const users = this.data.summary["m.heroes"] + const usernames = users.map(u => (u.match(/^@([^:]+):/) || [])[1] || u) + name = usernames.join(", ") + } + return name + } + + getIcon() { + const avatar = this.data.state.events.find(e => e.type === "m.room.avatar") + if (avatar) { + return resolveMxc(avatar.content.url || avatar.content.avatar_url, 32, "crop") + } else { + return null + } + } + + isDirect() { + return store.directs.has(this.id) + } + + getGroup() { + return this.isDirect() ? store.groups.get("directs").value() : store.groups.get("channels").value() } onClick() { @@ -71,6 +109,16 @@ class Room extends ElemJS { } render() { + this.clearChildren() + // data + const icon = this.getIcon() + if (icon) { + this.child(ejs("img").class("c-room__icon").attribute("src", icon)) + } else { + this.child(ejs("div").class("c-room__icon", "c-room__icon--no-icon")) + } + this.child(ejs("div").class("c-room__name").text(this.getName())) + // active const active = store.activeRoom.value() === this this.element.classList[active ? "add" : "remove"]("c-room--active") } @@ -84,8 +132,10 @@ class Rooms extends ElemJS { this.rooms = [] store.rooms.subscribe("askAdd", this.askAdd.bind(this)) - store.rooms.subscribe("changeItem", this.render.bind(this)) + store.rooms.subscribe("addItem", this.addItem.bind(this)) + // store.rooms.subscribe("changeItem", this.render.bind(this)) store.activeGroup.subscribe("changeSelf", this.render.bind(this)) + store.directs.subscribe("changeItem", this.render.bind(this)) this.render() } @@ -95,18 +145,25 @@ class Rooms extends ElemJS { store.rooms.addEnd(key, room) } + addItem(event, key) { + const room = store.rooms.get(key).value() + if (room.getGroup() === store.activeGroup.value()) { + this.child(room) + } + } + render() { this.clearChildren() let first = null // set room list store.rooms.forEach((id, room) => { - if (room.value().data.group === store.activeGroup.value()) { + if (room.value().getGroup() === store.activeGroup.value()) { if (!first) first = room.value() this.child(room.value()) } }) // if needed, change the active room to be an item in the room list - if (!store.activeRoom.exists() || store.activeRoom.value().data.group !== store.activeGroup.value()) { + if (!store.activeRoom.exists() || store.activeRoom.value().getGroup() !== store.activeGroup.value()) { if (first) { store.activeRoom.set(first) } else { @@ -136,6 +193,7 @@ class Groups extends ElemJS { } const groups = new Groups() + ;[ { id: "directs", @@ -146,7 +204,7 @@ const groups = new Groups() id: "channels", name: "Channels", icon: "/static/channels.svg" - }, + }/*, { id: "123", name: "Fediverse Drama Museum" @@ -158,9 +216,10 @@ const groups = new Groups() { id: "789", name: "Invidious" - } + }*/ ].forEach(data => store.groups.askAdd(data.id, data)) +/* ;[ {id: "001", name: "riley", group: store.groups.get("directs").value()}, {id: "002", name: "BadAtNames", group: store.groups.get("directs").value()}, @@ -188,5 +247,6 @@ const groups = new Groups() {id: "024", name: "osu", group: store.groups.get("456").value()}, {id: "025", name: "covid", group: store.groups.get("456").value()} ].forEach(data => store.rooms.askAdd(data.id, data)) +*/ store.activeGroup.set(store.groups.get("directs").value()) diff --git a/build/static/store/SubscribeMapList.js b/build/static/store/SubscribeMapList.js index fb93574..8338355 100644 --- a/build/static/store/SubscribeMapList.js +++ b/build/static/store/SubscribeMapList.js @@ -7,14 +7,14 @@ class SubscribeMapList extends Subscribable { this.inner = inner Object.assign(this.events, { addItem: [], - removeItem: [], + deleteItem: [], editItem: [], changeItem: [], askAdd: [] }) Object.assign(this.eventDeps, { addItem: ["changeItem"], - removeItem: ["changeItem"], + deleteItem: ["changeItem"], editItem: ["changeItem"], changeItem: [], askAdd: [] @@ -59,7 +59,7 @@ class SubscribeMapList extends Subscribable { const exists = this.map.get(key).exists() s = this.map.get(key).set(value) if (exists) { - this.broadcast("changeItem", key) + this.broadcast("editItem", key) } else { this.broadcast("addItem", key) } diff --git a/build/static/store/SubscribeSet.js b/build/static/store/SubscribeSet.js new file mode 100644 index 0000000..2cbdaa3 --- /dev/null +++ b/build/static/store/SubscribeSet.js @@ -0,0 +1,50 @@ +import {Subscribable} from "./Subscribable.js" + +class SubscribeSet extends Subscribable { + constructor() { + super() + Object.assign(this.events, { + addItem: [], + deleteItem: [], + changeItem: [], + askAdd: [] + }) + Object.assign(this.eventDeps, { + addItem: ["changeItem"], + deleteItem: ["changeItem"], + changeItem: [], + askAdd: [] + }) + this.set = new Set() + } + + has(key) { + return this.set.has(key) + } + + forEach(f) { + for (const key of this.set.keys()) { + f(key) + } + } + + askAdd(key) { + this.broadcast("askAdd", key) + } + + add(key) { + if (!this.set.has(key)) { + this.set.add(key) + this.broadcast("addItem", key) + } + } + + delete(key) { + if (this.set.has(key)) { + this.set.delete(key) + this.broadcast("deleteItem", key) + } + } +} + +export {SubscribeSet} diff --git a/build/static/store/store.js b/build/static/store/store.js index a4479ca..ede0657 100644 --- a/build/static/store/store.js +++ b/build/static/store/store.js @@ -1,9 +1,11 @@ import {SubscribeMapList} from "./SubscribeMapList.js" +import {SubscribeSet} from "./SubscribeSet.js" import {SubscribeValue} from "./SubscribeValue.js" const store = { groups: new SubscribeMapList(SubscribeValue), rooms: new SubscribeMapList(SubscribeValue), + directs: new SubscribeSet(), activeGroup: new SubscribeValue(), activeRoom: new SubscribeValue() } diff --git a/build/static/sync/sync.js b/build/static/sync/sync.js new file mode 100644 index 0000000..cea0f31 --- /dev/null +++ b/build/static/sync/sync.js @@ -0,0 +1,62 @@ +import {store} from "../store/store.js" +import * as lsm from "../lsm.js" + +let lastBatch = null + +function sync() { + const url = new URL(`${lsm.get("domain")}/_matrix/client/r0/sync`) + url.searchParams.append("access_token", lsm.get("access_token")) + const filter = { + room: { + // pulling more from the timeline massively increases download size + timeline: { + limit: 5 + }, + // members are not currently needed + state: { + lazy_load_members: true + } + }, + presence: { + // presence is not implemented, ignore it + types: [] + } + } + url.searchParams.append("filter", JSON.stringify(filter)) + url.searchParams.append("timeout", 20000) + if (lastBatch) { + url.searchParams.append("since", lastBatch) + } + return fetch(url.toString()).then(res => res.json()).then(root => { + lastBatch = root.next_batch + return root + }) +} + +function manageSync(root) { + try { + // set up directs + const directs = root.account_data.events.find(e => e.type === "m.direct") + if (directs) { + Object.values(directs.content).forEach(ids => { + ids.forEach(id => store.directs.add(id)) + }) + } + + // set up rooms + Object.entries(root.rooms.join).forEach(([id, room]) => { + if (!store.rooms.has(id)) { + store.rooms.askAdd(id, room) + } + }) + } catch (e) { + console.error(root) + throw e + } +} + +function syncLoop() { + return sync().then(manageSync).then(syncLoop) +} + +syncLoop() diff --git a/spec.js b/spec.js index 0376a0f..3f529d9 100644 --- a/spec.js +++ b/spec.js @@ -10,25 +10,60 @@ module.exports = [ target: "/static/whitney-400.woff" }, { - type: "file", + type: "js", source: "/js/basic.js", target: "/static/basic.js" }, { - type: "file", + type: "js", source: "/js/groups.js", target: "/static/groups.js" }, { - type: "file", + type: "js", source: "/js/chat-input.js", target: "/static/chat-input.js" }, { - type: "file", + type: "js", source: "/js/room-picker.js", target: "/static/room-picker.js" }, + { + type: "js", + source: "/js/store/store.js", + target: "/static/store/store.js" + }, + { + type: "js", + source: "/js/store/Subscribable.js", + target: "/static/store/Subscribable.js" + }, + { + type: "js", + source: "/js/store/SubscribeValue.js", + target: "/static/store/SubscribeValue.js" + }, + { + type: "js", + source: "/js/store/SubscribeMapList.js", + target: "/static/store/SubscribeMapList.js" + }, + { + type: "js", + source: "/js/store/SubscribeSet.js", + target: "/static/store/SubscribeSet.js" + }, + { + type: "js", + source: "/js/sync/sync.js", + target: "/static/sync/sync.js" + }, + { + type: "js", + source: "/js/lsm.js", + target: "/static/lsm.js" + }, { type: "file", source: "/assets/fonts/whitney-500.woff", diff --git a/src/home.pug b/src/home.pug index cfb0c54..fcadfda 100644 --- a/src/home.pug +++ b/src/home.pug @@ -37,6 +37,7 @@ html script(type="module" src=getStatic("/js/groups.js")) script(type="module" src=getStatic("/js/chat-input.js")) script(type="module" src=getStatic("/js/room-picker.js")) + script(type="module" src=getStatic("/js/sync/sync.js")) title Carbon body main.main @@ -50,7 +51,7 @@ html .c-chat__inner +message-notice("You've reached the start of the conversation.") +message("Cadence", [ - `the second button is for rooms (gonna call them "channels to make discord users happy) that are not in a group (which will be most rooms - few people set up groups because they're so annoying, and many communities of people only need a single chatroom)`, + `the second button is for rooms (gonna call them "channels" to make discord users happy) that are not in a group (which will be most rooms - few people set up groups because they're so annoying, and many communities of people only need a single chatroom)`, `for now, please assume that current groups ("groups v1") will not be recognised by this client at all`, `so yeah, press the second button, you see all the ungrouped channels` ]) diff --git a/src/js/lsm.js b/src/js/lsm.js new file mode 100644 index 0000000..7338343 --- /dev/null +++ b/src/js/lsm.js @@ -0,0 +1,11 @@ +function get(name) { + return localStorage.getItem(name) +} + +function set(name, value) { + return localStorage.setItem(name, value) +} + +window.lsm = {get, set} + +export {get, set} diff --git a/src/js/room-picker.js b/src/js/room-picker.js index 9099473..7d19236 100644 --- a/src/js/room-picker.js +++ b/src/js/room-picker.js @@ -1,5 +1,15 @@ import {q, ElemJS, ejs} from "./basic.js" import {store} from "./store/store.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}` + } +} class ActiveGroupMarker extends ElemJS { constructor() { @@ -51,19 +61,47 @@ class Group extends ElemJS { } class Room extends ElemJS { - constructor(key, data) { + constructor(id, data) { super("div") + this.id = id this.data = data this.class("c-room") - this.child( - ejs("div").class("c-room__icon"), - ejs("div").class("c-room__name").text(this.data.name) - ) this.on("click", this.onClick.bind(this)) store.activeRoom.subscribe("changeSelf", this.render.bind(this)) + + this.render() + } + + getName() { + let name = this.data.state.events.find(e => e.type === "m.room.name") + if (name) { + name = name.content.name + } else { + const users = this.data.summary["m.heroes"] + const usernames = users.map(u => (u.match(/^@([^:]+):/) || [])[1] || u) + name = usernames.join(", ") + } + return name + } + + getIcon() { + const avatar = this.data.state.events.find(e => e.type === "m.room.avatar") + if (avatar) { + return resolveMxc(avatar.content.url || avatar.content.avatar_url, 32, "crop") + } else { + return null + } + } + + isDirect() { + return store.directs.has(this.id) + } + + getGroup() { + return this.isDirect() ? store.groups.get("directs").value() : store.groups.get("channels").value() } onClick() { @@ -71,6 +109,16 @@ class Room extends ElemJS { } render() { + this.clearChildren() + // data + const icon = this.getIcon() + if (icon) { + this.child(ejs("img").class("c-room__icon").attribute("src", icon)) + } else { + this.child(ejs("div").class("c-room__icon", "c-room__icon--no-icon")) + } + this.child(ejs("div").class("c-room__name").text(this.getName())) + // active const active = store.activeRoom.value() === this this.element.classList[active ? "add" : "remove"]("c-room--active") } @@ -84,8 +132,10 @@ class Rooms extends ElemJS { this.rooms = [] store.rooms.subscribe("askAdd", this.askAdd.bind(this)) - store.rooms.subscribe("changeItem", this.render.bind(this)) + store.rooms.subscribe("addItem", this.addItem.bind(this)) + // store.rooms.subscribe("changeItem", this.render.bind(this)) store.activeGroup.subscribe("changeSelf", this.render.bind(this)) + store.directs.subscribe("changeItem", this.render.bind(this)) this.render() } @@ -95,18 +145,25 @@ class Rooms extends ElemJS { store.rooms.addEnd(key, room) } + addItem(event, key) { + const room = store.rooms.get(key).value() + if (room.getGroup() === store.activeGroup.value()) { + this.child(room) + } + } + render() { this.clearChildren() let first = null // set room list store.rooms.forEach((id, room) => { - if (room.value().data.group === store.activeGroup.value()) { + if (room.value().getGroup() === store.activeGroup.value()) { if (!first) first = room.value() this.child(room.value()) } }) // if needed, change the active room to be an item in the room list - if (!store.activeRoom.exists() || store.activeRoom.value().data.group !== store.activeGroup.value()) { + if (!store.activeRoom.exists() || store.activeRoom.value().getGroup() !== store.activeGroup.value()) { if (first) { store.activeRoom.set(first) } else { @@ -136,6 +193,7 @@ class Groups extends ElemJS { } const groups = new Groups() + ;[ { id: "directs", @@ -146,7 +204,7 @@ const groups = new Groups() id: "channels", name: "Channels", icon: "/static/channels.svg" - }, + }/*, { id: "123", name: "Fediverse Drama Museum" @@ -158,9 +216,10 @@ const groups = new Groups() { id: "789", name: "Invidious" - } + }*/ ].forEach(data => store.groups.askAdd(data.id, data)) +/* ;[ {id: "001", name: "riley", group: store.groups.get("directs").value()}, {id: "002", name: "BadAtNames", group: store.groups.get("directs").value()}, @@ -188,5 +247,6 @@ const groups = new Groups() {id: "024", name: "osu", group: store.groups.get("456").value()}, {id: "025", name: "covid", group: store.groups.get("456").value()} ].forEach(data => store.rooms.askAdd(data.id, data)) +*/ store.activeGroup.set(store.groups.get("directs").value()) diff --git a/src/js/store/SubscribeMapList.js b/src/js/store/SubscribeMapList.js index fb93574..8338355 100644 --- a/src/js/store/SubscribeMapList.js +++ b/src/js/store/SubscribeMapList.js @@ -7,14 +7,14 @@ class SubscribeMapList extends Subscribable { this.inner = inner Object.assign(this.events, { addItem: [], - removeItem: [], + deleteItem: [], editItem: [], changeItem: [], askAdd: [] }) Object.assign(this.eventDeps, { addItem: ["changeItem"], - removeItem: ["changeItem"], + deleteItem: ["changeItem"], editItem: ["changeItem"], changeItem: [], askAdd: [] @@ -59,7 +59,7 @@ class SubscribeMapList extends Subscribable { const exists = this.map.get(key).exists() s = this.map.get(key).set(value) if (exists) { - this.broadcast("changeItem", key) + this.broadcast("editItem", key) } else { this.broadcast("addItem", key) } diff --git a/src/js/store/SubscribeSet.js b/src/js/store/SubscribeSet.js new file mode 100644 index 0000000..2cbdaa3 --- /dev/null +++ b/src/js/store/SubscribeSet.js @@ -0,0 +1,50 @@ +import {Subscribable} from "./Subscribable.js" + +class SubscribeSet extends Subscribable { + constructor() { + super() + Object.assign(this.events, { + addItem: [], + deleteItem: [], + changeItem: [], + askAdd: [] + }) + Object.assign(this.eventDeps, { + addItem: ["changeItem"], + deleteItem: ["changeItem"], + changeItem: [], + askAdd: [] + }) + this.set = new Set() + } + + has(key) { + return this.set.has(key) + } + + forEach(f) { + for (const key of this.set.keys()) { + f(key) + } + } + + askAdd(key) { + this.broadcast("askAdd", key) + } + + add(key) { + if (!this.set.has(key)) { + this.set.add(key) + this.broadcast("addItem", key) + } + } + + delete(key) { + if (this.set.has(key)) { + this.set.delete(key) + this.broadcast("deleteItem", key) + } + } +} + +export {SubscribeSet} diff --git a/src/js/store/store.js b/src/js/store/store.js index a4479ca..ede0657 100644 --- a/src/js/store/store.js +++ b/src/js/store/store.js @@ -1,9 +1,11 @@ import {SubscribeMapList} from "./SubscribeMapList.js" +import {SubscribeSet} from "./SubscribeSet.js" import {SubscribeValue} from "./SubscribeValue.js" const store = { groups: new SubscribeMapList(SubscribeValue), rooms: new SubscribeMapList(SubscribeValue), + directs: new SubscribeSet(), activeGroup: new SubscribeValue(), activeRoom: new SubscribeValue() } diff --git a/src/js/sync/sync.js b/src/js/sync/sync.js new file mode 100644 index 0000000..cea0f31 --- /dev/null +++ b/src/js/sync/sync.js @@ -0,0 +1,62 @@ +import {store} from "../store/store.js" +import * as lsm from "../lsm.js" + +let lastBatch = null + +function sync() { + const url = new URL(`${lsm.get("domain")}/_matrix/client/r0/sync`) + url.searchParams.append("access_token", lsm.get("access_token")) + const filter = { + room: { + // pulling more from the timeline massively increases download size + timeline: { + limit: 5 + }, + // members are not currently needed + state: { + lazy_load_members: true + } + }, + presence: { + // presence is not implemented, ignore it + types: [] + } + } + url.searchParams.append("filter", JSON.stringify(filter)) + url.searchParams.append("timeout", 20000) + if (lastBatch) { + url.searchParams.append("since", lastBatch) + } + return fetch(url.toString()).then(res => res.json()).then(root => { + lastBatch = root.next_batch + return root + }) +} + +function manageSync(root) { + try { + // set up directs + const directs = root.account_data.events.find(e => e.type === "m.direct") + if (directs) { + Object.values(directs.content).forEach(ids => { + ids.forEach(id => store.directs.add(id)) + }) + } + + // set up rooms + Object.entries(root.rooms.join).forEach(([id, room]) => { + if (!store.rooms.has(id)) { + store.rooms.askAdd(id, room) + } + }) + } catch (e) { + console.error(root) + throw e + } +} + +function syncLoop() { + return sync().then(manageSync).then(syncLoop) +} + +syncLoop() diff --git a/src/sass/components/rooms.sass b/src/sass/components/rooms.sass index dc0f0e2..462e13c 100644 --- a/src/sass/components/rooms.sass +++ b/src/sass/components/rooms.sass @@ -8,7 +8,7 @@ $icon-padding: 8px background-color: c.$darker padding: $icon-padding width: $list-width - font-size: 20px + font-size: 18px font-weight: 500 overflow-y: auto scrollbar-width: thin @@ -32,11 +32,13 @@ $icon-padding: 8px &__icon width: $icon-size height: $icon-size - background-color: #bbb margin-right: $icon-padding border-radius: 50% flex-shrink: 0 + &--no-icon + background-color: #bbb + &__name white-space: nowrap overflow: hidden