mirror of
https://github.com/ivabus/pop
synced 2024-12-04 22:15: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 (
|
||||
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
|
||||
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/atotto/clipboard v0.1.4 // 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/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0 // 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/termenv v0.15.1 // 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
|
||||
golang.org/x/sync v0.1.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/charmbracelet/bubbles v0.16.1 h1:6uzpAAaT9ZqKssntbvZMlksWHruQLNxg49H5WdeuYSY=
|
||||
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/go.mod h1:XdrNrV4J8GiyshTtx3DNuYkR1FDaJmO3l2nejekbsgg=
|
||||
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/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk=
|
||||
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/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/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||
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/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
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/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/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/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
|
|
|
@ -15,11 +15,11 @@ type KeyMap struct {
|
|||
func DefaultKeybinds() KeyMap {
|
||||
return KeyMap{
|
||||
NextInput: key.NewBinding(
|
||||
key.WithKeys("tab", "ctrl+n"),
|
||||
key.WithKeys("tab"),
|
||||
key.WithHelp("tab", "next"),
|
||||
),
|
||||
PrevInput: key.NewBinding(
|
||||
key.WithKeys("shift+tab", "ctrl+p"),
|
||||
key.WithKeys("shift+tab"),
|
||||
),
|
||||
Send: key.NewBinding(
|
||||
key.WithKeys("ctrl+d", "enter"),
|
||||
|
|
64
model.go
64
model.go
|
@ -8,9 +8,11 @@ import (
|
|||
"github.com/charmbracelet/bubbles/help"
|
||||
"github.com/charmbracelet/bubbles/key"
|
||||
"github.com/charmbracelet/bubbles/list"
|
||||
"github.com/charmbracelet/bubbles/spinner"
|
||||
"github.com/charmbracelet/bubbles/textarea"
|
||||
"github.com/charmbracelet/bubbles/textinput"
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"golang.org/x/exp/constraints"
|
||||
)
|
||||
|
||||
type State int
|
||||
|
@ -44,10 +46,11 @@ type Model struct {
|
|||
Attachments list.Model
|
||||
|
||||
// filepicker is used to pick file attachments.
|
||||
filepicker filepicker.Model
|
||||
help help.Model
|
||||
keymap KeyMap
|
||||
quitting bool
|
||||
filepicker filepicker.Model
|
||||
loadingSpinner spinner.Model
|
||||
help help.Model
|
||||
keymap KeyMap
|
||||
quitting bool
|
||||
}
|
||||
|
||||
func NewModel() Model {
|
||||
|
@ -76,7 +79,7 @@ func NewModel() Model {
|
|||
subject.Placeholder = "Hello!"
|
||||
|
||||
body := textarea.New()
|
||||
body.Placeholder = "# Hi"
|
||||
body.Placeholder = "# Email"
|
||||
body.ShowLineNumbers = false
|
||||
body.FocusedStyle.CursorLine = activeTextStyle
|
||||
body.FocusedStyle.Prompt = activeLabelStyle
|
||||
|
@ -103,16 +106,20 @@ func NewModel() Model {
|
|||
picker := filepicker.New()
|
||||
picker.CurrentDirectory, _ = os.UserHomeDir()
|
||||
|
||||
loadingSpinner := spinner.NewModel()
|
||||
loadingSpinner.Spinner = spinner.Dot
|
||||
|
||||
return Model{
|
||||
state: editingFrom,
|
||||
From: from,
|
||||
To: to,
|
||||
Subject: subject,
|
||||
Body: body,
|
||||
Attachments: attachments,
|
||||
filepicker: picker,
|
||||
help: help.New(),
|
||||
keymap: DefaultKeybinds(),
|
||||
state: editingFrom,
|
||||
From: from,
|
||||
To: to,
|
||||
Subject: subject,
|
||||
Body: body,
|
||||
Attachments: attachments,
|
||||
filepicker: picker,
|
||||
help: help.New(),
|
||||
keymap: DefaultKeybinds(),
|
||||
loadingSpinner: loadingSpinner,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -168,6 +175,10 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||
m.focusActiveInput()
|
||||
|
||||
case key.Matches(msg, m.keymap.Send):
|
||||
m.state = sendingEmail
|
||||
return m, tea.Batch(
|
||||
m.loadingSpinner.Tick,
|
||||
)
|
||||
case key.Matches(msg, m.keymap.Attach):
|
||||
m.state = pickingFile
|
||||
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)
|
||||
cmds = append(cmds, cmd)
|
||||
|
||||
if m.state == pickingFile {
|
||||
switch m.state {
|
||||
case pickingFile:
|
||||
if didSelect, path := m.filepicker.DidSelectFile(msg); didSelect {
|
||||
m.Attachments.InsertItem(0, attachment(path))
|
||||
m.Attachments.SetHeight(len(m.Attachments.Items()) + 2)
|
||||
m.state = editingAttachments
|
||||
m.updateKeymap()
|
||||
}
|
||||
}
|
||||
|
||||
if m.state == editingAttachments {
|
||||
case editingAttachments:
|
||||
m.Attachments, cmd = m.Attachments.Update(msg)
|
||||
cmds = append(cmds, cmd)
|
||||
case sendingEmail:
|
||||
m.loadingSpinner, cmd = m.loadingSpinner.Update(msg)
|
||||
cmds = append(cmds, cmd)
|
||||
}
|
||||
|
||||
m.help, cmd = m.help.Update(msg)
|
||||
cmds = append(cmds, cmd)
|
||||
|
||||
|
@ -259,9 +273,12 @@ func (m Model) View() string {
|
|||
return ""
|
||||
}
|
||||
|
||||
if m.state == pickingFile {
|
||||
switch m.state {
|
||||
case pickingFile:
|
||||
return "\n" + activeLabelStyle.Render("Attachments") +
|
||||
"\n\n" + m.filepicker.View()
|
||||
case sendingEmail:
|
||||
return "\n " + m.loadingSpinner.View() + "Sending email"
|
||||
}
|
||||
|
||||
var s strings.Builder
|
||||
|
@ -278,5 +295,12 @@ func (m Model) View() string {
|
|||
s.WriteString("\n")
|
||||
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)
|
||||
cursorStyle = lipgloss.NewStyle().Foreground(whiteColor)
|
||||
|
||||
paddedStyle = lipgloss.NewStyle().Padding(1)
|
||||
)
|
||||
|
|
Loading…
Reference in a new issue