Simplify and optimize notifications

This commit is contained in:
Jon Staab
2024-12-16 11:24:10 -08:00
parent 85e5413951
commit 3d3ffaf406
12 changed files with 120 additions and 151 deletions
+3 -4
View File
@@ -1,7 +1,7 @@
<script lang="ts"> <script lang="ts">
import {onMount} from "svelte" import {onMount} from "svelte"
import {page} from "$app/stores" import {page} from "$app/stores"
import {remove, assoc} from "@welshman/lib" import {remove} from "@welshman/lib"
import type {TrustedEvent} from "@welshman/util" import type {TrustedEvent} from "@welshman/util"
import {pubkey, loadInboxRelaySelections} from "@welshman/app" import {pubkey, loadInboxRelaySelections} from "@welshman/app"
import {fade} from "@lib/transition" import {fade} from "@lib/transition"
@@ -10,7 +10,7 @@
import ProfileCircle from "@app/components/ProfileCircle.svelte" import ProfileCircle from "@app/components/ProfileCircle.svelte"
import ProfileCircles from "@app/components/ProfileCircles.svelte" import ProfileCircles from "@app/components/ProfileCircles.svelte"
import {makeChatPath} from "@app/routes" import {makeChatPath} from "@app/routes"
import {CHAT_FILTERS, deriveNotification} from "@app/notifications" import {notifications} from "@app/notifications"
export let id: string export let id: string
export let pubkeys: string[] export let pubkeys: string[]
@@ -19,7 +19,6 @@
const others = remove($pubkey!, pubkeys) const others = remove($pubkey!, pubkeys)
const active = $page.params.chat === id const active = $page.params.chat === id
const path = makeChatPath(pubkeys) const path = makeChatPath(pubkeys)
const notification = deriveNotification(path, CHAT_FILTERS.map(assoc("authors", pubkeys)))
onMount(() => { onMount(() => {
for (const pk of others) { for (const pk of others) {
@@ -47,7 +46,7 @@
</p> </p>
{/if} {/if}
</div> </div>
{#if !active && $notification} {#if !active && $notifications.has(path)}
<div class="h-2 w-2 rounded-full bg-primary" transition:fade /> <div class="h-2 w-2 rounded-full bg-primary" transition:fade />
{/if} {/if}
</div> </div>
+2 -3
View File
@@ -22,7 +22,7 @@
deriveUserRooms, deriveUserRooms,
deriveOtherRooms, deriveOtherRooms,
} from "@app/state" } from "@app/state"
import {deriveNotification, THREAD_FILTERS} from "@app/notifications" import {notifications} from "@app/notifications"
import {pullConservatively} from "@app/requests" import {pullConservatively} from "@app/requests"
import {pushModal} from "@app/modal" import {pushModal} from "@app/modal"
import {makeSpacePath} from "@app/routes" import {makeSpacePath} from "@app/routes"
@@ -30,7 +30,6 @@
export let url export let url
const threadsPath = makeSpacePath(url, "threads") const threadsPath = makeSpacePath(url, "threads")
const threadsNotification = deriveNotification(threadsPath, THREAD_FILTERS, url)
const userRooms = deriveUserRooms(url) const userRooms = deriveUserRooms(url)
const otherRooms = deriveOtherRooms(url) const otherRooms = deriveOtherRooms(url)
@@ -114,7 +113,7 @@
<SecondaryNavItem href={makeSpacePath(url)}> <SecondaryNavItem href={makeSpacePath(url)}>
<Icon icon="home-smile" /> Home <Icon icon="home-smile" /> Home
</SecondaryNavItem> </SecondaryNavItem>
<SecondaryNavItem href={threadsPath} notification={$threadsNotification}> <SecondaryNavItem href={threadsPath} notification={$notifications.has(threadsPath)}>
<Icon icon="notes-minimalistic" /> Threads <Icon icon="notes-minimalistic" /> Threads
</SecondaryNavItem> </SecondaryNavItem>
<div class="h-2" /> <div class="h-2" />
+5 -32
View File
@@ -1,48 +1,21 @@
<script lang="ts"> <script lang="ts">
import {page} from "$app/stores"
import {derived} from "svelte/store"
import {max} from "@welshman/lib"
import {matchFilter, MESSAGE} from "@welshman/util"
import {pubkey} from "@welshman/app"
import Icon from "@lib/components/Icon.svelte" import Icon from "@lib/components/Icon.svelte"
import Button from "@lib/components/Button.svelte" import Button from "@lib/components/Button.svelte"
import MenuSpace from "@app/components/MenuSpace.svelte" import MenuSpace from "@app/components/MenuSpace.svelte"
import {checked, getNotification, deriveNotification, THREAD_FILTERS} from "@app/notifications" import {notifications} from "@app/notifications"
import {userMembership, getMembershipRoomsByUrl, deriveEventsForUrl, GENERAL} from "@app/state" import {makeSpacePath} from "@app/routes"
import {makeRoomPath, makeSpacePath} from "@app/routes"
import {pushDrawer} from "@app/modal" import {pushDrawer} from "@app/modal"
export let url export let url
const path = makeSpacePath(url)
const openMenu = () => pushDrawer(MenuSpace, {url}) const openMenu = () => pushDrawer(MenuSpace, {url})
const events = deriveEventsForUrl(url, [{kinds: [MESSAGE]}])
const threadsPath = makeSpacePath(url, "threads")
const threadsNotification = deriveNotification(threadsPath, THREAD_FILTERS, url)
const notification = derived(
[page, events, checked, userMembership],
([$page, $events, $checked, $userMembership]) =>
getMembershipRoomsByUrl(url, $userMembership)
.concat(GENERAL)
.some(room => {
const path = makeRoomPath(url, room)
if ($page.url.pathname === path) return false
const lastChecked = max([$checked["*"], $checked[path]])
const roomEvents = $events.filter(e => matchFilter({"#h": [room]}, e))
return getNotification($pubkey, lastChecked, roomEvents)
}),
)
</script> </script>
<Button on:click={openMenu} class="btn btn-neutral btn-sm relative md:hidden"> <Button on:click={openMenu} class="btn btn-neutral btn-sm relative md:hidden">
<Icon icon="menu-dots" /> <Icon icon="menu-dots" />
{#if $threadsNotification || $notification} {#if $notifications.has(path)}
<div class="absolute right-0 top-0 -mr-1 -mt-1 h-2 w-2 rounded-full bg-primary" /> <div class="absolute right-0 top-0 -mr-1 -mt-1 h-2 w-2 rounded-full bg-primary" />
{/if} {/if}
</Button> </Button>
+2 -6
View File
@@ -1,11 +1,10 @@
<script lang="ts"> <script lang="ts">
import {readable} from "svelte/store"
import Icon from "@lib/components/Icon.svelte" import Icon from "@lib/components/Icon.svelte"
import SecondaryNavItem from "@lib/components/SecondaryNavItem.svelte" import SecondaryNavItem from "@lib/components/SecondaryNavItem.svelte"
import ChannelName from "@app/components/ChannelName.svelte" import ChannelName from "@app/components/ChannelName.svelte"
import {makeSpacePath} from "@app/routes" import {makeSpacePath} from "@app/routes"
import {deriveChannel, channelIsLocked} from "@app/state" import {deriveChannel, channelIsLocked} from "@app/state"
import {deriveNotification, getRoomFilters} from "@app/notifications" import {notifications} from "@app/notifications"
export let url export let url
export let room export let room
@@ -13,12 +12,9 @@
const path = makeSpacePath(url, room) const path = makeSpacePath(url, room)
const channel = deriveChannel(url, room) const channel = deriveChannel(url, room)
const notification = notify
? deriveNotification(path, getRoomFilters(room), url)
: readable(false)
</script> </script>
<SecondaryNavItem href={path} notification={$notification}> <SecondaryNavItem href={path} notification={notify ? $notifications.has(path) : false}>
{#if channelIsLocked($channel)} {#if channelIsLocked($channel)}
<Icon icon="lock" size={4} /> <Icon icon="lock" size={4} />
{:else} {:else}
+2 -2
View File
@@ -5,7 +5,7 @@
import RelayName from "@app/components/RelayName.svelte" import RelayName from "@app/components/RelayName.svelte"
import RelayDescription from "@app/components/RelayDescription.svelte" import RelayDescription from "@app/components/RelayDescription.svelte"
import {makeSpacePath} from "@app/routes" import {makeSpacePath} from "@app/routes"
import {inactiveSpacesNotifications} from "@app/notifications" import {inactiveNotifications} from "@app/notifications"
export let url export let url
@@ -17,7 +17,7 @@
<div slot="icon"><SpaceAvatar {url} /></div> <div slot="icon"><SpaceAvatar {url} /></div>
<div slot="title" class="flex gap-1"> <div slot="title" class="flex gap-1">
<RelayName {url} /> <RelayName {url} />
{#if $inactiveSpacesNotifications.includes(path)} {#if $inactiveNotifications.has(path)}
<div class="relative top-1 h-2 w-2 rounded-full bg-primary" /> <div class="relative top-1 h-2 w-2 rounded-full bg-primary" />
{/if} {/if}
</div> </div>
+14 -12
View File
@@ -17,20 +17,22 @@
PLATFORM_LOGO, PLATFORM_LOGO,
} from "@app/state" } from "@app/state"
import {pushModal} from "@app/modal" import {pushModal} from "@app/modal"
import {deriveNotification, inactiveSpacesNotifications, CHAT_FILTERS} from "@app/notifications" import {makeSpacePath} from "@app/routes"
import {notifications, inactiveNotifications} from "@app/notifications"
const chatNotification = deriveNotification("/chat", CHAT_FILTERS)
const addSpace = () => pushModal(SpaceAdd) const addSpace = () => pushModal(SpaceAdd)
const showSpacesMenu = () => const showSpacesMenu = () => (spacePaths.length > 0 ? pushModal(MenuSpaces) : pushModal(SpaceAdd))
getMembershipUrls($userMembership).length > 0 ? pushModal(MenuSpaces) : pushModal(SpaceAdd)
const showSettingsMenu = () => pushModal(MenuSettings) const showSettingsMenu = () => pushModal(MenuSettings)
const openNotes = () => ($canDecrypt ? goto("/notes") : pushModal(ChatEnable, {next: "/notes"})) const openNotes = () => ($canDecrypt ? goto("/notes") : pushModal(ChatEnable, {next: "/notes"}))
const openChat = () => ($canDecrypt ? goto("/chat") : pushModal(ChatEnable, {next: "/chat"})) const openChat = () => ($canDecrypt ? goto("/chat") : pushModal(ChatEnable, {next: "/chat"}))
$: spaceUrls = getMembershipUrls($userMembership)
$: spacePaths = spaceUrls.map(url => makeSpacePath(url))
$: anySpaceNotifications = spacePaths.some(path => $inactiveNotifications.has(path))
</script> </script>
<div class="relative z-nav hidden w-14 flex-shrink-0 bg-base-200 pt-4 md:block"> <div class="relative z-nav hidden w-14 flex-shrink-0 bg-base-200 pt-4 md:block">
@@ -43,7 +45,7 @@
<Avatar src={PLATFORM_LOGO} class="!h-10 !w-10" /> <Avatar src={PLATFORM_LOGO} class="!h-10 !w-10" />
</PrimaryNavItem> </PrimaryNavItem>
<Divider /> <Divider />
{#each getMembershipUrls($userMembership) as url (url)} {#each spaceUrls as url (url)}
<PrimaryNavItemSpace {url} /> <PrimaryNavItemSpace {url} />
{/each} {/each}
<PrimaryNavItem title="Add Space" on:click={addSpace} class="tooltip-right"> <PrimaryNavItem title="Add Space" on:click={addSpace} class="tooltip-right">
@@ -66,7 +68,7 @@
title="Messages" title="Messages"
on:click={openChat} on:click={openChat}
class="tooltip-right" class="tooltip-right"
notification={$chatNotification}> notification={$notifications.has("/chat")}>
<Avatar icon="letter" class="!h-10 !w-10" /> <Avatar icon="letter" class="!h-10 !w-10" />
</PrimaryNavItem> </PrimaryNavItem>
<PrimaryNavItem title="Search" href="/people" class="tooltip-right"> <PrimaryNavItem title="Search" href="/people" class="tooltip-right">
@@ -88,13 +90,13 @@
<PrimaryNavItem title="Notes" href="/notes"> <PrimaryNavItem title="Notes" href="/notes">
<Avatar icon="notes-minimalistic" class="!h-10 !w-10" /> <Avatar icon="notes-minimalistic" class="!h-10 !w-10" />
</PrimaryNavItem> </PrimaryNavItem>
<PrimaryNavItem title="Messages" on:click={openChat} notification={$chatNotification}> <PrimaryNavItem
title="Messages"
on:click={openChat}
notification={$notifications.has("/chat")}>
<Avatar icon="letter" class="!h-10 !w-10" /> <Avatar icon="letter" class="!h-10 !w-10" />
</PrimaryNavItem> </PrimaryNavItem>
<PrimaryNavItem <PrimaryNavItem title="Spaces" on:click={showSpacesMenu} notification={anySpaceNotifications}>
title="Spaces"
on:click={showSpacesMenu}
notification={$inactiveSpacesNotifications.length > 0}>
<Avatar icon="settings-minimalistic" class="!h-10 !w-10" /> <Avatar icon="settings-minimalistic" class="!h-10 !w-10" />
</PrimaryNavItem> </PrimaryNavItem>
</div> </div>
@@ -3,7 +3,7 @@
import PrimaryNavItem from "@lib/components/PrimaryNavItem.svelte" import PrimaryNavItem from "@lib/components/PrimaryNavItem.svelte"
import SpaceAvatar from "@app/components/SpaceAvatar.svelte" import SpaceAvatar from "@app/components/SpaceAvatar.svelte"
import {makeSpacePath} from "@app/routes" import {makeSpacePath} from "@app/routes"
import {spacesNotifications} from "@app/notifications" import {notifications} from "@app/notifications"
export let url export let url
@@ -14,6 +14,6 @@
title={displayRelayUrl(url)} title={displayRelayUrl(url)}
href={path} href={path}
class="tooltip-right" class="tooltip-right"
notification={$spacesNotifications.includes(path)}> notification={$notifications.has(path)}>
<SpaceAvatar {url} /> <SpaceAvatar {url} />
</PrimaryNavItem> </PrimaryNavItem>
+2 -3
View File
@@ -15,7 +15,7 @@
import ThunkStatus from "@app/components/ThunkStatus.svelte" import ThunkStatus from "@app/components/ThunkStatus.svelte"
import ThreadMenu from "@app/components/ThreadMenu.svelte" import ThreadMenu from "@app/components/ThreadMenu.svelte"
import {publishDelete, publishReaction} from "@app/commands" import {publishDelete, publishReaction} from "@app/commands"
import {deriveNotification} from "@app/notifications" import {notifications} from "@app/notifications"
import {makeSpacePath} from "@app/routes" import {makeSpacePath} from "@app/routes"
import {PROTECTED} from "@app/state" import {PROTECTED} from "@app/state"
@@ -28,7 +28,6 @@
const path = makeSpacePath(url, "threads", event.id) const path = makeSpacePath(url, "threads", event.id)
const filters = [{kinds: [COMMENT], "#E": [event.id]}] const filters = [{kinds: [COMMENT], "#E": [event.id]}]
const replies = deriveEvents(repository, {filters}) const replies = deriveEvents(repository, {filters})
const notification = deriveNotification(path, filters, url)
const showPopover = () => popover.show() const showPopover = () => popover.show()
@@ -70,7 +69,7 @@
<span>{$replies.length} {$replies.length === 1 ? "reply" : "replies"}</span> <span>{$replies.length} {$replies.length === 1 ? "reply" : "replies"}</span>
</div> </div>
<div class="btn btn-neutral btn-xs relative hidden rounded-full sm:flex"> <div class="btn btn-neutral btn-xs relative hidden rounded-full sm:flex">
{#if $notification} {#if $notifications.has(path)}
<div class="h-2 w-2 rounded-full bg-primary" /> <div class="h-2 w-2 rounded-full bg-primary" />
{/if} {/if}
Active {formatTimestampRelative(lastActive)} Active {formatTimestampRelative(lastActive)}
+63 -75
View File
@@ -1,16 +1,15 @@
import {writable, derived} from "svelte/store" import {writable, derived} from "svelte/store"
import {page} from "$app/stores" import {page} from "$app/stores"
import {deriveEvents} from "@welshman/store" import {pubkey} from "@welshman/app"
import {repository, pubkey} from "@welshman/app" import {prop, max, sortBy, now} from "@welshman/lib"
import {prop, max, sortBy, assoc, lt, now} from "@welshman/lib" import type {TrustedEvent} from "@welshman/util"
import type {Filter, TrustedEvent} from "@welshman/util" import {MESSAGE} from "@welshman/util"
import {DIRECT_MESSAGE, MESSAGE, THREAD, COMMENT} from "@welshman/util" import {makeSpacePath, makeChatPath, makeThreadPath, makeRoomPath} from "@app/routes"
import {makeSpacePath, makeThreadPath, makeRoomPath} from "@app/routes"
import { import {
LEGACY_THREAD, THREAD_FILTER,
COMMENT_FILTER,
chats,
getEventsForUrl, getEventsForUrl,
deriveEventsForUrl,
getMembershipUrls,
userRoomsByUrl, userRoomsByUrl,
repositoryStore, repositoryStore,
} from "@app/state" } from "@app/state"
@@ -19,85 +18,74 @@ import {
export const checked = writable<Record<string, number>>({}) export const checked = writable<Record<string, number>>({})
checked.subscribe(v => console.log("====== checked", v))
export const deriveChecked = (key: string) => derived(checked, prop(key)) export const deriveChecked = (key: string) => derived(checked, prop(key))
export const setChecked = (key: string, ts = now()) => export const setChecked = (key: string) =>
Boolean(console.trace("====== setChecked", key)) || checked.update(state => ({...state, [key]: now()}))
checked.update(state => ({...state, [key]: ts}))
// Filters for various routes // Derived notifications state
export const CHAT_FILTERS: Filter[] = [{kinds: [DIRECT_MESSAGE]}] export const notifications = derived(
[pubkey, checked, chats, userRoomsByUrl, repositoryStore],
([$pubkey, $checked, $chats, $userRoomsByUrl, $repository]) => {
const hasNotification = (path: string, events: TrustedEvent[]) => {
const [latestEvent] = sortBy($e => -$e.created_at, events)
export const SPACE_FILTERS: Filter[] = [{kinds: [THREAD, MESSAGE, COMMENT]}] if (!latestEvent || latestEvent.pubkey === $pubkey) {
return false
}
export const ROOM_FILTERS: Filter[] = [{kinds: [MESSAGE]}] let checkPath = ""
let lastChecked = $checked["*"]
export const THREAD_FILTERS: Filter[] = [ for (const segment of path.slice(1).split("/")) {
{kinds: [THREAD, LEGACY_THREAD]}, checkPath += "/" + segment
{kinds: [COMMENT], "#K": [String(THREAD), String(LEGACY_THREAD)]}, lastChecked = max([lastChecked, $checked[checkPath]])
] }
export const getNotificationFilters = (since: number): Filter[] => return lastChecked < latestEvent.created_at
[...CHAT_FILTERS, ...SPACE_FILTERS, ...THREAD_FILTERS].map(assoc("since", since))
export const getRoomFilters = (room: string): Filter[] => ROOM_FILTERS.map(assoc("#h", [room]))
// Notification derivation
export const getNotification = (
pubkey: string | null,
lastChecked: number,
events: TrustedEvent[],
) => {
const [latestEvent] = sortBy($e => -$e.created_at, events)
return latestEvent?.pubkey !== pubkey && lt(lastChecked, latestEvent?.created_at)
}
export const deriveNotification = (path: string, filters: Filter[], url?: string) => {
const events = url ? deriveEventsForUrl(url, filters) : deriveEvents(repository, {filters})
return derived(
[pubkey, deriveChecked("*"), deriveChecked(path), events],
([$pubkey, $allChecked, $checked, $events]) => {
return getNotification($pubkey, max([$allChecked, $checked]), $events)
},
)
}
export const spacesNotifications = derived(
[pubkey, checked, userRoomsByUrl, repositoryStore],
([$pubkey, $checked, $userRoomsByUrl, $repository]) => {
const hasNotification = (url: string, path: string, filters: Filter[]) => {
const lastChecked = max([$checked["*"], $checked[path]])
const events = getEventsForUrl($repository, url, filters)
return getNotification($pubkey, lastChecked, events)
} }
return Array.from($userRoomsByUrl.entries()) const paths = new Set<string>()
.filter(([url, rooms]) => {
if (hasNotification(url, makeThreadPath(url), THREAD_FILTERS)) {
return true
}
for (const room of rooms) { for (const {pubkeys, messages} of $chats) {
if (hasNotification(url, makeRoomPath(url, room), [{kinds: [MESSAGE], "#h": [room]}])) { const chatPath = makeChatPath(pubkeys)
return true
}
}
return false if (hasNotification(chatPath, messages)) {
}) paths.add("/chat")
.map(([url]) => makeSpacePath(url)) paths.add(chatPath)
}
}
for (const [url, rooms] of $userRoomsByUrl.entries()) {
const spacePath = makeSpacePath(url)
const threadPath = makeThreadPath(url)
const threadFilters = [THREAD_FILTER, COMMENT_FILTER]
const threadEvents = getEventsForUrl($repository, url, threadFilters)
if (hasNotification(threadPath, threadEvents)) {
paths.add(spacePath)
paths.add(threadPath)
}
for (const room of rooms) {
const roomPath = makeRoomPath(url, room)
const roomFilters = [{kinds: [MESSAGE], "#h": [room]}]
const roomEvents = getEventsForUrl($repository, url, roomFilters)
if (hasNotification(roomPath, roomEvents)) {
paths.add(spacePath)
paths.add(roomPath)
}
}
}
return paths
}, },
) )
export const inactiveSpacesNotifications = derived( export const inactiveNotifications = derived(
[page, spacesNotifications], [page, notifications],
([$page, $spacesNotifications]) => ([$page, $notifications]) =>
$spacesNotifications.filter(path => !$page.url.pathname.startsWith(path)), new Set(Array.from($notifications).filter(path => !$page.url.pathname.startsWith(path))),
) )
+16 -2
View File
@@ -40,7 +40,14 @@ import {
asDecryptedEvent, asDecryptedEvent,
normalizeRelayUrl, normalizeRelayUrl,
} from "@welshman/util" } from "@welshman/util"
import type {TrustedEvent, SignedEvent, PublishedList, List, Filter} from "@welshman/util" import type {
TrustedEvent,
Repository,
SignedEvent,
PublishedList,
List,
Filter,
} from "@welshman/util"
import {Nip59} from "@welshman/signer" import {Nip59} from "@welshman/signer"
import { import {
pubkey, pubkey,
@@ -63,7 +70,7 @@ import {
thunks, thunks,
walkThunks, walkThunks,
} from "@welshman/app" } from "@welshman/app"
import type {Thunk} from "@welshman/app" import type {Thunk, Relay} from "@welshman/app"
import type {SubscribeRequestWithHandlers} from "@welshman/net" import type {SubscribeRequestWithHandlers} from "@welshman/net"
import {deriveEvents, deriveEventsMapped, withGetter, synced} from "@welshman/store" import {deriveEvents, deriveEventsMapped, withGetter, synced} from "@welshman/store"
@@ -107,6 +114,13 @@ export const IMGPROXY_URL = "https://imgproxy.coracle.social"
export const REACTION_KINDS = [REACTION, ZAP_RESPONSE] export const REACTION_KINDS = [REACTION, ZAP_RESPONSE]
export const THREAD_FILTER: Filter = {kinds: [THREAD, LEGACY_THREAD]}
export const COMMENT_FILTER: Filter = {
kinds: [COMMENT],
"#K": [String(THREAD), String(LEGACY_THREAD)],
}
export const NIP46_PERMS = export const NIP46_PERMS =
"nip04_encrypt,nip04_decrypt,nip44_encrypt,nip44_decrypt," + "nip04_encrypt,nip04_decrypt,nip44_encrypt,nip44_decrypt," +
[CLIENT_AUTH, AUTH_JOIN, MESSAGE, THREAD, COMMENT, GROUPS, WRAP, REACTION] [CLIENT_AUTH, AUTH_JOIN, MESSAGE, THREAD, COMMENT, GROUPS, WRAP, REACTION]
+2 -2
View File
@@ -13,7 +13,7 @@
import {setChecked} from "@app/notifications" import {setChecked} from "@app/notifications"
import {checkRelayConnection, checkRelayAuth, checkRelayAccess} from "@app/commands" import {checkRelayConnection, checkRelayAuth, checkRelayAccess} from "@app/commands"
import {decodeRelay} from "@app/state" import {decodeRelay} from "@app/state"
import {spacesNotifications} from "@app/notifications" import {notifications} from "@app/notifications"
const url = decodeRelay($page.params.relay) const url = decodeRelay($page.params.relay)
@@ -35,7 +35,7 @@
// We have to watch this one, since on mobile the badge will be visible when active // We have to watch this one, since on mobile the badge will be visible when active
$: { $: {
if ($spacesNotifications.includes($page.url.pathname)) { if ($notifications.has($page.url.pathname)) {
setChecked($page.url.pathname) setChecked($page.url.pathname)
} }
} }
@@ -3,7 +3,7 @@
import {derived} from "svelte/store" import {derived} from "svelte/store"
import {page} from "$app/stores" import {page} from "$app/stores"
import {sortBy, min, nthEq, sleep} from "@welshman/lib" import {sortBy, min, nthEq, sleep} from "@welshman/lib"
import {getListTags, getPubkeyTagValues, THREAD, COMMENT} from "@welshman/util" import {getListTags, getPubkeyTagValues} from "@welshman/util"
import {throttled} from "@welshman/store" import {throttled} from "@welshman/store"
import {feedsFromFilters, makeIntersectionFeed, makeRelayFeed} from "@welshman/feeds" import {feedsFromFilters, makeIntersectionFeed, makeRelayFeed} from "@welshman/feeds"
import {createFeedController, userMutes} from "@welshman/app" import {createFeedController, userMutes} from "@welshman/app"
@@ -16,15 +16,14 @@
import MenuSpaceButton from "@app/components/MenuSpaceButton.svelte" import MenuSpaceButton from "@app/components/MenuSpaceButton.svelte"
import ThreadItem from "@app/components/ThreadItem.svelte" import ThreadItem from "@app/components/ThreadItem.svelte"
import ThreadCreate from "@app/components/ThreadCreate.svelte" import ThreadCreate from "@app/components/ThreadCreate.svelte"
import {LEGACY_THREAD, decodeRelay, deriveEventsForUrl} from "@app/state" import {THREAD_FILTER, COMMENT_FILTER, decodeRelay, deriveEventsForUrl} from "@app/state"
import {THREAD_FILTERS, setChecked} from "@app/notifications" import {setChecked} from "@app/notifications"
import {pushModal} from "@app/modal" import {pushModal} from "@app/modal"
const url = decodeRelay($page.params.relay) const url = decodeRelay($page.params.relay)
const threads = deriveEventsForUrl(url, [{kinds: [THREAD, LEGACY_THREAD]}]) const feeds = feedsFromFilters([THREAD_FILTER, COMMENT_FILTER])
const comments = deriveEventsForUrl(url, [ const threads = deriveEventsForUrl(url, [THREAD_FILTER])
{kinds: [COMMENT], "#K": [String(THREAD), String(LEGACY_THREAD)]}, const comments = deriveEventsForUrl(url, [COMMENT_FILTER])
])
const mutedPubkeys = getPubkeyTagValues(getListTags($userMutes)) const mutedPubkeys = getPubkeyTagValues(getListTags($userMutes))
const events = throttled( const events = throttled(
@@ -51,7 +50,7 @@
const ctrl = createFeedController({ const ctrl = createFeedController({
useWindowing: true, useWindowing: true,
feed: makeIntersectionFeed(makeRelayFeed(url), feedsFromFilters(THREAD_FILTERS)), feed: makeIntersectionFeed(makeRelayFeed(url), feeds),
onExhausted: () => { onExhausted: () => {
loading = false loading = false
}, },