Max Fixes and scrolling update

This commit is contained in:
foglar 2025-09-04 16:03:49 +02:00
parent 8046177af0
commit 1eebca289f
10 changed files with 128 additions and 94 deletions

2
.gitignore vendored
View File

@ -1,3 +1,5 @@
vendor/
/gomod2nix-template
result
configs/servers/default/users/*

View File

@ -6,7 +6,7 @@
go run cmd/main.go
```
- Run on nix
- Run on nix (don't work for now)
```shell
nix run git+https://git.foglar.tech/foglar/WhspBrd.git

View File

@ -1,30 +1,12 @@
schema = 3
[mod]
[mod."github.com/getlantern/context"]
version = "v0.0.0-20190109183933-c447772a6520"
hash = "sha256-T4v8t2Hg7lT5d69hD7189WN+dPeMxWXY3vfyiW+oQSM="
[mod."github.com/getlantern/errors"]
version = "v0.0.0-20190325191628-abdb3e3e36f7"
hash = "sha256-AvZvWYUJtOMo7Lk7sZ0BzIougsGltlZ3fAZ6yNjkZs8="
[mod."github.com/getlantern/golog"]
version = "v0.0.0-20190830074920-4ef2e798c2d7"
hash = "sha256-X3o4fSfl+Hb2ZIViUpIg9jpfWjMObrJ53m5E4WFwiLg="
[mod."github.com/getlantern/hex"]
version = "v0.0.0-20190417191902-c6586a6fe0b7"
hash = "sha256-WGOCIMQrXovgp1TGheQv9GOZa/4T5xI2h2gh5Eeqayc="
[mod."github.com/getlantern/hidden"]
version = "v0.0.0-20190325191715-f02dbb02be55"
hash = "sha256-zTYo91NllpZhrWKerxtOdqNkLm7hxpd91POHSAajKT4="
[mod."github.com/getlantern/ops"]
version = "v0.0.0-20190325191751-d70cb0d6f85f"
hash = "sha256-2+oDnDZ1YjJc68ERVV902VAbjmGbFi6rvWtWisFjrlQ="
[mod."github.com/getlantern/systray"]
version = "v1.2.2"
hash = "sha256-GEflgBfashORmopz8kxD7R3GRMKyF7bGE2DXr0w5nX0="
[mod."github.com/go-stack/stack"]
version = "v1.8.0"
hash = "sha256-26RlTEcAkbewMUtmirKrDGQ1WJlNousp69v7HMopYnI="
[mod."github.com/Endg4meZer0/go-mpris"]
version = "v1.0.5"
hash = "sha256-BT5lIuVGPfYCikmVdK8JdTHQorMgALB7a5nScv78GVc="
[mod."github.com/godbus/dbus/v5"]
version = "v5.1.0"
hash = "sha256-xOCMJpQK3KTmHTPn/CdqI4j0eENCtMmJDgAIoYqYOEY="
[mod."github.com/jroimartin/gocui"]
version = "v0.5.0"
hash = "sha256-yNVYFx11d9ITkJKPNoFoGM1gIXnuJBjA4VZJXPh/zZM="
@ -34,9 +16,6 @@ schema = 3
[mod."github.com/nsf/termbox-go"]
version = "v1.1.1"
hash = "sha256-Fxk9s3vKmXO3uWmpneN1iZQ+nCbUEZLWShDyeJcwhvM="
[mod."github.com/oxtoacart/bpool"]
version = "v0.0.0-20190530202638-03653db5a59c"
hash = "sha256-Jaw3QTrj05MwADtv7lSjwMACp8s2Z/ratmxPw0t9LbM="
[mod."golang.org/x/sys"]
version = "v0.30.0"
hash = "sha256-BuhWtwDkciVioc03rxty6G2vcZVnPX85lI7tgQOFVP8="

View File

@ -1,22 +1,28 @@
package tui
import (
"encoding/base64"
"fmt"
"log"
"strings"
"time"
"whspbrd/pkg/cell_size"
//"whspbrd/pkg/clean_image"
"whspbrd/pkg/render_image"
"whspbrd/pkg/clean_image"
"github.com/jroimartin/gocui"
)
var chatData ChatData
var selectedUserIdx int = 0
func layoutChat(g *gocui.Gui, maxX, maxY int) error {
if v, err := g.SetView("chat", 21, 0, maxX-1, maxY-5); err != nil {
if err != gocui.ErrUnknownView {
return err
}
v.Title = "Chat"
v.Title = " Chat "
v.Wrap = true
v.Autoscroll = true
updateChatView(v)
@ -29,7 +35,7 @@ func layoutInput(g *gocui.Gui, maxX, maxY int) error {
if err != gocui.ErrUnknownView {
return err
}
v.Title = "Type your message"
v.Title = " Type your message: "
v.Editable = true
v.Wrap = true
if _, err := g.SetCurrentView("input"); err != nil {
@ -42,12 +48,23 @@ func layoutInput(g *gocui.Gui, maxX, maxY int) error {
func updateChatView(v *gocui.View) {
v.Clear()
clear := cleanimage.NewKittyImageCleaner()
//clear := cleanimage.NewKittyImageCleaner()
// TODO: In future optimize this to only clear certain part of screen
fmt.Print(clear.DeleteAllVisiblePlacements(true))
//fmt.Print(clear.DeleteAllVisiblePlacements(true))
for i, msg := range chatData.Messages {
decoded, err := base64.StdEncoding.DecodeString(msg.Content)
if err != nil {
log.Printf("Error decoding message: %v", err)
continue
}
if strings.HasSuffix(string(decoded), "\n") {
decoded = []byte(strings.TrimSuffix(string(decoded), "\n"))
}
t, _ := time.Parse(time.RFC3339, msg.Timestamp)
formattedTime := t.Format("2006-01-02 15:04")
for i, msg := range messages {
fmt.Fprintf(v, "%s\n\n", msg)
w, h, err := cell_size.GetTerminalCellSizePixels()
if err != nil {
log.Println("Error getting terminal cell size:", err)
@ -60,7 +77,16 @@ func updateChatView(v *gocui.View) {
w = w*3 - (w / 10)
h = 0
}
render_image.RenderImage("./configs/icon.png", i*3+2, 23, w, h, 0)
if !strings.EqualFold(msg.Sender, users[selectedUserIdx]) {
fmt.Fprintf(v, "%s", "\t\t\t\t\t"+Colors.Text(Colors.Base02)+"You ("+formattedTime+"):"+Colors.Reset+"\n\t\t\t\t\t"+string(decoded)+"\n\n")
render_image.RenderImage("./configs/icon.png", i*3+2, 23, w, h, false)
} else {
fmt.Fprintf(v, "%s", "\t\t\t\t\t"+Colors.Text(Colors.Base05)+msg.Sender+" ("+formattedTime+"):"+Colors.Reset+"\n\t\t\t\t\t"+string(decoded)+"\n\n")
icon_path := fmt.Sprintf("./configs/servers/default/users/%s/icon.png", strings.ToLower(msg.Sender))
render_image.RenderImage(icon_path, i*3+2, 23, w, h, false)
}
}
}
@ -72,8 +98,6 @@ func sendMessage(g *gocui.Gui, v *gocui.View) error {
v.SetOrigin(0, 0)
WriteMessage(users[selectedUserIdx], "You", users[selectedUserIdx], input)
messages = []string{}
LoadMessages(users[selectedUserIdx])
updateChatView(g.Views()[1])

View File

@ -15,7 +15,7 @@ func layout(g *gocui.Gui) error {
}
if err := layoutSidebar(g, maxY); err != nil {
updateUsersView(g)
updateContactsView(g)
return err
}
if err := layoutChat(g, maxX, maxY); err != nil {
@ -27,5 +27,3 @@ func layout(g *gocui.Gui) error {
return nil
}

View File

@ -103,31 +103,8 @@ func LoadMessages(username string) {
return
}
var chatData ChatData
if err := json.Unmarshal(data, &chatData); err != nil {
log.Printf("Error parsing JSON: %v", err)
return
}
for _, msg := range chatData.Messages {
decoded, err := base64.StdEncoding.DecodeString(msg.Content)
if err != nil {
log.Printf("Error decoding message: %v", err)
continue
}
if strings.HasSuffix(string(decoded), "\n") {
decoded = []byte(strings.TrimSuffix(string(decoded), "\n"))
}
t, _ := time.Parse(time.RFC3339, msg.Timestamp)
formattedTime := t.Format("2006-01-02 15:04")
// TODO: Move this part to the rendering chat file (./chat.go) and here i should only load all messages and related data to that
// TODO: And in the chat file i should get all data in nice structure and then just select what i need from that
if !strings.EqualFold(msg.Sender, username) {
messages = append(messages, "\t\t\t\t\t"+Colors.Text(Colors.Base02)+"You ("+formattedTime+"):"+Colors.Reset+"\n\t\t\t\t\t"+string(decoded))
} else {
messages = append(messages, "\t\t\t\t\t"+Colors.Text(Colors.Base05)+msg.Sender+" ("+formattedTime+"):\n"+Colors.Reset+"\t\t\t\t\t"+string(decoded))
}
}
}

View File

@ -0,0 +1,32 @@
package tui
import (
"github.com/jroimartin/gocui"
)
func layoutProfile(g *gocui.Gui, maxX, maxY int) error {
var VIEW_WIDTH int
if maxX-maxX/6 < 21 {
VIEW_WIDTH = 30
} else {
VIEW_WIDTH = maxX - maxX/6
}
if v, err := g.SetView("profile", VIEW_WIDTH, 0, maxX-1, maxY-5); err != nil {
if err != gocui.ErrUnknownView {
return err
}
v.Title = " Profile "
v.Wrap = true
//updateProfileView(v)
}
return nil
}
func toggleProfileView(g *gocui.Gui, v *gocui.View) error {
if _, err := g.View("profile"); err != nil {
layoutProfile(g, prevWidth, prevHeight)
} else {
g.DeleteView("profile")
}
return nil
}

View File

@ -1,12 +1,18 @@
package tui
import (
"errors"
"fmt"
"github.com/jroimartin/gocui"
)
//"math"
//"strings"
//"whspbrd/pkg/cell_size"
"whspbrd/pkg/render_image"
//"whspbrd/pkg/resize_image"
var selectedUserIdx int = 0
"github.com/jroimartin/gocui"
//"os"
)
// LAYOUT
func layoutSidebar(g *gocui.Gui, maxY int) error {
@ -14,14 +20,14 @@ func layoutSidebar(g *gocui.Gui, maxY int) error {
if err != gocui.ErrUnknownView {
return err
}
v.Title = "Users"
v.Title = " Users "
v.Clear()
updateUsersView(g)
updateContactsView(g)
}
return nil
}
func updateUsersView(g *gocui.Gui) error {
func updateContactsView(g *gocui.Gui) error {
v, err := g.View("users")
if err != nil {
return err
@ -29,27 +35,34 @@ func updateUsersView(g *gocui.Gui) error {
v.Clear()
messages = nil
// TODO: If no contacts then error, create some add contacts window or hello to WhspBrd
LoadMessages(users[selectedUserIdx])
// TODO: Render profile image of users and change colors of each user maybe?
for i, u := range users {
if len(users) == 0 {
fmt.Fprintln(v, "No Contacts")
return errors.New("no contacts in the list, find some friends")
}
_, maxY := g.Size()
h := min(len(users), (maxY / 2) - 1)
startI := max(0, min(selectedUserIdx - (h / 2), len(users) - h))
fmt.Fprint(v, "\n\n")
for i := startI; i < startI + h; i++ {
u := users[i]
fmt.Fprint(v, "\t\t\t\t")
icon_path := fmt.Sprintf("./configs/servers/default/users/%s/icon.png", u)
render_image.RenderImage(icon_path, 3 + 2 * (i - startI), 2, 30, 30, false)
// Change Selected User In The TUI Window
if i == selectedUserIdx {
fmt.Fprintf(v, "%s%s%s\n", Colors.Background(Colors.Base06), u, Colors.Reset)
_, y := v.Size()
if i == 0 {
v.SetOrigin(0, 0)
} else {
v.SetOrigin(0, i-y+1)
}
fmt.Fprintln(v, "\x1b[7m"+u+"\x1b[0m\n")
} else {
fmt.Fprintln(v, u)
fmt.Fprintln(v, u+"\n")
}
}
return nil
}
@ -59,8 +72,13 @@ func nextContact(g *gocui.Gui, v *gocui.View) error {
if len(users) == 0 {
return nil
}
selectedUserIdx = (selectedUserIdx + 1) % len(users)
err := updateUsersView(g)
selectedUserIdx++
if selectedUserIdx == len(users) {
selectedUserIdx = 0
}
err := updateContactsView(g)
updateChatView(g.Views()[1])
return err
}
@ -69,8 +87,13 @@ func prevContact(g *gocui.Gui, v *gocui.View) error {
if len(users) == 0 {
return nil
}
selectedUserIdx = (selectedUserIdx - 1 + len(users)) % len(users)
err := updateUsersView(g)
selectedUserIdx--
if selectedUserIdx == -1 {
selectedUserIdx = len(users) - 1
}
err := updateContactsView(g)
updateChatView(g.Views()[1])
return err
}

View File

@ -6,7 +6,6 @@ import (
"github.com/jroimartin/gocui"
)
var messages []string
var users []string
var prevWidth, prevHeight int

View File

@ -22,30 +22,30 @@ func LoadImage(filePath string) (image.Image, error) {
return img, err
}
func convertToRGBA(img image.Image) *image.RGBA {
func ConvertToRGBA(img image.Image) *image.RGBA {
rgba := image.NewRGBA(img.Bounds())
draw.Draw(rgba, rgba.Bounds(), img, image.Point{0, 0}, draw.Src)
return rgba
}
func encodeImageToBase64RGBA(rgba *image.RGBA) string {
func EncodeImageToBase64RGBA(rgba *image.RGBA) string {
return base64.StdEncoding.EncodeToString(rgba.Pix)
}
func RenderImage(filepath string, row int, col int, width_ int, height_ int, units int) {
func RenderImage(filepath string, row int, col int, width_ int, height_ int, units bool) {
img, err := LoadImage(filepath)
if err != nil {
fmt.Printf("Error loading image: %v\n", err)
return
}
rgba := convertToRGBA(img)
if units == 1 {
rgba := ConvertToRGBA(img)
if units {
rgba, _ = resize_image.ResizeInTerminal(*rgba, width_, height_)
} else {
rgba, _ = resize_image.Resize(*rgba, width_, height_)
}
encoded := encodeImageToBase64RGBA(rgba)
encoded := EncodeImageToBase64RGBA(rgba)
width := rgba.Rect.Dx()
height := rgba.Rect.Dy()