mirror of
https://github.com/streamyfin/streamyfin.git
synced 2026-06-25 15:20:34 +01:00
Genre/year/tag filters lived in global atoms with no per-library memory and no reset on library switch, so a selection in one library (e.g. Anime) bled into another (e.g. Shows). Sort/order/filterBy were already per-library but persisted across app restarts. Move all per-library filter state to in-memory preferences — genres/years/tags get their own, and sort/order/filterBy stop using atomWithStorage: each library remembers its own filters for the session and everything resets when the app is fully closed. The library mount effect restores the active library's selection, the shared useFilterReset clears it, and collections open with a clean slate. Also fix the grid not returning to the top on a filter/sort change or reset: it now pins to the top instantly and re-pins once the filtered fetch settles (FlashList was restoring the previous offset as the new content grew); pagination is left untouched.
109 lines
3.4 KiB
TypeScript
109 lines
3.4 KiB
TypeScript
import { useAtom } from "jotai";
|
|
import { useCallback } from "react";
|
|
import {
|
|
FilterByPreferenceAtom,
|
|
filterByAtom,
|
|
genreFilterAtom,
|
|
genrePreferenceAtom,
|
|
SortByOption,
|
|
SortOrderOption,
|
|
sortByAtom,
|
|
sortByPreferenceAtom,
|
|
sortOrderAtom,
|
|
sortOrderPreferenceAtom,
|
|
tagPreferenceAtom,
|
|
tagsFilterAtom,
|
|
yearFilterAtom,
|
|
yearPreferenceAtom,
|
|
} from "@/utils/atoms/filters";
|
|
|
|
/**
|
|
* Single source of truth for the library filter bar's "reset" action and its
|
|
* visibility. The mobile ResetFiltersButton and the TV filter header both use
|
|
* this so they can't drift — sort/order used to be reset on neither path, so
|
|
* the reset (X) never reflected a changed sort.
|
|
*
|
|
* A reset clears the session filters AND the per-library in-memory preferences
|
|
* (sort, order, filterBy, genres, years, tags); otherwise the saved preference
|
|
* resurfaces when the library's mount effect re-applies it on the next entry.
|
|
*/
|
|
export const useFilterReset = (libraryId: string) => {
|
|
const [selectedGenres, setSelectedGenres] = useAtom(genreFilterAtom);
|
|
const [selectedYears, setSelectedYears] = useAtom(yearFilterAtom);
|
|
const [selectedTags, setSelectedTags] = useAtom(tagsFilterAtom);
|
|
const [filterBy, setFilterBy] = useAtom(filterByAtom);
|
|
const [sortBy, setSortBy] = useAtom(sortByAtom);
|
|
const [sortOrder, setSortOrder] = useAtom(sortOrderAtom);
|
|
const [, setSortByPreference] = useAtom(sortByPreferenceAtom);
|
|
const [, setSortOrderPreference] = useAtom(sortOrderPreferenceAtom);
|
|
const [, setFilterByPreference] = useAtom(FilterByPreferenceAtom);
|
|
const [, setGenrePreference] = useAtom(genrePreferenceAtom);
|
|
const [, setYearPreference] = useAtom(yearPreferenceAtom);
|
|
const [, setTagPreference] = useAtom(tagPreferenceAtom);
|
|
|
|
// SortName / Ascending is the baseline a library opens with (mount-effect
|
|
// fallback), so any other value counts as an active, resettable sort.
|
|
const hasActiveFilters =
|
|
selectedGenres.length > 0 ||
|
|
selectedYears.length > 0 ||
|
|
selectedTags.length > 0 ||
|
|
filterBy.length > 0 ||
|
|
sortBy[0] !== SortByOption.SortName ||
|
|
sortOrder[0] !== SortOrderOption.Ascending;
|
|
|
|
const resetAllFilters = useCallback(() => {
|
|
setSelectedGenres([]);
|
|
setSelectedYears([]);
|
|
setSelectedTags([]);
|
|
setFilterBy([]);
|
|
setSortBy([SortByOption.SortName]);
|
|
setSortOrder([SortOrderOption.Ascending]);
|
|
setSortByPreference((prev) => {
|
|
const next = { ...prev };
|
|
delete next[libraryId];
|
|
return next;
|
|
});
|
|
setSortOrderPreference((prev) => {
|
|
const next = { ...prev };
|
|
delete next[libraryId];
|
|
return next;
|
|
});
|
|
setFilterByPreference((prev) => {
|
|
const next = { ...prev };
|
|
delete next[libraryId];
|
|
return next;
|
|
});
|
|
setGenrePreference((prev) => {
|
|
const next = { ...prev };
|
|
delete next[libraryId];
|
|
return next;
|
|
});
|
|
setYearPreference((prev) => {
|
|
const next = { ...prev };
|
|
delete next[libraryId];
|
|
return next;
|
|
});
|
|
setTagPreference((prev) => {
|
|
const next = { ...prev };
|
|
delete next[libraryId];
|
|
return next;
|
|
});
|
|
}, [
|
|
libraryId,
|
|
setSelectedGenres,
|
|
setSelectedYears,
|
|
setSelectedTags,
|
|
setFilterBy,
|
|
setSortBy,
|
|
setSortOrder,
|
|
setSortByPreference,
|
|
setSortOrderPreference,
|
|
setFilterByPreference,
|
|
setGenrePreference,
|
|
setYearPreference,
|
|
setTagPreference,
|
|
]);
|
|
|
|
return { hasActiveFilters, resetAllFilters };
|
|
};
|