1package main
2
3import (
4 "github.com/gdamore/tcell/v2"
5)
6
7type UserInterface struct {
8 Mails []Mail
9 Screen tcell.Screen
10 index int
11}
12
13const (
14 // Rune used to indicate that the row has been abbreviated.
15 abbreviated = '…'
16)
17
18var (
19 // Style used for non-selected rows.
20 defStyle = tcell.StyleDefault.Background(tcell.ColorReset).Foreground(tcell.ColorReset)
21
22 // Style used for the currently selected row.
23 selStyle = tcell.StyleDefault.Background(tcell.ColorWhite).Foreground(tcell.ColorBlack)
24)
25
26func NewUI(mails []Mail, screen tcell.Screen) *UserInterface {
27 return &UserInterface{
28 Mails: mails,
29 Screen: screen,
30 index: 0,
31 }
32}
33
34func (ui *UserInterface) Refresh() error {
35 var err error
36 ui.Mails, err = mscan()
37 if err != nil {
38 return err
39 }
40
41 // If the last mail was modified, the length of the sequence could
42 // have been reduced by 1; therefore, we need to update the index.
43 ui.index = min(ui.index, len(ui.Mails)-1)
44 return nil
45}
46
47func (ui *UserInterface) visible() int {
48 _, ymax := ui.Screen.Size()
49 return min(ymax, len(ui.Mails))
50}
51
52func (ui *UserInterface) SelectedMail() Mail {
53 return ui.Mails[ui.index]
54}
55
56func (ui *UserInterface) IsSelected(m Mail) bool {
57 selected := ui.SelectedMail()
58 return selected.Path == m.Path
59}
60
61func (ui *UserInterface) NextMail() {
62 if ui.index < len(ui.Mails)-1 {
63 ui.index++
64 ui.Draw()
65 }
66}
67
68func (ui *UserInterface) PrevMail() {
69 if ui.index > 0 {
70 ui.index--
71 ui.Draw()
72 }
73}
74
75func (ui *UserInterface) NextPage() {
76 ui.index = min(len(ui.Mails)-1, ui.index+ui.visible())
77 ui.Draw()
78}
79
80func (ui *UserInterface) PrevPage() {
81 visible := ui.visible()
82 if ui.index > visible {
83 ui.index = ui.index - visible
84 } else {
85 ui.index = 0
86 }
87 ui.Draw()
88}
89
90func (ui *UserInterface) Draw() {
91 xmax, _ := ui.Screen.Size()
92 if xmax <= 1 {
93 panic("terminal is too small")
94 }
95
96 mails := ui.Mails
97 visible := ui.visible()
98 if ui.index >= visible {
99 start := ui.index - visible
100 mails = ui.Mails[start+1:]
101 }
102
103 y := 0
104 for _, mail := range mails {
105 text := mail.String()
106
107 var style tcell.Style
108 if ui.IsSelected(mail) {
109 style = selStyle
110 } else {
111 style = defStyle
112 }
113
114 truncated := false
115 if len(text) >= xmax {
116 text = text[0 : len(text)-1]
117 truncated = true
118 }
119 lastCol := drawText(ui.Screen, y, 0, style, text)
120 if truncated {
121 // TODO: Determine cells needed for abbreviated.
122 ui.Screen.SetContent(xmax-1, y, abbreviated, nil, style)
123 } else {
124 for x := lastCol; x < xmax; x++ {
125 ui.Screen.SetContent(x, y, ' ', nil, style)
126 }
127 }
128
129 y++
130 if y >= visible {
131 break
132 }
133 }
134}
135
136func (ui *UserInterface) withoutScreen(fn func() error) error {
137 ui.Screen.Fini()
138 err := fn()
139 if err != nil {
140 return err
141 }
142
143 ui.Screen, err = initScreen()
144 if err != nil {
145 return err
146 }
147 ui.Draw()
148
149 return nil
150}