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