mirror of
https://github.com/zoriya/flood.git
synced 2026-06-08 12:42:41 +00:00
client: convert elements in util/ to FC
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
import {FC, memo} from 'react';
|
||||
|
||||
import type {TorrentStatus} from '@shared/constants/torrentStatusMap';
|
||||
|
||||
import {Error, Spinner, Start, Stop} from '@client/ui/icons';
|
||||
|
||||
const STATUS_ICON_MAP: Partial<Record<TorrentStatus, JSX.Element>> = {
|
||||
error: <Error />,
|
||||
checking: <Spinner />,
|
||||
stopped: <Stop />,
|
||||
downloading: <Start />,
|
||||
seeding: <Start />,
|
||||
} as const;
|
||||
|
||||
interface TorrentStatusIconProps {
|
||||
statuses: TorrentStatus[];
|
||||
}
|
||||
|
||||
const TorrentStatusIcon: FC<TorrentStatusIconProps> = ({statuses}: TorrentStatusIconProps) => {
|
||||
let resultIcon = <Stop />;
|
||||
|
||||
Object.keys(STATUS_ICON_MAP).some((key) => {
|
||||
const status = key as TorrentStatus;
|
||||
if (statuses.includes(status)) {
|
||||
const icon = STATUS_ICON_MAP[status];
|
||||
if (icon != null) {
|
||||
resultIcon = icon;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
return resultIcon;
|
||||
};
|
||||
|
||||
export default memo(TorrentStatusIcon);
|
||||
@@ -6,13 +6,13 @@ import {Trans, useLingui} from '@lingui/react';
|
||||
import {Clock, DownloadThick, Ratio, Start, Stop, UploadThick} from '@client/ui/icons';
|
||||
import TorrentActions from '@client/actions/TorrentActions';
|
||||
import torrentStatusClasses from '@client/util/torrentStatusClasses';
|
||||
import torrentStatusIcons from '@client/util/torrentStatusIcons';
|
||||
import TorrentStore from '@client/stores/TorrentStore';
|
||||
import UIStore from '@client/stores/UIStore';
|
||||
|
||||
import Duration from '../../general/Duration';
|
||||
import PriorityMeter from '../../general/PriorityMeter';
|
||||
import ProgressBar from '../../general/ProgressBar';
|
||||
import TorrentStatusIcon from '../../general/TorrentStatusIcon';
|
||||
import Size from '../../general/Size';
|
||||
|
||||
const TorrentHeading: FC = observer(() => {
|
||||
@@ -41,7 +41,6 @@ const TorrentHeading: FC = observer(() => {
|
||||
},
|
||||
'torrent-details__header',
|
||||
);
|
||||
const torrentStatusIcon = torrentStatusIcons(torrent.status);
|
||||
|
||||
return (
|
||||
<div className={torrentClasses}>
|
||||
@@ -118,7 +117,10 @@ const TorrentHeading: FC = observer(() => {
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<ProgressBar percent={Math.ceil(torrent.percentComplete)} icon={torrentStatusIcon} />
|
||||
<ProgressBar
|
||||
percent={Math.ceil(torrent.percentComplete)}
|
||||
icon={<TorrentStatusIcon statuses={torrent.status} />}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1,20 +1,152 @@
|
||||
import classnames from 'classnames';
|
||||
import {FC, ReactNode} from 'react';
|
||||
import {FC, memo} from 'react';
|
||||
import {observer} from 'mobx-react';
|
||||
import {Trans, useLingui} from '@lingui/react';
|
||||
|
||||
import {DetailNotAvailable} from '@client/ui/icons';
|
||||
import {getTorrentListCellContent} from '@client/util/torrentListCellContents';
|
||||
import torrentPropertyIcons from '@client/util/torrentPropertyIcons';
|
||||
import {
|
||||
CalendarCreated,
|
||||
Calendar,
|
||||
CheckmarkThick,
|
||||
Clock,
|
||||
DiskFlat,
|
||||
DetailNotAvailable,
|
||||
DownloadThick,
|
||||
FolderClosedSolid,
|
||||
Hash,
|
||||
Lock,
|
||||
TrackerMessage,
|
||||
Peers,
|
||||
Ratio,
|
||||
Seeds,
|
||||
Radar,
|
||||
UploadThick,
|
||||
} from '@client/ui/icons';
|
||||
import Duration from '@client/components/general/Duration';
|
||||
import Size from '@client/components/general/Size';
|
||||
import TorrentStore from '@client/stores/TorrentStore';
|
||||
|
||||
import type {TorrentListColumn} from '@client/constants/TorrentListColumns';
|
||||
|
||||
import type {TorrentProperties} from '@shared/types/Torrent';
|
||||
|
||||
const ICONS: Partial<Record<TorrentListColumn, JSX.Element>> = {
|
||||
eta: <Clock />,
|
||||
sizeBytes: <DiskFlat />,
|
||||
downRate: <DownloadThick />,
|
||||
directory: <FolderClosedSolid />,
|
||||
hash: <Hash />,
|
||||
dateAdded: <Calendar />,
|
||||
dateCreated: <CalendarCreated />,
|
||||
isPrivate: <Lock />,
|
||||
message: <TrackerMessage />,
|
||||
percentComplete: <DownloadThick />,
|
||||
peers: <Peers />,
|
||||
ratio: <Ratio />,
|
||||
seeds: <Seeds />,
|
||||
trackerURIs: <Radar />,
|
||||
upRate: <UploadThick />,
|
||||
upTotal: <UploadThick />,
|
||||
} as const;
|
||||
|
||||
const BooleanCell: FC<{value: boolean}> = memo(({value}: {value: boolean}) =>
|
||||
value ? <CheckmarkThick className="torrent__detail__icon torrent__detail__icon--checkmark" /> : null,
|
||||
);
|
||||
|
||||
const DateCell: FC<{date: number}> = memo(({date}: {date: number}) => {
|
||||
const {i18n} = useLingui();
|
||||
|
||||
return <span>{i18n.date(new Date(date * 1000))}</span>;
|
||||
});
|
||||
|
||||
const ETACell: FC<{eta: number}> = memo(({eta}: {eta: number}) => (eta ? <Duration value={eta} /> : null));
|
||||
|
||||
const PeerCell: FC<{peersConnected: number; totalPeers: number}> = memo(
|
||||
({peersConnected, totalPeers}: {peersConnected: number; totalPeers: number}) => {
|
||||
const {i18n} = useLingui();
|
||||
|
||||
return (
|
||||
<Trans
|
||||
id="torrent.list.peers"
|
||||
values={{
|
||||
connected: i18n.number(peersConnected),
|
||||
of: (
|
||||
<em className="unit">
|
||||
<Trans id="torrent.list.peers.of" />
|
||||
</em>
|
||||
),
|
||||
total: i18n.number(totalPeers),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
const RatioCell: FC<{ratio: number}> = memo(({ratio}: {ratio: number}) => {
|
||||
const {i18n} = useLingui();
|
||||
|
||||
return <span>{i18n.number(ratio, {maximumFractionDigits: 2})}</span>;
|
||||
});
|
||||
|
||||
const TagsCell: FC<{tags: string[]}> = memo(({tags}: {tags: string[]}) => (
|
||||
<ul className="torrent__tags tag">
|
||||
{tags.map((tag) => (
|
||||
<li className="torrent__tag" key={tag}>
|
||||
{tag}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
));
|
||||
|
||||
const TrackersCell: FC<{trackers: string[]}> = memo(({trackers}: {trackers: string[]}) => (
|
||||
<span>{trackers.join(', ')}</span>
|
||||
));
|
||||
|
||||
interface TorrentListCellContentProps {
|
||||
torrent: TorrentProperties;
|
||||
column: TorrentListColumn;
|
||||
}
|
||||
|
||||
const DefaultTorrentListCellContent: FC<TorrentListCellContentProps> = observer(
|
||||
({torrent, column}: TorrentListCellContentProps) => {
|
||||
switch (column) {
|
||||
case 'dateAdded':
|
||||
return <DateCell date={torrent[column]} />;
|
||||
case 'dateCreated':
|
||||
return <DateCell date={torrent[column]} />;
|
||||
case 'downRate':
|
||||
return <Size value={torrent[column]} isSpeed />;
|
||||
case 'upRate':
|
||||
return <Size value={torrent[column]} isSpeed />;
|
||||
case 'downTotal':
|
||||
return <Size value={torrent[column]} />;
|
||||
case 'upTotal':
|
||||
return <Size value={torrent[column]} />;
|
||||
case 'sizeBytes':
|
||||
return <Size value={torrent[column]} />;
|
||||
case 'ratio':
|
||||
return <RatioCell ratio={torrent[column]} />;
|
||||
case 'isPrivate':
|
||||
return <BooleanCell value={torrent[column]} />;
|
||||
case 'tags':
|
||||
return <TagsCell tags={torrent[column]} />;
|
||||
case 'trackerURIs':
|
||||
return <TrackersCell trackers={torrent[column]} />;
|
||||
case 'eta':
|
||||
return <ETACell eta={torrent[column]} />;
|
||||
case 'seeds':
|
||||
return <PeerCell peersConnected={torrent.seedsConnected} totalPeers={torrent.seedsTotal} />;
|
||||
case 'peers':
|
||||
return <PeerCell peersConnected={torrent.peersConnected} totalPeers={torrent.peersTotal} />;
|
||||
default:
|
||||
return <span>{torrent[column]}</span>;
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
interface TorrentListCellProps {
|
||||
hash: string;
|
||||
column: TorrentListColumn;
|
||||
content?: (torrent: TorrentProperties, column: TorrentListColumn) => ReactNode;
|
||||
content?: FC<TorrentListCellContentProps>;
|
||||
className?: string;
|
||||
classNameOverride?: boolean;
|
||||
width?: number;
|
||||
@@ -22,8 +154,16 @@ interface TorrentListCellProps {
|
||||
}
|
||||
|
||||
const TorrentListCell: FC<TorrentListCellProps> = observer(
|
||||
({hash, content, column, className, classNameOverride, width, showIcon}: TorrentListCellProps) => {
|
||||
const icon = showIcon ? torrentPropertyIcons[column] : null;
|
||||
({
|
||||
hash,
|
||||
content: TorrentListCellContent,
|
||||
column,
|
||||
className,
|
||||
classNameOverride,
|
||||
width,
|
||||
showIcon,
|
||||
}: TorrentListCellProps) => {
|
||||
const icon = showIcon ? ICONS[column] : null;
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -33,7 +173,11 @@ const TorrentListCell: FC<TorrentListCellProps> = observer(
|
||||
role="cell"
|
||||
style={{width: `${width}px`}}>
|
||||
{icon}
|
||||
{content?.(TorrentStore.torrents[hash], column) || <DetailNotAvailable />}
|
||||
{TorrentListCellContent ? (
|
||||
<TorrentListCellContent torrent={TorrentStore.torrents[hash]} column={column} />
|
||||
) : (
|
||||
<DetailNotAvailable />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
@@ -42,7 +186,7 @@ const TorrentListCell: FC<TorrentListCellProps> = observer(
|
||||
TorrentListCell.defaultProps = {
|
||||
className: undefined,
|
||||
classNameOverride: false,
|
||||
content: getTorrentListCellContent,
|
||||
content: DefaultTorrentListCellContent,
|
||||
width: undefined,
|
||||
showIcon: false,
|
||||
};
|
||||
|
||||
@@ -5,7 +5,7 @@ import ProgressBar from '../general/ProgressBar';
|
||||
import SettingStore from '../../stores/SettingStore';
|
||||
import TorrentListCell from './TorrentListCell';
|
||||
import TorrentListColumns from '../../constants/TorrentListColumns';
|
||||
import torrentStatusIcons from '../../util/torrentStatusIcons';
|
||||
import TorrentStatusIcon from '../general/TorrentStatusIcon';
|
||||
|
||||
interface TorrentListRowCondensedProps {
|
||||
className: string;
|
||||
@@ -52,8 +52,11 @@ const TorrentListRowCondensed = observer(
|
||||
key={id}
|
||||
hash={hash}
|
||||
column={id}
|
||||
content={(torrent) => (
|
||||
<ProgressBar percent={Math.ceil(torrent.percentComplete)} icon={torrentStatusIcons(torrent.status)} />
|
||||
content={({torrent}) => (
|
||||
<ProgressBar
|
||||
percent={Math.ceil(torrent.percentComplete)}
|
||||
icon={<TorrentStatusIcon statuses={torrent.status} />}
|
||||
/>
|
||||
)}
|
||||
width={SettingStore.floodSettings.torrentListColumnWidths[id]}
|
||||
/>,
|
||||
|
||||
@@ -4,11 +4,11 @@ import {useLingui} from '@lingui/react';
|
||||
|
||||
import SettingStore from '@client/stores/SettingStore';
|
||||
import TorrentListColumns from '@client/constants/TorrentListColumns';
|
||||
import torrentStatusIcons from '@client/util/torrentStatusIcons';
|
||||
|
||||
import ProgressBar from '../general/ProgressBar';
|
||||
import Size from '../general/Size';
|
||||
import TorrentListCell from './TorrentListCell';
|
||||
import TorrentStatusIcon from '../general/TorrentStatusIcon';
|
||||
|
||||
interface TorrentListRowExpandedProps {
|
||||
className: string;
|
||||
@@ -59,7 +59,7 @@ const TorrentListRowExpanded = observer(
|
||||
key="percentComplete"
|
||||
hash={hash}
|
||||
column="percentComplete"
|
||||
content={(torrent) => (
|
||||
content={({torrent}) => (
|
||||
<span>
|
||||
{i18n.number(torrent.percentComplete, {maximumFractionDigits: 1})}
|
||||
<em className="unit">%</em>
|
||||
@@ -75,8 +75,11 @@ const TorrentListRowExpanded = observer(
|
||||
key="percentBar"
|
||||
hash={hash}
|
||||
column="percentComplete"
|
||||
content={(torrent) => (
|
||||
<ProgressBar percent={Math.ceil(torrent.percentComplete)} icon={torrentStatusIcons(torrent.status)} />
|
||||
content={({torrent}) => (
|
||||
<ProgressBar
|
||||
percent={Math.ceil(torrent.percentComplete)}
|
||||
icon={<TorrentStatusIcon statuses={torrent.status} />}
|
||||
/>
|
||||
)}
|
||||
className="torrent__details__section torrent__details__section--quaternary"
|
||||
classNameOverride
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
import {i18n} from '@lingui/core';
|
||||
import {Trans} from '@lingui/react';
|
||||
|
||||
import type {ReactNode} from 'react';
|
||||
|
||||
import {CheckmarkThick} from '@client/ui/icons';
|
||||
import Duration from '@client/components/general/Duration';
|
||||
import Size from '@client/components/general/Size';
|
||||
|
||||
import type {TorrentListColumn} from '@client/constants/TorrentListColumns';
|
||||
|
||||
import type {TorrentProperties} from '@shared/types/Torrent';
|
||||
|
||||
const booleanTransformer = (value: boolean): ReactNode =>
|
||||
value ? <CheckmarkThick className="torrent__detail__icon torrent__detail__icon--checkmark" /> : null;
|
||||
const dateTransformer = (date: number): ReactNode => i18n.date(new Date(date * 1000));
|
||||
const peersTransformer = (peersConnected: number, totalPeers: number): ReactNode => (
|
||||
<Trans
|
||||
id="torrent.list.peers"
|
||||
values={{
|
||||
connected: i18n.number(peersConnected),
|
||||
of: (
|
||||
<em className="unit">
|
||||
<Trans id="torrent.list.peers.of" />
|
||||
</em>
|
||||
),
|
||||
total: i18n.number(totalPeers),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
const speedTransformer = (value: number): ReactNode => <Size value={value} isSpeed />;
|
||||
const sizeTransformer = (value: number): ReactNode => <Size value={value} />;
|
||||
|
||||
export const torrentListCellTransformers = {
|
||||
dateAdded: dateTransformer,
|
||||
dateCreated: dateTransformer,
|
||||
downRate: speedTransformer,
|
||||
downTotal: sizeTransformer,
|
||||
isPrivate: booleanTransformer,
|
||||
peers: peersTransformer,
|
||||
seeds: peersTransformer,
|
||||
tags: (tags: TorrentProperties['tags']): ReactNode => (
|
||||
<ul className="torrent__tags tag">
|
||||
{tags.map((tag) => (
|
||||
<li className="torrent__tag" key={tag}>
|
||||
{tag}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
),
|
||||
ratio: (ratio: TorrentProperties['ratio']): ReactNode => i18n.number(ratio, {maximumFractionDigits: 2}),
|
||||
sizeBytes: sizeTransformer,
|
||||
trackerURIs: (trackers: TorrentProperties['trackerURIs']): ReactNode => trackers.join(', '),
|
||||
upRate: speedTransformer,
|
||||
upTotal: sizeTransformer,
|
||||
eta: (eta: TorrentProperties['eta']): ReactNode => {
|
||||
if (!eta) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return <Duration value={eta} />;
|
||||
},
|
||||
};
|
||||
|
||||
export const getTorrentListCellContent = (torrent: TorrentProperties, column: TorrentListColumn): ReactNode => {
|
||||
switch (column) {
|
||||
case 'dateAdded':
|
||||
case 'dateCreated':
|
||||
case 'downRate':
|
||||
case 'upRate':
|
||||
case 'downTotal':
|
||||
case 'upTotal':
|
||||
case 'sizeBytes':
|
||||
case 'ratio':
|
||||
return torrentListCellTransformers[column](torrent[column]);
|
||||
case 'isPrivate':
|
||||
return torrentListCellTransformers[column](torrent[column]);
|
||||
case 'tags':
|
||||
case 'trackerURIs':
|
||||
return torrentListCellTransformers[column](torrent[column]);
|
||||
case 'eta':
|
||||
return torrentListCellTransformers[column](torrent[column]);
|
||||
case 'seeds':
|
||||
return torrentListCellTransformers[column](torrent.seedsConnected, torrent.seedsTotal);
|
||||
case 'peers':
|
||||
return torrentListCellTransformers[column](torrent.peersConnected, torrent.peersTotal);
|
||||
default:
|
||||
return torrent[column];
|
||||
}
|
||||
};
|
||||
@@ -1,39 +0,0 @@
|
||||
import {
|
||||
CalendarCreated,
|
||||
Calendar,
|
||||
Clock,
|
||||
DiskFlat,
|
||||
DownloadThick,
|
||||
FolderClosedSolid,
|
||||
Hash,
|
||||
Lock,
|
||||
TrackerMessage,
|
||||
Peers,
|
||||
Ratio,
|
||||
Seeds,
|
||||
Radar,
|
||||
UploadThick,
|
||||
} from '@client/ui/icons';
|
||||
|
||||
import type {TorrentListColumn} from '@client/constants/TorrentListColumns';
|
||||
|
||||
const ICONS: Partial<Record<TorrentListColumn, JSX.Element>> = {
|
||||
eta: <Clock />,
|
||||
sizeBytes: <DiskFlat />,
|
||||
downRate: <DownloadThick />,
|
||||
directory: <FolderClosedSolid />,
|
||||
hash: <Hash />,
|
||||
dateAdded: <Calendar />,
|
||||
dateCreated: <CalendarCreated />,
|
||||
isPrivate: <Lock />,
|
||||
message: <TrackerMessage />,
|
||||
percentComplete: <DownloadThick />,
|
||||
peers: <Peers />,
|
||||
ratio: <Ratio />,
|
||||
seeds: <Seeds />,
|
||||
trackerURIs: <Radar />,
|
||||
upRate: <UploadThick />,
|
||||
upTotal: <UploadThick />,
|
||||
} as const;
|
||||
|
||||
export default ICONS;
|
||||
@@ -1,27 +0,0 @@
|
||||
import type {ReactNode} from 'react';
|
||||
|
||||
import type {TorrentStatus} from '@shared/constants/torrentStatusMap';
|
||||
|
||||
import {Error, Spinner, Start, Stop} from '@client/ui/icons';
|
||||
|
||||
const STATUS_ICON_MAP: Partial<Record<TorrentStatus, ReactNode>> = {
|
||||
error: <Error />,
|
||||
checking: <Spinner />,
|
||||
stopped: <Stop />,
|
||||
downloading: <Start />,
|
||||
seeding: <Start />,
|
||||
} as const;
|
||||
|
||||
function torrentStatusIcons(statuses: Array<TorrentStatus>): ReactNode {
|
||||
let resultIcon: ReactNode = <Stop />;
|
||||
Object.entries(STATUS_ICON_MAP).some(([status, icon]) => {
|
||||
if (statuses.includes(status as TorrentStatus) && icon != null) {
|
||||
resultIcon = icon;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
return resultIcon;
|
||||
}
|
||||
|
||||
export default torrentStatusIcons;
|
||||
Reference in New Issue
Block a user