diff options
| author | Kyren223 <Kyren223@proton.me> | 2024-11-09 21:36:11 +0200 |
|---|---|---|
| committer | Kyren223 <Kyren223@proton.me> | 2024-11-09 21:36:11 +0200 |
| commit | 1b2c19149631f0397d1532644e2a2ce3d6a44e11 (patch) | |
| tree | 03e362bdcbb024c6ee08b2c86fbc29159e46980b /internal/client/ui/loadscreen/loadscreen.go | |
| parent | 8d97e7000c6579180d37c977edf5d071e4ff1219 (diff) | |
feat: add WIP loading screen, messed around with custom spinners
Diffstat (limited to 'internal/client/ui/loadscreen/loadscreen.go')
| -rw-r--r-- | internal/client/ui/loadscreen/loadscreen.go | 208 |
1 files changed, 208 insertions, 0 deletions
diff --git a/internal/client/ui/loadscreen/loadscreen.go b/internal/client/ui/loadscreen/loadscreen.go new file mode 100644 index 0000000..6639f7d --- /dev/null +++ b/internal/client/ui/loadscreen/loadscreen.go @@ -0,0 +1,208 @@ +package loadscreen + +import ( + "log" + "time" + + "github.com/charmbracelet/bubbles/spinner" + "github.com/charmbracelet/bubbles/viewport" + tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/lipgloss" + + "github.com/kyren223/eko/internal/client/ui" + "github.com/kyren223/eko/pkg/assert" +) + +var ( + style = lipgloss.NewStyle().Border(lipgloss.ThickBorder()).Padding(1) + _ = spinner.Spinner{ + Frames: []string{ + "██▓▓▒▒\n ░░\n ", + "▓▓▒▒░░\n██ \n ", + "▒▒░░ \n▓▓ \n██ ", + "░░ \n▒▒ \n▓▓██ ", + " \n░░ \n▒▒▓▓██", + " \n ██\n░░▒▒▓▓", + " ██\n ▓▓\n ░░▒▒", + " ██▓▓\n ▒▒\n ░░", + }, + FPS: time.Second / 8, + } + + apple = lipgloss.NewStyle().Foreground(lipgloss.Color("#FF0000")).Render("██") + // loadingFrames = circleTrail(5, 5, 0, true, " ", "░░", "▒▒", "▓▓", "██") + // loadingFrames = circleTrail(5, 5, 0, true, " ", "░░", "▒▒", "▓▓", "██", " ", " ", " ", apple) + // loadingFrames = circleTrail(5, 5, 0, true, " ", "░░", "░░", "▒▒", "▒▒", "▓▓", "▓▓", "██", " ", " ", " ", apple) + loadingFrames = func() []string { + green := lipgloss.NewStyle().Foreground(lipgloss.Color("#00FF00")) + trail := []string{"░░", "░░", "▒▒", "▒▒", "▓▓", "██", " ", " "} + for i := range trail { + trail[i] = green.Render(trail[i]) + } + trail = append(trail, apple) + return circleTrail(5, 5, 0, true, " ", trail...) + }() + loading = spinner.Spinner{ + Frames: loadingFrames, + FPS: time.Second / time.Duration(len(loadingFrames)), + } +) + +func circleTrail(width int, height int, offset int, clockwise bool, bg string, trail ...string) (states []string) { + slots := (width+height)*2 - 4 + slotWidth := lipgloss.Width(bg) + slotHeight := lipgloss.Height(bg) + + assert.Assert(slots-len(trail) >= 0, "not enough space to fit trail") + assert.AddData("slotWidth", slotWidth) + assert.AddData("slotHeight", slotHeight) + defer assert.RemoveData("slotWidth") + defer assert.RemoveData("slotHeight") + for _, elem := range trail { + w := lipgloss.Width(elem) + h := lipgloss.Height(elem) + assert.AddData("elemWidth", w) + assert.AddData("elemHeight", h) + assert.Assert(slotWidth == w, "bg and all trails must have the same height") + assert.Assert(slotHeight == h, "bg and all trails must have the same height") + assert.RemoveData("elemWidth") + assert.RemoveData("elemHeight") + } + + matrix := make([][]string, height) + for i := range matrix { + matrix[i] = make([]string, width) + } + + for i := 0; i < slots; i++ { + for y := range matrix { + for x := range matrix[y] { + matrix[y][x] = bg + } + } + + x, y := 0, 0 + for j := 0; j < i+offset; j++ { + if clockwise { + if y == 0 && x != width-1 { + x++ + } else if x == width-1 && y != height-1 { + y++ + } else if y == height-1 && x != 0 { + x-- + } else if x == 0 && y != 0 { + y-- + } + } else { + if x == 0 && y != height-1 { + y++ + } else if y == height-1 && x != width-1 { + x++ + } else if x == width-1 && y != 0 { + y-- + } else if y == 0 && x != 0 { + x-- + } + } + } + + for _, trail := range trail { + matrix[y][x] = trail + if clockwise { + if y == 0 && x != width-1 { + x++ + } else if x == width-1 && y != height-1 { + y++ + } else if y == height-1 && x != 0 { + x-- + } else if x == 0 && y != 0 { + y-- + } + } else { + if x == 0 && y != height-1 { + y++ + } else if y == height-1 && x != width-1 { + x++ + } else if x == width-1 && y != 0 { + y-- + } else if y == 0 && x != 0 { + x-- + } + } + } + + var rows []string + for _, row := range matrix { + rows = append(rows, lipgloss.JoinHorizontal(0, row...)) + } + state := lipgloss.JoinVertical(0, rows...) + states = append(states, state) + } + + return states +} + +type Model struct { + sp spinner.Model + content string + + Style lipgloss.Style + + delta time.Time + index int +} + +func New() Model { + return Model{ + sp: spinner.New(spinner.WithSpinner(loading)), + content: "Update Failed - retrying in 3 sec...", + Style: style, + } +} + +func (m Model) Init() tea.Cmd { + return m.sp.Tick +} + +func (m Model) View() string { + vp := viewport.New(40, 5) + vp.Style = m.Style + vp.SetContent(m.content) + + result := lipgloss.JoinVertical(lipgloss.Center, m.sp.View(), vp.View()) + + return lipgloss.Place( + ui.Width, ui.Height, + lipgloss.Center, lipgloss.Center, + result, + ) +} + +func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + switch msg := msg.(type) { + + case tea.KeyMsg: + key := msg.Type + switch key { + case tea.KeyCtrlC: + return m, tea.Quit + + case tea.KeyCtrlT: + return m, m.sp.Tick + } + + case spinner.TickMsg: + if m.index == 0 { + m.delta = time.Now() + } + delta := time.Since(m.delta) + log.Printf("Frame %v Delta %v\n", m.index, delta) + m.index++ + m.delta = time.Now() + var cmd tea.Cmd + m.sp, cmd = m.sp.Update(msg) + return m, cmd + } + + return m, nil +} |
