F1-F5 leave full-screen views; dialogs still block them

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-20 19:57:05 +02:00
co-authored by Claude Sonnet 5.5
parent 2dfd018284
commit 6668f91e7a
5 changed files with 46 additions and 13 deletions
+27 -8
View File
@@ -58,6 +58,8 @@ type overlay struct {
page string
focus tview.Primitive
hints string
full bool // full-screen view (can be left with F1-F5), as opposed to a dialog
close func() // optional cleanup when the overlay is removed
}
// New builds the application shell: a tab bar, one page per view and a status bar.
@@ -185,9 +187,9 @@ func (a *App) renderStatus() {
}
// pushOverlay stacks p above everything and focuses focus.
func (a *App) pushOverlay(p, focus tview.Primitive, hints string) {
func (a *App) pushOverlay(p, focus tview.Primitive, hints string, full bool, onClose func()) {
name := fmt.Sprintf("overlay-%d", len(a.overlays))
a.overlays = append(a.overlays, overlay{page: name, focus: a.app.GetFocus(), hints: hints})
a.overlays = append(a.overlays, overlay{page: name, focus: a.app.GetFocus(), hints: hints, full: full, close: onClose})
a.pages.AddPage(name, p, true, true)
a.app.SetFocus(focus)
a.renderStatus()
@@ -202,12 +204,12 @@ func (a *App) openModal(p tview.Primitive, width, height int) {
AddItem(p, height, 0, true).
AddItem(nil, 0, 1, false), width, 0, true).
AddItem(nil, 0, 1, false)
a.pushOverlay(box, p, "↑↓ move · ←→ change · Enter select · Esc cancel")
a.pushOverlay(box, p, "↑↓ move · ←→ change · Enter select · Esc cancel", false, nil)
}
// openFull shows p above the whole view area (the tab bar and status bar stay visible).
func (a *App) openFull(p tview.Primitive, hints string) {
a.pushOverlay(p, p, hints)
func (a *App) openFull(p tview.Primitive, hints string, onClose func()) {
a.pushOverlay(p, p, hints, true, onClose)
}
// closeModal removes the topmost overlay and restores the previous focus.
@@ -218,6 +220,9 @@ func (a *App) closeModal() {
top := a.overlays[len(a.overlays)-1]
a.overlays = a.overlays[:len(a.overlays)-1]
a.pages.RemovePage(top.page)
if top.close != nil {
top.close()
}
if top.focus != nil {
a.app.SetFocus(top.focus)
}
@@ -239,6 +244,16 @@ func (a *App) confirm(text string, yes func()) {
a.openModal(m, 60, 7+min(lines, 10))
}
// onlyFullOverlays is true when no dialog is open (full-screen views may be).
func (a *App) onlyFullOverlays() bool {
for _, o := range a.overlays {
if !o.full {
return false
}
}
return true
}
// typing reports whether keystrokes belong to a text field or dialog and must
// not trigger global shortcuts.
func (a *App) typing() bool {
@@ -254,13 +269,17 @@ func (a *App) handleKey(ev *tcell.EventKey) *tcell.EventKey {
a.app.Stop()
return nil
}
// Shortcuts that also work while typing in a search box. Not while a dialog is open.
if len(a.overlays) == 0 {
if ev.Key() == tcell.KeyF9 {
// Shortcuts that also work while typing in a search box. Dialogs block them;
// full-screen views (release list, episodes) are closed by a view switch.
if a.onlyFullOverlays() {
if ev.Key() == tcell.KeyF9 && len(a.overlays) == 0 {
a.showHelp()
return nil
}
if i := a.viewShortcut(ev); i >= 0 && i < len(a.views) {
for len(a.overlays) > 0 {
a.closeModal()
}
a.switchTo(i)
return nil
}