summary refs log tree commit diff stats
path: root/widgets/account.go
blob: f8abdc9489e49e6e8c9bbffa0da96c0abd176e85 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
package widgets

import (
	"fmt"
	"log"

	"github.com/gdamore/tcell"

	"git.sr.ht/~sircmpwn/aerc2/config"
	"git.sr.ht/~sircmpwn/aerc2/lib"
	"git.sr.ht/~sircmpwn/aerc2/lib/ui"
	"git.sr.ht/~sircmpwn/aerc2/worker"
	"git.sr.ht/~sircmpwn/aerc2/worker/types"
)

type AccountView struct {
	acct         *config.AccountConfig
	conf         *config.AercConfig
	dirlist      *DirectoryList
	grid         *ui.Grid
	host         TabHost
	logger       *log.Logger
	onInvalidate func(d ui.Drawable)
	msglist      *MessageList
	msgStores    map[string]*lib.MessageStore
	worker       *types.Worker
}

func NewAccountView(conf *config.AercConfig, acct *config.AccountConfig,
	logger *log.Logger, host TabHost) *AccountView {

	grid := ui.NewGrid().Rows([]ui.GridSpec{
		{ui.SIZE_WEIGHT, 1},
	}).Columns([]ui.GridSpec{
		{ui.SIZE_EXACT, conf.Ui.SidebarWidth},
		{ui.SIZE_WEIGHT, 1},
	})

	worker, err := worker.NewWorker(acct.Source, logger)
	if err != nil {
		host.SetStatus(fmt.Sprintf("%s: %s", acct.Name, err))
		return &AccountView{
			acct:   acct,
			grid:   grid,
			host:   host,
			logger: logger,
		}
	}

	dirlist := NewDirectoryList(acct, logger, worker)
	grid.AddChild(ui.NewBordered(dirlist, ui.BORDER_RIGHT))

	msglist := NewMessageList(logger)
	grid.AddChild(msglist).At(0, 1)

	view := &AccountView{
		acct:      acct,
		conf:      conf,
		dirlist:   dirlist,
		grid:      grid,
		host:      host,
		logger:    logger,
		msglist:   msglist,
		msgStores: make(map[string]*lib.MessageStore),
		worker:    worker,
	}

	go worker.Backend.Run()
	go func() {
		for {
			msg := <-worker.Messages
			msg = worker.ProcessMessage(msg)
			view.onMessage(msg)
		}
	}()

	worker.PostAction(&types.Configure{Config: acct}, nil)
	worker.PostAction(&types.Connect{}, view.connected)
	host.SetStatus("Connecting...")

	return view
}

func (acct *AccountView) Name() string {
	return acct.acct.Name
}

func (acct *AccountView) Children() []ui.Drawable {
	return acct.grid.Children()
}

func (acct *AccountView) OnInvalidate(onInvalidate func(d ui.Drawable)) {
	acct.grid.OnInvalidate(func(_ ui.Drawable) {
		onInvalidate(acct)
	})
}

func (acct *AccountView) Invalidate() {
	acct.grid.Invalidate()
}

func (acct *AccountView) Draw(ctx *ui.Context) {
	acct.grid.Draw(ctx)
}

func (acct *AccountView) Focus(focus bool) {
	// TODO: Unfocus children I guess
}

func (acct *AccountView) connected(msg types.WorkerMessage) {
	switch msg := msg.(type) {
	case *types.Done:
		acct.host.SetStatus("Listing mailboxes...")
		acct.logger.Println("Listing mailboxes...")
		acct.dirlist.UpdateList(func(dirs []string) {
			var dir string
			for _, _dir := range dirs {
				if _dir == acct.acct.Default {
					dir = _dir
					break
				}
			}
			if dir == "" {
				dir = dirs[0]
			}
			acct.dirlist.Select(dir)
			acct.logger.Println("Connected.")
			acct.host.SetStatus("Connected.")
		})
	case *types.CertificateApprovalRequest:
		// TODO: Ask the user
		acct.worker.PostAction(&types.ApproveCertificate{
			Message:  types.RespondTo(msg),
			Approved: true,
		}, acct.connected)
	}
}

func (acct *AccountView) Directories() *DirectoryList {
	return acct.dirlist
}

