-
Notifications
You must be signed in to change notification settings - Fork 0
/
model.go
126 lines (101 loc) · 3.36 KB
/
model.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
package bubbleup
import (
"strings"
"time"
tea "github.com/charmbracelet/bubbletea"
"github.com/muesli/reflow/ansi"
)
// AlertModel maintains a list of alert types, and facilitates the display and
// clearing of alerts, as well as registering custom alerts and overrides to defaults
type AlertModel struct {
useNerdFont bool
alertTypes map[string]AlertDefinition
activeAlert *alert
width int
}
// TODO: Set defaults for position and duration
// NewAlertModel creates and returns a new AlertModel, initialized with default alert types
func NewAlertModel(width int, useNerdFont bool) *AlertModel {
model := &AlertModel{
activeAlert: nil,
width: width,
useNerdFont: useNerdFont,
alertTypes: make(map[string]AlertDefinition),
}
model.registerDefaultAlertTypes()
return model
}
// Init starts the ticking command that causes alert refreshing
// Implemented as part of BubbleTea Model interface
func (m AlertModel) Init() tea.Cmd {
return tickCmd()
}
// Update takes in a message and returns an associated command to drive model functionality
// Implemented as part of BubbleTea Model interface
func (m AlertModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tickMsg: // Check to see if it's time to clear the alert
if m.activeAlert != nil {
if m.activeAlert.deathTime.Before(time.Time(msg)) {
m.activeAlert = nil
} else {
m.activeAlert.curLerpStep += DefaultLerpIncrement
if m.activeAlert.curLerpStep > 1 {
m.activeAlert.curLerpStep = 1
}
}
}
return m, tickCmd()
case alertMsg:
m.activeAlert = m.newNotif(msg.alertKey, msg.msg, msg.dur)
}
return m, nil
}
// View doesn't do anything, and it should never be called directly
// Implemented as part of BubbleTea Model interface
func (m AlertModel) View() string {
return ""
}
// RenderAlert takes in the main view content and overlays the model's active alert.
// This function expects you build the entirety of your view's content before calling
// this function. It's recommended for this to be the final call of your model's View().
// Returns a string representation of the content with overlayed alert.
func (m AlertModel) Render(content string) string {
if m.activeAlert == nil {
return content
}
notifString := m.activeAlert.render()
notifSplit, _ := getLines(notifString)
contentSplit, _ := getLines(content)
notifHeight := len(notifSplit)
contentHeight := len(contentSplit)
var builder strings.Builder
// NOTE: The current implementation here assumes the notification is
// in the top left. It will need to be adapted to handle other positions
for i := range contentHeight {
if i > 0 {
// End previous line with a newline
builder.WriteByte('\n')
}
if i >= notifHeight { // If we're past the notifation, render normally
builder.WriteString(contentSplit[i])
} else {
// Add notification line
notifLine := notifSplit[i]
builder.WriteString(notifLine)
notifLen := ansi.PrintableRuneWidth(notifLine)
remainingContent := cutLeft(contentSplit[i], notifLen)
builder.WriteString(remainingContent)
}
}
return builder.String()
}
// Timer stuff
// tickMsg is the message that tells the model to assess active alert lifespan.
type tickMsg time.Time
// tickCmd returns a tea Command to initiate a tick.
func tickCmd() tea.Cmd {
return tea.Tick(time.Millisecond*100, func(t time.Time) tea.Msg {
return tickMsg(t)
})
}