From a782b709d1312bfe80dda7c864de96ba1c854bc2 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Sun, 13 Jan 2019 20:02:21 -0500 Subject: [PATCH] Add loading spinner --- widgets/directories.go | 20 +++++++++- widgets/spinner.go | 80 +++++++++++++++++++++++++++++++++++++ worker/messages.go | 91 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 190 insertions(+), 1 deletion(-) create mode 100644 widgets/spinner.go create mode 100644 worker/messages.go diff --git a/widgets/directories.go b/widgets/directories.go index 13018bb..11fe2d6 100644 --- a/widgets/directories.go +++ b/widgets/directories.go @@ -17,13 +17,24 @@ type DirectoryList struct { logger *log.Logger onInvalidate func(d ui.Drawable) selected string + spinner *Spinner worker *types.Worker } func NewDirectoryList(conf *config.AccountConfig, logger *log.Logger, worker *types.Worker) *DirectoryList { - return &DirectoryList{conf: conf, logger: logger, worker: worker} + dirlist := &DirectoryList{ + conf: conf, + logger: logger, + spinner: NewSpinner(), + worker: worker, + } + dirlist.spinner.OnInvalidate(func(_ ui.Drawable) { + dirlist.Invalidate() + }) + dirlist.spinner.Start() + return dirlist } func (dirlist *DirectoryList) UpdateList(done func(dirs []string)) { @@ -37,6 +48,7 @@ func (dirlist *DirectoryList) UpdateList(done func(dirs []string)) { case *types.Done: sort.Strings(dirs) dirlist.dirs = dirs + dirlist.spinner.Stop() dirlist.Invalidate() if done != nil { done(dirs) @@ -63,6 +75,12 @@ func (dirlist *DirectoryList) Invalidate() { func (dirlist *DirectoryList) Draw(ctx *ui.Context) { ctx.Fill(0, 0, ctx.Width(), ctx.Height(), ' ', tcell.StyleDefault) + + if dirlist.spinner.IsRunning() { + dirlist.spinner.Draw(ctx) + return + } + row := 0 for _, name := range dirlist.dirs { if row >= ctx.Height() { diff --git a/widgets/spinner.go b/widgets/spinner.go new file mode 100644 index 0000000..2e7e367 --- /dev/null +++ b/widgets/spinner.go @@ -0,0 +1,80 @@ +package widgets + +import ( + "time" + + "github.com/gdamore/tcell" + + "git.sr.ht/~sircmpwn/aerc2/lib/ui" +) + +var ( + frames = []string{ + "[..] ", + " [..] ", + " [..] ", + " [..] ", + " [..]", + " [..] ", + " [..] ", + " [..] ", + } +) + +type Spinner struct { + frame int + onInvalidate func(d ui.Drawable) + stop chan interface{} +} + +func NewSpinner() *Spinner { + spinner := Spinner{ + stop: make(chan interface{}), + frame: -1, + } + return &spinner +} + +func (s *Spinner) Start() { + s.frame = 0 + go func() { + for { + select { + case <-s.stop: + return + case <-time.After(200 * time.Millisecond): + s.frame++ + if s.frame >= len(frames) { + s.frame = 0 + } + s.Invalidate() + } + } + }() +} + +func (s *Spinner) Stop() { + s.stop <- nil + s.frame = -1 + s.Invalidate() +} + +func (s *Spinner) IsRunning() bool { + return s.frame != -1 +} + +func (s *Spinner) Draw(ctx *ui.Context) { + ctx.Fill(0, 0, ctx.Width(), ctx.Height(), ' ', tcell.StyleDefault) + col := ctx.Width()/2 - len(frames[0])/2 + 1 + ctx.Printf(col, 0, tcell.StyleDefault, "%s", frames[s.frame]) +} + +func (s *Spinner) OnInvalidate(onInvalidate func(d ui.Drawable)) { + s.onInvalidate = onInvalidate +} + +func (s *Spinner) Invalidate() { + if s.onInvalidate != nil { + s.onInvalidate(s) + } +} diff --git a/worker/messages.go b/worker/messages.go new file mode 100644 index 0000000..90fcfa0 --- /dev/null +++ b/worker/messages.go @@ -0,0 +1,91 @@ +package worker + +import ( + "crypto/x509" + + "git.sr.ht/~sircmpwn/aerc2/config" +) + +type WorkerMessage interface { + InResponseTo() WorkerMessage +} + +type Message struct { + inResponseTo WorkerMessage +} + +func RespondTo(msg WorkerMessage) Message { + return Message{ + inResponseTo: msg, + } +} + +func (m Message) InResponseTo() WorkerMessage { + return m.inResponseTo +} + +// Meta-messages + +type Done struct { + Message +} + +type Error struct { + Message + Error error +} + +type Unsupported struct { + Message +} + +// Actions + +type ApproveCertificate struct { + Message + Approved bool +} + +type Configure struct { + Message + Config *config.AccountConfig +} + +type Connect struct { + Message +} + +type Disconnect struct { + Message +} + +type ListDirectories struct { + Message +} + +type OpenDirectory struct { + Message + Directory string +} + +// Messages + +type CertificateApprovalRequest struct { + Message + CertPool *x509.CertPool +} + +type Directory struct { + Message + Attributes []string + Name string +} + +type DirectoryInfo struct { + Message + Flags []string + Name string + ReadOnly bool + + Exists, Recent, Unseen int +}