diff --git a/ROADMAP.md b/ROADMAP.md index f5235e02..9460d281 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1,9 +1,5 @@ # Current -- [ ] Fix pagination - -# Next - - [ ] Relay detail page, with more information about the relay + tabbed feeds (notes, more?) - [ ] Add customize icon and route with editable custom view cards using "lists" nip - nevent1qqspjcqw2hu5gfcpkrjhs0aqvxuzjgtp50l375mcqjfpmk48cg5hevgpr3mhxue69uhkummnw3ez6un9d3shjtnhd3m8xtnnwpskxegpzamhxue69uhkummnw3ezuendwsh8w6t69e3xj7spramhxue69uhkummnw3ez6un9d3shjtnwdahxxefwv93kzer9d4usz9rhwden5te0wfjkccte9ejxzmt4wvhxjmcpr9mhxue69uhkummnw3ezuer9d3hjuum0ve68wctjv5n8hwfg diff --git a/src/partials/Channel.svelte b/src/partials/Channel.svelte index 97403898..a6db92c1 100644 --- a/src/partials/Channel.svelte +++ b/src/partials/Channel.svelte @@ -72,12 +72,11 @@ const scroller = createScroller( async () => { await loadMessages(cursor, newMessages => { - cursor.onChunk(newMessages) - stickToBottom('auto', () => { loading = sleep(30_000) messages = sortBy(e => -e.created_at, newMessages.concat(messages)) network.loadPeople(pluck('pubkey', newMessages)) + cursor.update(messages) }) }) }, diff --git a/src/util/misc.ts b/src/util/misc.ts index afd0188d..718aa5aa 100644 --- a/src/util/misc.ts +++ b/src/util/misc.ts @@ -1,5 +1,5 @@ import {debounce, throttle} from 'throttle-debounce' -import {path as getPath, allPass, pipe, isNil, complement, equals, is, pluck, sum, identity, sortBy} from "ramda" +import {aperture, path as getPath, allPass, pipe, isNil, complement, equals, is, pluck, sum, identity, sortBy} from "ramda" import Fuse from "fuse.js/dist/fuse.min.js" import {writable} from 'svelte/store' import {isObject} from 'hurdak/lib/hurdak' @@ -152,14 +152,19 @@ export class Cursor { this.until = now() this.limit = limit } - onChunk(events) { - const minDelta = timedelta(1, 'minutes') - const maxDelta = timedelta(1, 'hours') - const delta = pluck('created_at', events).reduce(Math.min, 0) || 0 + update(events) { + // update takes all events in a feed and figures out the best place to set `until` + // in order to find older events without re-fetching events that we've already seen. + // There are various edge cases: + // - When we have zero events, there's nothing we can do, presumably we have everything. + // - Sometimes relays send us extremely old events. Use median to avoid too-large gaps + if (events.length > 1) { + const timestamps = sortBy(identity, pluck('created_at', events)) + const gaps = aperture(2, timestamps).map(([a, b]) => b - a) + const gap = quantile(gaps, 0.5) - // If the delta is very large, size it down. Relays with sparse data - // can slide the window very quickly, skipping a lot of events on more dense relays - this.until -= Math.max(minDelta, Math.min(maxDelta, delta)) + this.until -= Math.round(gap * events.length) + } } } @@ -262,3 +267,14 @@ export const union = (...sets) => export const difference = (a, b) => new Set(Array.from(a).filter(x => !b.has(x))) + +export const quantile = (a, q) => { + const sorted = sortBy(identity, a) + const pos = (sorted.length - 1) * q + const base = Math.floor(pos) + const rest = pos - base + + return isNil(sorted[base + 1]) + ? sorted[base] + : sorted[base] + rest * (sorted[base + 1] - sorted[base]) +} diff --git a/src/views/Toast.svelte b/src/views/Toast.svelte index c81abd92..966e8629 100644 --- a/src/views/Toast.svelte +++ b/src/views/Toast.svelte @@ -12,7 +12,7 @@ transition:fly={{y: -50, duration: 300}}>
{