diff --git a/widgets/account.go b/widgets/account.go index 3085d27..8857535 100644 --- a/widgets/account.go +++ b/widgets/account.go @@ -21,6 +21,7 @@ type AccountView struct { interactive ui.Interactive onInvalidate func(d ui.Drawable) runCmd func(cmd string) error + msglist *MessageList msgStores map[string]*MessageStore statusline *StatusLine statusbar *ui.Stack @@ -41,9 +42,6 @@ func NewAccountView(conf *config.AccountConfig, {ui.SIZE_EXACT, 20}, {ui.SIZE_WEIGHT, 1}, }) - spinner := NewSpinner() - spinner.Start() - grid.AddChild(spinner).At(0, 1) grid.AddChild(statusbar).At(1, 1) worker, err := worker.NewWorker(conf.Source, logger) @@ -60,11 +58,15 @@ func NewAccountView(conf *config.AccountConfig, dirlist := NewDirectoryList(conf, logger, worker) grid.AddChild(ui.NewBordered(dirlist, ui.BORDER_RIGHT)).Span(2, 1) + msglist := NewMessageList(logger, worker) + grid.AddChild(msglist).At(0, 1) + acct := &AccountView{ conf: conf, dirlist: dirlist, grid: grid, logger: logger, + msglist: msglist, msgStores: make(map[string]*MessageStore), runCmd: runCmd, statusbar: statusbar, @@ -173,7 +175,8 @@ func (acct *AccountView) onMessage(msg types.WorkerMessage) { case *types.OpenDirectory: acct.worker.PostAction(&types.FetchDirectoryContents{}, func(msg types.WorkerMessage) { - // TODO: Do we care + store := acct.msgStores[acct.dirlist.selected] + acct.msglist.SetStore(store) }) } case *types.DirectoryInfo: diff --git a/widgets/msglist.go b/widgets/msglist.go index 370ba85..8e3c2eb 100644 --- a/widgets/msglist.go +++ b/widgets/msglist.go @@ -1,6 +1,12 @@ package widgets import ( + "log" + + "github.com/gdamore/tcell" + + "git.sr.ht/~sircmpwn/aerc2/config" + "git.sr.ht/~sircmpwn/aerc2/lib/ui" "git.sr.ht/~sircmpwn/aerc2/worker/types" ) @@ -34,3 +40,86 @@ func (store *MessageStore) Update(msg types.WorkerMessage) { break } } + +type MessageList struct { + conf *config.AercConfig + logger *log.Logger + onInvalidate func(d ui.Drawable) + spinner *Spinner + store *MessageStore + worker *types.Worker +} + +// TODO: fish in config +func NewMessageList(logger *log.Logger, worker *types.Worker) *MessageList { + ml := &MessageList{ + logger: logger, + spinner: NewSpinner(), + worker: worker, + } + ml.spinner.OnInvalidate(func(_ ui.Drawable) { + ml.Invalidate() + }) + // TODO: stop spinner, probably + ml.spinner.Start() + return ml +} + +func (ml *MessageList) OnInvalidate(onInvalidate func(d ui.Drawable)) { + ml.onInvalidate = onInvalidate +} + +func (ml *MessageList) Invalidate() { + if ml.onInvalidate != nil { + ml.onInvalidate(ml) + } +} + +func (ml *MessageList) Draw(ctx *ui.Context) { + ctx.Fill(0, 0, ctx.Width(), ctx.Height(), ' ', tcell.StyleDefault) + + if ml.store == nil { + ml.spinner.Draw(ctx) + return + } + + var ( + needsHeaders []uint64 + row int = 0 + ) + + for uid, msg := range ml.store.Messages { + if row >= ctx.Height() { + break + } + + if msg == nil { + needsHeaders = append(needsHeaders, uid) + ml.spinner.Draw(ctx.Subcontext(0, row, ctx.Width(), 1)) + } + + row += 1 + } + + if len(needsHeaders) != 0 { + ml.spinner.Start() + } else { + ml.spinner.Stop() + } + + // TODO: Fetch these messages +} + +func (ml *MessageList) SetStore(store *MessageStore) { + if ml.store == store { + return + } + + ml.store = store + if store != nil { + ml.spinner.Stop() + } else { + ml.spinner.Start() + } + ml.Invalidate() +} diff --git a/widgets/spinner.go b/widgets/spinner.go index 2e7e367..812fb2c 100644 --- a/widgets/spinner.go +++ b/widgets/spinner.go @@ -36,6 +36,10 @@ func NewSpinner() *Spinner { } func (s *Spinner) Start() { + if s.IsRunning() { + return + } + s.frame = 0 go func() { for { @@ -54,6 +58,10 @@ func (s *Spinner) Start() { } func (s *Spinner) Stop() { + if !s.IsRunning() { + return + } + s.stop <- nil s.frame = -1 s.Invalidate() @@ -64,6 +72,10 @@ func (s *Spinner) IsRunning() bool { } func (s *Spinner) Draw(ctx *ui.Context) { + if !s.IsRunning() { + return + } + 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])