Optionally hide library manga when browsing source (#665)
This commit is contained in:
@@ -811,6 +811,7 @@
|
|||||||
},
|
},
|
||||||
"label": {
|
"label": {
|
||||||
"dark_theme": "Dark theme",
|
"dark_theme": "Dark theme",
|
||||||
|
"hide_library_entries": "Hide entries already in library",
|
||||||
"language_description": "Feel free to translate the project on",
|
"language_description": "Feel free to translate the project on",
|
||||||
"manga_item_width": "Manga item width",
|
"manga_item_width": "Manga item width",
|
||||||
"show_nsfw": "Show NSFW",
|
"show_nsfw": "Show NSFW",
|
||||||
|
|||||||
@@ -38,6 +38,9 @@ export const getDefaultSettings = (): MetadataServerSettings => ({
|
|||||||
includeChapters: true,
|
includeChapters: true,
|
||||||
includeCategories: true,
|
includeCategories: true,
|
||||||
deleteChapters: true,
|
deleteChapters: true,
|
||||||
|
|
||||||
|
// browse
|
||||||
|
hideLibraryEntries: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const convertSettingsToMetadata = (
|
export const convertSettingsToMetadata = (
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ import {
|
|||||||
GetSourceMangasFetchMutationVariables,
|
GetSourceMangasFetchMutationVariables,
|
||||||
} from '@/lib/graphql/generated/graphql.ts';
|
} from '@/lib/graphql/generated/graphql.ts';
|
||||||
import { NavBarContext, useSetDefaultBackTo } from '@/components/context/NavbarContext.tsx';
|
import { NavBarContext, useSetDefaultBackTo } from '@/components/context/NavbarContext.tsx';
|
||||||
|
import { useMetadataServerSettings } from '@/lib/metadata/metadataServerSettings.ts';
|
||||||
|
|
||||||
const ContentTypeMenu = styled('div')(({ theme }) => ({
|
const ContentTypeMenu = styled('div')(({ theme }) => ({
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
@@ -107,12 +108,13 @@ const useSourceManga = (
|
|||||||
searchTerm: string | null | undefined,
|
searchTerm: string | null | undefined,
|
||||||
filters: IPos[],
|
filters: IPos[],
|
||||||
initialPages: number,
|
initialPages: number,
|
||||||
|
hideLibraryEntries: boolean,
|
||||||
): [
|
): [
|
||||||
AbortableApolloUseMutationPaginatedResponse<GetSourceMangasFetchMutation, GetSourceMangasFetchMutationVariables>[0],
|
AbortableApolloUseMutationPaginatedResponse<GetSourceMangasFetchMutation, GetSourceMangasFetchMutationVariables>[0],
|
||||||
AbortableApolloUseMutationPaginatedResponse<
|
AbortableApolloUseMutationPaginatedResponse<
|
||||||
GetSourceMangasFetchMutation,
|
GetSourceMangasFetchMutation,
|
||||||
GetSourceMangasFetchMutationVariables
|
GetSourceMangasFetchMutationVariables
|
||||||
>[1][number],
|
>[1][number] & { filteredOutAllItemsOfFetchedPage: boolean },
|
||||||
] => {
|
] => {
|
||||||
let result: AbortableApolloUseMutationPaginatedResponse<
|
let result: AbortableApolloUseMutationPaginatedResponse<
|
||||||
GetSourceMangasFetchMutation,
|
GetSourceMangasFetchMutation,
|
||||||
@@ -158,17 +160,32 @@ const useSourceManga = (
|
|||||||
const pages = result[1]!;
|
const pages = result[1]!;
|
||||||
const lastLoadedPageIndex = pages.findLastIndex((page) => !!page.data?.fetchSourceManga);
|
const lastLoadedPageIndex = pages.findLastIndex((page) => !!page.data?.fetchSourceManga);
|
||||||
const lastLoadedPage = pages[lastLoadedPageIndex];
|
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) {
|
const isPageLoading = pages.slice(-1)[0].isLoading;
|
||||||
return [result[0] as any, result[1][result[1].length - 1]];
|
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 [
|
return [
|
||||||
@@ -183,9 +200,10 @@ const useSourceManga = (
|
|||||||
pages.length > lastLoadedPageIndex + 1
|
pages.length > lastLoadedPageIndex + 1
|
||||||
? false
|
? false
|
||||||
: lastLoadedPage!.data!.fetchSourceManga.hasNextPage,
|
: lastLoadedPage!.data!.fetchSourceManga.hasNextPage,
|
||||||
mangas: uniqueItems,
|
mangas: items,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
filteredOutAllItemsOfFetchedPage,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
@@ -217,6 +235,10 @@ export function SourceMangas() {
|
|||||||
setIsFirstRender(false);
|
setIsFirstRender(false);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const {
|
||||||
|
settings: { hideLibraryEntries },
|
||||||
|
} = useMetadataServerSettings();
|
||||||
|
|
||||||
const { options } = useLibraryOptionsContext();
|
const { options } = useLibraryOptionsContext();
|
||||||
const [query] = useQueryParam('query', StringParam);
|
const [query] = useQueryParam('query', StringParam);
|
||||||
const [dialogFiltersToApply, setDialogFiltersToApply] = useState<IPos[]>(currentLocationFiltersToApply);
|
const [dialogFiltersToApply, setDialogFiltersToApply] = useState<IPos[]>(currentLocationFiltersToApply);
|
||||||
@@ -224,13 +246,9 @@ export function SourceMangas() {
|
|||||||
const searchTerm = useDebounce(query, 1000);
|
const searchTerm = useDebounce(query, 1000);
|
||||||
const [resetScrollPosition, setResetScrollPosition] = useState(false);
|
const [resetScrollPosition, setResetScrollPosition] = useState(false);
|
||||||
const [contentType, setContentType] = useState(currentLocationContentType);
|
const [contentType, setContentType] = useState(currentLocationContentType);
|
||||||
const [loadPage, { data, isLoading, size: lastPageNum, abortRequest }] = useSourceManga(
|
const [loadPage, { data, isLoading: loading, size: lastPageNum, abortRequest, filteredOutAllItemsOfFetchedPage }] =
|
||||||
sourceId,
|
useSourceManga(sourceId, contentType, searchTerm, filtersToApply, 1, hideLibraryEntries);
|
||||||
contentType,
|
const isLoading = loading || filteredOutAllItemsOfFetchedPage;
|
||||||
searchTerm,
|
|
||||||
filtersToApply,
|
|
||||||
1,
|
|
||||||
);
|
|
||||||
const mangas = data?.fetchSourceManga.mangas ?? [];
|
const mangas = data?.fetchSourceManga.mangas ?? [];
|
||||||
const hasNextPage = data?.fetchSourceManga.hasNextPage ?? false;
|
const hasNextPage = data?.fetchSourceManga.hasNextPage ?? false;
|
||||||
|
|
||||||
@@ -311,6 +329,12 @@ export function SourceMangas() {
|
|||||||
setResetScrollPosition(true);
|
setResetScrollPosition(true);
|
||||||
}, [sourceId, contentType, updateLocationFilters]);
|
}, [sourceId, contentType, updateLocationFilters]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (filteredOutAllItemsOfFetchedPage && hasNextPage && !loading) {
|
||||||
|
loadPage(lastPageNum + 1);
|
||||||
|
}
|
||||||
|
}, [filteredOutAllItemsOfFetchedPage, loading]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!clearCache) {
|
if (!clearCache) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -16,9 +16,13 @@ import { NavBarContext, useSetDefaultBackTo } from '@/components/context/NavbarC
|
|||||||
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
||||||
import { NumberSetting } from '@/components/settings/NumberSetting.tsx';
|
import { NumberSetting } from '@/components/settings/NumberSetting.tsx';
|
||||||
import { MutableListSetting } from '@/components/settings/MutableListSetting.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 { TextSetting } from '@/components/settings/text/TextSetting.tsx';
|
||||||
import { useLocalStorage } from '@/util/useLocalStorage.tsx';
|
import { useLocalStorage } from '@/util/useLocalStorage.tsx';
|
||||||
|
import {
|
||||||
|
createUpdateMetadataServerSettings,
|
||||||
|
useMetadataServerSettings,
|
||||||
|
} from '@/lib/metadata/metadataServerSettings.ts';
|
||||||
|
|
||||||
type ExtensionsSettings = Pick<GqlServerSettings, 'maxSourcesInParallel' | 'localSourcePath' | 'extensionRepos'>;
|
type ExtensionsSettings = Pick<GqlServerSettings, 'maxSourcesInParallel' | 'localSourcePath' | 'extensionRepos'>;
|
||||||
|
|
||||||
@@ -52,8 +56,21 @@ export const BrowseSettings = () => {
|
|||||||
mutateSettings({ variables: { input: { settings: { [setting]: value } } } });
|
mutateSettings({ variables: { input: { settings: { [setting]: value } } } });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const {
|
||||||
|
settings: { hideLibraryEntries },
|
||||||
|
} = useMetadataServerSettings();
|
||||||
|
const updateMetadataServerSettings = createUpdateMetadataServerSettings<keyof MetadataBrowseSettings>();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<List>
|
<List>
|
||||||
|
<ListItem>
|
||||||
|
<ListItemText primary={t('settings.label.hide_library_entries')} />
|
||||||
|
<Switch
|
||||||
|
edge="end"
|
||||||
|
checked={hideLibraryEntries}
|
||||||
|
onChange={() => updateMetadataServerSettings('hideLibraryEntries', !hideLibraryEntries)}
|
||||||
|
/>
|
||||||
|
</ListItem>
|
||||||
<ListItem>
|
<ListItem>
|
||||||
<ListItemText
|
<ListItemText
|
||||||
primary={t('settings.label.show_nsfw')}
|
primary={t('settings.label.show_nsfw')}
|
||||||
|
|||||||
@@ -241,10 +241,15 @@ export type MetadataMigrationSettings = {
|
|||||||
deleteChapters: boolean;
|
deleteChapters: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type MetadataBrowseSettings = {
|
||||||
|
hideLibraryEntries: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
export type MetadataServerSettings = MetadataDownloadSettings &
|
export type MetadataServerSettings = MetadataDownloadSettings &
|
||||||
MetadataLibrarySettings &
|
MetadataLibrarySettings &
|
||||||
MetadataClientSettings &
|
MetadataClientSettings &
|
||||||
MetadataMigrationSettings;
|
MetadataMigrationSettings &
|
||||||
|
MetadataBrowseSettings;
|
||||||
|
|
||||||
export interface ISearchSettings {
|
export interface ISearchSettings {
|
||||||
ignoreFilters: boolean;
|
ignoreFilters: boolean;
|
||||||
|
|||||||
Reference in New Issue
Block a user