From b9b963cca82ee57136239864b688826e6e4be922 Mon Sep 17 00:00:00 2001 From: grafixeyehero Date: Thu, 8 Aug 2024 04:25:05 +0300 Subject: [PATCH 1/2] Move reusable TextLines component to common file --- .../components/library/ItemsView.tsx | 2 +- src/components/common/textLines/TextLines.tsx | 46 ++++++++ .../common/textLines/TextWrapper.tsx | 33 ++++++ src/components/common/textLines/types.ts | 18 +++ .../textLines/useTextLines.tsx} | 107 ++++++++---------- src/components/listview/List/ListContent.tsx | 2 +- src/components/listview/List/ListItemBody.tsx | 24 +++- .../listview/List/ListTextWrapper.tsx | 30 ----- src/components/listview/listview.scss | 4 + src/types/listOptions.ts | 14 +-- 10 files changed, 177 insertions(+), 103 deletions(-) create mode 100644 src/components/common/textLines/TextLines.tsx create mode 100644 src/components/common/textLines/TextWrapper.tsx create mode 100644 src/components/common/textLines/types.ts rename src/components/{listview/List/useListTextlines.tsx => common/textLines/useTextLines.tsx} (52%) delete mode 100644 src/components/listview/List/ListTextWrapper.tsx diff --git a/src/apps/experimental/components/library/ItemsView.tsx b/src/apps/experimental/components/library/ItemsView.tsx index e2aa480cc0..282e3df244 100644 --- a/src/apps/experimental/components/library/ItemsView.tsx +++ b/src/apps/experimental/components/library/ItemsView.tsx @@ -92,7 +92,7 @@ const ItemsView: FC = ({ listOptions.showParentTitle = true; listOptions.action = 'playallfromhere'; listOptions.smallIcon = true; - listOptions.artist = true; + listOptions.showArtist = true; listOptions.addToListButton = true; } else if (viewType === LibraryTab.Albums) { listOptions.sortBy = libraryViewSettings.SortBy; diff --git a/src/components/common/textLines/TextLines.tsx b/src/components/common/textLines/TextLines.tsx new file mode 100644 index 0000000000..475aff1cbf --- /dev/null +++ b/src/components/common/textLines/TextLines.tsx @@ -0,0 +1,46 @@ +import React, { type FC } from 'react'; +import Box from '@mui/material/Box'; +import useTextLines from './useTextLines'; +import TextWrapper from './TextWrapper'; + +import type { ItemDto } from 'types/base/models/item-dto'; +import type { TextLine, TextLineOpts } from './types'; + +interface TextLinesProps { + item: ItemDto; + textLineOpts?: TextLineOpts; + isLargeStyle?: boolean; + className?: string; + textClassName?: string; +} + +const TextLines: FC = ({ + item, + textLineOpts, + isLargeStyle, + className, + textClassName +}) => { + const { textLines } = useTextLines({ item, textLineOpts }); + + const renderTextlines = (text: TextLine, index: number) => { + return ( + + {text.title} + + ); + }; + + return ( + + {textLines?.map((text, index) => renderTextlines(text, index))} + + ); +}; + +export default TextLines; diff --git a/src/components/common/textLines/TextWrapper.tsx b/src/components/common/textLines/TextWrapper.tsx new file mode 100644 index 0000000000..fead0bff6b --- /dev/null +++ b/src/components/common/textLines/TextWrapper.tsx @@ -0,0 +1,33 @@ +import React, { type FC, type PropsWithChildren } from 'react'; +import classNames from 'classnames'; +import Typography from '@mui/material/Typography'; +import Box from '@mui/material/Box'; + +interface TextWrapperProps { + index?: number; + isLargeStyle?: boolean; + className?: string; +} + +const TextWrapper: FC> = ({ + index, + isLargeStyle, + className, + children +}) => { + if (index === 0) { + return ( + + {children} + + ); + } else { + return ( + + {children} + + ); + } +}; + +export default TextWrapper; diff --git a/src/components/common/textLines/types.ts b/src/components/common/textLines/types.ts new file mode 100644 index 0000000000..bc6e3e16fb --- /dev/null +++ b/src/components/common/textLines/types.ts @@ -0,0 +1,18 @@ +export interface TextLine { + title?: string; + cssClass?: string; +} + +export interface TextLineOpts { + showProgramDateTime?: boolean; + showProgramTime?: boolean; + showChannel?: boolean; + showTitle?: boolean; + showParentTitle?: boolean; + showIndexNumber?: boolean; + parentTitleWithTitle?: boolean; + showArtist?: boolean; + showCurrentProgram?: boolean; + includeIndexNumber?: boolean; + includeParentInfoInTitle?: boolean; +} diff --git a/src/components/listview/List/useListTextlines.tsx b/src/components/common/textLines/useTextLines.tsx similarity index 52% rename from src/components/listview/List/useListTextlines.tsx rename to src/components/common/textLines/useTextLines.tsx index 490f94634d..9a51e63306 100644 --- a/src/components/listview/List/useListTextlines.tsx +++ b/src/components/common/textLines/useTextLines.tsx @@ -1,27 +1,25 @@ -import { BaseItemKind } from '@jellyfin/sdk/lib/generated-client/models/base-item-kind'; -import React from 'react'; import itemHelper from '../../itemHelper'; import datetime from 'scripts/datetime'; -import ListTextWrapper from './ListTextWrapper'; import type { ItemDto } from 'types/base/models/item-dto'; -import type { ListOptions } from 'types/listOptions'; +import type { TextLine, TextLineOpts } from './types'; +import { ItemKind } from 'types/base/models/item-kind'; function getParentTitle( - showParentTitle: boolean | undefined, item: ItemDto, + showParentTitle: boolean | undefined, parentTitleWithTitle: boolean | undefined, displayName: string | null | undefined ) { - let parentTitle = null; + let parentTitle; if (showParentTitle) { - if (item.Type === BaseItemKind.Episode) { + if (item.Type === ItemKind.Season || item.Type === ItemKind.Episode) { parentTitle = item.SeriesName; } else if (item.IsSeries || (item.EpisodeTitle && item.Name)) { parentTitle = item.Name; } } if (showParentTitle && parentTitleWithTitle) { - if (displayName) { + if (displayName && parentTitle) { parentTitle += ' - '; } parentTitle = (parentTitle ?? '') + displayName; @@ -31,11 +29,13 @@ function getParentTitle( function getNameOrIndexWithName( item: ItemDto, - listOptions: ListOptions, - showIndexNumber: boolean | undefined + showIndexNumber?: boolean, + includeParentInfoInTitle?: boolean, + includeIndexNumber?: boolean ) { let displayName = itemHelper.getDisplayName(item, { - includeParentInfo: listOptions.includeParentInfoInTitle + includeParentInfo: includeParentInfoInTitle, + includeIndexNumber }); if (showIndexNumber && item.IndexNumber != null) { @@ -44,27 +44,31 @@ function getNameOrIndexWithName( return displayName; } -interface UseListTextlinesProps { +interface UseTextLinesProps { item: ItemDto; - listOptions?: ListOptions; - isLargeStyle?: boolean; + textLineOpts?: TextLineOpts; } -function useListTextlines({ item = {}, listOptions = {}, isLargeStyle }: UseListTextlinesProps) { +function useTextLines({ item, textLineOpts = {} }: UseTextLinesProps) { const { + showTitle, showProgramDateTime, showProgramTime, showChannel, showParentTitle, showIndexNumber, parentTitleWithTitle, - artist - } = listOptions; - const textLines: string[] = []; + showArtist, + showCurrentProgram, + includeParentInfoInTitle, + includeIndexNumber + } = textLineOpts; - const addTextLine = (text: string | null) => { - if (text) { - textLines.push(text); + const textLines: TextLine[] = []; + + const addTextLine = (textLine: TextLine) => { + if (textLine) { + textLines.push(textLine); } }; @@ -80,7 +84,7 @@ function useListTextlines({ item = {}, listOptions = {}, isLargeStyle }: UseList minute: '2-digit' } ); - addTextLine(programDateTime); + addTextLine({ title: programDateTime }); } }; @@ -89,50 +93,54 @@ function useListTextlines({ item = {}, listOptions = {}, isLargeStyle }: UseList const programTime = datetime.getDisplayTime( datetime.parseISO8601Date(item.StartDate) ); - addTextLine(programTime); + addTextLine({ title: programTime }); } }; const addChannelName = () => { if (showChannel && item.ChannelName) { - addTextLine(item.ChannelName); + addTextLine({ title: item.ChannelName }); } }; - const displayName = getNameOrIndexWithName(item, listOptions, showIndexNumber); + const displayName = getNameOrIndexWithName(item, showIndexNumber, includeParentInfoInTitle, includeIndexNumber); - const parentTitle = getParentTitle(showParentTitle, item, parentTitleWithTitle, displayName ); + const parentTitle = getParentTitle(item, showParentTitle, parentTitleWithTitle, displayName ); const addParentTitle = () => { - addTextLine(parentTitle ?? ''); + if (parentTitle) { + addTextLine({ title: parentTitle }); + } }; const addDisplayName = () => { - if (displayName && !parentTitleWithTitle) { - addTextLine(displayName); + if (displayName && !parentTitleWithTitle && showTitle !== false) { + addTextLine({ title: displayName }); } }; const addAlbumArtistOrArtists = () => { - if (item.IsFolder && artist !== false) { - if (item.AlbumArtist && item.Type === BaseItemKind.MusicAlbum) { - addTextLine(item.AlbumArtist); + if (item.IsFolder && showArtist !== false) { + if (item.AlbumArtist && item.Type === ItemKind.MusicAlbum) { + addTextLine({ title: item.AlbumArtist }); } - } else if (artist) { + } else if (showArtist) { const artistItems = item.ArtistItems; - if (artistItems && item.Type !== BaseItemKind.MusicAlbum) { + if (artistItems && item.Type !== ItemKind.MusicAlbum) { const artists = artistItems.map((a) => a.Name).join(', '); - addTextLine(artists); + addTextLine({ title: artists }); } } }; const addCurrentProgram = () => { - if (item.Type === BaseItemKind.TvChannel && item.CurrentProgram) { - const currentProgram = itemHelper.getDisplayName( - item.CurrentProgram - ); - addTextLine(currentProgram); + if (item.Type === ItemKind.TvChannel && item.CurrentProgram && showCurrentProgram !== false) { + const currentProgram = itemHelper.getDisplayName(item.CurrentProgram, { + includeParentInfo: includeParentInfoInTitle, + includeIndexNumber + }); + + addTextLine({ title: currentProgram }); } }; @@ -144,24 +152,9 @@ function useListTextlines({ item = {}, listOptions = {}, isLargeStyle }: UseList addAlbumArtistOrArtists(); addCurrentProgram(); - const renderTextlines = (text: string, index: number) => { - return ( - - {text} - - ); - }; - - const listTextLines = textLines?.map((text, index) => renderTextlines(text, index)); - return { - listTextLines + textLines }; } -export default useListTextlines; +export default useTextLines; diff --git a/src/components/listview/List/ListContent.tsx b/src/components/listview/List/ListContent.tsx index 6dba901dbf..6d4d49b83a 100644 --- a/src/components/listview/List/ListContent.tsx +++ b/src/components/listview/List/ListContent.tsx @@ -75,7 +75,7 @@ const ListContent: FC = ({ getMissingIndicator={indicator.getMissingIndicator} /> - {listOptions.mediaInfo !== false && enableSideMediaInfo && ( + {listOptions.showMediaInfo !== false && enableSideMediaInfo && ( = ({ enableSideMediaInfo, getMissingIndicator }) => { - const { listTextLines } = useListTextlines({ item, listOptions, isLargeStyle }); const cssClass = classNames( 'listItemBody', { 'itemAction': !clickEntireItem }, @@ -40,9 +40,25 @@ const ListItemBody: FC = ({ return ( - {listTextLines} + - {listOptions.mediaInfo !== false && !enableSideMediaInfo && ( + {listOptions.showMediaInfo !== false && !enableSideMediaInfo && ( > = ({ - index, - isLargeStyle, - children -}) => { - if (index === 0) { - if (isLargeStyle) { - return ( - - {children} - - ); - } else { - return {children}; - } - } else { - return {children}; - } -}; - -export default ListTextWrapper; diff --git a/src/components/listview/listview.scss b/src/components/listview/listview.scss index ea829154bb..f3fae54f19 100644 --- a/src/components/listview/listview.scss +++ b/src/components/listview/listview.scss @@ -5,6 +5,10 @@ contain: layout style; } +.listItemMediaInfo { + align-items: center; +} + .listItem { background: transparent; border: 0; diff --git a/src/types/listOptions.ts b/src/types/listOptions.ts index e34999e758..fb17cbb7c0 100644 --- a/src/types/listOptions.ts +++ b/src/types/listOptions.ts @@ -1,7 +1,9 @@ import { ItemSortBy } from '@jellyfin/sdk/lib/models/api/item-sort-by'; import type { CollectionType } from '@jellyfin/sdk/lib/generated-client/models/collection-type'; import type { ItemDto } from './base/models/item-dto'; -export interface ListOptions { +import type { TextLineOpts } from 'components/common/textLines/types'; + +export interface ListOptions extends TextLineOpts { items?: ItemDto[] | null; index?: string; showIndex?: boolean; @@ -17,21 +19,13 @@ export interface ListOptions { highlight?: boolean; dragHandle?: boolean; showIndexNumberLeft?: boolean; - mediaInfo?: boolean; + showMediaInfo?: boolean; recordButton?: boolean; image?: boolean; imageSource?: string; defaultCardImageIcon?: string; disableIndicators?: boolean; imagePlayButton?: boolean; - showProgramDateTime?: boolean; - showProgramTime?: boolean; - showChannel?: boolean; - showParentTitle?: boolean; - showIndexNumber?: boolean; - parentTitleWithTitle?: boolean; - artist?: boolean; - includeParentInfoInTitle?: boolean; addToListButton?: boolean; infoButton?: boolean; enableUserDataButtons?: boolean; From d2aa788579960c0b517a9c56ca0f951f77c88e97 Mon Sep 17 00:00:00 2001 From: grafixeyehero Date: Tue, 20 Aug 2024 23:20:23 +0300 Subject: [PATCH 2/2] apply suggestion Co-authored-by: Bill Thornton --- src/components/common/textLines/TextLines.tsx | 36 ++++++++++++++++--- .../common/textLines/TextWrapper.tsx | 33 ----------------- 2 files changed, 32 insertions(+), 37 deletions(-) delete mode 100644 src/components/common/textLines/TextWrapper.tsx diff --git a/src/components/common/textLines/TextLines.tsx b/src/components/common/textLines/TextLines.tsx index 475aff1cbf..245950cc73 100644 --- a/src/components/common/textLines/TextLines.tsx +++ b/src/components/common/textLines/TextLines.tsx @@ -1,11 +1,39 @@ -import React, { type FC } from 'react'; +import React, { type FC, type PropsWithChildren } from 'react'; +import classNames from 'classnames'; +import Typography from '@mui/material/Typography'; import Box from '@mui/material/Box'; import useTextLines from './useTextLines'; -import TextWrapper from './TextWrapper'; import type { ItemDto } from 'types/base/models/item-dto'; import type { TextLine, TextLineOpts } from './types'; +interface TextWrapperProps { + isHeading?: boolean; + isLargeStyle?: boolean; + className?: string; +} + +const TextWrapper: FC> = ({ + isHeading, + isLargeStyle, + className, + children +}) => { + if (isHeading) { + return ( + + {children} + + ); + } else { + return ( + + {children} + + ); + } +}; + interface TextLinesProps { item: ItemDto; textLineOpts?: TextLineOpts; @@ -27,11 +55,11 @@ const TextLines: FC = ({ return ( - {text.title} + {text.title} ); }; diff --git a/src/components/common/textLines/TextWrapper.tsx b/src/components/common/textLines/TextWrapper.tsx deleted file mode 100644 index fead0bff6b..0000000000 --- a/src/components/common/textLines/TextWrapper.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import React, { type FC, type PropsWithChildren } from 'react'; -import classNames from 'classnames'; -import Typography from '@mui/material/Typography'; -import Box from '@mui/material/Box'; - -interface TextWrapperProps { - index?: number; - isLargeStyle?: boolean; - className?: string; -} - -const TextWrapper: FC> = ({ - index, - isLargeStyle, - className, - children -}) => { - if (index === 0) { - return ( - - {children} - - ); - } else { - return ( - - {children} - - ); - } -}; - -export default TextWrapper;