diff --git a/src/assets/locales/en.json b/src/assets/locales/en.json index 38abaca0..6d5b62ba 100644 --- a/src/assets/locales/en.json +++ b/src/assets/locales/en.json @@ -308,7 +308,9 @@ "save": "Save", "cancel": "Cancel", "saveChanges": "Save Changes", - "resetToDefault": "Reset to default" + "resetToDefault": "Reset to default", + "numberKeySeeking": "Number key progress seeking", + "numberKeySeekingDescription": "Use number keys 0-9 to seek to specific positions in the video. 0 goes to the beginning, 1-8 jump to 10%-80%, and 9 goes to 90%." } }, "home": { diff --git a/src/backend/accounts/settings.ts b/src/backend/accounts/settings.ts index 03c950e8..592f19a2 100644 --- a/src/backend/accounts/settings.ts +++ b/src/backend/accounts/settings.ts @@ -44,6 +44,7 @@ export interface SettingsInput { manualSourceSelection?: boolean; enableDoubleClickToSeek?: boolean; enableAutoResumeOnPlaybackError?: boolean; + enableNumberKeySeeking?: boolean; keyboardShortcuts?: KeyboardShortcuts; customTheme?: CustomThemeSettings; } @@ -82,6 +83,7 @@ export interface SettingsResponse { manualSourceSelection?: boolean; enableDoubleClickToSeek?: boolean; enableAutoResumeOnPlaybackError?: boolean; + enableNumberKeySeeking?: boolean; keyboardShortcuts?: KeyboardShortcuts; customTheme?: CustomThemeSettings; } diff --git a/src/components/overlays/KeyboardCommandsEditModal.tsx b/src/components/overlays/KeyboardCommandsEditModal.tsx index 750042ff..55131395 100644 --- a/src/components/overlays/KeyboardCommandsEditModal.tsx +++ b/src/components/overlays/KeyboardCommandsEditModal.tsx @@ -3,6 +3,7 @@ import { useTranslation } from "react-i18next"; import { updateSettings } from "@/backend/accounts/settings"; import { Button } from "@/components/buttons/Button"; +import { Toggle } from "@/components/buttons/Toggle"; import { Dropdown } from "@/components/form/Dropdown"; import { Icon, Icons } from "@/components/Icon"; import { Modal, ModalCard, useModal } from "@/components/overlays/Modal"; @@ -203,6 +204,12 @@ export function KeyboardCommandsEditModal({ const setKeyboardShortcuts = usePreferencesStore( (s) => s.setKeyboardShortcuts, ); + const enableNumberKeySeeking = usePreferencesStore( + (s) => s.enableNumberKeySeeking, + ); + const setEnableNumberKeySeeking = usePreferencesStore( + (s) => s.setEnableNumberKeySeeking, + ); const [editingShortcuts, setEditingShortcuts] = useState(keyboardShortcuts); @@ -212,6 +219,8 @@ export function KeyboardCommandsEditModal({ ); const [editingKey, setEditingKey] = useState(""); const [isCapturingKey, setIsCapturingKey] = useState(false); + const [editingEnableNumberKeySeeking, setEditingEnableNumberKeySeeking] = + useState(enableNumberKeySeeking); // Cancel any active editing when modal closes useEffect(() => { @@ -220,8 +229,9 @@ export function KeyboardCommandsEditModal({ setEditingModifier(""); setEditingKey(""); setIsCapturingKey(false); + setEditingEnableNumberKeySeeking(enableNumberKeySeeking); } - }, [modal.isShown]); + }, [modal.isShown, enableNumberKeySeeking]); const shortcutGroups = getShortcutGroups(t, editingShortcuts).map( (group) => ({ @@ -339,11 +349,13 @@ export function KeyboardCommandsEditModal({ const handleSave = useCallback(async () => { setKeyboardShortcuts(editingShortcuts); + setEnableNumberKeySeeking(editingEnableNumberKeySeeking); if (account && backendUrl) { try { await updateSettings(backendUrl, account, { keyboardShortcuts: editingShortcuts, + enableNumberKeySeeking: editingEnableNumberKeySeeking, }); } catch (error) { console.error("Failed to save keyboard shortcuts:", error); @@ -353,9 +365,11 @@ export function KeyboardCommandsEditModal({ hideModal(id); }, [ editingShortcuts, + editingEnableNumberKeySeeking, account, backendUrl, setKeyboardShortcuts, + setEnableNumberKeySeeking, hideModal, id, ]); @@ -508,6 +522,24 @@ export function KeyboardCommandsEditModal({ ))} +
+
+

+ {t("global.keyboardShortcuts.numberKeySeeking")} +

+

+ {t("global.keyboardShortcuts.numberKeySeekingDescription")} +

+
+ + setEditingEnableNumberKeySeeking( + !editingEnableNumberKeySeeking, + ) + } + /> +
diff --git a/src/components/player/internals/KeyboardEvents.tsx b/src/components/player/internals/KeyboardEvents.tsx index 8335f094..b252e569 100644 --- a/src/components/player/internals/KeyboardEvents.tsx +++ b/src/components/player/internals/KeyboardEvents.tsx @@ -67,6 +67,9 @@ export function KeyboardEvents() { const setEnableNativeSubtitles = usePreferencesStore( (s) => s.setEnableNativeSubtitles, ); + const enableNumberKeySeeking = usePreferencesStore( + (s) => s.enableNumberKeySeeking, + ); const [isRolling, setIsRolling] = useState(false); const volumeDebounce = useRef | undefined>(); @@ -314,6 +317,7 @@ export function KeyboardEvents() { keyboardShortcuts, enableNativeSubtitles, setEnableNativeSubtitles, + enableNumberKeySeeking, }); useEffect(() => { @@ -350,6 +354,7 @@ export function KeyboardEvents() { keyboardShortcuts, enableNativeSubtitles, setEnableNativeSubtitles, + enableNumberKeySeeking, }; }, [ setShowVolume, @@ -379,6 +384,7 @@ export function KeyboardEvents() { keyboardShortcuts, enableNativeSubtitles, setEnableNativeSubtitles, + enableNumberKeySeeking, ]); useEffect(() => { @@ -606,6 +612,7 @@ export function KeyboardEvents() { // Skip to percentage with number keys (0-9) - locked, always use number keys // Number keys are reserved for progress skipping, so handle them before customizable shortcuts if ( + dataRef.current.enableNumberKeySeeking && /^[0-9]$/.test(k) && dataRef.current.duration > 0 && !evt.ctrlKey && diff --git a/src/stores/preferences/index.tsx b/src/stores/preferences/index.tsx index c9dcb3ab..0e70d049 100644 --- a/src/stores/preferences/index.tsx +++ b/src/stores/preferences/index.tsx @@ -38,6 +38,7 @@ export interface PreferencesStore { manualSourceSelection: boolean; enableDoubleClickToSeek: boolean; enableAutoResumeOnPlaybackError: boolean; + enableNumberKeySeeking: boolean; keyboardShortcuts: KeyboardShortcuts; setEnableThumbnails(v: boolean): void; @@ -70,6 +71,7 @@ export interface PreferencesStore { setManualSourceSelection(v: boolean): void; setEnableDoubleClickToSeek(v: boolean): void; setEnableAutoResumeOnPlaybackError(v: boolean): void; + setEnableNumberKeySeeking(v: boolean): void; setKeyboardShortcuts(v: KeyboardShortcuts): void; } @@ -106,6 +108,7 @@ export const usePreferencesStore = create( manualSourceSelection: false, enableDoubleClickToSeek: false, enableAutoResumeOnPlaybackError: true, + enableNumberKeySeeking: true, keyboardShortcuts: DEFAULT_KEYBOARD_SHORTCUTS, setEnableThumbnails(v) { set((s) => { @@ -262,6 +265,11 @@ export const usePreferencesStore = create( s.enableAutoResumeOnPlaybackError = v; }); }, + setEnableNumberKeySeeking(v) { + set((s) => { + s.enableNumberKeySeeking = v; + }); + }, setKeyboardShortcuts(v) { set((s) => { s.keyboardShortcuts = v;