mirror of
https://github.com/taigrr/wtf
synced 2025-01-18 04:03:14 -08:00
Basic selectable todo functionality working
Can: - move between todo items - toggle checked/unchecked state Cannot: - persiste changes to file - add items - delete items
This commit is contained in:
parent
67e02bf4f5
commit
a0ce5eb412
@ -64,8 +64,6 @@ func (widget *Widget) formatChange(line string) string {
|
||||
line = strings.Replace(line, "M", "[yellow]M[white]", 1)
|
||||
case 'R':
|
||||
line = strings.Replace(line, "R", "[purple]R[white]", 1)
|
||||
default:
|
||||
line = line
|
||||
}
|
||||
|
||||
return fmt.Sprintf(" %s\n", strings.Replace(line, "\"", "", -1))
|
||||
|
@ -97,6 +97,4 @@ func (widget *Widget) keyboardIntercept(event *tcell.EventKey) *tcell.EventKey {
|
||||
default:
|
||||
return event
|
||||
}
|
||||
|
||||
return event
|
||||
}
|
||||
|
@ -96,6 +96,4 @@ func (widget *Widget) keyboardIntercept(event *tcell.EventKey) *tcell.EventKey {
|
||||
default:
|
||||
return event
|
||||
}
|
||||
|
||||
return event
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ package textfile
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"time"
|
||||
|
||||
"github.com/olebedev/config"
|
||||
@ -20,8 +19,8 @@ type Widget struct {
|
||||
|
||||
func NewWidget() *Widget {
|
||||
widget := Widget{
|
||||
TextWidget: wtf.NewTextWidget(" Text File ", "textfile"),
|
||||
FilePath: Config.UString("wtf.mods.textfile.filepath"),
|
||||
TextWidget: wtf.NewTextWidget(" 📄 Text File ", "textfile"),
|
||||
FilePath: Config.UString("wtf.mods.textfile.filename"),
|
||||
}
|
||||
|
||||
widget.View.SetWrap(true)
|
||||
@ -41,7 +40,7 @@ func (widget *Widget) Refresh() {
|
||||
|
||||
widget.View.Clear()
|
||||
|
||||
fileData, err := widget.readFile()
|
||||
fileData, err := wtf.ReadFile(widget.FilePath)
|
||||
|
||||
if err != nil {
|
||||
fmt.Fprintf(widget.View, "%s", err)
|
||||
@ -49,16 +48,3 @@ func (widget *Widget) Refresh() {
|
||||
fmt.Fprintf(widget.View, "%s", fileData)
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------- Uneported Functions -------------------- */
|
||||
|
||||
func (widget *Widget) readFile() (string, error) {
|
||||
absPath, _ := wtf.ExpandHomeDir(widget.FilePath)
|
||||
|
||||
bytes, err := ioutil.ReadFile(absPath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(bytes), nil
|
||||
}
|
||||
|
31
todo/display.go
Normal file
31
todo/display.go
Normal file
@ -0,0 +1,31 @@
|
||||
package todo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func (widget *Widget) display() {
|
||||
widget.View.Clear()
|
||||
|
||||
title := fmt.Sprintf(" 📝 %s ", widget.FilePath)
|
||||
widget.View.SetTitle(title)
|
||||
|
||||
str := ""
|
||||
for idx, item := range widget.list.Items {
|
||||
foreColor, backColor := "white", "black"
|
||||
|
||||
if widget.View.HasFocus() && idx == widget.list.selected {
|
||||
foreColor, backColor = "black", "olive"
|
||||
}
|
||||
|
||||
str = str + fmt.Sprintf(
|
||||
"[%s:%s]|%s| %s[white]\n",
|
||||
foreColor,
|
||||
backColor,
|
||||
item.CheckMark(),
|
||||
item.Text,
|
||||
)
|
||||
}
|
||||
|
||||
fmt.Fprintf(widget.View, "%s", str)
|
||||
}
|
29
todo/item.go
Normal file
29
todo/item.go
Normal file
@ -0,0 +1,29 @@
|
||||
package todo
|
||||
|
||||
import(
|
||||
"time"
|
||||
)
|
||||
|
||||
type Item struct {
|
||||
Checked bool
|
||||
Index int
|
||||
Text string
|
||||
|
||||
createdAt time.Time
|
||||
updatedAt time.Time
|
||||
}
|
||||
|
||||
func (item *Item) CheckMark() string {
|
||||
if item.Checked {
|
||||
return "x"
|
||||
} else {
|
||||
return " "
|
||||
}
|
||||
}
|
||||
|
||||
func (item *Item) Toggle() {
|
||||
item.Checked = !item.Checked
|
||||
item.updatedAt = time.Now()
|
||||
}
|
||||
|
||||
|
44
todo/list.go
Normal file
44
todo/list.go
Normal file
@ -0,0 +1,44 @@
|
||||
package todo
|
||||
|
||||
import ()
|
||||
|
||||
type List struct {
|
||||
Items []*Item
|
||||
|
||||
selected int
|
||||
}
|
||||
|
||||
func (list *List) Len() int {
|
||||
return len(list.Items)
|
||||
}
|
||||
|
||||
func (list *List) Less(i, j int) bool {
|
||||
return list.Items[i].Index < list.Items[j].Index
|
||||
}
|
||||
|
||||
func (list *List) Swap(i, j int) {
|
||||
list.Items[i], list.Items[j] = list.Items[j], list.Items[i]
|
||||
}
|
||||
|
||||
func (list *List) Next() {
|
||||
list.selected = list.selected + 1
|
||||
if list.selected >= len(list.Items) {
|
||||
list.selected = 0
|
||||
}
|
||||
}
|
||||
|
||||
func (list *List) Prev() {
|
||||
list.selected = list.selected - 1
|
||||
if list.selected < 0 {
|
||||
list.selected = len(list.Items) - 1
|
||||
}
|
||||
}
|
||||
|
||||
// Toggle switches the checked state of the selected item
|
||||
func (list *List) Toggle() {
|
||||
list.Items[list.selected].Toggle()
|
||||
}
|
||||
|
||||
func (list *List) Unselect() {
|
||||
list.selected = -1
|
||||
}
|
101
todo/widget.go
Normal file
101
todo/widget.go
Normal file
@ -0,0 +1,101 @@
|
||||
package todo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/gdamore/tcell"
|
||||
"github.com/olebedev/config"
|
||||
"github.com/senorprogrammer/wtf/wtf"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
// Config is a pointer to the global config object
|
||||
var Config *config.Config
|
||||
|
||||
type Widget struct {
|
||||
wtf.TextWidget
|
||||
|
||||
FilePath string
|
||||
list *List
|
||||
}
|
||||
|
||||
func NewWidget() *Widget {
|
||||
widget := Widget{
|
||||
TextWidget: wtf.NewTextWidget(" 📝 Todo ", "todo"),
|
||||
FilePath: Config.UString("wtf.mods.todo.filename"),
|
||||
|
||||
list: &List{selected: -1},
|
||||
}
|
||||
|
||||
widget.init()
|
||||
widget.View.SetInputCapture(widget.keyboardIntercept)
|
||||
|
||||
return &widget
|
||||
}
|
||||
|
||||
/* -------------------- Exported Functions -------------------- */
|
||||
|
||||
func (widget *Widget) Refresh() {
|
||||
if widget.Disabled() {
|
||||
return
|
||||
}
|
||||
|
||||
confDir, _ := wtf.ConfigDir()
|
||||
|
||||
fileData, _ := wtf.ReadYamlFile(fmt.Sprintf("%s/%s", confDir, widget.FilePath))
|
||||
yaml.Unmarshal(fileData, &widget.list)
|
||||
|
||||
widget.display()
|
||||
widget.RefreshedAt = time.Now()
|
||||
}
|
||||
|
||||
/* -------------------- Unexported Functions -------------------- */
|
||||
|
||||
func (widget *Widget) init() {
|
||||
_, err := wtf.CreateFile(widget.FilePath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (widget *Widget) keyboardIntercept(event *tcell.EventKey) *tcell.EventKey {
|
||||
switch string(event.Rune()) {
|
||||
case " ":
|
||||
// Check/uncheck selected item
|
||||
widget.list.Toggle()
|
||||
widget.display()
|
||||
return nil
|
||||
case "e":
|
||||
// Edit selected item
|
||||
return nil
|
||||
case "n":
|
||||
// Add a new item
|
||||
return nil
|
||||
}
|
||||
|
||||
switch event.Key() {
|
||||
case tcell.KeyCtrlD:
|
||||
// Delete selected item
|
||||
return nil
|
||||
case tcell.KeyDown:
|
||||
widget.list.Next()
|
||||
widget.display()
|
||||
return nil
|
||||
//case tcell.KeySpac:
|
||||
//// Check/uncheck an item
|
||||
//return nil
|
||||
case tcell.KeyEsc:
|
||||
// Unselect the current row and pass the key on through to unselect the widget
|
||||
widget.list.Unselect()
|
||||
widget.display()
|
||||
return event
|
||||
case tcell.KeyUp:
|
||||
// Select next item up
|
||||
widget.list.Prev()
|
||||
widget.display()
|
||||
return nil
|
||||
default:
|
||||
return event
|
||||
}
|
||||
}
|
@ -204,6 +204,4 @@ func (widget *Widget) keyboardIntercept(event *tcell.EventKey) *tcell.EventKey {
|
||||
default:
|
||||
return event
|
||||
}
|
||||
|
||||
return event
|
||||
}
|
||||
|
3
wtf.go
3
wtf.go
@ -20,6 +20,7 @@ import (
|
||||
"github.com/senorprogrammer/wtf/security"
|
||||
"github.com/senorprogrammer/wtf/status"
|
||||
"github.com/senorprogrammer/wtf/textfile"
|
||||
"github.com/senorprogrammer/wtf/todo"
|
||||
"github.com/senorprogrammer/wtf/weather"
|
||||
"github.com/senorprogrammer/wtf/wtf"
|
||||
)
|
||||
@ -126,6 +127,7 @@ func main() {
|
||||
security.Config = Config
|
||||
status.Config = Config
|
||||
textfile.Config = Config
|
||||
todo.Config = Config
|
||||
weather.Config = Config
|
||||
|
||||
Widgets = []wtf.TextViewer{
|
||||
@ -140,6 +142,7 @@ func main() {
|
||||
security.NewWidget(),
|
||||
status.NewWidget(),
|
||||
textfile.NewWidget(),
|
||||
todo.NewWidget(),
|
||||
weather.NewWidget(),
|
||||
}
|
||||
|
||||
|
@ -3,16 +3,26 @@ package wtf
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/olebedev/config"
|
||||
)
|
||||
|
||||
func ConfigDir() (string, error) {
|
||||
configDir, err := ExpandHomeDir("~/.wtf/")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return configDir, nil
|
||||
}
|
||||
|
||||
// CreateConfigDir creates the .wtf directory in the user's home dir
|
||||
func CreateConfigDir() bool {
|
||||
homeDir, _ := ExpandHomeDir("~/.wtf/")
|
||||
configDir, _ := ConfigDir()
|
||||
|
||||
if _, err := os.Stat(homeDir); os.IsNotExist(err) {
|
||||
err := os.Mkdir(homeDir, os.ModePerm)
|
||||
if _, err := os.Stat(configDir); os.IsNotExist(err) {
|
||||
err := os.Mkdir(configDir, os.ModePerm)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@ -21,6 +31,34 @@ func CreateConfigDir() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// CreateFile creates the named file in the config directory, if it does not already exist.
|
||||
// If the file exists it does not recreate it.
|
||||
// If successful, eturns the absolute path to the file
|
||||
// If unsuccessful, returns an error
|
||||
func CreateFile(fileName string) (string, error) {
|
||||
configDir, err := ConfigDir()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
filePath := fmt.Sprintf("%s/%s", configDir, fileName)
|
||||
|
||||
// Check if the file already exists; if it does not, create it
|
||||
_, err = os.Stat(filePath)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
_, err = os.Create(filePath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
} else {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
return filePath, nil
|
||||
}
|
||||
|
||||
// LoadConfigFile loads the config.yml file to configure the app
|
||||
func LoadConfigFile(filePath string) *config.Config {
|
||||
absPath, _ := ExpandHomeDir(filePath)
|
||||
@ -34,3 +72,20 @@ func LoadConfigFile(filePath string) *config.Config {
|
||||
|
||||
return cfg
|
||||
}
|
||||
|
||||
|
||||
func ReadFile(fileName string) (string, error) {
|
||||
configDir, err := ConfigDir()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
filePath := fmt.Sprintf("%s/%s", configDir, fileName)
|
||||
|
||||
bytes, err := ioutil.ReadFile(filePath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(bytes), nil
|
||||
}
|
||||
|
10
wtf/utils.go
10
wtf/utils.go
@ -82,6 +82,16 @@ func Now() time.Time {
|
||||
return time.Now().Local()
|
||||
}
|
||||
|
||||
func ReadYamlFile(filePath string) ([]byte, error) {
|
||||
file, err := ioutil.ReadFile(filePath)
|
||||
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
}
|
||||
|
||||
return file, nil
|
||||
}
|
||||
|
||||
func RightAlignFormat(view *tview.TextView) string {
|
||||
_, _, w, _ := view.GetInnerRect()
|
||||
return fmt.Sprintf("%%%ds", w-1)
|
||||
|
Loading…
x
Reference in New Issue
Block a user