Rename library option variable names

This commit is contained in:
schroda
2024-09-16 11:35:55 +02:00
parent 83ce1caee6
commit df129f723a
5 changed files with 108 additions and 75 deletions

View File

@@ -26,21 +26,21 @@ export const DefaultLibraryOptions: LibraryOptions = {
showDownloadBadge: false, showDownloadBadge: false,
showUnreadBadge: false, showUnreadBadge: false,
gridLayout: GridLayout.Compact, gridLayout: GridLayout.Compact,
SourcegridLayout: GridLayout.Compact, sourceGridLayout: GridLayout.Compact,
showTabSize: false, showTabSize: false,
// sort options // sort options
sortDesc: undefined, sortDesc: undefined,
sorts: undefined, sortBy: undefined,
// filter options // filter options
downloaded: undefined, hasDownloadedChapters: undefined,
bookmarked: undefined, hasBookmarkedChapters: undefined,
unread: undefined, hasUnreadChapters: undefined,
hasDuplicateChapters: undefined, hasDuplicateChapters: undefined,
tracker: {}, hasTrackerBinding: {},
status: {} as LibraryOptions['status'], hasStatus: {} as LibraryOptions['hasStatus'],
}; };
export const LibraryOptionsContext = React.createContext<ContextType>({ export const LibraryOptionsContext = React.createContext<ContextType>({

View File

@@ -30,13 +30,13 @@ const TITLES: { [key in 'filter' | 'sort' | 'display']: TranslationKey } = {
}; };
const SORT_OPTIONS: [LibrarySortMode, TranslationKey][] = [ const SORT_OPTIONS: [LibrarySortMode, TranslationKey][] = [
['sortToRead', 'library.option.sort.label.by_unread_chapters'], ['unreadChapters', 'library.option.sort.label.by_unread_chapters'],
['sortTotalChapters', 'library.option.sort.label.by_total_chapters'], ['totalChapters', 'library.option.sort.label.by_total_chapters'],
['sortAlph', 'library.option.sort.label.alphabetically'], ['alphabetically', 'library.option.sort.label.alphabetically'],
['sortDateAdded', 'library.option.sort.label.by_date_added'], ['dateAdded', 'library.option.sort.label.by_date_added'],
['sortLastRead', 'library.option.sort.label.by_last_read'], ['lastRead', 'library.option.sort.label.by_last_read'],
['sortLatestFetchedChapter', 'library.option.sort.label.by_latest_fetched_chapter'], ['latestFetchedChapter', 'library.option.sort.label.by_latest_fetched_chapter'],
['sortLatestUploadedChapter', 'library.option.sort.label.by_latest_uploaded_chapter'], ['latestUploadedChapter', 'library.option.sort.label.by_latest_uploaded_chapter'],
]; ];
interface IProps { interface IProps {
@@ -67,18 +67,18 @@ export const LibraryOptionsPanel: React.FC<IProps> = ({ open, onClose }) => {
<> <>
<ThreeStateCheckboxInput <ThreeStateCheckboxInput
label={t('global.filter.label.unread')} label={t('global.filter.label.unread')}
checked={options.unread} checked={options.hasUnreadChapters}
onChange={(c) => handleFilterChange('unread', c)} onChange={(c) => handleFilterChange('hasUnreadChapters', c)}
/> />
<ThreeStateCheckboxInput <ThreeStateCheckboxInput
label={t('global.filter.label.downloaded')} label={t('global.filter.label.downloaded')}
checked={options.downloaded} checked={options.hasDownloadedChapters}
onChange={(c) => handleFilterChange('downloaded', c)} onChange={(c) => handleFilterChange('hasDownloadedChapters', c)}
/> />
<ThreeStateCheckboxInput <ThreeStateCheckboxInput
label={t('global.filter.label.bookmarked')} label={t('global.filter.label.bookmarked')}
checked={options.bookmarked} checked={options.hasBookmarkedChapters}
onChange={(c) => handleFilterChange('bookmarked', c)} onChange={(c) => handleFilterChange('hasBookmarkedChapters', c)}
/> />
<ThreeStateCheckboxInput <ThreeStateCheckboxInput
label={t('global.filter.label.duplicate_chapters')} label={t('global.filter.label.duplicate_chapters')}
@@ -89,10 +89,10 @@ export const LibraryOptionsPanel: React.FC<IProps> = ({ open, onClose }) => {
{Object.values(MangaStatus).map((status) => ( {Object.values(MangaStatus).map((status) => (
<ThreeStateCheckboxInput <ThreeStateCheckboxInput
label={t(statusToTranslationKey[status])} label={t(statusToTranslationKey[status])}
checked={options.status[status]} checked={options.hasStatus[status]}
onChange={(checked) => onChange={(checked) =>
handleFilterChange('status', { handleFilterChange('hasStatus', {
...options.status, ...options.hasStatus,
[status]: checked, [status]: checked,
}) })
} }
@@ -103,9 +103,12 @@ export const LibraryOptionsPanel: React.FC<IProps> = ({ open, onClose }) => {
<ThreeStateCheckboxInput <ThreeStateCheckboxInput
key={tracker.id} key={tracker.id}
label={tracker.name} label={tracker.name}
checked={options.tracker[tracker.id]} checked={options.hasTrackerBinding[tracker.id]}
onChange={(checked) => onChange={(checked) =>
handleFilterChange('tracker', { ...options.tracker, [tracker.id]: checked }) handleFilterChange('hasTrackerBinding', {
...options.hasTrackerBinding,
[tracker.id]: checked,
})
} }
/> />
))} ))}
@@ -117,11 +120,11 @@ export const LibraryOptionsPanel: React.FC<IProps> = ({ open, onClose }) => {
<SortRadioInput <SortRadioInput
key={mode} key={mode}
label={t(label)} label={t(label)}
checked={options.sorts === mode} checked={options.sortBy === mode}
sortDescending={options.sortDesc} sortDescending={options.sortDesc}
onClick={() => onClick={() =>
mode !== options.sorts mode !== options.sortBy
? handleFilterChange('sorts', mode) ? handleFilterChange('sortBy', mode)
: handleFilterChange('sortDesc', !options.sortDesc) : handleFilterChange('sortDesc', !options.sortDesc)
} }
/> />

View File

@@ -11,8 +11,8 @@ import IconButton from '@mui/material/IconButton';
import Tooltip from '@mui/material/Tooltip'; import Tooltip from '@mui/material/Tooltip';
import React, { useState } from 'react'; import React, { useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useLibraryOptionsContext } from '@/components/context/LibraryOptionsContext';
import { LibraryOptionsPanel } from '@/components/library/LibraryOptionsPanel'; import { LibraryOptionsPanel } from '@/components/library/LibraryOptionsPanel';
import { useLibraryOptionsContext } from '@/components/context/LibraryOptionsContext.tsx';
export const LibraryToolbarMenu: React.FC = () => { export const LibraryToolbarMenu: React.FC = () => {
const { t } = useTranslation(); const { t } = useTranslation();
@@ -20,9 +20,9 @@ export const LibraryToolbarMenu: React.FC = () => {
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const { options } = useLibraryOptionsContext(); const { options } = useLibraryOptionsContext();
const active = const active =
options.downloaded != null || options.hasDownloadedChapters != null ||
options.unread != null || options.hasUnreadChapters != null ||
Object.values(options.tracker).some((trackerFilterStatus) => trackerFilterStatus != null); Object.values(options.hasTrackerBinding).some((trackerFilterStatus) => trackerFilterStatus != null);
return ( return (
<> <>

View File

@@ -77,7 +77,7 @@ const querySearchManga = (
performSearch([query], [source?.displayName]); performSearch([query], [source?.displayName]);
type TMangaTrackerFilter = { trackRecords: { nodes: Pick<TrackRecordType, 'id' | 'trackerId'>[] } }; type TMangaTrackerFilter = { trackRecords: { nodes: Pick<TrackRecordType, 'id' | 'trackerId'>[] } };
const trackerFilter = (trackFilters: LibraryOptions['tracker'], manga: TMangaTrackerFilter): boolean => const trackerFilter = (trackFilters: LibraryOptions['hasTrackerBinding'], manga: TMangaTrackerFilter): boolean =>
Object.entries(trackFilters) Object.entries(trackFilters)
.map(([trackFilterId, trackFilterState]) => { .map(([trackFilterId, trackFilterState]) => {
const isTrackerBound = manga.trackRecords.nodes.some( const isTrackerBound = manga.trackRecords.nodes.some(
@@ -93,28 +93,40 @@ const trackerFilter = (trackFilters: LibraryOptions['tracker'], manga: TMangaTra
.every(Boolean); .every(Boolean);
type TMangaStatusFilter = Pick<MangaType, 'status'>; type TMangaStatusFilter = Pick<MangaType, 'status'>;
const statusFilter = (statusFilters: LibraryOptions['status'], manga: TMangaStatusFilter): boolean => const statusFilter = (statusFilters: LibraryOptions['hasStatus'], manga: TMangaStatusFilter): boolean =>
Object.entries(statusFilters) Object.entries(statusFilters)
.map(([status, statusFilterState]) => triStateFilterBoolean(statusFilterState, status === manga.status)) .map(([status, statusFilterState]) => triStateFilterBoolean(statusFilterState, status === manga.status))
.every(Boolean); .every(Boolean);
type TMangaFilterOptions = Pick< type TMangaFilterOptions = Pick<
LibraryOptions, LibraryOptions,
'unread' | 'downloaded' | 'bookmarked' | 'hasDuplicateChapters' | 'tracker' | 'status' | 'hasUnreadChapters'
| 'hasDownloadedChapters'
| 'hasBookmarkedChapters'
| 'hasDuplicateChapters'
| 'hasTrackerBinding'
| 'hasStatus'
>; >;
type TMangaFilter = Pick<MangaType, 'downloadCount' | 'unreadCount' | 'bookmarkCount' | 'hasDuplicateChapters'> & type TMangaFilter = Pick<MangaType, 'downloadCount' | 'unreadCount' | 'bookmarkCount' | 'hasDuplicateChapters'> &
TMangaTrackerFilter & TMangaTrackerFilter &
TMangaStatusFilter; TMangaStatusFilter;
const filterManga = ( const filterManga = (
manga: TMangaFilter, manga: TMangaFilter,
{ unread, downloaded, bookmarked, hasDuplicateChapters, tracker, status }: TMangaFilterOptions, {
hasDownloadedChapters,
hasUnreadChapters,
hasBookmarkedChapters,
hasDuplicateChapters,
hasTrackerBinding,
hasStatus,
}: TMangaFilterOptions,
): boolean => ): boolean =>
triStateFilterNumber(downloaded, manga.downloadCount) && triStateFilterNumber(hasDownloadedChapters, manga.downloadCount) &&
triStateFilterNumber(unread, manga.unreadCount) && triStateFilterNumber(hasUnreadChapters, manga.unreadCount) &&
triStateFilterNumber(bookmarked, manga.bookmarkCount) && triStateFilterNumber(hasBookmarkedChapters, manga.bookmarkCount) &&
triStateFilterBoolean(hasDuplicateChapters, manga.hasDuplicateChapters) && triStateFilterBoolean(hasDuplicateChapters, manga.hasDuplicateChapters) &&
trackerFilter(tracker, manga) && trackerFilter(hasTrackerBinding, manga) &&
statusFilter(status, manga); statusFilter(hasStatus, manga);
type TMangasFilter = TMangaQueryFilter & TMangaFilter; type TMangasFilter = TMangaQueryFilter & TMangaFilter;
const filterMangas = <Manga extends TMangasFilter>( const filterMangas = <Manga extends TMangasFilter>(
@@ -150,27 +162,27 @@ const sortManga = <Manga extends TMangaSort>(
const result = [...manga]; const result = [...manga];
switch (sort) { switch (sort) {
case 'sortAlph': case 'alphabetically':
result.sort((a, b) => sortByString(a.title, b.title)); result.sort((a, b) => sortByString(a.title, b.title));
break; break;
case 'sortDateAdded': case 'dateAdded':
result.sort((a, b) => sortByNumber(a.inLibraryAt, b.inLibraryAt)); result.sort((a, b) => sortByNumber(a.inLibraryAt, b.inLibraryAt));
break; break;
case 'sortToRead': case 'unreadChapters':
result.sort((a, b) => sortByNumber(a.unreadCount, b.unreadCount)); result.sort((a, b) => sortByNumber(a.unreadCount, b.unreadCount));
break; break;
case 'sortLastRead': case 'lastRead':
result.sort((a, b) => sortByNumber(a.lastReadChapter?.lastReadAt, b.lastReadChapter?.lastReadAt)); result.sort((a, b) => sortByNumber(a.lastReadChapter?.lastReadAt, b.lastReadChapter?.lastReadAt));
break; break;
case 'sortLatestUploadedChapter': case 'latestUploadedChapter':
result.sort((a, b) => result.sort((a, b) =>
sortByNumber(a.latestUploadedChapter?.uploadDate, b.latestUploadedChapter?.uploadDate), sortByNumber(a.latestUploadedChapter?.uploadDate, b.latestUploadedChapter?.uploadDate),
); );
break; break;
case 'sortLatestFetchedChapter': case 'latestFetchedChapter':
result.sort((a, b) => sortByNumber(a.latestFetchedChapter?.fetchedAt, b.latestFetchedChapter?.fetchedAt)); result.sort((a, b) => sortByNumber(a.latestFetchedChapter?.fetchedAt, b.latestFetchedChapter?.fetchedAt));
break; break;
case 'sortTotalChapters': case 'totalChapters':
result.sort((a, b) => sortByNumber(a.chapters.totalCount, b.chapters.totalCount)); result.sort((a, b) => sortByNumber(a.chapters.totalCount, b.chapters.totalCount));
break; break;
default: default:
@@ -192,30 +204,48 @@ export const useGetVisibleLibraryMangas = <Manga extends MangaIdInfo & TMangasFi
} => { } => {
const [query] = useQueryParam('query', StringParam); const [query] = useQueryParam('query', StringParam);
const { options } = useLibraryOptionsContext(); const { options } = useLibraryOptionsContext();
const { unread, downloaded, bookmarked, tracker, hasDuplicateChapters, status } = options; const {
hasUnreadChapters,
hasDownloadedChapters,
hasBookmarkedChapters,
hasTrackerBinding,
hasDuplicateChapters,
hasStatus,
} = options;
const { settings } = useMetadataServerSettings(); const { settings } = useMetadataServerSettings();
const filteredMangas = useMemo( const filteredMangas = useMemo(
() => () =>
filterMangas(mangas, query, { filterMangas(mangas, query, {
unread, ...options,
downloaded,
bookmarked,
hasDuplicateChapters,
tracker,
status,
ignoreFilters: settings.ignoreFilters, ignoreFilters: settings.ignoreFilters,
}), }),
[mangas, query, unread, downloaded, bookmarked, hasDuplicateChapters, tracker, settings.ignoreFilters], [
mangas,
query,
hasUnreadChapters,
hasDownloadedChapters,
hasBookmarkedChapters,
hasTrackerBinding,
hasDuplicateChapters,
hasStatus,
settings.ignoreFilters,
],
); );
const sortedMangas = useMemo( const sortedMangas = useMemo(
() => sortManga(filteredMangas, options.sorts, options.sortDesc), () => sortManga(filteredMangas, options.sortBy, options.sortDesc),
[filteredMangas, options.sorts, options.sortDesc], [filteredMangas, options.sortBy, options.sortDesc],
); );
const isATrackFilterActive = Object.values(options.tracker).some((trackFilterState) => trackFilterState != null); const isATrackFilterActive = Object.values(options.hasTrackerBinding).some(
(trackFilterState) => trackFilterState != null,
);
const showFilteredOutMessage = const showFilteredOutMessage =
(unread != null || downloaded != null || bookmarked != null || !!query || isATrackFilterActive) && (hasUnreadChapters != null ||
hasDownloadedChapters != null ||
hasBookmarkedChapters != null ||
!!query ||
isATrackFilterActive) &&
filteredMangas.length === 0 && filteredMangas.length === 0 &&
mangas.length > 0; mangas.length > 0;

View File

@@ -252,13 +252,13 @@ export type ChapterOptionsReducerAction =
| { type: 'showChapterNumber' }; | { type: 'showChapterNumber' };
export type LibrarySortMode = export type LibrarySortMode =
| 'sortToRead' | 'unreadChapters'
| 'sortAlph' | 'totalChapters'
| 'sortDateAdded' | 'alphabetically'
| 'sortLastRead' | 'dateAdded'
| 'sortLatestFetchedChapter' | 'lastRead'
| 'sortLatestUploadedChapter' | 'latestFetchedChapter'
| 'sortTotalChapters'; | 'latestUploadedChapter';
enum GridLayout { enum GridLayout {
Compact = 0, Compact = 0,
@@ -272,20 +272,20 @@ export interface LibraryOptions {
showDownloadBadge: boolean; showDownloadBadge: boolean;
showUnreadBadge: boolean; showUnreadBadge: boolean;
gridLayout: GridLayout; gridLayout: GridLayout;
SourcegridLayout: GridLayout; sourceGridLayout: GridLayout;
showTabSize: boolean;
// sort options // sort options
sorts: NullAndUndefined<LibrarySortMode>; sortBy: NullAndUndefined<LibrarySortMode>;
sortDesc: NullAndUndefined<boolean>; sortDesc: NullAndUndefined<boolean>;
// filter options // filter options
downloaded: NullAndUndefined<boolean>; hasDownloadedChapters: NullAndUndefined<boolean>;
bookmarked: NullAndUndefined<boolean>; hasBookmarkedChapters: NullAndUndefined<boolean>;
unread: NullAndUndefined<boolean>; hasUnreadChapters: NullAndUndefined<boolean>;
hasDuplicateChapters: NullAndUndefined<boolean>; hasDuplicateChapters: NullAndUndefined<boolean>;
showTabSize: boolean; hasTrackerBinding: Record<TrackerType['id'], NullAndUndefined<boolean>>;
tracker: Record<TrackerType['id'], NullAndUndefined<boolean>>; hasStatus: Record<MangaStatus, NullAndUndefined<boolean>>;
status: Record<MangaStatus, NullAndUndefined<boolean>>;
} }
export type ServerSettings = GetServerSettingsQuery['settings']; export type ServerSettings = GetServerSettingsQuery['settings'];