2020-05-13 16:53:58 +00:00
|
|
|
package ui
|
|
|
|
|
|
|
|
import (
|
2020-05-13 23:02:39 +00:00
|
|
|
"fmt"
|
|
|
|
"sort"
|
2020-05-14 22:47:59 +00:00
|
|
|
"strconv"
|
2020-05-13 23:02:39 +00:00
|
|
|
"strings"
|
|
|
|
|
2020-05-13 16:53:58 +00:00
|
|
|
"github.com/charmbracelet/boba"
|
|
|
|
"github.com/charmbracelet/boba/spinner"
|
|
|
|
"github.com/charmbracelet/charm"
|
|
|
|
"github.com/charmbracelet/charm/ui/common"
|
2020-05-13 23:02:39 +00:00
|
|
|
"github.com/muesli/reflow/indent"
|
|
|
|
te "github.com/muesli/termenv"
|
2020-05-13 16:53:58 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// MSG
|
|
|
|
|
|
|
|
type stashErrMsg error
|
2020-05-13 20:00:27 +00:00
|
|
|
type stashSpinnerTickMsg struct{}
|
2020-05-14 02:08:17 +00:00
|
|
|
type gotStashMsg []*charm.Markdown
|
|
|
|
type gotStashedItemMsg *charm.Markdown
|
2020-05-13 20:00:27 +00:00
|
|
|
|
2020-05-13 16:53:58 +00:00
|
|
|
// MODEL
|
|
|
|
|
|
|
|
type stashState int
|
|
|
|
|
|
|
|
const (
|
2020-05-13 20:00:27 +00:00
|
|
|
stashStateInit stashState = iota
|
2020-05-13 23:02:39 +00:00
|
|
|
stashStateLoaded
|
2020-05-14 02:08:17 +00:00
|
|
|
stashStateLoadingItem
|
2020-05-13 16:53:58 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type stashModel struct {
|
|
|
|
cc *charm.Client
|
|
|
|
err error
|
|
|
|
state stashState
|
|
|
|
documents []*charm.Markdown
|
|
|
|
page int
|
|
|
|
spinner spinner.Model
|
2020-05-14 00:21:37 +00:00
|
|
|
index int
|
2020-05-13 16:53:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// INIT
|
|
|
|
|
|
|
|
func stashInit(cc *charm.Client) (stashModel, boba.Cmd) {
|
|
|
|
s := spinner.NewModel()
|
|
|
|
s.Type = spinner.Dot
|
|
|
|
s.ForegroundColor = common.SpinnerColor
|
2020-05-13 20:00:27 +00:00
|
|
|
s.CustomMsgFunc = newSpinnerTickMsg
|
2020-05-13 16:53:58 +00:00
|
|
|
|
|
|
|
m := stashModel{
|
|
|
|
cc: cc,
|
|
|
|
spinner: s,
|
2020-05-13 20:00:27 +00:00
|
|
|
page: 1,
|
2020-05-13 16:53:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return m, boba.Batch(
|
2020-05-14 02:08:17 +00:00
|
|
|
loadStash(m),
|
2020-05-13 16:53:58 +00:00
|
|
|
spinner.Tick(s),
|
|
|
|
)
|
|
|
|
}
|
2020-05-13 20:00:27 +00:00
|
|
|
func newSpinnerTickMsg() boba.Msg {
|
|
|
|
return stashSpinnerTickMsg{}
|
|
|
|
}
|
2020-05-13 16:53:58 +00:00
|
|
|
|
|
|
|
// UPDATE
|
|
|
|
|
|
|
|
func stashUpdate(msg boba.Msg, m stashModel) (stashModel, boba.Cmd) {
|
|
|
|
switch msg := msg.(type) {
|
|
|
|
|
2020-05-14 00:21:37 +00:00
|
|
|
case boba.KeyMsg:
|
|
|
|
switch msg.String() {
|
|
|
|
|
|
|
|
case "k":
|
|
|
|
fallthrough
|
|
|
|
case "up":
|
|
|
|
m.index = max(0, m.index-1)
|
|
|
|
return m, nil
|
|
|
|
|
|
|
|
case "j":
|
|
|
|
fallthrough
|
|
|
|
case "down":
|
|
|
|
m.index = min(len(m.documents)-1, m.index+1)
|
|
|
|
return m, nil
|
|
|
|
|
2020-05-14 02:08:17 +00:00
|
|
|
case "enter":
|
|
|
|
m.state = stashStateLoadingItem
|
|
|
|
return m, boba.Batch(
|
|
|
|
loadStashedItem(m.cc, m.documents[m.index].ID),
|
|
|
|
spinner.Tick(m.spinner),
|
|
|
|
)
|
|
|
|
|
2020-05-14 00:21:37 +00:00
|
|
|
}
|
|
|
|
|
2020-05-13 16:53:58 +00:00
|
|
|
case stashErrMsg:
|
|
|
|
m.err = msg
|
2020-05-14 02:08:17 +00:00
|
|
|
return m, nil
|
2020-05-13 16:53:58 +00:00
|
|
|
|
|
|
|
case gotStashMsg:
|
2020-05-13 23:02:39 +00:00
|
|
|
sort.Sort(charm.MarkdownsByCreatedAt(msg)) // sort by date
|
2020-05-13 16:53:58 +00:00
|
|
|
m.documents = msg
|
2020-05-13 23:02:39 +00:00
|
|
|
m.state = stashStateLoaded
|
2020-05-14 02:08:17 +00:00
|
|
|
return m, nil
|
2020-05-13 16:53:58 +00:00
|
|
|
|
2020-05-13 20:00:27 +00:00
|
|
|
case stashSpinnerTickMsg:
|
2020-05-14 02:08:17 +00:00
|
|
|
if m.state == stashStateInit || m.state == stashStateLoadingItem {
|
2020-05-13 16:53:58 +00:00
|
|
|
var cmd boba.Cmd
|
|
|
|
m.spinner, cmd = spinner.Update(msg, m.spinner)
|
|
|
|
return m, cmd
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return m, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// VIEW
|
|
|
|
|
|
|
|
func stashView(m stashModel) string {
|
|
|
|
var s string
|
2020-05-13 23:02:39 +00:00
|
|
|
switch m.state {
|
|
|
|
case stashStateInit:
|
|
|
|
s += spinner.View(m.spinner) + " Loading stash..."
|
2020-05-14 02:08:17 +00:00
|
|
|
case stashStateLoadingItem:
|
|
|
|
s += spinner.View(m.spinner) + " Loading document..."
|
2020-05-13 23:02:39 +00:00
|
|
|
case stashStateLoaded:
|
|
|
|
if len(m.documents) == 0 {
|
|
|
|
s += stashEmtpyView(m)
|
|
|
|
break
|
|
|
|
}
|
|
|
|
s += stashPopulatedView(m)
|
|
|
|
}
|
|
|
|
return "\n" + indent.String(s, 2)
|
|
|
|
}
|
|
|
|
|
|
|
|
func stashEmtpyView(m stashModel) string {
|
|
|
|
return "Nothing stashed yet."
|
|
|
|
}
|
|
|
|
|
|
|
|
func stashPopulatedView(m stashModel) string {
|
|
|
|
s := "Here's your markdown stash:\n\n"
|
2020-05-14 00:21:37 +00:00
|
|
|
for i, v := range m.documents {
|
|
|
|
state := common.StateNormal
|
|
|
|
if i == m.index {
|
|
|
|
state = common.StateSelected
|
|
|
|
}
|
|
|
|
s += stashListItemView(*v).render(state) + "\n\n"
|
2020-05-13 23:02:39 +00:00
|
|
|
}
|
|
|
|
s = strings.TrimSpace(s)
|
|
|
|
return s
|
|
|
|
}
|
|
|
|
|
|
|
|
type stashListItemView charm.Markdown
|
|
|
|
|
2020-05-14 00:21:37 +00:00
|
|
|
func (m stashListItemView) render(state common.State) string {
|
|
|
|
line := common.VerticalLine(state) + " "
|
2020-05-14 22:47:59 +00:00
|
|
|
keyColor := common.NoColor
|
|
|
|
switch state {
|
|
|
|
case common.StateSelected:
|
|
|
|
keyColor = common.Fuschia
|
|
|
|
case common.StateDeleting:
|
|
|
|
keyColor = common.Red
|
|
|
|
}
|
|
|
|
titleKey := strconv.Itoa(m.ID)
|
|
|
|
if m.Note != "" {
|
|
|
|
titleKey += ":"
|
2020-05-14 00:21:37 +00:00
|
|
|
}
|
2020-05-14 22:47:59 +00:00
|
|
|
titleKey = te.String("#" + titleKey).Foreground(keyColor.Color()).String()
|
|
|
|
dateKey := te.String("Stashed:").Foreground(keyColor.Color()).String()
|
2020-05-13 23:02:39 +00:00
|
|
|
var s string
|
2020-05-14 22:47:59 +00:00
|
|
|
s += fmt.Sprintf("%s%s %s\n", line, titleKey, m.title(state))
|
|
|
|
s += fmt.Sprintf("%s%s %s", line, dateKey, m.date(state))
|
2020-05-13 23:02:39 +00:00
|
|
|
return s
|
|
|
|
}
|
|
|
|
|
2020-05-14 00:21:37 +00:00
|
|
|
func (m stashListItemView) date(state common.State) string {
|
|
|
|
c := common.Indigo
|
|
|
|
if state == common.StateDeleting {
|
|
|
|
c = common.FaintRed
|
|
|
|
}
|
2020-05-13 23:02:39 +00:00
|
|
|
s := m.CreatedAt.Format("02 Jan 2006 15:04:05 MST")
|
2020-05-14 00:21:37 +00:00
|
|
|
return te.String(s).Foreground(c.Color()).String()
|
2020-05-13 23:02:39 +00:00
|
|
|
}
|
|
|
|
|
2020-05-14 00:21:37 +00:00
|
|
|
func (m stashListItemView) title(state common.State) string {
|
2020-05-13 23:02:39 +00:00
|
|
|
if m.Note == "" {
|
|
|
|
return ""
|
2020-05-13 16:53:58 +00:00
|
|
|
}
|
2020-05-14 00:21:37 +00:00
|
|
|
c := common.Indigo
|
|
|
|
if state == common.StateDeleting {
|
|
|
|
c = common.Red
|
|
|
|
}
|
2020-05-14 22:47:59 +00:00
|
|
|
return te.String(m.Note).Foreground(c.Color()).String()
|
2020-05-13 16:53:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// CMD
|
|
|
|
|
2020-05-14 02:08:17 +00:00
|
|
|
func loadStash(m stashModel) boba.Cmd {
|
2020-05-13 16:53:58 +00:00
|
|
|
return func() boba.Msg {
|
|
|
|
stash, err := m.cc.GetStash(m.page)
|
|
|
|
if err != nil {
|
|
|
|
return stashErrMsg(err)
|
|
|
|
}
|
|
|
|
return gotStashMsg(stash)
|
|
|
|
}
|
|
|
|
}
|
2020-05-14 02:08:17 +00:00
|
|
|
|
|
|
|
func loadStashedItem(cc *charm.Client, id int) boba.Cmd {
|
|
|
|
return func() boba.Msg {
|
|
|
|
m, err := cc.GetStashMarkdown(id)
|
|
|
|
if err != nil {
|
|
|
|
return stashErrMsg(err)
|
|
|
|
}
|
|
|
|
return gotStashedItemMsg(m)
|
|
|
|
}
|
|
|
|
}
|