client: TorrentListRow: switch to use-long-press

This commit is contained in:
Jesse Chan
2020-10-21 02:16:35 +08:00
parent d5831be093
commit 782898f92f
11 changed files with 1128 additions and 321 deletions

View File

@@ -1,4 +1,8 @@
{
"presets": ["@babel/env", "@babel/typescript", "@babel/react"],
"plugins": ["@babel/plugin-proposal-class-properties", "@babel/proposal-object-rest-spread"]
"plugins": [
"@babel/plugin-proposal-class-properties",
"@babel/proposal-object-rest-spread",
"@babel/plugin-proposal-optional-chaining"
]
}

View File

@@ -12,7 +12,6 @@
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<script>/* long-press-event - v2.2.2 @author John Doherty <www.johndoherty.info> @license MIT */!function(e,t){"use strict";var n=null,a="ontouchstart"in e||navigator.MaxTouchPoints>0||navigator.msMaxTouchPoints>0,i=a?"touchstart":"mousedown",o=a?"touchend":"mouseup",s=a?"touchmove":"mousemove",c="click",u=0,r=0,m=10,l=10;function v(i){f(i);var s=i.target,u=parseInt(s.getAttribute("data-long-press-delay")||"500",10);n=function(t,n){if(!(e.requestAnimationFrame||e.webkitRequestAnimationFrame||e.mozRequestAnimationFrame&&e.mozCancelRequestAnimationFrame||e.oRequestAnimationFrame||e.msRequestAnimationFrame))return e.setTimeout(t,n);var a=(new Date).getTime(),i={},o=function(){(new Date).getTime()-a>=n?t.call():i.value=requestAnimFrame(o)};return i.value=requestAnimFrame(o),i}(function(n){f();var i=a?n.touches[0].clientX:n.clientX,s=a?n.touches[0].clientY:n.clientY;this.dispatchEvent(new MouseEvent("long-press",{bubbles:!0,cancelable:!0,detail:{clientX:i,clientY:s,offsetX:a?n.touches[0].offsetX:n.offsetX,offsetY:a?n.touches[0].offsetY:n.offsetY,pageX:a?n.touches[0].pageX:n.pageX,pageY:a?n.touches[0].pageY:n.pageY,screenX:a?n.touches[0].screenX:n.screenX,screenY:a?n.touches[0].screenY:n.screenY},clientX:a?n.touches[0].clientX:n.clientX,clientY:a?n.touches[0].clientY:n.clientY,offsetX:a?n.touches[0].offsetX:n.offsetX,offsetY:a?n.touches[0].offsetY:n.offsetY,pageX:a?n.touches[0].pageX:n.pageX,pageY:a?n.touches[0].pageY:n.pageY,screenX:a?n.touches[0].screenX:n.screenX,screenY:a?n.touches[0].screenY:n.screenY})),e.longPressSuppressClickEvent&&(t.addEventListener(o,function e(n){t.removeEventListener(o,e,!0),p(n)},!0),t.addEventListener(c,function e(n){t.removeEventListener(c,e,!0),p(n)},!0))}.bind(s,i),u)}function f(t){var a;(a=n)&&(e.cancelAnimationFrame?e.cancelAnimationFrame(a.value):e.webkitCancelAnimationFrame?e.webkitCancelAnimationFrame(a.value):e.webkitCancelRequestAnimationFrame?e.webkitCancelRequestAnimationFrame(a.value):e.mozCancelRequestAnimationFrame?e.mozCancelRequestAnimationFrame(a.value):e.oCancelRequestAnimationFrame?e.oCancelRequestAnimationFrame(a.value):e.msCancelRequestAnimationFrame?e.msCancelRequestAnimationFrame(a.value):clearTimeout(a)),n=null}function p(e){e.stopImmediatePropagation(),e.preventDefault(),e.stopPropagation()}"function"!=typeof e.CustomEvent&&(e.CustomEvent=function(e,n){n=n||{bubbles:!1,cancelable:!1,detail:void 0};var a=t.createEvent("CustomEvent");return a.initCustomEvent(e,n.bubbles,n.cancelable,n.detail),a},e.CustomEvent.prototype=e.Event.prototype),e.requestAnimFrame=e.requestAnimationFrame||e.webkitRequestAnimationFrame||e.mozRequestAnimationFrame||e.oRequestAnimationFrame||e.msRequestAnimationFrame||function(t){e.setTimeout(t,1e3/60)},t.addEventListener(o,f,!0),t.addEventListener(s,function(e){var t=Math.abs(u-e.clientX),n=Math.abs(r-e.clientY);(t>=m||n>=l)&&f()},!0),t.addEventListener("wheel",f,!0),t.addEventListener("scroll",f,!0),t.addEventListener(i,function(e){u=e.clientX,r=e.clientY,v(e)},!0)}(window,document);</script>
<div id="app"></div>
</body>
</html>

View File

