mirror of
https://github.com/zoriya/flood.git
synced 2026-06-01 10:35:59 +00:00
client: fix and improve memoization of "ProgressBar"
This commit is contained in:
@@ -1,13 +1,18 @@
|
||||
import {FC, memo, ReactNode} from 'react';
|
||||
import {FC} from 'react';
|
||||
import {observer} from 'mobx-react';
|
||||
|
||||
import type {TorrentStatus} from '@shared/constants/torrentStatusMap';
|
||||
|
||||
import TorrentStatusIcon from './TorrentStatusIcon';
|
||||
|
||||
interface ProgressBarProps {
|
||||
percent: number;
|
||||
icon?: ReactNode;
|
||||
status?: TorrentStatus;
|
||||
}
|
||||
|
||||
const ProgressBar: FC<ProgressBarProps> = memo(({percent, icon}: ProgressBarProps) => (
|
||||
const ProgressBar: FC<ProgressBarProps> = observer(({percent, status}: ProgressBarProps) => (
|
||||
<div className="progress-bar">
|
||||
<div className="progress-bar__icon">{icon}</div>
|
||||
<div className="progress-bar__icon">{status && <TorrentStatusIcon status={status} />}</div>
|
||||
<div className="progress-bar__fill__wrapper">
|
||||
<div className="progress-bar__fill" style={{width: `${percent}%`}} />
|
||||
</div>
|
||||
@@ -15,7 +20,7 @@ const ProgressBar: FC<ProgressBarProps> = memo(({percent, icon}: ProgressBarProp
|
||||
));
|
||||
|
||||
ProgressBar.defaultProps = {
|
||||
icon: undefined,
|
||||
status: undefined,
|
||||
};
|
||||
|
||||
export default ProgressBar;
|
||||
|
||||
@@ -4,34 +4,23 @@ import {Error, Spinner, Start, Stop} from '@client/ui/icons';
|
||||
|
||||
import type {TorrentStatus} from '@shared/constants/torrentStatusMap';
|
||||
|
||||
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[];
|
||||
status: TorrentStatus;
|
||||
}
|
||||
|
||||
const TorrentStatusIcon: FC<TorrentStatusIconProps> = ({statuses}: TorrentStatusIconProps) => {
|
||||
let resultIcon = <Stop />;
|
||||
const TorrentStatusIcon: FC<TorrentStatusIconProps> = memo(({status}: TorrentStatusIconProps) => {
|
||||
switch (status) {
|
||||
case 'error':
|
||||
return <Error />;
|
||||
case 'checking':
|
||||
return <Spinner />;
|
||||
case 'downloading':
|
||||
return <Start />;
|
||||
case 'seeding':
|
||||
return <Start />;
|
||||
default:
|
||||
return <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);
|
||||
export default TorrentStatusIcon;
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
import classnames from 'classnames';
|
||||
import {computed} from 'mobx';
|
||||
import {FC, useEffect, useState} from 'react';
|
||||
import {observer} from 'mobx-react';
|
||||
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 {torrentStatusClasses, torrentStatusEffective} from '@client/util/torrentStatus';
|
||||
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(() => {
|
||||
@@ -118,8 +118,8 @@ const TorrentHeading: FC = observer(() => {
|
||||
</ul>
|
||||
</div>
|
||||
<ProgressBar
|
||||
percent={Math.ceil(torrent.percentComplete)}
|
||||
icon={<TorrentStatusIcon statuses={torrent.status} />}
|
||||
percent={computed(() => Math.ceil(torrent.percentComplete)).get()}
|
||||
status={computed(() => torrentStatusEffective(torrent.status)).get()}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import classnames from 'classnames';
|
||||
import {computed} from 'mobx';
|
||||
import {FC} from 'react';
|
||||
import {observer} from 'mobx-react';
|
||||
import {Trans, useLingui} from '@lingui/react';
|
||||
@@ -22,7 +23,9 @@ import {
|
||||
UploadThick,
|
||||
} from '@client/ui/icons';
|
||||
import Duration from '@client/components/general/Duration';
|
||||
import ProgressBar from '@client/components/general/ProgressBar';
|
||||
import Size from '@client/components/general/Size';
|
||||
import {torrentStatusEffective} from '@client/util/torrentStatus';
|
||||
import TorrentStore from '@client/stores/TorrentStore';
|
||||
|
||||
import type {TorrentListColumn} from '@client/constants/TorrentListColumns';
|
||||
@@ -101,7 +104,7 @@ const TrackersCell: FC<{trackers: string[]}> = observer(({trackers}: {trackers:
|
||||
<span>{trackers.join(', ')}</span>
|
||||
));
|
||||
|
||||
interface TorrentListCellContentProps {
|
||||
export interface TorrentListCellContentProps {
|
||||
torrent: TorrentProperties;
|
||||
column: TorrentListColumn;
|
||||
}
|
||||
@@ -137,6 +140,13 @@ const DefaultTorrentListCellContent: FC<TorrentListCellContentProps> = observer(
|
||||
return <PeerCell peersConnected={torrent.seedsConnected} totalPeers={torrent.seedsTotal} />;
|
||||
case 'peers':
|
||||
return <PeerCell peersConnected={torrent.peersConnected} totalPeers={torrent.peersTotal} />;
|
||||
case 'percentComplete':
|
||||
return (
|
||||
<ProgressBar
|
||||
percent={computed(() => Math.ceil(torrent.percentComplete)).get()}
|
||||
status={computed(() => torrentStatusEffective(torrent.status)).get()}
|
||||
/>
|
||||
);
|
||||
default:
|
||||
return <span>{torrent[column]}</span>;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import SettingStore from '../../stores/SettingStore';
|
||||
import TorrentListContextMenu from './TorrentListContextMenu';
|
||||
import TorrentListRowCondensed from './TorrentListRowCondensed';
|
||||
import TorrentListRowExpanded from './TorrentListRowExpanded';
|
||||
import torrentStatusClasses from '../../util/torrentStatusClasses';
|
||||
import {torrentStatusClasses} from '../../util/torrentStatus';
|
||||
import TorrentStore from '../../stores/TorrentStore';
|
||||
import UIActions from '../../actions/UIActions';
|
||||
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import {CSSProperties, forwardRef, KeyboardEvent, MouseEvent, ReactNodeArray, TouchEvent} from 'react';
|
||||
import {observer} from 'mobx-react';
|
||||
|
||||
import ProgressBar from '../general/ProgressBar';
|
||||
import SettingStore from '../../stores/SettingStore';
|
||||
import TorrentListCell from './TorrentListCell';
|
||||
import TorrentListColumns from '../../constants/TorrentListColumns';
|
||||
import TorrentStatusIcon from '../general/TorrentStatusIcon';
|
||||
|
||||
interface TorrentListRowCondensedProps {
|
||||
className: string;
|
||||
@@ -45,26 +43,6 @@ const TorrentListRowCondensed = observer(
|
||||
return accumulator;
|
||||
}
|
||||
|
||||
if (id === 'percentComplete') {
|
||||
accumulator.push(
|
||||
<TorrentListCell
|
||||
className="table__cell"
|
||||
key={id}
|
||||
hash={hash}
|
||||
column={id}
|
||||
content={({torrent}) => (
|
||||
<ProgressBar
|
||||
percent={Math.ceil(torrent.percentComplete)}
|
||||
icon={<TorrentStatusIcon statuses={torrent.status} />}
|
||||
/>
|
||||
)}
|
||||
width={SettingStore.floodSettings.torrentListColumnWidths[id]}
|
||||
/>,
|
||||
);
|
||||
|
||||
return accumulator;
|
||||
}
|
||||
|
||||
accumulator.push(
|
||||
<TorrentListCell
|
||||
className="table__cell"
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import {CSSProperties, forwardRef, KeyboardEvent, MouseEvent, ReactNodeArray, TouchEvent} from 'react';
|
||||
import {CSSProperties, FC, forwardRef, KeyboardEvent, MouseEvent, ReactNodeArray, TouchEvent} from 'react';
|
||||
import {observer} from 'mobx-react';
|
||||
import {useLingui} from '@lingui/react';
|
||||
|
||||
import SettingStore from '@client/stores/SettingStore';
|
||||
import TorrentListColumns from '@client/constants/TorrentListColumns';
|
||||
|
||||
import ProgressBar from '../general/ProgressBar';
|
||||
import Size from '../general/Size';
|
||||
import TorrentListCell from './TorrentListCell';
|
||||
import TorrentStatusIcon from '../general/TorrentStatusIcon';
|
||||
|
||||
import type {TorrentListCellContentProps} from './TorrentListCell';
|
||||
|
||||
interface TorrentListRowExpandedProps {
|
||||
className: string;
|
||||
@@ -22,6 +22,20 @@ interface TorrentListRowExpandedProps {
|
||||
handleKeyPress: (event: KeyboardEvent) => void;
|
||||
}
|
||||
|
||||
const TorrentListCellPercentageNumber: FC<TorrentListCellContentProps> = observer(
|
||||
({torrent}: TorrentListCellContentProps) => {
|
||||
const {i18n} = useLingui();
|
||||
return (
|
||||
<span>
|
||||
{i18n.number(torrent.percentComplete, {maximumFractionDigits: 1})}
|
||||
<em className="unit">%</em>
|
||||
—
|
||||
<Size value={torrent.downTotal} />
|
||||
</span>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
const TorrentListRowExpanded = observer(
|
||||
forwardRef<HTMLDivElement, TorrentListRowExpandedProps>(
|
||||
(
|
||||
@@ -38,7 +52,6 @@ const TorrentListRowExpanded = observer(
|
||||
}: TorrentListRowExpandedProps,
|
||||
ref,
|
||||
) => {
|
||||
const {i18n} = useLingui();
|
||||
const columns = SettingStore.floodSettings.torrentListColumns;
|
||||
|
||||
const primarySection: ReactNodeArray = [
|
||||
@@ -59,14 +72,7 @@ const TorrentListRowExpanded = observer(
|
||||
key="percentComplete"
|
||||
hash={hash}
|
||||
column="percentComplete"
|
||||
content={({torrent}) => (
|
||||
<span>
|
||||
{i18n.number(torrent.percentComplete, {maximumFractionDigits: 1})}
|
||||
<em className="unit">%</em>
|
||||
—
|
||||
<Size value={torrent.downTotal} />
|
||||
</span>
|
||||
)}
|
||||
content={TorrentListCellPercentageNumber}
|
||||
showIcon
|
||||
/>,
|
||||
];
|
||||
@@ -75,12 +81,6 @@ const TorrentListRowExpanded = observer(
|
||||
key="percentBar"
|
||||
hash={hash}
|
||||
column="percentComplete"
|
||||
content={({torrent}) => (
|
||||
<ProgressBar
|
||||
percent={Math.ceil(torrent.percentComplete)}
|
||||
icon={<TorrentStatusIcon statuses={torrent.status} />}
|
||||
/>
|
||||
)}
|
||||
className="torrent__details__section torrent__details__section--quaternary"
|
||||
classNameOverride
|
||||
/>,
|
||||
|
||||
+16
-5
@@ -2,11 +2,11 @@ import classnames from 'classnames';
|
||||
|
||||
import type {TorrentProperties} from '@shared/types/Torrent';
|
||||
|
||||
function torrentStatusClasses(
|
||||
export const torrentStatusClasses = (
|
||||
{status, downRate, upRate}: Pick<TorrentProperties, 'status' | 'downRate' | 'upRate'>,
|
||||
...classes: Array<string>
|
||||
): string {
|
||||
return classnames(classes, {
|
||||
): string =>
|
||||
classnames(classes, {
|
||||
'torrent--has-error': status.includes('error'),
|
||||
'torrent--is-stopped': status.includes('stopped'),
|
||||
'torrent--is-downloading': status.includes('downloading'),
|
||||
@@ -17,6 +17,17 @@ function torrentStatusClasses(
|
||||
'torrent--is-checking': status.includes('checking'),
|
||||
'torrent--is-inactive': status.includes('inactive'),
|
||||
});
|
||||
}
|
||||
|
||||
export default torrentStatusClasses;
|
||||
export const torrentStatusEffective = (status: TorrentProperties['status']): TorrentProperties['status'][number] => {
|
||||
let result: TorrentProperties['status'][number] = 'stopped';
|
||||
|
||||
['error', 'checking', 'stopped', 'downloading', 'seeding'].some((state) => {
|
||||
if (status.includes(state as TorrentProperties['status'][number])) {
|
||||
result = state as TorrentProperties['status'][number];
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
return result;
|
||||
};
|
||||
Reference in New Issue
Block a user