In my true love's dying breath, she whispered to me 'never commit with descriptive messages'. So I kept her promise.

This commit is contained in:
2026-01-30 21:31:33 +00:00
parent 69bee8766e
commit 19b43345f7
4 changed files with 119 additions and 52 deletions

View File

@@ -17,7 +17,8 @@ func scrollToBottomAfterUpdate(scrolledWindow *gtk.ScrolledWindow) {
} }
func createTab(jid string, isMuc bool) { func createTab(jid string, isMuc bool) {
_, ok := tabs[jid] fmt.Println("Creating tab", jid, "isMuc:", isMuc)
_, ok := tabs.Load(jid)
if !ok { if !ok {
newTab := new(chatTab) newTab := new(chatTab)
newTab.isMuc = isMuc newTab.isMuc = isMuc
@@ -26,13 +27,21 @@ func createTab(jid string, isMuc bool) {
newTab.msgs.SetShowSeparators(true) newTab.msgs.SetShowSeparators(true)
newTab.msgs.Append(gtk.NewButtonWithLabel("Get past messages...")) newTab.msgs.Append(gtk.NewButtonWithLabel("Get past messages..."))
tabs[jid] = newTab tabs.Store(jid, newTab)
} }
} }
func switchToTab(jid string) { func switchToTab(jid string) {
current = jid current = jid
scroller.SetChild(tabs[current].msgs) tab, ok := tabs.Load(current)
if !ok {
return
}
typed_tab := tab.(*chatTab)
scroller.SetChild(typed_tab.msgs)
if typed_tab.isMuc {
m, _ := mucmembers.Load(jid) m, _ := mucmembers.Load(jid)
ma := m.(mucUnit) ma := m.(mucUnit)
mm := ma.Members mm := ma.Members
@@ -56,6 +65,9 @@ func switchToTab(jid string) {
}) })
memberList.SetChild(gen) memberList.SetChild(gen)
} else {
memberList.SetChild(gtk.NewLabel(jid))
}
} }

View File

@@ -80,6 +80,7 @@ func generateMessageWidget(p stanza.Packet) gtk.Widgetter {
// authorBox.Append(im) // authorBox.Append(im)
if m.Type == stanza.MessageTypeGroupchat {
mo, _ := mucmembers.Load(jid.MustParse(m.From).Bare().String()) mo, _ := mucmembers.Load(jid.MustParse(m.From).Bare().String())
mm := mo.(mucUnit) mm := mo.(mucUnit)
mmm := mm.Members mmm := mm.Members
@@ -98,11 +99,14 @@ func generateMessageWidget(p stanza.Packet) gtk.Widgetter {
im := newImageFromPath("debug.png") im := newImageFromPath("debug.png")
im.SetPixelSize(40) im.SetPixelSize(40)
im.AddCSSClass("author_img") im.AddCSSClass("author_img")
authorBox.Append(im)
} }
} else { } else {
im := newImageFromPath("debug.png") im := newImageFromPath("debug.png")
im.SetPixelSize(40) im.SetPixelSize(40)
im.AddCSSClass("author_img") im.AddCSSClass("author_img")
authorBox.Append(im)
}
} }
al := gtk.NewLabel(jid.MustParse(m.From).Resourcepart()) al := gtk.NewLabel(jid.MustParse(m.From).Resourcepart())

75
main.go
View File

