From 1946985a9820947a4a6b87d1b3908c6dd6aec726 Mon Sep 17 00:00:00 2001 From: tanuj pavan sree ganesh margana Date: Thu, 16 Apr 2026 23:00:58 +0530 Subject: [PATCH] fix(settings): correct crypto config UI/UX (#535) Co-authored-by: drew --- tui/settings.go | 177 ++++++++++++++++++++++++++---------------------- 1 file changed, 95 insertions(+), 82 deletions(-) diff --git a/tui/settings.go b/tui/settings.go index 5f0fcd0d260ef33c9d81aa5dc41ac8a9bbb36327..53845fa82e0359723f9069bedb8254e3283275b7 100644 --- a/tui/settings.go +++ b/tui/settings.go @@ -390,6 +390,34 @@ const cryptoConfigMaxFocus = 9 func (m *Settings) updateSMIMEConfig(msg tea.KeyPressMsg) (*Settings, tea.Cmd) { var cmds []tea.Cmd var cmd tea.Cmd + key := msg.Key() + isEnter := key.Code == tea.KeyEnter || key.Code == tea.KeyReturn || key.Code == tea.KeyKpEnter + isSpace := key.Code == tea.KeySpace + + setFocus := func(next int) tea.Cmd { + m.focusIndex = next + + m.smimeCertInput.Blur() + m.smimeKeyInput.Blur() + m.pgpPublicKeyInput.Blur() + m.pgpPrivateKeyInput.Blur() + m.pgpPINInput.Blur() + + switch m.focusIndex { + case 0: + return m.smimeCertInput.Focus() + case 1: + return m.smimeKeyInput.Focus() + case 3: + return m.pgpPublicKeyInput.Focus() + case 4: + return m.pgpPrivateKeyInput.Focus() + case 6: + return m.pgpPINInput.Focus() + default: + return nil + } + } switch msg.String() { case "esc": @@ -408,95 +436,80 @@ func (m *Settings) updateSMIMEConfig(msg tea.KeyPressMsg) (*Settings, tea.Cmd) { } } - m.smimeCertInput.Blur() - m.smimeKeyInput.Blur() - m.pgpPublicKeyInput.Blur() - m.pgpPrivateKeyInput.Blur() - m.pgpPINInput.Blur() - - switch m.focusIndex { - case 0: - cmds = append(cmds, m.smimeCertInput.Focus()) - case 1: - cmds = append(cmds, m.smimeKeyInput.Focus()) - case 3: - cmds = append(cmds, m.pgpPublicKeyInput.Focus()) - case 4: - cmds = append(cmds, m.pgpPrivateKeyInput.Focus()) - case 6: - cmds = append(cmds, m.pgpPINInput.Focus()) + // Skip Yubikey PIN field when key source is "file" + if m.focusIndex == 6 && m.pgpKeySource != "yubikey" { + if msg.String() == "shift+tab" || msg.String() == "up" { + m.focusIndex = 5 + } else { + m.focusIndex = 7 + } } + + cmds = append(cmds, setFocus(m.focusIndex)) return m, tea.Batch(cmds...) - case "enter", " ": + } + + if isEnter { switch m.focusIndex { case 0: // S/MIME cert - enter advances to next field - if msg.String() == "enter" { - m.focusIndex = 1 - m.smimeCertInput.Blur() - cmds = append(cmds, m.smimeKeyInput.Focus()) - return m, tea.Batch(cmds...) - } + cmds = append(cmds, setFocus(1)) + return m, tea.Batch(cmds...) case 1: // S/MIME key - enter advances - if msg.String() == "enter" { - m.focusIndex = 2 - m.smimeKeyInput.Blur() - return m, nil - } - case 2: // S/MIME sign toggle - if msg.String() == "enter" || msg.String() == " " { - m.cfg.Accounts[m.editingAccountIdx].SMIMESignByDefault = !m.cfg.Accounts[m.editingAccountIdx].SMIMESignByDefault - } - return m, nil + cmds = append(cmds, setFocus(2)) + return m, tea.Batch(cmds...) + case 2: // S/MIME sign toggle - enter advances + cmds = append(cmds, setFocus(3)) + return m, tea.Batch(cmds...) case 3: // PGP public key - enter advances - if msg.String() == "enter" { - m.focusIndex = 4 - m.pgpPublicKeyInput.Blur() - cmds = append(cmds, m.pgpPrivateKeyInput.Focus()) - return m, tea.Batch(cmds...) - } + cmds = append(cmds, setFocus(4)) + return m, tea.Batch(cmds...) case 4: // PGP private key - enter advances - if msg.String() == "enter" { - m.focusIndex = 5 - m.pgpPrivateKeyInput.Blur() - return m, nil + cmds = append(cmds, setFocus(5)) + return m, tea.Batch(cmds...) + case 5: // PGP key source - enter advances + nextFocus := 7 + if m.pgpKeySource == "yubikey" { + nextFocus = 6 } + cmds = append(cmds, setFocus(nextFocus)) + return m, tea.Batch(cmds...) + case 6: // PGP PIN input - enter advances + cmds = append(cmds, setFocus(7)) + return m, tea.Batch(cmds...) + case 7: // PGP sign toggle - enter advances + cmds = append(cmds, setFocus(8)) + return m, tea.Batch(cmds...) + case 8: // Save + m.cfg.Accounts[m.editingAccountIdx].SMIMECert = m.smimeCertInput.Value() + m.cfg.Accounts[m.editingAccountIdx].SMIMEKey = m.smimeKeyInput.Value() + m.cfg.Accounts[m.editingAccountIdx].PGPPublicKey = m.pgpPublicKeyInput.Value() + m.cfg.Accounts[m.editingAccountIdx].PGPPrivateKey = m.pgpPrivateKeyInput.Value() + m.cfg.Accounts[m.editingAccountIdx].PGPKeySource = m.pgpKeySource + m.cfg.Accounts[m.editingAccountIdx].PGPPIN = m.pgpPINInput.Value() + _ = config.SaveConfig(m.cfg) + m.state = SettingsAccounts + return m, nil + case 9: // Cancel + m.state = SettingsAccounts + return m, nil + } + } + + if isSpace { + switch m.focusIndex { + case 2: // S/MIME sign toggle + m.cfg.Accounts[m.editingAccountIdx].SMIMESignByDefault = !m.cfg.Accounts[m.editingAccountIdx].SMIMESignByDefault + return m, nil case 5: // PGP key source toggle (file/yubikey) - if msg.String() == "enter" || msg.String() == " " { - if m.pgpKeySource == "file" { - m.pgpKeySource = "yubikey" - } else { - m.pgpKeySource = "file" - } + if m.pgpKeySource == "file" { + m.pgpKeySource = "yubikey" + } else { + m.pgpKeySource = "file" } return m, nil - case 6: // PGP PIN input - enter advances - if msg.String() == "enter" { - m.focusIndex = 7 - m.pgpPINInput.Blur() - return m, nil - } case 7: // PGP sign toggle - if msg.String() == "enter" || msg.String() == " " { - m.cfg.Accounts[m.editingAccountIdx].PGPSignByDefault = !m.cfg.Accounts[m.editingAccountIdx].PGPSignByDefault - } + m.cfg.Accounts[m.editingAccountIdx].PGPSignByDefault = !m.cfg.Accounts[m.editingAccountIdx].PGPSignByDefault return m, nil - case 8: // Save - if msg.String() == "enter" { - m.cfg.Accounts[m.editingAccountIdx].SMIMECert = m.smimeCertInput.Value() - m.cfg.Accounts[m.editingAccountIdx].SMIMEKey = m.smimeKeyInput.Value() - m.cfg.Accounts[m.editingAccountIdx].PGPPublicKey = m.pgpPublicKeyInput.Value() - m.cfg.Accounts[m.editingAccountIdx].PGPPrivateKey = m.pgpPrivateKeyInput.Value() - m.cfg.Accounts[m.editingAccountIdx].PGPKeySource = m.pgpKeySource - m.cfg.Accounts[m.editingAccountIdx].PGPPIN = m.pgpPINInput.Value() - _ = config.SaveConfig(m.cfg) - m.state = SettingsAccounts - return m, nil - } - case 9: // Cancel - if msg.String() == "enter" { - m.state = SettingsAccounts - return m, nil - } } } @@ -835,9 +848,9 @@ func (m *Settings) viewSMIMEConfig() string { smimeSignStatus = "ON" } if m.focusIndex == 2 { - b.WriteString(settingsFocusedStyle.Render(fmt.Sprintf("> Sign By Default: %s\n\n", smimeSignStatus))) + b.WriteString(settingsFocusedStyle.Render(fmt.Sprintf("Sign By Default: %s", smimeSignStatus)) + "\n\n") } else { - b.WriteString(settingsBlurredStyle.Render(fmt.Sprintf(" Sign By Default: %s\n\n", smimeSignStatus))) + b.WriteString(settingsBlurredStyle.Render(fmt.Sprintf("Sign By Default: %s", smimeSignStatus)) + "\n\n") } // --- PGP Section --- @@ -863,9 +876,9 @@ func (m *Settings) viewSMIMEConfig() string { keySourceDisplay = "YubiKey" } if m.focusIndex == 5 { - b.WriteString(settingsFocusedStyle.Render(fmt.Sprintf("> Key Source: %s\n\n", keySourceDisplay))) + b.WriteString(settingsFocusedStyle.Render(fmt.Sprintf("Key Source: %s", keySourceDisplay)) + "\n\n") } else { - b.WriteString(settingsBlurredStyle.Render(fmt.Sprintf(" Key Source: %s\n\n", keySourceDisplay))) + b.WriteString(settingsBlurredStyle.Render(fmt.Sprintf("Key Source: %s", keySourceDisplay)) + "\n\n") } // PIN input (only shown if YubiKey is selected) @@ -883,9 +896,9 @@ func (m *Settings) viewSMIMEConfig() string { pgpSignStatus = "ON" } if m.focusIndex == 7 { - b.WriteString(settingsFocusedStyle.Render(fmt.Sprintf("> Sign By Default: %s\n\n", pgpSignStatus))) + b.WriteString(settingsFocusedStyle.Render(fmt.Sprintf("Sign By Default: %s", pgpSignStatus)) + "\n\n") } else { - b.WriteString(settingsBlurredStyle.Render(fmt.Sprintf(" Sign By Default: %s\n\n", pgpSignStatus))) + b.WriteString(settingsBlurredStyle.Render(fmt.Sprintf("Sign By Default: %s", pgpSignStatus)) + "\n\n") } // --- Buttons ---