Skip to content

Commit

Permalink
Merge pull request #10736 from fcannizzaro/add-stream-deck-selection-…
Browse files Browse the repository at this point in the history
…deep-link

Add Stream Deck deep-link selection
  • Loading branch information
bhollis authored Oct 28, 2024
2 parents 9a94491 + 6637301 commit cc83e8e
Show file tree
Hide file tree
Showing 17 changed files with 148 additions and 97 deletions.
3 changes: 3 additions & 0 deletions config/i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -821,6 +821,7 @@
"Redo": "Redo",
"RestoreAllItems": "All Items",
"Save": "Save",
"OpenOnStreamDeck": "Open on Stream Deck",
"SaveLoadout": "Save Loadout",
"UpdateLoadout": "Update Loadout",
"SaveAsDIM": "Save as DIM Loadout",
Expand Down Expand Up @@ -1001,6 +1002,7 @@
"Rewards": "Rewards:",
"SendToVault": "Send to Vault",
"Store": "Pull to:",
"OpenOnStreamDeck": "Open on Stream Deck",
"StoreWithName": "Pull to {{character}}",
"Subtitle": {
"Type": "{{classType}} {{typeName}}",
Expand Down Expand Up @@ -1369,6 +1371,7 @@
"Others": "{{count}}x Ghost Projection"
},
"StreamDeck": {
"name": "Stream Deck",
"Tooltip": {
"Title": "DIM Stream Deck Plugin",
"Version": "Version:",
Expand Down
13 changes: 0 additions & 13 deletions src/app/inventory/DraggableInventoryItem.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import { hideItemPopup } from 'app/item-popup/item-popup';
import { useStreamDeckSelection } from 'app/stream-deck/stream-deck';
import clsx from 'clsx';
import { BucketHashes } from 'data/d2/generated-enums';
import React from 'react';
import { useDrag } from 'react-dnd';
import styles from './DraggableInventoryItem.m.scss';
Expand All @@ -17,16 +15,6 @@ interface Props {
let dragTimeout: number | null = null;

export default function DraggableInventoryItem({ children, item, anyBucket = false }: Props) {
const selectionProps = $featureFlags.elgatoStreamDeck
? // eslint-disable-next-line
useStreamDeckSelection({
type: 'item',
item,
isSubClass: item.bucket.hash === BucketHashes.Subclass,
equippable: !item.notransfer,
})
: undefined;

const canDrag =
(!item.location.inPostmaster || item.destinyVersion === 2) && item.notransfer
? item.equipment
Expand Down Expand Up @@ -65,7 +53,6 @@ export default function DraggableInventoryItem({ children, item, anyBucket = fal
return (
<div
ref={dragRef}
{...selectionProps}
className={clsx('item-drag-container', {
[styles.engram]: item.isEngram,
[styles.cantDrag]: !canDrag,
Expand Down
20 changes: 20 additions & 0 deletions src/app/item-actions/ItemAccessoryButtons.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { DimItem } from 'app/inventory/item-types';
import { ItemActionsModel } from 'app/item-popup/item-popup-actions';
import { streamDeckEnabledSelector } from 'app/stream-deck/selectors';
import { lazy, Suspense } from 'react';
import { useSelector } from 'react-redux';
import {
CompareActionButton,
ConsolidateActionButton,
Expand All @@ -10,6 +13,13 @@ import {
TagActionButton,
} from './ActionButtons';

const OpenOnStreamDeckButton = lazy(
() =>
import(
/* webpackChunkName: "send-to-stream-deck-button" */ 'app/stream-deck/OpenOnStreamDeckButton/OpenOnStreamDeckButton'
),
);

/**
* "Accessory" buttons like tagging, locking, comparing, adding to loadout. Displayed separately on mobile, but together with the move actions on desktop.
*/
Expand All @@ -24,6 +34,11 @@ export default function ItemAccessoryButtons({
showLabel: boolean;
actionsModel: ItemActionsModel;
}) {
const streamDeckEnabled = $featureFlags.elgatoStreamDeck
? // eslint-disable-next-line react-hooks/rules-of-hooks
useSelector(streamDeckEnabledSelector)
: false;

return (
<>
{actionsModel.taggable && (
Expand All @@ -43,6 +58,11 @@ export default function ItemAccessoryButtons({
{actionsModel.infusable && (
<InfuseActionButton item={item} label={showLabel} actionModel={actionsModel} />
)}
{streamDeckEnabled && (
<Suspense>
<OpenOnStreamDeckButton label={showLabel} item={item} />
</Suspense>
)}
</>
);
}
4 changes: 0 additions & 4 deletions src/app/loadout/LoadoutView.m.scss
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,3 @@
.artifactMods {
--item-size: 40px;
}

.disableEvents > div {
pointer-events: none;
}
1 change: 0 additions & 1 deletion src/app/loadout/LoadoutView.m.scss.d.ts

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

18 changes: 1 addition & 17 deletions src/app/loadout/LoadoutView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,11 @@ import { getLight } from 'app/loadout-drawer/loadout-utils';
import { Loadout, LoadoutItem, ResolvedLoadoutItem } from 'app/loadout/loadout-types';
import AppIcon from 'app/shell/icons/AppIcon';
import { useIsPhonePortrait } from 'app/shell/selectors';
import { useStreamDeckSelection } from 'app/stream-deck/stream-deck';
import { filterMap, isEmpty } from 'app/utils/collections';
import { emptyObject } from 'app/utils/empty';
import { itemCanBeEquippedBy } from 'app/utils/item-utils';
import { addDividers } from 'app/utils/react';
import { DestinyClass } from 'bungie-api-ts/destiny2';
import clsx from 'clsx';
import { BucketHashes } from 'data/d2/generated-enums';
import { ReactNode, useMemo } from 'react';
import { useSelector } from 'react-redux';
Expand Down Expand Up @@ -120,22 +118,8 @@ export default function LoadoutView({
);
const power = loadoutPower(store, loadoutItemsByCategory);

const selectionProps = $featureFlags.elgatoStreamDeck
? // eslint-disable-next-line
useStreamDeckSelection({
type: 'loadout',
loadout,
store,
equippable: !hideShowModPlacements,
})
: undefined;

return (
<div
className={clsx(styles.loadout, selectionProps?.ref && styles.disableEvents)}
id={loadout.id}
{...selectionProps}
>
<div className={styles.loadout} id={loadout.id}>
<div className={styles.title}>
<h2>
{$featureFlags.editInGameLoadoutIdentifiers && loadout.parameters?.inGameIdentifiers && (
Expand Down
32 changes: 31 additions & 1 deletion src/app/loadout/LoadoutsRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { deleteLoadout } from 'app/loadout/actions';
import { Loadout } from 'app/loadout/loadout-types';
import { AppIcon, deleteIcon } from 'app/shell/icons';
import { useThunkDispatch } from 'app/store/thunk-dispatch';
import { useStreamDeckSelection } from 'app/stream-deck/stream-deck';
import { ReactNode, memo, useMemo } from 'react';
import LoadoutView from './LoadoutView';

Expand All @@ -30,6 +31,16 @@ export default memo(function LoadoutRow({
}) {
const dispatch = useThunkDispatch();

const streamDeckDeepLink = $featureFlags.elgatoStreamDeck
? // eslint-disable-next-line
useStreamDeckSelection({
type: 'loadout',
loadout,
store,
equippable,
})
: undefined;

const actionButtons = useMemo(() => {
const handleDeleteClick = () => dispatch(deleteLoadout(loadout.id));

Expand Down Expand Up @@ -71,6 +82,16 @@ export default memo(function LoadoutRow({
</button>,
);

if (streamDeckDeepLink) {
actionButtons.push(
<a href={streamDeckDeepLink} target="_blank">
<button key="open-on-stream-deck" type="button" className="dim-button">
{t('Loadouts.OpenOnStreamDeck')}
</button>
</a>,
);
}

if (saved) {
actionButtons.push(
<ConfirmButton key="delete" danger onClick={handleDeleteClick}>
Expand All @@ -91,7 +112,16 @@ export default memo(function LoadoutRow({
}

return actionButtons;
}, [dispatch, equippable, loadout, onShare, onSnapshotInGameLoadout, saved, store]);
}, [
dispatch,
equippable,
loadout,
onShare,
onSnapshotInGameLoadout,
saved,
store,
streamDeckDeepLink,
]);

return (
<LoadoutView
Expand Down
35 changes: 18 additions & 17 deletions src/app/loadout/ingame/InGameLoadoutStrip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,15 @@ function InGameLoadoutTile({
onShare(dimLoadout);
};

const streamDeckDeepLink = $featureFlags.elgatoStreamDeck
? // eslint-disable-next-line
useStreamDeckSelection({
type: 'in-game-loadout',
equippable: true,
loadout: gameLoadout,
})
: undefined;

const options: Option[] = compact([
{
key: 'details',
Expand Down Expand Up @@ -124,6 +133,11 @@ function InGameLoadoutTile({
content: t('Loadouts.ShareLoadout'),
onSelected: handleShare,
},
streamDeckDeepLink && {
key: 'open-on-stream-deck',
content: t('Loadouts.OpenOnStreamDeck'),
onSelected: () => window.open(streamDeckDeepLink),
},
{
key: 'delete',
content: (
Expand Down Expand Up @@ -174,18 +188,9 @@ function InGameLoadoutTile({
);
}

const selectionProps = $featureFlags.elgatoStreamDeck
? // eslint-disable-next-line
useStreamDeckSelection({
type: 'in-game-loadout',
equippable: true,
loadout: gameLoadout,
})
: undefined;

const loadoutIcon = (
<div className={styles.inGameTile} onClick={() => onShowDetails(gameLoadout)}>
<div {...selectionProps} className={styles.igtIconHolder}>
<div className={styles.igtIconHolder}>
<InGameLoadoutIconWithIndex loadout={gameLoadout} className={styles.igtIcon} size={32} />{' '}
</div>
<AppIcon
Expand All @@ -204,13 +209,9 @@ function InGameLoadoutTile({
key={gameLoadout.index}
className={clsx(styles.inGameTileWrapper, { [styles.isEquipped]: isEquipped })}
>
{selectionProps?.ref ? (
loadoutIcon
) : (
<PressTip tooltip={tooltipContent.length ? tooltipContent : null} placement="bottom">
{loadoutIcon}
</PressTip>
)}
<PressTip tooltip={tooltipContent.length ? tooltipContent : null} placement="bottom">
{loadoutIcon}
</PressTip>
<Dropdown
label={t('Loadouts.InGameActions')}
kebab
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
.icon {
margin-right: 8px;
}

.link {
text-decoration: none;
}

.link span {
padding-right: 8px;
}

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

Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { t } from 'app/i18next-t';
import { DimItem } from 'app/inventory/item-types';
import ActionButton from 'app/item-actions/ActionButton';
import { BucketHashes } from 'data/d2/generated-enums';
import streamDeckIcon from 'images/streamDeck.svg';
import { useStreamDeckSelection } from '../stream-deck';
import styles from './OpenOnStreamDeckButton.m.scss';

export default function OpenOnStreamDeckButton({ item, label }: { item: DimItem; label: boolean }) {
const deepLink = useStreamDeckSelection({
type: 'item',
item,
isSubClass: item.bucket.hash === BucketHashes.Subclass,
equippable: !item.notransfer,
});

if (!deepLink) {
return null;
}

return (
<a href={deepLink} target="_blank" className={styles.link}>
<ActionButton onClick={() => null}>
<img src={streamDeckIcon} className={styles.icon} />
{label && <span>{t('MovePopup.OpenOnStreamDeck')}</span>}
</ActionButton>
</a>
);
}
2 changes: 1 addition & 1 deletion src/app/stream-deck/StreamDeckButton/StreamDeckButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ function StreamDeckButton() {
className={styles.streamDeckButton}
title={t('StreamDeck.Tooltip.Title')}
>
<img src={streamDeckIcon} className="stream-deck-img" />
<img src={streamDeckIcon} />
{error ? (
<div className={styles.error}>
<AppIcon icon={banIcon} />
Expand Down
2 changes: 1 addition & 1 deletion src/app/stream-deck/stream-deck.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,4 @@ export const startStreamDeckConnection = () => lazyLoaded.start!();
export const stopStreamDeckConnection = () => lazyLoaded.stop!();

export const useStreamDeckSelection: UseStreamDeckSelectionFn = (...args) =>
lazyLoaded.useSelection?.(...args) ?? {};
lazyLoaded.useSelection?.(...args);
Loading

0 comments on commit cc83e8e

Please sign in to comment.