From 78b7e4e993f50e7b86e6cbb7ede06c6f0fa9798c Mon Sep 17 00:00:00 2001 From: Tim Culverhouse Date: Fri, 29 Apr 2022 07:48:15 -0500 Subject: [PATCH] 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 Tested-by: Koni Marti --- widgets/compose.go | 83 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 78 insertions(+), 5 deletions(-) diff --git a/widgets/compose.go b/widgets/compose.go index d660fe3..b956abc 100644 --- a/widgets/compose.go +++ b/widgets/compose.go @@ -48,6 +48,7 @@ type Composer struct { review *reviewMessage worker *types.Worker completer *completer.Completer + crypto *cryptoStatus sign bool encrypt bool @@ -114,6 +115,7 @@ func NewComposer(aerc *Aerc, acct *AccountView, conf *config.AercConfig, c.AddSignature() c.updateGrid() + c.updateCrypto() c.ShowTerminal() return c, nil @@ -176,6 +178,7 @@ func (c *Composer) Sent() bool { func (c *Composer) SetSign(sign bool) *Composer { c.sign = sign + c.updateCrypto() return c } @@ -185,6 +188,7 @@ func (c *Composer) Sign() bool { func (c *Composer) SetEncrypt(encrypt bool) *Composer { c.encrypt = encrypt + c.updateCrypto() return c } @@ -192,6 +196,36 @@ func (c *Composer) Encrypt() bool { 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 // Draw() call. func (c *Composer) SetContents(reader io.Reader) *Composer { @@ -631,7 +665,7 @@ func (c *Composer) resetReview() { if c.review != nil { c.grid.RemoveChild(c.review) 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) { c.grid.RemoveChild(c.editor) 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 = nil 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.OnEvent = c.termEvent 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) } @@ -762,9 +796,13 @@ func (c *Composer) updateGrid() { {Strategy: ui.SIZE_WEIGHT, Size: ui.Const(1)}, }) } - + crHeight := 0 + if c.sign || c.encrypt { + crHeight = 1 + } c.grid.Rows([]ui.GridSpec{ {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_WEIGHT, Size: ui.Const(1)}, }) @@ -776,7 +814,7 @@ func (c *Composer) updateGrid() { borderChar := c.acct.UiConfig().BorderCharHorizontal c.heditors = heditors 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 { @@ -1019,3 +1057,38 @@ func (rm *reviewMessage) OnInvalidate(fn func(ui.Drawable)) { func (rm *reviewMessage) Draw(ctx *ui.Context) { 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) + }) +}