Antonio Mika
·
08 Oct 24
settings.go
1package settings
2
3import (
4 "fmt"
5 "time"
6
7 tea "github.com/charmbracelet/bubbletea"
8 "github.com/charmbracelet/lipgloss"
9 "github.com/charmbracelet/lipgloss/table"
10 "github.com/picosh/pico/db"
11 "github.com/picosh/pico/tui/common"
12 "github.com/picosh/pico/tui/pages"
13 "github.com/picosh/utils"
14)
15
16var maxWidth = 50
17
18type state int
19
20const (
21 stateLoading state = iota
22 stateReady
23)
24
25type focus int
26
27const (
28 focusNone = iota
29 focusAnalytics
30)
31
32type featuresLoadedMsg []*db.FeatureFlag
33
34type Model struct {
35 shared common.SharedModel
36 features []*db.FeatureFlag
37 state state
38 focus focus
39}
40
41func NewModel(shrd common.SharedModel) Model {
42 return Model{
43 shared: shrd,
44 state: stateLoading,
45 focus: focusNone,
46 }
47}
48
49func (m Model) Init() tea.Cmd {
50 return m.fetchFeatures()
51}
52
53func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
54 switch msg := msg.(type) {
55 case tea.KeyMsg:
56 switch msg.String() {
57 case "q", "esc":
58 return m, pages.Navigate(pages.MenuPage)
59 case "tab":
60 if m.focus == focusNone {
61 m.focus = focusAnalytics
62 } else {
63 m.focus = focusNone
64 }
65 case "enter":
66 if m.focus == focusAnalytics {
67 return m, m.toggleAnalytics()
68 }
69 }
70
71 case featuresLoadedMsg:
72 m.state = stateReady
73 m.focus = focusNone
74 m.features = msg
75 }
76 return m, nil
77}
78
79func (m Model) View() string {
80 if m.state == stateLoading {
81 return "Loading ..."
82 }
83 return m.featuresView() + "\n" + m.analyticsView()
84}
85
86func (m Model) findAnalyticsFeature() *db.FeatureFlag {
87 for _, feature := range m.features {
88 if feature.Name == "analytics" {
89 return feature
90 }
91 }
92 return nil
93}
94
95func (m Model) analyticsView() string {
96 banner := `Get usage statistics on your blog, blog posts, and pages sites. For example, see unique visitors, most popular URLs, and top referers.
97
98We do not collect usage statistic unless analytics is enabled. Further, when analytics are disabled we do not purge usage statistics.
99
100We will only store usage statistics for 1 year from when the event was created.`
101
102 str := ""
103 hasPlus := m.shared.PlusFeatureFlag != nil
104 if hasPlus {
105 ff := m.findAnalyticsFeature()
106 hasFocus := m.focus == focusAnalytics
107 if ff == nil {
108 str += banner + "\n\nEnable analytics " + common.OKButtonView(m.shared.Styles, hasFocus, false)
109 } else {
110 str += "Disable analytics " + common.OKButtonView(m.shared.Styles, hasFocus, false)
111 }
112 } else {
113 str += banner + "\n\n" + m.shared.Styles.Error.SetString("Analytics is only available to pico+ users.").String()
114 }
115
116 return m.shared.Styles.RoundedBorder.Width(maxWidth).SetString(str).String()
117}
118
119func (m Model) featuresView() string {
120 headers := []string{
121 "Name",
122 "Quota (GB)",
123 "Expires At",
124 }
125
126 data := [][]string{}
127 for _, feature := range m.features {
128 storeMax := utils.BytesToGB(int(feature.FindStorageMax(0)))
129 row := []string{
130 feature.Name,
131 fmt.Sprintf("%.2f", storeMax),
132 feature.ExpiresAt.Format(common.DateFormat),
133 }
134 data = append(data, row)
135 }
136 t := table.New().
137 Border(lipgloss.RoundedBorder()).
138 BorderStyle(m.shared.Styles.Renderer.NewStyle().BorderForeground(common.Indigo)).
139 Width(maxWidth).
140 Headers(headers...).
141 Rows(data...)
142 return "Features\n" + t.String()
143}
144
145func (m Model) fetchFeatures() tea.Cmd {
146 return func() tea.Msg {
147 features, err := m.shared.Dbpool.FindFeaturesForUser(m.shared.User.ID)
148 if err != nil {
149 return common.ErrMsg{Err: err}
150 }
151 return featuresLoadedMsg(features)
152 }
153}
154
155func (m Model) toggleAnalytics() tea.Cmd {
156 return func() tea.Msg {
157 if m.findAnalyticsFeature() == nil {
158 now := time.Now()
159 expiresAt := now.AddDate(100, 0, 0)
160 _, err := m.shared.Dbpool.InsertFeature(m.shared.User.ID, "analytics", expiresAt)
161 if err != nil {
162 return common.ErrMsg{Err: err}
163 }
164 } else {
165 err := m.shared.Dbpool.RemoveFeature(m.shared.User.ID, "analytics")
166 if err != nil {
167 return common.ErrMsg{Err: err}
168 }
169 }
170
171 cmd := m.fetchFeatures()
172 return cmd()
173 }
174}