smutok/internal/tui/tui.go(view raw)
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 |
package tui
import (
"context"
"github.com/charmbracelet/bubbles/table"
"github.com/charmbracelet/bubbles/viewport"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/glamour"
"olexsmir.xyz/smutok/internal/store"
)
type Syncer interface {
Sync(ctx context.Context) error
}
type AppState int
const (
ArticlesView AppState = iota
FeedsView
ReadingView
)
type Model struct {
ctx context.Context
state AppState
isQutting bool
showErr bool
err error
syncer Syncer
store *store.Sqlite
articles []store.Article
glamur *glamour.TermRenderer
table table.Model // feeds, articles feed
viewport viewport.Model // article content reader
}
func NewModel(
ctx context.Context,
syncer Syncer,
store *store.Sqlite,
) *Model {
tbl := table.New(table.WithFocused(true))
vp := viewport.New(0, 0)
return &Model{
ctx: ctx,
syncer: syncer,
store: store,
glamur: &glamour.TermRenderer{},
table: tbl,
viewport: vp,
state: ArticlesView,
isQutting: false,
showErr: false,
err: nil,
articles: nil,
}
}
func (m *Model) Init() tea.Cmd {
return tea.Batch(
tea.SetWindowTitle("smutok"),
m.fetchArticles(store.ArticleAll),
)
}
func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
var cmd tea.Cmd
switch msg := msg.(type) {
case errMsg:
m.err = msg
m.showErr = true
return m, nil
case tea.WindowSizeMsg:
m.table.SetHeight(msg.Height)
m.table.SetWidth(msg.Width - 2)
m.viewport.Height = msg.Height
m.viewport.Width = msg.Width
return m, nil
case fetchedArticles:
m.articles = msg
m.setupTableWithArticles()
return m, nil
case tea.KeyMsg:
// page specific keys
switch m.state {
case ArticlesView, FeedsView:
m.table, cmd = m.table.Update(msg)
case ReadingView:
m.viewport, cmd = m.viewport.Update(msg)
}
// global keys
switch msg.String() {
case "q":
m.isQutting = true
return m, tea.Quit
}
}
return m, cmd
}
func (m *Model) View() string {
if m.isQutting {
return ""
}
var out string
switch m.state {
case ArticlesView, FeedsView:
out = m.table.View()
case ReadingView:
out = m.viewport.View()
}
return out
}
|