163 lines
3.9 KiB
Go
163 lines
3.9 KiB
Go
package tui
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"fmt"
|
|
"log"
|
|
"strings"
|
|
"time"
|
|
|
|
"whspbrd/pkg/cell_size"
|
|
"whspbrd/pkg/clean_image"
|
|
"whspbrd/pkg/render_image"
|
|
|
|
"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()
|
|
fmt.Print(clear.DeleteByColumn(chatViewColumn, false))
|
|
|
|
// Reset scroll offset when switching contacts or if out of bounds
|
|
if chatScrollOffset < 0 {
|
|
chatScrollOffset = 0
|
|
}
|
|
if chatScrollOffset > len(chatData.Messages) {
|
|
chatScrollOffset = len(chatData.Messages)
|
|
}
|
|
|
|
// Set view origin based on scroll offset
|
|
ox, _ := v.Origin()
|
|
v.SetOrigin(ox, chatScrollOffset)
|
|
|
|
// Check if we have valid users
|
|
if len(users) == 0 || selectedUserIdx >= len(users) {
|
|
return
|
|
}
|
|
|
|
// Get view dimensions to check if images are visible
|
|
_, viewHeight := v.Size()
|
|
|
|
// Get terminal cell size once for all messages
|
|
w, h, err := cell_size.GetTerminalCellSizePixels()
|
|
if err != nil {
|
|
log.Println("Error getting terminal cell size:", err)
|
|
w, h = 10, 20 // fallback values
|
|
}
|
|
if h > w {
|
|
h = h * 2
|
|
w = 0
|
|
} else {
|
|
w = w*3 - (w / 10)
|
|
h = 0
|
|
}
|
|
|
|
for i, msg := range chatData.Messages {
|
|
decoded, err := base64.StdEncoding.DecodeString(msg.Content)
|
|
if err != nil {
|
|
log.Printf("Error decoding message: %v", err)
|
|
continue
|
|
}
|
|
decoded = []byte(strings.TrimSuffix(string(decoded), "\n"))
|
|
|
|
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")
|
|
|
|
// Determine if this is a message from the user or the contact
|
|
isUserMessage := !strings.EqualFold(msg.Sender, users[selectedUserIdx])
|
|
var senderLabel string
|
|
var iconPath string
|
|
|
|
if isUserMessage {
|
|
senderLabel = Colors.Text(Colors.Base02) + "You (" + formattedTime + "):" + Colors.Reset
|
|
iconPath = userIconPath
|
|
} else {
|
|
senderLabel = Colors.Text(Colors.Base05) + msg.Sender + " (" + formattedTime + "):" + Colors.Reset
|
|
iconPath = fmt.Sprintf(contactIconPathFmt, strings.ToLower(msg.Sender))
|
|
}
|
|
|
|
// Print message text
|
|
fmt.Fprintf(v, "%s", "\t\t\t\t\t"+senderLabel+"\n\t\t\t\t\t"+string(decoded)+"\n\n")
|
|
|
|
// Calculate row position accounting for scroll offset
|
|
// Each message takes 3 lines (messageRowIncrement)
|
|
rowPosition := i*messageRowIncrement + messageRowOffset - chatScrollOffset
|
|
|
|
// Only render images that are visible in the view
|
|
if rowPosition >= 0 && rowPosition < viewHeight {
|
|
render_image.RenderImage(iconPath, rowPosition, chatViewColumn, w, h, false)
|
|
}
|
|
}
|
|
}
|
|
|
|
func sendMessage(g *gocui.Gui, v *gocui.View) error {
|
|
if len(users) == 0 || selectedUserIdx >= len(users) {
|
|
return nil
|
|
}
|
|
|
|
input := v.Buffer()
|
|
v.Clear()
|
|
v.SetCursor(0, 0)
|
|
v.SetOrigin(0, 0)
|
|
|
|
if err := WriteMessage(users[selectedUserIdx], "You", users[selectedUserIdx], input); err != nil {
|
|
log.Printf("Error writing message: %v", err)
|
|
return err
|
|
}
|
|
LoadMessages(users[selectedUserIdx])
|
|
|
|
chatView, err := g.View("chat")
|
|
if err != nil {
|
|
log.Printf("Error getting chat view: %v", err)
|
|
return err
|
|
}
|
|
|
|
// Reset scroll to bottom when sending a new message
|
|
chatScrollOffset = 0
|
|
updateChatView(chatView)
|
|
return nil
|
|
}
|
|
|
|
func scrollChatUp(g *gocui.Gui, v *gocui.View) error {
|
|
chatView, err := g.View("chat")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Scroll up by 1 line
|
|
if chatScrollOffset > 0 {
|
|
chatScrollOffset--
|
|
updateChatView(chatView)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func scrollChatDown(g *gocui.Gui, v *gocui.View) error {
|
|
chatView, err := g.View("chat")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Scroll down by 1 line
|
|
maxScroll := len(chatData.Messages) * messageRowIncrement
|
|
if chatScrollOffset < maxScroll {
|
|
chatScrollOffset++
|
|
updateChatView(chatView)
|
|
}
|
|
return nil
|
|
}
|