feat(09-02): add shortcuts config package with default bindings and Wails persistence
- Create backend/shortcuts/config.go with DefaultBindings(), ApplyDefaults(), Validate() - Wire Shortcuts field into main Config struct with TOML persistence - Add GetShortcuts, SetShortcuts, SetShortcut, ResetShortcuts Wails binding methods - Regenerate Wails TypeScript bindings for new config methods - Fix wsl lint in library.go (blank line before logger call)
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
// Package shortcuts manages keyboard shortcut configuration.
|
||||
package shortcuts
|
||||
|
||||
// Config holds user-customized keyboard shortcut bindings.
|
||||
// Keys are action IDs (e.g. "player.playPause"), values are
|
||||
// key combo strings in canonical format (e.g. "Ctrl+F", "Space").
|
||||
type Config struct {
|
||||
Bindings map[string]string `toml:"Bindings"`
|
||||
}
|
||||
|
||||
// DefaultBindings returns the default keyboard shortcut bindings.
|
||||
// Follows hybrid style: Space/arrows for player, Ctrl+key for app actions.
|
||||
func DefaultBindings() map[string]string {
|
||||
return map[string]string{
|
||||
// Player controls (Global scope, no modifier)
|
||||
"player.playPause": "Space",
|
||||
"player.next": "N",
|
||||
"player.previous": "P",
|
||||
"player.volumeUp": "Up",
|
||||
"player.volumeDown": "Down",
|
||||
"player.seekForward": "Right",
|
||||
"player.seekBack": "Left",
|
||||
"player.shuffle": "S",
|
||||
"player.repeat": "R",
|
||||
"player.mute": "M",
|
||||
|
||||
// Navigation (Global scope)
|
||||
"nav.search": "/",
|
||||
"nav.searchAlt": "Ctrl+F",
|
||||
"nav.queue": "Q",
|
||||
|
||||
// App actions (Global scope, Ctrl modifier)
|
||||
"app.selectAll": "Ctrl+A",
|
||||
|
||||
// Panel-specific (track list)
|
||||
"tracklist.play": "Enter",
|
||||
"tracklist.delete": "Delete",
|
||||
}
|
||||
}
|
||||
|
||||
// ApplyDefaults fills any missing bindings with defaults.
|
||||
// Existing user customizations are preserved.
|
||||
func (c *Config) ApplyDefaults() {
|
||||
if c.Bindings == nil {
|
||||
c.Bindings = DefaultBindings()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
defaults := DefaultBindings()
|
||||
for action, key := range defaults {
|
||||
if _, exists := c.Bindings[action]; !exists {
|
||||
c.Bindings[action] = key
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Validate checks that the config is well-formed.
|
||||
func (c *Config) Validate() error {
|
||||
c.ApplyDefaults()
|
||||
// No validation errors possible — any string is a valid binding.
|
||||
// Conflict detection is a frontend UX concern, not a config error.
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user