@@ -4,58 +4,285 @@ part of 'shortcuts_manager.dart';
44
55class _ShortcutsManagerDesktop extends ShortcutsManager {
66 @override
7- Future <void > init () async {
8- if (kDebugMode) await hotKeyManager.unregisterAll ();
7+ List <ShortcutKeyData > get _keysToRegister => __keysToRegister;
98
10- final keysToRegister = < _ShortcutKeyData > [
11- _ShortcutKeyData (
12- key: PhysicalKeyboardKey .escape,
9+ late final __keysToRegister = < ShortcutKeyData > [
10+ // ------------------- playback -------------------
11+ ShortcutKeyData (
12+ key: LogicalKeyboardKey .space,
13+ callback: Player .inst.togglePlayPause,
14+ title: "${lang .PLAY }/${lang .PAUSE }" ,
15+ ),
16+ ShortcutKeyData (
17+ key: LogicalKeyboardKey .arrowLeft,
18+ callback: Player .inst.seekSecondsBackward,
19+ title: "<- ${lang .SEEK_DURATION }" ,
20+ ),
21+ ShortcutKeyData (
22+ key: LogicalKeyboardKey .arrowRight,
23+ callback: Player .inst.seekSecondsForward,
24+ title: "${lang .SEEK_DURATION } ->" ,
25+ ),
26+ ShortcutKeyData (
27+ key: LogicalKeyboardKey .arrowUp,
28+ control: true ,
29+ includeRepeats: true ,
30+ callback: Player .inst.volumeUp,
31+ title: "${lang .VOLUME } ↑" ,
32+ ),
33+ ShortcutKeyData (
34+ key: LogicalKeyboardKey .arrowDown,
35+ control: true ,
36+ includeRepeats: true ,
37+ callback: Player .inst.volumeDown,
38+ title: "${lang .VOLUME } ↓" ,
39+ ),
40+ ShortcutKeyData (
41+ key: LogicalKeyboardKey .arrowLeft,
42+ control: true ,
43+ callback: Player .inst.previous,
44+ title: lang.PREVIOUS ,
45+ ),
46+ ShortcutKeyData (
47+ key: LogicalKeyboardKey .arrowRight,
48+ control: true ,
49+ callback: Player .inst.next,
50+ title: lang.NEXT ,
51+ ),
52+
53+ // -------------------
54+ ShortcutKeyData (
55+ key: LogicalKeyboardKey .keyF,
56+ control: true ,
57+ callback: () => ScrollSearchController .inst.searchBarKey.currentState? .openCloseSearchBar (
58+ forceOpen: ScrollSearchController .inst.searchBarKey.currentState? .focusNode.hasPrimaryFocus != true ,
59+ ),
60+ title: lang.SEARCH ,
61+ ),
62+ ShortcutKeyData (
63+ key: LogicalKeyboardKey .keyR,
64+ control: true ,
65+ callback: Indexer .inst.refreshLibraryAndCheckForDiff,
66+ title: lang.REFRESH_LIBRARY ,
67+ ),
68+ ShortcutKeyData (
69+ key: LogicalKeyboardKey .keyE,
70+ control: true ,
71+ callback: () {
72+ _executeMiniPlayers (
73+ (localPlayer, ytPlayer, ytQueueChip) {
74+ if (ytPlayer != null ) {
75+ if (ytPlayer.isExpanded) {
76+ ytPlayer.animateToState (false );
77+ } else {
78+ ytPlayer.animateToState (true );
79+ }
80+ } else {
81+ if (localPlayer.isMinimized) {
82+ localPlayer.snapToExpanded ();
83+ } else {
84+ localPlayer.snapToMini ();
85+ }
86+ }
87+ },
88+ );
89+ },
90+ title: lang.OPEN_MINIPLAYER ,
91+ ),
92+ ShortcutKeyData (
93+ key: LogicalKeyboardKey .keyQ,
94+ control: true ,
95+ callback: () {
96+ _executeMiniPlayers (
97+ (localPlayer, ytPlayer, ytQueueChip) {
98+ if (ytPlayer != null ) {
99+ if (! ytPlayer.isExpanded) ytPlayer.animateToState (true );
100+ _executeYtQueueSheet (ytQueueChip, (chip) => chip.toggleSheet ());
101+ } else {
102+ if (localPlayer.isInQueue) {
103+ localPlayer.snapToExpanded ();
104+ } else {
105+ localPlayer.snapToQueue ();
106+ }
107+ }
108+ },
109+ );
110+ },
111+ title: lang.OPEN_QUEUE ,
112+ ),
113+ ShortcutKeyData (
114+ key: LogicalKeyboardKey .keyL,
115+ control: true ,
116+ callback: () {
117+ settings.save (enableLyrics: ! settings.enableLyrics.value);
118+ final currentItem = Player .inst.currentItem.value;
119+ if (currentItem != null ) {
120+ Lyrics .inst.updateLyrics (currentItem);
121+ }
122+ },
123+ title: lang.LYRICS ,
124+ ),
125+ ShortcutKeyData (
126+ key: LogicalKeyboardKey .keyL,
127+ control: true ,
128+ shift: true ,
129+ callback: () {
130+ final fullscreenState = Lyrics .inst.lrcViewKeyFullscreen.currentState;
131+ if (fullscreenState != null ) {
132+ fullscreenState.exitFullScreen ();
133+ } else {
134+ Lyrics .inst.lrcViewKey.currentState? .enterFullScreen ();
135+ }
136+ },
137+ title: "${lang .LYRICS } (${lang .FULLSCREEN })" ,
138+ ),
139+ ShortcutKeyData (
140+ key: LogicalKeyboardKey .tab,
141+ control: true ,
142+ callback: () {
143+ final e = settings.player.repeatMode.value.nextElement (RepeatMode .values);
144+ settings.player.save (repeatMode: e);
145+ },
146+ title: lang.REPEAT_MODE ,
147+ ),
148+ // -----------------
149+ for (int i = 1 ; i <= 9 ; i++ )
150+ ShortcutKeyData (
151+ key: LogicalKeyboardKey (0x00000000030 + i),
152+ control: true ,
13153 callback: () {
14- if (NamidaNavigator .inst.isInFullScreen) {
15- NamidaNavigator .inst.exitFullScreen ();
16- } else {
17- NamidaNavigator .inst.popPage ();
154+ try {
155+ final tab = settings.libraryTabs.value[i - 1 ];
156+ ScrollSearchController .inst.animatePageController (tab);
157+ } catch (_) {
158+ // -- index larger than tabs length
18159 }
19160 },
161+ title: lang.LIBRARY_TABS ,
20162 ),
21- _ShortcutKeyData (
22- key: PhysicalKeyboardKey .f11,
23- callback: () async {
24- final isFullscreen = await windowManager.isFullScreen ();
25- windowManager.setFullScreen (! isFullscreen);
26- },
27- ),
28- ];
29163
30- for (final k in keysToRegister) {
31- _register (data: k);
32- }
33- }
164+ // ------------------- media buttons -------------------
165+ ShortcutKeyData (
166+ key: LogicalKeyboardKey .mediaPlay,
167+ callback: Player .inst.play,
168+ title: lang.PLAY ,
169+ ),
170+ ShortcutKeyData (
171+ key: LogicalKeyboardKey .mediaPause,
172+ callback: Player .inst.pause,
173+ title: lang.PAUSE ,
174+ ),
175+ ShortcutKeyData (
176+ key: LogicalKeyboardKey .mediaPlayPause,
177+ callback: Player .inst.togglePlayPause,
178+ title: "${lang .PLAY }/${lang .PAUSE }" ,
179+ ),
180+ ShortcutKeyData (
181+ key: LogicalKeyboardKey .mediaStop,
182+ callback: Player .inst.pause,
183+ title: lang.PAUSE ,
184+ ),
185+ ShortcutKeyData (
186+ key: LogicalKeyboardKey .mediaFastForward,
187+ callback: Player .inst.seekSecondsForward,
188+ title: "${lang .SEEK_DURATION } ->" ,
189+ ),
190+ ShortcutKeyData (
191+ key: LogicalKeyboardKey .mediaRewind,
192+ callback: Player .inst.seekSecondsBackward,
193+ title: "<- ${lang .SEEK_DURATION }" ,
194+ ),
195+ ShortcutKeyData (
196+ key: LogicalKeyboardKey .mediaTrackNext,
197+ callback: Player .inst.next,
198+ title: lang.NEXT ,
199+ ),
200+ ShortcutKeyData (
201+ key: LogicalKeyboardKey .mediaTrackPrevious,
202+ callback: Player .inst.previous,
203+ title: lang.PREVIOUS ,
204+ ),
205+ ShortcutKeyData (
206+ key: LogicalKeyboardKey (0x000000b0 ),
207+ callback: Player .inst.next,
208+ title: lang.NEXT ,
209+ ),
210+ ShortcutKeyData (
211+ key: LogicalKeyboardKey (0x000000b1 ),
212+ callback: Player .inst.previous,
213+ title: lang.PREVIOUS ,
214+ ),
215+ // ================
216+ ShortcutKeyData (
217+ key: LogicalKeyboardKey .f11,
218+ callback: () async {
219+ final isFullscreen = await windowManager.isFullScreen ();
220+ windowManager.setFullScreen (! isFullscreen);
221+ },
222+ title: lang.FULLSCREEN ,
223+ ),
224+ ShortcutKeyData (
225+ key: LogicalKeyboardKey .escape,
226+ callback: () {
227+ if (NamidaNavigator .inst.isInFullScreen) {
228+ NamidaNavigator .inst.exitFullScreen ();
229+ } else {
230+ NamidaNavigator .inst.popPage ();
231+ }
232+ },
233+ title: lang.EXIT ,
234+ ),
235+ ];
34236
35- void _register ({required _ShortcutKeyData data}) {
36- hotKeyManager.register (
37- HotKey (
38- key: data.key,
39- scope: data.scope,
40- modifiers: data.modifiers,
41- ),
42- keyDownHandler: (_) {
43- data.callback ();
237+ FocusAttachment ? _attachment;
238+
239+ @override
240+ void init () {
241+ _attachment = FocusManager .instance.rootScope.attach (
242+ null ,
243+ onKeyEvent: (node, event) {
244+ for (final ShortcutActivator activator in bindings.keys) {
245+ if (activator.accepts (event, HardwareKeyboard .instance)) {
246+ bindings[activator]! .call ();
247+ return KeyEventResult .handled;
248+ }
249+ }
250+ return KeyEventResult .ignored;
44251 },
45252 );
46253 }
47- }
48254
49- class _ShortcutKeyData {
50- final KeyboardKey key;
51- final List <HotKeyModifier >? modifiers;
52- final HotKeyScope scope;
53- final VoidCallback callback;
54-
55- _ShortcutKeyData ({
56- required this .key,
57- this .modifiers,
58- this .scope = HotKeyScope .inapp,
59- required this .callback,
60- });
255+ @override
256+ void dispose () {
257+ _attachment? .detach ();
258+ }
259+
260+ void _executeMiniPlayers (
261+ void Function (
262+ MiniPlayerController localPlayer,
263+ NamidaYTMiniplayerState ? ytPlayer,
264+ YTMiniplayerQueueChipState ? ytQueueChip,
265+ ) callback) {
266+ callback (
267+ MiniPlayerController .inst,
268+ MiniPlayerController .inst.ytMiniplayerKey.currentState,
269+ NamidaNavigator .inst.ytQueueSheetKey.currentState,
270+ );
271+ }
272+
273+ void _executeYtQueueSheet (YTMiniplayerQueueChipState ? ytQueueChip, void Function (YTMiniplayerQueueChipState ytQueueChip) callback) {
274+ final ytQueue = NamidaNavigator .inst.ytQueueSheetKey.currentState;
275+ if (ytQueue != null ) {
276+ callback (ytQueue);
277+ return ;
278+ }
279+
280+ Timer (
281+ const Duration (milliseconds: 100 ),
282+ () {
283+ final ytQueue = NamidaNavigator .inst.ytQueueSheetKey.currentState;
284+ if (ytQueue != null ) callback (ytQueue);
285+ },
286+ );
287+ }
61288}
0 commit comments