From 08dcd932dc78a7b68a2dbeaeeda06b13ead986ba Mon Sep 17 00:00:00 2001 From: themaskedshell Date: Mon, 20 Jul 2026 19:01:28 -0400 Subject: [PATCH] Added random sorting option for library (#1129) * Update useGetVisibleLibraryMangas.ts Begin implementation of random sort * Update LibraryOptionsPanel.tsx Added random sort option * Update Library.types.ts Adding random to LibrarySortMode types * Moved sorting process to before filter Changed the order of the sorting/filter process. Now sorts through entries before filtering them. * Implementing Reviewer Feedback: Replacing Random Icon Replaced icon with Replay icon from mui. * Update SortRadioInput.tsx Replaced random icon with replay icon from mui to replicate mihon functionality * Fixed Formatting * Update CHANGELOG.md Added proposed changes from pull request. * Update CHANGELOG.md Co-authored-by: schroda <50052685+schroda@users.noreply.github.com> --------- Co-authored-by: jburkh10 Co-authored-by: schroda <50052685+schroda@users.noreply.github.com> --- CHANGELOG.md | 1 + src/base/components/inputs/SortRadioInput.tsx | 5 +++ src/features/library/Library.types.ts | 3 +- .../components/LibraryOptionsPanel.tsx | 43 +++++++++++++------ .../hooks/useGetVisibleLibraryMangas.ts | 19 +++++--- src/i18n/locales/en.po | 4 ++ 6 files changed, 53 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f9363671..637648b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). - (**Reader**) Add setting to keep the screen on while reading - (**Extension**) Support installing external JARs - (**Reader**) Add auto background color setting +- (**Library**) Add random sort option to library ### Changed diff --git a/src/base/components/inputs/SortRadioInput.tsx b/src/base/components/inputs/SortRadioInput.tsx index b61ce61b..aab02e4e 100644 --- a/src/base/components/inputs/SortRadioInput.tsx +++ b/src/base/components/inputs/SortRadioInput.tsx @@ -8,6 +8,7 @@ import ArrowDownward from '@mui/icons-material/ArrowDownward'; import ArrowUpward from '@mui/icons-material/ArrowUpward'; +import Replay from '@mui/icons-material/Replay'; import { memo } from 'react'; import type { RadioInputProps } from '@/base/components/inputs/RadioInput.tsx'; import { RadioInput } from '@/base/components/inputs/RadioInput.tsx'; @@ -22,3 +23,7 @@ export const SortRadioInput = memo(({ sortDescending, ...rest }: IProps) => ( {...rest} /> )); + +export const SortRadioInputRandom = memo(({ sortDescending, ...rest }: IProps) => ( + } {...rest} /> +)); diff --git a/src/features/library/Library.types.ts b/src/features/library/Library.types.ts index 760b871d..e1935a3d 100644 --- a/src/features/library/Library.types.ts +++ b/src/features/library/Library.types.ts @@ -28,7 +28,8 @@ export type LibrarySortMode = | 'dateAdded' | 'lastRead' | 'latestFetchedChapter' - | 'latestUploadedChapter'; + | 'latestUploadedChapter' + | 'random'; export interface LibraryOptions { // sort options diff --git a/src/features/library/components/LibraryOptionsPanel.tsx b/src/features/library/components/LibraryOptionsPanel.tsx index 2480d90c..95c3f803 100644 --- a/src/features/library/components/LibraryOptionsPanel.tsx +++ b/src/features/library/components/LibraryOptionsPanel.tsx @@ -15,7 +15,7 @@ import { useMemo } from 'react'; import uniqBy from 'lodash/fp/uniqBy'; import { CheckboxInput } from '@/base/components/inputs/CheckboxInput.tsx'; import { RadioInput } from '@/base/components/inputs/RadioInput.tsx'; -import { SortRadioInput } from '@/base/components/inputs/SortRadioInput.tsx'; +import { SortRadioInput, SortRadioInputRandom } from '@/base/components/inputs/SortRadioInput.tsx'; import { ThreeStateCheckboxInput } from '@/base/components/inputs/ThreeStateCheckboxInput.tsx'; import { OptionsTabs } from '@/base/components/modals/OptionsTabs.tsx'; import { requestManager } from '@/lib/requests/RequestManager.ts'; @@ -51,6 +51,7 @@ const SORT_OPTIONS: [LibrarySortMode, MessageDescriptor][] = [ ['lastRead', msg`Recently read`], ['latestFetchedChapter', msg`Latest fetched chapter`], ['latestUploadedChapter', msg`Latest uploaded chapter`], + ['random', msg`Random`], ]; export const LibraryOptionsPanel = ({ @@ -174,19 +175,33 @@ export const LibraryOptionsPanel = ({ ); } if (key === 'sort') { - return SORT_OPTIONS.map(([mode, label]) => ( - - mode !== categoryLibraryOptions.sortBy - ? updateCategoryLibraryOptions('sortBy', mode) - : updateCategoryLibraryOptions('sortDesc', !categoryLibraryOptions.sortDesc) - } - /> - )); + return SORT_OPTIONS.map(([mode, label]) => + mode === 'random' ? ( + + mode !== categoryLibraryOptions.sortBy + ? updateCategoryLibraryOptions('sortBy', mode) + : updateCategoryLibraryOptions('sortDesc', !categoryLibraryOptions.sortDesc) + } + /> + ) : ( + + mode !== categoryLibraryOptions.sortBy + ? updateCategoryLibraryOptions('sortBy', mode) + : updateCategoryLibraryOptions('sortDesc', !categoryLibraryOptions.sortDesc) + } + /> + ), + ); } if (key === 'display') { return ( diff --git a/src/features/library/hooks/useGetVisibleLibraryMangas.ts b/src/features/library/hooks/useGetVisibleLibraryMangas.ts index be791265..1c77d007 100644 --- a/src/features/library/hooks/useGetVisibleLibraryMangas.ts +++ b/src/features/library/hooks/useGetVisibleLibraryMangas.ts @@ -182,6 +182,8 @@ const sortByNumber = (a: number | string = 0, b: number | string = 0) => Number( const sortByString = (a: string, b: string): number => a.localeCompare(b, undefined, { sensitivity: 'base' }); +const sortByRandom = () => Math.floor(Math.random() * 3 - 1); + type TMangaSort = MangaTitleInfo & MangaInLibraryInfo & MangaUnreadInfo & @@ -213,6 +215,8 @@ const sortManga = ( return (a, b) => sortByNumber(a.latestFetchedChapter?.fetchedAt, b.latestFetchedChapter?.fetchedAt); case 'totalChapters': return (a, b) => sortByNumber(a.chapters.totalCount, b.chapters.totalCount); + case 'random': + return () => sortByRandom(); default: return () => 0; } @@ -256,14 +260,19 @@ export const useGetVisibleLibraryMangas = sortManga(mangas, options.sortBy, options.sortDesc), + [mangas, options.sortBy, options.sortDesc], + ); + const filteredMangas = useMemo( () => - filterMangas(mangas, query, { + filterMangas(sortedMangas, query, { ...options, ignoreFilters: settings.ignoreFilters, }), [ - mangas, + sortedMangas, query, hasUnreadChapters, hasReadChapters, @@ -276,10 +285,6 @@ export const useGetVisibleLibraryMangas = sortManga(filteredMangas, options.sortBy, options.sortDesc), - [filteredMangas, options.sortBy, options.sortDesc], - ); const isATrackFilterActive = Object.values(options.hasTrackerBinding).some( (trackFilterState) => trackFilterState != null, @@ -299,7 +304,7 @@ export const useGetVisibleLibraryMangas = 0; return { - visibleMangas: sortedMangas, + visibleMangas: filteredMangas, showFilteredOutMessage, filterKey: `${JSON.stringify(options)}${settings.ignoreFilters}`, }; diff --git a/src/i18n/locales/en.po b/src/i18n/locales/en.po index 600708f1..eb99592b 100644 --- a/src/i18n/locales/en.po +++ b/src/i18n/locales/en.po @@ -2942,6 +2942,10 @@ msgstr "Queued" msgid "Quick settings" msgstr "Quick settings" +#: src/features/library/components/LibraryOptionsPanel.tsx +msgid "Random" +msgstr "Random" + #: src/features/reader/settings/screens/GlobalReaderSettings.tsx #: src/features/settings/screens/Settings.tsx msgid "Reader"