@@ -10,7 +10,7 @@ import type {ContextMenu, Modal} from '../stores/UIStore';
export interface UIClickTorrentAction {
type: 'UI_CLICK_TORRENT';
data: {event: React.MouseEvent; hash: string};
data: {event: React.MouseEvent | React.TouchEvent; hash: string};
}
export interface UIClickTorrentDetailsAction {

View File

@@ -159,8 +159,15 @@ class TorrentList extends React.Component<TorrentListProps, TorrentListStates> {
}, 0);
}
handleContextMenuClick = (torrent: TorrentProperties, event: React.MouseEvent) => {
event.preventDefault();
handleContextMenuClick = (torrent: TorrentProperties, event: React.MouseEvent | React.TouchEvent) => {
if (event.cancelable === true) {
event.preventDefault();
}
const mouseClientX = ((event as unknown) as MouseEvent).clientX;
const mouseClientY = ((event as unknown) as MouseEvent).clientY;
const touchClientX = ((event as unknown) as TouchEvent).touches?.[0].clientX;
const touchClientY = ((event as unknown) as TouchEvent).touches?.[0].clientY;
if (!TorrentStore.getSelectedTorrents().includes(torrent.hash)) {
UIActions.handleTorrentClick({hash: torrent.hash, event});
@@ -169,8 +176,8 @@ class TorrentList extends React.Component<TorrentListProps, TorrentListStates> {
UIActions.displayContextMenu({
id: 'torrent-list-item',
clickPosition: {
x: event.clientX,
y: event.clientY,
x: mouseClientX || touchClientX || 0,
y: mouseClientY || touchClientY || 0,
},
items: TorrentListContextMenu.getContextMenuItems(this.props.intl, torrent).filter((item) => {
if (item.type === 'separator') {

View File

@@ -1,4 +1,5 @@
import classnames from 'classnames';
import {LongPressDetectEvents, useLongPress} from 'use-long-press';
import React from 'react';
import type {TorrentProperties} from '@shared/types/Torrent';
@@ -17,85 +18,72 @@ interface TorrentListRowProps {
isCondensed: boolean;
handleClick: (torrent: TorrentProperties, event: React.MouseEvent) => void;
handleDoubleClick: (torrent: TorrentProperties, event: React.MouseEvent) => void;
handleRightClick: (torrent: TorrentProperties, event: React.MouseEvent) => void;
handleRightClick: (torrent: TorrentProperties, event: React.MouseEvent | React.TouchEvent) => void;
}
class TorrentListRow extends React.PureComponent<TorrentListRowProps> {
torrentRef: HTMLLIElement | null = null;
handleRightClick: (event: React.MouseEvent) => void;
const TorrentListRow: React.FC<TorrentListRowProps> = (props: TorrentListRowProps) => {
const {
isCondensed,
isSelected,
columns,
columnWidths,
torrent,
handleClick,
handleDoubleClick,
handleRightClick,
} = props;
static defaultProps = {
isCondensed: false,
};
const torrentClasses = torrentStatusClasses(
torrent,
classnames({
'torrent--is-selected': isSelected,
'torrent--is-condensed': isCondensed,
'torrent--is-expanded': !isCondensed,
}),
'torrent',
);
constructor(props: TorrentListRowProps) {
super(props);
const {handleRightClick, torrent} = props;
this.handleRightClick = handleRightClick.bind(this, torrent);
}
componentDidMount(): void {
if (this.torrentRef != null) {
this.torrentRef.addEventListener('long-press', (e) => this.handleRightClick((e as unknown) as React.MouseEvent));
}
}
componentWillUnmount(): void {
if (this.torrentRef != null) {
this.torrentRef.removeEventListener('long-press', (e) =>
this.handleRightClick((e as unknown) as React.MouseEvent),
);
}
}
render(): React.ReactNode {
const {
isCondensed,
isSelected,
columns,
columnWidths,
torrent,
handleClick,
handleDoubleClick,
handleRightClick,
} = this.props;
const torrentClasses = torrentStatusClasses(
torrent,
classnames({
'torrent--is-selected': isSelected,
'torrent--is-condensed': isCondensed,
'torrent--is-expanded': !isCondensed,
}),
'torrent',
);
if (isCondensed) {
return (
<TorrentListRowCondensed
className={torrentClasses}
columns={columns}
columnWidths={columnWidths}
torrent={torrent}
handleClick={handleClick}
handleDoubleClick={handleDoubleClick}
handleRightClick={handleRightClick}
/>
);
}
const longPressBind = useLongPress(
(e) => {
if (e != null) {
handleRightClick(torrent, e);
}
},
{
captureEvent: true,
detect: LongPressDetectEvents.TOUCH,
onFinish: (e) => ((e as unknown) as TouchEvent)?.preventDefault(),
},
);
if (isCondensed) {
return (
<TorrentListRowExpanded
<TorrentListRowCondensed
className={torrentClasses}
columns={columns}
columnWidths={columnWidths}
torrent={torrent}
handleClick={handleClick}
handleDoubleClick={handleDoubleClick}
handleRightClick={handleRightClick}
handleTouchStart={longPressBind.onTouchStart}
handleTouchEnd={longPressBind.onTouchEnd}
/>
);
}
}
export default TorrentListRow;
return (
<TorrentListRowExpanded
className={torrentClasses}
columns={columns}
torrent={torrent}
handleClick={handleClick}
handleDoubleClick={handleDoubleClick}
handleRightClick={handleRightClick}
handleTouchStart={longPressBind.onTouchStart}
handleTouchEnd={longPressBind.onTouchEnd}
/>
);
};
export default React.memo(TorrentListRow);

View File

@@ -16,6 +16,8 @@ interface TorrentListRowCondensedProps {
handleClick: (torrent: TorrentProperties, event: React.MouseEvent) => void;
handleDoubleClick: (torrent: TorrentProperties, event: React.MouseEvent) => void;
handleRightClick: (torrent: TorrentProperties, event: React.MouseEvent) => void;
handleTouchStart: (event: React.TouchEvent) => void;
handleTouchEnd: (event: React.TouchEvent) => void;
}
const TorrentListRowCondensed = React.forwardRef<HTMLLIElement, TorrentListRowCondensedProps>(
@@ -28,6 +30,8 @@ const TorrentListRowCondensed = React.forwardRef<HTMLLIElement, TorrentListRowCo
handleClick,
handleDoubleClick,
handleRightClick,
handleTouchStart,
handleTouchEnd,
}: TorrentListRowCondensedProps,
ref,
) => {
@@ -56,6 +60,8 @@ const TorrentListRowCondensed = React.forwardRef<HTMLLIElement, TorrentListRowCo
onClick={handleClick.bind(this, torrent)}
onContextMenu={handleRightClick.bind(this, torrent)}
onDoubleClick={handleDoubleClick.bind(this, torrent)}
onTouchStart={handleTouchStart}
onTouchEnd={handleTouchEnd}
ref={ref}>
{torrentListColumns}
</li>

View File

@@ -17,11 +17,22 @@ interface TorrentListRowExpandedProps {
handleClick: (torrent: TorrentProperties, event: React.MouseEvent) => void;
handleDoubleClick: (torrent: TorrentProperties, event: React.MouseEvent) => void;
handleRightClick: (torrent: TorrentProperties, event: React.MouseEvent) => void;
handleTouchStart: (event: React.TouchEvent) => void;
handleTouchEnd: (event: React.TouchEvent) => void;
}
const TorrentListRowExpanded = React.forwardRef<HTMLLIElement, TorrentListRowExpandedProps>(
(
{className, columns, torrent, handleClick, handleDoubleClick, handleRightClick}: TorrentListRowExpandedProps,
{
className,
columns,
torrent,
handleClick,
handleDoubleClick,
handleRightClick,
handleTouchStart,
handleTouchEnd,
}: TorrentListRowExpandedProps,
ref,
) => {
const primarySection: React.ReactNodeArray = [];
@@ -85,6 +96,8 @@ const TorrentListRowExpanded = React.forwardRef<HTMLLIElement, TorrentListRowExp
onClick={handleClick.bind(this, torrent)}
onContextMenu={handleRightClick.bind(this, torrent)}
onDoubleClick={handleDoubleClick.bind(this, torrent)}
onTouchStart={handleTouchStart}
onTouchEnd={handleTouchEnd}
ref={ref}>
<div className="torrent__details__section__wrapper">
{primarySection}

View File

@@ -190,7 +190,7 @@ class TorrentStoreClass extends BaseStore {
});
}
setSelectedTorrents({event, hash}: {event: React.MouseEvent; hash: string}) {
setSelectedTorrents({event, hash}: {event: React.MouseEvent | React.TouchEvent; hash: string}) {
this.selectedTorrents = selectTorrents({
event,
hash,

View File

@@ -3,7 +3,7 @@ import React from 'react';
import type {TorrentProperties} from '@shared/types/Torrent';
interface SelectTorrentOptions {
event: React.MouseEvent;
event: React.MouseEvent | React.TouchEvent;
hash: string;
selectedTorrents: Array<string>;
torrentList: Array<TorrentProperties>;

1276
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -55,7 +55,8 @@
"devDependencies": {
"@babel/core": "^7.12.0",
"@babel/plugin-proposal-class-properties": "^7.10.4",
"@babel/preset-env": "^7.12.0",
"@babel/plugin-proposal-optional-chaining": "^7.12.1",
"@babel/preset-env": "^7.12.1",
"@babel/preset-react": "^7.10.4",
"@babel/preset-typescript": "^7.12.0",
"@formatjs/cli": "^2.13.2",
@@ -191,6 +192,7 @@
"typed-emitter": "^1.3.1",
"typescript": "^4.0.3",
"url-loader": "^4.1.1",
"use-long-press": "^1.0.4",
"webpack": "^4.44.2",
"webpack-dev-server": "^3.11.0",
"webpack-manifest-plugin": "^2.2.0",