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" "runtime" ) func generatePresenceWidget(p stanza.Packet) gtk.Widgetter { presence, ok := p.(stanza.Presence) if !ok { return gtk.NewLabel("Unsupported message.") } if presence.Type == stanza.PresenceTypeUnavailable { var mu MucUser ok := presence.Get(&mu) if ok { if mu.MucUserItem.Affiliation == "outcast" { return gtk.NewLabel(jid.MustParse(presence.From).Resourcepart() + " has been banned!") } } return gtk.NewLabel(jid.MustParse(presence.From).Resourcepart() + " left the room") } else { return gtk.NewLabel(jid.MustParse(presence.From).Resourcepart() + " joined the room") } } func generateMessageWidget(p stanza.Packet) gtk.Widgetter { m, ok := p.(stanza.Message) if !ok { return gtk.NewLabel("Unsupported message.") } fmt.Println(m.Body) readmarker := Marker{} ok = m.Get(&readmarker) if ok { return nil } 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) if m.Type == stanza.MessageTypeGroupchat { mo, _ := mucmembers.Load(jid.MustParse(m.From).Bare().String()) mm := mo.(mucUnit) mmm := mm.Members mmmm, ok := mmm.Load(ocu.ID) if ok { pres := mmmm.(stanza.Presence) var vu VCardUpdate pres.Get(&vu) if vu.Photo != "" { im := getAvatar(m.From, vu.Photo) im.SetPixelSize(40) im.AddCSSClass("author_img") authorBox.Append(im) } else { im := newImageFromPath("debug.png") im.SetPixelSize(40) im.AddCSSClass("author_img") authorBox.Append(im) } } else { im := newImageFromPath("debug.png") 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.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") } if hash == "" { fmt.Println("Hash is 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 == "" || (card.Photo.Type == "image/svg+xml" && runtime.GOOS == "windows") { 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) }