diff --git a/src/App.tsx b/src/App.tsx index b1972854..37fdaf21 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -812,6 +812,9 @@ function TauriEventBridge() { win.isFullscreen().then(fs => win.setFullscreen(!fs)); break; } + case 'open-mini-player': + invoke('open_mini_player').catch(() => {}); + break; } }; window.addEventListener('keydown', onKey); @@ -983,6 +986,7 @@ export default function App() { if (!e.key) return; if (e.key === 'psysonic_theme') useThemeStore.persist.rehydrate(); else if (e.key === 'psysonic_font') useFontStore.persist.rehydrate(); + else if (e.key === 'psysonic_keybindings') useKeybindingsStore.persist.rehydrate(); else if (e.key === 'psysonic_language' && e.newValue) { import('./i18n').then(m => m.default.changeLanguage(e.newValue!)); } diff --git a/src/components/MiniPlayer.tsx b/src/components/MiniPlayer.tsx index c324fd72..1b37ee67 100644 --- a/src/components/MiniPlayer.tsx +++ b/src/components/MiniPlayer.tsx @@ -5,6 +5,7 @@ import { Play, Pause, SkipBack, SkipForward, Pin, PinOff, Maximize2, X, ListMusi import CachedImage from './CachedImage'; import { buildCoverArtUrl, coverArtCacheKey } from '../api/subsonic'; import { usePlayerStore } from '../store/playerStore'; +import { useKeybindingsStore, matchInAppBinding } from '../store/keybindingsStore'; import { useDragDrop } from '../contexts/DragDropContext'; import MiniContextMenu from './MiniContextMenu'; import type { MiniSyncPayload, MiniControlAction, MiniTrackInfo } from '../utils/miniPlayerBridge'; @@ -178,11 +179,21 @@ export default function MiniPlayer() { }, [alwaysOnTop]); // Keyboard: Space → toggle, ← / → → prev / next. Ignore when typing. + // Also honour the user-configured 'open-mini-player' shortcut so the + // same chord that opens the mini from main also closes it from here. useEffect(() => { const onKey = (e: KeyboardEvent) => { const tgt = e.target as HTMLElement | null; const tag = tgt?.tagName; if (tag === 'INPUT' || tag === 'TEXTAREA' || tgt?.isContentEditable) return; + + const openMiniBinding = useKeybindingsStore.getState().bindings['open-mini-player']; + if (matchInAppBinding(e, openMiniBinding)) { + e.preventDefault(); + invoke('open_mini_player').catch(() => {}); + return; + } + if (e.key === ' ' || e.code === 'Space') { e.preventDefault(); emit('mini:control', 'toggle').catch(() => {}); diff --git a/src/locales/de.ts b/src/locales/de.ts index d17662f2..47482246 100644 --- a/src/locales/de.ts +++ b/src/locales/de.ts @@ -642,6 +642,7 @@ export const deTranslation = { shortcutOpenFolderBrowser: '{{folderBrowser}} öffnen', shortcutFullscreenPlayer: 'Vollbild-Player', shortcutNativeFullscreen: 'Nativer Vollbildmodus', + shortcutOpenMiniPlayer: 'Mini-Player öffnen', tabSystem: 'System', tabGeneral: 'Allgemein', ratingsSectionTitle: 'Bewertungen', diff --git a/src/locales/en.ts b/src/locales/en.ts index 0e59a4c7..5d2f0867 100644 --- a/src/locales/en.ts +++ b/src/locales/en.ts @@ -667,6 +667,7 @@ export const enTranslation = { shortcutOpenFolderBrowser: 'Open {{folderBrowser}}', shortcutFullscreenPlayer: 'Fullscreen player', shortcutNativeFullscreen: 'Native fullscreen', + shortcutOpenMiniPlayer: 'Open mini player', playbackTitle: 'Playback', replayGain: 'Replay Gain', replayGainDesc: 'Normalize track volume using ReplayGain metadata', diff --git a/src/locales/es.ts b/src/locales/es.ts index 1d01ec63..309dd064 100644 --- a/src/locales/es.ts +++ b/src/locales/es.ts @@ -658,6 +658,7 @@ export const esTranslation = { shortcutOpenFolderBrowser: 'Abrir {{folderBrowser}}', shortcutFullscreenPlayer: 'Reproductor pantalla completa', shortcutNativeFullscreen: 'Pantalla completa nativa', + shortcutOpenMiniPlayer: 'Abrir mini reproductor', playbackTitle: 'Reproducción', replayGain: 'Replay Gain', replayGainDesc: 'Normalizar volumen de pistas usando metadatos ReplayGain', diff --git a/src/locales/fr.ts b/src/locales/fr.ts index baf69967..fae364f1 100644 --- a/src/locales/fr.ts +++ b/src/locales/fr.ts @@ -630,6 +630,7 @@ export const frTranslation = { shortcutOpenFolderBrowser: 'Ouvrir {{folderBrowser}}', shortcutFullscreenPlayer: 'Lecteur plein écran', shortcutNativeFullscreen: 'Plein écran natif', + shortcutOpenMiniPlayer: 'Ouvrir le mini-lecteur', tabSystem: 'Système', tabGeneral: 'Général', ratingsSectionTitle: 'Notes', diff --git a/src/locales/nb.ts b/src/locales/nb.ts index 33f1aee2..aea79434 100644 --- a/src/locales/nb.ts +++ b/src/locales/nb.ts @@ -652,6 +652,7 @@ export const nbTranslation = { shortcutOpenFolderBrowser: 'Åpne {{folderBrowser}}', shortcutFullscreenPlayer: 'Fullskjermsspiller', shortcutNativeFullscreen: 'Naturlig fullskjerm', + shortcutOpenMiniPlayer: 'Åpne minispiller', playbackTitle: 'Avspilling', replayGain: 'Replay Gain', replayGainDesc: 'Normaliser sporvolumet ved hjelp av ReplayGain-metadata', diff --git a/src/locales/nl.ts b/src/locales/nl.ts index 56cb4318..a931317d 100644 --- a/src/locales/nl.ts +++ b/src/locales/nl.ts @@ -629,6 +629,7 @@ export const nlTranslation = { shortcutOpenFolderBrowser: '{{folderBrowser}} openen', shortcutFullscreenPlayer: 'Volledigschermspeler', shortcutNativeFullscreen: 'Systeemvolledig scherm', + shortcutOpenMiniPlayer: 'Mini-speler openen', tabSystem: 'Systeem', tabGeneral: 'Algemeen', ratingsSectionTitle: 'Beoordelingen', diff --git a/src/locales/ru.ts b/src/locales/ru.ts index 997c6929..9eb674e1 100644 --- a/src/locales/ru.ts +++ b/src/locales/ru.ts @@ -682,6 +682,7 @@ export const ruTranslation = { shortcutOpenFolderBrowser: 'Открыть {{folderBrowser}}', shortcutFullscreenPlayer: 'Полноэкранный плеер', shortcutNativeFullscreen: 'Системный полный экран', + shortcutOpenMiniPlayer: 'Открыть мини-плеер', playbackTitle: 'Воспроизведение', replayGain: 'Replay Gain', replayGainDesc: 'Выравнивание громкости по метаданным ReplayGain', diff --git a/src/locales/zh.ts b/src/locales/zh.ts index f3d49d03..a9b35e5c 100644 --- a/src/locales/zh.ts +++ b/src/locales/zh.ts @@ -648,6 +648,7 @@ export const zhTranslation = { shortcutOpenFolderBrowser: '打开{{folderBrowser}}', shortcutFullscreenPlayer: '全屏播放器', shortcutNativeFullscreen: '原生全屏', + shortcutOpenMiniPlayer: '打开迷你播放器', playbackTitle: '播放', replayGain: '回放增益', replayGainDesc: '使用 ReplayGain 元数据标准化曲目音量', diff --git a/src/pages/Settings.tsx b/src/pages/Settings.tsx index 91f38586..51262214 100644 --- a/src/pages/Settings.tsx +++ b/src/pages/Settings.tsx @@ -2010,6 +2010,7 @@ export default function Settings() { ['open-folder-browser', t('settings.shortcutOpenFolderBrowser', { folderBrowser: t('sidebar.folderBrowser') })], ['fullscreen-player', t('settings.shortcutFullscreenPlayer')], ['native-fullscreen', t('settings.shortcutNativeFullscreen')], + ['open-mini-player', t('settings.shortcutOpenMiniPlayer')], ] as [KeyAction, string][]).map(([action, label]) => { const bound = kb.bindings[action]; const isListening = listeningFor === action; diff --git a/src/store/keybindingsStore.ts b/src/store/keybindingsStore.ts index a70f8302..d52dba5b 100644 --- a/src/store/keybindingsStore.ts +++ b/src/store/keybindingsStore.ts @@ -12,7 +12,8 @@ export type KeyAction = | 'toggle-queue' | 'open-folder-browser' | 'fullscreen-player' - | 'native-fullscreen'; + | 'native-fullscreen' + | 'open-mini-player'; /** Physical keys only — ignore for binding capture */ export const MODIFIER_KEY_CODES = [ @@ -35,6 +36,7 @@ export const DEFAULT_BINDINGS: Bindings = { 'open-folder-browser': null, 'fullscreen-player': null, 'native-fullscreen': 'F11', + 'open-mini-player': null, }; interface KeybindingsState {