https://go.dev/doc/modules/layout This also enables us to later import just the db interaction part say to the gemini capsule backend go project.
151 lines
3.1 KiB
Go
151 lines
3.1 KiB
Go
package ui
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"log/slog"
|
|
"os"
|
|
|
|
gemlog "git.travisshears.com/travisshears/gemlog-cli/gemlog"
|
|
tea "github.com/charmbracelet/bubbletea"
|
|
)
|
|
|
|
type Page string
|
|
|
|
const (
|
|
ActionList Page = "actionList"
|
|
EntryList Page = "entryList"
|
|
Entry Page = "entry"
|
|
)
|
|
|
|
type SwitchPages struct{ Page Page }
|
|
type Notification string
|
|
type ErrorMsg struct{ err error }
|
|
type GemLogsLoaded struct{ Logs []gemlog.GemlogListEntry }
|
|
type GemLogLoaded struct{ Log gemlog.GemlogEntry }
|
|
|
|
type uiState struct {
|
|
notification string
|
|
errorTxt string
|
|
|
|
page Page
|
|
entryListPage EntryListPageModel
|
|
entryPage EntryPageModel
|
|
actionListPage ActionListPageModel
|
|
}
|
|
|
|
type context struct {
|
|
config *gemlog.Config
|
|
}
|
|
|
|
type model struct {
|
|
ui uiState
|
|
context *context
|
|
}
|
|
|
|
func initialModel(config *gemlog.Config) model {
|
|
return model{
|
|
ui: uiState{
|
|
page: ActionList,
|
|
actionListPage: initialActionListPageModel(),
|
|
entryListPage: initialEntryListPageModel(),
|
|
entryPage: initialEntryPageModel(),
|
|
},
|
|
context: &context{
|
|
config: config,
|
|
},
|
|
}
|
|
}
|
|
|
|
func (m model) Init() tea.Cmd {
|
|
cmds := make([]tea.Cmd, 0)
|
|
cmds = append(cmds, tea.SetWindowTitle("Gemlog CLI"))
|
|
// TODO: add init commands from other pages
|
|
return tea.Batch(cmds...)
|
|
}
|
|
|
|
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|
cmds := make([]tea.Cmd, 3)
|
|
switch msg := msg.(type) {
|
|
case SwitchPages:
|
|
m.ui.page = msg.Page
|
|
case ErrorMsg:
|
|
m.ui.errorTxt = fmt.Sprintf("%s\n\n", fmt.Errorf("%s", msg))
|
|
case Notification:
|
|
m.ui.notification = fmt.Sprintf("%s\n\n", string(msg))
|
|
case tea.KeyMsg:
|
|
switch msg.String() {
|
|
case "ctrl+c", "q":
|
|
return m, tea.Quit
|
|
}
|
|
}
|
|
|
|
actionListM, cmd := m.ui.actionListPage.Update(msg, m.ui.page == ActionList, m.context)
|
|
m.ui.actionListPage = actionListM
|
|
cmds = append(cmds, cmd)
|
|
|
|
entryListM, cmd := m.ui.entryListPage.Update(msg, m.ui.page == EntryList, m.context)
|
|
m.ui.entryListPage = entryListM
|
|
cmds = append(cmds, cmd)
|
|
|
|
entrytM, cmd := m.ui.entryPage.Update(msg, m.ui.page == Entry, m.context)
|
|
m.ui.entryPage = entrytM
|
|
cmds = append(cmds, cmd)
|
|
|
|
return m, tea.Batch(cmds...)
|
|
}
|
|
|
|
func (m model) View() string {
|
|
if len(m.ui.errorTxt) > 0 {
|
|
return m.ui.errorTxt
|
|
}
|
|
s := ""
|
|
if m.ui.notification != "" {
|
|
s += m.ui.notification
|
|
}
|
|
|
|
switch m.ui.page {
|
|
case ActionList:
|
|
s += m.ui.actionListPage.View()
|
|
case EntryList:
|
|
s += m.ui.entryListPage.View()
|
|
case Entry:
|
|
s += m.ui.entryPage.View()
|
|
}
|
|
|
|
s += "\nPress q to quit.\n"
|
|
|
|
return s
|
|
}
|
|
|
|
var enableLogs bool = false
|
|
|
|
func Run() {
|
|
if enableLogs {
|
|
f, err := tea.LogToFile("debug.log", "debug")
|
|
if err != nil {
|
|
fmt.Println("fatal:", err)
|
|
os.Exit(1)
|
|
}
|
|
defer f.Close()
|
|
} else {
|
|
logger := slog.New(slog.NewJSONHandler(io.Discard, nil))
|
|
slog.SetDefault(logger)
|
|
}
|
|
slog.Info("Starting gemlog cli")
|
|
config, err := gemlog.LoadConfig()
|
|
if err != nil {
|
|
fmt.Printf("Error loading config: %v", err)
|
|
os.Exit(1)
|
|
}
|
|
err = gemlog.CheckDBConnection(config)
|
|
if err != nil {
|
|
fmt.Printf("Error checking db connection: %v", err)
|
|
os.Exit(1)
|
|
}
|
|
p := tea.NewProgram(initialModel(config))
|
|
if _, err := p.Run(); err != nil {
|
|
fmt.Printf("Alas, there's been an error: %v", err)
|
|
os.Exit(1)
|
|
}
|
|
}
|