feat: sending email spinner

This commit is contained in:
Maas Lalani 2023-06-13 23:53:24 -04:00
parent 5c247b107d
commit 7952e251bd
No known key found for this signature in database
GPG key ID: 5A6ED5CBF1A0A000
5 changed files with 60 additions and 26 deletions

7
go.mod
View file

@ -4,15 +4,17 @@ go 1.19
require ( require (
github.com/charmbracelet/bubbles v0.16.1 github.com/charmbracelet/bubbles v0.16.1
github.com/charmbracelet/bubbletea v0.24.3-0.20230609163353-b80eb8303bba
github.com/charmbracelet/lipgloss v0.7.1
github.com/spf13/cobra v1.7.0 github.com/spf13/cobra v1.7.0
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1
) )
require ( require (
github.com/atotto/clipboard v0.1.4 // indirect github.com/atotto/clipboard v0.1.4 // indirect
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/charmbracelet/bubbletea v0.24.3-0.20230609163353-b80eb8303bba // indirect
github.com/charmbracelet/lipgloss v0.7.1 // indirect
github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 // indirect github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/mattn/go-isatty v0.0.18 // indirect github.com/mattn/go-isatty v0.0.18 // indirect
@ -23,6 +25,7 @@ require (
github.com/muesli/reflow v0.3.0 // indirect github.com/muesli/reflow v0.3.0 // indirect
github.com/muesli/termenv v0.15.1 // indirect github.com/muesli/termenv v0.15.1 // indirect
github.com/rivo/uniseg v0.2.0 // indirect github.com/rivo/uniseg v0.2.0 // indirect
github.com/sahilm/fuzzy v0.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/pflag v1.0.5 // indirect
golang.org/x/sync v0.1.0 // indirect golang.org/x/sync v0.1.0 // indirect
golang.org/x/sys v0.6.0 // indirect golang.org/x/sys v0.6.0 // indirect

9
go.sum
View file

@ -4,8 +4,6 @@ github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiE
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
github.com/charmbracelet/bubbles v0.16.1 h1:6uzpAAaT9ZqKssntbvZMlksWHruQLNxg49H5WdeuYSY= github.com/charmbracelet/bubbles v0.16.1 h1:6uzpAAaT9ZqKssntbvZMlksWHruQLNxg49H5WdeuYSY=
github.com/charmbracelet/bubbles v0.16.1/go.mod h1:2QCp9LFlEsBQMvIYERr7Ww2H2bA7xen1idUDIzm/+Xc= github.com/charmbracelet/bubbles v0.16.1/go.mod h1:2QCp9LFlEsBQMvIYERr7Ww2H2bA7xen1idUDIzm/+Xc=
github.com/charmbracelet/bubbletea v0.24.1 h1:LpdYfnu+Qc6XtvMz6d/6rRY71yttHTP5HtrjMgWvixc=
github.com/charmbracelet/bubbletea v0.24.1/go.mod h1:rK3g/2+T8vOSEkNHvtq40umJpeVYDn6bLaqbgzhL/hg=
github.com/charmbracelet/bubbletea v0.24.3-0.20230609163353-b80eb8303bba h1:hWjlqzPiG3dWN5KZUAKKnqz/R8BlYqX1Aw+nk7riQss= github.com/charmbracelet/bubbletea v0.24.3-0.20230609163353-b80eb8303bba h1:hWjlqzPiG3dWN5KZUAKKnqz/R8BlYqX1Aw+nk7riQss=
github.com/charmbracelet/bubbletea v0.24.3-0.20230609163353-b80eb8303bba/go.mod h1:XdrNrV4J8GiyshTtx3DNuYkR1FDaJmO3l2nejekbsgg= github.com/charmbracelet/bubbletea v0.24.3-0.20230609163353-b80eb8303bba/go.mod h1:XdrNrV4J8GiyshTtx3DNuYkR1FDaJmO3l2nejekbsgg=
github.com/charmbracelet/lipgloss v0.7.1 h1:17WMwi7N1b1rVWOjMT+rCh7sQkvDU75B2hbZpc5Kc1E= github.com/charmbracelet/lipgloss v0.7.1 h1:17WMwi7N1b1rVWOjMT+rCh7sQkvDU75B2hbZpc5Kc1E=
@ -13,8 +11,11 @@ github.com/charmbracelet/lipgloss v0.7.1/go.mod h1:yG0k3giv8Qj8edTCbbg6AlQ5e8KNW
github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 h1:q2hJAaP1k2wIvVRd/hEHD7lacgqrCPS+k8g1MndzfWY= github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 h1:q2hJAaP1k2wIvVRd/hEHD7lacgqrCPS+k8g1MndzfWY=
github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk= github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98= github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98=
@ -36,10 +37,14 @@ github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sahilm/fuzzy v0.1.0 h1:FzWGaw2Opqyu+794ZQ9SYifWv2EIXpwP4q8dY1kDAwI=
github.com/sahilm/fuzzy v0.1.0/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=
github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc=
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=

View file

@ -15,11 +15,11 @@ type KeyMap struct {
func DefaultKeybinds() KeyMap { func DefaultKeybinds() KeyMap {
return KeyMap{ return KeyMap{
NextInput: key.NewBinding( NextInput: key.NewBinding(
key.WithKeys("tab", "ctrl+n"), key.WithKeys("tab"),
key.WithHelp("tab", "next"), key.WithHelp("tab", "next"),
), ),
PrevInput: key.NewBinding( PrevInput: key.NewBinding(
key.WithKeys("shift+tab", "ctrl+p"), key.WithKeys("shift+tab"),
), ),
Send: key.NewBinding( Send: key.NewBinding(
key.WithKeys("ctrl+d", "enter"), key.WithKeys("ctrl+d", "enter"),

View file

@ -8,9 +8,11 @@ import (
"github.com/charmbracelet/bubbles/help" "github.com/charmbracelet/bubbles/help"
"github.com/charmbracelet/bubbles/key" "github.com/charmbracelet/bubbles/key"
"github.com/charmbracelet/bubbles/list" "github.com/charmbracelet/bubbles/list"
"github.com/charmbracelet/bubbles/spinner"
"github.com/charmbracelet/bubbles/textarea" "github.com/charmbracelet/bubbles/textarea"
"github.com/charmbracelet/bubbles/textinput" "github.com/charmbracelet/bubbles/textinput"
tea "github.com/charmbracelet/bubbletea" tea "github.com/charmbracelet/bubbletea"
"golang.org/x/exp/constraints"
) )
type State int type State int
@ -45,6 +47,7 @@ type Model struct {
// filepicker is used to pick file attachments. // filepicker is used to pick file attachments.
filepicker filepicker.Model filepicker filepicker.Model
loadingSpinner spinner.Model
help help.Model help help.Model
keymap KeyMap keymap KeyMap
quitting bool quitting bool
@ -76,7 +79,7 @@ func NewModel() Model {
subject.Placeholder = "Hello!" subject.Placeholder = "Hello!"
body := textarea.New() body := textarea.New()
body.Placeholder = "# Hi" body.Placeholder = "# Email"
body.ShowLineNumbers = false body.ShowLineNumbers = false
body.FocusedStyle.CursorLine = activeTextStyle body.FocusedStyle.CursorLine = activeTextStyle
body.FocusedStyle.Prompt = activeLabelStyle body.FocusedStyle.Prompt = activeLabelStyle
@ -103,6 +106,9 @@ func NewModel() Model {
picker := filepicker.New() picker := filepicker.New()
picker.CurrentDirectory, _ = os.UserHomeDir() picker.CurrentDirectory, _ = os.UserHomeDir()
loadingSpinner := spinner.NewModel()
loadingSpinner.Spinner = spinner.Dot
return Model{ return Model{
state: editingFrom, state: editingFrom,
From: from, From: from,
@ -113,6 +119,7 @@ func NewModel() Model {
filepicker: picker, filepicker: picker,
help: help.New(), help: help.New(),
keymap: DefaultKeybinds(), keymap: DefaultKeybinds(),
loadingSpinner: loadingSpinner,
} }
} }
@ -168,6 +175,10 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.focusActiveInput() m.focusActiveInput()
case key.Matches(msg, m.keymap.Send): case key.Matches(msg, m.keymap.Send):
m.state = sendingEmail
return m, tea.Batch(
m.loadingSpinner.Tick,
)
case key.Matches(msg, m.keymap.Attach): case key.Matches(msg, m.keymap.Attach):
m.state = pickingFile m.state = pickingFile
case key.Matches(msg, m.keymap.Unattach): case key.Matches(msg, m.keymap.Unattach):
@ -194,19 +205,22 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.filepicker, cmd = m.filepicker.Update(msg) m.filepicker, cmd = m.filepicker.Update(msg)
cmds = append(cmds, cmd) cmds = append(cmds, cmd)
if m.state == pickingFile { switch m.state {
case pickingFile:
if didSelect, path := m.filepicker.DidSelectFile(msg); didSelect { if didSelect, path := m.filepicker.DidSelectFile(msg); didSelect {
m.Attachments.InsertItem(0, attachment(path)) m.Attachments.InsertItem(0, attachment(path))
m.Attachments.SetHeight(len(m.Attachments.Items()) + 2) m.Attachments.SetHeight(len(m.Attachments.Items()) + 2)
m.state = editingAttachments m.state = editingAttachments
m.updateKeymap() m.updateKeymap()
} }
} case editingAttachments:
if m.state == editingAttachments {
m.Attachments, cmd = m.Attachments.Update(msg) m.Attachments, cmd = m.Attachments.Update(msg)
cmds = append(cmds, cmd) cmds = append(cmds, cmd)
case sendingEmail:
m.loadingSpinner, cmd = m.loadingSpinner.Update(msg)
cmds = append(cmds, cmd)
} }
m.help, cmd = m.help.Update(msg) m.help, cmd = m.help.Update(msg)
cmds = append(cmds, cmd) cmds = append(cmds, cmd)
@ -259,9 +273,12 @@ func (m Model) View() string {
return "" return ""
} }
if m.state == pickingFile { switch m.state {
case pickingFile:
return "\n" + activeLabelStyle.Render("Attachments") + return "\n" + activeLabelStyle.Render("Attachments") +
"\n\n" + m.filepicker.View() "\n\n" + m.filepicker.View()
case sendingEmail:
return "\n " + m.loadingSpinner.View() + "Sending email"
} }
var s strings.Builder var s strings.Builder
@ -278,5 +295,12 @@ func (m Model) View() string {
s.WriteString("\n") s.WriteString("\n")
s.WriteString(m.help.View(m.keymap)) s.WriteString(m.help.View(m.keymap))
return s.String() return paddedStyle.Render(s.String())
}
func max[T constraints.Ordered](a, b T) T {
if a > b {
return a
}
return b
} }

View file

@ -17,4 +17,6 @@ var (
placeholderStyle = lipgloss.NewStyle().Foreground(darkGrayColor) placeholderStyle = lipgloss.NewStyle().Foreground(darkGrayColor)
cursorStyle = lipgloss.NewStyle().Foreground(whiteColor) cursorStyle = lipgloss.NewStyle().Foreground(whiteColor)
paddedStyle = lipgloss.NewStyle().Padding(1)
) )