func (acct *AccountView) Messages() *MessageList {
	return acct.msglist
}

func (acct *AccountView) onMessage(msg types.WorkerMessage) {
	switch msg := msg.(type) {
	case *types.Done:
		switch msg.InResponseTo().(type) {
		case *types.OpenDirectory:
			if store, ok := acct.msgStores[acct.dirlist.selected]; ok {
				// 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)
			}
			acct.worker.PostAction(&types.FetchDirectoryContents{},
				func(msg types.WorkerMessage) {
					store := acct.msgStores[acct.dirlist.selected]
					acct.msglist.SetStore(store)
				})
		}
	case *types.DirectoryInfo:
		if store, ok := acct.msgStores[msg.Name]; ok {
			store.Update(msg)
		} else {
			acct.msgStores[msg.Name] = lib.NewMessageStore(acct.worker, msg)
		}
	case *types.DirectoryContents:
		store := acct.msgStores[acct.dirlist.selected]
		store.Update(msg)
	case *types.FullMessage:
		store := acct.msgStores[acct.dirlist.selected]
		store.Update(msg)
	case *types.MessageInfo:
		store := acct.msgStores[acct.dirlist.selected]
		store.Update(msg)
	case *types.MessagesDeleted:
		store := acct.msgStores[acct.dirlist.selected]
		store.Update(msg)
	case *types.Error:
		acct.logger.Printf("%v", msg.Error)
		acct.host.SetStatus(fmt.Sprintf("%v", msg.Error)).
			Color(tcell.ColorDefault, tcell.ColorRed)
	}
}
KeyStroke{tcell.KeyEnd, 0} keyNames["insert"] = KeyStroke{tcell.KeyInsert, 0} keyNames["delete"] = KeyStroke{tcell.KeyDelete, 0} keyNames["help"] = KeyStroke{tcell.KeyHelp, 0} keyNames["exit"] = KeyStroke{tcell.KeyExit, 0} keyNames["clear"] = KeyStroke{tcell.KeyClear, 0} keyNames["cancel"] = KeyStroke{tcell.KeyCancel, 0} keyNames["print"] = KeyStroke{tcell.KeyPrint, 0} keyNames["pause"] = KeyStroke{tcell.KeyPause, 0} keyNames["backtab"] = KeyStroke{tcell.KeyBacktab, 0} keyNames["f1"] = KeyStroke{tcell.KeyF1, 0} keyNames["f2"] = KeyStroke{tcell.KeyF2, 0} keyNames["f3"] = KeyStroke{tcell.KeyF3, 0} keyNames["f4"] = KeyStroke{tcell.KeyF4, 0} keyNames["f5"] = KeyStroke{tcell.KeyF5, 0} keyNames["f6"] = KeyStroke{tcell.KeyF6, 0} keyNames["f7"] = KeyStroke{tcell.KeyF7, 0} keyNames["f8"] = KeyStroke{tcell.KeyF8, 0} keyNames["f9"] = KeyStroke{tcell.KeyF9, 0} keyNames["f10"] = KeyStroke{tcell.KeyF10, 0} keyNames["f11"] = KeyStroke{tcell.KeyF11, 0} keyNames["f12"] = KeyStroke{tcell.KeyF12, 0} keyNames["f13"] = KeyStroke{tcell.KeyF13, 0} keyNames["f14"] = KeyStroke{tcell.KeyF14, 0} keyNames["f15"] = KeyStroke{tcell.KeyF15, 0} keyNames["f16"] = KeyStroke{tcell.KeyF16, 0} keyNames["f17"] = KeyStroke{tcell.KeyF17, 0} keyNames["f18"] = KeyStroke{tcell.KeyF18, 0} keyNames["f19"] = KeyStroke{tcell.KeyF19, 0} keyNames["f20"] = KeyStroke{tcell.KeyF20, 0} keyNames["f21"] = KeyStroke{tcell.KeyF21, 0} keyNames["f22"] = KeyStroke{tcell.KeyF22, 0} keyNames["f23"] = KeyStroke{tcell.KeyF23, 0} keyNames["f24"] = KeyStroke{tcell.KeyF24, 0} keyNames["f25"] = KeyStroke{tcell.KeyF25, 0} keyNames["f26"] = KeyStroke{tcell.KeyF26, 0} keyNames["f27"] = KeyStroke{tcell.KeyF27, 0} keyNames["f28"] = KeyStroke{tcell.KeyF28, 0} keyNames["f29"] = KeyStroke{tcell.KeyF29, 0} keyNames["f30"] = KeyStroke{tcell.KeyF30, 0} keyNames["f31"] = KeyStroke{tcell.KeyF31, 0} keyNames["f32"] = KeyStroke{tcell.KeyF32, 0} keyNames["f33"] = KeyStroke{tcell.KeyF33, 0} keyNames["f34"] = KeyStroke{tcell.KeyF34, 0} keyNames["f35"] = KeyStroke{tcell.KeyF35, 0} keyNames["f36"] = KeyStroke{tcell.KeyF36, 0} keyNames["f37"] = KeyStroke{tcell.KeyF37, 0} keyNames["f38"] = KeyStroke{tcell.KeyF38, 0} keyNames["f39"] = KeyStroke{tcell.KeyF39, 0} keyNames["f40"] = KeyStroke{tcell.KeyF40, 0} keyNames["f41"] = KeyStroke{tcell.KeyF41, 0} keyNames["f42"] = KeyStroke{tcell.KeyF42, 0} keyNames["f43"] = KeyStroke{tcell.KeyF43, 0} keyNames["f44"] = KeyStroke{tcell.KeyF44, 0} keyNames["f45"] = KeyStroke{tcell.KeyF45, 0} keyNames["f46"] = KeyStroke{tcell.KeyF46, 0} keyNames["f47"] = KeyStroke{tcell.KeyF47, 0} keyNames["f48"] = KeyStroke{tcell.KeyF48, 0} keyNames["f49"] = KeyStroke{tcell.KeyF49, 0} keyNames["f50"] = KeyStroke{tcell.KeyF50, 0} keyNames["f51"] = KeyStroke{tcell.KeyF51, 0} keyNames["f52"] = KeyStroke{tcell.KeyF52, 0} keyNames["f53"] = KeyStroke{tcell.KeyF53, 0} keyNames["f54"] = KeyStroke{tcell.KeyF54, 0} keyNames["f55"] = KeyStroke{tcell.KeyF55, 0} keyNames["f56"] = KeyStroke{tcell.KeyF56, 0} keyNames["f57"] = KeyStroke{tcell.KeyF57, 0} keyNames["f58"] = KeyStroke{tcell.KeyF58, 0} keyNames["f59"] = KeyStroke{tcell.KeyF59, 0} keyNames["f60"] = KeyStroke{tcell.KeyF60, 0} keyNames["f61"] = KeyStroke{tcell.KeyF61, 0} keyNames["f62"] = KeyStroke{tcell.KeyF62, 0} keyNames["f63"] = KeyStroke{tcell.KeyF63, 0} keyNames["f64"] = KeyStroke{tcell.KeyF64, 0} keyNames["c-space"] = KeyStroke{tcell.KeyCtrlSpace, 0} keyNames["c-a"] = KeyStroke{tcell.KeyCtrlA, 0} keyNames["c-b"] = KeyStroke{tcell.KeyCtrlB, 0} keyNames["c-c"] = KeyStroke{tcell.KeyCtrlC, 0} keyNames["c-d"] = KeyStroke{tcell.KeyCtrlD, 0} keyNames["c-e"] = KeyStroke{tcell.KeyCtrlE, 0} keyNames["c-f"] = KeyStroke{tcell.KeyCtrlF, 0} keyNames["c-g"] = KeyStroke{tcell.KeyCtrlG, 0} keyNames["c-h"] = KeyStroke{tcell.KeyCtrlH, 0} keyNames["c-i"] = KeyStroke{tcell.KeyCtrlI, 0} keyNames["c-j"] = KeyStroke{tcell.KeyCtrlJ, 0} keyNames["c-k"] = KeyStroke{tcell.KeyCtrlK, 0} keyNames["c-l"] = KeyStroke{tcell.KeyCtrlL, 0} keyNames["c-m"] = KeyStroke{tcell.KeyCtrlM, 0} keyNames["c-n"] = KeyStroke{tcell.KeyCtrlN, 0} keyNames["c-o"] = KeyStroke{tcell.KeyCtrlO, 0} keyNames["c-p"] = KeyStroke{tcell.KeyCtrlP, 0} keyNames["c-q"] = KeyStroke{tcell.KeyCtrlQ, 0} keyNames["c-r"] = KeyStroke{tcell.KeyCtrlR, 0} keyNames["c-s"] = KeyStroke{tcell.KeyCtrlS, 0} keyNames["c-t"] = KeyStroke{tcell.KeyCtrlT, 0} keyNames["c-u"] = KeyStroke{tcell.KeyCtrlU, 0} keyNames["c-v"] = KeyStroke{tcell.KeyCtrlV, 0} keyNames["c-w"] = KeyStroke{tcell.KeyCtrlW, 0} keyNames["c-x"] = KeyStroke{tcell.KeyCtrlX, 0} keyNames["c-y"] = KeyStroke{tcell.KeyCtrlY, 0} keyNames["c-z"] = KeyStroke{tcell.KeyCtrlZ, 0} keyNames["c-]"] = KeyStroke{tcell.KeyCtrlLeftSq, 0} keyNames["c-\\"] = KeyStroke{tcell.KeyCtrlBackslash, 0} keyNames["c-["] = KeyStroke{tcell.KeyCtrlRightSq, 0} keyNames["c-^"] = KeyStroke{tcell.KeyCtrlCarat, 0} keyNames["c-_"] = KeyStroke{tcell.KeyCtrlUnderscore, 0} keyNames["NUL"] = KeyStroke{tcell.KeyNUL, 0} keyNames["SOH"] = KeyStroke{tcell.KeySOH, 0} keyNames["STX"] = KeyStroke{tcell.KeySTX, 0} keyNames["ETX"] = KeyStroke{tcell.KeyETX, 0} keyNames["EOT"] = KeyStroke{tcell.KeyEOT, 0} keyNames["ENQ"] = KeyStroke{tcell.KeyENQ, 0} keyNames["ACK"] = KeyStroke{tcell.KeyACK, 0} keyNames["BEL"] = KeyStroke{tcell.KeyBEL, 0} keyNames["BS"] = KeyStroke{tcell.KeyBS, 0} keyNames["tab"] = KeyStroke{tcell.KeyTAB, 0} keyNames["LF"] = KeyStroke{tcell.KeyLF, 0} keyNames["VT"] = KeyStroke{tcell.KeyVT, 0} keyNames["FF"] = KeyStroke{tcell.KeyFF, 0} keyNames["CR"] = KeyStroke{tcell.KeyCR, 0} keyNames["SO"] = KeyStroke{tcell.KeySO, 0} keyNames["SI"] = KeyStroke{tcell.KeySI, 0} keyNames["DLE"] = KeyStroke{tcell.KeyDLE, 0} keyNames["DC1"] = KeyStroke{tcell.KeyDC1, 0} keyNames["DC2"] = KeyStroke{tcell.KeyDC2, 0} keyNames["DC3"] = KeyStroke{tcell.KeyDC3, 0} keyNames["DC4"] = KeyStroke{tcell.KeyDC4, 0} keyNames["NAK"] = KeyStroke{tcell.KeyNAK, 0} keyNames["SYN"] = KeyStroke{tcell.KeySYN, 0} keyNames["ETB"] = KeyStroke{tcell.KeyETB, 0} keyNames["CAN"] = KeyStroke{tcell.KeyCAN, 0} keyNames["EM"] = KeyStroke{tcell.KeyEM, 0} keyNames["SUB"] = KeyStroke{tcell.KeySUB, 0} keyNames["ESC"] = KeyStroke{tcell.KeyESC, 0} keyNames["FS"] = KeyStroke{tcell.KeyFS, 0} keyNames["GS"] = KeyStroke{tcell.KeyGS, 0} keyNames["RS"] = KeyStroke{tcell.KeyRS, 0} keyNames["US"] = KeyStroke{tcell.KeyUS, 0} keyNames["DEL"] = KeyStroke{tcell.KeyDEL, 0} }