feat(ui): improve key handling
- handle add-destination input in own handler func - handle CTRL-C when modal is visible - fix destination wraparound on key-up
This commit is contained in:
parent
af4410c4cf
commit
2fbf2176cf
@ -40,9 +40,11 @@ const (
|
|||||||
|
|
||||||
// UI is responsible for managing the terminal user interface.
|
// UI is responsible for managing the terminal user interface.
|
||||||
type UI struct {
|
type UI struct {
|
||||||
commandCh chan Command
|
commandCh chan Command
|
||||||
buildInfo domain.BuildInfo
|
clipboardAvailable bool
|
||||||
logger *slog.Logger
|
configFilePath string
|
||||||
|
buildInfo domain.BuildInfo
|
||||||
|
logger *slog.Logger
|
||||||
|
|
||||||
// tview state
|
// tview state
|
||||||
|
|
||||||
@ -214,14 +216,16 @@ func StartUI(ctx context.Context, params StartParams) (*UI, error) {
|
|||||||
app.EnableMouse(false)
|
app.EnableMouse(false)
|
||||||
|
|
||||||
ui := &UI{
|
ui := &UI{
|
||||||
commandCh: commandCh,
|
commandCh: commandCh,
|
||||||
buildInfo: params.BuildInfo,
|
clipboardAvailable: params.ClipboardAvailable,
|
||||||
logger: params.Logger,
|
configFilePath: params.ConfigFilePath,
|
||||||
app: app,
|
buildInfo: params.BuildInfo,
|
||||||
screen: screen,
|
logger: params.Logger,
|
||||||
screenCaptureC: screenCaptureC,
|
app: app,
|
||||||
pages: pages,
|
screen: screen,
|
||||||
container: container,
|
screenCaptureC: screenCaptureC,
|
||||||
|
pages: pages,
|
||||||
|
container: container,
|
||||||
sourceViews: sourceViews{
|
sourceViews: sourceViews{
|
||||||
url: urlTextView,
|
url: urlTextView,
|
||||||
status: statusTextView,
|
status: statusTextView,
|
||||||
@ -237,45 +241,7 @@ func StartUI(ctx context.Context, params StartParams) (*UI, error) {
|
|||||||
urlsToStartState: make(map[string]startState),
|
urlsToStartState: make(map[string]startState),
|
||||||
}
|
}
|
||||||
|
|
||||||
app.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
|
app.SetInputCapture(ui.handleInputCapture)
|
||||||
// Special case: allow all keys except Escape to be passed to the add
|
|
||||||
// destination modal.
|
|
||||||
//
|
|
||||||
// TODO: catch Ctrl-c
|
|
||||||
if pageName, _ := pages.GetFrontPage(); pageName == pageNameAddDestination {
|
|
||||||
if event.Key() == tcell.KeyEscape {
|
|
||||||
ui.closeAddDestinationForm()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return event
|
|
||||||
}
|
|
||||||
|
|
||||||
switch event.Key() {
|
|
||||||
case tcell.KeyRune:
|
|
||||||
switch event.Rune() {
|
|
||||||
case 'a', 'A':
|
|
||||||
ui.addDestination()
|
|
||||||
return nil
|
|
||||||
case 'r', 'R':
|
|
||||||
ui.removeDestination()
|
|
||||||
return nil
|
|
||||||
case ' ':
|
|
||||||
ui.toggleDestination()
|
|
||||||
case 'u', 'U':
|
|
||||||
ui.copySourceURLToClipboard(params.ClipboardAvailable)
|
|
||||||
case 'c', 'C':
|
|
||||||
ui.copyConfigFilePathToClipboard(params.ClipboardAvailable, params.ConfigFilePath)
|
|
||||||
case '?':
|
|
||||||
ui.showAbout()
|
|
||||||
}
|
|
||||||
case tcell.KeyCtrlC:
|
|
||||||
ui.confirmQuit()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return event
|
|
||||||
})
|
|
||||||
|
|
||||||
if ui.screenCaptureC != nil {
|
if ui.screenCaptureC != nil {
|
||||||
app.SetAfterDrawFunc(ui.captureScreen)
|
app.SetAfterDrawFunc(ui.captureScreen)
|
||||||
@ -315,6 +281,45 @@ func (ui *UI) run(ctx context.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ui *UI) handleInputCapture(event *tcell.EventKey) *tcell.EventKey {
|
||||||
|
// Special case: handle CTRL-C even when a modal is visible.
|
||||||
|
if event.Key() == tcell.KeyCtrlC {
|
||||||
|
ui.confirmQuit()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if ui.modalVisible() {
|
||||||
|
return event
|
||||||
|
}
|
||||||
|
|
||||||
|
switch event.Key() {
|
||||||
|
case tcell.KeyRune:
|
||||||
|
switch event.Rune() {
|
||||||
|
case 'a', 'A':
|
||||||
|
ui.addDestination()
|
||||||
|
return nil
|
||||||
|
case 'r', 'R':
|
||||||
|
ui.removeDestination()
|
||||||
|
return nil
|
||||||
|
case ' ':
|
||||||
|
ui.toggleDestination()
|
||||||
|
case 'u', 'U':
|
||||||
|
ui.copySourceURLToClipboard(ui.clipboardAvailable)
|
||||||
|
case 'c', 'C':
|
||||||
|
ui.copyConfigFilePathToClipboard(ui.clipboardAvailable, ui.configFilePath)
|
||||||
|
case '?':
|
||||||
|
ui.showAbout()
|
||||||
|
}
|
||||||
|
case tcell.KeyUp:
|
||||||
|
row, _ := ui.destView.GetSelection()
|
||||||
|
if row == 1 {
|
||||||
|
ui.destView.Select(ui.destView.GetRowCount(), 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return event
|
||||||
|
}
|
||||||
|
|
||||||
func (ui *UI) ShowSourceNotLiveModal() {
|
func (ui *UI) ShowSourceNotLiveModal() {
|
||||||
ui.app.QueueUpdateDraw(func() {
|
ui.app.QueueUpdateDraw(func() {
|
||||||
ui.showModal(
|
ui.showModal(
|
||||||
@ -508,6 +513,11 @@ func (ui *UI) resetFocus() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ui *UI) modalVisible() bool {
|
||||||
|
pageName, _ := ui.pages.GetFrontPage()
|
||||||
|
return pageName != pageNameMain && pageName != pageNameNoDestinations
|
||||||
|
}
|
||||||
|
|
||||||
func (ui *UI) showModal(pageName string, text string, buttons []string, doneFunc func(int, string)) {
|
func (ui *UI) showModal(pageName string, text string, buttons []string, doneFunc func(int, string)) {
|
||||||
if ui.pages.HasPage(pageName) {
|
if ui.pages.HasPage(pageName) {
|
||||||
return
|
return
|
||||||
@ -520,6 +530,11 @@ func (ui *UI) showModal(pageName string, text string, buttons []string, doneFunc
|
|||||||
SetTextColor(tcell.ColorWhite).
|
SetTextColor(tcell.ColorWhite).
|
||||||
SetDoneFunc(func(buttonIndex int, buttonLabel string) {
|
SetDoneFunc(func(buttonIndex int, buttonLabel string) {
|
||||||
ui.pages.RemovePage(pageName)
|
ui.pages.RemovePage(pageName)
|
||||||
|
|
||||||
|
if !ui.modalVisible() {
|
||||||
|
ui.app.SetInputCapture(ui.handleInputCapture)
|
||||||
|
}
|
||||||
|
|
||||||
ui.resetFocus()
|
ui.resetFocus()
|
||||||
|
|
||||||
if doneFunc != nil {
|
if doneFunc != nil {
|
||||||
@ -753,6 +768,13 @@ func (ui *UI) addDestination() {
|
|||||||
SetBorder(true).
|
SetBorder(true).
|
||||||
SetTitle("Add a new destination").
|
SetTitle("Add a new destination").
|
||||||
SetTitleAlign(tview.AlignLeft).
|
SetTitleAlign(tview.AlignLeft).
|
||||||
|
SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
|
||||||
|
if event.Key() == tcell.KeyEscape {
|
||||||
|
ui.closeAddDestinationForm()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return event
|
||||||
|
}).
|
||||||
SetRect((currWidth-formWidth)/2, (currHeight-formHeight)/2, formWidth, formHeight)
|
SetRect((currWidth-formWidth)/2, (currHeight-formHeight)/2, formWidth, formHeight)
|
||||||
|
|
||||||
ui.mu.Lock()
|
ui.mu.Lock()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user