From cdc3be41c1edbccbec01a5628a9426d7a301f6ca Mon Sep 17 00:00:00 2001 From: Fredrik Burmester Date: Wed, 4 Sep 2024 22:49:43 +0300 Subject: [PATCH] fix: preserve sort order per library/collection fixes #84 --- app/(auth)/(tabs)/(home)/index.tsx | 2 + app/(auth)/(tabs)/(libraries)/[libraryId].tsx | 66 ++++++++++++++++--- utils/atoms/filters.ts | 66 +++++++++++++++++++ 3 files changed, 124 insertions(+), 10 deletions(-) diff --git a/app/(auth)/(tabs)/(home)/index.tsx b/app/(auth)/(tabs)/(home)/index.tsx index e9a47e9f..69733e9b 100644 --- a/app/(auth)/(tabs)/(home)/index.tsx +++ b/app/(auth)/(tabs)/(home)/index.tsx @@ -204,6 +204,7 @@ export default function index() { fields: ["PrimaryImageAspectRatio", "Path"], imageTypeLimit: 1, enableImageTypes: ["Primary", "Backdrop", "Thumb"], + includeItemTypes: ["Movie"], parentId: movieCollectionId, }) ).data || [], @@ -220,6 +221,7 @@ export default function index() { fields: ["PrimaryImageAspectRatio", "Path"], imageTypeLimit: 1, enableImageTypes: ["Primary", "Backdrop", "Thumb"], + includeItemTypes: ["Series"], parentId: tvShowCollectionId, }) ).data || [], diff --git a/app/(auth)/(tabs)/(libraries)/[libraryId].tsx b/app/(auth)/(tabs)/(libraries)/[libraryId].tsx index 77f77978..ca1ec02b 100644 --- a/app/(auth)/(tabs)/(libraries)/[libraryId].tsx +++ b/app/(auth)/(tabs)/(libraries)/[libraryId].tsx @@ -1,8 +1,8 @@ import { useInfiniteQuery, useQuery } from "@tanstack/react-query"; -import { useLocalSearchParams } from "expo-router"; +import { useFocusEffect, useLocalSearchParams } from "expo-router"; import * as ScreenOrientation from "expo-screen-orientation"; import { useAtom } from "jotai"; -import React, { useCallback, useLayoutEffect, useMemo } from "react"; +import React, { useCallback, useEffect, useLayoutEffect, useMemo } from "react"; import { FlatList, useWindowDimensions, View } from "react-native"; import { Text } from "@/components/common/Text"; @@ -15,12 +15,16 @@ import { ItemPoster } from "@/components/posters/ItemPoster"; import { apiAtom, userAtom } from "@/providers/JellyfinProvider"; import { genreFilterAtom, + getSortByPreference, + getSortOrderPreference, sortByAtom, SortByOption, + sortByPreferenceAtom, sortOptions, sortOrderAtom, SortOrderOption, sortOrderOptions, + sortOrderPreferenceAtom, tagsFilterAtom, yearFilterAtom, } from "@/utils/atoms/filters"; @@ -50,10 +54,57 @@ const Page = () => { const [selectedGenres, setSelectedGenres] = useAtom(genreFilterAtom); const [selectedYears, setSelectedYears] = useAtom(yearFilterAtom); const [selectedTags, setSelectedTags] = useAtom(tagsFilterAtom); - const [sortBy, setSortBy] = useAtom(sortByAtom); - const [sortOrder, setSortOrder] = useAtom(sortOrderAtom); + const [sortBy, _setSortBy] = useAtom(sortByAtom); + const [sortOrder, _setSortOrder] = useAtom(sortOrderAtom); + const [orientation] = useAtom(orientationAtom); + const [sortByPreference, setSortByPreference] = useAtom(sortByPreferenceAtom); + const [sortOrderPreference, setOderByPreference] = useAtom( + sortOrderPreferenceAtom + ); - const [orientation, setOrientation] = useAtom(orientationAtom); + useEffect(() => { + const sop = getSortOrderPreference(libraryId, sortOrderPreference); + if (sop) { + console.log("getSortOrderPreference ~", sop, libraryId); + _setSortOrder([sop]); + } else { + _setSortOrder([SortOrderOption.Ascending]); + } + const obp = getSortByPreference(libraryId, sortByPreference); + console.log("getSortByPreference ~", obp, libraryId); + if (obp) { + _setSortBy([obp]); + } else { + _setSortBy([SortByOption.SortName]); + } + }, []); + + const setSortBy = useCallback( + (sortBy: SortByOption[]) => { + const sop = getSortByPreference(libraryId, sortByPreference); + if (sortBy[0] !== sop) { + console.log("setSortByPreference ~", sortBy[0], libraryId); + setSortByPreference({ ...sortByPreference, [libraryId]: sortBy[0] }); + } + _setSortBy(sortBy); + }, + [libraryId, sortByPreference] + ); + + const setSortOrder = useCallback( + (sortOrder: SortOrderOption[]) => { + const sop = getSortOrderPreference(libraryId, sortOrderPreference); + if (sortOrder[0] !== sop) { + console.log("setSortOrderPreference ~", sortOrder[0], libraryId); + setOderByPreference({ + ...sortOrderPreference, + [libraryId]: sortOrder[0], + }); + } + _setSortOrder(sortOrder); + }, + [libraryId, sortOrderPreference] + ); const getNumberOfColumns = useCallback(() => { if (orientation === ScreenOrientation.Orientation.PORTRAIT_UP) return 3; @@ -63,11 +114,6 @@ const Page = () => { return 6; }, [screenWidth, orientation]); - useLayoutEffect(() => { - setSortBy([SortByOption.SortName]); - setSortOrder([SortOrderOption.Ascending]); - }, []); - const { data: library, isLoading: isLibraryLoading } = useQuery({ queryKey: ["library", libraryId], queryFn: async () => { diff --git a/utils/atoms/filters.ts b/utils/atoms/filters.ts index f49b17d4..9d758e26 100644 --- a/utils/atoms/filters.ts +++ b/utils/atoms/filters.ts @@ -1,4 +1,6 @@ +import AsyncStorage from "@react-native-async-storage/async-storage"; import { atom } from "jotai"; +import { atomWithStorage, createJSONStorage } from "jotai/utils"; export enum SortByOption { Default = "Default", @@ -65,3 +67,67 @@ export const sortByAtom = atom([SortByOption.Default]); export const sortOrderAtom = atom([ SortOrderOption.Ascending, ]); + +/** + * Sort preferences with persistence + */ +export interface SortPreference { + [libraryId: string]: SortByOption; +} + +export interface SortOrderPreference { + [libraryId: string]: SortOrderOption; +} + +const defaultSortPreference: SortPreference = {}; +const defaultSortOrderPreference: SortOrderPreference = {}; + +export const sortByPreferenceAtom = atomWithStorage( + "sortByPreference", + defaultSortPreference, + { + getItem: async (key) => { + const value = await AsyncStorage.getItem(key); + return value ? JSON.parse(value) : null; + }, + setItem: async (key, value) => { + await AsyncStorage.setItem(key, JSON.stringify(value)); + }, + removeItem: async (key) => { + await AsyncStorage.removeItem(key); + }, + } +); + +export const sortOrderPreferenceAtom = atomWithStorage( + "sortOrderPreference", + defaultSortOrderPreference, + { + getItem: async (key) => { + const value = await AsyncStorage.getItem(key); + return value ? JSON.parse(value) : null; + }, + setItem: async (key, value) => { + await AsyncStorage.setItem(key, JSON.stringify(value)); + }, + removeItem: async (key) => { + await AsyncStorage.removeItem(key); + }, + } +); + +// Helper functions to get and set sort preferences +export const getSortByPreference = ( + libraryId: string, + preferences: SortPreference +) => { + return preferences?.[libraryId] || null; +}; + +export const getSortOrderPreference = ( + libraryId: string, + preferences: SortOrderPreference +) => { + return preferences?.[libraryId] || null; +}; +