mirror of
https://github.com/coracle-social/flotilla.git
synced 2025-12-10 10:57:04 +00:00
Fix loading and scrolling
This commit is contained in:
@@ -22,7 +22,7 @@
|
||||
const expand = () => pushModal(ContentLinkDetail, {url}, {fullscreen: true})
|
||||
</script>
|
||||
|
||||
<Link external href={url} class="my-2 flex">
|
||||
<Link external href={url} class="my-2 inline-block">
|
||||
<div class="overflow-hidden rounded-box leading-[0]">
|
||||
{#if url.match(/\.(mov|webm|mp4)$/)}
|
||||
<video controls src={url} class="max-h-96 object-contain object-center">
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
</p>
|
||||
</div>
|
||||
{:else}
|
||||
<p class="-mb-3 h-0 text-end text-xs opacity-75">
|
||||
<p class="mb-3 h-0 text-xs opacity-75">
|
||||
{formatTimestamp(event.created_at)}
|
||||
</p>
|
||||
{/if}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import {get} from "svelte/store"
|
||||
import {partition, assoc, now, ago, MONTH} from "@welshman/lib"
|
||||
import {MESSAGE, DELETE, THREAD, COMMENT} from "@welshman/util"
|
||||
import {partition, assoc, now} from "@welshman/lib"
|
||||
import {MESSAGE, THREAD, COMMENT} from "@welshman/util"
|
||||
import type {Subscription} from "@welshman/net"
|
||||
import type {AppSyncOpts} from "@welshman/app"
|
||||
import {subscribe, repository, pull, hasNegentropy} from "@welshman/app"
|
||||
import {subscribe, load, repository, pull, hasNegentropy} from "@welshman/app"
|
||||
import {userRoomsByUrl, getUrlsForEvent} from "@app/state"
|
||||
|
||||
// Utils
|
||||
@@ -35,12 +35,12 @@ export const listenForNotifications = () => {
|
||||
const subs: Subscription[] = []
|
||||
|
||||
for (const [url, rooms] of userRoomsByUrl.get()) {
|
||||
pullConservatively({
|
||||
load({
|
||||
relays: [url],
|
||||
filters: [
|
||||
{kinds: [THREAD, DELETE], since: ago(MONTH)},
|
||||
{kinds: [COMMENT], "#K": [String(THREAD)], since: ago(MONTH)},
|
||||
...Array.from(rooms).map(room => ({kinds: [MESSAGE], "#h": [room], since: ago(MONTH)})),
|
||||
{kinds: [THREAD], limit: 1},
|
||||
{kinds: [COMMENT], "#K": [String(THREAD)], limit: 1},
|
||||
...Array.from(rooms).map(room => ({kinds: [MESSAGE], "#h": [room], limit: 1})),
|
||||
],
|
||||
})
|
||||
|
||||
|
||||
@@ -607,8 +607,7 @@ export const userSettingValues = withGetter(
|
||||
derived(userSettings, $s => $s?.values || defaultSettings),
|
||||
)
|
||||
|
||||
export const getSetting = <T = any>(key: keyof Settings["values"]) =>
|
||||
userSettingValues.get()[key] as T
|
||||
export const getSetting = <T>(key: keyof Settings["values"]) => userSettingValues.get()[key] as T
|
||||
|
||||
export const userMembership = withGetter(
|
||||
derived([pubkey, membershipByPubkey], ([$pubkey, $membershipByPubkey]) => {
|
||||
|
||||
@@ -5,20 +5,12 @@
|
||||
import {get, derived} from "svelte/store"
|
||||
import {dev} from "$app/environment"
|
||||
import {bytesToHex, hexToBytes} from "@noble/hashes/utils"
|
||||
import {
|
||||
identity,
|
||||
sleep,
|
||||
take,
|
||||
sortBy,
|
||||
ago,
|
||||
now,
|
||||
HOUR,
|
||||
WEEK,
|
||||
Worker,
|
||||
} from "@welshman/lib"
|
||||
import {identity, sleep, take, sortBy, ago, now, HOUR, WEEK, MONTH, Worker} from "@welshman/lib"
|
||||
import type {TrustedEvent} from "@welshman/util"
|
||||
import {
|
||||
MESSAGE,
|
||||
PROFILE,
|
||||
DELETE,
|
||||
REACTION,
|
||||
ZAP_RESPONSE,
|
||||
FOLLOWS,
|
||||
@@ -111,13 +103,13 @@
|
||||
events: storageAdapters.fromRepositoryAndTracker(repository, tracker, {
|
||||
throttle: 3000,
|
||||
migrate: (events: TrustedEvent[]) => {
|
||||
if (events.length < 50_000) {
|
||||
if (events.length < 15_000) {
|
||||
return events
|
||||
}
|
||||
|
||||
const NEVER_KEEP = 0
|
||||
const ALWAYS_KEEP = Infinity
|
||||
const reactionKinds = [REACTION, ZAP_RESPONSE]
|
||||
const reactionKinds = [REACTION, ZAP_RESPONSE, DELETE]
|
||||
const metaKinds = [PROFILE, FOLLOWS, RELAYS, INBOX_RELAYS]
|
||||
const $sessionKeys = new Set(Object.keys(app.sessions.get()))
|
||||
const $userFollows = new Set(getPubkeyTagValues(getListTags(get(app.userFollows))))
|
||||
@@ -129,6 +121,9 @@
|
||||
// No need to keep a record of everyone who follows the current user
|
||||
if (e.kind === FOLLOWS && !isFollowing) return NEVER_KEEP
|
||||
|
||||
// Drop room messages after a month, re-load on demand
|
||||
if (e.kind === MESSAGE && e.created_at < ago(MONTH)) return NEVER_KEEP
|
||||
|
||||
// Always keep stuff by or tagging a signed in user
|
||||
if ($sessionKeys.has(e.pubkey)) return ALWAYS_KEEP
|
||||
if (e.tags.some(t => $sessionKeys.has(t[1]))) return ALWAYS_KEEP
|
||||
@@ -148,7 +143,7 @@
|
||||
}
|
||||
|
||||
return take(
|
||||
30_000,
|
||||
10_000,
|
||||
sortBy(e => -scoreEvent(e), events),
|
||||
)
|
||||
},
|
||||
@@ -193,11 +188,11 @@
|
||||
// Listen for chats, populate chat-based notifications
|
||||
let chatsSub: any
|
||||
|
||||
derived([pubkey, userInboxRelaySelections], identity).subscribe(
|
||||
([$pubkey, $userInboxRelaySelections]) => {
|
||||
derived([pubkey, canDecrypt, userInboxRelaySelections], identity).subscribe(
|
||||
([$pubkey, $canDecrypt, $userInboxRelaySelections]) => {
|
||||
chatsSub?.close()
|
||||
|
||||
if ($pubkey) {
|
||||
if ($pubkey && $canDecrypt) {
|
||||
chatsSub = subscribe({
|
||||
filters: [
|
||||
{kinds: [WRAP], "#p": [$pubkey], since: ago(WEEK, 2)},
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<script lang="ts">
|
||||
import {onMount} from "svelte"
|
||||
import {page} from "$app/stores"
|
||||
import {now} from "@welshman/lib"
|
||||
import {ago, WEEK} from "@welshman/lib"
|
||||
import {GROUPS, MESSAGE, DELETE} from "@welshman/util"
|
||||
import {subscribe} from "@welshman/app"
|
||||
import {DELETE, REACTION, GROUPS} from "@welshman/util"
|
||||
import Page from "@lib/components/Page.svelte"
|
||||
import SecondaryNav from "@lib/components/SecondaryNav.svelte"
|
||||
import MenuSpace from "@app/components/MenuSpace.svelte"
|
||||
@@ -12,11 +12,14 @@
|
||||
import {pushModal} from "@app/modal"
|
||||
import {setChecked} from "@app/notifications"
|
||||
import {checkRelayConnection, checkRelayAuth, checkRelayAccess} from "@app/commands"
|
||||
import {decodeRelay} from "@app/state"
|
||||
import {decodeRelay, userRoomsByUrl, THREAD_FILTER, COMMENT_FILTER} from "@app/state"
|
||||
import {pullConservatively} from "@app/requests"
|
||||
import {notifications} from "@app/notifications"
|
||||
|
||||
const url = decodeRelay($page.params.relay)
|
||||
|
||||
const rooms = Array.from($userRoomsByUrl.get(url) || [])
|
||||
|
||||
const checkConnection = async () => {
|
||||
const connectionError = await checkRelayConnection(url)
|
||||
|
||||
@@ -43,11 +46,27 @@
|
||||
onMount(() => {
|
||||
checkConnection()
|
||||
|
||||
const sub = subscribe({
|
||||
relays: [url],
|
||||
filters: [{kinds: [GROUPS]}, {kinds: [DELETE, REACTION], since: now()}],
|
||||
const relays = [url]
|
||||
const since = ago(WEEK)
|
||||
|
||||
// Load all groups for this space to populate navigation
|
||||
pullConservatively({relays, filters: [{kinds: [GROUPS]}]})
|
||||
|
||||
// Load threads and comments
|
||||
pullConservatively({
|
||||
relays,
|
||||
filters: [
|
||||
{...THREAD_FILTER, since},
|
||||
{...COMMENT_FILTER, since},
|
||||
],
|
||||
})
|
||||
|
||||
// Load recent messages for user rooms to help with a quick page transition
|
||||
pullConservatively({relays, filters: rooms.map(r => ({kinds: [MESSAGE], "#h": [r], since}))})
|
||||
|
||||
// Listen for deletes that would apply to messages we already have
|
||||
const sub = subscribe({relays, filters: [{kinds: [DELETE], since}]})
|
||||
|
||||
return () => {
|
||||
sub.close()
|
||||
}
|
||||
|
||||
@@ -1,13 +1,20 @@
|
||||
<script lang="ts">
|
||||
import {nip19} from "nostr-tools"
|
||||
import {onDestroy} from "svelte"
|
||||
import {onMount} from "svelte"
|
||||
import {derived} from "svelte/store"
|
||||
import {page} from "$app/stores"
|
||||
import {sleep, ctx} from "@welshman/lib"
|
||||
import {sleep, now, ctx} from "@welshman/lib"
|
||||
import type {TrustedEvent, EventContent} from "@welshman/util"
|
||||
import {throttled} from "@welshman/store"
|
||||
import {createEvent, MESSAGE} from "@welshman/util"
|
||||
import {formatTimestampAsDate, publishThunk, deriveRelay} from "@welshman/app"
|
||||
import {feedsFromFilter, makeIntersectionFeed, makeRelayFeed} from "@welshman/feeds"
|
||||
import {createEvent, MESSAGE, DELETE, REACTION} from "@welshman/util"
|
||||
import {
|
||||
formatTimestampAsDate,
|
||||
createFeedController,
|
||||
subscribe,
|
||||
publishThunk,
|
||||
deriveRelay,
|
||||
} from "@welshman/app"
|
||||
import {slide} from "@lib/transition"
|
||||
import {createScroller, type Scroller} from "@lib/html"
|
||||
import Icon from "@lib/components/Icon.svelte"
|
||||
@@ -41,6 +48,8 @@
|
||||
const url = decodeRelay($page.params.relay)
|
||||
const relay = deriveRelay(url)
|
||||
const legacyRoom = room === GENERAL ? "general" : room
|
||||
const feeds = feedsFromFilter({kinds: [MESSAGE], "#h": [room]})
|
||||
|
||||
const events = throttled(
|
||||
300,
|
||||
deriveEventsForUrl(url, [
|
||||
@@ -49,6 +58,14 @@
|
||||
]),
|
||||
)
|
||||
|
||||
const ctrl = createFeedController({
|
||||
useWindowing: true,
|
||||
feed: makeIntersectionFeed(makeRelayFeed(url), ...feeds),
|
||||
onExhausted: () => {
|
||||
loading = false
|
||||
},
|
||||
})
|
||||
|
||||
const assertEvent = (e: any) => e as TrustedEvent
|
||||
|
||||
const joinRoom = async () => {
|
||||
@@ -87,8 +104,9 @@
|
||||
delay: $userSettingValues.send_delay,
|
||||
})
|
||||
|
||||
let limit = 30
|
||||
let loading = sleep(5000)
|
||||
let limit = 100
|
||||
let loading = true
|
||||
let unmounted = false
|
||||
let element: HTMLElement
|
||||
let scroller: Scroller
|
||||
let editor: ReturnType<typeof getEditor>
|
||||
@@ -118,27 +136,39 @@
|
||||
previousPubkey = pubkey
|
||||
}
|
||||
|
||||
return $elements.reverse().slice(0, limit)
|
||||
return $elements.reverse()
|
||||
})
|
||||
|
||||
// Sveltekit doesn't set element in onMount for some reason
|
||||
$: {
|
||||
if (element) {
|
||||
scroller = createScroller({
|
||||
element,
|
||||
delay: 300,
|
||||
threshold: 3000,
|
||||
onScroll: () => {
|
||||
limit += 30
|
||||
loading = sleep(5000)
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
onMount(() => {
|
||||
// Element is frequently not defined. I don't know why
|
||||
sleep(1000).then(() => {
|
||||
if (!unmounted) {
|
||||
scroller = createScroller({
|
||||
element,
|
||||
delay: 300,
|
||||
threshold: 10_000,
|
||||
onScroll: () => {
|
||||
limit += 100
|
||||
|
||||
onDestroy(() => {
|
||||
setChecked($page.url.pathname)
|
||||
scroller?.stop()
|
||||
if ($events.length - limit < 100) {
|
||||
ctrl.load(200)
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
const sub = subscribe({
|
||||
relays: [url],
|
||||
filters: [{kinds: [DELETE, REACTION, MESSAGE], "#h": [room], since: now()}],
|
||||
})
|
||||
|
||||
return () => {
|
||||
unmounted = true
|
||||
setChecked($page.url.pathname)
|
||||
scroller?.stop()
|
||||
sub.close()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -170,7 +200,7 @@
|
||||
<div
|
||||
class="scroll-container -mt-2 flex flex-grow flex-col-reverse overflow-auto py-2"
|
||||
bind:this={element}>
|
||||
{#each $elements as { type, id, value, showPubkey } (id)}
|
||||
{#each $elements.slice(0, limit) as { type, id, value, showPubkey } (id)}
|
||||
{#if type === "date"}
|
||||
<Divider>{value}</Divider>
|
||||
{:else}
|
||||
@@ -180,11 +210,11 @@
|
||||
{/if}
|
||||
{/each}
|
||||
<p class="flex h-10 items-center justify-center py-20">
|
||||
{#await loading}
|
||||
{#if loading}
|
||||
<Spinner loading>Looking for messages...</Spinner>
|
||||
{:then}
|
||||
{:else}
|
||||
<Spinner>End of message history</Spinner>
|
||||
{/await}
|
||||
{/if}
|
||||
</p>
|
||||
</div>
|
||||
<ChannelCompose bind:editor {content} {onSubmit} />
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
import {sortBy, min, nthEq, sleep} from "@welshman/lib"
|
||||
import {getListTags, getPubkeyTagValues} from "@welshman/util"
|
||||
import {throttled} from "@welshman/store"
|
||||
import {feedsFromFilters, makeIntersectionFeed, makeRelayFeed} from "@welshman/feeds"
|
||||
import {feedFromFilters, makeIntersectionFeed, makeRelayFeed} from "@welshman/feeds"
|
||||
import {createFeedController, userMutes} from "@welshman/app"
|
||||
import {createScroller, type Scroller} from "@lib/html"
|
||||
import {fly} from "@lib/transition"
|
||||
@@ -21,7 +21,7 @@
|
||||
import {pushModal} from "@app/modal"
|
||||
|
||||
const url = decodeRelay($page.params.relay)
|
||||
const feeds = feedsFromFilters([THREAD_FILTER, COMMENT_FILTER])
|
||||
const feed = feedFromFilters([THREAD_FILTER, COMMENT_FILTER])
|
||||
const threads = deriveEventsForUrl(url, [THREAD_FILTER])
|
||||
const comments = deriveEventsForUrl(url, [COMMENT_FILTER])
|
||||
const mutedPubkeys = getPubkeyTagValues(getListTags($userMutes))
|
||||
@@ -50,7 +50,7 @@
|
||||
|
||||
const ctrl = createFeedController({
|
||||
useWindowing: true,
|
||||
feed: makeIntersectionFeed(makeRelayFeed(url), feeds),
|
||||
feed: makeIntersectionFeed(makeRelayFeed(url), feed),
|
||||
onExhausted: () => {
|
||||
loading = false
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user