From 39cdd5e6c11777904f38d70ec5308b83ca240dc3 Mon Sep 17 00:00:00 2001 From: sunglocto Date: Sat, 9 May 2026 07:33:47 +0100 Subject: [PATCH] format + allow closing --- assets.go | 1 - gtk-helpers.go | 35 +++++++++++++++++++++++++++--- gtk-message.go | 59 ++++++++++++++++++++++++-------------------------- main.go | 44 ++++++++++++++++++++++++++++++++----- types.go | 27 ++++++++++++----------- 5 files changed, 112 insertions(+), 54 deletions(-) diff --git a/assets.go b/assets.go index 5ed90c0..7752b07 100644 --- a/assets.go +++ b/assets.go @@ -140,7 +140,6 @@ var moderateBytes []byte //go:embed assets/jabber.png var jabberBytes []byte - //go:embed assets/fail.png var failBytes []byte diff --git a/gtk-helpers.go b/gtk-helpers.go index 505071b..9902fe7 100644 --- a/gtk-helpers.go +++ b/gtk-helpers.go @@ -14,9 +14,9 @@ import ( "github.com/rrivera/identicon" "gosrc.io/xmpp/stanza" "image" + "image/color" "image/png" xmpp_color "mellium.im/xmpp/color" - "image/color" "strconv" ) @@ -54,6 +54,34 @@ func createTab(jid string, isMuc bool, name string) bool { return false } +func removeTab(jid string, w *gtk.Window) { + t, ok := tabs.Load(jid) + if ok { + tab := t.(*chatTab) + tab.msgs.RemoveAll() + if tab.isMuc { + client.SendRaw(fmt.Sprintf(` + + + + `, clientroot.Session.BindJid, jid+"/"+tab.current_nick)) + } + + tabs.Delete(jid) + mucmembers.Delete(jid) + userdevices.Delete(jid) + + if current == jid { + current = "" + scroller.SetChild(empty_dialog) + typingStatus.SetText("") + memberList.SetChild(gtk.NewLabel("")) + } + + mucmembers.Delete(jid) + } +} + func switchToTab(jid string, w *gtk.Window) { current = jid tab, ok := tabs.Load(current) @@ -160,7 +188,6 @@ func switchToTab(jid string, w *gtk.Window) { } } - status := gtk.NewImageFromPaintable(clientAssets["status_"+string(u.Show)]) status.SetTooltipText(string(u.Show)) @@ -521,6 +548,7 @@ func switchToTab(jid string, w *gtk.Window) { gen.Prepend(muci) muc_name := gtk.NewLabel(typed_tab.name) muc_name.AddCSSClass("author") + muc_name.SetWrap(true) gen.Prepend(muc_name) memberList.SetChild(gen) } else { @@ -529,7 +557,7 @@ func switchToTab(jid string, w *gtk.Window) { } -func showErrorDialog(err error) { +func showErrorDialog(err error, w *gtk.Window) { err_win := gtk.NewWindow() err_win.SetTitle(loadedLocale["error"]) err_win.SetDefaultSize(400, 200) @@ -546,6 +574,7 @@ func showErrorDialog(err error) { }) box.Append(close_btn) err_win.SetChild(box) + err_win.SetTransientFor(w) err_win.Present() } diff --git a/gtk-message.go b/gtk-message.go index 7b0dcb0..d01a36a 100644 --- a/gtk-message.go +++ b/gtk-message.go @@ -92,46 +92,45 @@ func generateMessageWidget(p stanza.Packet) gtk.Widgetter { popover.SetParent(mainBox) popover.SetHasArrow(false) - gesture.Connect("pressed", func(n_press, x, y int) { - rc_box := gtk.NewBox(gtk.OrientationVertical, 0) + rc_box := gtk.NewBox(gtk.OrientationVertical, 0) - reactions := gtk.NewBox(gtk.OrientationHorizontal, 0) - reaction := []string{"👍", "👎", "♥️", "🤣", "💀"} - for _, v := range reaction { - like := gtk.NewButton() - like.SetLabel(v) - like.SetHExpand(true) - like.ConnectClicked(func() { - fmt.Println("licked") // TODO: Implement proper support for reactions via extension - client.SendRaw(fmt.Sprintf(` + reactions := gtk.NewBox(gtk.OrientationHorizontal, 0) + reaction := []string{"👍", "👎", "♥️", "🤣", "💀"} + for _, v := range reaction { + like := gtk.NewButton() + like.SetLabel(v) + like.SetHExpand(true) + like.ConnectClicked(func() { + fmt.Println("licked") // TODO: Implement proper support for reactions via extension + client.SendRaw(fmt.Sprintf(` %s `, m.To, jid.MustParse(m.From).Bare().String(), uuid.New().String(), m.Type, sid.ID, v)) - }) - reactions.Append(like) - } - - rc_box.Append(reactions) - - quote := gtk.NewButtonWithLabel("Quote") - quote.ConnectClicked(func() { - lines := strings.Split(m.Body, "\n") - for i, line := range lines { - quoteline := "> " + line - lines[i] = quoteline + }) + reactions.Append(like) } - newstr := strings.Join(lines, "\n") + "\n\n" + rc_box.Append(reactions) - message_en.SetText(newstr) - }) - rc_box.Append(quote) + quote := gtk.NewButtonWithLabel("Quote") + quote.ConnectClicked(func() { + lines := strings.Split(m.Body, "\n") + for i, line := range lines { + quoteline := "> " + line + lines[i] = quoteline + } - popover.SetChild(rc_box) + newstr := strings.Join(lines, "\n") + "\n\n" + + message_en.SetText(newstr) + }) + rc_box.Append(quote) + + popover.SetChild(rc_box) rect := gdk.NewRectangle(x, y, 1, 1) popover.SetPointingTo(&rect) popover.Popup() @@ -233,7 +232,6 @@ func generateMessageWidget(p stanza.Packet) gtk.Widgetter { mainBox.Append(authorBox) mainBox.Append(contentBox) - oob := stanza.OOB{} ok = m.Get(&oob) if ok { @@ -315,7 +313,7 @@ func getAvatar(j, hash string) *gtk.Image { // TODO: This function probably shou invalidImages.Store(oghash, true) return createIdenticon(j, false) } - i.AddCSSClass(loadedConfig.CVD.String() + "_CVD") + // i.AddCSSClass(loadedConfig.CVD.String() + "_CVD") return i } @@ -346,7 +344,6 @@ func getAvatar(j, hash string) *gtk.Image { // TODO: This function probably shou base64_data := card.Photo.Binval if card.Photo.Binval == "" || ((card.Photo.Type == "image/svg+xml" || card.Photo.Type == "image/webp") && (runtime.GOOS == "windows" || runtime.GOOS == "netbsd")) { - fmt.Println("Blocking image") invalidImages.Store(oghash, true) return createIdenticon(j, false) } diff --git a/main.go b/main.go index 842b879..7c1dddf 100644 --- a/main.go +++ b/main.go @@ -325,6 +325,7 @@ func main() { ok = presence.Get(&mu) if ok { // This is a presence stanza from a user in a MUC + presence.Get(&ocu) // id := ocu.ID // if id == "" { @@ -333,7 +334,7 @@ func main() { from, _ := stanza.NewJid(presence.From) muc := from.Bare() _, ok = mucmembers.Load(muc) - if !ok { + if !ok && presence.Type != "unavailable" { mucmembers.Store(muc, mucUnit{}) } @@ -344,6 +345,14 @@ func main() { typed_unit := unit.(mucUnit) + if mu.MucUserItem.JID == clientroot.Session.BindJid { + tab, ok := tabs.Load(muc) + if ok { + typed_tab := tab.(*chatTab) + typed_tab.current_nick = id + } + } + if presence.Type != "unavailable" { _, ok := typed_unit.Members.Load(id) if !ok && loadedConfig.ShowPresenceUpdates { @@ -408,7 +417,7 @@ func main() { }) if err != nil { - showErrorDialog(err) + showErrorDialog(err, &window.Window) panic(err) } client = c @@ -524,6 +533,13 @@ func main() { gesture1.Connect("pressed", func() { switchToTab(jid, &window.Window) }) + gesture2 := gtk.NewGestureClick() + gesture2.SetButton(3) + gesture2.Connect("pressed", func() { + removeTab(jid, &window.Window) + box.SetVisible(false) + }) + box.Append(b) go func() { new_im := getAvatar(jid, jid) // TODO: Use PEP avatar and do not use JID as hash @@ -604,6 +620,13 @@ func main() { gesture1.Connect("pressed", func() { switchToTab(jid, &window.Window) }) + + gesture2 := gtk.NewGestureClick() + gesture2.SetButton(3) + gesture2.Connect("pressed", func() { + removeTab(jid, &window.Window) + box.SetVisible(false) + }) box.Append(b) go func() { new_im := getAvatar(jid, jid) @@ -614,6 +637,7 @@ func main() { }() box.AddController(gesture1) + box.AddController(gesture2) menu.Append(box) menu.Append(gtk.NewSeparator(gtk.OrientationHorizontal)) }) @@ -840,7 +864,7 @@ func activate(app *gtk.Application) { jm := func(n string, pw string) { err := joinMuc(client, clientroot.Session.BindJid, t, nick_entry.Text(), pw) if err != nil { - showErrorDialog(err) + showErrorDialog(err, win) return } @@ -861,7 +885,15 @@ func activate(app *gtk.Application) { switchToTab(t, &window.Window) }) + gesture2 := gtk.NewGestureClick() + gesture2.SetButton(3) + gesture2.Connect("pressed", func() { + removeTab(t, &window.Window) + box.SetVisible(false) + }) + box.AddController(gesture1) + box.AddController(gesture2) menu.Append(box) menu.Append(gtk.NewSeparator(gtk.OrientationHorizontal)) } @@ -999,9 +1031,9 @@ func activate(app *gtk.Application) { } else { allowed = false if result.Error != nil { - showErrorDialog(fmt.Errorf("%s: %s - %s", loadedLocale["discoFail"], result.Error.Reason, result.Error.Text)) + showErrorDialog(fmt.Errorf("%s: %s - %s", loadedLocale["discoFail"], result.Error.Reason, result.Error.Text), win) } else { - showErrorDialog(fmt.Errorf(loadedLocale["discoFail"])) + showErrorDialog(fmt.Errorf(loadedLocale["discoFail"]), win) } } } @@ -1227,7 +1259,7 @@ func activate(app *gtk.Application) { err := sendMessage(client, current, message_type, t, "", "", exts) if err != nil { - showErrorDialog(err) + showErrorDialog(err, &window.Window) } message_en.SetText("") scrollToBottomAfterUpdate(scroller) diff --git a/types.go b/types.go index 521232c..290b03f 100644 --- a/types.go +++ b/types.go @@ -7,22 +7,23 @@ import ( ) type chatTab struct { - isMuc bool - msgs *gtk.ListBox - name string + isMuc bool + msgs *gtk.ListBox + name string + current_nick string } type lambdaConfig struct { - Server string - Username string - Resource string - Password string - Insecure bool - Nick string - JoinBookmarks bool - CVD color.CVD - Identicons bool - Debug bool + Server string + Username string + Resource string + Password string + Insecure bool + Nick string + JoinBookmarks bool + CVD color.CVD + Identicons bool + Debug bool ShowPresenceUpdates bool }