repos / pico

pico services mono repo
git clone https://github.com/picosh/pico.git

pico / pkg / tui
Eric Bower  ·  2025-03-17

menu.go

  1package tui
  2
  3import (
  4	"git.sr.ht/~rockorager/vaxis"
  5	"git.sr.ht/~rockorager/vaxis/vxfw"
  6	"git.sr.ht/~rockorager/vaxis/vxfw/list"
  7	"git.sr.ht/~rockorager/vaxis/vxfw/text"
  8	"github.com/picosh/pico/pkg/db"
  9)
 10
 11var menuChoices = []string{
 12	"pubkeys",
 13	"tokens",
 14	"logs",
 15	"analytics",
 16	"tuns",
 17	"pico+",
 18	"chat",
 19}
 20
 21type LoadedUsageStats struct{}
 22
 23type MenuPage struct {
 24	shared *SharedModel
 25
 26	list     list.Dynamic
 27	features *FeaturesList
 28	stats    *db.UserStats
 29}
 30
 31func getMenuWidget(i uint, cursor uint) vxfw.Widget {
 32	if int(i) >= len(menuChoices) {
 33		return nil
 34	}
 35	var style vaxis.Style
 36	if i == cursor {
 37		style.Attribute = vaxis.AttrReverse
 38	}
 39	content := menuChoices[i]
 40	return &text.Text{
 41		Content: content,
 42		Style:   style,
 43	}
 44}
 45
 46func NewMenuPage(shrd *SharedModel) *MenuPage {
 47	m := &MenuPage{shared: shrd}
 48	m.list = list.Dynamic{Builder: getMenuWidget, DrawCursor: true}
 49	m.features = NewFeaturesList(shrd)
 50	return m
 51}
 52
 53func loadChat(shrd *SharedModel) {
 54	sp := &SenpaiCmd{
 55		Shared: shrd,
 56	}
 57	_ = sp.Run()
 58}
 59
 60func (m *MenuPage) fetchUsageStats() error {
 61	stats, err := m.shared.Dbpool.FindUserStats(m.shared.User.ID)
 62	if err != nil {
 63		return err
 64	}
 65	m.stats = stats
 66	return nil
 67}
 68
 69func (m *MenuPage) HandleEvent(ev vaxis.Event, phase vxfw.EventPhase) (vxfw.Command, error) {
 70	switch msg := ev.(type) {
 71	case PageIn:
 72		_ = m.fetchUsageStats()
 73		cmd, _ := m.features.HandleEvent(vxfw.Init{}, phase)
 74		return vxfw.BatchCmd([]vxfw.Command{
 75			cmd,
 76			vxfw.FocusWidgetCmd(&m.list),
 77		}), nil
 78	case vaxis.Key:
 79		if msg.Matches(vaxis.KeyEnter) {
 80			choice := menuChoices[m.list.Cursor()]
 81			m.shared.App.PostEvent(Navigate{To: choice})
 82		}
 83	}
 84	return nil, nil
 85}
 86
 87func (m *MenuPage) Draw(ctx vxfw.DrawContext) (vxfw.Surface, error) {
 88	info, _ := NewUserInfo(m.shared).Draw(ctx)
 89
 90	brd := NewBorder(&m.list)
 91	brd.Label = "menu"
 92	brd.Style = vaxis.Style{Foreground: oj}
 93	menuSurf, _ := brd.Draw(vxfw.DrawContext{
 94		Characters: ctx.Characters,
 95		Max: vxfw.Size{
 96			Width:  30,
 97			Height: uint16(len(menuChoices)) + 3,
 98		},
 99	})
100
101	services, _ := NewServicesList(m.shared.PlusFeatureFlag).Draw(ctx)
102	features, _ := m.features.Draw(ctx)
103
104	leftPane := NewGroupStack([]vxfw.Surface{
105		menuSurf,
106		info,
107		services,
108	})
109	leftSurf, _ := leftPane.Draw(ctx)
110
111	right := []vxfw.Surface{}
112	if len(m.features.features) > 0 {
113		right = append(right, features)
114	}
115
116	if m.stats != nil {
117		pages, _ := NewUsageInfo("pages", &m.stats.Pages).Draw(ctx)
118		prose, _ := NewUsageInfo("prose", &m.stats.Prose).Draw(ctx)
119		pastes, _ := NewUsageInfo("pastes", &m.stats.Pastes).Draw(ctx)
120		feeds, _ := NewUsageInfo("rss-to-email", &m.stats.Feeds).Draw(ctx)
121		right = append(right,
122			pages,
123			prose,
124			pastes,
125			feeds,
126		)
127	}
128	rightPane := NewGroupStack(right)
129	rightSurf, _ := rightPane.Draw(ctx)
130
131	root := vxfw.NewSurface(ctx.Max.Width, ctx.Max.Height, m)
132	root.AddChild(0, 0, leftSurf)
133	root.AddChild(30, 0, rightSurf)
134	return root, nil
135}