mirror of
https://github.com/ivabus/pop
synced 2024-11-14 04:25:08 +03:00
feat: sending email spinner
This commit is contained in:
parent
5c247b107d
commit
7952e251bd
5 changed files with 60 additions and 26 deletions
7
go.mod
7
go.mod
|
@ -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
9
go.sum
|
@ -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=
|
||||||
|
|
|
@ -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"),
|
||||||
|
|
38
model.go
38
model.go
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
2
style.go
2
style.go
|
@ -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)
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in a new issue