2020-06-18 23:54:48 +03:00
package display
import (
2020-06-22 03:37:27 +03:00
"fmt"
2020-06-18 23:54:48 +03:00
"strconv"
"strings"
2020-07-11 01:59:51 +03:00
"time"
2020-06-18 23:54:48 +03:00
2020-08-22 16:03:13 +03:00
humanize "github.com/dustin/go-humanize"
2020-06-18 23:54:48 +03:00
"github.com/gdamore/tcell"
2020-07-28 23:58:32 +03:00
"github.com/makeworld-the-better-one/amfora/config"
2020-06-24 18:37:32 +03:00
"github.com/spf13/viper"
2020-06-18 23:54:48 +03:00
"gitlab.com/tslocum/cview"
)
2020-06-24 03:07:25 +03:00
// This file contains code for the popups / modals used in the display.
// The bookmark modal is in bookmarks.go
2020-06-18 23:54:48 +03:00
var infoModal = cview . NewModal ( ) .
AddButtons ( [ ] string { "Ok" } )
var errorModal = cview . NewModal ( ) .
AddButtons ( [ ] string { "Ok" } )
2020-07-28 23:58:32 +03:00
var inputModal = cview . NewModal ( )
2020-06-18 23:54:48 +03:00
var inputCh = make ( chan string )
var inputModalText string // The current text of the input field in the modal
var yesNoModal = cview . NewModal ( ) .
AddButtons ( [ ] string { "Yes" , "No" } )
2020-06-19 00:23:54 +03:00
// Channel to receive yesNo answer on
2020-06-18 23:54:48 +03:00
var yesNoCh = make ( chan bool )
func modalInit ( ) {
2020-06-24 03:07:25 +03:00
tabPages . AddPage ( "info" , infoModal , false , false ) .
AddPage ( "error" , errorModal , false , false ) .
AddPage ( "input" , inputModal , false , false ) .
AddPage ( "yesno" , yesNoModal , false , false ) .
2020-07-10 21:37:18 +03:00
AddPage ( "bkmk" , bkmkModal , false , false ) .
AddPage ( "dlChoice" , dlChoiceModal , false , false ) .
AddPage ( "dl" , dlModal , false , false )
2020-06-24 03:07:25 +03:00
2020-06-24 18:37:32 +03:00
// Color setup
if viper . GetBool ( "a-general.color" ) {
2020-07-28 23:58:32 +03:00
infoModal . SetBackgroundColor ( config . GetColor ( "info_modal_bg" ) ) .
SetButtonBackgroundColor ( config . GetColor ( "btn_bg" ) ) .
SetButtonTextColor ( config . GetColor ( "btn_text" ) ) .
SetTextColor ( config . GetColor ( "info_modal_text" ) )
infoModal . GetFrame ( ) .
SetBorderColor ( config . GetColor ( "info_modal_text" ) ) .
SetTitleColor ( config . GetColor ( "info_modal_text" ) )
errorModal . SetBackgroundColor ( config . GetColor ( "error_modal_bg" ) ) .
SetButtonBackgroundColor ( config . GetColor ( "btn_bg" ) ) .
SetButtonTextColor ( config . GetColor ( "btn_text" ) ) .
SetTextColor ( config . GetColor ( "error_modal_text" ) )
errorModal . GetFrame ( ) .
SetBorderColor ( config . GetColor ( "error_modal_text" ) ) .
SetTitleColor ( config . GetColor ( "error_modal_text" ) )
inputModal . SetBackgroundColor ( config . GetColor ( "input_modal_bg" ) ) .
SetButtonBackgroundColor ( config . GetColor ( "btn_bg" ) ) .
SetButtonTextColor ( config . GetColor ( "btn_text" ) ) .
SetTextColor ( config . GetColor ( "input_modal_text" ) )
inputModal . GetFrame ( ) .
SetBorderColor ( config . GetColor ( "input_modal_text" ) ) .
SetTitleColor ( config . GetColor ( "input_modal_text" ) )
inputModal . GetForm ( ) .
SetFieldBackgroundColor ( config . GetColor ( "input_modal_field_bg" ) ) .
SetFieldTextColor ( config . GetColor ( "input_modal_field_text" ) )
yesNoModal . SetButtonBackgroundColor ( config . GetColor ( "btn_bg" ) ) .
SetButtonTextColor ( config . GetColor ( "btn_text" ) )
2020-06-24 18:37:32 +03:00
} else {
infoModal . SetBackgroundColor ( tcell . ColorBlack ) .
SetButtonBackgroundColor ( tcell . ColorWhite ) .
2020-07-28 23:58:32 +03:00
SetButtonTextColor ( tcell . ColorBlack ) .
SetTextColor ( tcell . ColorWhite )
infoModal . GetFrame ( ) .
SetBorderColor ( tcell . ColorWhite ) .
SetTitleColor ( tcell . ColorWhite )
2020-06-24 18:37:32 +03:00
errorModal . SetBackgroundColor ( tcell . ColorBlack ) .
SetButtonBackgroundColor ( tcell . ColorWhite ) .
2020-07-28 23:58:32 +03:00
SetButtonTextColor ( tcell . ColorBlack ) .
SetTextColor ( tcell . ColorWhite )
errorModal . GetFrame ( ) .
SetBorderColor ( tcell . ColorWhite ) .
SetTitleColor ( tcell . ColorWhite )
2020-06-24 18:37:32 +03:00
inputModal . SetBackgroundColor ( tcell . ColorBlack ) .
SetButtonBackgroundColor ( tcell . ColorWhite ) .
2020-07-28 23:58:32 +03:00
SetButtonTextColor ( tcell . ColorBlack ) .
SetTextColor ( tcell . ColorWhite )
inputModal . GetFrame ( ) .
SetBorderColor ( tcell . ColorWhite ) .
SetTitleColor ( tcell . ColorWhite )
2020-06-24 18:37:32 +03:00
inputModal . GetForm ( ) .
SetFieldBackgroundColor ( tcell . ColorWhite ) .
SetFieldTextColor ( tcell . ColorBlack )
// YesNo background color is changed in funcs
yesNoModal . SetButtonBackgroundColor ( tcell . ColorWhite ) .
SetButtonTextColor ( tcell . ColorBlack )
}
2020-06-18 23:54:48 +03:00
// Modal functions that can't be added up above, because they return the wrong type
2020-06-24 03:07:25 +03:00
2020-06-18 23:54:48 +03:00
infoModal . SetBorder ( true )
2020-07-28 23:58:32 +03:00
infoModal . GetFrame ( ) .
SetTitleAlign ( cview . AlignCenter ) .
SetTitle ( " Info " )
2020-06-18 23:54:48 +03:00
infoModal . SetDoneFunc ( func ( buttonIndex int , buttonLabel string ) {
tabPages . SwitchToPage ( strconv . Itoa ( curTab ) )
2020-07-29 01:09:36 +03:00
App . SetFocus ( tabs [ curTab ] . view )
App . Draw ( )
2020-06-18 23:54:48 +03:00
} )
errorModal . SetBorder ( true )
2020-07-28 23:58:32 +03:00
errorModal . GetFrame ( ) . SetTitleAlign ( cview . AlignCenter )
2020-06-18 23:54:48 +03:00
errorModal . SetDoneFunc ( func ( buttonIndex int , buttonLabel string ) {
tabPages . SwitchToPage ( strconv . Itoa ( curTab ) )
2020-07-29 01:09:36 +03:00
App . SetFocus ( tabs [ curTab ] . view )
App . Draw ( )
2020-06-18 23:54:48 +03:00
} )
inputModal . SetBorder ( true )
2020-07-28 23:58:32 +03:00
inputModal . GetFrame ( ) .
SetTitleAlign ( cview . AlignCenter ) .
SetTitle ( " Input " )
2020-06-18 23:54:48 +03:00
inputModal . SetDoneFunc ( func ( buttonIndex int , buttonLabel string ) {
if buttonLabel == "Send" {
inputCh <- inputModalText
return
}
// Empty string indicates no input
inputCh <- ""
} )
yesNoModal . SetBorder ( true )
2020-07-28 23:58:32 +03:00
yesNoModal . GetFrame ( ) . SetTitleAlign ( cview . AlignCenter )
2020-06-18 23:54:48 +03:00
yesNoModal . SetDoneFunc ( func ( buttonIndex int , buttonLabel string ) {
if buttonLabel == "Yes" {
yesNoCh <- true
return
}
yesNoCh <- false
} )
2020-06-24 03:07:25 +03:00
bkmkInit ( )
2020-07-10 21:37:18 +03:00
dlInit ( )
2020-06-18 23:54:48 +03:00
}
// Error displays an error on the screen in a modal.
func Error ( title , text string ) {
2020-08-22 16:03:13 +03:00
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 += "."
}
2020-06-18 23:54:48 +03:00
}
// Add spaces to title for aesthetic reasons
title = " " + strings . TrimSpace ( title ) + " "
2020-06-19 21:05:05 +03:00
errorModal . GetFrame ( ) . SetTitle ( title )
2020-06-18 23:54:48 +03:00
errorModal . SetText ( text )
tabPages . ShowPage ( "error" )
tabPages . SendToFront ( "error" )
App . SetFocus ( errorModal )
App . Draw ( )
}
// Info displays some info on the screen in a modal.
func Info ( s string ) {
infoModal . SetText ( s )
tabPages . ShowPage ( "info" )
tabPages . SendToFront ( "info" )
App . SetFocus ( infoModal )
App . Draw ( )
}
// Input pulls up a modal that asks for input, and returns the user's input.
// It returns an bool indicating if the user chose to send input or not.
func Input ( prompt string ) ( string , bool ) {
2020-06-29 20:30:20 +03:00
// 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" } )
2020-06-18 23:54:48 +03:00
inputModalText = ""
inputModal . GetForm ( ) . AddInputField ( "" , "" , 0 , nil ,
func ( text string ) {
// Store for use later
inputModalText = text
} )
2020-07-28 23:58:32 +03:00
inputModal . SetText ( prompt + " " )
2020-06-18 23:54:48 +03:00
tabPages . ShowPage ( "input" )
tabPages . SendToFront ( "input" )
App . SetFocus ( inputModal )
App . Draw ( )
resp := <- inputCh
2020-07-29 01:09:36 +03:00
2020-06-18 23:54:48 +03:00
tabPages . SwitchToPage ( strconv . Itoa ( curTab ) )
2020-07-29 01:09:36 +03:00
App . SetFocus ( tabs [ curTab ] . view )
App . Draw ( )
2020-06-18 23:54:48 +03:00
if resp == "" {
return "" , false
}
return resp , true
}
// YesNo displays a modal asking a yes-or-no question.
func YesNo ( prompt string ) bool {
2020-06-24 18:37:32 +03:00
if viper . GetBool ( "a-general.color" ) {
2020-07-28 23:58:32 +03:00
yesNoModal .
SetBackgroundColor ( config . GetColor ( "yesno_modal_bg" ) ) .
SetTextColor ( config . GetColor ( "yesno_modal_text" ) )
yesNoModal . GetFrame ( ) .
SetBorderColor ( config . GetColor ( "yesno_modal_text" ) ) .
SetTitleColor ( config . GetColor ( "yesno_modal_text" ) )
2020-06-24 18:37:32 +03:00
} else {
2020-07-28 23:58:32 +03:00
yesNoModal .
SetBackgroundColor ( tcell . ColorBlack ) .
SetTextColor ( tcell . ColorWhite )
yesNoModal . GetFrame ( ) .
SetBorderColor ( tcell . ColorWhite ) .
SetTitleColor ( tcell . ColorWhite )
2020-06-24 18:37:32 +03:00
}
2020-07-11 01:59:51 +03:00
yesNoModal . GetFrame ( ) . SetTitle ( "" )
2020-06-24 18:37:32 +03:00
yesNoModal . SetText ( prompt )
2020-06-22 03:37:27 +03:00
tabPages . ShowPage ( "yesno" )
tabPages . SendToFront ( "yesno" )
App . SetFocus ( yesNoModal )
App . Draw ( )
resp := <- yesNoCh
tabPages . SwitchToPage ( strconv . Itoa ( curTab ) )
2020-07-29 01:09:36 +03:00
App . SetFocus ( tabs [ curTab ] . view )
App . Draw ( )
2020-06-22 03:37:27 +03:00
return resp
}
// Tofu displays the TOFU warning modal.
// It returns a bool indicating whether the user wants to continue.
2020-07-11 01:59:51 +03:00
func Tofu ( host string , expiry time . Time ) bool {
2020-07-28 23:58:32 +03:00
// Reuses yesNoModal, with error color
2020-06-22 03:37:27 +03:00
2020-06-24 18:37:32 +03:00
if viper . GetBool ( "a-general.color" ) {
2020-07-28 23:58:32 +03:00
yesNoModal .
SetBackgroundColor ( config . GetColor ( "tofu_modal_bg" ) ) .
SetTextColor ( config . GetColor ( "tofu_modal_text" ) )
yesNoModal . GetFrame ( ) .
SetBorderColor ( config . GetColor ( "tofu_modal_text" ) ) .
SetTitleColor ( config . GetColor ( "tofu_modal_text" ) )
2020-06-24 18:37:32 +03:00
} else {
2020-07-28 23:58:32 +03:00
yesNoModal .
SetBackgroundColor ( tcell . ColorBlack ) .
SetTextColor ( tcell . ColorWhite )
yesNoModal .
SetBorderColor ( tcell . ColorWhite ) .
SetTitleColor ( tcell . ColorWhite )
2020-06-24 18:37:32 +03:00
}
2020-07-11 01:59:51 +03:00
yesNoModal . GetFrame ( ) . SetTitle ( " TOFU " )
2020-06-22 03:37:27 +03:00
yesNoModal . SetText (
2020-08-27 18:47:57 +03:00
//nolint:lll
2020-07-11 01:59:51 +03:00
fmt . Sprintf ( "%s's certificate has changed, possibly indicating an security issue. The certificate would have expired %s. Are you sure you want to continue? " ,
host ,
humanize . Time ( expiry ) ,
) ,
2020-06-22 03:37:27 +03:00
)
2020-06-18 23:54:48 +03:00
tabPages . ShowPage ( "yesno" )
tabPages . SendToFront ( "yesno" )
App . SetFocus ( yesNoModal )
App . Draw ( )
resp := <- yesNoCh
tabPages . SwitchToPage ( strconv . Itoa ( curTab ) )
2020-07-29 01:09:36 +03:00
App . SetFocus ( tabs [ curTab ] . view )
App . Draw ( )
2020-06-18 23:54:48 +03:00
return resp
}