Add rendering forms to messages, add configuring mucs, add getting muc affiliations, add a bunch of other stuff idk man check the diff

This commit is contained in:
Sunglocto committed 2026-10-11 12:08:38 +01:00
1 parent 7a875f84a5
commit 34b885a770
19 files changed
+706 -101

No files matched your search

+206 -39
View File
@@ -19,6 +19,7 @@ import (
"github.com/diamondburned/gotk4/pkg/gio/v2"
"github.com/diamondburned/gotk4/pkg/glib/v2"
"github.com/diamondburned/gotk4/pkg/gtk/v4"
"github.com/diamondburned/gotk4/pkg/pango"
"github.com/gen2brain/beeep"
"github.com/go-analyze/charts"
"github.com/google/uuid"
@@ -83,11 +84,18 @@ var xmlLog *os.File
// Basic roster
var Roster = make(map[string]bool)
var config_filename = "lambda.toml"
var app_id = "net.sunglocto.lambda"
func init() {
beeep.AppName = loadedLocale["appName"]
}
func main() {
if os.Getenv("PROFILE") != "" {
config_filename = fmt.Sprintf("lambda_%s.toml", os.Getenv("PROFILE"))
app_id = "net.sunglocto.lambda." + os.Getenv("PROFILE")
}
pingTimes = append(pingTimes, []float64{})
p, err := ensureConfig()
@@ -95,7 +103,7 @@ func main() {
panic(err)
}
b, err := os.ReadFile(filepath.Join(p, "lambda.toml"))
b, err := os.ReadFile(filepath.Join(p, config_filename))
if err != nil {
dropToSignInPage(err)
return
@@ -169,6 +177,7 @@ func main() {
iqResp.Type = "error"
iqResp.From = clientroot.Session.BindJid
iqResp.Id = iq.Id
stanza_err := new(stanza.Err)
stanza_err.Type = stanza.ErrorTypeCancel
@@ -203,6 +212,7 @@ func main() {
{Var: "urn:xmpp:ping"},
{Var: "jabber:iq:oob"},
{Var: "jabber:x:oob"},
{Var: "jabber:x:data"},
},
}
iqResp.Payload = &payload
@@ -230,6 +240,7 @@ func main() {
iqResp.Type = "error"
iqResp.From = clientroot.Session.BindJid
iqResp.Id = iq.Id
stanza_err := new(stanza.Err)
stanza_err.Type = stanza.ErrorTypeCancel
@@ -360,8 +371,8 @@ func main() {
// Handle read indicators
marker := new(Marker)
ok = m.Get(marker)
if ok {
_, ok := typed_tab.msg_refsOSID[marker.ID]
if ok && !loadedConfig.CompactMode {
_, ok := typed_tab.msg_refsOSID.Load(marker.ID)
if ok {
im := gtk.NewImage()
im.SetPixelSize(20)
@@ -381,10 +392,13 @@ func main() {
go getAvatar(m.From, vu.Photo, im)
}
ind, ok := typed_tab.msg_refsOSID[marker.ID]
if ok {
if ind.read_indicator != nil {
ind.read_indicator.Append(im)
uind, loaded := typed_tab.msg_refsOSID.Load(marker.ID)
if loaded {
ind, ok := uind.(*abMessage)
if ok {
if ind.read_indicator != nil {
ind.read_indicator.Append(im)
}
}
}
return
@@ -423,30 +437,21 @@ func main() {
tab, ok := tabs.Load(originator)
if ok {
typed_tab := tab.(*chatTab)
/*
to_retract := ""
refs := typed_tab.msg_refsID
// If it is a DM, then we use regular message ID. If it is a MUC, we use stanza id
to_retract = sid.ID
if typed_tab.isMuc && sid != nil {
to_retract = sid.ID
refs = typed_tab.msg_refsOSID
}
*/
msg, ok := typed_tab.msg_refsOSID[retraction.ID]
umsg, ok := typed_tab.msg_refsOSID.Load(retraction.ID)
if ok {
lab := msg.label_ref
glib.IdleAdd(func() {
GenerateRetraction(lab, *retraction)
})
return
msg, ok := umsg.(*abMessage)
if ok {
lab := msg.label_ref
glib.IdleAdd(func() {
GenerateRetraction(lab, *retraction)
})
return
}
}
}
}
glib.IdleAdd(func() {
glib.IdleAddPriority(glib.PriorityLow, func() {
b := gtk.NewBox(gtk.OrientationVertical, 0)
tab, ok := tabs.Load(originator)
@@ -472,9 +477,11 @@ func main() {
if valid && converted_successfully {
mStatus.SetText(originator)
typed_tab.msgs.Append(b)
b.Append(ba)
b.Append(gtk.NewSeparator(gtk.OrientationVertical))
if typed_tab.msgs != nil {
typed_tab.msgs.Append(b)
b.Append(ba)
b.Append(gtk.NewSeparator(gtk.OrientationVertical))
}
}
})
})
@@ -496,6 +503,20 @@ func main() {
ok = presence.Get(&mu)
if ok { // This is a presence stanza from a user in a MUC
from_self, created := false, false
for _, status := range mu.StatusCodes {
if status.Code == "110" {
from_self = true
}
if status.Code == "201" {
created = true
}
}
if from_self && created {
showDialog("You have created a new MUC. In order for people to be able to join this MUC, you must first configure it. You can configure this MUC by clicking on the MUC button in the top right and then clicking 'Configre MUC'.", &window.Window)
}
presence.Get(&ocu)
id := JidMustParse(presence.From).Resource
@@ -524,7 +545,7 @@ func main() {
if presence.Type != "unavailable" {
_, ok := typed_unit.Members.Load(id)
if !ok && loadedConfig.ShowPresenceUpdates {
glib.IdleAdd(func() {
glib.IdleAddPriority(glib.PriorityLow, func() {
b := gtk.NewBox(gtk.OrientationVertical, 0)
ba, ok := generatePresenceWidget(p).(*gtk.Box)
if ok {
@@ -548,7 +569,7 @@ func main() {
} else {
typed_unit.Members.Delete(id)
if loadedConfig.ShowPresenceUpdates {
glib.IdleAdd(func() {
glib.IdleAddPriority(glib.PriorityLow, func() {
b := gtk.NewBox(gtk.OrientationVertical, 0)
ba, ok := generatePresenceWidget(p).(*gtk.Box)
if ok {
@@ -604,7 +625,7 @@ func main() {
cm := xmpp.NewStreamManager(c, func(c xmpp.Sender) {
fmt.Println("XMPP client connected")
// client = c
client = c
// clientroot = c
go func() {
@@ -810,7 +831,7 @@ func main() {
}
}
app := gtk.NewApplication("net.sunglocto.lambda", gio.ApplicationDefaultFlags)
app := gtk.NewApplication(app_id, gio.ApplicationDefaultFlags)
app.ConnectActivate(func() {
activate(app)
go conc()
@@ -834,6 +855,86 @@ func activate(app *gtk.Application) {
fileMenu := gio.NewMenu()
fileMenu.Append(loadedLocale["joinMUCMenu"], "app.join")
fileMenu.Append(loadedLocale["destroyMUCMenu"], "app.destroymuc")
fileMenu.Append("MUC Affiliations", "app.mucaffils")
fileMenu.Append("Configure MUC", "app.configuremuc")
viewAffilsMucAction := gio.NewSimpleAction("mucaffils", nil)
viewAffilsMucAction.ConnectActivate(func(p *glib.Variant) {
go func() {
cur, ok := tabs.Load(current)
if ok {
cur := cur.(*chatTab)
if cur.isMuc {
affils := []string{"owner", "admin", "member", "outcast"}
items := []MucAdminItem{}
for _, affil := range affils {
iq, err := stanza.NewIQ(stanza.Attrs{Type: stanza.IQTypeGet, To: current, Id: uuid.NewString(), From: clientroot.Session.BindJid})
if err != nil {
return
}
q := new(MucAdminQuery)
q.MucAdminItems = append(q.MucAdminItems, MucAdminItem{Affiliation: affil})
iq.Payload = q
ctx := context.TODO()
mychan, err := client.SendIQ(ctx, iq)
result := <-mychan
res, ok := result.Payload.(*MucAdminQuery)
if ok {
for _, item := range res.MucAdminItems {
items = append(items, item)
}
}
}
glib.IdleAdd(func() {
affil_win := gtk.NewWindow()
affil_box := gtk.NewBox(gtk.OrientationVertical, 2)
affil_box.Append(gtk.NewLabel("Affiliations"))
scroller := gtk.NewScrolledWindow()
scroller_grid := gtk.NewGrid()
scroller_grid.SetVExpand(true)
scroller.SetChild(scroller_grid)
scroller.SetVExpand(true)
affil_box.Append(scroller)
affil_win.SetChild(affil_box)
scroller_grid.Attach(gtk.NewLabel("Affiliation"), 0, 0, 1, 1)
scroller_grid.Attach(gtk.NewLabel("JID"), 1, 0, 1, 1)
scroller_grid.Attach(gtk.NewLabel("Nick"), 2, 0, 1, 1)
scroller_grid.Attach(gtk.NewLabel("Reason"), 3, 0, 1, 1)
for i, v := range items {
medal_box := gtk.NewBox(gtk.OrientationHorizontal, 0)
medal_box.Append(gtk.NewImageFromPaintable(clientAssetsLoad(v.Affiliation)))
medal_box.Append(gtk.NewLabel(v.Affiliation))
scroller_grid.Attach(medal_box, 0, i+1, 1, 1)
jid := gtk.NewLabel(v.JID)
jid.AddCSSClass("jid")
jid.SetSelectable(true)
scroller_grid.Attach(jid, 1, i+1, 1, 1)
nick := gtk.NewLabel(v.Nick)
nick.SetSelectable(true)
scroller_grid.Attach(nick, 2, i+1, 1, 1)
reason := gtk.NewLabel(v.Reason)
reason.SetSelectable(true)
reason.SetEllipsize(pango.EllipsizeEnd)
scroller_grid.Attach(reason, 3, i+1, 1, 1)
}
affil_win.SetVisible(true)
})
}
}
}()
})
dmMenu := gio.NewMenu()
dmMenu.Append(loadedLocale["startDMMenu"], "app.dm")
@@ -890,12 +991,81 @@ func activate(app *gtk.Application) {
a.SetAuthors([]string{"Sunglocto", "Hydrogen", "Kuyuhi"})
a.SetLicenseType(gtk.LicenseGPL30)
a.SetLogo(clientAssetsLoad("logo"))
a.SetWebsite("https://forge.sunglocto.net/sunglocto/lambda")
a.SetWebsite("https://sunglocto.net/lambda")
a.SetWebsiteLabel("Website")
a.SetVisible(true)
})
configureMucAction := gio.NewSimpleAction("configuremuc", nil)
configureMucAction.ConnectActivate(func(p *glib.Variant) {
go func() {
cur, ok := tabs.Load(current)
if ok {
cur := cur.(*chatTab)
if cur.isMuc {
iq, err := stanza.NewIQ(stanza.Attrs{
Type: stanza.IQTypeGet,
Id: uuid.NewString(),
To: current,
})
if err != nil {
glib.IdleAdd(func() { showErrorDialog(err, &window.Window) })
return
}
iq.Payload = &MucOwnerQuery{}
ctx := context.TODO()
mychan, err := client.SendIQ(ctx, iq)
if err != nil {
glib.IdleAdd(func() { showErrorDialog(err, &window.Window) })
return
}
result := <-mychan
res, ok := result.Payload.(*MucOwnerQuery)
if !ok {
return
}
glib.IdleAdd(func() {
f, win, _ := showFormDialog(res.Form)
win.ConnectCloseRequest(func() (ok bool) {
go func() {
iq, err := stanza.NewIQ(stanza.Attrs{
Id: result.Id,
To: result.From,
Type: stanza.IQTypeSet,
})
if err != nil {
glib.IdleAdd(func() { showErrorDialog(err, &window.Window) })
return
}
f.Type = "submit"
mo := new(MucOwnerQuery)
mo.Form = *f
iq.Payload = mo
ctx := context.TODO()
_, err = client.SendIQ(ctx, iq)
if err != nil {
glib.IdleAdd(func() { showErrorDialog(err, &window.Window) })
return
}
}()
return false
})
})
}
}
}()
})
destroymucAction := gio.NewSimpleAction("destroymuc", nil)
destroymucAction.ConnectActivate(func(p *glib.Variant) {
cur, ok := tabs.Load(current)
@@ -919,7 +1089,6 @@ func activate(app *gtk.Application) {
submit := gtk.NewButtonWithLabel(loadedLocale["destroyMUCActionButton"])
submit.ConnectClicked(func() {
fmt.Println(en.Text())
if en.Text() == loadedLocale["destroyMUCPassword"] {
cur, ok := tabs.Load(current)
if ok {
@@ -1069,7 +1238,6 @@ func activate(app *gtk.Application) {
var res *stanza.DiscoInfo
allowed := true
fmt.Println("Attempting to get Disco info")
myIQ, err := stanza.NewIQ(stanza.Attrs{
Type: "get",
@@ -1225,7 +1393,9 @@ func activate(app *gtk.Application) {
app.AddAction(joinAction)
app.AddAction(aboutAction)
app.AddAction(destroymucAction)
app.AddAction(configureMucAction)
app.AddAction(startDmAction)
app.AddAction(viewAffilsMucAction)
the_menu.AppendSubmenu("MUC", fileMenu)
the_menu.AppendSubmenu("DM", dmMenu)
@@ -1350,16 +1520,13 @@ func activate(app *gtk.Application) {
scrollerStatBar.SetChild(statBar)
box.Append(scrollerStatBar)
// scroller.SetChild(empty_dialog)
scroller.SetChild(empty_dialog)
menu_scroll := gtk.NewScrolledWindow()
menu_scroll.SetHExpand(true)
menu_scroll.SetChild(menu)
// box.Append(menu_scroll)
chatbox := gtk.NewBox(gtk.OrientationHorizontal, 0)
// chatbox.Append(menu_scroll)
chat_pane := gtk.NewPaned(gtk.OrientationHorizontal)
chat_pane.SetStartChild(scroller)
chat_pane.SetEndChild(memberList)