From ae93188f0f4f36086622636ba9ae4810cbd1f8c9 Mon Sep 17 00:00:00 2001 From: Owen Jacobson Date: Wed, 14 May 2025 00:46:13 -0400 Subject: Move derivation of the synthesized view of channels (and messages) into `session`. --- ui/lib/session.svelte.js | 52 +++++++++++++++++++++++++++++-- ui/lib/state/remote/channels.svelte.js | 5 ++- ui/lib/state/remote/messages.svelte.js | 7 +---- ui/routes/(app)/+layout.svelte | 26 ++-------------- ui/routes/(app)/ch/[channel]/+page.svelte | 2 +- 5 files changed, 55 insertions(+), 37 deletions(-) (limited to 'ui') diff --git a/ui/lib/session.svelte.js b/ui/lib/session.svelte.js index 21a391d..2dae3c4 100644 --- a/ui/lib/session.svelte.js +++ b/ui/lib/session.svelte.js @@ -6,16 +6,62 @@ import * as api from './apiServer.js'; import * as r from './state/remote/state.svelte.js'; import * as l from './state/local/channels.svelte.js'; import { Watchdog } from './watchdog.js'; +import { DateTime } from 'luxon'; +import { render } from '$lib/markdown.js'; + +class Channel { + static fromRemote({ at, id, name }, messages, meta) { + const sentAt = messages + .filter((message) => message.channel === id) + .map((message) => message.at); + const lastEventAt = Math.max(at, ...sentAt); + const lastReadAt = meta.get(id)?.lastReadAt; + + const hasUnreads = lastReadAt === undefined || lastEventAt > lastReadAt; + return new Channel({ at, id, name, hasUnreads }); + } + + constructor({ at, id, name, hasUnreads }) { + this.at = at; + this.id = id; + this.name = name; + this.hasUnreads = hasUnreads; + } +} + +class Message { + static fromRemote({ id, at, channel, sender, body, renderedBody }, users) { + return new Message({ + id, + at, + channel, + sender: users.get(sender), + body, + renderedBody + }); + } + + constructor({ id, at, channel, sender, body, renderedBody }) { + this.id = id; + this.at = at; + this.channel = channel; + this.sender = sender; + this.body = body; + this.renderedBody = renderedBody; + } +} class Session { remote = $state(); local = $state(); currentUser = $derived(this.remote.currentUser); users = $derived(this.remote.users.all); - channels = $derived(this.remote.channels.all); messages = $derived( - this.remote.messages.all.map((message) => - message.resolve({ sender: (id) => this.users.get(id) }) + this.remote.messages.all.map((message) => Message.fromRemote(message, this.users)) + ); + channels = $derived( + this.remote.channels.all.map((channel) => + Channel.fromRemote(channel, this.messages, this.local.all) ) ); diff --git a/ui/lib/state/remote/channels.svelte.js b/ui/lib/state/remote/channels.svelte.js index b6da31b..8b190dd 100644 --- a/ui/lib/state/remote/channels.svelte.js +++ b/ui/lib/state/remote/channels.svelte.js @@ -1,5 +1,4 @@ import { DateTime } from 'luxon'; -import { SvelteMap } from 'svelte/reactivity'; class Channel { static boot({ at, id, name }) { @@ -18,10 +17,10 @@ class Channel { } export class Channels { - all = $state(); + all = $state([]); static boot(channels) { - const all = new SvelteMap(channels.map((channel) => [channel.id, Channel.boot(channel)])); + const all = channels.map((channel) => Channel.boot(channel)); return new Channels({ all }); } diff --git a/ui/lib/state/remote/messages.svelte.js b/ui/lib/state/remote/messages.svelte.js index c6d31f0..0a081bb 100644 --- a/ui/lib/state/remote/messages.svelte.js +++ b/ui/lib/state/remote/messages.svelte.js @@ -1,7 +1,7 @@ import { DateTime } from 'luxon'; import { render } from '$lib/markdown.js'; -export class Message { +class Message { static boot({ id, at, channel, sender, body }) { return new Message({ id, @@ -21,11 +21,6 @@ export class Message { this.body = body; this.renderedBody = renderedBody; } - - resolve(get) { - const { sender, ...rest } = this; - return new Message({ sender: get.sender(sender), ...rest }); - } } export class Messages { diff --git a/ui/routes/(app)/+layout.svelte b/ui/routes/(app)/+layout.svelte index 90fa82e..c7e1f22 100644 --- a/ui/routes/(app)/+layout.svelte +++ b/ui/routes/(app)/+layout.svelte @@ -22,29 +22,7 @@ let pageContext = getContext('page'); let channel = $derived(page.params.channel); - let rawChannels = $derived(session.channels); - let rawChannelsMeta = $derived(session.local.all); - let rawMessages = $derived(session.messages); - - function enrichChannels(channels, channelsMeta, messages) { - const enrichedChannels = []; - for (const ch of channels.values()) { - const createdAt = ch.at; - const channelMessages = messages.filter((message) => message.channel === ch.id); - const sentAt = channelMessages.map((message) => message.at); - const lastEventAt = Math.max(createdAt, ...sentAt); - - const lastReadAt = channelsMeta.get(ch.id)?.lastReadAt; - const hasUnreads = lastReadAt === undefined || lastEventAt > lastReadAt; - enrichedChannels.push({ - ...ch, - hasUnreads - }); - } - return enrichedChannels; - } - - const enrichedChannels = $derived(enrichChannels(rawChannels, rawChannelsMeta, rawMessages)); + let channels = $derived(session.channels); function setUpGestures() { if (!browser) { @@ -136,7 +114,7 @@