2021-10-09 16:22:18 +01:00
|
|
|
package ui
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
|
2023-02-14 07:54:10 +00:00
|
|
|
"codeflow.dananglin.me.uk/apollo/canal/internal/board"
|
2021-10-09 16:22:18 +01:00
|
|
|
"github.com/rivo/tview"
|
|
|
|
)
|
|
|
|
|
|
|
|
type shiftDirection int
|
|
|
|
|
|
|
|
const (
|
|
|
|
shiftLeft shiftDirection = iota
|
|
|
|
shiftRight
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
mainPage string = "main"
|
|
|
|
quitPage string = "quit"
|
|
|
|
addPage string = "add"
|
|
|
|
)
|
|
|
|
|
|
|
|
// App does some magical stuff.
|
|
|
|
type App struct {
|
|
|
|
*tview.Application
|
|
|
|
|
|
|
|
columns []column
|
|
|
|
flex *tview.Flex
|
|
|
|
pages *tview.Pages
|
|
|
|
focusedColumn int
|
2023-04-22 13:18:13 +01:00
|
|
|
board board.Board
|
2021-10-09 16:22:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// shutdown shuts down the application.
|
|
|
|
func (a *App) shutdown() {
|
2023-04-22 13:18:13 +01:00
|
|
|
a.closeBoard()
|
2021-10-09 16:22:18 +01:00
|
|
|
a.Stop()
|
|
|
|
}
|
|
|
|
|
2023-04-22 13:18:13 +01:00
|
|
|
// closeBoard closes the BoltDB database.
|
|
|
|
func (a *App) closeBoard() {
|
|
|
|
_ = a.board.Close()
|
2021-10-09 16:22:18 +01:00
|
|
|
}
|
|
|
|
|
2023-04-22 13:18:13 +01:00
|
|
|
// openBoard opens the kanban project.
|
|
|
|
func (a *App) openBoard(path string) error {
|
|
|
|
b, err := board.Open(path)
|
2021-10-09 16:22:18 +01:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("unable to load board, %w", err)
|
|
|
|
}
|
|
|
|
|
2023-04-22 13:18:13 +01:00
|
|
|
a.board = b
|
2021-10-09 16:22:18 +01:00
|
|
|
|
|
|
|
if err = a.refresh(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// refresh refreshes the UI.
|
|
|
|
func (a *App) refresh() error {
|
2023-04-22 13:18:13 +01:00
|
|
|
statusList, err := a.board.StatusList()
|
2021-10-09 16:22:18 +01:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("unable to get the status list, %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
a.updateBoard(statusList)
|
|
|
|
|
|
|
|
a.setColumnFocus()
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *App) updateBoard(statusList []board.Status) error {
|
|
|
|
a.flex.Clear()
|
2023-02-27 00:51:48 +00:00
|
|
|
|
2021-10-09 16:22:18 +01:00
|
|
|
columns := make([]column, len(statusList))
|
|
|
|
|
|
|
|
for i := range statusList {
|
|
|
|
columns[i] = a.newColumn(statusList[i].ID, statusList[i].Name)
|
|
|
|
|
|
|
|
if len(statusList[i].CardIds) > 0 {
|
2023-04-22 13:18:13 +01:00
|
|
|
cards, err := a.board.CardList(statusList[i].CardIds)
|
2021-10-09 16:22:18 +01:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("unable to get the card list. %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, c := range cards {
|
|
|
|
columns[i].cards.AddItem(fmt.Sprintf("[%d] %s", c.Id(), c.Title), "", 0, nil)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
a.flex.AddItem(columns[i].cards, 0, 1, false)
|
|
|
|
}
|
|
|
|
|
|
|
|
a.columns = columns
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *App) shiftColumnFocus(s shiftDirection) {
|
|
|
|
switch s {
|
|
|
|
case shiftRight:
|
|
|
|
if a.focusedColumn == len(a.columns)-1 {
|
|
|
|
a.focusedColumn = 0
|
|
|
|
} else {
|
|
|
|
a.focusedColumn++
|
|
|
|
}
|
|
|
|
case shiftLeft:
|
|
|
|
if a.focusedColumn == 0 {
|
|
|
|
a.focusedColumn = len(a.columns) - 1
|
|
|
|
} else {
|
|
|
|
a.focusedColumn--
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
a.setColumnFocus()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *App) setColumnFocus() {
|
|
|
|
a.SetFocus(a.columns[a.focusedColumn].cards)
|
|
|
|
}
|
|
|
|
|
|
|
|
// newCard creates a new card and saves it to the database.
|
|
|
|
func (a *App) newCard(title, content string) error {
|
|
|
|
args := board.CardArgs{
|
2023-02-27 00:51:48 +00:00
|
|
|
NewTitle: title,
|
2021-10-09 16:22:18 +01:00
|
|
|
NewContent: content,
|
|
|
|
}
|
|
|
|
|
2023-04-22 13:18:13 +01:00
|
|
|
if err := a.board.CreateCard(args); err != nil {
|
2021-10-09 16:22:18 +01:00
|
|
|
return fmt.Errorf("unable to create card, %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
a.refresh()
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: Move 'Add' to the centre of the app
|
|
|
|
// TODO: Customize list primitive or create a new one
|
2023-04-22 06:19:50 +01:00
|
|
|
// TODO: If customizing existing list primitive, wrap list around a column type. Add statusID to it.
|
2021-10-09 16:22:18 +01:00
|
|
|
// TODO: Update card status (card ID, oldStatus, newStatus)
|
|
|
|
|
|
|
|
//func viewCard() error {
|
|
|
|
//return nil
|
|
|
|
//}
|