mirror of
https://github.com/zoriya/flood.git
synced 2026-06-08 04:41:03 +00:00
TorrentList: observe torrent properties at cell level
This commit is contained in:
@@ -43,7 +43,7 @@ class TorrentHeading extends React.Component {
|
||||
return null;
|
||||
}
|
||||
|
||||
const torrentClasses = torrentStatusClasses(torrent, 'torrent-details__header');
|
||||
const torrentClasses = torrentStatusClasses(torrent.status, 'torrent-details__header');
|
||||
const torrentStatusIcon = torrentStatusIcons(torrent.status);
|
||||
this.torrentStatus = getCurrentStatus(torrent.status);
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ import React from 'react';
|
||||
import defaultFloodSettings from '@shared/constants/defaultFloodSettings';
|
||||
|
||||
import type {FloodSettings} from '@shared/types/FloodSettings';
|
||||
import type {TorrentProperties} from '@shared/types/Torrent';
|
||||
|
||||
import {Button} from '../../ui';
|
||||
import ClientStatusStore from '../../stores/ClientStatusStore';
|
||||
@@ -53,9 +52,9 @@ const getEmptyTorrentListNotification = (): React.ReactNode => {
|
||||
);
|
||||
};
|
||||
|
||||
const handleClick = (torrent: TorrentProperties, event: React.MouseEvent) =>
|
||||
UIActions.handleTorrentClick({hash: torrent.hash, event});
|
||||
const handleDoubleClick = (torrent: TorrentProperties) => TorrentListContextMenu.handleDetailsClick(torrent);
|
||||
const handleClick = (hash: string, event: React.MouseEvent) => UIActions.handleTorrentClick({hash, event});
|
||||
const handleDoubleClick = (hash: string) => TorrentListContextMenu.handleDetailsClick(hash);
|
||||
|
||||
@observer
|
||||
class TorrentList extends React.Component<WrappedComponentProps> {
|
||||
listContainer: HTMLDivElement | null = null;
|
||||
@@ -82,7 +81,7 @@ class TorrentList extends React.Component<WrappedComponentProps> {
|
||||
});
|
||||
};
|
||||
|
||||
handleContextMenuClick = (torrent: TorrentProperties, event: React.MouseEvent | React.TouchEvent) => {
|
||||
handleContextMenuClick = (hash: string, event: React.MouseEvent | React.TouchEvent) => {
|
||||
if (event.cancelable === true) {
|
||||
event.preventDefault();
|
||||
}
|
||||
@@ -92,11 +91,12 @@ class TorrentList extends React.Component<WrappedComponentProps> {
|
||||
const touchClientX = ((event as unknown) as TouchEvent).touches?.[0].clientX;
|
||||
const touchClientY = ((event as unknown) as TouchEvent).touches?.[0].clientY;
|
||||
|
||||
if (!TorrentStore.selectedTorrents.includes(torrent.hash)) {
|
||||
UIActions.handleTorrentClick({hash: torrent.hash, event});
|
||||
if (!TorrentStore.selectedTorrents.includes(hash)) {
|
||||
UIActions.handleTorrentClick({hash, event});
|
||||
}
|
||||
|
||||
const {torrentContextMenuActions = defaultFloodSettings.torrentContextMenuActions} = SettingStore.floodSettings;
|
||||
const torrent = TorrentStore.torrents[hash];
|
||||
|
||||
UIActions.displayContextMenu({
|
||||
id: 'torrent-list-item',
|
||||
|
||||
@@ -1,23 +1,32 @@
|
||||
import classnames from 'classnames';
|
||||
import {observer} from 'mobx-react';
|
||||
import React from 'react';
|
||||
|
||||
import type {TorrentProperties} from '@shared/types/Torrent';
|
||||
|
||||
import DetailNotAvailableIcon from '../icons/DetailNotAvailableIcon';
|
||||
import {getTorrentListCellContent} from '../../util/torrentListCellContents';
|
||||
import torrentPropertyIcons from '../../util/torrentPropertyIcons';
|
||||
import TorrentStore from '../../stores/TorrentStore';
|
||||
|
||||
import type {TorrentListColumn} from '../../constants/TorrentListColumns';
|
||||
|
||||
interface TorrentListCellProps {
|
||||
content: React.ReactNode;
|
||||
hash: string;
|
||||
column: TorrentListColumn;
|
||||
content?: (torrent: TorrentProperties, column: TorrentListColumn) => React.ReactNode;
|
||||
className?: string;
|
||||
classNameOverride?: boolean;
|
||||
width?: number;
|
||||
showIcon?: boolean;
|
||||
}
|
||||
|
||||
const TorrentListCell: React.FC<TorrentListCellProps> = ({
|
||||
hash,
|
||||
content,
|
||||
column,
|
||||
className,
|
||||
classNameOverride,
|
||||
width,
|
||||
showIcon,
|
||||
}: TorrentListCellProps) => {
|
||||
@@ -25,18 +34,20 @@ const TorrentListCell: React.FC<TorrentListCellProps> = ({
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classnames('torrent__detail', `torrent__detail--${column}`, className)}
|
||||
className={classNameOverride ? className : classnames('torrent__detail', `torrent__detail--${column}`, className)}
|
||||
style={{width: `${width}px`}}>
|
||||
{icon}
|
||||
{content || <DetailNotAvailableIcon />}
|
||||
{content?.(TorrentStore.torrents[hash], column) || <DetailNotAvailableIcon />}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
TorrentListCell.defaultProps = {
|
||||
className: undefined,
|
||||
classNameOverride: false,
|
||||
content: getTorrentListCellContent,
|
||||
width: undefined,
|
||||
showIcon: false,
|
||||
};
|
||||
|
||||
export default React.memo(TorrentListCell);
|
||||
export default observer(TorrentListCell);
|
||||
|
||||
@@ -17,10 +17,10 @@ import type {TorrentContextMenuAction} from '../../constants/TorrentContextMenuA
|
||||
const priorityMeterRef: React.RefObject<PriorityMeterType> = React.createRef();
|
||||
let prioritySelected = 1;
|
||||
|
||||
const handleDetailsClick = (torrent: TorrentProperties): void => {
|
||||
const handleDetailsClick = (hash: string): void => {
|
||||
UIActions.displayModal({
|
||||
id: 'torrent-details',
|
||||
hash: torrent.hash,
|
||||
hash,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -66,10 +66,10 @@ const handleItemClick = (action: TorrentContextMenuAction, event: React.MouseEve
|
||||
UIActions.displayModal({id: 'move-torrents'});
|
||||
break;
|
||||
case 'torrentDetails':
|
||||
handleDetailsClick(TorrentStore.torrents[selectedTorrents.pop() as string]);
|
||||
handleDetailsClick(selectedTorrents[selectedTorrents.length - 1]);
|
||||
break;
|
||||
case 'torrentDownload':
|
||||
handleTorrentDownload(TorrentStore.torrents[selectedTorrents.pop() as string], event);
|
||||
handleTorrentDownload(TorrentStore.torrents[selectedTorrents[selectedTorrents.length - 1]], event);
|
||||
break;
|
||||
case 'setPriority':
|
||||
if (priorityMeterRef.current != null) {
|
||||
|
||||
@@ -3,8 +3,6 @@ import {LongPressDetectEvents, useLongPress} from 'use-long-press';
|
||||
import {observer} from 'mobx-react';
|
||||
import React from 'react';
|
||||
|
||||
import type {TorrentProperties} from '@shared/types/Torrent';
|
||||
|
||||
import SettingStore from '../../stores/SettingStore';
|
||||
import torrentStatusClasses from '../../util/torrentStatusClasses';
|
||||
import TorrentStore from '../../stores/TorrentStore';
|
||||
@@ -14,21 +12,20 @@ import TorrentListRowExpanded from './TorrentListRowExpanded';
|
||||
|
||||
interface TorrentListRowProps {
|
||||
hash: string;
|
||||
handleClick: (torrent: TorrentProperties, event: React.MouseEvent) => void;
|
||||
handleDoubleClick: (torrent: TorrentProperties, event: React.MouseEvent) => void;
|
||||
handleRightClick: (torrent: TorrentProperties, event: React.MouseEvent | React.TouchEvent) => void;
|
||||
handleClick: (hash: string, event: React.MouseEvent) => void;
|
||||
handleDoubleClick: (hash: string, event: React.MouseEvent) => void;
|
||||
handleRightClick: (hash: string, event: React.MouseEvent | React.TouchEvent) => void;
|
||||
}
|
||||
|
||||
const TorrentListRow: React.FC<TorrentListRowProps> = (props: TorrentListRowProps) => {
|
||||
const {hash, handleClick, handleDoubleClick, handleRightClick} = props;
|
||||
|
||||
const torrent = TorrentStore.torrents[hash];
|
||||
const isCondensed = SettingStore.floodSettings.torrentListViewSize === 'condensed';
|
||||
|
||||
const torrentClasses = torrentStatusClasses(
|
||||
torrent,
|
||||
TorrentStore.torrents?.[hash].status,
|
||||
classnames({
|
||||
'torrent--is-selected': TorrentStore.selectedTorrents.includes(torrent.hash),
|
||||
'torrent--is-selected': TorrentStore.selectedTorrents.includes(hash),
|
||||
'torrent--is-condensed': isCondensed,
|
||||
'torrent--is-expanded': !isCondensed,
|
||||
}),
|
||||
@@ -38,7 +35,7 @@ const TorrentListRow: React.FC<TorrentListRowProps> = (props: TorrentListRowProp
|
||||
const longPressBind = useLongPress(
|
||||
(e) => {
|
||||
if (e != null) {
|
||||
handleRightClick(torrent, e);
|
||||
handleRightClick(hash, e);
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,21 +1,17 @@
|
||||
import {observer} from 'mobx-react';
|
||||
import React from 'react';
|
||||
|
||||
import type {TorrentProperties} from '@shared/types/Torrent';
|
||||
|
||||
import {getTorrentListCellContent} from '../../util/torrentListCellContents';
|
||||
import ProgressBar from '../general/ProgressBar';
|
||||
import SettingStore from '../../stores/SettingStore';
|
||||
import TorrentListCell from './TorrentListCell';
|
||||
import torrentStatusIcons from '../../util/torrentStatusIcons';
|
||||
import TorrentStore from '../../stores/TorrentStore';
|
||||
|
||||
interface TorrentListRowCondensedProps {
|
||||
className: string;
|
||||
hash: string;
|
||||
handleClick: (torrent: TorrentProperties, event: React.MouseEvent) => void;
|
||||
handleDoubleClick: (torrent: TorrentProperties, event: React.MouseEvent) => void;
|
||||
handleRightClick: (torrent: TorrentProperties, event: React.MouseEvent) => void;
|
||||
handleClick: (hash: string, event: React.MouseEvent) => void;
|
||||
handleDoubleClick: (hash: string, event: React.MouseEvent) => void;
|
||||
handleRightClick: (hash: string, event: React.MouseEvent) => void;
|
||||
handleTouchStart: (event: React.TouchEvent) => void;
|
||||
handleTouchEnd: (event: React.TouchEvent) => void;
|
||||
}
|
||||
@@ -33,26 +29,35 @@ const TorrentListRowCondensed = React.forwardRef<HTMLLIElement, TorrentListRowCo
|
||||
}: TorrentListRowCondensedProps,
|
||||
ref,
|
||||
) => {
|
||||
const torrent = TorrentStore.torrents[hash];
|
||||
const torrentListColumns = SettingStore.floodSettings.torrentListColumns.reduce(
|
||||
(accumulator: React.ReactNodeArray, {id, visible}) => {
|
||||
if (!visible) {
|
||||
return accumulator;
|
||||
}
|
||||
|
||||
const content: React.ReactNode =
|
||||
id === 'percentComplete' ? (
|
||||
<ProgressBar percent={torrent.percentComplete} icon={torrentStatusIcons(torrent.status)} />
|
||||
) : (
|
||||
getTorrentListCellContent(torrent, id)
|
||||
if (id === 'percentComplete') {
|
||||
accumulator.push(
|
||||
<TorrentListCell
|
||||
className="table__cell"
|
||||
key={id}
|
||||
hash={hash}
|
||||
column={id}
|
||||
content={(torrent) => (
|
||||
<ProgressBar percent={torrent.percentComplete} icon={torrentStatusIcons(torrent.status)} />
|
||||
)}
|
||||
width={SettingStore.floodSettings.torrentListColumnWidths[id]}
|
||||
/>,
|
||||
);
|
||||
|
||||
return accumulator;
|
||||
}
|
||||
|
||||
accumulator.push(
|
||||
<TorrentListCell
|
||||
className="table__cell"
|
||||
key={id}
|
||||
hash={hash}
|
||||
column={id}
|
||||
content={content}
|
||||
width={SettingStore.floodSettings.torrentListColumnWidths[id]}
|
||||
/>,
|
||||
);
|
||||
@@ -65,9 +70,9 @@ const TorrentListRowCondensed = React.forwardRef<HTMLLIElement, TorrentListRowCo
|
||||
return (
|
||||
<li
|
||||
className={className}
|
||||
onClick={handleClick.bind(this, torrent)}
|
||||
onContextMenu={handleRightClick.bind(this, torrent)}
|
||||
onDoubleClick={handleDoubleClick.bind(this, torrent)}
|
||||
onClick={handleClick.bind(this, hash)}
|
||||
onContextMenu={handleRightClick.bind(this, hash)}
|
||||
onDoubleClick={handleDoubleClick.bind(this, hash)}
|
||||
onTouchStart={handleTouchStart}
|
||||
onTouchEnd={handleTouchEnd}
|
||||
ref={ref}>
|
||||
|
||||
@@ -2,22 +2,18 @@ import {FormattedNumber} from 'react-intl';
|
||||
import {observer} from 'mobx-react';
|
||||
import React from 'react';
|
||||
|
||||
import type {TorrentProperties} from '@shared/types/Torrent';
|
||||
|
||||
import {getTorrentListCellContent} from '../../util/torrentListCellContents';
|
||||
import ProgressBar from '../general/ProgressBar';
|
||||
import SettingStore from '../../stores/SettingStore';
|
||||
import Size from '../general/Size';
|
||||
import TorrentListCell from './TorrentListCell';
|
||||
import torrentStatusIcons from '../../util/torrentStatusIcons';
|
||||
import TorrentStore from '../../stores/TorrentStore';
|
||||
|
||||
interface TorrentListRowExpandedProps {
|
||||
className: string;
|
||||
hash: string;
|
||||
handleClick: (torrent: TorrentProperties, event: React.MouseEvent) => void;
|
||||
handleDoubleClick: (torrent: TorrentProperties, event: React.MouseEvent) => void;
|
||||
handleRightClick: (torrent: TorrentProperties, event: React.MouseEvent) => void;
|
||||
handleClick: (hash: string, event: React.MouseEvent) => void;
|
||||
handleDoubleClick: (hash: string, event: React.MouseEvent) => void;
|
||||
handleRightClick: (hash: string, event: React.MouseEvent) => void;
|
||||
handleTouchStart: (event: React.TouchEvent) => void;
|
||||
handleTouchEnd: (event: React.TouchEvent) => void;
|
||||
}
|
||||
@@ -35,42 +31,49 @@ const TorrentListRowExpanded = React.forwardRef<HTMLLIElement, TorrentListRowExp
|
||||
}: TorrentListRowExpandedProps,
|
||||
ref,
|
||||
) => {
|
||||
const torrent = TorrentStore.torrents[hash];
|
||||
const columns = SettingStore.floodSettings.torrentListColumns;
|
||||
|
||||
const primarySection: React.ReactNodeArray = [
|
||||
<TorrentListCell
|
||||
key="name"
|
||||
hash={hash}
|
||||
column="name"
|
||||
className="torrent__details__section torrent__details__section--primary"
|
||||
content={getTorrentListCellContent(torrent, 'name')}
|
||||
/>,
|
||||
];
|
||||
const secondarySection: React.ReactNodeArray = [
|
||||
<TorrentListCell key="eta" column="eta" content={getTorrentListCellContent(torrent, 'eta')} showIcon />,
|
||||
<TorrentListCell
|
||||
key="downRate"
|
||||
column="downRate"
|
||||
content={getTorrentListCellContent(torrent, 'downRate')}
|
||||
showIcon
|
||||
/>,
|
||||
<TorrentListCell key="upRate" column="upRate" content={getTorrentListCellContent(torrent, 'upRate')} showIcon />,
|
||||
<TorrentListCell key="eta" hash={hash} column="eta" showIcon />,
|
||||
<TorrentListCell key="downRate" hash={hash} column="downRate" showIcon />,
|
||||
<TorrentListCell key="upRate" hash={hash} column="upRate" showIcon />,
|
||||
];
|
||||
const tertiarySection: React.ReactNodeArray = [
|
||||
<TorrentListCell
|
||||
key="percentComplete"
|
||||
hash={hash}
|
||||
column="percentComplete"
|
||||
content={
|
||||
content={(torrent) => (
|
||||
<span>
|
||||
<FormattedNumber value={torrent.percentComplete} />
|
||||
<em className="unit">%</em>
|
||||
—
|
||||
<Size value={torrent.downTotal} />
|
||||
</span>
|
||||
}
|
||||
)}
|
||||
showIcon
|
||||
/>,
|
||||
];
|
||||
const quaternarySection: React.ReactNodeArray = [
|
||||
<TorrentListCell
|
||||
key="percentBar"
|
||||
hash={hash}
|
||||
column="percentComplete"
|
||||
content={(torrent) => (
|
||||
<ProgressBar percent={torrent.percentComplete} icon={torrentStatusIcons(torrent.status)} />
|
||||
)}
|
||||
className="torrent__details__section torrent__details__section--quaternary"
|
||||
classNameOverride
|
||||
/>,
|
||||
];
|
||||
|
||||
// Using a for loop to maximize performance.
|
||||
for (let index = 0; index < columns.length; index += 1) {
|
||||
@@ -88,9 +91,7 @@ const TorrentListRowExpanded = React.forwardRef<HTMLLIElement, TorrentListRowExp
|
||||
case 'percentComplete':
|
||||
break;
|
||||
default:
|
||||
tertiarySection.push(
|
||||
<TorrentListCell key={id} column={id} content={getTorrentListCellContent(torrent, id)} showIcon />,
|
||||
);
|
||||
tertiarySection.push(<TorrentListCell key={id} hash={hash} column={id} showIcon />);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -99,9 +100,9 @@ const TorrentListRowExpanded = React.forwardRef<HTMLLIElement, TorrentListRowExp
|
||||
return (
|
||||
<li
|
||||
className={className}
|
||||
onClick={handleClick.bind(this, torrent)}
|
||||
onContextMenu={handleRightClick.bind(this, torrent)}
|
||||
onDoubleClick={handleDoubleClick.bind(this, torrent)}
|
||||
onClick={handleClick.bind(this, hash)}
|
||||
onContextMenu={handleRightClick.bind(this, hash)}
|
||||
onDoubleClick={handleDoubleClick.bind(this, hash)}
|
||||
onTouchStart={handleTouchStart}
|
||||
onTouchEnd={handleTouchEnd}
|
||||
ref={ref}>
|
||||
@@ -110,9 +111,7 @@ const TorrentListRowExpanded = React.forwardRef<HTMLLIElement, TorrentListRowExp
|
||||
<div className="torrent__details__section torrent__details__section--secondary">{secondarySection}</div>
|
||||
</div>
|
||||
<div className="torrent__details__section torrent__details__section--tertiary">{tertiarySection}</div>
|
||||
<div className="torrent__details__section torrent__details__section--quaternary">
|
||||
<ProgressBar percent={torrent.percentComplete} icon={torrentStatusIcons(torrent.status)} />
|
||||
</div>
|
||||
{quaternarySection}
|
||||
</li>
|
||||
);
|
||||
},
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
import classnames from 'classnames';
|
||||
|
||||
import type {TorrentStatus} from '@shared/constants/torrentStatusMap';
|
||||
|
||||
function torrentStatusClasses(torrent: {status: Array<TorrentStatus>}, ...classes: Array<string>) {
|
||||
function torrentStatusClasses(status: Array<TorrentStatus>, ...classes: Array<string>) {
|
||||
return classnames(classes, {
|
||||
'torrent--has-error': torrent.status.includes('error'),
|
||||
'torrent--is-stopped': torrent.status.includes('stopped'),
|
||||
'torrent--is-downloading': torrent.status.includes('downloading'),
|
||||
'torrent--is-downloading--actively': torrent.status.includes('activelyDownloading'),
|
||||
'torrent--is-uploading--actively': torrent.status.includes('activelyUploading'),
|
||||
'torrent--is-seeding': torrent.status.includes('seeding'),
|
||||
'torrent--is-completed': torrent.status.includes('complete'),
|
||||
'torrent--is-checking': torrent.status.includes('checking'),
|
||||
'torrent--is-inactive': torrent.status.includes('inactive'),
|
||||
'torrent--has-error': status.includes('error'),
|
||||
'torrent--is-stopped': status.includes('stopped'),
|
||||
'torrent--is-downloading': status.includes('downloading'),
|
||||
'torrent--is-downloading--actively': status.includes('activelyDownloading'),
|
||||
'torrent--is-uploading--actively': status.includes('activelyUploading'),
|
||||
'torrent--is-seeding': status.includes('seeding'),
|
||||
'torrent--is-completed': status.includes('complete'),
|
||||
'torrent--is-checking': status.includes('checking'),
|
||||
'torrent--is-inactive': status.includes('inactive'),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user