Refactor codebase: fix formatting, error handling, and remove magic numbers
Co-authored-by: foglar <82380203+foglar@users.noreply.github.com>
This commit is contained in:
parent
e98ac69d58
commit
cfedfd3550
1
.gitignore
vendored
1
.gitignore
vendored
@ -3,3 +3,4 @@ vendor/
|
||||
result
|
||||
|
||||
configs/servers/default/users/*
|
||||
main
|
||||
|
||||
@ -2,10 +2,8 @@ package main
|
||||
|
||||
import (
|
||||
"whspbrd/internal/tui"
|
||||
//"whspbrd/pkg/render_image"
|
||||
)
|
||||
|
||||
func main() {
|
||||
//config.NewConfigLoadTemplate()
|
||||
tui.Run()
|
||||
}
|
||||
|
||||
@ -14,12 +14,19 @@ import (
|
||||
"github.com/jroimartin/gocui"
|
||||
)
|
||||
|
||||
const (
|
||||
chatViewColumn = 23
|
||||
userIconPath = "./configs/icon.png"
|
||||
contactIconPathFmt = "./configs/servers/default/users/%s/icon.png"
|
||||
messageRowOffset = 2
|
||||
messageRowIncrement = 3
|
||||
)
|
||||
|
||||
func updateChatView(v *gocui.View) {
|
||||
v.Clear()
|
||||
|
||||
clear := cleanimage.NewKittyImageCleaner()
|
||||
// TODO: In future optimize this to only clear certain part of screen
|
||||
fmt.Print(clear.DeleteByColumn(23, false))
|
||||
fmt.Print(clear.DeleteByColumn(chatViewColumn, false))
|
||||
|
||||
for i, msg := range chatData.Messages {
|
||||
decoded, err := base64.StdEncoding.DecodeString(msg.Content)
|
||||
@ -27,11 +34,13 @@ func updateChatView(v *gocui.View) {
|
||||
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)
|
||||
t, err := time.Parse(time.RFC3339, msg.Timestamp)
|
||||
if err != nil {
|
||||
log.Printf("Error parsing timestamp: %v", err)
|
||||
t = time.Now() // fallback to current time
|
||||
}
|
||||
formattedTime := t.Format("2006-01-02 15:04")
|
||||
|
||||
w, h, err := cell_size.GetTerminalCellSizePixels()
|
||||
@ -46,29 +55,43 @@ func updateChatView(v *gocui.View) {
|
||||
w = w*3 - (w / 10)
|
||||
h = 0
|
||||
}
|
||||
|
||||
if len(users) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
render_image.RenderImage(userIconPath, i*messageRowIncrement+messageRowOffset, chatViewColumn, 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)
|
||||
iconPath := fmt.Sprintf(contactIconPathFmt, strings.ToLower(msg.Sender))
|
||||
render_image.RenderImage(iconPath, i*messageRowIncrement+messageRowOffset, chatViewColumn, w, h, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Rewrite This Code
|
||||
func sendMessage(g *gocui.Gui, v *gocui.View) error {
|
||||
if len(users) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
input := v.Buffer()
|
||||
v.Clear()
|
||||
v.SetCursor(0, 0)
|
||||
v.SetOrigin(0, 0)
|
||||
|
||||
WriteMessage(users[selectedUserIdx], "You", users[selectedUserIdx], input)
|
||||
if err := WriteMessage(users[selectedUserIdx], "You", users[selectedUserIdx], input); err != nil {
|
||||
log.Printf("Error writing message: %v", err)
|
||||
return err
|
||||
}
|
||||
LoadMessages(users[selectedUserIdx])
|
||||
|
||||
updateChatView(g.Views()[1])
|
||||
chatView, err := g.View("chat")
|
||||
if err != nil {
|
||||
log.Printf("Error getting chat view: %v", err)
|
||||
return err
|
||||
}
|
||||
updateChatView(chatView)
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -5,9 +5,6 @@ import (
|
||||
)
|
||||
|
||||
func keybindings(g *gocui.Gui) error {
|
||||
//if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {
|
||||
// return err
|
||||
//}
|
||||
if err := g.SetKeybinding("input", gocui.KeyEnter, gocui.ModNone, sendMessage); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -4,6 +4,12 @@ import (
|
||||
"github.com/jroimartin/gocui"
|
||||
)
|
||||
|
||||
const (
|
||||
sidebarWidth = 20
|
||||
inputHeight = 4
|
||||
chatXOffset = 21
|
||||
)
|
||||
|
||||
func layout(g *gocui.Gui) error {
|
||||
maxX, maxY := g.Size()
|
||||
|
||||
@ -13,17 +19,12 @@ func layout(g *gocui.Gui) error {
|
||||
updateChatView(chatView)
|
||||
}
|
||||
|
||||
//if profileView, err := g.View("profile"); err == nil {
|
||||
// updateProfileView(profileView)
|
||||
//}
|
||||
|
||||
if _, err := g.View("users"); err == nil {
|
||||
updateContactsView(g)
|
||||
}
|
||||
}
|
||||
|
||||
if err := layoutSidebar(g, maxY); err != nil {
|
||||
updateContactsView(g)
|
||||
return err
|
||||
}
|
||||
if err := layoutChat(g, maxX, maxY); err != nil {
|
||||
@ -37,7 +38,7 @@ func layout(g *gocui.Gui) 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", chatXOffset, 0, maxX-1, maxY-inputHeight-1); err != nil {
|
||||
if err != gocui.ErrUnknownView {
|
||||
return err
|
||||
}
|
||||
@ -50,7 +51,7 @@ func layoutChat(g *gocui.Gui, maxX, maxY int) error {
|
||||
}
|
||||
|
||||
func layoutInput(g *gocui.Gui, maxX, maxY int) error {
|
||||
if v, err := g.SetView("input", 21, maxY-4, maxX-1, maxY-1); err != nil {
|
||||
if v, err := g.SetView("input", chatXOffset, maxY-inputHeight, maxX-1, maxY-1); err != nil {
|
||||
if err != gocui.ErrUnknownView {
|
||||
return err
|
||||
}
|
||||
@ -65,7 +66,7 @@ func layoutInput(g *gocui.Gui, maxX, 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, sidebarWidth, maxY-1); err != nil {
|
||||
if err != gocui.ErrUnknownView {
|
||||
return err
|
||||
}
|
||||
@ -77,19 +78,16 @@ func layoutSidebar(g *gocui.Gui, maxY int) error {
|
||||
}
|
||||
|
||||
func layoutProfile(g *gocui.Gui, maxX, maxY int) error {
|
||||
var VIEW_WIDTH int
|
||||
if maxX-maxX/6 < 21 {
|
||||
VIEW_WIDTH = 50
|
||||
} else {
|
||||
VIEW_WIDTH = maxX - maxX/3
|
||||
viewWidth := maxX - maxX/3
|
||||
if viewWidth < chatXOffset {
|
||||
viewWidth = 50
|
||||
}
|
||||
if v, err := g.SetView("profile", VIEW_WIDTH, 0, maxX-1, maxY-5); err != nil {
|
||||
if v, err := g.SetView("profile", viewWidth, 0, maxX-1, maxY-inputHeight-1); err != nil {
|
||||
if err != gocui.ErrUnknownView {
|
||||
return err
|
||||
}
|
||||
v.Title = " Profile "
|
||||
v.Wrap = true
|
||||
//updateProfileView(v)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -12,6 +12,12 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultServerPath = "configs/servers/default"
|
||||
usersSubPath = "users"
|
||||
messagesFileName = "messages.json"
|
||||
)
|
||||
|
||||
type ChatMessage struct {
|
||||
ID string `json:"id"`
|
||||
Sender string `json:"sender"`
|
||||
@ -26,14 +32,13 @@ type ChatData struct {
|
||||
|
||||
func LoadContacts(path string) {
|
||||
users = nil
|
||||
contactsPath := filepath.Join(path, "users")
|
||||
contactsPath := filepath.Join(path, usersSubPath)
|
||||
folders, err := os.ReadDir(contactsPath)
|
||||
if err != nil {
|
||||
log.Printf("Error reading contacts directory: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: Instead of just using list create some more complex structure so i can load details about the user in it
|
||||
for _, folder := range folders {
|
||||
if folder.IsDir() {
|
||||
users = append(users, folder.Name())
|
||||
@ -42,11 +47,14 @@ func LoadContacts(path string) {
|
||||
}
|
||||
|
||||
func WriteMessage(username, sender, receiver, content string) error {
|
||||
chatFile := filepath.Join("configs", "servers", "default", "users", strings.ToLower(username), "messages.json")
|
||||
chatFile := filepath.Join(defaultServerPath, usersSubPath, strings.ToLower(username), messagesFileName)
|
||||
|
||||
if _, err := os.Stat(chatFile); os.IsNotExist(err) {
|
||||
emptyData := ChatData{Messages: []ChatMessage{}}
|
||||
data, _ := json.MarshalIndent(emptyData, "", " ")
|
||||
data, err := json.MarshalIndent(emptyData, "", " ")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal empty chat data: %v", err)
|
||||
}
|
||||
if err := os.WriteFile(chatFile, data, 0644); err != nil {
|
||||
return fmt.Errorf("failed to create chat file: %v", err)
|
||||
}
|
||||
@ -96,7 +104,7 @@ func WriteMessage(username, sender, receiver, content string) error {
|
||||
}
|
||||
|
||||
func LoadMessages(username string) {
|
||||
chatFile := filepath.Join("configs", "servers", "default", "users", strings.ToLower(username), "messages.json")
|
||||
chatFile := filepath.Join(defaultServerPath, usersSubPath, strings.ToLower(username), messagesFileName)
|
||||
data, err := os.ReadFile(chatFile)
|
||||
if err != nil {
|
||||
log.Printf("Error reading chat file: %v", err)
|
||||
|
||||
@ -3,16 +3,19 @@ package tui
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
//"math"
|
||||
//"strings"
|
||||
//"whspbrd/pkg/cell_size"
|
||||
"whspbrd/pkg/clean_image"
|
||||
"whspbrd/pkg/render_image"
|
||||
//"whspbrd/pkg/resize_image"
|
||||
|
||||
"github.com/jroimartin/gocui"
|
||||
//"os"
|
||||
)
|
||||
|
||||
const (
|
||||
sidebarIconColumn = 2
|
||||
sidebarIconSize = 30
|
||||
sidebarRowOffset = 3
|
||||
sidebarRowSpacing = 2
|
||||
)
|
||||
|
||||
func updateContactsView(g *gocui.Gui) error {
|
||||
@ -23,17 +26,15 @@ func updateContactsView(g *gocui.Gui) error {
|
||||
|
||||
v.Clear()
|
||||
clear := cleanimage.NewKittyImageCleaner()
|
||||
fmt.Print(clear.DeleteByColumn(2, false))
|
||||
fmt.Print(clear.DeleteByColumn(sidebarIconColumn, false))
|
||||
|
||||
// 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?
|
||||
if len(users) == 0 {
|
||||
fmt.Fprintln(v, "No Contacts")
|
||||
return errors.New("no contacts in the list, find some friends")
|
||||
}
|
||||
|
||||
LoadMessages(users[selectedUserIdx])
|
||||
|
||||
_, maxY := g.Size()
|
||||
h := min(len(users), (maxY/2)-1)
|
||||
startI := max(0, min(selectedUserIdx-(h/2), len(users)-h))
|
||||
@ -44,20 +45,18 @@ func updateContactsView(g *gocui.Gui) error {
|
||||
|
||||
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)
|
||||
iconPath := fmt.Sprintf(contactIconPathFmt, u)
|
||||
render_image.RenderImage(iconPath, sidebarRowOffset+sidebarRowSpacing*(i-startI), sidebarIconColumn, sidebarIconSize, sidebarIconSize, false)
|
||||
|
||||
if i == selectedUserIdx {
|
||||
fmt.Fprintln(v, "\x1b[7m"+u+"\x1b[0m\n")
|
||||
} else {
|
||||
fmt.Fprintln(v, u+"\n")
|
||||
}
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// KEYBINDINGS
|
||||
func nextContact(g *gocui.Gui, v *gocui.View) error {
|
||||
if len(users) == 0 {
|
||||
return nil
|
||||
@ -67,10 +66,17 @@ func nextContact(g *gocui.Gui, v *gocui.View) error {
|
||||
selectedUserIdx = 0
|
||||
}
|
||||
|
||||
err := updateContactsView(g)
|
||||
|
||||
updateChatView(g.Views()[1])
|
||||
if err := updateContactsView(g); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
chatView, err := g.View("chat")
|
||||
if err != nil {
|
||||
log.Printf("Error getting chat view: %v", err)
|
||||
return err
|
||||
}
|
||||
updateChatView(chatView)
|
||||
return nil
|
||||
}
|
||||
|
||||
func prevContact(g *gocui.Gui, v *gocui.View) error {
|
||||
@ -82,8 +88,15 @@ func prevContact(g *gocui.Gui, v *gocui.View) error {
|
||||
selectedUserIdx = len(users) - 1
|
||||
}
|
||||
|
||||
err := updateContactsView(g)
|
||||
|
||||
updateChatView(g.Views()[1])
|
||||
if err := updateContactsView(g); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
chatView, err := g.View("chat")
|
||||
if err != nil {
|
||||
log.Printf("Error getting chat view: %v", err)
|
||||
return err
|
||||
}
|
||||
updateChatView(chatView)
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -12,8 +12,7 @@ var chatData ChatData
|
||||
var selectedUserIdx int = 0
|
||||
|
||||
func Run() {
|
||||
|
||||
LoadContacts("configs/servers/default")
|
||||
LoadContacts(defaultServerPath)
|
||||
|
||||
g, err := gocui.NewGui(gocui.OutputNormal)
|
||||
if err != nil {
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
//+build linux darwin
|
||||
//go:build linux || darwin
|
||||
// +build linux darwin
|
||||
|
||||
// File generated by 2goarray (http://github.com/cratonica/2goarray)
|
||||
|
||||
package icon
|
||||
|
||||
var Data []byte = []byte {
|
||||
var Data []byte = []byte{
|
||||
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d,
|
||||
0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20,
|
||||
0x08, 0x06, 0x00, 0x00, 0x00, 0x73, 0x7a, 0x7a, 0xf4, 0x00, 0x00, 0x00,
|
||||
@ -193,4 +194,3 @@ var Data []byte = []byte {
|
||||
0xdd, 0x63, 0x24, 0x57, 0x80, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45,
|
||||
0x4e, 0x44, 0xae, 0x42, 0x60, 0x82,
|
||||
}
|
||||
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
//+build windows
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
// File generated by 2goarray v0.1.0 (http://github.com/cratonica/2goarray)
|
||||
|
||||
|
||||
@ -32,7 +32,7 @@ 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 bool) {
|
||||
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)
|
||||
@ -41,35 +41,35 @@ func RenderImage(filepath string, row int, col int, width_ int, height_ int, uni
|
||||
|
||||
rgba := ConvertToRGBA(img)
|
||||
if units {
|
||||
rgba, _ = resize_image.ResizeInTerminal(*rgba, width_, height_)
|
||||
rgba, _ = resize_image.ResizeInTerminal(*rgba, width, height)
|
||||
} else {
|
||||
rgba, _ = resize_image.Resize(*rgba, width_, height_)
|
||||
rgba, _ = resize_image.Resize(*rgba, width, height)
|
||||
}
|
||||
encoded := EncodeImageToBase64RGBA(rgba)
|
||||
|
||||
width := rgba.Rect.Dx()
|
||||
height := rgba.Rect.Dy()
|
||||
imgWidth := rgba.Rect.Dx()
|
||||
imgHeight := rgba.Rect.Dy()
|
||||
|
||||
fmt.Printf("\033[s\033[%d;%dH", row, col)
|
||||
|
||||
chunk_size := 4096
|
||||
chunkSize := 4096
|
||||
pos := 0
|
||||
first := true
|
||||
for pos < len(encoded) {
|
||||
fmt.Print("\033_G")
|
||||
if first {
|
||||
fmt.Printf("q=2,a=T,f=32,s=%d,v=%d,", width, height)
|
||||
fmt.Printf("q=2,a=T,f=32,s=%d,v=%d,", imgWidth, imgHeight)
|
||||
first = false
|
||||
}
|
||||
chunk_len := len(encoded) - pos
|
||||
if chunk_len > chunk_size {
|
||||
chunk_len = chunk_size
|
||||
chunkLen := len(encoded) - pos
|
||||
if chunkLen > chunkSize {
|
||||
chunkLen = chunkSize
|
||||
}
|
||||
if pos+chunk_len < len(encoded) {
|
||||
if pos+chunkLen < len(encoded) {
|
||||
fmt.Print("m=1")
|
||||
}
|
||||
fmt.Printf(";%s\033\\", encoded[pos:pos+chunk_len])
|
||||
pos += chunk_len
|
||||
fmt.Printf(";%s\033\\", encoded[pos:pos+chunkLen])
|
||||
pos += chunkLen
|
||||
}
|
||||
fmt.Print("\033[u")
|
||||
}
|
||||
|
||||
@ -43,7 +43,7 @@ func RenderImage(filepath string, row int, col int) {
|
||||
|
||||
fmt.Printf("\033[s\033[%d;%dH", row, col)
|
||||
|
||||
chunk_size := 4096
|
||||
chunkSize := 4096
|
||||
pos := 0
|
||||
first := true
|
||||
for pos < len(encoded) {
|
||||
@ -52,15 +52,15 @@ func RenderImage(filepath string, row int, col int) {
|
||||
fmt.Printf("q=2,a=T,f=32,s=%d,v=%d,", width, height)
|
||||
first = false
|
||||
}
|
||||
chunk_len := len(encoded) - pos
|
||||
if chunk_len > chunk_size {
|
||||
chunk_len = chunk_size
|
||||
chunkLen := len(encoded) - pos
|
||||
if chunkLen > chunkSize {
|
||||
chunkLen = chunkSize
|
||||
}
|
||||
if pos+chunk_len < len(encoded) {
|
||||
if pos+chunkLen < len(encoded) {
|
||||
fmt.Print("m=1")
|
||||
}
|
||||
fmt.Printf(";%s\033\\", encoded[pos:pos+chunk_len])
|
||||
pos += chunk_len
|
||||
fmt.Printf(";%s\033\\", encoded[pos:pos+chunkLen])
|
||||
pos += chunkLen
|
||||
}
|
||||
fmt.Print("\033[u")
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user