package ui import ( "fmt" "time" tea "charm.land/bubbletea/v2" ) // toastKind selects which of the theme's toast styles a notification uses. type toastKind int const ( toastInfo toastKind = iota toastSuccess toastWarn toastErr ) // toast is a transient status/error message shown in the footer. Replaces // the old Model.statusText/errText, which never expired once set. type toast struct { kind toastKind text string seq int } // toastExpireMsg clears the toast identified by seq — guarded so a // newer toast issued while an older one's timer is still running can't be // clobbered by the older timer firing after it. type toastExpireMsg struct{ seq int } // notify replaces the current toast and returns the tea.Cmd that expires // it. Errors linger noticeably longer than routine status updates. func (m *Model) notify(kind toastKind, format string, args ...any) tea.Cmd { m.toastSeq++ seq := m.toastSeq m.toast = &toast{kind: kind, text: fmt.Sprintf(format, args...), seq: seq} d := 4 * time.Second if kind == toastErr { d = 8 * time.Second } return tea.Tick(d, func(time.Time) tea.Msg { return toastExpireMsg{seq: seq} }) } func (m *Model) clearExpiredToast(msg toastExpireMsg) { if m.toast != nil && m.toast.seq == msg.seq { m.toast = nil } } // toastView renders the current toast, or "" if there is none. func (m *Model) toastView() string { if m.toast == nil { return "" } switch m.toast.kind { case toastSuccess: return m.styles.ToastSuccess.Render(symOK + " " + m.toast.text) case toastWarn: return m.styles.ToastWarn.Render(symWarn + " " + m.toast.text) case toastErr: return m.styles.ToastError.Render(symErr + " " + m.toast.text) default: return m.styles.ToastInfo.Render(m.toast.text) } }