Browse Source

bug-fixes

imwald
Silberengel 4 weeks ago
parent
commit
a68dec76e4
  1. 17
      src/PageManager.tsx
  2. 16
      src/components/NoteList/index.tsx
  3. 98
      src/components/Sidebar/SidebarCalendarWeekWidget.tsx
  4. 1
      src/constants.ts
  5. 9
      src/contexts/primary-page-context.tsx
  6. 31
      src/layouts/PrimaryPageLayout/index.tsx
  7. 94
      src/pages/primary/CalendarPrimaryPage.tsx
  8. 12
      src/services/note-stats.service.ts

17
src/PageManager.tsx

@ -15,6 +15,7 @@ import { ImwaldBrandBar } from '@/assets/Logo'
import LiveActivitiesStrip from '@/components/LiveActivitiesStrip' import LiveActivitiesStrip from '@/components/LiveActivitiesStrip'
import NoteDrawer from '@/components/NoteDrawer' import NoteDrawer from '@/components/NoteDrawer'
import client from '@/services/client.service' import client from '@/services/client.service'
import noteStatsService from '@/services/note-stats.service'
import { navigationEventStore } from '@/services/navigation-event-store' import { navigationEventStore } from '@/services/navigation-event-store'
import type { Event } from 'nostr-tools' import type { Event } from 'nostr-tools'
import { Sheet, SheetContent } from '@/components/ui/sheet' import { Sheet, SheetContent } from '@/components/ui/sheet'
@ -2126,19 +2127,31 @@ export function PageManager({ maxStackSize = 5 }: { maxStackSize?: number }) {
setSinglePaneSheetOpen(shouldBeOpen) setSinglePaneSheetOpen(shouldBeOpen)
}, [panelMode, isSmallScreen, secondaryStack.length, drawerOpen]) }, [panelMode, isSmallScreen, secondaryStack.length, drawerOpen])
const primaryFrozen =
secondaryStack.length > 0 && (isSmallScreen || panelMode === 'double')
useEffect(() => {
noteStatsService.setBackgroundStatsPaused(primaryFrozen)
if (primaryFrozen) {
client.interruptBackgroundQueries()
}
}, [primaryFrozen])
const primaryPageContextValue = useMemo( const primaryPageContextValue = useMemo(
(): PrimaryPageContextValue => ({ (): PrimaryPageContextValue => ({
navigate: navigatePrimaryPageStable, navigate: navigatePrimaryPageStable,
current: currentPrimaryPage, current: currentPrimaryPage,
currentPageProps, currentPageProps,
display: isSmallScreen ? secondaryStack.length === 0 : true display: isSmallScreen ? secondaryStack.length === 0 : true,
frozen: primaryFrozen
}), }),
[ [
navigatePrimaryPageStable, navigatePrimaryPageStable,
currentPrimaryPage, currentPrimaryPage,
currentPageProps, currentPageProps,
isSmallScreen, isSmallScreen,
secondaryStack.length secondaryStack.length,
primaryFrozen
] ]
) )

16
src/components/NoteList/index.tsx

