aerc

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

dirlist.go (3465B)


      1 package widgets
      2 
      3 import (
      4 	"log"
      5 	"sort"
      6 
      7 	"github.com/gdamore/tcell"
      8 
      9 	"git.sr.ht/~sircmpwn/aerc/config"
     10 	"git.sr.ht/~sircmpwn/aerc/lib/ui"
     11 	"git.sr.ht/~sircmpwn/aerc/worker/types"
     12 )
     13 
     14 type DirectoryList struct {
     15 	ui.Invalidatable
     16 	conf      *config.AccountConfig
     17 	dirs      []string
     18 	logger    *log.Logger
     19 	selecting string
     20 	selected  string
     21 	spinner   *Spinner
     22 	worker    *types.Worker
     23 }
     24 
     25 func NewDirectoryList(conf *config.AccountConfig,
     26 	logger *log.Logger, worker *types.Worker) *DirectoryList {
     27 
     28 	dirlist := &DirectoryList{
     29 		conf:    conf,
     30 		logger:  logger,
     31 		spinner: NewSpinner(),
     32 		worker:  worker,
     33 	}
     34 	dirlist.spinner.OnInvalidate(func(_ ui.Drawable) {
     35 		dirlist.Invalidate()
     36 	})
     37 	dirlist.spinner.Start()
     38 	return dirlist
     39 }
     40 
     41 func (dirlist *DirectoryList) UpdateList(done func(dirs []string)) {
     42 	var dirs []string
     43 	dirlist.worker.PostAction(
     44 		&types.ListDirectories{}, func(msg types.WorkerMessage) {
     45 
     46 			switch msg := msg.(type) {
     47 			case *types.Directory:
     48 				dirs = append(dirs, msg.Name)
     49 			case *types.Done:
     50 				// There is always an INBOX, RFC-guaranteed
     51 				// However, for some reason Dovecot doesn't always send it.
     52 				inbox := false
     53 				for _, dir := range dirs {
     54 					if dir == "INBOX" {
     55 						inbox = true
     56 					}
     57 				}
     58 				if !inbox {
     59 					dirs = append(dirs, "INBOX")
     60 				}
     61 				sort.Strings(dirs)
     62 				dirlist.dirs = dirs
     63 				dirlist.spinner.Stop()
     64 				dirlist.Invalidate()
     65 				if done != nil {
     66 					done(dirs)
     67 				}
     68 			}
     69 		})
     70 }
     71 
     72 func (dirlist *DirectoryList) Select(name string) {
     73 	dirlist.selecting = name
     74 	dirlist.worker.PostAction(&types.OpenDirectory{Directory: name},
     75 		func(msg types.WorkerMessage) {
     76 			switch msg.(type) {
     77 			case *types.Error:
     78 				dirlist.selecting = ""
     79 			case *types.Done:
     80 				dirlist.selected = dirlist.selecting
     81 			}
     82 			dirlist.Invalidate()
     83 		})
     84 	dirlist.Invalidate()
     85 }
     86 
     87 func (dirlist *DirectoryList) Selected() string {
     88 	return dirlist.selected
     89 }
     90 
     91 func (dirlist *DirectoryList) Invalidate() {
     92 	dirlist.DoInvalidate(dirlist)
     93 }
     94 
     95 func (dirlist *DirectoryList) Draw(ctx *ui.Context) {
     96 	ctx.Fill(0, 0, ctx.Width(), ctx.Height(), ' ', tcell.StyleDefault)
     97 
     98 	if dirlist.spinner.IsRunning() {
     99 		dirlist.spinner.Draw(ctx)
    100 		return
    101 	}
    102 
    103 	row := 0
    104 	for _, name := range dirlist.dirs {
    105 		if row >= ctx.Height() {
    106 			break
    107 		}
    108 		if len(dirlist.conf.Folders) > 1 && name != dirlist.selected {
    109 			idx := sort.SearchStrings(dirlist.conf.Folders, name)
    110 			if idx == len(dirlist.conf.Folders) ||
    111 				dirlist.conf.Folders[idx] != name {
    112 				continue
    113 			}
    114 		}
    115 		style := tcell.StyleDefault
    116 		if name == dirlist.selected {
    117 			style = style.Foreground(tcell.ColorBlue).Reverse(true)
    118 		}
    119 		ctx.Fill(0, row, ctx.Width(), 1, ' ', style)
    120 		ctx.Printf(0, row, style, "%s", name)
    121 		row++
    122 	}
    123 }
    124 
    125 func (dirlist *DirectoryList) nextPrev(delta int) {
    126 	for i, dir := range dirlist.dirs {
    127 		if dir == dirlist.selected {
    128 			var j int
    129 			ndirs := len(dirlist.dirs)
    130 			for j = i + delta; j != i; j += delta {
    131 				if j < 0 {
    132 					j = ndirs - 1
    133 				}
    134 				if j >= ndirs {
    135 					j = 0
    136 				}
    137 				name := dirlist.dirs[j]
    138 				if len(dirlist.conf.Folders) > 1 && name != dirlist.selected {
    139 					idx := sort.SearchStrings(dirlist.conf.Folders, name)
    140 					if idx == len(dirlist.conf.Folders) ||
    141 						dirlist.conf.Folders[idx] != name {
    142 
    143 						continue
    144 					}
    145 				}
    146 				break
    147 			}
    148 			dirlist.Select(dirlist.dirs[j])
    149 			break
    150 		}
    151 	}
    152 }
    153 
    154 func (dirlist *DirectoryList) Next() {
    155 	dirlist.nextPrev(1)
    156 }
    157 
    158 func (dirlist *DirectoryList) Prev() {
    159 	dirlist.nextPrev(-1)
    160 }