emdb/terminal-client/tui/tabemdb.go

288 lines
6.7 KiB
Go
Raw Normal View History

2023-12-23 18:43:38 +01:00
package tui
import (
2023-12-24 11:06:04 +01:00
"fmt"
2023-12-26 12:01:37 +01:00
"strconv"
"strings"
2023-12-24 11:06:04 +01:00
"code.ewintr.nl/emdb/storage"
2023-12-23 18:43:38 +01:00
"github.com/charmbracelet/bubbles/list"
2024-01-06 13:00:29 +01:00
"github.com/charmbracelet/bubbles/textarea"
2023-12-26 12:01:37 +01:00
"github.com/charmbracelet/bubbles/textinput"
2023-12-23 18:43:38 +01:00
tea "github.com/charmbracelet/bubbletea"
2023-12-26 12:01:37 +01:00
"github.com/charmbracelet/lipgloss"
2023-12-23 18:43:38 +01:00
)
2023-12-26 13:19:23 +01:00
var (
focusedStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("205"))
blurredStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("240"))
noStyle = lipgloss.NewStyle()
)
2023-12-26 12:01:37 +01:00
type UpdateForm tea.Msg
type StoredMovie struct{}
2023-12-24 12:55:38 +01:00
type tabEMDB struct {
2024-01-06 13:00:29 +01:00
initialized bool
2024-03-09 13:18:51 +01:00
movieRepo *storage.MovieRepository
2024-01-06 13:00:29 +01:00
mode string
focused string
colWidth int
colHeight int
list list.Model
formLabels []string
inputWatchedOn textinput.Model
inputRating textinput.Model
inputComment textarea.Model
formFocus int
logger *Logger
2023-12-23 18:43:38 +01:00
}
2024-03-09 13:18:51 +01:00
func NewTabEMDB(movieRepo *storage.MovieRepository, logger *Logger) (tea.Model, tea.Cmd) {
2023-12-26 12:01:37 +01:00
del := list.NewDefaultDelegate()
list := list.New([]list.Item{}, del, 0, 0)
2023-12-24 10:16:11 +01:00
list.Title = "Movies"
list.SetShowHelp(false)
2023-12-26 12:01:37 +01:00
formLabels := []string{
2023-12-28 08:49:10 +01:00
"Watched on",
2023-12-26 12:01:37 +01:00
"Rating",
"Comment",
}
2024-01-06 14:49:45 +01:00
2024-01-06 13:00:29 +01:00
inputWatchedOn := textinput.New()
inputWatchedOn.Prompt = ""
inputWatchedOn.Width = 50
inputWatchedOn.CharLimit = 500
inputRating := textinput.New()
inputRating.Prompt = ""
inputRating.Width = 50
inputRating.CharLimit = 500
inputComment := textarea.New()
inputComment.SetWidth(50)
inputComment.SetHeight(3)
inputComment.CharLimit = 500
2023-12-26 12:01:37 +01:00
2023-12-24 12:55:38 +01:00
m := tabEMDB{
2024-01-06 13:00:29 +01:00
focused: "form",
movieRepo: movieRepo,
2024-01-06 13:00:29 +01:00
logger: logger,
mode: "view",
list: list,
formLabels: formLabels,
inputWatchedOn: inputWatchedOn,
inputRating: inputRating,
inputComment: inputComment,
2023-12-24 10:16:11 +01:00
}
2023-12-23 18:43:38 +01:00
2023-12-24 17:11:29 +01:00
logger.Log("search emdb...")
return m, FetchMovieList(movieRepo)
2023-12-23 18:43:38 +01:00
}
2023-12-24 12:55:38 +01:00
func (m tabEMDB) Init() tea.Cmd {
2023-12-23 18:43:38 +01:00
return nil
}
2023-12-24 12:55:38 +01:00
func (m tabEMDB) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
2023-12-23 18:43:38 +01:00
var cmd tea.Cmd
var cmds []tea.Cmd
switch msg := msg.(type) {
2023-12-25 13:29:43 +01:00
case TabSizeMsg:
2023-12-24 10:16:11 +01:00
if !m.initialized {
m.initialized = true
2023-12-23 18:43:38 +01:00
}
2023-12-26 12:01:37 +01:00
m.colWidth = msg.Width / 2
2024-01-06 13:00:29 +01:00
m.colHeight = msg.Height
2024-01-14 12:07:25 +01:00
m.list.SetSize(m.colWidth, msg.Height-4)
2023-12-26 12:01:37 +01:00
m.list, cmd = m.list.Update(msg)
cmds = append(cmds, cmd)
2023-12-24 10:16:11 +01:00
case Movies:
2023-12-24 17:11:29 +01:00
m.logger.Log(fmt.Sprintf("found %d movies in in emdb", len(msg)))
2023-12-24 10:16:11 +01:00
m.list.SetItems(msg.listItems())
2023-12-28 15:55:18 +01:00
m.list.Select(len(msg.listItems()) - 1)
2023-12-27 11:28:28 +01:00
m.UpdateForm()
2023-12-26 12:01:37 +01:00
m.list, cmd = m.list.Update(msg)
cmds = append(cmds, cmd)
case StoredMovie:
m.logger.Log("stored movie, fetching movie list")
cmds = append(cmds, FetchMovieList(m.movieRepo))
2023-12-26 12:01:37 +01:00
case tea.KeyMsg:
switch m.mode {
case "edit":
switch msg.String() {
case "tab", "shift+tab", "up", "down":
2023-12-27 10:49:51 +01:00
cmds = append(cmds, m.NavigateForm(msg.String())...)
2023-12-26 12:01:37 +01:00
case "enter":
m.mode = "view"
cmds = append(cmds, m.StoreMovie())
default:
cmds = append(cmds, m.updateFormInputs(msg))
}
default:
switch msg.String() {
2023-12-27 08:25:09 +01:00
case "ctrl+c", "q", "esc":
return m, tea.Quit
case "right", "tab":
cmds = append(cmds, SelectNextTab())
case "left", "shift+tab":
cmds = append(cmds, SelectPrevTab())
2023-12-26 12:01:37 +01:00
case "up":
m.list, cmd = m.list.Update(msg)
2023-12-28 08:49:10 +01:00
m.UpdateForm()
2023-12-26 12:01:37 +01:00
cmds = append(cmds, cmd)
case "down":
m.list, cmd = m.list.Update(msg)
2023-12-28 08:49:10 +01:00
m.UpdateForm()
2023-12-26 12:01:37 +01:00
cmds = append(cmds, cmd)
case "e":
m.mode = "edit"
2023-12-26 13:19:23 +01:00
m.formFocus = 0
2024-01-06 13:00:29 +01:00
m.inputWatchedOn.PromptStyle = focusedStyle
m.inputWatchedOn.TextStyle = focusedStyle
cmds = append(cmds, m.inputWatchedOn.Focus())
2023-12-26 12:01:37 +01:00
}
}
2023-12-23 18:43:38 +01:00
}
return m, tea.Batch(cmds...)
}
2023-12-24 12:55:38 +01:00
func (m tabEMDB) View() string {
2024-01-06 13:00:29 +01:00
colLeft := lipgloss.NewStyle().
2024-01-14 12:07:25 +01:00
Width(m.colWidth).
Height(m.colHeight).
2024-01-06 13:00:29 +01:00
Render(m.list.View())
colRight := lipgloss.NewStyle().
2024-01-14 12:07:25 +01:00
Width(m.colWidth).
Height(m.colHeight).
2024-01-06 13:00:29 +01:00
Render(m.ViewForm())
2023-12-26 12:01:37 +01:00
return lipgloss.JoinHorizontal(lipgloss.Top, colLeft, colRight)
}
2023-12-26 13:19:23 +01:00
func (m *tabEMDB) UpdateForm() {
movie, ok := m.list.SelectedItem().(Movie)
if !ok {
return
}
2024-01-06 13:00:29 +01:00
m.inputWatchedOn.SetValue(movie.m.WatchedOn)
m.inputRating.SetValue(fmt.Sprintf("%d", movie.m.Rating))
m.inputComment.SetValue(movie.m.Comment)
m.Log(fmt.Sprintf("showing movie %s", movie.m.ID))
2023-12-26 12:01:37 +01:00
}
2024-01-13 13:59:13 +01:00
func (m *tabEMDB) updateFormInputs(msg tea.Msg) tea.Cmd {
var cmd tea.Cmd
2023-12-26 13:19:23 +01:00
2024-01-13 13:59:13 +01:00
switch m.formFocus {
case 0:
m.inputWatchedOn, cmd = m.inputWatchedOn.Update(msg)
case 1:
m.inputRating, cmd = m.inputRating.Update(msg)
case 2:
m.inputComment, cmd = m.inputComment.Update(msg)
2023-12-26 13:19:23 +01:00
}
2024-01-13 13:59:13 +01:00
return cmd
2023-12-26 13:19:23 +01:00
}
2023-12-27 10:49:51 +01:00
func (m *tabEMDB) NavigateForm(key string) []tea.Cmd {
2024-01-06 13:00:29 +01:00
order := []string{"Watched on", "Rating", "Comment"}
2023-12-27 10:49:51 +01:00
var cmds []tea.Cmd
if key == "up" || key == "shift+tab" {
m.formFocus--
} else {
m.formFocus++
}
2024-01-13 13:59:13 +01:00
if m.formFocus >= len(order) {
2023-12-27 10:49:51 +01:00
m.formFocus = 0
}
if m.formFocus < 0 {
2024-01-13 13:59:13 +01:00
m.formFocus = len(order) - 1
2023-12-27 10:49:51 +01:00
}
2024-01-06 13:00:29 +01:00
switch order[m.formFocus] {
case "Watched on":
m.inputWatchedOn.PromptStyle = focusedStyle
m.inputWatchedOn.TextStyle = focusedStyle
cmds = append(cmds, m.inputWatchedOn.Focus())
m.inputRating.Blur()
m.inputComment.Blur()
case "Rating":
m.inputRating.PromptStyle = focusedStyle
m.inputRating.TextStyle = focusedStyle
cmds = append(cmds, m.inputRating.Focus())
m.inputWatchedOn.Blur()
m.inputComment.Blur()
case "Comment":
cmds = append(cmds, m.inputComment.Focus())
m.inputWatchedOn.Blur()
m.inputRating.Blur()
2023-12-27 10:49:51 +01:00
}
return cmds
}
2024-01-13 13:59:13 +01:00
func (m *tabEMDB) ViewForm() string {
movie, ok := m.list.SelectedItem().(Movie)
if !ok {
return ""
}
labels := []string{
"Title: ",
"English title: ",
"Year: ",
"Directors: ",
"Summary: ",
}
for _, l := range m.formLabels {
labels = append(labels, fmt.Sprintf("%s: ", l))
}
fields := []string{
movie.m.Title,
movie.m.EnglishTitle,
fmt.Sprintf("%d", movie.m.Year),
strings.Join(movie.m.Directors, ","),
movie.m.Summary,
}
fields = append(fields, m.inputWatchedOn.View(), m.inputRating.View(), m.inputComment.View())
labelView := strings.Join(labels, "\n")
fieldsView := strings.Join(fields, "\n")
return lipgloss.JoinHorizontal(lipgloss.Top, labelView, fieldsView)
}
2023-12-26 12:01:37 +01:00
func (m *tabEMDB) StoreMovie() tea.Cmd {
return func() tea.Msg {
2023-12-27 10:49:51 +01:00
updatedMovie := m.list.SelectedItem().(Movie)
2024-01-06 13:00:29 +01:00
updatedMovie.m.WatchedOn = m.inputWatchedOn.Value()
2023-12-27 10:49:51 +01:00
var err error
2024-01-06 13:00:29 +01:00
if updatedMovie.m.Rating, err = strconv.Atoi(m.inputRating.Value()); err != nil {
2023-12-26 12:01:37 +01:00
return fmt.Errorf("rating cannot be converted to an int: %w", err)
}
2024-01-06 13:00:29 +01:00
updatedMovie.m.Comment = m.inputComment.Value()
if err := m.movieRepo.Store(updatedMovie.m); err != nil {
2023-12-26 12:01:37 +01:00
return err
}
return StoredMovie{}
}
2023-12-23 18:43:38 +01:00
}
2023-12-24 12:55:38 +01:00
func (m *tabEMDB) Log(s string) {
m.logger.Log(s)
}
2023-12-24 11:06:04 +01:00
2024-03-09 13:18:51 +01:00
func FetchMovieList(movieRepo *storage.MovieRepository) tea.Cmd {
2023-12-24 11:06:04 +01:00
return func() tea.Msg {
ems, err := movieRepo.FindAll()
2023-12-24 11:06:04 +01:00
if err != nil {
2023-12-24 17:11:29 +01:00
return err
2023-12-24 11:06:04 +01:00
}
return Movies(ems)
}
}