mirror of
https://github.com/makeworld-the-better-one/amfora.git
synced 2024-11-25 05:39:27 +03:00
328 lines
10 KiB
Go
328 lines
10 KiB
Go
package display
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
|
|
"code.rocketnine.space/tslocum/cview"
|
|
humanize "github.com/dustin/go-humanize"
|
|
"github.com/gdamore/tcell/v2"
|
|
"github.com/makeworld-the-better-one/amfora/config"
|
|
"github.com/spf13/viper"
|
|
)
|
|
|
|
// This file contains code for the popups / modals used in the display.
|
|
// The bookmark modal is in bookmarks.go
|
|
|
|
var infoModal = cview.NewModal()
|
|
var errorModal = cview.NewModal()
|
|
var inputModal = cview.NewModal()
|
|
var yesNoModal = cview.NewModal()
|
|
|
|
var inputCh = make(chan string)
|
|
var yesNoCh = make(chan bool)
|
|
|
|
var inputModalText string // The current text of the input field in the modal
|
|
|
|
// Internal channel used to know when a modal has been dismissed
|
|
var modalDone = make(chan struct{})
|
|
|
|
func modalInit() {
|
|
infoModal.AddButtons([]string{"Ok"})
|
|
errorModal.AddButtons([]string{"Ok"})
|
|
yesNoModal.AddButtons([]string{"Yes", "No"})
|
|
|
|
panels.AddPanel(PanelInfoModal, infoModal, false, false)
|
|
panels.AddPanel(PanelErrorModal, errorModal, false, false)
|
|
panels.AddPanel(PanelInputModal, inputModal, false, false)
|
|
panels.AddPanel(PanelYesNoModal, yesNoModal, false, false)
|
|
|
|
// Color setup
|
|
if viper.GetBool("a-general.color") {
|
|
m := infoModal
|
|
m.SetBackgroundColor(config.GetColor("info_modal_bg"))
|
|
m.SetButtonBackgroundColor(config.GetColor("btn_bg"))
|
|
m.SetButtonTextColor(config.GetColor("btn_text"))
|
|
m.SetTextColor(config.GetColor("info_modal_text"))
|
|
form := m.GetForm()
|
|
form.SetButtonBackgroundColorFocused(config.GetColor("btn_text"))
|
|
form.SetButtonTextColorFocused(config.GetTextColor("btn_bg", "btn_text"))
|
|
frame := m.GetFrame()
|
|
frame.SetBorderColor(config.GetColor("info_modal_text"))
|
|
frame.SetTitleColor(config.GetColor("info_modal_text"))
|
|
|
|
m = errorModal
|
|
m.SetBackgroundColor(config.GetColor("error_modal_bg"))
|
|
m.SetButtonBackgroundColor(config.GetColor("btn_bg"))
|
|
m.SetButtonTextColor(config.GetColor("btn_text"))
|
|
m.SetTextColor(config.GetColor("error_modal_text"))
|
|
form = m.GetForm()
|
|
form.SetButtonBackgroundColorFocused(config.GetColor("btn_text"))
|
|
form.SetButtonTextColorFocused(config.GetTextColor("btn_bg", "btn_text"))
|
|
frame = errorModal.GetFrame()
|
|
frame.SetBorderColor(config.GetColor("error_modal_text"))
|
|
frame.SetTitleColor(config.GetColor("error_modal_text"))
|
|
|
|
m = inputModal
|
|
m.SetBackgroundColor(config.GetColor("input_modal_bg"))
|
|
m.SetButtonBackgroundColor(config.GetColor("btn_bg"))
|
|
m.SetButtonTextColor(config.GetColor("btn_text"))
|
|
m.SetTextColor(config.GetColor("input_modal_text"))
|
|
frame = inputModal.GetFrame()
|
|
frame.SetBorderColor(config.GetColor("input_modal_text"))
|
|
frame.SetTitleColor(config.GetColor("input_modal_text"))
|
|
form = inputModal.GetForm()
|
|
form.SetFieldBackgroundColor(config.GetColor("input_modal_field_bg"))
|
|
form.SetFieldTextColor(config.GetColor("input_modal_field_text"))
|
|
form.SetButtonBackgroundColorFocused(config.GetColor("btn_text"))
|
|
form.SetButtonTextColorFocused(config.GetTextColor("btn_bg", "btn_text"))
|
|
|
|
m = yesNoModal
|
|
m.SetButtonBackgroundColor(config.GetColor("btn_bg"))
|
|
m.SetButtonTextColor(config.GetColor("btn_text"))
|
|
form = m.GetForm()
|
|
form.SetButtonBackgroundColorFocused(config.GetColor("btn_text"))
|
|
form.SetButtonTextColorFocused(config.GetTextColor("btn_bg", "btn_text"))
|
|
} else {
|
|
m := infoModal
|
|
m.SetBackgroundColor(tcell.ColorBlack)
|
|
m.SetButtonBackgroundColor(tcell.ColorWhite)
|
|
m.SetButtonTextColor(tcell.ColorBlack)
|
|
m.SetTextColor(tcell.ColorWhite)
|
|
form := m.GetForm()
|
|
form.SetButtonBackgroundColorFocused(tcell.ColorBlack)
|
|
form.SetButtonTextColorFocused(tcell.ColorWhite)
|
|
frame := infoModal.GetFrame()
|
|
frame.SetBorderColor(tcell.ColorWhite)
|
|
frame.SetTitleColor(tcell.ColorWhite)
|
|
|
|
m = errorModal
|
|
m.SetBackgroundColor(tcell.ColorBlack)
|
|
m.SetButtonBackgroundColor(tcell.ColorWhite)
|
|
m.SetButtonTextColor(tcell.ColorBlack)
|
|
m.SetTextColor(tcell.ColorWhite)
|
|
form = m.GetForm()
|
|
form.SetButtonBackgroundColorFocused(tcell.ColorBlack)
|
|
form.SetButtonTextColorFocused(tcell.ColorWhite)
|
|
frame = errorModal.GetFrame()
|
|
frame.SetBorderColor(tcell.ColorWhite)
|
|
frame.SetTitleColor(tcell.ColorWhite)
|
|
|
|
m = inputModal
|
|
m.SetBackgroundColor(tcell.ColorBlack)
|
|
m.SetButtonBackgroundColor(tcell.ColorWhite)
|
|
m.SetButtonTextColor(tcell.ColorBlack)
|
|
m.SetTextColor(tcell.ColorWhite)
|
|
frame = inputModal.GetFrame()
|
|
frame.SetBorderColor(tcell.ColorWhite)
|
|
frame.SetTitleColor(tcell.ColorWhite)
|
|
form = inputModal.GetForm()
|
|
form.SetFieldBackgroundColor(tcell.ColorWhite)
|
|
form.SetFieldTextColor(tcell.ColorBlack)
|
|
form.SetButtonBackgroundColorFocused(tcell.ColorBlack)
|
|
form.SetButtonTextColorFocused(tcell.ColorWhite)
|
|
|
|
// YesNo background color is changed in funcs
|
|
m = yesNoModal
|
|
m.SetButtonBackgroundColor(tcell.ColorWhite)
|
|
m.SetButtonTextColor(tcell.ColorBlack)
|
|
form = m.GetForm()
|
|
form.SetButtonBackgroundColorFocused(tcell.ColorBlack)
|
|
form.SetButtonTextColorFocused(tcell.ColorWhite)
|
|
}
|
|
|
|
// Modal functions that can't be added up above, because they return the wrong type
|
|
|
|
infoModal.SetBorder(true)
|
|
frame := infoModal.GetFrame()
|
|
frame.SetTitleAlign(cview.AlignCenter)
|
|
frame.SetTitle(" Info ")
|
|
infoModal.SetDoneFunc(func(buttonIndex int, buttonLabel string) {
|
|
panels.HidePanel(PanelInfoModal)
|
|
App.SetFocus(tabs[curTab].view)
|
|
App.Draw()
|
|
modalDone <- struct{}{}
|
|
})
|
|
|
|
errorModal.SetBorder(true)
|
|
errorModal.GetFrame().SetTitleAlign(cview.AlignCenter)
|
|
errorModal.SetDoneFunc(func(buttonIndex int, buttonLabel string) {
|
|
panels.HidePanel(PanelErrorModal)
|
|
App.SetFocus(tabs[curTab].view)
|
|
App.Draw()
|
|
modalDone <- struct{}{}
|
|
})
|
|
|
|
inputModal.SetBorder(true)
|
|
frame = inputModal.GetFrame()
|
|
frame.SetTitleAlign(cview.AlignCenter)
|
|
frame.SetTitle(" Input ")
|
|
inputModal.SetDoneFunc(func(buttonIndex int, buttonLabel string) {
|
|
if buttonLabel == "Send" {
|
|
inputCh <- inputModalText
|
|
return
|
|
}
|
|
// Empty string indicates no input
|
|
inputCh <- ""
|
|
})
|
|
|
|
yesNoModal.SetBorder(true)
|
|
yesNoModal.GetFrame().SetTitleAlign(cview.AlignCenter)
|
|
yesNoModal.SetDoneFunc(func(buttonIndex int, buttonLabel string) {
|
|
if buttonLabel == "Yes" {
|
|
yesNoCh <- true
|
|
return
|
|
}
|
|
yesNoCh <- false
|
|
})
|
|
|
|
bkmkInit()
|
|
dlInit()
|
|
}
|
|
|
|
// Error displays an error on the screen in a modal, and blocks until dismissed by the user.
|
|
func Error(title, text string) {
|
|
if text == "" {
|
|
text = "No additional information."
|
|
} else {
|
|
text = strings.ToUpper(string([]rune(text)[0])) + text[1:]
|
|
if !strings.HasSuffix(text, ".") && !strings.HasSuffix(text, "!") && !strings.HasSuffix(text, "?") {
|
|
text += "."
|
|
}
|
|
}
|
|
// Add spaces to title for aesthetic reasons
|
|
title = " " + strings.TrimSpace(title) + " "
|
|
|
|
errorModal.GetFrame().SetTitle(title)
|
|
errorModal.SetText(text)
|
|
panels.ShowPanel(PanelErrorModal)
|
|
panels.SendToFront(PanelErrorModal)
|
|
App.SetFocus(errorModal)
|
|
App.Draw()
|
|
|
|
<-modalDone
|
|
}
|
|
|
|
// Info displays some info on the screen in a modal, and blocks until dismissed by the user.
|
|
func Info(s string) {
|
|
infoModal.SetText(s)
|
|
panels.ShowPanel(PanelInfoModal)
|
|
panels.SendToFront(PanelInfoModal)
|
|
App.SetFocus(infoModal)
|
|
App.Draw()
|
|
|
|
<-modalDone
|
|
}
|
|
|
|
// Input pulls up a modal that asks for input, waits for that input, and returns it.
|
|
// It returns an bool indicating if the user chose to send input or not.
|
|
func Input(prompt string, sensitive bool) (string, bool) {
|
|
// Remove elements and re-add them - to clear input text and keep input in focus
|
|
inputModal.ClearButtons()
|
|
inputModal.GetForm().Clear(false)
|
|
|
|
inputModal.AddButtons([]string{"Send", "Cancel"})
|
|
inputModalText = ""
|
|
|
|
if sensitive {
|
|
// TODO use bullet characters if user wants it once bug is fixed - see NOTES.md
|
|
inputModal.GetForm().AddPasswordField("", "", 0, '*',
|
|
func(text string) {
|
|
// Store for use later
|
|
inputModalText = text
|
|
})
|
|
} else {
|
|
inputModal.GetForm().AddInputField("", "", 0, nil,
|
|
func(text string) {
|
|
inputModalText = text
|
|
})
|
|
}
|
|
|
|
inputModal.SetText(prompt + " ")
|
|
panels.ShowPanel(PanelInputModal)
|
|
panels.SendToFront(PanelInputModal)
|
|
App.SetFocus(inputModal)
|
|
App.Draw()
|
|
|
|
resp := <-inputCh
|
|
|
|
panels.HidePanel(PanelInputModal)
|
|
App.SetFocus(tabs[curTab].view)
|
|
App.Draw()
|
|
|
|
if resp == "" {
|
|
return "", false
|
|
}
|
|
return resp, true
|
|
}
|
|
|
|
// YesNo displays a modal asking a yes-or-no question, waits for an answer, then returns it as a bool.
|
|
func YesNo(prompt string) bool {
|
|
if viper.GetBool("a-general.color") {
|
|
m := yesNoModal
|
|
m.SetBackgroundColor(config.GetColor("yesno_modal_bg"))
|
|
m.SetTextColor(config.GetColor("yesno_modal_text"))
|
|
frame := yesNoModal.GetFrame()
|
|
frame.SetBorderColor(config.GetColor("yesno_modal_text"))
|
|
frame.SetTitleColor(config.GetColor("yesno_modal_text"))
|
|
} else {
|
|
m := yesNoModal
|
|
m.SetBackgroundColor(tcell.ColorBlack)
|
|
m.SetTextColor(tcell.ColorWhite)
|
|
frame := yesNoModal.GetFrame()
|
|
frame.SetBorderColor(tcell.ColorWhite)
|
|
frame.SetTitleColor(tcell.ColorWhite)
|
|
}
|
|
yesNoModal.GetFrame().SetTitle("")
|
|
yesNoModal.SetText(prompt)
|
|
panels.ShowPanel(PanelYesNoModal)
|
|
panels.SendToFront(PanelYesNoModal)
|
|
App.SetFocus(yesNoModal)
|
|
App.Draw()
|
|
|
|
resp := <-yesNoCh
|
|
panels.HidePanel(PanelYesNoModal)
|
|
App.SetFocus(tabs[curTab].view)
|
|
App.Draw()
|
|
return resp
|
|
}
|
|
|
|
// Tofu displays the TOFU warning modal.
|
|
// It blocks then returns a bool indicating whether the user wants to continue.
|
|
func Tofu(host string, expiry time.Time) bool {
|
|
// Reuses yesNoModal, with error color
|
|
|
|
m := yesNoModal
|
|
frame := yesNoModal.GetFrame()
|
|
if viper.GetBool("a-general.color") {
|
|
m.SetBackgroundColor(config.GetColor("tofu_modal_bg"))
|
|
m.SetTextColor(config.GetColor("tofu_modal_text"))
|
|
frame.SetBorderColor(config.GetColor("tofu_modal_text"))
|
|
frame.SetTitleColor(config.GetColor("tofu_modal_text"))
|
|
} else {
|
|
m.SetBackgroundColor(tcell.ColorBlack)
|
|
m.SetTextColor(tcell.ColorWhite)
|
|
m.SetBorderColor(tcell.ColorWhite)
|
|
m.SetTitleColor(tcell.ColorWhite)
|
|
}
|
|
frame.SetTitle(" TOFU ")
|
|
m.SetText(
|
|
//nolint:lll
|
|
fmt.Sprintf("%s's certificate has changed, possibly indicating a security issue. The certificate would have expired %s. Are you sure you want to continue? ",
|
|
host,
|
|
humanize.Time(expiry),
|
|
),
|
|
)
|
|
panels.ShowPanel(PanelYesNoModal)
|
|
panels.SendToFront(PanelYesNoModal)
|
|
App.SetFocus(yesNoModal)
|
|
App.Draw()
|
|
|
|
resp := <-yesNoCh
|
|
panels.HidePanel(PanelYesNoModal)
|
|
App.SetFocus(tabs[curTab].view)
|
|
App.Draw()
|
|
return resp
|
|
}
|