diff --git a/src/i18n/locale/en.json b/src/i18n/locale/en.json index 1781c108..21e08a8a 100644 --- a/src/i18n/locale/en.json +++ b/src/i18n/locale/en.json @@ -811,6 +811,7 @@ }, "label": { "dark_theme": "Dark theme", + "hide_library_entries": "Hide entries already in library", "language_description": "Feel free to translate the project on", "manga_item_width": "Manga item width", "show_nsfw": "Show NSFW", diff --git a/src/lib/metadata/metadataServerSettings.ts b/src/lib/metadata/metadataServerSettings.ts index 397f184c..1aa0c18e 100644 --- a/src/lib/metadata/metadataServerSettings.ts +++ b/src/lib/metadata/metadataServerSettings.ts @@ -38,6 +38,9 @@ export const getDefaultSettings = (): MetadataServerSettings => ({ includeChapters: true, includeCategories: true, deleteChapters: true, + + // browse + hideLibraryEntries: false, }); export const convertSettingsToMetadata = ( diff --git a/src/screens/SourceMangas.tsx b/src/screens/SourceMangas.tsx index 98814899..a7b6e891 100644 --- a/src/screens/SourceMangas.tsx +++ b/src/screens/SourceMangas.tsx @@ -34,6 +34,7 @@ import { GetSourceMangasFetchMutationVariables, } from '@/lib/graphql/generated/graphql.ts'; import { NavBarContext, useSetDefaultBackTo } from '@/components/context/NavbarContext.tsx'; +import { useMetadataServerSettings } from '@/lib/metadata/metadataServerSettings.ts'; const ContentTypeMenu = styled('div')(({ theme }) => ({ display: 'flex', @@ -107,12 +108,13 @@ const useSourceManga = ( searchTerm: string | null | undefined, filters: IPos[], initialPages: number, + hideLibraryEntries: boolean, ): [ AbortableApolloUseMutationPaginatedResponse[0], AbortableApolloUseMutationPaginatedResponse< GetSourceMangasFetchMutation, GetSourceMangasFetchMutationVariables - >[1][number], + >[1][number] & { filteredOutAllItemsOfFetchedPage: boolean }, ] => { let result: AbortableApolloUseMutationPaginatedResponse< GetSourceMangasFetchMutation, @@ -158,17 +160,32 @@ const useSourceManga = ( const pages = result[1]!; const lastLoadedPageIndex = pages.findLastIndex((page) => !!page.data?.fetchSourceManga); const lastLoadedPage = pages[lastLoadedPageIndex]; - const items = useMemo( - () => - (pages ?? []) - .map((page) => page.data?.fetchSourceManga.mangas ?? []) - .reduce((prevList, list) => [...prevList, ...list], []), - [pages], - ); - const uniqueItems = useMemo(() => getUniqueMangas(items), [items]); - if (!uniqueItems.length) { - return [result[0] as any, result[1][result[1].length - 1]]; + const isPageLoading = pages.slice(-1)[0].isLoading; + let filteredOutAllItemsOfFetchedPage = !isPageLoading; + const items = useMemo(() => { + type FetchItemsResult = GetSourceMangasFetchMutation['fetchSourceManga']['mangas']; + let allItems: FetchItemsResult = []; + + pages.forEach((page, index) => { + const pageItems = page.data?.fetchSourceManga.mangas ?? ([] as FetchItemsResult); + const uniqueItems = getUniqueMangas([...allItems, ...pageItems]); + const uniquePageItems = pageItems.filter( + (pageItem) => !!uniqueItems.find((uniqueItem) => uniqueItem.id === pageItem.id), + ); + const nonLibraryItems = uniquePageItems.filter((item) => !hideLibraryEntries || !item.inLibrary); + // const nonLibraryItems = uniquePageItems; + + const isLastPage = !isPageLoading && pages.length === index + 1; + filteredOutAllItemsOfFetchedPage = isLastPage && !nonLibraryItems.length && !!pageItems.length; + allItems = [...allItems, ...nonLibraryItems]; + }); + + return allItems; + }, [pages, hideLibraryEntries]); + + if (lastLoadedPageIndex === -1) { + return [result[0], { ...result[1][result[1].length - 1], filteredOutAllItemsOfFetchedPage }]; } return [ @@ -183,9 +200,10 @@ const useSourceManga = ( pages.length > lastLoadedPageIndex + 1 ? false : lastLoadedPage!.data!.fetchSourceManga.hasNextPage, - mangas: uniqueItems, + mangas: items, }, }, + filteredOutAllItemsOfFetchedPage, }, ]; }; @@ -217,6 +235,10 @@ export function SourceMangas() { setIsFirstRender(false); }, []); + const { + settings: { hideLibraryEntries }, + } = useMetadataServerSettings(); + const { options } = useLibraryOptionsContext(); const [query] = useQueryParam('query', StringParam); const [dialogFiltersToApply, setDialogFiltersToApply] = useState(currentLocationFiltersToApply); @@ -224,13 +246,9 @@ export function SourceMangas() { const searchTerm = useDebounce(query, 1000); const [resetScrollPosition, setResetScrollPosition] = useState(false); const [contentType, setContentType] = useState(currentLocationContentType); - const [loadPage, { data, isLoading, size: lastPageNum, abortRequest }] = useSourceManga( - sourceId, - contentType, - searchTerm, - filtersToApply, - 1, - ); + const [loadPage, { data, isLoading: loading, size: lastPageNum, abortRequest, filteredOutAllItemsOfFetchedPage }] = + useSourceManga(sourceId, contentType, searchTerm, filtersToApply, 1, hideLibraryEntries); + const isLoading = loading || filteredOutAllItemsOfFetchedPage; const mangas = data?.fetchSourceManga.mangas ?? []; const hasNextPage = data?.fetchSourceManga.hasNextPage ?? false; @@ -311,6 +329,12 @@ export function SourceMangas() { setResetScrollPosition(true); }, [sourceId, contentType, updateLocationFilters]); + useEffect(() => { + if (filteredOutAllItemsOfFetchedPage && hasNextPage && !loading) { + loadPage(lastPageNum + 1); + } + }, [filteredOutAllItemsOfFetchedPage, loading]); + useEffect(() => { if (!clearCache) { return; diff --git a/src/screens/settings/BrowseSettings.tsx b/src/screens/settings/BrowseSettings.tsx index 879b1068..bcbbb7da 100644 --- a/src/screens/settings/BrowseSettings.tsx +++ b/src/screens/settings/BrowseSettings.tsx @@ -16,9 +16,13 @@ import { NavBarContext, useSetDefaultBackTo } from '@/components/context/NavbarC import { requestManager } from '@/lib/requests/RequestManager.ts'; import { NumberSetting } from '@/components/settings/NumberSetting.tsx'; import { MutableListSetting } from '@/components/settings/MutableListSetting.tsx'; -import { ServerSettings as GqlServerSettings } from '@/typings.ts'; +import { MetadataBrowseSettings, ServerSettings as GqlServerSettings } from '@/typings.ts'; import { TextSetting } from '@/components/settings/text/TextSetting.tsx'; import { useLocalStorage } from '@/util/useLocalStorage.tsx'; +import { + createUpdateMetadataServerSettings, + useMetadataServerSettings, +} from '@/lib/metadata/metadataServerSettings.ts'; type ExtensionsSettings = Pick; @@ -52,8 +56,21 @@ export const BrowseSettings = () => { mutateSettings({ variables: { input: { settings: { [setting]: value } } } }); }; + const { + settings: { hideLibraryEntries }, + } = useMetadataServerSettings(); + const updateMetadataServerSettings = createUpdateMetadataServerSettings(); + return ( + + + updateMetadataServerSettings('hideLibraryEntries', !hideLibraryEntries)} + /> +