Skip to content

Commit

Permalink
Merge pull request #10894 from DestinyItemManager/restore-drag-perf
Browse files Browse the repository at this point in the history
  • Loading branch information
bhollis authored Jan 15, 2025
2 parents 301d306 + 5477d76 commit fc53ee2
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/app/inventory-page/Inventory.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { DestinyAccount } from 'app/accounts/destiny-account';
import ShowPageLoading from 'app/dim-ui/ShowPageLoading';
import GearPower from 'app/gear-power/GearPower';
import { t } from 'app/i18next-t';
import DragPerformanceFix from 'app/inventory/DragPerformanceFix';
import { useLoadStores } from 'app/inventory/store/hooks';
import { MaterialCountsSheet } from 'app/material-counts/MaterialCountsWrappers';
import { usePageTitle } from 'app/utils/hooks';
Expand All @@ -18,6 +19,7 @@ export default function Inventory({ account }: { account: DestinyAccount }) {
return (
<>
<Stores />
<DragPerformanceFix />
{account.destinyVersion === 2 && <GearPower />}
{account.destinyVersion === 2 && <MaterialCountsSheet />}
</>
Expand Down
2 changes: 2 additions & 0 deletions src/app/inventory-page/StoreBucketDropTarget.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { hideDragFixOverlay } from 'app/inventory/DragPerformanceFix';
import { InventoryBucket } from 'app/inventory/inventory-buckets';
import { DimItem } from 'app/inventory/item-types';
import { dropItem } from 'app/inventory/move-item';
Expand Down Expand Up @@ -64,6 +65,7 @@ export default function StoreBucketDropTarget({
[styles.canDrop]: canDrop,
[styles.grouped]: grouped,
})}
onClick={hideDragFixOverlay}
aria-label={bucket.name}
>
{children}
Expand Down
44 changes: 44 additions & 0 deletions src/app/inventory/DragPerformanceFix.m.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// A div that overlays the whole inventory to block hit-testing during drag.
// Note the z-index which should be above all other elements. Except for the
// sub-bucket overlays.
.dragPerfFix {
// to test, set a nonzero opacity and a background color
opacity: 0;

position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;

z-index: 8;

display: none;

.dragPerfShow & {
display: block;
}
}

// Each sub-bucket (inventory drag target) gets its own overlay as well, with a
// z-index one higher than the global overlay. This allows them to still receive
// drag events.
:global(.sub-bucket) {
&::before {
content: '';

// to test, set a nonzero opacity and a background color
opacity: 0;
width: 100%;
height: 100%;
position: absolute;

z-index: 9;

display: none;

.dragPerfShow & {
display: block;
}
}
}
8 changes: 8 additions & 0 deletions src/app/inventory/DragPerformanceFix.m.scss.d.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

27 changes: 27 additions & 0 deletions src/app/inventory/DragPerformanceFix.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import styles from './DragPerformanceFix.m.scss';

/**
* This is a workaround for sluggish dragging in Chrome on Windows. It may or
* may not be related to Logitech mouse drivers or high-DPI mice, but in Chrome
* on Windows only, some users experience a problem where they can drag items,
* but the drag targets do not get events very quickly, so it may take a second
* or two of hovering over a drop target to make it light up. This was still a
* problem as of January 2025.
*
* This workaround is to put a full-screen invisible div over the entire app,
* and then put separate invisible divs over each drop target. That simplifies
* the hit-testing Chrome has to do, and makes dragging feel normal.
*/
export default function DragPerformanceFix() {
// Rarely (possibly never in typical usage), a browser will forget to dispatch the dragEnd event
// So we try not to trap the user here by allowing them to click away the overlay.
return <div className={styles.dragPerfFix} onClick={hideDragFixOverlay} />;
}

export function showDragFixOverlay() {
document.body.classList.add(styles.dragPerfShow);
}

export function hideDragFixOverlay() {
document.body.classList.remove(styles.dragPerfShow);
}
11 changes: 11 additions & 0 deletions src/app/inventory/DraggableInventoryItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { hideItemPopup } from 'app/item-popup/item-popup';
import clsx from 'clsx';
import React from 'react';
import { useDrag } from 'react-dnd';
import { hideDragFixOverlay, showDragFixOverlay } from './DragPerformanceFix';
import styles from './DraggableInventoryItem.m.scss';
import { isDragging$ } from './drag-events';
import { DimItem } from './item-types';
Expand All @@ -12,6 +13,8 @@ interface Props {
children?: React.ReactNode;
}

let dragTimeout: number | null = null;

export default function DraggableInventoryItem({ children, item, anyBucket = false }: Props) {
const canDrag =
(!item.location.inPostmaster || item.destinyVersion === 2) && item.notransfer
Expand All @@ -28,10 +31,18 @@ export default function DraggableInventoryItem({ children, item, anyBucket = fal
: item.bucket.hash.toString(),
item: () => {
hideItemPopup();
dragTimeout = requestAnimationFrame(() => {
dragTimeout = null;
showDragFixOverlay();
});
isDragging$.next(true);
return item;
},
end: () => {
if (dragTimeout !== null) {
cancelAnimationFrame(dragTimeout);
}
hideDragFixOverlay();
isDragging$.next(false);
},
canDrag,
Expand Down

0 comments on commit fc53ee2

Please sign in to comment.