ai-customization #22
@@ -38,6 +38,9 @@ export default function MixedView({ libraryId, initialPath }: Props) {
|
||||
const [recursiveLoaded, setRecursiveLoaded] = useState(false)
|
||||
const [doomScrollActive, setDoomScrollActive] = useState(false)
|
||||
const [doomScrollLoading, setDoomScrollLoading] = useState(false)
|
||||
const [doomScrollEntries, setDoomScrollEntries] = useState<FileEntry[]>([])
|
||||
const [doomScrollEntriesLoading, setDoomScrollEntriesLoading] = useState(false)
|
||||
const [doomScrollEntriesLoaded, setDoomScrollEntriesLoaded] = useState(false)
|
||||
|
||||
const toggleTag = (tagId: string) =>
|
||||
setSelectedTagIds((prev) => {
|
||||
@@ -71,6 +74,14 @@ export default function MixedView({ libraryId, initialPath }: Props) {
|
||||
loadPath(initialPath)
|
||||
}, [loadPath, initialPath])
|
||||
|
||||
// Invalidate doom scroll entry cache when the user navigates to a different directory
|
||||
useEffect(() => {
|
||||
setDoomScrollEntries([])
|
||||
setDoomScrollEntriesLoaded(false)
|
||||
setDoomScrollEntriesLoading(false)
|
||||
setDoomScrollLoading(false)
|
||||
}, [currentPath])
|
||||
|
||||
const fetchAssignments = useCallback(() => {
|
||||
fetch(`/api/tags/library-assignments?libraryId=${encodeURIComponent(libraryId)}`)
|
||||
.then((r) => r.json())
|
||||
@@ -95,6 +106,21 @@ export default function MixedView({ libraryId, initialPath }: Props) {
|
||||
.finally(() => setRecursiveLoading(false))
|
||||
}, [libraryId, recursiveLoaded, recursiveLoading])
|
||||
|
||||
const fetchDoomScrollEntries = useCallback(() => {
|
||||
if (doomScrollEntriesLoaded || doomScrollEntriesLoading) return
|
||||
setDoomScrollEntriesLoading(true)
|
||||
fetch(
|
||||
`/api/browse?libraryId=${encodeURIComponent(libraryId)}&path=${encodeURIComponent(currentPath)}&recursive=true`
|
||||
)
|
||||
.then((r) => r.json())
|
||||
.then((data: DirectoryListing) => {
|
||||
setDoomScrollEntries(data.entries)
|
||||
setDoomScrollEntriesLoaded(true)
|
||||
})
|
||||
.catch(() => {})
|
||||
.finally(() => setDoomScrollEntriesLoading(false))
|
||||
}, [libraryId, currentPath, doomScrollEntriesLoaded, doomScrollEntriesLoading])
|
||||
|
||||
// Fetch the full recursive listing the first time any filter becomes active
|
||||
useEffect(() => {
|
||||
if (!filtersActive) return
|
||||
@@ -182,25 +208,33 @@ export default function MixedView({ libraryId, initialPath }: Props) {
|
||||
fetchRecursive()
|
||||
return
|
||||
}
|
||||
if (recursiveLoaded) {
|
||||
// No filters: scope to current directory
|
||||
if (doomScrollEntriesLoaded) {
|
||||
setDoomScrollActive(true)
|
||||
return
|
||||
}
|
||||
setDoomScrollLoading(true)
|
||||
fetchRecursive()
|
||||
fetchDoomScrollEntries()
|
||||
}
|
||||
|
||||
// Activate doom scroll once the recursive listing finishes loading (when triggered by button)
|
||||
// Activate doom scroll once the appropriate listing finishes loading (when triggered by button)
|
||||
useEffect(() => {
|
||||
if (doomScrollLoading && !recursiveLoading && recursiveLoaded) {
|
||||
if (!doomScrollLoading) return
|
||||
const filtersDone = filtersActive && !recursiveLoading && recursiveLoaded
|
||||
const noFiltersDone = !filtersActive && !doomScrollEntriesLoading && doomScrollEntriesLoaded
|
||||
if (filtersDone || noFiltersDone) {
|
||||
setDoomScrollLoading(false)
|
||||
setDoomScrollActive(true)
|
||||
}
|
||||
}, [doomScrollLoading, recursiveLoading, recursiveLoaded])
|
||||
}, [
|
||||
doomScrollLoading, filtersActive,
|
||||
recursiveLoading, recursiveLoaded,
|
||||
doomScrollEntriesLoading, doomScrollEntriesLoaded,
|
||||
])
|
||||
|
||||
// When filters are active, doom scroll uses filteredEntries (already filtered by search/tags).
|
||||
// When no filters, doom scroll uses the full recursiveEntries.
|
||||
const doomScrollItems: DoomScrollItem[] = (filtersActive ? filteredEntries : recursiveEntries)
|
||||
// When no filters, doom scroll uses files recursively under the current directory.
|
||||
const doomScrollItems: DoomScrollItem[] = (filtersActive ? filteredEntries : doomScrollEntries)
|
||||
.filter((e) => e.type === 'file' && (e.mediaType === 'video' || e.mediaType === 'image') && e.url && isBrowserPlayable(e.name))
|
||||
.map((e) => ({ url: e.url!, name: e.name, mediaType: e.mediaType as 'video' | 'image' }))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user