2022-03-22 21:58:42 +00:00
|
|
|
package ui
|
|
|
|
|
|
|
|
import (
|
|
|
|
table "github.com/calyptia/go-bubble-table"
|
|
|
|
"github.com/charmbracelet/bubbles/viewport"
|
|
|
|
tea "github.com/charmbracelet/bubbletea"
|
|
|
|
"github.com/charmbracelet/lipgloss"
|
2022-03-22 22:23:31 +00:00
|
|
|
"log"
|
|
|
|
"strings"
|
2022-03-22 21:58:42 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type uiModel struct {
|
|
|
|
table table.Model
|
|
|
|
viewport viewport.Model
|
|
|
|
|
2022-03-22 22:23:31 +00:00
|
|
|
ready bool
|
2022-03-22 21:58:42 +00:00
|
|
|
tableRows []table.Row
|
2022-03-22 22:23:31 +00:00
|
|
|
message string
|
2022-03-22 21:58:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func NewModel() tea.Model {
|
|
|
|
tbl := table.New([]string{"seq", "message"}, 100, 20)
|
|
|
|
rows := make([]table.Row, 0)
|
|
|
|
tbl.SetRows(rows)
|
|
|
|
|
|
|
|
model := uiModel{
|
|
|
|
table: tbl,
|
|
|
|
tableRows: rows,
|
2022-03-22 22:23:31 +00:00
|
|
|
message: "",
|
2022-03-22 21:58:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return model
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m uiModel) Init() tea.Cmd {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *uiModel) updateViewportToSelectedMessage() {
|
2022-03-22 22:23:31 +00:00
|
|
|
if !m.ready {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(m.tableRows) == 0 {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-03-22 21:58:42 +00:00
|
|
|
if message, ok := m.table.SelectedRow().(messageTableRow); ok {
|
|
|
|
m.viewport.SetContent(message.Data)
|
|
|
|
} else {
|
|
|
|
m.viewport.SetContent("(no message selected)")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m uiModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|
|
|
switch msg := msg.(type) {
|
|
|
|
case NewMessagesEvent:
|
|
|
|
for _, newMsg := range msg {
|
|
|
|
m.tableRows = append(m.tableRows, messageTableRow(*newMsg))
|
|
|
|
}
|
|
|
|
m.table.SetRows(m.tableRows)
|
|
|
|
m.updateViewportToSelectedMessage()
|
|
|
|
|
2022-03-22 22:23:31 +00:00
|
|
|
case tea.WindowSizeMsg:
|
|
|
|
footerHeight := lipgloss.Height(m.footerView())
|
|
|
|
|
|
|
|
if !m.ready {
|
|
|
|
tableHeight := msg.Height / 2
|
|
|
|
|
|
|
|
m.table.SetSize(msg.Width, tableHeight)
|
|
|
|
m.viewport = viewport.New(msg.Width, msg.Height-tableHeight-footerHeight)
|
|
|
|
m.viewport.SetContent("(no message selected)")
|
|
|
|
m.ready = true
|
|
|
|
log.Println("Viewport is now ready")
|
|
|
|
} else {
|
|
|
|
tableHeight := msg.Height / 2
|
|
|
|
|
|
|
|
m.table.SetSize(msg.Width, tableHeight)
|
|
|
|
m.viewport.Width = msg.Width
|
|
|
|
m.viewport.Height = msg.Height - tableHeight - footerHeight
|
|
|
|
//m.viewport.YPosition = tableHeight
|
|
|
|
}
|
|
|
|
|
2022-03-22 21:58:42 +00:00
|
|
|
case tea.KeyMsg:
|
|
|
|
|
|
|
|
switch msg.String() {
|
|
|
|
|
|
|
|
case "ctrl+c", "q":
|
|
|
|
return m, tea.Quit
|
|
|
|
case "up", "i":
|
|
|
|
m.table.GoUp()
|
|
|
|
m.updateViewportToSelectedMessage()
|
|
|
|
case "down", "k":
|
|
|
|
m.table.GoDown()
|
|
|
|
m.updateViewportToSelectedMessage()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-22 22:23:31 +00:00
|
|
|
updatedTable, tableMsgs := m.table.Update(msg)
|
2022-03-22 21:58:42 +00:00
|
|
|
updatedViewport, viewportMsgs := m.viewport.Update(msg)
|
|
|
|
|
|
|
|
m.table = updatedTable
|
|
|
|
m.viewport = updatedViewport
|
|
|
|
|
|
|
|
return m, tea.Batch(tableMsgs, viewportMsgs)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m uiModel) View() string {
|
2022-03-22 22:23:31 +00:00
|
|
|
if !m.ready {
|
|
|
|
return "Initializing"
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Println("Returning full view")
|
|
|
|
return lipgloss.JoinVertical(lipgloss.Top, m.table.View(), m.viewport.View(), m.footerView())
|
|
|
|
//return lipgloss.JoinVertical(lipgloss.Top, m.table.View(), m.footerView())
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m uiModel) footerView() string {
|
|
|
|
title := m.message
|
|
|
|
line := strings.Repeat(" ", max(0, m.viewport.Width-lipgloss.Width(title)))
|
|
|
|
return lipgloss.JoinHorizontal(lipgloss.Left, title, line)
|
|
|
|
}
|
|
|
|
|
|
|
|
func max(a, b int) int {
|
|
|
|
if a > b {
|
|
|
|
return a
|
|
|
|
}
|
|
|
|
return b
|
2022-03-22 21:58:42 +00:00
|
|
|
}
|