@ -1016,6 +1016,7 @@ const NoteList = forwardRef(
const primaryPageCtx = usePrimaryPageOptional() const primaryPageCtx = usePrimaryPageOptional()
const primaryPageCurrent = primaryPageCtx?.current ?? null const primaryPageCurrent = primaryPageCtx?.current ?? null
const primaryPanelFrozen = primaryPageCtx?.frozen ?? false
/** Clears text/author/time/full-search; does not change panel open state. */ /** Clears text/author/time/full-search; does not change panel open state. */
const clearFeedClientSearchCriteria = useCallback(() => { const clearFeedClientSearchCriteria = useCallback(() => {
@ -1907,6 +1908,10 @@ const NoteList = forwardRef(
timelineEstablishedCloserRef.current?.() timelineEstablishedCloserRef.current?.()
timelineEstablishedCloserRef.current = null timelineEstablishedCloserRef.current = null
if (primaryPanelFrozen) {
return () => {}
}
const currentSubRequests = subRequestsRef.current const currentSubRequests = subRequestsRef.current
if (!currentSubRequests.length) { if (!currentSubRequests.length) {
if (oneShotDebugLabel) { if (oneShotDebugLabel) {
@ -3127,11 +3132,17 @@ const NoteList = forwardRef(
mapLiveSubRequestsForTimeline, mapLiveSubRequestsForTimeline,
progressiveWarmupQuery, progressiveWarmupQuery,
hostPrimaryPageName, hostPrimaryPageName,
relayAuthoritativeFeedOnly relayAuthoritativeFeedOnly,
primaryPanelFrozen
]) ])
useEffect(() => { useEffect(() => {
if (oneShotFetch) return if (oneShotFetch) return
if (primaryPanelFrozen) {
followingFeedDeltaCloserRef.current?.()
followingFeedDeltaCloserRef.current = null
return
}
const deltas = followingFeedDeltaSubRequests ?? [] const deltas = followingFeedDeltaSubRequests ?? []
if (deltas.length === 0) { if (deltas.length === 0) {
followingFeedDeltaCloserRef.current?.() followingFeedDeltaCloserRef.current?.()
@ -3388,7 +3399,8 @@ const NoteList = forwardRef(
effectiveShowKinds, effectiveShowKinds,
showKind1OPs, showKind1OPs,
showKind1Replies, showKind1Replies,
showKind1111 showKind1111,
primaryPanelFrozen
]) ])
const oneShotDebugPrevLoadingRef = useRef(false) const oneShotDebugPrevLoadingRef = useRef(false)

98
src/components/Sidebar/SidebarCalendarWeekWidget.tsx

@ -22,7 +22,7 @@ import indexedDb from '@/services/indexed-db.service'
import { CALENDAR_EVENT_KINDS, ExtendedKind } from '@/constants' import { CALENDAR_EVENT_KINDS, ExtendedKind } from '@/constants'
import { CalendarDays, ChevronLeft, ChevronRight } from 'lucide-react' import { CalendarDays, ChevronLeft, ChevronRight } from 'lucide-react'
import { type Event } from 'nostr-tools' import { type Event } from 'nostr-tools'
import { useCallback, useEffect, useMemo, useReducer, useState } from 'react' import { useCallback, useEffect, useMemo, useReducer, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { CalendarEventCoverImage } from '@/components/CalendarEventCoverImage' import { CalendarEventCoverImage } from '@/components/CalendarEventCoverImage'
import { Button } from '@/components/ui/button' import { Button } from '@/components/ui/button'
@ -103,36 +103,50 @@ export default function SidebarCalendarWeekWidget() {
} }
}, [rawEvents, weekOffset]) }, [rawEvents, weekOffset])
const fetchGenRef = useRef(0)
useEffect(() => { useEffect(() => {
const fetchGen = ++fetchGenRef.current
let cancelled = false let cancelled = false
let lateMergeTimer: number | null = null let lateMergeTimer: number | null = null
const { weekStartMs, weekEndExclusiveMs } = getLocalMondayWeekBounds(weekOffset) const stale = () => cancelled || fetchGenRef.current !== fetchGen
const weekBounds = () => getLocalMondayWeekBounds(weekOffset)
const replacePool = (pool: Event[]) => {
if (stale()) return
const { weekStartMs, weekEndExclusiveMs } = weekBounds()
setRawEvents(dedupeCalendarEventsPreferringOccurrenceRange(pool, weekStartMs, weekEndExclusiveMs))
}
const mergeIntoPool = (incoming: Event[]) => {
if (stale()) return
const { weekStartMs, weekEndExclusiveMs } = weekBounds()
setRawEvents((prev) =>
dedupeCalendarEventsPreferringOccurrenceRange([...prev, ...incoming], weekStartMs, weekEndExclusiveMs)
)
}
const { weekStartMs, weekEndExclusiveMs } = weekBounds()
const fromSessionSync = client.getSessionEventsMatchingSearch( const fromSessionSync = client.getSessionEventsMatchingSearch(
'', '',
SESSION_CALENDAR_MERGE_CAP, SESSION_CALENDAR_MERGE_CAP,
[...CALENDAR_EVENT_KINDS] [...CALENDAR_EVENT_KINDS]
) )
const sessionOnly = dedupeCalendarEventsPreferringOccurrenceRange( replacePool(
fromSessionSync, dedupeCalendarEventsPreferringOccurrenceRange(fromSessionSync, weekStartMs, weekEndExclusiveMs)
weekStartMs,
weekEndExclusiveMs
) )
setRawEvents(sessionOnly)
const scheduleLateSessionMerge = (mergeWithIdb: Event[]) => { const scheduleLateSessionMerge = () => {
lateMergeTimer = window.setTimeout(() => { lateMergeTimer = window.setTimeout(() => {
lateMergeTimer = null lateMergeTimer = null
if (cancelled) return if (stale()) return
const { weekStartMs: ws, weekEndExclusiveMs: we } = getLocalMondayWeekBounds(weekOffset)
const later = client.getSessionEventsMatchingSearch( const later = client.getSessionEventsMatchingSearch(
'', '',
SESSION_CALENDAR_MERGE_CAP, SESSION_CALENDAR_MERGE_CAP,
[...CALENDAR_EVENT_KINDS] [...CALENDAR_EVENT_KINDS]
) )
setRawEvents((prev) => mergeIntoPool(later)
dedupeCalendarEventsPreferringOccurrenceRange([...prev, ...later, ...mergeWithIdb], ws, we)
)
}, 2500) }, 2500)
} }
@ -151,25 +165,18 @@ export default function SidebarCalendarWeekWidget() {
) )
.catch((): Event[] => []) .catch((): Event[] => [])
void idbP.then((localBaseline) => { if (stale()) return
if (cancelled) return
const { weekStartMs: ws, weekEndExclusiveMs: we } = getLocalMondayWeekBounds(weekOffset) if (!relayUrls.length) {
const s2 = client.getSessionEventsMatchingSearch( const localBaseline = await idbP
if (stale()) return
const fromSession = client.getSessionEventsMatchingSearch(
'', '',
SESSION_CALENDAR_MERGE_CAP, SESSION_CALENDAR_MERGE_CAP,
[...CALENDAR_EVENT_KINDS] [...CALENDAR_EVENT_KINDS]
) )
setRawEvents( replacePool([...localBaseline, ...fromSession])
dedupeCalendarEventsPreferringOccurrenceRange([...localBaseline, ...s2], ws, we) scheduleLateSessionMerge()
)
})
if (cancelled) return
if (!relayUrls.length) {
void idbP.then((lb) => {
if (!cancelled) scheduleLateSessionMerge(lb)
})
return return
} }
@ -223,40 +230,19 @@ export default function SidebarCalendarWeekWidget() {
.catch(() => ({ batch: [] as Event[], fromFollowing: [] as Event[] })) .catch(() => ({ batch: [] as Event[], fromFollowing: [] as Event[] }))
const [{ batch, fromFollowing }, localBaseline] = await Promise.all([relayMergedP, idbP]) const [{ batch, fromFollowing }, localBaseline] = await Promise.all([relayMergedP, idbP])
if (cancelled) return if (stale()) return
const { weekStartMs: ws, weekEndExclusiveMs: we } = getLocalMondayWeekBounds(weekOffset)
const fromSessionAfterNet = client.getSessionEventsMatchingSearch( const fromSessionAfterNet = client.getSessionEventsMatchingSearch(
'', '',
SESSION_CALENDAR_MERGE_CAP, SESSION_CALENDAR_MERGE_CAP,
[...CALENDAR_EVENT_KINDS] [...CALENDAR_EVENT_KINDS]
) )
if (!cancelled) { replacePool([...localBaseline, ...fromSessionAfterNet, ...batch, ...fromFollowing])
setRawEvents( scheduleLateSessionMerge()
dedupeCalendarEventsPreferringOccurrenceRange(
[...localBaseline, ...fromSessionAfterNet, ...batch, ...fromFollowing],
ws,
we
)
)
}
lateMergeTimer = window.setTimeout(() => {
lateMergeTimer = null
if (cancelled) return
const { weekStartMs: w2, weekEndExclusiveMs: w2e } = getLocalMondayWeekBounds(weekOffset)
const later = client.getSessionEventsMatchingSearch(
'',
SESSION_CALENDAR_MERGE_CAP,
[...CALENDAR_EVENT_KINDS]
)
setRawEvents((prev) =>
dedupeCalendarEventsPreferringOccurrenceRange([...prev, ...later, ...localBaseline], w2, w2e)
)
}, 2500)
} catch { } catch {
if (!cancelled) { if (!stale()) {
try { try {
const { weekStartMs: ws, weekEndExclusiveMs: we } = getLocalMondayWeekBounds(weekOffset) const { weekStartMs: ws, weekEndExclusiveMs: we } = weekBounds()
const [idb, arc] = await Promise.all([ const [idb, arc] = await Promise.all([
indexedDb.getCalendarEventsForOccurrenceWindow(ws, we), indexedDb.getCalendarEventsForOccurrenceWindow(ws, we),
indexedDb.getArchivedCalendarEventsOverlappingWindow(ws, we, 25_000, 400) indexedDb.getArchivedCalendarEventsOverlappingWindow(ws, we, 25_000, 400)
@ -267,9 +253,9 @@ export default function SidebarCalendarWeekWidget() {
SESSION_CALENDAR_MERGE_CAP, SESSION_CALENDAR_MERGE_CAP,
[...CALENDAR_EVENT_KINDS] [...CALENDAR_EVENT_KINDS]
) )
setRawEvents(dedupeCalendarEventsPreferringOccurrenceRange([...salvage, ...fromSession], ws, we)) replacePool([...salvage, ...fromSession])
} catch { } catch {
setRawEvents([]) if (!stale()) setRawEvents([])
} }
} }
} }

1
src/constants.ts

@ -74,7 +74,6 @@ export const DESKTOP_APP_DOWNLOAD_URL_DEFAULT =
export const DEFAULT_FAVORITE_RELAYS = [ export const DEFAULT_FAVORITE_RELAYS = [
'wss://theforest.nostr1.com', 'wss://theforest.nostr1.com',
'wss://nostr.land', 'wss://nostr.land',
'wss://relays.land/spatianostra'
] ]
/** /**

9
src/contexts/primary-page-context.tsx

@ -12,7 +12,16 @@ export type PrimaryPageContextValue = {
current: TPrimaryPageName | null current: TPrimaryPageName | null
/** Props passed to the current primary page (e.g. `{ spell: 'discussions' }` for spells). */ /** Props passed to the current primary page (e.g. `{ spell: 'discussions' }` for spells). */
currentPageProps: object | undefined currentPageProps: object | undefined
/**
* False on small screens while the secondary stack is open (primary feed unmounted).
* True on desktop double-pane so the left column stays visible.
*/
display: boolean display: boolean
/**
* True while a secondary panel is open: pause primary feed timelines / background stats
* and preserve scroll position until the panel closes.
*/
frozen: boolean
} }
export const PrimaryPageContext = createContext<PrimaryPageContextValue | undefined>(undefined) export const PrimaryPageContext = createContext<PrimaryPageContextValue | undefined>(undefined)

31
src/layouts/PrimaryPageLayout/index.tsx

@ -44,7 +44,9 @@ const PrimaryPageLayout = forwardRef(
const smallScreenScrollAreaRef = useRef<HTMLDivElement>(null) const smallScreenScrollAreaRef = useRef<HTMLDivElement>(null)
const smallScreenLastScrollTopRef = useRef(0) const smallScreenLastScrollTopRef = useRef(0)
const { isSmallScreen } = useScreenSize() const { isSmallScreen } = useScreenSize()
const { current, display } = usePrimaryPage() const { current, display, frozen } = usePrimaryPage()
const savedScrollTopRef = useRef(0)
const wasFrozenRef = useRef(false)
useImperativeHandle( useImperativeHandle(
ref, ref,
@ -84,6 +86,28 @@ const PrimaryPageLayout = forwardRef(
} }
}, [current, isSmallScreen, display]) }, [current, isSmallScreen, display])
useEffect(() => {
if (isSmallScreen) return
const el = scrollAreaRef.current
if (!el) return
if (frozen && !wasFrozenRef.current) {
savedScrollTopRef.current = el.scrollTop
wasFrozenRef.current = true
return
}
if (!frozen && wasFrozenRef.current) {
wasFrozenRef.current = false
const top = savedScrollTopRef.current
requestAnimationFrame(() => {
if (scrollAreaRef.current) {
scrollAreaRef.current.scrollTop = top
}
})
}
}, [frozen, isSmallScreen, pageName])
useEffect(() => { useEffect(() => {
if (isSmallScreen) return if (isSmallScreen) return
if (current !== pageName || !display) return if (current !== pageName || !display) return
@ -133,7 +157,10 @@ const PrimaryPageLayout = forwardRef(
} }
return ( return (
<DeepBrowsingProvider active={current === pageName && display} scrollAreaRef={scrollAreaRef}> <DeepBrowsingProvider
active={current === pageName && display && !frozen}
scrollAreaRef={scrollAreaRef}
>
<div className="relative flex h-full min-h-0 min-w-0 flex-col"> <div className="relative flex h-full min-h-0 min-w-0 flex-col">
{hasTitlebarRow ? ( {hasTitlebarRow ? (
<PrimaryPageTitlebar <PrimaryPageTitlebar

94
src/pages/primary/CalendarPrimaryPage.tsx

@ -150,41 +150,52 @@ const CalendarPrimaryPage = forwardRef<TPageRef, CalendarPrimaryPageProps>(funct
return { rangeStartMs: startMs - pad, rangeEndExclusiveMs: endExclusiveMs + pad } return { rangeStartMs: startMs - pad, rangeEndExclusiveMs: endExclusiveMs + pad }
}, [viewYear, viewMonth]) }, [viewYear, viewMonth])
const calendarFetchGenRef = useRef(0)
useEffect(() => { useEffect(() => {
const fetchGen = ++calendarFetchGenRef.current
let cancelled = false let cancelled = false
let lateMergeTimer: number | null = null let lateMergeTimer: number | null = null
const stale = () => cancelled || calendarFetchGenRef.current !== fetchGen
const { rangeStartMs, rangeEndExclusiveMs } = paddedMonthRange const { rangeStartMs, rangeEndExclusiveMs } = paddedMonthRange
const replacePool = (pool: NostrEvent[]) => {
if (stale()) return
setRawEvents(dedupeCalendarEventsPreferringOccurrenceRange(pool, rangeStartMs, rangeEndExclusiveMs))
setLoading(false)
}
const mergeIntoPool = (incoming: NostrEvent[]) => {
if (stale()) return
setRawEvents((prev) =>
dedupeCalendarEventsPreferringOccurrenceRange(
[...prev, ...incoming],
rangeStartMs,
rangeEndExclusiveMs
)
)
}
/** Same-tick paint from in-memory session (no await) — IDB + relays merge in the async block below. */ /** Same-tick paint from in-memory session (no await) — IDB + relays merge in the async block below. */
const fromSessionSync = client.getSessionEventsMatchingSearch( const fromSessionSync = client.getSessionEventsMatchingSearch(
'', '',
SESSION_CALENDAR_MERGE_CAP, SESSION_CALENDAR_MERGE_CAP,
[...CALENDAR_EVENT_KINDS] [...CALENDAR_EVENT_KINDS]
) )
const sessionOnly = dedupeCalendarEventsPreferringOccurrenceRange( replacePool(
fromSessionSync, dedupeCalendarEventsPreferringOccurrenceRange(fromSessionSync, rangeStartMs, rangeEndExclusiveMs)
rangeStartMs,
rangeEndExclusiveMs
) )
setRawEvents(sessionOnly)
setLoading(false)
const scheduleLateSessionMerge = (mergeWithIdb: NostrEvent[]) => { const scheduleLateSessionMerge = () => {
lateMergeTimer = window.setTimeout(() => { lateMergeTimer = window.setTimeout(() => {
lateMergeTimer = null lateMergeTimer = null
if (cancelled) return if (stale()) return
const later = client.getSessionEventsMatchingSearch( const later = client.getSessionEventsMatchingSearch(
'', '',
SESSION_CALENDAR_MERGE_CAP, SESSION_CALENDAR_MERGE_CAP,
[...CALENDAR_EVENT_KINDS] [...CALENDAR_EVENT_KINDS]
) )
setRawEvents((prev) => mergeIntoPool(later)
dedupeCalendarEventsPreferringOccurrenceRange(
[...prev, ...later, ...mergeWithIdb],
rangeStartMs,
rangeEndExclusiveMs
)
)
}, 2500) }, 2500)
} }
@ -212,26 +223,18 @@ const CalendarPrimaryPage = forwardRef<TPageRef, CalendarPrimaryPageProps>(funct
) )
.catch((): NostrEvent[] => []) .catch((): NostrEvent[] => [])
void idbP.then((localBaseline) => { if (stale()) return
if (cancelled) return
const s2 = client.getSessionEventsMatchingSearch( if (!relayUrls.length) {
const localBaseline = await idbP
if (stale()) return
const fromSession = client.getSessionEventsMatchingSearch(
'', '',
SESSION_CALENDAR_MERGE_CAP, SESSION_CALENDAR_MERGE_CAP,
[...CALENDAR_EVENT_KINDS] [...CALENDAR_EVENT_KINDS]
) )
setRawEvents( replacePool([...localBaseline, ...fromSession])
dedupeCalendarEventsPreferringOccurrenceRange( scheduleLateSessionMerge()
[...localBaseline, ...s2],
rangeStartMs,
rangeEndExclusiveMs
)
)
})
if (!relayUrls.length) {
void idbP.then((lb) => {
if (!cancelled) scheduleLateSessionMerge(lb)
})
return return
} }
@ -288,38 +291,17 @@ const CalendarPrimaryPage = forwardRef<TPageRef, CalendarPrimaryPageProps>(funct
.catch(() => ({ batch: [] as NostrEvent[], fromFollowing: [] as NostrEvent[] })) .catch(() => ({ batch: [] as NostrEvent[], fromFollowing: [] as NostrEvent[] }))
const [{ batch, fromFollowing }, localBaseline] = await Promise.all([relayMergedP, idbP]) const [{ batch, fromFollowing }, localBaseline] = await Promise.all([relayMergedP, idbP])
if (cancelled) return if (stale()) return
const fromSession = client.getSessionEventsMatchingSearch( const fromSession = client.getSessionEventsMatchingSearch(
'', '',
SESSION_CALENDAR_MERGE_CAP, SESSION_CALENDAR_MERGE_CAP,
[...CALENDAR_EVENT_KINDS] [...CALENDAR_EVENT_KINDS]
) )
setRawEvents( replacePool([...localBaseline, ...fromSession, ...batch, ...fromFollowing])
dedupeCalendarEventsPreferringOccurrenceRange( scheduleLateSessionMerge()
[...batch, ...fromFollowing, ...fromSession, ...localBaseline],
rangeStartMs,
rangeEndExclusiveMs
)
)
lateMergeTimer = window.setTimeout(() => {
lateMergeTimer = null
if (cancelled) return
const later = client.getSessionEventsMatchingSearch(
'',
SESSION_CALENDAR_MERGE_CAP,
[...CALENDAR_EVENT_KINDS]
)
setRawEvents((prev) =>
dedupeCalendarEventsPreferringOccurrenceRange(
[...prev, ...later, ...localBaseline],
rangeStartMs,
rangeEndExclusiveMs
)
)
}, 2500)
} catch { } catch {
if (!cancelled) { if (!stale()) {
try { try {
const rs = rangeStartMs const rs = rangeStartMs
const re = rangeEndExclusiveMs const re = rangeEndExclusiveMs

12
src/services/note-stats.service.ts

@ -91,6 +91,8 @@ class NoteStatsService {
private batchTimeout: NodeJS.Timeout | null = null private batchTimeout: NodeJS.Timeout | null = null
/** Prevents overlapping processBatch runs (reentrant calls corrupted pendingEvents). */ /** Prevents overlapping processBatch runs (reentrant calls corrupted pendingEvents). */
private processBatchRunning = false private processBatchRunning = false
/** When true (secondary panel open), skip background stats relay batches so the note panel is not starved. */
private backgroundStatsPaused = false
/** While greater than zero, {@link processBatch} defers so user publishes are not starved for WebSocket pool / bandwidth. */ /** While greater than zero, {@link processBatch} defers so user publishes are not starved for WebSocket pool / bandwidth. */
private publishPriorityDepth = 0 private publishPriorityDepth = 0
private readonly BATCH_DELAY = 40 private readonly BATCH_DELAY = 40
@ -153,8 +155,13 @@ class NoteStatsService {
return out return out
} }
setBackgroundStatsPaused(paused: boolean): void {
this.backgroundStatsPaused = paused
}
/** Coalesce scroll bursts; flush immediately when backlog is large or a foreground note was queued. */ /** Coalesce scroll bursts; flush immediately when backlog is large or a foreground note was queued. */
private maybeFlushStatsBatch(foreground: boolean) { private maybeFlushStatsBatch(foreground: boolean) {
if (!foreground && this.backgroundStatsPaused) return
if (this.processBatchRunning) { if (this.processBatchRunning) {
return return
} }
@ -200,6 +207,11 @@ class NoteStatsService {
} }
} }
if (!foreground && this.backgroundStatsPaused) {
rememberRoot()
return
}
if (this.pendingEvents.has(eventId) || this.pendingForeground.has(eventId)) { if (this.pendingEvents.has(eventId) || this.pendingForeground.has(eventId)) {
this.mergeFavoriteRelaysIntoPending(eventId, favoriteRelays) this.mergeFavoriteRelaysIntoPending(eventId, favoriteRelays)
rememberRoot() rememberRoot()

Loading…
Cancel
Save