2019-01-13 17:39:06 +00:00
|
|
|
package widgets
|
|
|
|
|
|
|
|
import (
|
2019-07-10 00:04:21 +00:00
|
|
|
"errors"
|
2019-01-13 18:33:43 +00:00
|
|
|
"fmt"
|
2019-01-13 18:03:28 +00:00
|
|
|
"log"
|
2019-01-13 18:25:56 +00:00
|
|
|
|
|
|
|
"github.com/gdamore/tcell"
|
2019-01-13 18:03:28 +00:00
|
|
|
|
2019-05-18 00:57:10 +00:00
|
|
|
"git.sr.ht/~sircmpwn/aerc/config"
|
|
|
|
"git.sr.ht/~sircmpwn/aerc/lib"
|
2019-09-19 22:37:44 +00:00
|
|
|
"git.sr.ht/~sircmpwn/aerc/lib/sort"
|
2019-05-18 00:57:10 +00:00
|
|
|
"git.sr.ht/~sircmpwn/aerc/lib/ui"
|
2019-07-08 02:43:56 +00:00
|
|
|
"git.sr.ht/~sircmpwn/aerc/models"
|
2019-05-18 00:57:10 +00:00
|
|
|
"git.sr.ht/~sircmpwn/aerc/worker"
|
|
|
|
"git.sr.ht/~sircmpwn/aerc/worker/types"
|
2019-01-13 17:39:06 +00:00
|
|
|
)
|
|
|
|
|
2019-12-18 05:33:57 +00:00
|
|
|
var _ ProvidesMessages = (*AccountView)(nil)
|
|
|
|
|
2019-01-13 17:39:06 +00:00
|
|
|
type AccountView struct {
|
2019-07-21 21:39:36 +00:00
|
|
|
acct *config.AccountConfig
|
2019-09-05 22:32:36 +00:00
|
|
|
aerc *Aerc
|
2019-07-21 21:39:36 +00:00
|
|
|
conf *config.AercConfig
|
|
|
|
dirlist *DirectoryList
|
2019-12-21 15:21:25 +00:00
|
|
|
labels []string
|
2019-07-21 21:39:36 +00:00
|
|
|
grid *ui.Grid
|
|
|
|
host TabHost
|
|
|
|
logger *log.Logger
|
|
|
|
msglist *MessageList
|
|
|
|
worker *types.Worker
|
2019-01-13 17:39:06 +00:00
|
|
|
}
|
|
|
|
|
2020-01-23 12:56:48 +00:00
|
|
|
func (acct *AccountView) UiConfig() config.UIConfig {
|
2020-01-24 17:18:49 +00:00
|
|
|
return acct.conf.GetUiConfig(map[config.ContextType]string{
|
2020-01-23 12:56:48 +00:00
|
|
|
config.UI_CONTEXT_ACCOUNT: acct.AccountConfig().Name,
|
|
|
|
config.UI_CONTEXT_FOLDER: acct.Directories().Selected(),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2019-09-05 22:32:36 +00:00
|
|
|
func NewAccountView(aerc *Aerc, conf *config.AercConfig, acct *config.AccountConfig,
|
2019-03-17 20:19:15 +00:00
|
|
|
logger *log.Logger, host TabHost) *AccountView {
|
2019-01-13 17:39:06 +00:00
|
|
|
|
2020-01-24 17:18:49 +00:00
|
|
|
acctUiConf := conf.GetUiConfig(map[config.ContextType]string{
|
2020-01-23 12:56:48 +00:00
|
|
|
config.UI_CONTEXT_ACCOUNT: acct.Name,
|
|
|
|
})
|
|
|
|
|
2019-01-13 17:39:06 +00:00
|
|
|
grid := ui.NewGrid().Rows([]ui.GridSpec{
|
|
|
|
{ui.SIZE_WEIGHT, 1},
|
|
|
|
}).Columns([]ui.GridSpec{
|
2020-01-23 12:56:48 +00:00
|
|
|
{ui.SIZE_EXACT, acctUiConf.SidebarWidth},
|
2019-01-13 17:39:06 +00:00
|
|
|
{ui.SIZE_WEIGHT, 1},
|
|
|
|
})
|
2019-01-13 18:25:56 +00:00
|
|
|
|
2019-03-15 05:46:14 +00:00
|
|
|
worker, err := worker.NewWorker(acct.Source, logger)
|
2019-01-13 18:25:56 +00:00
|
|
|
if err != nil {
|
2019-05-20 23:20:20 +00:00
|
|
|
host.SetStatus(fmt.Sprintf("%s: %s", acct.Name, err)).
|
|
|
|
Color(tcell.ColorDefault, tcell.ColorRed)
|
2019-01-13 18:33:43 +00:00
|
|
|
return &AccountView{
|
2019-03-17 20:19:15 +00:00
|
|
|
acct: acct,
|
2019-09-05 22:32:36 +00:00
|
|
|
aerc: aerc,
|
2019-03-17 20:19:15 +00:00
|
|
|
grid: grid,
|
|
|
|
host: host,
|
|
|
|
logger: logger,
|
2019-01-13 18:33:43 +00:00
|
|
|
}
|
2019-01-13 18:25:56 +00:00
|
|
|
}
|
2019-01-13 18:03:28 +00:00
|
|
|
|
2020-01-23 12:56:48 +00:00
|
|
|
dirlist := NewDirectoryList(acct, &acctUiConf, logger, worker)
|
|
|
|
if acctUiConf.SidebarWidth > 0 {
|
2019-06-05 21:20:27 +00:00
|
|
|
grid.AddChild(ui.NewBordered(dirlist, ui.BORDER_RIGHT))
|
|
|
|
}
|
2019-01-13 19:25:46 +00:00
|
|
|
|
2019-09-05 22:32:36 +00:00
|
|
|
msglist := NewMessageList(conf, logger, aerc)
|
2019-03-15 01:37:00 +00:00
|
|
|
grid.AddChild(msglist).At(0, 1)
|
|
|
|
|
2019-03-15 05:46:14 +00:00
|
|
|
view := &AccountView{
|
2019-07-21 21:39:36 +00:00
|
|
|
acct: acct,
|
2019-09-05 22:32:36 +00:00
|
|
|
aerc: aerc,
|
2019-07-21 21:39:36 +00:00
|
|
|
conf: conf,
|
|
|
|
dirlist: dirlist,
|
|
|
|
grid: grid,
|
|
|
|
host: host,
|
|
|
|
logger: logger,
|
|
|
|
msglist: msglist,
|
|
|
|
worker: worker,
|
2019-01-13 18:03:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
go worker.Backend.Run()
|
|
|
|
|
2019-03-15 05:46:14 +00:00
|
|
|
worker.PostAction(&types.Configure{Config: acct}, nil)
|
|
|
|
worker.PostAction(&types.Connect{}, view.connected)
|
2019-03-17 20:19:15 +00:00
|
|
|
host.SetStatus("Connecting...")
|
2019-01-13 18:03:28 +00:00
|
|
|
|
2019-03-15 05:46:14 +00:00
|
|
|
return view
|
2019-01-13 18:03:28 +00:00
|
|
|
}
|
|
|
|
|
2019-05-19 09:49:57 +00:00
|
|
|
func (acct *AccountView) Tick() bool {
|
2019-05-20 23:20:20 +00:00
|
|
|
if acct.worker == nil {
|
|
|
|
return false
|
|
|
|
}
|
2019-05-19 09:49:57 +00:00
|
|
|
select {
|
|
|
|
case msg := <-acct.worker.Messages:
|
|
|
|
msg = acct.worker.ProcessMessage(msg)
|
|
|
|
acct.onMessage(msg)
|
|
|
|
return true
|
|
|
|
default:
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-13 20:04:01 +00:00
|
|
|
func (acct *AccountView) AccountConfig() *config.AccountConfig {
|
|
|
|
return acct.acct
|
|
|
|
}
|
|
|
|
|
2019-05-16 16:15:34 +00:00
|
|
|
func (acct *AccountView) Worker() *types.Worker {
|
|
|
|
return acct.worker
|
|
|
|
}
|
|
|
|
|
|
|
|
func (acct *AccountView) Logger() *log.Logger {
|
|
|
|
return acct.logger
|
|
|
|
}
|
|
|
|
|
2019-03-15 02:34:34 +00:00
|
|
|
func (acct *AccountView) Name() string {
|
2019-03-15 05:46:14 +00:00
|
|
|
return acct.acct.Name
|
2019-03-15 02:34:34 +00:00
|
|
|
}
|
|
|
|
|
2019-02-10 21:46:13 +00:00
|
|
|
func (acct *AccountView) Children() []ui.Drawable {
|
2019-01-20 20:08:30 +00:00
|
|
|
return acct.grid.Children()
|
|
|
|
}
|
|
|
|
|
2019-01-13 17:39:06 +00:00
|
|
|
func (acct *AccountView) OnInvalidate(onInvalidate func(d ui.Drawable)) {
|
2019-01-13 18:25:56 +00:00
|
|
|
acct.grid.OnInvalidate(func(_ ui.Drawable) {
|
|
|
|
onInvalidate(acct)
|
|
|
|
})
|
2019-01-13 17:39:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (acct *AccountView) Invalidate() {
|
|
|
|
acct.grid.Invalidate()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (acct *AccountView) Draw(ctx *ui.Context) {
|
|
|
|
acct.grid.Draw(ctx)
|
|
|
|
}
|
2019-01-13 18:33:43 +00:00
|
|
|
|
2019-09-05 22:32:36 +00:00
|
|
|
func (acct *AccountView) MouseEvent(localX int, localY int, event tcell.Event) {
|
|
|
|
acct.grid.MouseEvent(localX, localY, event)
|
|
|
|
}
|
|
|
|
|
2019-03-17 20:19:15 +00:00
|
|
|
func (acct *AccountView) Focus(focus bool) {
|
|
|
|
// TODO: Unfocus children I guess
|
2019-01-13 18:33:43 +00:00
|
|
|
}
|
2019-01-13 19:25:46 +00:00
|
|
|
|
|
|
|
func (acct *AccountView) connected(msg types.WorkerMessage) {
|
2019-05-20 18:03:00 +00:00
|
|
|
switch msg.(type) {
|
2019-01-13 19:25:46 +00:00
|
|
|
case *types.Done:
|
2019-03-17 20:19:15 +00:00
|
|
|
acct.host.SetStatus("Listing mailboxes...")
|
2019-01-13 20:32:52 +00:00
|
|
|
acct.logger.Println("Listing mailboxes...")
|
|
|
|
acct.dirlist.UpdateList(func(dirs []string) {
|
|
|
|
var dir string
|
|
|
|
for _, _dir := range dirs {
|
2019-03-16 01:33:08 +00:00
|
|
|
if _dir == acct.acct.Default {
|
2019-01-13 20:32:52 +00:00
|
|
|
dir = _dir
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
2019-06-12 06:31:51 +00:00
|
|
|
if dir == "" && len(dirs) > 0 {
|
2019-01-13 20:32:52 +00:00
|
|
|
dir = dirs[0]
|
|
|
|
}
|
2019-06-12 06:31:52 +00:00
|
|
|
if dir != "" {
|
|
|
|
acct.dirlist.Select(dir)
|
|
|
|
}
|
2019-07-31 07:50:07 +00:00
|
|
|
|
|
|
|
acct.msglist.SetInitDone()
|
2019-01-13 20:32:52 +00:00
|
|
|
acct.logger.Println("Connected.")
|
2019-03-17 20:19:15 +00:00
|
|
|
acct.host.SetStatus("Connected.")
|
2019-01-13 20:32:52 +00:00
|
|
|
})
|
2019-01-13 19:25:46 +00:00
|
|
|
}
|
|
|
|
}
|
2019-03-11 01:15:24 +00:00
|
|
|
|
|
|
|
func (acct *AccountView) Directories() *DirectoryList {
|
|
|
|
return acct.dirlist
|
|
|
|
}
|
|
|
|
|
2019-12-21 15:21:25 +00:00
|
|
|
func (acct *AccountView) Labels() []string {
|
|
|
|
return acct.labels
|
|
|
|
}
|
|
|
|
|
2019-03-15 03:41:25 +00:00
|
|
|
func (acct *AccountView) Messages() *MessageList {
|
|
|
|
return acct.msglist
|
|
|
|
}
|
|
|
|
|
2019-06-02 05:15:04 +00:00
|
|
|
func (acct *AccountView) Store() *lib.MessageStore {
|
2019-08-08 10:48:51 +00:00
|
|
|
if acct.msglist == nil {
|
|
|
|
return nil
|
|
|
|
}
|
2019-06-02 05:15:04 +00:00
|
|
|
return acct.msglist.Store()
|
|
|
|
}
|
|
|
|
|
2019-07-05 16:21:12 +00:00
|
|
|
func (acct *AccountView) SelectedAccount() *AccountView {
|
|
|
|
return acct
|
|
|
|
}
|
|
|
|
|
2019-07-10 00:04:21 +00:00
|
|
|
func (acct *AccountView) SelectedMessage() (*models.MessageInfo, error) {
|
2019-07-17 07:35:50 +00:00
|
|
|
if len(acct.msglist.Store().Uids()) == 0 {
|
2019-07-10 00:04:21 +00:00
|
|
|
return nil, errors.New("no message selected")
|
|
|
|
}
|
2019-09-10 13:53:40 +00:00
|
|
|
msg := acct.msglist.Selected()
|
|
|
|
if msg == nil {
|
|
|
|
return nil, errors.New("message not loaded")
|
|
|
|
}
|
|
|
|
return msg, nil
|
2019-06-02 05:15:04 +00:00
|
|
|
}
|
|
|
|
|
2019-12-18 05:33:57 +00:00
|
|
|
func (acct *AccountView) MarkedMessages() ([]*models.MessageInfo, error) {
|
|
|
|
store := acct.Store()
|
|
|
|
return msgInfoFromUids(store, store.Marked())
|
|
|
|
}
|
|
|
|
|
2019-07-05 16:21:12 +00:00
|
|
|
func (acct *AccountView) SelectedMessagePart() *PartInfo {
|
|
|
|
return nil
|
2019-06-02 05:15:04 +00:00
|
|
|
}
|
|
|
|
|
2019-03-11 01:15:24 +00:00
|
|
|
func (acct *AccountView) onMessage(msg types.WorkerMessage) {
|
2019-03-11 03:45:00 +00:00
|
|
|
switch msg := msg.(type) {
|
|
|
|
case *types.Done:
|
|
|
|
switch msg.InResponseTo().(type) {
|
|
|
|
case *types.OpenDirectory:
|
2019-07-21 21:39:36 +00:00
|
|
|
if store, ok := acct.dirlist.SelectedMsgStore(); ok {
|
2019-03-15 02:41:43 +00:00
|
|
|
// If we've opened this dir before, we can re-render it from
|
|
|
|
// memory while we wait for the update and the UI feels
|
|
|
|
// snappier. If not, we'll unset the store and show the spinner
|
|
|
|
// while we download the UID list.
|
|
|
|
acct.msglist.SetStore(store)
|
|
|
|
} else {
|
|
|
|
acct.msglist.SetStore(nil)
|
|
|
|
}
|
2019-06-08 17:41:56 +00:00
|
|
|
case *types.CreateDirectory:
|
|
|
|
acct.dirlist.UpdateList(nil)
|
2019-03-11 03:45:00 +00:00
|
|
|
}
|
|
|
|
case *types.DirectoryInfo:
|
2019-07-21 21:39:36 +00:00
|
|
|
if store, ok := acct.dirlist.MsgStore(msg.Info.Name); ok {
|
2019-03-11 03:45:00 +00:00
|
|
|
store.Update(msg)
|
|
|
|
} else {
|
2019-07-21 20:01:51 +00:00
|
|
|
store = lib.NewMessageStore(acct.worker, msg.Info,
|
2019-09-19 22:37:44 +00:00
|
|
|
acct.getSortCriteria(),
|
2019-07-21 20:01:51 +00:00
|
|
|
func(msg *models.MessageInfo) {
|
|
|
|
acct.conf.Triggers.ExecNewEmail(acct.acct,
|
|
|
|
acct.conf, msg)
|
2019-07-29 14:50:02 +00:00
|
|
|
}, func() {
|
2020-01-23 12:56:48 +00:00
|
|
|
if acct.UiConfig().NewMessageBell {
|
2019-07-29 14:50:02 +00:00
|
|
|
acct.host.Beep()
|
|
|
|
}
|
2019-07-21 20:01:51 +00:00
|
|
|
})
|
2019-07-21 21:39:36 +00:00
|
|
|
acct.dirlist.SetMsgStore(msg.Info.Name, store)
|
2019-05-14 00:16:55 +00:00
|
|
|
store.OnUpdate(func(_ *lib.MessageStore) {
|
|
|
|
store.OnUpdate(nil)
|
|
|
|
acct.msglist.SetStore(store)
|
|
|
|
})
|
2019-03-11 03:45:00 +00:00
|
|
|
}
|
|
|
|
case *types.DirectoryContents:
|
2019-07-21 21:39:36 +00:00
|
|
|
if store, ok := acct.dirlist.SelectedMsgStore(); ok {
|
2019-06-02 08:48:03 +00:00
|
|
|
store.Update(msg)
|
|
|
|
}
|
2019-03-31 16:35:51 +00:00
|
|
|
case *types.FullMessage:
|
2019-07-21 21:39:36 +00:00
|
|
|
if store, ok := acct.dirlist.SelectedMsgStore(); ok {
|
2019-06-02 08:48:03 +00:00
|
|
|
store.Update(msg)
|
|
|
|
}
|
2019-03-11 03:45:00 +00:00
|
|
|
case *types.MessageInfo:
|
2019-07-21 21:39:36 +00:00
|
|
|
if store, ok := acct.dirlist.SelectedMsgStore(); ok {
|
2019-06-02 08:48:03 +00:00
|
|
|
store.Update(msg)
|
|
|
|
}
|
2019-03-21 03:23:38 +00:00
|
|
|
case *types.MessagesDeleted:
|
2019-07-21 21:39:36 +00:00
|
|
|
if store, ok := acct.dirlist.SelectedMsgStore(); ok {
|
2019-06-02 08:48:03 +00:00
|
|
|
store.Update(msg)
|
|
|
|
}
|
2019-12-21 15:21:25 +00:00
|
|
|
case *types.LabelList:
|
|
|
|
acct.labels = msg.Labels
|
2019-03-11 03:45:00 +00:00
|
|
|
case *types.Error:
|
|
|
|
acct.logger.Printf("%v", msg.Error)
|
2019-03-17 20:19:15 +00:00
|
|
|
acct.host.SetStatus(fmt.Sprintf("%v", msg.Error)).
|
2019-03-30 17:05:00 +00:00
|
|
|
Color(tcell.ColorDefault, tcell.ColorRed)
|
2019-03-11 03:45:00 +00:00
|
|
|
}
|
2019-03-11 01:15:24 +00:00
|
|
|
}
|
2019-09-19 22:37:44 +00:00
|
|
|
|
|
|
|
func (acct *AccountView) getSortCriteria() []*types.SortCriterion {
|
2020-01-23 12:56:48 +00:00
|
|
|
if len(acct.UiConfig().Sort) == 0 {
|
2019-09-19 22:37:44 +00:00
|
|
|
return nil
|
|
|
|
}
|
2020-01-23 12:56:48 +00:00
|
|
|
criteria, err := sort.GetSortCriteria(acct.UiConfig().Sort)
|
2019-09-19 22:37:44 +00:00
|
|
|
if err != nil {
|
|
|
|
acct.aerc.PushError(" ui.sort: " + err.Error())
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return criteria
|
|
|
|
}
|