mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-13 20:10:07 +02:00
add list playback and navigation hotkeys (#1469)
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
import { useNavigate } from 'react-router';
|
||||
|
||||
import { getTitlePath } from '/@/renderer/components/item-list/helpers/get-title-path';
|
||||
import {
|
||||
ItemListStateActions,
|
||||
ItemListStateItemWithRequiredProperties,
|
||||
} from '/@/renderer/components/item-list/helpers/item-list-state';
|
||||
import { ItemControls } from '/@/renderer/components/item-list/types';
|
||||
import { useHotkeySettings, usePlayButtonBehavior } from '/@/renderer/store';
|
||||
import { useHotkeys } from '/@/shared/hooks/use-hotkeys';
|
||||
import { LibraryItem } from '/@/shared/types/domain-types';
|
||||
import { Play } from '/@/shared/types/types';
|
||||
|
||||
export const useListHotkeys = ({
|
||||
controls,
|
||||
focused,
|
||||
internalState,
|
||||
itemType,
|
||||
}: {
|
||||
controls: ItemControls;
|
||||
focused: boolean;
|
||||
internalState: ItemListStateActions;
|
||||
itemType: LibraryItem;
|
||||
}) => {
|
||||
const { bindings } = useHotkeySettings();
|
||||
const playButtonBehavior = usePlayButtonBehavior();
|
||||
const navigate = useNavigate();
|
||||
|
||||
// Helper to check if item has required properties
|
||||
const hasRequiredStateItemProperties = (
|
||||
item: unknown,
|
||||
): item is ItemListStateItemWithRequiredProperties => {
|
||||
return (
|
||||
typeof item === 'object' &&
|
||||
item !== null &&
|
||||
'id' in item &&
|
||||
typeof (item as any).id === 'string' &&
|
||||
'_serverId' in item &&
|
||||
typeof (item as any)._serverId === 'string' &&
|
||||
'_itemType' in item &&
|
||||
typeof (item as any)._itemType === 'string'
|
||||
);
|
||||
};
|
||||
|
||||
useHotkeys([
|
||||
[
|
||||
'mod+a',
|
||||
() => {
|
||||
if (focused) {
|
||||
if (internalState.isAllSelected()) {
|
||||
internalState.deselectAll();
|
||||
} else {
|
||||
internalState.selectAll();
|
||||
}
|
||||
}
|
||||
},
|
||||
],
|
||||
[
|
||||
bindings.listPlayDefault.hotkey,
|
||||
() => {
|
||||
if (!focused) return;
|
||||
const selected = internalState.getSelected();
|
||||
const validSelected = selected.filter(hasRequiredStateItemProperties);
|
||||
if (validSelected.length === 0) return;
|
||||
|
||||
const item = validSelected[0];
|
||||
const playType = playButtonBehavior;
|
||||
controls.onPlay?.({ item, itemType, playType } as any);
|
||||
},
|
||||
],
|
||||
[
|
||||
bindings.listPlayNow.hotkey,
|
||||
() => {
|
||||
if (!focused) return;
|
||||
const selected = internalState.getSelected();
|
||||
const validSelected = selected.filter(hasRequiredStateItemProperties);
|
||||
if (validSelected.length === 0) return;
|
||||
|
||||
const item = validSelected[0];
|
||||
controls.onPlay?.({ item, itemType, playType: Play.NOW } as any);
|
||||
},
|
||||
],
|
||||
[
|
||||
bindings.listPlayNext.hotkey,
|
||||
() => {
|
||||
if (!focused) return;
|
||||
const selected = internalState.getSelected();
|
||||
const validSelected = selected.filter(hasRequiredStateItemProperties);
|
||||
if (validSelected.length === 0) return;
|
||||
|
||||
const item = validSelected[0];
|
||||
controls.onPlay?.({ item, itemType, playType: Play.NEXT } as any);
|
||||
},
|
||||
],
|
||||
[
|
||||
bindings.listPlayLast.hotkey,
|
||||
() => {
|
||||
if (!focused) return;
|
||||
const selected = internalState.getSelected();
|
||||
const validSelected = selected.filter(hasRequiredStateItemProperties);
|
||||
if (validSelected.length === 0) return;
|
||||
|
||||
const item = validSelected[0];
|
||||
controls.onPlay?.({ item, itemType, playType: Play.LAST } as any);
|
||||
},
|
||||
],
|
||||
[
|
||||
bindings.listNavigateToPage.hotkey,
|
||||
() => {
|
||||
if (!focused) return;
|
||||
const selected = internalState.getSelected();
|
||||
const validSelected = selected.filter(hasRequiredStateItemProperties);
|
||||
if (validSelected.length === 0) return;
|
||||
|
||||
const item = validSelected[0];
|
||||
const path = getTitlePath(itemType, item.id);
|
||||
if (path) {
|
||||
navigate(path, { state: { item } });
|
||||
}
|
||||
},
|
||||
],
|
||||
]);
|
||||
};
|
||||
@@ -41,11 +41,11 @@ import {
|
||||
useItemListState,
|
||||
useItemListStateSubscription,
|
||||
} from '/@/renderer/components/item-list/helpers/item-list-state';
|
||||
import { useListHotkeys } from '/@/renderer/components/item-list/helpers/use-list-hotkeys';
|
||||
import { ItemControls, ItemListHandle } from '/@/renderer/components/item-list/types';
|
||||
import { animationProps } from '/@/shared/components/animations/animation-props';
|
||||
import { useElementSize } from '/@/shared/hooks/use-element-size';
|
||||
import { useFocusWithin } from '/@/shared/hooks/use-focus-within';
|
||||
import { useHotkeys } from '/@/shared/hooks/use-hotkeys';
|
||||
import { useMergedRef } from '/@/shared/hooks/use-merged-ref';
|
||||
import { LibraryItem } from '/@/shared/types/domain-types';
|
||||
|
||||
@@ -714,20 +714,12 @@ const BaseItemGridList = ({
|
||||
|
||||
useImperativeHandle(ref, () => imperativeHandle, [imperativeHandle]);
|
||||
|
||||
useHotkeys([
|
||||
[
|
||||
'mod+a',
|
||||
() => {
|
||||
if (focused) {
|
||||
if (internalState.isAllSelected()) {
|
||||
internalState.deselectAll();
|
||||
} else {
|
||||
internalState.selectAll();
|
||||
}
|
||||
}
|
||||
},
|
||||
],
|
||||
]);
|
||||
useListHotkeys({
|
||||
controls,
|
||||
focused,
|
||||
internalState,
|
||||
itemType,
|
||||
});
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
|
||||
@@ -32,6 +32,7 @@ import {
|
||||
useItemListStateSubscription,
|
||||
} from '/@/renderer/components/item-list/helpers/item-list-state';
|
||||
import { parseTableColumns } from '/@/renderer/components/item-list/helpers/parse-table-columns';
|
||||
import { useListHotkeys } from '/@/renderer/components/item-list/helpers/use-list-hotkeys';
|
||||
import { useStickyTableGroupRows } from '/@/renderer/components/item-list/item-table-list/hooks/use-sticky-table-group-rows';
|
||||
import { useStickyTableHeader } from '/@/renderer/components/item-list/item-table-list/hooks/use-sticky-table-header';
|
||||
import {
|
||||
@@ -42,7 +43,6 @@ import {
|
||||
import { PlayerContext, usePlayer } from '/@/renderer/features/player/context/player-context';
|
||||
import { animationProps } from '/@/shared/components/animations/animation-props';
|
||||
import { useFocusWithin } from '/@/shared/hooks/use-focus-within';
|
||||
import { useHotkeys } from '/@/shared/hooks/use-hotkeys';
|
||||
import { useMergedRef } from '/@/shared/hooks/use-merged-ref';
|
||||
import { LibraryItem } from '/@/shared/types/domain-types';
|
||||
import { TableColumn } from '/@/shared/types/types';
|
||||
@@ -2262,20 +2262,12 @@ const BaseItemTableList = ({
|
||||
stickyGroupTop,
|
||||
]);
|
||||
|
||||
useHotkeys([
|
||||
[
|
||||
'mod+a',
|
||||
() => {
|
||||
if (focused) {
|
||||
if (internalState.isAllSelected()) {
|
||||
internalState.deselectAll();
|
||||
} else {
|
||||
internalState.selectAll();
|
||||
}
|
||||
}
|
||||
},
|
||||
],
|
||||
]);
|
||||
useListHotkeys({
|
||||
controls,
|
||||
focused,
|
||||
internalState,
|
||||
itemType,
|
||||
});
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
|
||||
Reference in New Issue
Block a user