@@ -21,7 +21,6 @@ import (
"encoding/xml" "encoding/xml"
"runtime" "runtime"
"github.com/kr/pretty"
) )
var loadedConfig lambdaConfig var loadedConfig lambdaConfig
@@ -31,11 +30,13 @@ var empty_dialog *gtk.Label
// var msgs *gtk.ListBox // var msgs *gtk.ListBox
var content *gtk.Widgetter var content *gtk.Widgetter
var tabs map[string]*chatTab = make(map[string]*chatTab) // var tabs map[string]*chatTab = make(map[string]*chatTab)
var tabs sync.Map
var current string var current string
var scroller *gtk.ScrolledWindow var scroller *gtk.ScrolledWindow
var memberList *gtk.ScrolledWindow var memberList *gtk.ScrolledWindow
var menu *gtk.Box
//go:embed style.css //go:embed style.css
var styleCSS string var styleCSS string
@@ -47,6 +48,9 @@ var uiQueue = make(chan func(), 100)
// stores members of mucs // stores members of mucs
var mucmembers sync.Map var mucmembers sync.Map
// stores devices of users
var userdevices sync.Map
func init() { func init() {
go func() { go func() {
for fn := range uiQueue { for fn := range uiQueue {
@@ -154,10 +158,11 @@ func main() {
b = ba b = ba
} }
_, ok = tabs[originator] tab, ok := tabs.Load(originator)
typed_tab := tab.(*chatTab)
if ok { if ok {
tabs[originator].msgs.Append(b) typed_tab.msgs.Append(b)
scrollToBottomAfterUpdate(scroller) scrollToBottomAfterUpdate(scroller)
} else { } else {
fmt.Println("Got message when the tab does not exist!") fmt.Println("Got message when the tab does not exist!")
@@ -172,7 +177,10 @@ func main() {
return return
} }
pretty.Println(presence) if presence.Error != *new(stanza.Err) {
return
}
var mu MucUser var mu MucUser
var ocu OccupantID var ocu OccupantID
@@ -193,22 +201,48 @@ func main() {
} }
typed_unit := unit.(mucUnit) typed_unit := unit.(mucUnit)
/*
if typed_unit.Members == nil {
typed_unit.Members = make(map[string]stanza.Presence)
mucmembers.Store(muc, typed_unit)
}
*/
if presence.Type != "unavailable" { if presence.Type != "unavailable" {
typed_unit.Members.Store(ocu.ID, presence) typed_unit.Members.Store(ocu.ID, presence)
} else { } else {
typed_unit.Members.Delete(ocu.ID) typed_unit.Members.Delete(ocu.ID)
// delete(typed_unit.Members, ocu.ID)
} }
mucmembers.Store(muc, typed_unit) mucmembers.Store(muc, typed_unit)
} else { // This is a presence stanza from a regular user
// The code is basically the exact same as above, we just don't check for mucuser
user := jid.MustParse(presence.From).Bare().String()
_, ok := userdevices.Load(user)
if !ok {
userdevices.Store(user, userUnit{})
createTab(user, false)
b := gtk.NewButtonWithLabel(user)
b.ConnectClicked(func() {
b.AddCSSClass("accent")
switchToTab(user)
})
menu.Append(b)
}
unit, ok := userdevices.Load(user)
if !ok {
fmt.Println("Could not load user presence even after recreating it! Something weird is going on!")
return
}
resource := jid.MustParse(presence.From).Resourcepart()
typed_unit := unit.(userUnit)
if presence.Type != "unavailable" {
typed_unit.Devices.Store(resource, presence)
} else {
typed_unit.Devices.Delete(resource)
}
userdevices.Store(user, typed_unit)
} }
}) })
@@ -257,7 +291,7 @@ func activate(app *gtk.Application) {
window.SetTitle("Lambda") window.SetTitle("Lambda")
window.Window.AddCSSClass("ssd") window.Window.AddCSSClass("ssd")
menu := gtk.NewBox(gtk.OrientationHorizontal, 0) menu = gtk.NewBox(gtk.OrientationHorizontal, 0)
/* /*
f_menu := gtk.NewMenuButton() f_menu := gtk.NewMenuButton()
f_menu.SetLabel("File") f_menu.SetLabel("File")
@@ -323,7 +357,18 @@ func activate(app *gtk.Application) {
dialog.Choose(context.TODO(), &window.Window, nil) dialog.Choose(context.TODO(), &window.Window, nil)
} }
err := sendMessage(client, current, stanza.MessageTypeGroupchat, t, "", "") message_type := stanza.MessageTypeChat
tab, ok := tabs.Load(current)
if !ok {
return
}
typed_tab := tab.(*chatTab)
if typed_tab.isMuc {
message_type = stanza.MessageTypeGroupchat
}
err := sendMessage(client, current, message_type, t, "", "")
if err != nil { if err != nil {
panic(err) // TODO: Show error message via GTK panic(err) // TODO: Show error message via GTK
} }
@@ -348,7 +393,7 @@ func activate(app *gtk.Application) {
debug_btn.ConnectClicked(func() { debug_btn.ConnectClicked(func() {
t := en.Text() t := en.Text()
_, ok := tabs[t] _, ok := tabs.Load(t)
if !ok { if !ok {
err := joinMuc(client, clientroot.Session.BindJid, t, m_entry.Text()) err := joinMuc(client, clientroot.Session.BindJid, t, m_entry.Text())
if err != nil { if err != nil {

View File

@@ -23,3 +23,9 @@ type mucUnit struct {
// value: last user presence // value: last user presence
Members sync.Map Members sync.Map
} }
type userUnit struct {
// key: Resource
// value: last presence of this device
Devices sync.Map
}