Tab cycles panels within a view; views switch only via F1-F4/Alt+digit
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -46,13 +46,14 @@ Keep the file private (`chmod 600`); it holds your API keys.
|
|||||||
|
|
||||||
| Key | Action |
|
| Key | Action |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `F1`–`F4`, `Alt+1`–`4`, `Tab` | switch view |
|
| `F1`–`F4`, `Alt+1`–`4` | switch view |
|
||||||
|
| `Tab`, `Shift+Tab` | switch panel within a view |
|
||||||
| `?` / `F9` | help |
|
| `?` / `F9` | help |
|
||||||
| `/` | focus search box |
|
| `/` | focus search box |
|
||||||
| `Enter`, `a` | add selected title |
|
| `Enter`, `a` | add selected title |
|
||||||
| `i` | interactive release search |
|
| `i` | interactive release search |
|
||||||
| `Enter`/`g`, `s`, `f` (release list) | grab, cycle sort, hide rejected |
|
| `Enter`/`g`, `s`, `f` (release list) | grab, cycle sort, hide rejected |
|
||||||
| `p`, `d`, `t`, `b`, `h`, `r` (downloads) | pause, delete, retry, blocklist, next panel, refresh |
|
| `p`, `d`, `t`, `b`, `r` (downloads) | pause, delete, retry, blocklist, refresh |
|
||||||
| `Esc` | back / close dialog |
|
| `Esc` | back / close dialog |
|
||||||
| `q`, `Ctrl+C` | quit |
|
| `q`, `Ctrl+C` | quit |
|
||||||
|
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ Keybindings (initial proposal):
|
|||||||
|
|
||||||
| Key | Action |
|
| Key | Action |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `Tab` / `1-4` | Switch view |
|
| `Tab` / `Shift+Tab` | Switch panel within the current view (never the view) |
|
||||||
| `F1-F4` / `Alt+1-4` | Switch view, also while typing in a search box |
|
| `F1-F4` / `Alt+1-4` | Switch view, also while typing in a search box |
|
||||||
| `/` | Focus search |
|
| `/` | Focus search |
|
||||||
| `Enter` | Search / open details / confirm |
|
| `Enter` | Search / open details / confirm |
|
||||||
@@ -109,7 +109,7 @@ Keybindings (initial proposal):
|
|||||||
| `p` | Pause/resume SABnzbd (Downloads view) |
|
| `p` | Pause/resume SABnzbd (Downloads view) |
|
||||||
| `d` | Delete selected download, history entry or Radarr/Sonarr queue item (with confirm) |
|
| `d` | Delete selected download, history entry or Radarr/Sonarr queue item (with confirm) |
|
||||||
| `t` | Retry the selected failed download (history) |
|
| `t` | Retry the selected failed download (history) |
|
||||||
| `h` | Downloads view: cycle focus between SABnzbd queue, Radarr/Sonarr queue and history |
|
| `Tab` / `Shift+Tab` | Downloads view: cycle focus between SABnzbd queue, Radarr/Sonarr queue and history |
|
||||||
| `b` | Downloads view (Radarr/Sonarr queue): blocklist the release and search for another |
|
| `b` | Downloads view (Radarr/Sonarr queue): blocklist the release and search for another |
|
||||||
| `i` | Interactive release search for the selected library item (movies; series ask for a season, then an episode or the whole season) |
|
| `i` | Interactive release search for the selected library item (movies; series ask for a season, then an episode or the whole season) |
|
||||||
| `g` / `Enter` | Release list: grab the selected release (rejected ones ask for confirmation) |
|
| `g` / `Enter` | Release list: grab the selected release (rejected ones ask for confirmation) |
|
||||||
|
|||||||
+1
-7
@@ -164,7 +164,7 @@ func (a *App) Run() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) renderStatus() {
|
func (a *App) renderStatus() {
|
||||||
hints := "[gray]?/F9 help · q quit · Tab/F1-F4 views · / search"
|
hints := "[gray]?/F9 help · q quit · F1-F4 views · Tab panels · / search"
|
||||||
if len(a.overlays) > 0 {
|
if len(a.overlays) > 0 {
|
||||||
hints = "[gray]Esc back · Ctrl+C quit"
|
hints = "[gray]Esc back · Ctrl+C quit"
|
||||||
}
|
}
|
||||||
@@ -260,12 +260,6 @@ func (a *App) handleKey(ev *tcell.EventKey) *tcell.EventKey {
|
|||||||
return ev
|
return ev
|
||||||
}
|
}
|
||||||
switch ev.Key() {
|
switch ev.Key() {
|
||||||
case tcell.KeyTab:
|
|
||||||
a.switchTo((a.active + 1) % len(a.views))
|
|
||||||
return nil
|
|
||||||
case tcell.KeyBacktab:
|
|
||||||
a.switchTo((a.active + len(a.views) - 1) % len(a.views))
|
|
||||||
return nil
|
|
||||||
case tcell.KeyRune:
|
case tcell.KeyRune:
|
||||||
if ev.Rune() == 'q' {
|
if ev.Rune() == 'q' {
|
||||||
a.app.Stop()
|
a.app.Stop()
|
||||||
|
|||||||
@@ -84,13 +84,20 @@ func newDownloadsView(app *App, sab *sabnzbd.Client, sources []arrSource, interv
|
|||||||
common := func(extra map[rune]func()) func(*tcell.EventKey) *tcell.EventKey {
|
common := func(extra map[rune]func()) func(*tcell.EventKey) *tcell.EventKey {
|
||||||
keys := map[rune]func(){
|
keys := map[rune]func(){
|
||||||
'r': v.refreshNow,
|
'r': v.refreshNow,
|
||||||
'h': v.nextPanel,
|
|
||||||
'p': v.togglePause,
|
'p': v.togglePause,
|
||||||
}
|
}
|
||||||
for r, f := range extra {
|
for r, f := range extra {
|
||||||
keys[r] = f
|
keys[r] = f
|
||||||
}
|
}
|
||||||
return func(ev *tcell.EventKey) *tcell.EventKey {
|
return func(ev *tcell.EventKey) *tcell.EventKey {
|
||||||
|
switch ev.Key() {
|
||||||
|
case tcell.KeyTab:
|
||||||
|
v.nextPanel(1)
|
||||||
|
return nil
|
||||||
|
case tcell.KeyBacktab:
|
||||||
|
v.nextPanel(-1)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
if ev.Key() == tcell.KeyRune {
|
if ev.Key() == tcell.KeyRune {
|
||||||
if f, ok := keys[ev.Rune()]; ok {
|
if f, ok := keys[ev.Rune()]; ok {
|
||||||
f()
|
f()
|
||||||
@@ -114,12 +121,13 @@ func newDownloadsView(app *App, sab *sabnzbd.Client, sources []arrSource, interv
|
|||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
// nextPanel moves focus to the next panel (queue, Radarr/Sonarr queue, history).
|
// nextPanel moves focus to the next (dir 1) or previous (dir -1) panel:
|
||||||
func (v *downloadsView) nextPanel() {
|
// queue, Radarr/Sonarr queue, history.
|
||||||
|
func (v *downloadsView) nextPanel(dir int) {
|
||||||
cur := v.app.app.GetFocus()
|
cur := v.app.app.GetFocus()
|
||||||
for i, p := range v.panels {
|
for i, p := range v.panels {
|
||||||
if p == cur {
|
if p == cur {
|
||||||
v.app.app.SetFocus(v.panels[(i+1)%len(v.panels)])
|
v.app.app.SetFocus(v.panels[(i+dir+len(v.panels))%len(v.panels)])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -6,7 +6,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const helpText = `[yellow]Global[-]
|
const helpText = `[yellow]Global[-]
|
||||||
F1-F4, Alt+1-4, Tab switch view
|
F1-F4, Alt+1-4 switch view
|
||||||
|
Tab, Shift+Tab switch panel within a view
|
||||||
?, F9 this help (F9 works while typing)
|
?, F9 this help (F9 works while typing)
|
||||||
q, Ctrl+C quit
|
q, Ctrl+C quit
|
||||||
Esc close dialog / go back
|
Esc close dialog / go back
|
||||||
@@ -22,7 +23,6 @@ const helpText = `[yellow]Global[-]
|
|||||||
f hide rejected releases
|
f hide rejected releases
|
||||||
|
|
||||||
[yellow]Downloads[-]
|
[yellow]Downloads[-]
|
||||||
h next panel
|
|
||||||
p pause / resume the SABnzbd queue
|
p pause / resume the SABnzbd queue
|
||||||
d delete the selected job or entry
|
d delete the selected job or entry
|
||||||
b remove from arr queue + blocklist
|
b remove from arr queue + blocklist
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ func newSearchView(app *App, be backend, cfg config.Arr) *searchView {
|
|||||||
case tcell.KeyEnter:
|
case tcell.KeyEnter:
|
||||||
v.search(strings.TrimSpace(v.input.GetText()))
|
v.search(strings.TrimSpace(v.input.GetText()))
|
||||||
v.app.app.SetFocus(v.list)
|
v.app.app.SetFocus(v.list)
|
||||||
case tcell.KeyEscape, tcell.KeyTab:
|
case tcell.KeyEscape, tcell.KeyTab, tcell.KeyBacktab:
|
||||||
v.app.app.SetFocus(v.list)
|
v.app.app.SetFocus(v.list)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -85,6 +85,10 @@ func newSearchView(app *App, be backend, cfg config.Arr) *searchView {
|
|||||||
v.list.SetChangedFunc(func(i int, _, _ string, _ rune) { v.showDetails(i) })
|
v.list.SetChangedFunc(func(i int, _, _ string, _ rune) { v.showDetails(i) })
|
||||||
v.list.SetSelectedFunc(func(i int, _, _ string, _ rune) { v.add(i) })
|
v.list.SetSelectedFunc(func(i int, _, _ string, _ rune) { v.add(i) })
|
||||||
v.list.SetInputCapture(func(ev *tcell.EventKey) *tcell.EventKey {
|
v.list.SetInputCapture(func(ev *tcell.EventKey) *tcell.EventKey {
|
||||||
|
if ev.Key() == tcell.KeyTab || ev.Key() == tcell.KeyBacktab {
|
||||||
|
v.app.app.SetFocus(v.input)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
if ev.Key() != tcell.KeyRune {
|
if ev.Key() != tcell.KeyRune {
|
||||||
return ev
|
return ev
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user