diff --git a/app/menu.go b/app/menu.go index 6bfa440..cf0c43d 100644 --- a/app/menu.go +++ b/app/menu.go @@ -29,8 +29,8 @@ func NewMainMenu() *MainMenu { title, ui.NewList([]string{ "record some feels", - "manage your feels ", - "check out your neighbors", // TODO + "manage your feels", + "check out your neighbors", "browse global feels", // TODO "visit your subscriptions", // TODO "scribble some graffiti", // TODO @@ -64,6 +64,8 @@ func (menu *MainMenu) Event(state *ui.State, event vaxis.Event) (processed bool) newFeels(state) case 1: ui.ViewChange <- NewManagement() + case 2: + ui.ViewChange <- NewNeighbors() case 6: ui.ViewChange <- NewConfig() case 7: diff --git a/app/neighbors.go b/app/neighbors.go new file mode 100644 index 0000000..b93a74f --- /dev/null +++ b/app/neighbors.go @@ -0,0 +1,82 @@ +package app + +import ( + "fmt" + "strconv" + + "git.sr.ht/~rockorager/vaxis" + "git.tilde.town/nbsp/neofeels/ttbp" + "git.tilde.town/nbsp/neofeels/ui" + "github.com/dustin/go-humanize" +) + +type Neighbors struct { + title string + list ui.List + help string + neighbors []ttbp.User +} + +func NewNeighbors() *Neighbors { + users := ttbp.SortUsersByRecent(ttbp.GetUsers()) + list := []string{} + for _, user := range users { + publishDir := "" + if user.Publishing { + publishDir = fmt.Sprintf("%s%s/%s", ttbp.PathLive, user.Name, user.PublishDir) + } + list = append(list, fmt.Sprintf( + "~%-14s %-15s %-46s", + user.Name, + "("+humanize.Time(user.LastPublished)+")", + publishDir, + )) + } + + return &Neighbors{ + title, + ui.NewList(list), + "↑↓/kj move ↵ enter q return", + users, + } +} + +func (neighbors *Neighbors) Event(state *ui.State, event vaxis.Event) (processed bool) { + if key, ok := event.(vaxis.Key); ok && key.EventType == vaxis.EventPress { + switch key.String() { + case "Ctrl+c", "Ctrl+d": + close(ui.Quit) + case "Down", "j": + neighbors.list.Down() + case "Up", "k": + neighbors.list.Up() + case "End", "Shift+g": + neighbors.list.End() + case "Home", "g": + neighbors.list.Home() + case "0", "1", "2", "3", "4", "5", "6", "7", "8", "9": + i, _ := strconv.Atoi(key.String()) + neighbors.list.SetIndex(i) + case "q", "h", "Left": + ui.ViewChange <- NewMainMenu() + case "Enter", "l", "Right": + } + processed = true + } + neighbors.Draw(state) + return +} + +func (neighbors *Neighbors) Draw(state *ui.State) { + win := state.Window() + win.New(win.Width/2-10, win.Height/2-8, 20, 5).Print(vaxis.Segment{Text: neighbors.title}) + neighbors.list.Draw(vaxis.Window{ + Vx: win.Vx, + Parent: nil, + Column: win.Width/2 - 40, + Row: win.Height/2 - 2, + Width: 80, + Height: 10, + }) + win.New(win.Width/2-15, win.Height/2+7, 30, 1).Print(vaxis.Segment{Text: neighbors.help}) +} diff --git a/go.mod b/go.mod index 62fabe3..8a54edf 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ require git.sr.ht/~rockorager/vaxis v0.11.0 require ( github.com/containerd/console v1.0.3 // indirect github.com/creack/pty v1.1.18 // indirect + github.com/dustin/go-humanize v1.0.1 // indirect github.com/mattn/go-runewidth v0.0.14 // indirect github.com/mattn/go-sixel v0.0.5 // indirect github.com/rivo/uniseg v0.4.4 // indirect diff --git a/go.sum b/go.sum index 9d5dea7..f5e0224 100644 --- a/go.sum +++ b/go.sum @@ -6,6 +6,8 @@ github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-sixel v0.0.5 h1:55w2FR5ncuhKhXrM5ly1eiqMQfZsnAHIpYNGZX03Cv8= diff --git a/ttbp/ttbp.go b/ttbp/ttbp.go new file mode 100644 index 0000000..4f2354a --- /dev/null +++ b/ttbp/ttbp.go @@ -0,0 +1,81 @@ +package ttbp + +import ( + "encoding/json" + "os" + "path" + "sort" + "time" + + "git.tilde.town/nbsp/neofeels/config" +) + +var ( + PathVar = "/var/global/ttbp" + PathVarWWW = path.Join(PathVar, "www") + PathLive = "https://tilde.town/~" + PathUserFile = path.Join(PathVar, "users.txt") + PathGraff = path.Join(PathVar, "graffiti") + PathWall = path.Join(PathGraff, "wall.txt") + PathWallLock = path.Join(PathGraff, ".lock") +) + +type User struct { + Name string + Publishing bool + PublishDir string + LastPublished time.Time +} + +// GetUsers gets all users with a valid ttbp config, with their name, publishing +// settings, and date of last publish, if any. +func GetUsers() (users []User) { + userDirs, _ := os.ReadDir("/home") + for _, user := range userDirs { + if !user.IsDir() { + continue + } + if file, err := os.Open(path.Join("/home", user.Name(), ".ttbp/config/ttbprc")); err == nil { + defer file.Close() + + // get user config + var config config.Config + decoder := json.NewDecoder(file) + err = decoder.Decode(&config) + if err != nil { + continue + } + + // get last published file + entries, err := os.ReadDir(path.Join("/home", user.Name(), ".ttbp/entries")) + if err != nil { + continue + } + var lastPublished time.Time = *new(time.Time) + if len(entries) > 0 { + info, err := entries[len(entries)-1].Info() + if err != nil { + continue + } + lastPublished = info.ModTime() + } + + users = append(users, User{ + Name: user.Name(), + Publishing: config.Publishing, + PublishDir: config.PublishDir, + LastPublished: lastPublished, + }) + } + } + return users +} + +// SortUsersByRecent sorts users, putting the users with the most recent +// published feels at the beginning. +func SortUsersByRecent(users []User) []User { + sort.Slice(users, func(i, j int) bool { + return users[i].LastPublished.After(users[j].LastPublished) + }) + return users +}