feat: add listener for markedAsReadChanged events

Implemented event listener pattern in readingProgressController:
- Added onMarkedAsReadChanged() method for subscribers
- Added emitMarkedAsReadChanged() to notify when marked IDs update
- Call emitMarkedAsReadChanged() after loading reactions

In Me.tsx:
- Subscribe to onMarkedAsReadChanged() in new useEffect
- When fired, rebuild reads list with new marked-as-read items
- Include marked-only items (no progress event)

Now when reactions finish loading in background, /me/reads/completed
will update automatically with newly marked articles.
This commit is contained in:
Gigi
2025-10-20 00:34:38 +02:00
parent 2bf9b9789b
commit e5b1594933
2 changed files with 53 additions and 0 deletions

View File

@@ -192,6 +192,46 @@ const Me: React.FC<MeProps> = ({
unsubProgress()
}
}, [])
// Subscribe to marked-as-read changes and rebuild reads list
useEffect(() => {
const unsubMarkedAsRead = readingProgressController.onMarkedAsReadChanged(() => {
// Rebuild reads list including marked-as-read-only items
const progressMap = readingProgressController.getProgressMap()
const readItems: ReadItem[] = Array.from(progressMap.entries()).map(([id, progress]) => ({
id,
source: 'reading-progress',
type: 'article',
readingProgress: progress,
markedAsRead: readingProgressController.isMarkedAsRead(id),
readingTimestamp: Math.floor(Date.now() / 1000)
}))
// Include items that are only marked-as-read (no progress event yet)
const markedIds = readingProgressController.getMarkedAsReadIds()
for (const id of markedIds) {
if (!readItems.find(i => i.id === id)) {
const isArticle = id.startsWith('naddr1')
readItems.push({
id,
source: 'marked-as-read',
type: isArticle ? 'article' : 'external',
url: isArticle ? undefined : id,
markedAsRead: true,
readingTimestamp: Math.floor(Date.now() / 1000)
})
}
}
const readsMap = new Map(readItems.map(item => [item.id, item]))
setReadsMap(readsMap)
setReads(readItems)
})
return () => {
unsubMarkedAsRead()
}
}, [])
// Load reading progress data for writings tab
useEffect(() => {

View File

@@ -24,6 +24,7 @@ const PROGRESS_CACHE_KEY = 'reading_progress_cache_v1'
class ReadingProgressController {
private progressListeners: ProgressMapCallback[] = []
private loadingListeners: LoadingCallback[] = []
private markedAsReadListeners: (() => void)[] = []
private currentProgressMap: Map<string, number> = new Map()
private markedAsReadIds: Set<string> = new Set()
@@ -46,6 +47,13 @@ class ReadingProgressController {
}
}
onMarkedAsReadChanged(cb: () => void): () => void {
this.markedAsReadListeners.push(cb)
return () => {
this.markedAsReadListeners = this.markedAsReadListeners.filter(l => l !== cb)
}
}
private setLoading(loading: boolean): void {
this.loadingListeners.forEach(cb => cb(loading))
}
@@ -54,6 +62,10 @@ class ReadingProgressController {
this.progressListeners.forEach(cb => cb(new Map(progressMap)))
}
private emitMarkedAsReadChanged(): void {
this.markedAsReadListeners.forEach(cb => cb())
}
/**
* Get current reading progress map without triggering a reload
*/
@@ -378,6 +390,7 @@ class ReadingProgressController {
}
console.log('[readingProgress] Mark-as-read reactions complete. Total:', Array.from(this.markedAsReadIds).length)
this.emitMarkedAsReadChanged()
} catch (err) {
console.warn('[readingProgress] Failed to load mark-as-read reactions:', err)
}