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/ui/util"
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 util.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 util.InfoMsg) {
39 s.msg = msg
40}
41
42// ClearInfoMsg clears the status info message.
43func (s *Status) ClearInfoMsg() {
44 s.msg = util.InfoMsg{}
45}
46
47// SetWidth sets the width of the status bar and help view.
48func (s *Status) SetWidth(width int) {
49 helpStyle := s.com.Styles.Status.Help
50 horizontalPadding := helpStyle.GetPaddingLeft() + helpStyle.GetPaddingRight()
51 s.help.SetWidth(width - horizontalPadding)
52}
53
54// ShowingAll returns whether the full help view is shown.
55func (s *Status) ShowingAll() bool {
56 return s.help.ShowAll
57}
58
59// ToggleHelp toggles the full help view.
60func (s *Status) ToggleHelp() {
61 s.help.ShowAll = !s.help.ShowAll
62}
63
64// SetHideHelp sets whether the app is on the onboarding flow.
65func (s *Status) SetHideHelp(hideHelp bool) {
66 s.hideHelp = hideHelp
67}
68
69// Draw draws the status bar onto the screen.
70func (s *Status) Draw(scr uv.Screen, area uv.Rectangle) {
71 if !s.hideHelp {
72 helpView := s.com.Styles.Status.Help.Render(s.help.View(s.helpKm))
73 uv.NewStyledString(helpView).Draw(scr, area)
74 }
75
76 // Render notifications
77 if s.msg.IsEmpty() {
78 return
79 }
80
81 var indStyle lipgloss.Style
82 var msgStyle lipgloss.Style
83 switch s.msg.Type {
84 case util.InfoTypeError:
85 indStyle = s.com.Styles.Status.ErrorIndicator
86 msgStyle = s.com.Styles.Status.ErrorMessage
87 case util.InfoTypeWarn:
88 indStyle = s.com.Styles.Status.WarnIndicator
89 msgStyle = s.com.Styles.Status.WarnMessage
90 case util.InfoTypeUpdate:
91 indStyle = s.com.Styles.Status.UpdateIndicator
92 msgStyle = s.com.Styles.Status.UpdateMessage
93 case util.InfoTypeInfo:
94 indStyle = s.com.Styles.Status.InfoIndicator
95 msgStyle = s.com.Styles.Status.InfoMessage
96 case util.InfoTypeSuccess:
97 indStyle = s.com.Styles.Status.SuccessIndicator
98 msgStyle = s.com.Styles.Status.SuccessMessage
99 }
100
101 ind := indStyle.String()
102 messageWidth := area.Dx() - lipgloss.Width(ind)
103 msg := ansi.Truncate(s.msg.Msg, messageWidth, "…")
104 info := msgStyle.Width(messageWidth).Render(msg)
105
106 // Draw the info message over the help view
107 uv.NewStyledString(ind+info).Draw(scr, area)
108}
109
110// clearInfoMsgCmd returns a command that clears the info message after the
111// given TTL.
112func clearInfoMsgCmd(ttl time.Duration) tea.Cmd {
113 return tea.Tick(ttl, func(time.Time) tea.Msg {
114 return util.ClearStatusMsg{}
115 })
116}