Make scroller stoppable

This commit is contained in:
Jonathan Staab 2022-11-30 21:13:55 -08:00
parent 7015ed136c
commit ddcb5ac0a3
4 changed files with 50 additions and 27 deletions

View File

@ -7,7 +7,7 @@
import {toHtml} from 'src/util/html'
import UserBadge from 'src/partials/UserBadge.svelte'
import {Listener, Cursor, epoch} from 'src/state/nostr'
import {accounts, scroller, ensureAccounts} from 'src/state/app'
import {accounts, createScroller, ensureAccounts} from 'src/state/app'
import {dispatch} from 'src/state/dispatch'
import {user} from 'src/state/user'
import RoomList from "src/partials/chat/RoomList.svelte"
@ -16,7 +16,7 @@
let cursor
let listener
let scroll
let scroller
let textarea
let messages = []
let annotatedMessages = []
@ -63,7 +63,7 @@
}
cursor = new Cursor({kinds: [42], '#e': [room]})
scroll = scroller(
scroller = createScroller(
cursor,
chunk => {
stickToBottom('auto', async () => {
@ -97,14 +97,14 @@
}
)
scroll()
scroller.start()
listener.start()
})
onDestroy(() => {
cursor?.stop()
listener?.stop()
scroller?.stop()
})
const edit = () => {
@ -129,7 +129,7 @@
}
</script>
<svelte:window on:scroll={scroll} />
<svelte:window on:scroll={scroller?.start} />
<div class="flex gap-4 h-full">
<div class="sm:ml-56 w-full">

View File

@ -8,12 +8,13 @@
import Spinner from "src/partials/Spinner.svelte"
import Note from "src/partials/Note.svelte"
import {relays, Cursor} from "src/state/nostr"
import {scroller, annotateNotes, notesListener, modal} from "src/state/app"
import {createScroller, annotateNotes, notesListener, modal} from "src/state/app"
const notes = writable([])
let cursor
let listener
let scroll
let scroller
let modalUnsub
const createNote = () => {
navigate("/notes/new")
@ -22,38 +23,35 @@
onMount(async () => {
cursor = new Cursor({kinds: [1]})
listener = await notesListener(notes, {kinds: [1, 5, 7]})
scroll = scroller(cursor, async chunk => {
scroller = createScroller(cursor, async chunk => {
const annotated = await annotateNotes(chunk, {showParents: true})
notes.update($notes => uniqBy(prop('id'), $notes.concat(annotated)))
})
// Populate our initial empty space
scroll()
// When a modal opens, suspend our subscriptions
const modalUnsub = modal.subscribe(async $modal => {
modalUnsub = modal.subscribe(async $modal => {
if ($modal) {
cursor.stop()
listener.stop()
scroller.stop()
} else {
cursor.start()
listener.start()
scroller.start()
}
})
return () => {
modalUnsub()
}
})
onDestroy(() => {
cursor?.stop()
listener?.stop()
scroller?.stop()
modalUnsub?.()
})
</script>
<svelte:window on:scroll={scroll} />
<svelte:window on:scroll={scroller?.start} />
<ul class="py-8 flex flex-col gap-2 max-w-xl m-auto">
{#each (notes ? $notes : []) as n (n.id)}

View File

@ -7,7 +7,7 @@
import Spinner from "src/partials/Spinner.svelte"
import {Cursor, epoch} from 'src/state/nostr'
import {user as currentUser} from 'src/state/user'
import {accounts, scroller, notesListener, modal, annotateNotes} from "src/state/app"
import {accounts, createScroller, notesListener, modal, annotateNotes} from "src/state/app"
export let pubkey
@ -15,7 +15,7 @@
let user
let cursor
let listener
let scroll
let scroller
let interval
let loading = true
let modalUnsub
@ -25,14 +25,14 @@
onMount(async () => {
cursor = new Cursor({kinds: [1], authors: [pubkey]})
listener = await notesListener(notes, [{kinds: [1], authors: [pubkey]}, {kinds: [5, 7]}])
scroll = scroller(cursor, async chunk => {
scroller = createScroller(cursor, async chunk => {
const annotated = await annotateNotes(chunk, {showParents: true})
notes.update($notes => uniqBy(prop('id'), $notes.concat(annotated)))
})
// Populate our initial empty space
scroll()
scroller.start()
// Track loading based on cursor cutoff date
interval = setInterval(() => {
@ -54,13 +54,14 @@
onDestroy(() => {
cursor?.stop()
listener?.stop()
modalUnsub()
scroller?.stop()
modalUnsub?.()
clearInterval(interval)
})
</script>
<svelte:window on:scroll={scroll} />
<svelte:window on:scroll={scroller?.start} />
{#if user}
<div class="max-w-2xl m-auto flex flex-col gap-4 py-8 px-4">

View File

@ -170,10 +170,22 @@ export const notesListener = (notes, filter) => {
// UI
export const scroller = (cursor, cb, {isInModal = false, since = epoch, reverse = false} = {}) => {
export const createScroller = (
cursor,
onChunk,
{isInModal = false, since = epoch, reverse = false} = {}
) => {
const startingDelta = cursor.delta
return debounce(1000, async () => {
let active = false
const start = debounce(1000, async () => {
if (active) {
return
}
active = true
/* eslint no-constant-condition: 0 */
while (true) {
// If a modal opened up, wait for them to close it. Otherwise, throttle a tad
@ -206,7 +218,7 @@ export const scroller = (cursor, cb, {isInModal = false, since = epoch, reverse
// Notify the caller
if (chunk.length > 0) {
await cb(chunk)
await onChunk(chunk)
}
// If we have an empty chunk, increase our step size so we can get back to where
@ -216,6 +228,18 @@ export const scroller = (cursor, cb, {isInModal = false, since = epoch, reverse
} else {
cursor.delta = startingDelta
}
if (!active) {
break
}
}
active = false
})
return {
start,
stop: () => { active = false },
isActive: () => Boolean(cursor.sub),
}
}