Compare commits

..

No commits in common. "56827fa47003812c8b830c167ae714fe82ec19e9" and "8046177af0820e4a34dc55363ddd4571ca60c950" have entirely different histories.

10 changed files with 93 additions and 133 deletions

2
.gitignore vendored
View File

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

View File

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

View File

@ -1,12 +1,30 @@
schema = 3 schema = 3
[mod] [mod]
[mod."github.com/Endg4meZer0/go-mpris"] [mod."github.com/getlantern/context"]
version = "v1.0.5" version = "v0.0.0-20190109183933-c447772a6520"
hash = "sha256-BT5lIuVGPfYCikmVdK8JdTHQorMgALB7a5nScv78GVc=" hash = "sha256-T4v8t2Hg7lT5d69hD7189WN+dPeMxWXY3vfyiW+oQSM="
[mod."github.com/godbus/dbus/v5"] [mod."github.com/getlantern/errors"]
version = "v5.1.0" version = "v0.0.0-20190325191628-abdb3e3e36f7"
hash = "sha256-xOCMJpQK3KTmHTPn/CdqI4j0eENCtMmJDgAIoYqYOEY=" 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/jroimartin/gocui"] [mod."github.com/jroimartin/gocui"]
version = "v0.5.0" version = "v0.5.0"
hash = "sha256-yNVYFx11d9ITkJKPNoFoGM1gIXnuJBjA4VZJXPh/zZM=" hash = "sha256-yNVYFx11d9ITkJKPNoFoGM1gIXnuJBjA4VZJXPh/zZM="
@ -16,6 +34,9 @@ schema = 3
[mod."github.com/nsf/termbox-go"] [mod."github.com/nsf/termbox-go"]
version = "v1.1.1" version = "v1.1.1"
hash = "sha256-Fxk9s3vKmXO3uWmpneN1iZQ+nCbUEZLWShDyeJcwhvM=" hash = "sha256-Fxk9s3vKmXO3uWmpneN1iZQ+nCbUEZLWShDyeJcwhvM="
[mod."github.com/oxtoacart/bpool"]
version = "v0.0.0-20190530202638-03653db5a59c"
hash = "sha256-Jaw3QTrj05MwADtv7lSjwMACp8s2Z/ratmxPw0t9LbM="
[mod."golang.org/x/sys"] [mod."golang.org/x/sys"]
version = "v0.30.0" version = "v0.30.0"
hash = "sha256-BuhWtwDkciVioc03rxty6G2vcZVnPX85lI7tgQOFVP8=" hash = "sha256-BuhWtwDkciVioc03rxty6G2vcZVnPX85lI7tgQOFVP8="

View File

