compose: add sign/encrypt persistent display

Add a text row below the header editors to (persistently) display if the
current message will be signed, encrypted, or both. The display will
disappear if the message will not be signed or encrypted. The display
is visible on the reviewMessage screen as well

Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Tested-by: Koni Marti <koni.marti@gmail.com>
This commit is contained in:
Tim Culverhouse 2022-04-29 07:48:15 -05:00 committed by Robin Jarry
parent e1ae7b80cc
commit 78b7e4e993

View file

@ -48,6 +48,7 @@ type Composer struct {
review *reviewMessage review *reviewMessage
worker *types.Worker worker *types.Worker
completer *completer.Completer completer *completer.Completer
crypto *cryptoStatus
sign bool sign bool
encrypt bool encrypt bool
@ -114,6 +115,7 @@ func NewComposer(aerc *Aerc, acct *AccountView, conf *config.AercConfig,
c.AddSignature() c.AddSignature()
c.updateGrid() c.updateGrid()
c.updateCrypto()
c.ShowTerminal() c.ShowTerminal()
return c, nil return c, nil
@ -176,6 +178,7 @@ func (c *Composer) Sent() bool {
func (c *Composer) SetSign(sign bool) *Composer { func (c *Composer) SetSign(sign bool) *Composer {
c.sign = sign c.sign = sign
c.updateCrypto()
return c return c
} }
@ -185,6 +188,7 @@ func (c *Composer) Sign() bool {
func (c *Composer) SetEncrypt(encrypt bool) *Composer { func (c *Composer) SetEncrypt(encrypt bool) *Composer {
c.encrypt = encrypt c.encrypt = encrypt
c.updateCrypto()
return c return c
} }
@ -192,6 +196,36 @@ func (c *Composer) Encrypt() bool {
return c.encrypt return c.encrypt
} }
func (c *Composer) updateCrypto() {
if c.crypto == nil {
c.crypto = newCryptoStatus(&c.config.Ui)
}
crHeight := 0
st := ""
switch {
case c.sign && c.encrypt:
st = "Sign & Encrypt"
crHeight = 1
case c.sign:
st = "Sign"
crHeight = 1
case c.encrypt:
st = "Encrypt"
crHeight = 1
default:
st = ""
}
c.crypto.status.Text(st)
hHeight := len(c.layout)
c.grid.Rows([]ui.GridSpec{
{Strategy: ui.SIZE_EXACT, Size: ui.Const(hHeight)},
{Strategy: ui.SIZE_EXACT, Size: ui.Const(crHeight)},
{Strategy: ui.SIZE_EXACT, Size: ui.Const(1)},
{Strategy: ui.SIZE_WEIGHT, Size: ui.Const(1)},
})
c.grid.AddChild(c.crypto).At(1, 0)
}
// Note: this does not reload the editor. You must call this before the first // Note: this does not reload the editor. You must call this before the first
// Draw() call. // Draw() call.
func (c *Composer) SetContents(reader io.Reader) *Composer { func (c *Composer) SetContents(reader io.Reader) *Composer {
@ -631,7 +665,7 @@ func (c *Composer) resetReview() {
if c.review != nil { if c.review != nil {
c.grid.RemoveChild(c.review) c.grid.RemoveChild(c.review)
c.review = newReviewMessage(c, nil) c.review = newReviewMessage(c, nil)
c.grid.AddChild(c.review).At(2, 0) c.grid.AddChild(c.review).At(3, 0)
} }
} }
@ -650,7 +684,7 @@ func (c *Composer) termEvent(event tcell.Event) bool {
func (c *Composer) termClosed(err error) { func (c *Composer) termClosed(err error) {
c.grid.RemoveChild(c.editor) c.grid.RemoveChild(c.editor)
c.review = newReviewMessage(c, err) c.review = newReviewMessage(c, err)
c.grid.AddChild(c.review).At(2, 0) c.grid.AddChild(c.review).At(3, 0)
c.editor.Destroy() c.editor.Destroy()
c.editor = nil c.editor = nil
c.focusable = c.focusable[:len(c.focusable)-1] c.focusable = c.focusable[:len(c.focusable)-1]
@ -677,7 +711,7 @@ func (c *Composer) ShowTerminal() {
c.editor, _ = NewTerminal(editor) // TODO: handle error c.editor, _ = NewTerminal(editor) // TODO: handle error
c.editor.OnEvent = c.termEvent c.editor.OnEvent = c.termEvent
c.editor.OnClose = c.termClosed c.editor.OnClose = c.termClosed
c.grid.AddChild(c.editor).At(2, 0) c.grid.AddChild(c.editor).At(3, 0)
c.focusable = append(c.focusable, c.editor) c.focusable = append(c.focusable, c.editor)
} }
@ -762,9 +796,13 @@ func (c *Composer) updateGrid() {
{Strategy: ui.SIZE_WEIGHT, Size: ui.Const(1)}, {Strategy: ui.SIZE_WEIGHT, Size: ui.Const(1)},
}) })
} }
crHeight := 0
if c.sign || c.encrypt {
crHeight = 1
}
c.grid.Rows([]ui.GridSpec{ c.grid.Rows([]ui.GridSpec{
{Strategy: ui.SIZE_EXACT, Size: ui.Const(height)}, {Strategy: ui.SIZE_EXACT, Size: ui.Const(height)},
{Strategy: ui.SIZE_EXACT, Size: ui.Const(crHeight)},
{Strategy: ui.SIZE_EXACT, Size: ui.Const(1)}, {Strategy: ui.SIZE_EXACT, Size: ui.Const(1)},
{Strategy: ui.SIZE_WEIGHT, Size: ui.Const(1)}, {Strategy: ui.SIZE_WEIGHT, Size: ui.Const(1)},
}) })
@ -776,7 +814,7 @@ func (c *Composer) updateGrid() {
borderChar := c.acct.UiConfig().BorderCharHorizontal borderChar := c.acct.UiConfig().BorderCharHorizontal
c.heditors = heditors c.heditors = heditors
c.grid.AddChild(c.heditors).At(0, 0) c.grid.AddChild(c.heditors).At(0, 0)
c.grid.AddChild(ui.NewFill(borderChar, borderStyle)).At(1, 0) c.grid.AddChild(ui.NewFill(borderChar, borderStyle)).At(2, 0)
} }
func (c *Composer) reloadEmail() error { func (c *Composer) reloadEmail() error {
@ -1019,3 +1057,38 @@ func (rm *reviewMessage) OnInvalidate(fn func(ui.Drawable)) {
func (rm *reviewMessage) Draw(ctx *ui.Context) { func (rm *reviewMessage) Draw(ctx *ui.Context) {
rm.grid.Draw(ctx) rm.grid.Draw(ctx)
} }
type cryptoStatus struct {
title string
status *ui.Text
uiConfig *config.UIConfig
}
func newCryptoStatus(uiConfig *config.UIConfig) *cryptoStatus {
defaultStyle := uiConfig.GetStyle(config.STYLE_DEFAULT)
return &cryptoStatus{
title: "Security",
status: ui.NewText("", defaultStyle),
uiConfig: uiConfig,
}
}
func (cs *cryptoStatus) Draw(ctx *ui.Context) {
// Extra character to put a blank cell between the header and the input
size := runewidth.StringWidth(cs.title+":") + 1
defaultStyle := cs.uiConfig.GetStyle(config.STYLE_DEFAULT)
titleStyle := cs.uiConfig.GetStyle(config.STYLE_HEADER)
ctx.Fill(0, 0, size, ctx.Height(), ' ', defaultStyle)
ctx.Printf(0, 0, titleStyle, "%s:", cs.title)
cs.status.Draw(ctx.Subcontext(size, 0, ctx.Width()-size, 1))
}
func (cs *cryptoStatus) Invalidate() {
cs.status.Invalidate()
}
func (cs *cryptoStatus) OnInvalidate(fn func(ui.Drawable)) {
cs.status.OnInvalidate(func(_ ui.Drawable) {
fn(cs)
})
}