summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorDrew DeVault <sir@cmpwn.com>2019-01-13 20:02:21 -0500
committerDrew DeVault <sir@cmpwn.com>2019-01-13 20:02:21 -0500
commita782b709d1312bfe80dda7c864de96ba1c854bc2 (patch)
tree206846b95e787e302694cbc3f812e173eeb76b5e
parentf87fe502a6d252bac9da5f08fd2aa682a9fc2277 (diff)
downloadaerc-a782b709d1312bfe80dda7c864de96ba1c854bc2.tar.gz
Add loading spinner
-rw-r--r--widgets/directories.go20
-rw-r--r--widgets/spinner.go80
-rw-r--r--worker/messages.go91
3 files changed, 190 insertions, 1 deletions
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
+}