aerc

Working clone of aerc-mail.org
git clone git://git.danielmoch.com/aerc.git
Log | Files | Refs | README | LICENSE

account.go (5090B)


      1 package widgets
      2 
      3 import (
      4 	"fmt"
      5 	"log"
      6 
      7 	"github.com/gdamore/tcell"
      8 
      9 	"git.sr.ht/~sircmpwn/aerc/config"
     10 	"git.sr.ht/~sircmpwn/aerc/lib"
     11 	"git.sr.ht/~sircmpwn/aerc/lib/ui"
     12 	"git.sr.ht/~sircmpwn/aerc/worker"
     13 	"git.sr.ht/~sircmpwn/aerc/worker/types"
     14 )
     15 
     16 type AccountView struct {
     17 	acct      *config.AccountConfig
     18 	conf      *config.AercConfig
     19 	dirlist   *DirectoryList
     20 	grid      *ui.Grid
     21 	host      TabHost
     22 	logger    *log.Logger
     23 	msglist   *MessageList
     24 	msgStores map[string]*lib.MessageStore
     25 	worker    *types.Worker
     26 }
     27 
     28 func NewAccountView(conf *config.AercConfig, acct *config.AccountConfig,
     29 	logger *log.Logger, host TabHost) *AccountView {
     30 
     31 	grid := ui.NewGrid().Rows([]ui.GridSpec{
     32 		{ui.SIZE_WEIGHT, 1},
     33 	}).Columns([]ui.GridSpec{
     34 		{ui.SIZE_EXACT, conf.Ui.SidebarWidth},
     35 		{ui.SIZE_WEIGHT, 1},
     36 	})
     37 
     38 	worker, err := worker.NewWorker(acct.Source, logger)
     39 	if err != nil {
     40 		host.SetStatus(fmt.Sprintf("%s: %s", acct.Name, err)).
     41 			Color(tcell.ColorDefault, tcell.ColorRed)
     42 		return &AccountView{
     43 			acct:   acct,
     44 			grid:   grid,
     45 			host:   host,
     46 			logger: logger,
     47 		}
     48 	}
     49 
     50 	dirlist := NewDirectoryList(acct, logger, worker)
     51 	grid.AddChild(ui.NewBordered(dirlist, ui.BORDER_RIGHT))
     52 
     53 	msglist := NewMessageList(conf, logger)
     54 	grid.AddChild(msglist).At(0, 1)
     55 
     56 	view := &AccountView{
     57 		acct:      acct,
     58 		conf:      conf,
     59 		dirlist:   dirlist,
     60 		grid:      grid,
     61 		host:      host,
     62 		logger:    logger,
     63 		msglist:   msglist,
     64 		msgStores: make(map[string]*lib.MessageStore),
     65 		worker:    worker,
     66 	}
     67 
     68 	go worker.Backend.Run()
     69 
     70 	worker.PostAction(&types.Configure{Config: acct}, nil)
     71 	worker.PostAction(&types.Connect{}, view.connected)
     72 	host.SetStatus("Connecting...")
     73 
     74 	return view
     75 }
     76 
     77 func (acct *AccountView) Tick() bool {
     78 	if acct.worker == nil {
     79 		return false
     80 	}
     81 	select {
     82 	case msg := <-acct.worker.Messages:
     83 		msg = acct.worker.ProcessMessage(msg)
     84 		acct.onMessage(msg)
     85 		return true
     86 	default:
     87 		return false
     88 	}
     89 }
     90 
     91 func (acct *AccountView) AccountConfig() *config.AccountConfig {
     92 	return acct.acct
     93 }
     94 
     95 func (acct *AccountView) Worker() *types.Worker {
     96 	return acct.worker
     97 }
     98 
     99 func (acct *AccountView) Logger() *log.Logger {
    100 	return acct.logger
    101 }
    102 
    103 func (acct *AccountView) Name() string {
    104 	return acct.acct.Name
    105 }
    106 
    107 func (acct *AccountView) Children() []ui.Drawable {
    108 	return acct.grid.Children()
    109 }
    110 
    111 func (acct *AccountView) OnInvalidate(onInvalidate func(d ui.Drawable)) {
    112 	acct.grid.OnInvalidate(func(_ ui.Drawable) {
    113 		onInvalidate(acct)
    114 	})
    115 }
    116 
    117 func (acct *AccountView) Invalidate() {
    118 	acct.grid.Invalidate()
    119 }
    120 
    121 func (acct *AccountView) Draw(ctx *ui.Context) {
    122 	acct.grid.Draw(ctx)
    123 }
    124 
    125 func (acct *AccountView) Focus(focus bool) {
    126 	// TODO: Unfocus children I guess
    127 }
    128 
    129 func (acct *AccountView) connected(msg types.WorkerMessage) {
    130 	switch msg.(type) {
    131 	case *types.Done:
    132 		acct.host.SetStatus("Listing mailboxes...")
    133 		acct.logger.Println("Listing mailboxes...")
    134 		acct.dirlist.UpdateList(func(dirs []string) {
    135 			var dir string
    136 			for _, _dir := range dirs {
    137 				if _dir == acct.acct.Default {
    138 					dir = _dir
    139 					break
    140 				}
    141 			}
    142 			if dir == "" {
    143 				dir = dirs[0]
    144 			}
    145 			acct.dirlist.Select(dir)
    146 			acct.logger.Println("Connected.")
    147 			acct.host.SetStatus("Connected.")
    148 		})
    149 	}
    150 }
    151 
    152 func (acct *AccountView) Directories() *DirectoryList {
    153 	return acct.dirlist
    154 }
    155 
    156 func (acct *AccountView) Messages() *MessageList {
    157 	return acct.msglist
    158 }
    159 
    160 func (acct *AccountView) Store() *lib.MessageStore {
    161 	return acct.msglist.Store()
    162 }
    163 
    164 func (acct *AccountView) SelectedMessage() *types.MessageInfo {
    165 	return acct.msglist.Selected()
    166 }
    167 
    168 func (acct *AccountView) SelectedAccount() *AccountView {
    169 	return acct
    170 }
    171 
    172 func (acct *AccountView) onMessage(msg types.WorkerMessage) {
    173 	switch msg := msg.(type) {
    174 	case *types.Done:
    175 		switch msg.InResponseTo().(type) {
    176 		case *types.OpenDirectory:
    177 			if store, ok := acct.msgStores[acct.dirlist.selected]; ok {
    178 				// If we've opened this dir before, we can re-render it from
    179 				// memory while we wait for the update and the UI feels
    180 				// snappier. If not, we'll unset the store and show the spinner
    181 				// while we download the UID list.
    182 				acct.msglist.SetStore(store)
    183 			} else {
    184 				acct.msglist.SetStore(nil)
    185 			}
    186 		}
    187 	case *types.DirectoryInfo:
    188 		if store, ok := acct.msgStores[msg.Name]; ok {
    189 			store.Update(msg)
    190 		} else {
    191 			store = lib.NewMessageStore(acct.worker, msg)
    192 			acct.msgStores[msg.Name] = store
    193 			store.OnUpdate(func(_ *lib.MessageStore) {
    194 				store.OnUpdate(nil)
    195 				acct.msglist.SetStore(store)
    196 			})
    197 		}
    198 	case *types.DirectoryContents:
    199 		if store, ok := acct.msgStores[acct.dirlist.selected]; ok {
    200 			store.Update(msg)
    201 		}
    202 	case *types.FullMessage:
    203 		if store, ok := acct.msgStores[acct.dirlist.selected]; ok {
    204 			store.Update(msg)
    205 		}
    206 	case *types.MessageInfo:
    207 		if store, ok := acct.msgStores[acct.dirlist.selected]; ok {
    208 			store.Update(msg)
    209 		}
    210 	case *types.MessagesDeleted:
    211 		if store, ok := acct.msgStores[acct.dirlist.selected]; ok {
    212 			store.Update(msg)
    213 		}
    214 	case *types.Error:
    215 		acct.logger.Printf("%v", msg.Error)
    216 		acct.host.SetStatus(fmt.Sprintf("%v", msg.Error)).
    217 			Color(tcell.ColorDefault, tcell.ColorRed)
    218 	}
    219 }