1package model
2
3import (
4 "time"
5
6 "charm.land/bubbles/v2/help"
7 tea "charm.land/bubbletea/v2"
8 "charm.land/lipgloss/v2"
9 "github.com/charmbracelet/crush/internal/ui/common"
10 "github.com/charmbracelet/crush/internal/uiutil"
11 uv "github.com/charmbracelet/ultraviolet"
12 "github.com/charmbracelet/x/ansi"
13)
14
15// DefaultStatusTTL is the default time-to-live for status messages.
16const DefaultStatusTTL = 5 * time.Second
17
18// Status is the status bar and help model.
19type Status struct {
20 com *common.Common
21 hideHelp bool
22 help help.Model
23 helpKm help.KeyMap
24 msg uiutil.InfoMsg
25}
26
27// NewStatus creates a new status bar and help model.
28func NewStatus(com *common.Common, km help.KeyMap) *Status {
29 s := new(Status)
30 s.com = com
31 s.help = help.New()
32 s.help.Styles = com.Styles.Help
33 s.helpKm = km
34 return s
35}
36
37// SetInfoMsg sets the status info message.
38func (s *Status) SetInfoMsg(msg uiutil.InfoMsg) {
39 s.msg = msg
40}
41
42// ClearInfoMsg clears the status info message.
43func (s *Status) ClearInfoMsg() {
44 s.msg = uiutil.InfoMsg{}
45}
46
47// SetWidth sets the width of the status bar and help view.
48func (s *Status) SetWidth(width int) {
49 s.help.SetWidth(width)
50}
51
52// ShowingAll returns whether the full help view is shown.
53func (s *Status) ShowingAll() bool {
54 return s.help.ShowAll
55}
56
57// ToggleHelp toggles the full help view.
58func (s *Status) ToggleHelp() {
59 s.help.ShowAll = !s.help.ShowAll
60}
61
62// SetHideHelp sets whether the app is on the onboarding flow.
63func (s *Status) SetHideHelp(hideHelp bool) {
64 s.hideHelp = hideHelp
65}
66
67// Draw draws the status bar onto the screen.
68func (s *Status) Draw(scr uv.Screen, area uv.Rectangle) {
69 if !s.hideHelp {
70 helpView := s.com.Styles.Status.Help.Render(s.help.View(s.helpKm))
71 uv.NewStyledString(helpView).Draw(scr, area)
72 }
73
74 // Render notifications
75 if s.msg.IsEmpty() {
76 return
77 }
78
79 var indStyle lipgloss.Style
80 var msgStyle lipgloss.Style
81 switch s.msg.Type {
82 case uiutil.InfoTypeError:
83 indStyle = s.com.Styles.Status.ErrorIndicator
84 msgStyle = s.com.Styles.Status.ErrorMessage
85 case uiutil.InfoTypeWarn:
86 indStyle = s.com.Styles.Status.WarnIndicator
87 msgStyle = s.com.Styles.Status.WarnMessage
88 case uiutil.InfoTypeUpdate:
89 indStyle = s.com.Styles.Status.UpdateIndicator
90 msgStyle = s.com.Styles.Status.UpdateMessage
91 case uiutil.InfoTypeInfo:
92 indStyle = s.com.Styles.Status.InfoIndicator
93 msgStyle = s.com.Styles.Status.InfoMessage
94 case uiutil.InfoTypeSuccess:
95 indStyle = s.com.Styles.Status.SuccessIndicator
96 msgStyle = s.com.Styles.Status.SuccessMessage
97 }
98
99 ind := indStyle.String()
100 messageWidth := area.Dx() - lipgloss.Width(ind)
101 msg := ansi.Truncate(s.msg.Msg, messageWidth, "…")
102 info := msgStyle.Width(messageWidth).Render(msg)
103
104 // Draw the info message over the help view
105 uv.NewStyledString(ind+info).Draw(scr, area)
106}
107
108// clearInfoMsgCmd returns a command that clears the info message after the
109// given TTL.
110func clearInfoMsgCmd(ttl time.Duration) tea.Cmd {
111 return tea.Tick(ttl, func(time.Time) tea.Msg {
112 return uiutil.ClearStatusMsg{}
113 })
114}