File Property reorder autoscroll.
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
window.addEventListener .... done wrong everywhere!
|
||||
|
||||
touch scroll in file propertty dialog.
|
||||
|
||||
channel bindings help dialog. <ChannelBindingHelpDialog
|
||||
|
||||
Tooltips on touch ui?
|
||||
|
||||
draggable UI: scrolloffset!?
|
||||
|
||||
|
||||
@@ -19,9 +19,6 @@ div {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.draggable-button-base {
|
||||
touch-action: none;
|
||||
}
|
||||
|
||||
@media not all /* seems to be ok in current chrome (prefers-color-scheme: light) */{
|
||||
input[type="number"].scrollMod::-webkit-outer-spin-button,
|
||||
|
||||
@@ -26,10 +26,11 @@ import ButtonBase, { ButtonBaseProps } from "@mui/material/ButtonBase";
|
||||
|
||||
export interface DraggableButtonBaseProps extends ButtonBaseProps {
|
||||
onClick?: (e: React.MouseEvent<HTMLButtonElement>) => void;
|
||||
onLongPressStart?: (currentTarget: HTMLButtonElement, e: React.PointerEvent<HTMLButtonElement>) => boolean;
|
||||
onLongPressStart?: (currentTarget: HTMLButtonElement, e: React.PointerEvent<HTMLButtonElement> | React.MouseEvent<HTMLButtonElement>) => boolean;
|
||||
onLongPressMove?: (e: React.PointerEvent<HTMLButtonElement>) => void;
|
||||
onLongPressEnd?: (e: React.PointerEvent<HTMLButtonElement>) => void;
|
||||
longPressDelay? : number;
|
||||
onLongPressEnd?: (e: React.PointerEvent<HTMLButtonElement>| React.MouseEvent<HTMLButtonElement>) => void;
|
||||
instantMouseLongPress?: boolean;
|
||||
longPressDelay?: number;
|
||||
}
|
||||
|
||||
interface Point {
|
||||
@@ -58,37 +59,43 @@ function screenToClient(e: React.PointerEvent): Point {
|
||||
|
||||
export default function DraggableButtonBase(props: DraggableButtonBaseProps) {
|
||||
// Ensure that the props are spread correctly
|
||||
const { onClick, onLongPressStart, onLongPressEnd,longPressDelay, ...rest } = props;
|
||||
|
||||
const { onClick, onLongPressStart, onLongPressMove:
|
||||
doLongPressMove,onLongPressEnd, longPressDelay,instantMouseLongPress, ...rest } = props;
|
||||
|
||||
let [hTimeout, setHTimeout] = React.useState<number | null>(null);
|
||||
let [pointerId, setPointerId] = React.useState<number | null>(null);
|
||||
let [longPressed, setLongPressed] = React.useState<boolean>(false);
|
||||
let [clickSuppressed, setClickSuppressed] = React.useState<boolean>(false);
|
||||
let [pointerDownPoint, setPointerDownPoint] = React.useState<Point >({x: 0, y: 0});
|
||||
let [pointerDownPoint, setPointerDownPoint] = React.useState<Point>({ x: 0, y: 0 });
|
||||
let [ longPressedElement, setLongPressedElement ] = React.useState<HTMLButtonElement | null>(null);
|
||||
|
||||
|
||||
function handleSuppressClick(e: MouseEvent) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
setSuppressClick(false);
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
setSuppressClick(false);
|
||||
}
|
||||
|
||||
function setSuppressClick(value: boolean) {
|
||||
|
||||
if (value !== clickSuppressed) {
|
||||
setClickSuppressed(value);
|
||||
if (value) {
|
||||
window.addEventListener(
|
||||
"click",
|
||||
handleSuppressClick,
|
||||
{
|
||||
once: true,
|
||||
capture: true
|
||||
});
|
||||
} else {
|
||||
window.removeEventListener("click", handleSuppressClick);
|
||||
setClickSuppressed(value);
|
||||
}
|
||||
function startLongPress(currentTarget: HTMLButtonElement, e: React.PointerEvent<HTMLButtonElement> | React.MouseEvent<HTMLButtonElement>)
|
||||
{
|
||||
if (hTimeout !== null) {
|
||||
window.clearTimeout(hTimeout);
|
||||
setHTimeout(null);
|
||||
}
|
||||
if (props.onLongPressStart) {
|
||||
if (!props.onLongPressStart(currentTarget, e)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
setLongPressedElement(currentTarget);
|
||||
setLongPressed(true);
|
||||
setSuppressClick(true);
|
||||
currentTarget.style.touchAction = "none"; // prevent scrolling.
|
||||
// console.log("DraggableButtonBase: long press started");
|
||||
|
||||
}
|
||||
|
||||
function cancelLongPress() {
|
||||
@@ -99,23 +106,106 @@ export default function DraggableButtonBase(props: DraggableButtonBaseProps) {
|
||||
setPointerId(null);
|
||||
setLongPressed(false);
|
||||
setSuppressClick(false);
|
||||
if (longPressedElement) {
|
||||
longPressedElement.style.touchAction = "";
|
||||
setLongPressedElement(null);
|
||||
}
|
||||
if (longPressed) {
|
||||
// console.log("DraggableButtonBase: long press canceled");
|
||||
}
|
||||
}
|
||||
|
||||
function stopLongPress(e: React.PointerEvent<HTMLButtonElement> | React.MouseEvent<HTMLButtonElement>) {
|
||||
if (longPressed) {
|
||||
if (props.onLongPressEnd) {
|
||||
props.onLongPressEnd(e);
|
||||
}
|
||||
}
|
||||
cancelLongPress();
|
||||
}
|
||||
|
||||
const handleTouchMove = (e: TouchEvent) => {
|
||||
if (longPressed) {
|
||||
e.preventDefault(); // Prevent scrolling during long press
|
||||
e.stopPropagation();
|
||||
}
|
||||
}
|
||||
const handleTouchstart = (e: TouchEvent) => {
|
||||
if (longPressed) {
|
||||
e.preventDefault(); // Prevent default touch behavior during long press
|
||||
e.stopPropagation();
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
let hTouchMove = (e: TouchEvent) => {
|
||||
handleTouchMove(e);
|
||||
}
|
||||
addEventListener("touchmove", hTouchMove, { passive: false, capture: true });
|
||||
|
||||
let hTouchStart = (e: TouchEvent) => {
|
||||
handleTouchstart(e);
|
||||
}
|
||||
addEventListener("touchstart", hTouchStart, { passive: false, capture: true });
|
||||
|
||||
return () => {
|
||||
removeEventListener("touchmove", hTouchMove, { capture: true });
|
||||
removeEventListener("touchstart", hTouchStart, { capture: true });
|
||||
|
||||
setSuppressClick(false);
|
||||
cancelLongPress();
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (clickSuppressed) {
|
||||
let hclick = (e: MouseEvent) => {
|
||||
handleSuppressClick(e);
|
||||
};
|
||||
window.addEventListener("click",hclick, { capture: true });
|
||||
let hTimeout: number | null = null;
|
||||
hTimeout = window.setTimeout(() => {
|
||||
setSuppressClick(false);
|
||||
hTimeout = null;
|
||||
}, 100);
|
||||
return () => {
|
||||
if (hTimeout !== null) {
|
||||
window.clearTimeout(hTimeout);
|
||||
}
|
||||
window.removeEventListener("click", hclick, { capture: true });
|
||||
}
|
||||
} else {
|
||||
return ()=>{};
|
||||
}
|
||||
}, [clickSuppressed]);
|
||||
useEffect(() => {
|
||||
|
||||
if (longPressed) {
|
||||
const suppressTouchMove = (e: TouchEvent) => {
|
||||
e.preventDefault();
|
||||
}
|
||||
window.addEventListener("touchmove", suppressTouchMove, { capture: true, passive: false } );
|
||||
return () => {
|
||||
window.removeEventListener("touchmove", suppressTouchMove, {capture: true})
|
||||
}
|
||||
}
|
||||
else {
|
||||
return () => {
|
||||
};
|
||||
}
|
||||
}, [longPressed]);
|
||||
|
||||
return (
|
||||
<ButtonBase
|
||||
{...rest}
|
||||
className="draggable-button-base"
|
||||
style={{ touchAction: longPressed ? "none" : undefined, ...props.style }}
|
||||
onContextMenu={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
if (e.button === -1) { // touch long press
|
||||
startLongPress(e.currentTarget as HTMLButtonElement,e);
|
||||
}
|
||||
return false;
|
||||
}}
|
||||
onPointerDown={(e) => {
|
||||
@@ -130,19 +220,14 @@ export default function DraggableButtonBase(props: DraggableButtonBaseProps) {
|
||||
setPointerDownPoint(screenToClient(e));
|
||||
|
||||
let currentTarget = e.currentTarget as HTMLButtonElement;
|
||||
if (longPressDelay === undefined || longPressDelay >= 0)
|
||||
{
|
||||
if (longPressDelay === undefined || longPressDelay >= 0) {
|
||||
let delay = longPressDelay ?? 1250;
|
||||
if (instantMouseLongPress === true && e.pointerType === "mouse") {
|
||||
delay = 0;
|
||||
}
|
||||
setHTimeout(window.setTimeout(() => {
|
||||
setHTimeout(null);
|
||||
if (props.onLongPressStart) {
|
||||
if (!props.onLongPressStart(currentTarget,e))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
setLongPressed(true);
|
||||
setSuppressClick(true);
|
||||
}, longPressDelay??1250));
|
||||
startLongPress(currentTarget, e);
|
||||
}, delay));
|
||||
}
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
@@ -150,17 +235,17 @@ export default function DraggableButtonBase(props: DraggableButtonBaseProps) {
|
||||
}}
|
||||
onPointerMove={(e) => {
|
||||
if (e.pointerId === pointerId) {
|
||||
if(longPressed) {
|
||||
if (props.onLongPressMove) {
|
||||
props.onLongPressMove(e);
|
||||
if (longPressed) {
|
||||
if (doLongPressMove) {
|
||||
doLongPressMove(e);
|
||||
}
|
||||
} else {
|
||||
let clientPoint = screenToClient(e);
|
||||
|
||||
let dx = pointerDownPoint.x- clientPoint.x;
|
||||
let dx = pointerDownPoint.x - clientPoint.x;
|
||||
let dy = pointerDownPoint.y - clientPoint.y;
|
||||
if (Math.abs(dx) > 5 || Math.abs(dy) > 5) {
|
||||
cancelLongPress();
|
||||
stopLongPress(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -171,14 +256,8 @@ export default function DraggableButtonBase(props: DraggableButtonBaseProps) {
|
||||
onPointerUp={(e) => {
|
||||
if (e.pointerId === pointerId) {
|
||||
e.currentTarget.releasePointerCapture(e.pointerId);
|
||||
setPointerId(null);
|
||||
if (longPressed) {
|
||||
if (props.onLongPressEnd) {
|
||||
props.onLongPressEnd(e);
|
||||
}
|
||||
}
|
||||
cancelLongPress();
|
||||
if (e.isPropagationStopped()) {
|
||||
stopLongPress(e);
|
||||
if (e.isPropagationStopped() || e.isDefaultPrevented()) {
|
||||
setSuppressClick(true); // only way to cancel the click
|
||||
return;
|
||||
}
|
||||
@@ -187,30 +266,24 @@ export default function DraggableButtonBase(props: DraggableButtonBaseProps) {
|
||||
|
||||
}
|
||||
}}
|
||||
// onTouchStart={(e)=> {
|
||||
// //e.preventDefault();
|
||||
// }}
|
||||
// onTouchMove={(e)=> {
|
||||
// //e.preventDefault();
|
||||
// }}
|
||||
onTouchStart={(e)=> {
|
||||
//e.preventDefault();
|
||||
}}
|
||||
onClick={(e) => {
|
||||
if (clickSuppressed) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
setSuppressClick(false);
|
||||
} else {
|
||||
if (props.onClick) {
|
||||
props.onClick(e);
|
||||
if (onClick) {
|
||||
onClick(e);
|
||||
}
|
||||
}
|
||||
}}
|
||||
onPointerCancelCapture={(e) => {
|
||||
if (pointerId !== null) {
|
||||
e.currentTarget.releasePointerCapture(e.pointerId);
|
||||
if (longPressed && props.onLongPressEnd) {
|
||||
props.onLongPressEnd(e)
|
||||
}
|
||||
cancelLongPress();
|
||||
stopLongPress(e);
|
||||
}
|
||||
}}>
|
||||
{props.children}
|
||||
|
||||
@@ -63,6 +63,13 @@ import HomeIcon from '@mui/icons-material/Home';
|
||||
import FilePropertyDirectorySelectDialog from './FilePropertyDirectorySelectDialog';
|
||||
import { getAlbumArtUri, getTrackTitle } from './AudioFileMetadata';
|
||||
|
||||
|
||||
const AUTOSCROLL_TICK_DELAY = 30;
|
||||
const AUTOSCROLL_THRESHOLD = 48;
|
||||
const AUTOSCROLL_SCROLL_PER_SECOND = 500;
|
||||
const AUTOSCROLL_SCROLL_RATE = AUTOSCROLL_SCROLL_PER_SECOND * AUTOSCROLL_TICK_DELAY / 1000;
|
||||
|
||||
|
||||
interface Point {
|
||||
x: number;
|
||||
y: number;
|
||||
@@ -93,7 +100,7 @@ const audioFileExtensions: { [name: string]: boolean } = {
|
||||
".ra": true
|
||||
};
|
||||
|
||||
function screenToClient(currentTarget: HTMLElement, e: React.PointerEvent): Point {
|
||||
function screenToClient(currentTarget: HTMLElement, e: React.PointerEvent | React.MouseEvent): Point {
|
||||
let rect = currentTarget.getBoundingClientRect();
|
||||
const x = e.clientX + rect.left;
|
||||
const y = e.clientY + rect.right;
|
||||
@@ -157,11 +164,14 @@ export interface FilePropertyDialogState {
|
||||
|
||||
};
|
||||
|
||||
class DragState {
|
||||
activeItem: string = "";
|
||||
height: number = 0;
|
||||
from: number = 0;
|
||||
to: number = 0;
|
||||
interface DragState {
|
||||
activeItem: string;
|
||||
height: number;
|
||||
dragElement: HTMLElement;
|
||||
dragElementDy: number;
|
||||
from: number;
|
||||
to: number;
|
||||
lastMousePoint: Point;
|
||||
};
|
||||
|
||||
export default withStyles(
|
||||
@@ -323,8 +333,6 @@ export default withStyles(
|
||||
|
||||
longPressStartPoint: Point | null = null;
|
||||
|
||||
dragFromPosition: number = -1;
|
||||
dragToPosition: number = -1;
|
||||
maxPosition: number = 0;
|
||||
|
||||
handleMultisSelectClose() {
|
||||
@@ -336,24 +344,29 @@ export default withStyles(
|
||||
|
||||
handleLongPressStart(
|
||||
currentTarget: HTMLButtonElement,
|
||||
e: React.PointerEvent<HTMLButtonElement>,
|
||||
e: React.PointerEvent<HTMLButtonElement> | React.MouseEvent<HTMLButtonElement>,
|
||||
fileEntry: FileEntry): boolean {
|
||||
if (this.state.reordering) {
|
||||
|
||||
if (!this.isTracksDirectory()) {
|
||||
return false;
|
||||
}
|
||||
this.dragFromPosition = parseInt(currentTarget.getAttribute("data-position") as string, 10);
|
||||
this.dragToPosition = this.dragToPosition;
|
||||
let element = currentTarget;
|
||||
element.style.position = "relative";
|
||||
element.style.zIndex = "1000";
|
||||
element.style.top = "5px";
|
||||
element.style.left = "5px";
|
||||
element.style.background = isDarkMode() ? "#555" : "#EEF" // xxx: dark mode.
|
||||
let index = parseInt(element.getAttribute("data-position") as string, 10);
|
||||
if (this.listContainerElementRef) {
|
||||
this.longPressStartPoint = screenToClient(currentTarget,e);
|
||||
this.longPressStartPoint = screenToClient(currentTarget, e);
|
||||
let dragState: DragState = {
|
||||
activeItem: fileEntry.pathname,
|
||||
dragElement: element,
|
||||
height: element.clientHeight,
|
||||
dragElementDy: 0,
|
||||
from: index,
|
||||
to: index,
|
||||
lastMousePoint: {...this.longPressStartPoint}
|
||||
};
|
||||
this.setState({ dragState: dragState });
|
||||
}
|
||||
|
||||
return true;
|
||||
} else if (!this.state.multiSelect) {
|
||||
if (fileEntry.isProtected) {
|
||||
@@ -370,6 +383,48 @@ export default withStyles(
|
||||
return false;
|
||||
|
||||
}
|
||||
dragTarget: HTMLButtonElement | null = null;
|
||||
|
||||
|
||||
updateReorderPosition(element: HTMLButtonElement, point: Point) {
|
||||
if (this.longPressStartPoint) {
|
||||
let dragDy = point.y - this.longPressStartPoint.y;
|
||||
let height = element.clientHeight;
|
||||
|
||||
let dragFromPosition = parseInt(element.getAttribute("data-position") as string, 10);
|
||||
|
||||
let elementOffset = dragFromPosition * height;
|
||||
let newOffset = elementOffset + dragDy;
|
||||
if (newOffset < 0) {
|
||||
dragDy = -elementOffset;
|
||||
newOffset = 0;
|
||||
}
|
||||
let maxOffset = (this.maxPosition - 1) * height;
|
||||
if (newOffset > maxOffset) {
|
||||
dragDy = maxOffset - elementOffset;
|
||||
newOffset = maxOffset;
|
||||
}
|
||||
let toPosition = Math.floor((newOffset + height / 2) / height);
|
||||
if (toPosition < 0) {
|
||||
toPosition = 0;
|
||||
}
|
||||
if (toPosition > this.maxPosition) {
|
||||
toPosition = this.maxPosition;
|
||||
}
|
||||
// console.log("drag from " + dragFromPosition + " to " + toPosition + " dy: " + dragDy);
|
||||
this.setState({
|
||||
dragState: {
|
||||
activeItem: element.getAttribute("data-pathname") || "",
|
||||
dragElement: element,
|
||||
height: height,
|
||||
dragElementDy: dragDy,
|
||||
from: dragFromPosition,
|
||||
to: toPosition,
|
||||
lastMousePoint: point
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
handleLongPressMove(e: React.PointerEvent<HTMLButtonElement>) {
|
||||
if (this.state.reordering) {
|
||||
if (!this.isTracksDirectory()) {
|
||||
@@ -377,37 +432,10 @@ export default withStyles(
|
||||
}
|
||||
if (this.listContainerElementRef) {
|
||||
let element = e.target as HTMLButtonElement;
|
||||
let point = screenToClient(e.currentTarget,e);
|
||||
if (this.longPressStartPoint) {
|
||||
let dy = point.y - this.longPressStartPoint.y;
|
||||
element.style.left = (5) + "px";
|
||||
element.style.top = (5 + dy) + "px";
|
||||
let height = element.clientHeight;
|
||||
let positionChange_: number = 0;
|
||||
if (dy > 0) {
|
||||
positionChange_ = Math.floor((dy + height / 2) / height);
|
||||
} else {
|
||||
positionChange_ = Math.ceil((dy - height / 2) / height)
|
||||
}
|
||||
let toPosition = this.dragFromPosition + positionChange_;
|
||||
if (toPosition < 0) {
|
||||
toPosition = 0;
|
||||
}
|
||||
if (toPosition > this.maxPosition) {
|
||||
toPosition = this.maxPosition;
|
||||
}
|
||||
if (toPosition !== this.dragToPosition) {
|
||||
this.dragToPosition = toPosition;
|
||||
this.setState({
|
||||
dragState: {
|
||||
activeItem: element.getAttribute("data-pathname") || "",
|
||||
height: height,
|
||||
from: this.dragFromPosition,
|
||||
to: toPosition
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
let point = screenToClient(e.currentTarget, e);
|
||||
this.updateReorderPosition(element, point);
|
||||
this.startAutoScroll()
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -457,7 +485,7 @@ export default withStyles(
|
||||
this.model.moveAudioFile(
|
||||
this.state.currentDirectory, from, to);
|
||||
}
|
||||
handleLongPressEnd(e: React.PointerEvent<HTMLButtonElement>, fileEntry: FileEntry) {
|
||||
handleLongPressEnd(e: React.PointerEvent<HTMLButtonElement> | React.MouseEvent<HTMLButtonElement>, fileEntry: FileEntry) {
|
||||
if (this.state.reordering) {
|
||||
if (!this.isTracksDirectory()) {
|
||||
return;
|
||||
@@ -471,14 +499,8 @@ export default withStyles(
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
let element = e.currentTarget as HTMLButtonElement;
|
||||
|
||||
element.style.position = "";
|
||||
element.style.zIndex = "";
|
||||
element.style.top = "";
|
||||
element.style.left = "";
|
||||
element.style.background = ""; // xxx: dark mode.
|
||||
this.setState({ dragState: null });
|
||||
this.stopAutoScroll();
|
||||
} else if (!this.state.multiSelect) {
|
||||
let selectedFile = fileEntry.pathname;
|
||||
if (selectedFile === "") {
|
||||
@@ -526,6 +548,7 @@ export default withStyles(
|
||||
this.requestScroll = true;
|
||||
}
|
||||
componentWillUnmount() {
|
||||
this.stopAutoScroll();
|
||||
this.cancelProgressTimeout();
|
||||
|
||||
super.componentWillUnmount();
|
||||
@@ -925,7 +948,98 @@ export default withStyles(
|
||||
return (<InsertDriveFileIcon style={style} />);
|
||||
}
|
||||
|
||||
listContainerElementRef: HTMLDivElement | null = null;
|
||||
private listContainerElementRef: HTMLDivElement | null = null;
|
||||
private scrollContainerElementRef: HTMLDivElement | null = null;
|
||||
private autoScrollTimer: number | null = null;
|
||||
|
||||
handleAutoScrollTick() {
|
||||
let dragState = this.state.dragState;
|
||||
if (!dragState) return;
|
||||
|
||||
let scrollContainer = this.scrollContainerElementRef;
|
||||
if (!scrollContainer) {
|
||||
return;
|
||||
}
|
||||
let scrollBounds_ = scrollContainer.getBoundingClientRect();
|
||||
let scrollClientTop = scrollBounds_.top;
|
||||
let scrollClientBottom = scrollClientTop + scrollContainer.clientHeight;
|
||||
let dragBounds = dragState.dragElement?.getBoundingClientRect();
|
||||
|
||||
let dy = 0;
|
||||
let y = scrollContainer.scrollTop;
|
||||
if (dragBounds.top < scrollClientTop + AUTOSCROLL_THRESHOLD) {
|
||||
dy = -AUTOSCROLL_SCROLL_RATE;
|
||||
|
||||
y = scrollContainer.scrollTop + dy;
|
||||
if (y < 0) y = 0;
|
||||
dy = y - scrollContainer.scrollTop;
|
||||
} else if (dragBounds.bottom > scrollClientBottom - AUTOSCROLL_THRESHOLD) {
|
||||
dy = AUTOSCROLL_SCROLL_RATE;
|
||||
|
||||
y = scrollContainer.scrollTop + dy;
|
||||
let maxScrollTop = scrollContainer.scrollHeight - scrollContainer.clientHeight;
|
||||
if (y > maxScrollTop) {
|
||||
y = maxScrollTop;
|
||||
}
|
||||
dy = y - scrollContainer.scrollTop;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
if (this.longPressStartPoint === null) {
|
||||
return;
|
||||
}
|
||||
if (dy === 0) {
|
||||
return;
|
||||
}
|
||||
this.longPressStartPoint = {
|
||||
x: this.longPressStartPoint.x,
|
||||
y: this.longPressStartPoint.y - dy
|
||||
};
|
||||
let dragElementDy = dragState.lastMousePoint.y - this.longPressStartPoint.y;
|
||||
let originalY = dragState.from * dragState.height;
|
||||
let newY = originalY + dragElementDy;
|
||||
if (newY < 0)
|
||||
{
|
||||
newY = 0;
|
||||
dragElementDy = -originalY;
|
||||
}
|
||||
let maxDy = (this.maxPosition - 1) * dragState.height;
|
||||
if (newY > maxDy) {
|
||||
newY = maxDy;
|
||||
dragElementDy = maxDy - originalY;
|
||||
}
|
||||
let newTo = Math.floor((newY + dragState.height / 2) / dragState.height);
|
||||
|
||||
|
||||
let newDragState = { ...dragState };
|
||||
|
||||
newDragState.dragElementDy = dragElementDy;
|
||||
newDragState.to = newTo;
|
||||
|
||||
// console.log("autoscroll from " + dragState.from + " to " + newTo + " dy: " + dragElementDy);
|
||||
// avoid jitter.
|
||||
newDragState.dragElement.style.top = (newDragState.dragElementDy + 5) + "px";
|
||||
|
||||
this.setState({ dragState: newDragState });
|
||||
scrollContainer.scrollTo({ left: 0, top: y, behavior: "instant" });
|
||||
this.startAutoScroll();
|
||||
|
||||
}
|
||||
|
||||
|
||||
stopAutoScroll() {
|
||||
if (this.autoScrollTimer !== null) {
|
||||
clearTimeout(this.autoScrollTimer);
|
||||
this.autoScrollTimer = null;
|
||||
}
|
||||
}
|
||||
startAutoScroll() {
|
||||
this.stopAutoScroll();
|
||||
|
||||
this.autoScrollTimer = setTimeout(
|
||||
() => { this.handleAutoScrollTick() }, AUTOSCROLL_TICK_DELAY);
|
||||
}
|
||||
|
||||
|
||||
render() {
|
||||
const isTracksDirectory = this.isTracksDirectory();
|
||||
@@ -1146,7 +1260,9 @@ export default withStyles(
|
||||
<DialogContent style={{
|
||||
paddingLeft: 0, paddingRight: 0, paddingTop: 0, colorScheme: (isDarkMode() ? "dark" : "light"),
|
||||
position: "relative"
|
||||
}}>
|
||||
}}
|
||||
ref={(element: HTMLDivElement | null) => { this.scrollContainerElementRef = element; }}
|
||||
>
|
||||
|
||||
<div style={{
|
||||
paddingLeft: 16, paddingRight: 16, paddingTop: 8, paddingBottom: 8,
|
||||
@@ -1210,7 +1326,10 @@ export default withStyles(
|
||||
scrollRef = (element) => { this.onScrollRef(element) };
|
||||
}
|
||||
let dragOffset = 0;
|
||||
let dragLeft = 0;
|
||||
let dragState = this.state.dragState;
|
||||
let zIndex: number | undefined = undefined;
|
||||
let background: string | undefined = undefined;
|
||||
if (dragState && value.metadata) {
|
||||
if (myTrackPosition !== dragState.from) {
|
||||
if (myTrackPosition >= dragState.to && myTrackPosition < dragState.from) {
|
||||
@@ -1218,21 +1337,31 @@ export default withStyles(
|
||||
} else if (myTrackPosition > dragState.from && myTrackPosition <= dragState.to) {
|
||||
dragOffset = -dragState.height;
|
||||
}
|
||||
} else {
|
||||
dragOffset = dragState.dragElementDy + 5;
|
||||
dragLeft = 5;
|
||||
zIndex = 1000;
|
||||
background = isDarkMode() ? "#555" : "#EEF";
|
||||
}
|
||||
}
|
||||
let dragButtonStyle: React.CSSProperties = {
|
||||
width: columnWidth, flex: "0 0 auto", height: (value.metadata && !compactVertical) ? 64 : 48,
|
||||
position: "relative",
|
||||
top: dragOffset,
|
||||
left: dragLeft,
|
||||
zIndex: zIndex,
|
||||
background: background,
|
||||
};
|
||||
return (
|
||||
<DraggableButtonBase key={value.pathname}
|
||||
longPressDelay={this.state.reordering ? 0 : undefined}
|
||||
longPressDelay={this.state.reordering ? 300 : undefined}
|
||||
data-position={dataPosition}
|
||||
data-pathname={
|
||||
value.metadata ? value.metadata.fileName : null
|
||||
}
|
||||
instantMouseLongPress={this.state.reordering}
|
||||
|
||||
style={{
|
||||
width: columnWidth, flex: "0 0 auto", height: (value.metadata && !compactVertical) ? 64 : 48,
|
||||
position: "relative",
|
||||
top: dragOffset + "px",
|
||||
}}
|
||||
style={dragButtonStyle}
|
||||
onClick={(e) => this.handleFileClick(e, value)}
|
||||
onDoubleClick={() => { this.onDoubleClickValue(value.pathname); }}
|
||||
|
||||
@@ -1559,7 +1688,7 @@ export default withStyles(
|
||||
await this.model.renameFilePropertyFile(oldFilePath, newFilePath, this.props.fileProperty);
|
||||
let index = newFileList.indexOf(file);
|
||||
if (index !== -1) {
|
||||
newFileList.splice(index,1);
|
||||
newFileList.splice(index, 1);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1570,8 +1699,7 @@ export default withStyles(
|
||||
if (!this.mounted) {
|
||||
return;
|
||||
}
|
||||
if (newFileList.length === 0 )
|
||||
{
|
||||
if (newFileList.length === 0) {
|
||||
this.setState({
|
||||
multiSelect: false,
|
||||
selectedFiles: []
|
||||
|
||||
@@ -81,7 +81,7 @@ function ToolTipEx(props: ToolTipExProps) {
|
||||
if (valueTooltip === undefined) // no timeout if there's a value tooltip
|
||||
{
|
||||
if (t > 0) {
|
||||
console.log("ToolTipEx: starting timeout for ", t);
|
||||
// console.log("ToolTipEx: starting timeout for ", t);
|
||||
handle = window.setTimeout(() => {
|
||||
setOpen(true);
|
||||
},t);
|
||||
@@ -89,7 +89,7 @@ function ToolTipEx(props: ToolTipExProps) {
|
||||
}
|
||||
return () => {
|
||||
if (handle !== null) {
|
||||
console.log("ToolTipEx: clearing timeout for ", t);
|
||||
// console.log("ToolTipEx: clearing timeout for ", t);
|
||||
window.clearTimeout(handle);
|
||||
}
|
||||
};
|
||||
@@ -181,39 +181,39 @@ function ToolTipEx(props: ToolTipExProps) {
|
||||
return (
|
||||
<div
|
||||
onClickCapture={(e) => {
|
||||
console.log("ToolTipEx: onClickCapture");
|
||||
// console.log("ToolTipEx: onClickCapture");
|
||||
handleClickCapture(e);
|
||||
}}
|
||||
|
||||
onMouseEnter={(e)=> {
|
||||
console.log("ToolTipEx: onMouseEnter");
|
||||
// console.log("ToolTipEx: onMouseEnter");
|
||||
|
||||
handleMouseEnter(e);
|
||||
}}
|
||||
onMouseLeave={(e)=> {
|
||||
console.log("ToolTipEx: onMouseLeave");
|
||||
// console.log("ToolTipEx: onMouseLeave");
|
||||
handleMouseLeave(e);
|
||||
}}
|
||||
|
||||
onPointerCancelCapture={(e) => {
|
||||
console.log("ToolTipEx: onPointerCancelCapture");
|
||||
// console.log("ToolTipEx: onPointerCancelCapture");
|
||||
handlePointerCancel(e);
|
||||
}}
|
||||
onContextMenuCapture={(e) => {
|
||||
console.log("ToolTipEx: onContextMenuCapture");
|
||||
// console.log("ToolTipEx: onContextMenuCapture");
|
||||
handleConextMenu(e);
|
||||
return false;
|
||||
}}
|
||||
onPointerDownCapture={(e) => {
|
||||
console.log("ToolTipEx: onPointerDownCapture");
|
||||
// console.log("ToolTipEx: onPointerDownCapture");
|
||||
handlePointerDownCapture(e);
|
||||
}}
|
||||
onPointerMoveCapture={(e) => {
|
||||
console.log("ToolTipEx: onPointerMoveCapture");
|
||||
// console.log("ToolTipEx: onPointerMoveCapture");
|
||||
handlePointerMoveCapture(e);
|
||||
}}
|
||||
onPointerUpCapture={(e) => {
|
||||
console.log("ToolTipEx: onPointerUpCapture");
|
||||
// console.log("ToolTipEx: onPointerUpCapture");
|
||||
handlePointerUpCapture(e);
|
||||
}}
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user