package main // This file contains the function that generates message widgets depending on message stanza import ( "context" "encoding/base64" "fmt" "github.com/diamondburned/gotk4/pkg/gtk/v4" "github.com/google/uuid" "github.com/jacoblockett/sanitizefilename" "github.com/jasonlovesdoggo/gopen" "gosrc.io/xmpp/stanza" "mellium.im/xmpp/jid" "os" "path/filepath" ) func generateMessageWidget(p stanza.Packet) gtk.Widgetter { m, ok := p.(stanza.Message) if !ok { return gtk.NewLabel("Unsupported message.") } sid := StanzaID{} m.Get(&sid) mainBox := gtk.NewBox(gtk.OrientationVertical, 0) gesture := gtk.NewGestureClick() gesture.SetButton(3) // Right click vis := false reactions := gtk.NewBox(gtk.OrientationHorizontal, 0) reactions.SetVisible(false) reaction := []string{"👍", "👎", "♥️", "🤣", "😭"} for _, v := range reaction { like := gtk.NewButton() like.SetLabel(v) like.SetHExpand(true) like.ConnectClicked(func() { fmt.Println("licked") client.SendRaw(fmt.Sprintf(` %s `, m.To, jid.MustParse(m.From).Bare().String(), uuid.New().String(), m.Type, sid.ID, v)) }) reactions.Append(like) } gesture.Connect("pressed", func(n_press, x, y int) { if !vis { vis = true reactions.SetVisible(true) } else { vis = false reactions.SetVisible(false) } }) mainBox.AddController(gesture) reply := Reply{} ok = m.Get(&reply) if ok { replyBox := gtk.NewBox(gtk.OrientationHorizontal, 0) replyBox.Append(gtk.NewLabel("↱ " + jid.MustParse(reply.To).Resourcepart())) mainBox.Append(replyBox) } ocu := OccupantID{} m.Get(&ocu) authorBox := gtk.NewBox(gtk.OrientationHorizontal, 10) contentBox := gtk.NewBox(gtk.OrientationHorizontal, 0) // im := newImageFromPath("debug.png") // authorBox.Append(im) im := getAvatar(m.From, ocu.ID) im.SetPixelSize(40) im.AddCSSClass("author_img") authorBox.Append(im) al := gtk.NewLabel(jid.MustParse(m.From).Resourcepart()) al.AddCSSClass("author") authorBox.Append(al) mlabel := gtk.NewLabel(m.Body) // mlabel.SetMarkup(convertXEPToPango(m.Body)) mlabel.SetWrap(true) mlabel.SetSelectable(true) mlabel.SetHAlign(gtk.AlignFill) contentBox.Append(mlabel) mainBox.Append(authorBox) mainBox.Append(contentBox) mainBox.Append(reactions) oob := stanza.OOB{} ok = m.Get(&oob) if ok { // media := newPictureFromWeb(oob.URL) // media.SetCanShrink(false) // mainBox.Append(media) // media.AddCSSClass("chat_image") mbtn := gtk.NewButtonWithLabel("🖼️") // mbtn.SetChild(newImageFromWeb(oob.URL)) mbtn.ConnectClicked(func() { gopen.Open(oob.URL) }) authorBox.Append(mbtn) } return mainBox } func getVAdjustment(scrolledWindow *gtk.ScrolledWindow) *gtk.Adjustment { val := scrolledWindow.ObjectProperty("vadjustment").(*gtk.Adjustment) return val } func getAvatar(j, hash string) *gtk.Image { // TODO: This function probably shouldn't be here, and should probably be in xmpp-helpers or somewhere similar. p, err := ensureCache() if err != nil { return newImageFromPath("debug.png") } hash = filepath.Join(p, sanitizefilename.Sanitize(hash)) _, err = os.ReadFile(hash) if err == nil { return newImageFromPath(hash) } iqResp, err := stanza.NewIQ(stanza.Attrs{ Type: "get", From: clientroot.Session.BindJid, To: j, Id: "vc2", Lang: "en", }) if err != nil { panic(err) } iqResp.Payload = &VCard{} ctx := context.TODO() mychan, err := client.SendIQ(ctx, iqResp) if err != nil { panic(err) } result := <-mychan card, ok := result.Payload.(*VCard) if !ok { return newImageFromPath("debug.png") } base64_data := card.Photo.Binval if card.Photo.Binval == "" { return newImageFromPath("debug.png") } data, err := base64.StdEncoding.DecodeString(base64_data) if err != nil { panic(err) } err = os.WriteFile(hash, data, 0644) if err != nil { panic(err) } return newImageFromPath(hash) }