From a7d05a29f5a0da181474839d4e283cc47be88da7 Mon Sep 17 00:00:00 2001 From: Gigi Date: Sun, 19 Oct 2025 12:29:44 +0200 Subject: [PATCH] feat: process local reading progress via eventStore.timeline() - Subscribe to timeline for immediate local events and reactive updates - Clean up timeline subscription on reset/start to avoid leaks - Keep relay sync for background augmentation - Should populate progress map even without relay roundtrip --- src/services/readingProgressController.ts | 26 +++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/services/readingProgressController.ts b/src/services/readingProgressController.ts index 6fec89f8..34610378 100644 --- a/src/services/readingProgressController.ts +++ b/src/services/readingProgressController.ts @@ -23,6 +23,7 @@ class ReadingProgressController { private currentProgressMap: Map = new Map() private lastLoadedPubkey: string | null = null private generation = 0 + private timelineSubscription: { unsubscribe: () => void } | null = null onProgress(cb: ProgressMapCallback): () => void { this.progressListeners.push(cb) @@ -73,6 +74,11 @@ class ReadingProgressController { */ reset(): void { this.generation++ + // Unsubscribe from any active timeline subscription + if (this.timelineSubscription) { + try { this.timelineSubscription.unsubscribe() } catch {} + this.timelineSubscription = null + } this.currentProgressMap = new Map() this.lastLoadedPubkey = null this.emitProgress(this.currentProgressMap) @@ -130,6 +136,26 @@ class ReadingProgressController { this.lastLoadedPubkey = pubkey try { + // Subscribe to local timeline for immediate and reactive updates + // Clean up any previous subscription first + if (this.timelineSubscription) { + try { this.timelineSubscription.unsubscribe() } catch {} + this.timelineSubscription = null + } + + const timeline$ = eventStore.timeline({ + kinds: [KINDS.ReadingProgress], + authors: [pubkey] + }) + const generationAtSubscribe = this.generation + this.timelineSubscription = timeline$.subscribe((localEvents: NostrEvent[]) => { + // Ignore if controller generation has changed (e.g., logout/login) + if (generationAtSubscribe !== this.generation) return + if (!Array.isArray(localEvents) || localEvents.length === 0) return + console.log('📊 [ReadingProgress] Timeline update with', localEvents.length, 'event(s)') + this.processEvents(localEvents) + }) + // Query events from relays // Force full sync if map is empty (first load) or if explicitly forced const needsFullSync = force || this.currentProgressMap.size === 0