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
|
|
|
|
2023-12-24 11:03:32 +01:00
|
|
|
"ewintr.nl/emdb/client"
|
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
|
|
|
|
emdb *client.EMDB
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2023-12-24 12:55:38 +01:00
|
|
|
func NewTabEMDB(emdb *client.EMDB, 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",
|
|
|
|
emdb: emdb,
|
|
|
|
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(emdb)
|
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
|
|
|
|
m.list.SetSize(m.colWidth-4, 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.emdb))
|
|
|
|
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().
|
|
|
|
Width(m.colWidth - 2).
|
|
|
|
Height(m.colHeight - 2).
|
|
|
|
Padding(1).
|
|
|
|
Render(m.list.View())
|
|
|
|
colRight := lipgloss.NewStyle().
|
|
|
|
Width(m.colWidth - 2).
|
|
|
|
Height(m.colHeight - 2).
|
|
|
|
Padding(1).
|
|
|
|
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()
|
2023-12-27 11:28:28 +01:00
|
|
|
if _, err := m.emdb.CreateMovie(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 11:03:32 +01:00
|
|
|
|
2023-12-24 12:55:38 +01:00
|
|
|
func (m *tabEMDB) Log(s string) {
|
2023-12-24 11:03:32 +01:00
|
|
|
m.logger.Log(s)
|
|
|
|
}
|
2023-12-24 11:06:04 +01:00
|
|
|
|
2023-12-24 17:11:29 +01:00
|
|
|
func FetchMovieList(emdb *client.EMDB) tea.Cmd {
|
2023-12-24 11:06:04 +01:00
|
|
|
return func() tea.Msg {
|
|
|
|
ems, err := emdb.GetMovies()
|
|
|
|
if err != nil {
|
2023-12-24 17:11:29 +01:00
|
|
|
return err
|
2023-12-24 11:06:04 +01:00
|
|
|
}
|
|
|
|
return Movies(ems)
|
|
|
|
}
|
|
|
|
}
|