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