@ -1,22 +1,16 @@
package tui package tui
import ( import (
"encoding/base64"
"fmt" "fmt"
"log" "log"
"strings"
"time"
"whspbrd/pkg/cell_size" "whspbrd/pkg/cell_size"
"whspbrd/pkg/clean_image"
"whspbrd/pkg/render_image" "whspbrd/pkg/render_image"
"whspbrd/pkg/clean_image"
"github.com/jroimartin/gocui" "github.com/jroimartin/gocui"
) )
var chatData ChatData
var selectedUserIdx int = 0
func layoutChat(g *gocui.Gui, maxX, maxY int) error { func layoutChat(g *gocui.Gui, maxX, maxY int) error {
if v, err := g.SetView("chat", 21, 0, maxX-1, maxY-5); err != nil { if v, err := g.SetView("chat", 21, 0, maxX-1, maxY-5); err != nil {
if err != gocui.ErrUnknownView { if err != gocui.ErrUnknownView {
@ -35,7 +29,7 @@ func layoutInput(g *gocui.Gui, maxX, maxY int) error {
if err != gocui.ErrUnknownView { if err != gocui.ErrUnknownView {
return err return err
} }
v.Title = " Type your message: " v.Title = "Type your message"
v.Editable = true v.Editable = true
v.Wrap = true v.Wrap = true
if _, err := g.SetCurrentView("input"); err != nil { if _, err := g.SetCurrentView("input"); err != nil {
@ -50,21 +44,10 @@ func updateChatView(v *gocui.View) {
clear := cleanimage.NewKittyImageCleaner() clear := cleanimage.NewKittyImageCleaner()
// TODO: In future optimize this to only clear certain part of screen // TODO: In future optimize this to only clear certain part of screen
fmt.Print(clear.DeleteByColumn(23, false)) 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() w, h, err := cell_size.GetTerminalCellSizePixels()
if err != nil { if err != nil {
log.Println("Error getting terminal cell size:", err) log.Println("Error getting terminal cell size:", err)
@ -77,16 +60,7 @@ func updateChatView(v *gocui.View) {
w = w*3 - (w / 10) w = w*3 - (w / 10)
h = 0 h = 0
} }
if !strings.EqualFold(msg.Sender, users[selectedUserIdx]) { render_image.RenderImage("./configs/icon.png", i*3+2, 23, w, h, 0)
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)
}
} }
} }
@ -98,6 +72,8 @@ func sendMessage(g *gocui.Gui, v *gocui.View) error {
v.SetOrigin(0, 0) v.SetOrigin(0, 0)
WriteMessage(users[selectedUserIdx], "You", users[selectedUserIdx], input) WriteMessage(users[selectedUserIdx], "You", users[selectedUserIdx], input)
messages = []string{}
LoadMessages(users[selectedUserIdx]) LoadMessages(users[selectedUserIdx])
updateChatView(g.Views()[1]) updateChatView(g.Views()[1])

View File

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

View File

@ -103,8 +103,31 @@ func LoadMessages(username string) {
return return
} }
var chatData ChatData
if err := json.Unmarshal(data, &chatData); err != nil { if err := json.Unmarshal(data, &chatData); err != nil {
log.Printf("Error parsing JSON: %v", err) log.Printf("Error parsing JSON: %v", err)
return 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

@ -1,32 +0,0 @@
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,20 +1,13 @@
package tui package tui
import ( import (
"errors"
"fmt" "fmt"
//"math"
//"strings"
//"whspbrd/pkg/cell_size"
"whspbrd/pkg/clean_image"
"whspbrd/pkg/render_image"
//"whspbrd/pkg/resize_image"
"github.com/jroimartin/gocui" "github.com/jroimartin/gocui"
//"os"
) )
var selectedUserIdx int = 0
// LAYOUT // LAYOUT
func layoutSidebar(g *gocui.Gui, maxY int) error { func layoutSidebar(g *gocui.Gui, maxY int) error {
if v, err := g.SetView("users", 0, 0, 20, maxY-1); err != nil { if v, err := g.SetView("users", 0, 0, 20, maxY-1); err != nil {
@ -23,49 +16,40 @@ func layoutSidebar(g *gocui.Gui, maxY int) error {
} }
v.Title = "Users" v.Title = "Users"
v.Clear() v.Clear()
updateContactsView(g) updateUsersView(g)
} }
return nil return nil
} }
func updateContactsView(g *gocui.Gui) error { func updateUsersView(g *gocui.Gui) error {
v, err := g.View("users") v, err := g.View("users")
if err != nil { if err != nil {
return err return err
} }
v.Clear() v.Clear()
clear := cleanimage.NewKittyImageCleaner()
fmt.Print(clear.DeleteByColumn(2, false)) messages = nil
// TODO: If no contacts then error, create some add contacts window or hello to WhspBrd // TODO: If no contacts then error, create some add contacts window or hello to WhspBrd
LoadMessages(users[selectedUserIdx]) LoadMessages(users[selectedUserIdx])
// TODO: Render profile image of users and change colors of each user maybe? // TODO: Render profile image of users and change colors of each user maybe?
if len(users) == 0 { for i, u := range users {
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 { if i == selectedUserIdx {
fmt.Fprintln(v, "\x1b[7m"+u+"\x1b[0m\n") 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 { } else {
fmt.Fprintln(v, u+"\n") v.SetOrigin(0, i-y+1)
} }
} else {
fmt.Fprintln(v, u)
}
} }
return nil return nil
} }
@ -75,13 +59,8 @@ func nextContact(g *gocui.Gui, v *gocui.View) error {
if len(users) == 0 { if len(users) == 0 {
return nil return nil
} }
selectedUserIdx++ selectedUserIdx = (selectedUserIdx + 1) % len(users)
if selectedUserIdx == len(users) { err := updateUsersView(g)
selectedUserIdx = 0
}
err := updateContactsView(g)
updateChatView(g.Views()[1]) updateChatView(g.Views()[1])
return err return err
} }
@ -90,13 +69,8 @@ func prevContact(g *gocui.Gui, v *gocui.View) error {
if len(users) == 0 { if len(users) == 0 {
return nil return nil
} }
selectedUserIdx-- selectedUserIdx = (selectedUserIdx - 1 + len(users)) % len(users)
if selectedUserIdx == -1 { err := updateUsersView(g)
selectedUserIdx = len(users) - 1
}
err := updateContactsView(g)
updateChatView(g.Views()[1]) updateChatView(g.Views()[1])
return err return err
} }

View File

@ -6,13 +6,11 @@ import (
"github.com/jroimartin/gocui" "github.com/jroimartin/gocui"
) )
var messages []string
var users []string var users []string
var prevWidth, prevHeight int var prevWidth, prevHeight int
func Run() { func Run() {
LoadContacts("configs/servers/default") LoadContacts("configs/servers/default")
g, err := gocui.NewGui(gocui.OutputNormal) g, err := gocui.NewGui(gocui.OutputNormal)

View File

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