feat(ui): improve modal handling
This commit is contained in:
parent
ab6ed51b77
commit
d6a028c37b
@ -61,6 +61,7 @@ func Run(ctx context.Context, params RunParams) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ui.AllowQuit()
|
||||||
|
|
||||||
srv := mediaserver.StartActor(ctx, mediaserver.StartActorParams{
|
srv := mediaserver.StartActor(ctx, mediaserver.StartActorParams{
|
||||||
ContainerClient: containerClient,
|
ContainerClient: containerClient,
|
||||||
|
@ -53,6 +53,7 @@ type UI struct {
|
|||||||
|
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
urlsToStartState map[string]startState
|
urlsToStartState map[string]startState
|
||||||
|
allowQuit bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// StartParams contains the parameters for starting a new terminal user
|
// StartParams contains the parameters for starting a new terminal user
|
||||||
@ -240,12 +241,11 @@ func (ui *UI) ShowStartupCheckModal() bool {
|
|||||||
done := make(chan bool)
|
done := make(chan bool)
|
||||||
|
|
||||||
ui.app.QueueUpdateDraw(func() {
|
ui.app.QueueUpdateDraw(func() {
|
||||||
modal := tview.NewModal()
|
ui.showModal(
|
||||||
modal.SetText("Another instance of Octoplex may already be running. Pressing continue will close that instance. Continue?").
|
modalGroupStartupCheck,
|
||||||
AddButtons([]string{"Continue", "Exit"}).
|
"Another instance of Octoplex may already be running. Pressing continue will close that instance. Continue?",
|
||||||
SetBackgroundColor(tcell.ColorBlack).
|
[]string{"Continue", "Exit"},
|
||||||
SetTextColor(tcell.ColorWhite).
|
func(buttonIndex int, _ string) {
|
||||||
SetDoneFunc(func(buttonIndex int, _ string) {
|
|
||||||
if buttonIndex == 0 {
|
if buttonIndex == 0 {
|
||||||
ui.pages.RemovePage("modal")
|
ui.pages.RemovePage("modal")
|
||||||
ui.app.SetFocus(ui.destView)
|
ui.app.SetFocus(ui.destView)
|
||||||
@ -253,15 +253,26 @@ func (ui *UI) ShowStartupCheckModal() bool {
|
|||||||
} else {
|
} else {
|
||||||
done <- false
|
done <- false
|
||||||
}
|
}
|
||||||
})
|
},
|
||||||
modal.SetBorderStyle(tcell.StyleDefault.Background(tcell.ColorBlack).Foreground(tcell.ColorWhite))
|
)
|
||||||
|
|
||||||
ui.pages.AddPage("modal", modal, true, true)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
return <-done
|
return <-done
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AllowQuit enables the quit action.
|
||||||
|
func (ui *UI) AllowQuit() {
|
||||||
|
ui.mu.Lock()
|
||||||
|
defer ui.mu.Unlock()
|
||||||
|
|
||||||
|
// This is required to prevent the user from quitting during the startup
|
||||||
|
// check modal, when the main event loop is not yet running, and avoid an
|
||||||
|
// unexpected user experience. It might be nice to find a way to remove this
|
||||||
|
// but it probably means refactoring the mediaserver actor to separate
|
||||||
|
// starting the server from starting the event loop.
|
||||||
|
ui.allowQuit = true
|
||||||
|
}
|
||||||
|
|
||||||
// SetState sets the state of the terminal user interface.
|
// SetState sets the state of the terminal user interface.
|
||||||
func (ui *UI) SetState(state domain.AppState) {
|
func (ui *UI) SetState(state domain.AppState) {
|
||||||
if state.Source.ExitReason != "" {
|
if state.Source.ExitReason != "" {
|
||||||
@ -280,6 +291,44 @@ func (ui *UI) SetState(state domain.AppState) {
|
|||||||
ui.app.QueueUpdateDraw(func() { ui.redrawFromState(stateClone) })
|
ui.app.QueueUpdateDraw(func() { ui.redrawFromState(stateClone) })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// modalGroup represents a specific modal of which only one may be shown
|
||||||
|
// simultaneously.
|
||||||
|
type modalGroup string
|
||||||
|
|
||||||
|
const (
|
||||||
|
modalGroupAbout modalGroup = "about"
|
||||||
|
modalGroupQuit modalGroup = "quit"
|
||||||
|
modalGroupStartupCheck modalGroup = "startup-check"
|
||||||
|
modalGroupClipboard modalGroup = "clipboard"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (ui *UI) showModal(group modalGroup, text string, buttons []string, doneFunc func(int, string)) {
|
||||||
|
modalName := "modal-" + string(group)
|
||||||
|
if ui.pages.HasPage(modalName) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
modal := tview.NewModal()
|
||||||
|
modal.SetText(text).
|
||||||
|
AddButtons(buttons).
|
||||||
|
SetBackgroundColor(tcell.ColorBlack).
|
||||||
|
SetTextColor(tcell.ColorWhite).
|
||||||
|
SetDoneFunc(func(buttonIndex int, buttonLabel string) {
|
||||||
|
ui.pages.RemovePage(modalName)
|
||||||
|
|
||||||
|
if ui.pages.GetPageCount() == 1 {
|
||||||
|
ui.app.SetFocus(ui.destView)
|
||||||
|
}
|
||||||
|
|
||||||
|
if doneFunc != nil {
|
||||||
|
doneFunc(buttonIndex, buttonLabel)
|
||||||
|
}
|
||||||
|
}).
|
||||||
|
SetBorderStyle(tcell.StyleDefault.Background(tcell.ColorBlack).Foreground(tcell.ColorWhite))
|
||||||
|
|
||||||
|
ui.pages.AddPage(modalName, modal, true, true)
|
||||||
|
}
|
||||||
|
|
||||||
func (ui *UI) handleMediaServerClosed(exitReason string) {
|
func (ui *UI) handleMediaServerClosed(exitReason string) {
|
||||||
done := make(chan struct{})
|
done := make(chan struct{})
|
||||||
|
|
||||||
@ -480,59 +529,50 @@ func (ui *UI) copySourceURLToClipboard(clipboardAvailable bool) {
|
|||||||
text = "Copy to clipboard not available"
|
text = "Copy to clipboard not available"
|
||||||
}
|
}
|
||||||
|
|
||||||
modal := tview.NewModal()
|
ui.showModal(
|
||||||
modal.SetText(text).
|
modalGroupClipboard,
|
||||||
AddButtons([]string{"Ok"}).
|
text,
|
||||||
SetBackgroundColor(tcell.ColorBlack).
|
[]string{"Ok"},
|
||||||
SetTextColor(tcell.ColorWhite).
|
nil,
|
||||||
SetBorderStyle(tcell.StyleDefault.Background(tcell.ColorBlack).Foreground(tcell.ColorWhite))
|
)
|
||||||
|
|
||||||
modal.SetDoneFunc(func(buttonIndex int, _ string) {
|
|
||||||
ui.pages.RemovePage("modal")
|
|
||||||
ui.app.SetFocus(ui.destView)
|
|
||||||
})
|
|
||||||
|
|
||||||
ui.pages.AddPage("modal", modal, true, true)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ui *UI) confirmQuit() {
|
func (ui *UI) confirmQuit() {
|
||||||
modal := tview.NewModal()
|
var allowQuit bool
|
||||||
modal.SetText("Are you sure you want to quit?").
|
ui.mu.Lock()
|
||||||
AddButtons([]string{"Quit", "Cancel"}).
|
allowQuit = ui.allowQuit
|
||||||
SetBackgroundColor(tcell.ColorBlack).
|
ui.mu.Unlock()
|
||||||
SetTextColor(tcell.ColorWhite).
|
|
||||||
SetDoneFunc(func(buttonIndex int, _ string) {
|
if !allowQuit {
|
||||||
if buttonIndex == 1 || buttonIndex == -1 {
|
|
||||||
ui.pages.RemovePage("modal")
|
|
||||||
ui.app.SetFocus(ui.destView)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ui.showModal(
|
||||||
|
modalGroupQuit,
|
||||||
|
"Are you sure you want to quit?",
|
||||||
|
[]string{"Quit", "Cancel"},
|
||||||
|
func(buttonIndex int, _ string) {
|
||||||
|
if buttonIndex == 0 {
|
||||||
|
ui.logger.Info("quitting")
|
||||||
ui.commandCh <- CommandQuit{}
|
ui.commandCh <- CommandQuit{}
|
||||||
})
|
return
|
||||||
modal.SetBorderStyle(tcell.StyleDefault.Background(tcell.ColorBlack).Foreground(tcell.ColorWhite))
|
}
|
||||||
|
},
|
||||||
ui.pages.AddPage("modal", modal, true, true)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ui *UI) showAbout() {
|
func (ui *UI) showAbout() {
|
||||||
modal := tview.NewModal()
|
ui.showModal(
|
||||||
modal.SetText(fmt.Sprintf(
|
modalGroupAbout,
|
||||||
|
fmt.Sprintf(
|
||||||
"%s: live stream multiplexer\n\nv0.0.0 %s (%s)",
|
"%s: live stream multiplexer\n\nv0.0.0 %s (%s)",
|
||||||
domain.AppName,
|
domain.AppName,
|
||||||
ui.buildInfo.Version,
|
ui.buildInfo.Version,
|
||||||
ui.buildInfo.GoVersion,
|
ui.buildInfo.GoVersion,
|
||||||
)).
|
),
|
||||||
AddButtons([]string{"Ok"}).
|
[]string{"Ok"},
|
||||||
SetBackgroundColor(tcell.ColorBlack).
|
nil,
|
||||||
SetTextColor(tcell.ColorWhite).
|
)
|
||||||
SetDoneFunc(func(buttonIndex int, _ string) {
|
|
||||||
ui.pages.RemovePage("modal")
|
|
||||||
ui.app.SetFocus(ui.destView)
|
|
||||||
})
|
|
||||||
modal.SetBorderStyle(tcell.StyleDefault.Background(tcell.ColorBlack).Foreground(tcell.ColorWhite))
|
|
||||||
|
|
||||||
ui.pages.AddPage("modal", modal, true, true)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// comtainerStateToStartState converts a container state to a start state.
|
// comtainerStateToStartState converts a container state to a start state.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user