Skip to content

Commit

Permalink
client: fix and improve memoization of "ProgressBar"
Browse files Browse the repository at this point in the history
  • Loading branch information
jesec committed Jul 11, 2021
1 parent 6fdbf71 commit 78611b2
Show file tree
Hide file tree
Showing 8 changed files with 77 additions and 84 deletions.
15 changes: 10 additions & 5 deletions client/src/javascript/components/general/ProgressBar.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,26 @@
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>
</div>
));

ProgressBar.defaultProps = {
icon: undefined,
status: undefined,
};

export default ProgressBar;
45 changes: 17 additions & 28 deletions client/src/javascript/components/general/TorrentStatusIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 />;

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);
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 />;
}
});

export default TorrentStatusIcon;
Original file line number Diff line number Diff line change
@@ -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(() => {
Expand Down Expand Up @@ -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>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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';
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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>;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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"
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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>
&nbsp;&mdash;&nbsp;
<Size value={torrent.downTotal} />
</span>
);
},
);

const TorrentListRowExpanded = observer(
forwardRef<HTMLDivElement, TorrentListRowExpandedProps>(
(
Expand All @@ -38,7 +52,6 @@ const TorrentListRowExpanded = observer(
}: TorrentListRowExpandedProps,
ref,
) => {
const {i18n} = useLingui();
const columns = SettingStore.floodSettings.torrentListColumns;

const primarySection: ReactNodeArray = [
Expand All @@ -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>
&nbsp;&mdash;&nbsp;
<Size value={torrent.downTotal} />
</span>
)}
content={TorrentListCellPercentageNumber}
showIcon
/>,
];
Expand All @@ -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
/>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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'),
Expand All @@ -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;
};

0 comments on commit 78611b2

Please sign in to comment.