Compare commits
2 Commits
359e8ed63e
...
7416aa37e0
| Author | SHA1 | Date | |
|---|---|---|---|
| 7416aa37e0 | |||
| ce83000e0c |
Binary file not shown.
|
Before Width: | Height: | Size: 666 B After Width: | Height: | Size: 910 B |
@@ -4,6 +4,8 @@ go 1.25.5
|
||||
|
||||
require (
|
||||
github.com/BurntSushi/toml v1.6.0
|
||||
github.com/boxes-ltd/imaging v1.7.5
|
||||
github.com/crazy3lf/colorconv v1.2.0
|
||||
github.com/diamondburned/gotk4/pkg v0.3.1
|
||||
github.com/gen2brain/beeep v0.11.2
|
||||
github.com/go-analyze/charts v0.5.24
|
||||
@@ -12,6 +14,10 @@ require (
|
||||
github.com/jasonlovesdoggo/gopen v0.0.0-20250130105607-39c98c645030
|
||||
github.com/kirsle/configdir v0.0.0-20170128060238-e45d2f54772f
|
||||
github.com/kr/pretty v0.2.0
|
||||
github.com/mskrha/svg2png v0.0.0-20240706085601-64fa78f4eb07
|
||||
github.com/rrivera/identicon v0.0.0-20240116195454-d5ba35832c0d
|
||||
github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c
|
||||
github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef
|
||||
golang.org/x/net v0.29.0
|
||||
gosrc.io/xmpp v0.5.1
|
||||
mellium.im/xmpp v0.22.0
|
||||
@@ -33,10 +39,10 @@ require (
|
||||
github.com/sergeymakinen/go-ico v1.0.0-beta.0 // indirect
|
||||
github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af // indirect
|
||||
go4.org/unsafe/assume-no-moving-gc v0.0.0-20231121144256-b99613f794b6 // indirect
|
||||
golang.org/x/image v0.24.0 // indirect
|
||||
golang.org/x/sync v0.11.0 // indirect
|
||||
golang.org/x/image v0.36.0 // indirect
|
||||
golang.org/x/sync v0.19.0 // indirect
|
||||
golang.org/x/sys v0.30.0 // indirect
|
||||
golang.org/x/text v0.22.0 // indirect
|
||||
golang.org/x/text v0.34.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 // indirect
|
||||
mellium.im/reader v0.1.0 // indirect
|
||||
mellium.im/xmlstream v0.15.4 // indirect
|
||||
|
||||
@@ -5,12 +5,16 @@ github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2
|
||||
github.com/KarpelesLab/weak v0.1.1 h1:fNnlPo3aypS9tBzoEQluY13XyUfd/eWaSE/vMvo9s4g=
|
||||
github.com/KarpelesLab/weak v0.1.1/go.mod h1:pzXsWs5f2bf+fpgHayTlBE1qJpO3MpJKo5sRaLu1XNw=
|
||||
github.com/agnivade/wasmbrowsertest v0.3.1/go.mod h1:zQt6ZTdl338xxRaMW395qccVE2eQm0SjC/SDz0mPWQI=
|
||||
github.com/boxes-ltd/imaging v1.7.5 h1:k4kYxJEhysoGhEEN1IEeKoSbnG8/8snjj7M48Ok0fnk=
|
||||
github.com/boxes-ltd/imaging v1.7.5/go.mod h1:+8H+oRvis3InOFtTpcoCCB1RDXqo6p9tQBtjZfWnrC8=
|
||||
github.com/chromedp/cdproto v0.0.0-20190614062957-d6d2f92b486d/go.mod h1:S8mB5wY3vV+vRIzf39xDXsw3XKYewW9X6rW2aEmkrSw=
|
||||
github.com/chromedp/cdproto v0.0.0-20190621002710-8cbd498dd7a0/go.mod h1:S8mB5wY3vV+vRIzf39xDXsw3XKYewW9X6rW2aEmkrSw=
|
||||
github.com/chromedp/cdproto v0.0.0-20190812224334-39ef923dcb8d/go.mod h1:0YChpVzuLJC5CPr+x3xkHN6Z8KOSXjNbL7qV8Wc4GW0=
|
||||
github.com/chromedp/cdproto v0.0.0-20190926234355-1b4886c6fad6/go.mod h1:0YChpVzuLJC5CPr+x3xkHN6Z8KOSXjNbL7qV8Wc4GW0=
|
||||
github.com/chromedp/chromedp v0.3.1-0.20190619195644-fd957a4d2901/go.mod h1:mJdvfrVn594N9tfiPecUidF6W5jPRKHymqHfzbobPsM=
|
||||
github.com/chromedp/chromedp v0.4.0/go.mod h1:DC3QUn4mJ24dwjcaGQLoZrhm4X/uPHZ6spDbS2uFhm4=
|
||||
github.com/crazy3lf/colorconv v1.2.0 h1:UM7kSZWnwFMGiC+PpYrjxQSOd6sEyWb+dRKKTd3KslA=
|
||||
github.com/crazy3lf/colorconv v1.2.0/go.mod h1:2jTJ7QCWCj2sSLOhF4Gzi0J5/hoX8/VY8VzNvXAlD1I=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@@ -80,6 +84,8 @@ github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVc
|
||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
|
||||
github.com/mskrha/svg2png v0.0.0-20240706085601-64fa78f4eb07 h1:7fan6wzUXasMPMHho2ePSkB+QTEb0Rh/f6B+IkkP1Sc=
|
||||
github.com/mskrha/svg2png v0.0.0-20240706085601-64fa78f4eb07/go.mod h1:KFdfdIgpr48ODxdkxKvpcYwuyLpQ6rfkAsFB2UQ6jD4=
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
@@ -89,6 +95,8 @@ github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rrivera/identicon v0.0.0-20240116195454-d5ba35832c0d h1:l3+2LWCbVxn5itfvXAfH9n4YL9jh8l1g5zcncbIc1cs=
|
||||
github.com/rrivera/identicon v0.0.0-20240116195454-d5ba35832c0d/go.mod h1:TbpErkob6SY7cyozRVSGoB3OlO2qOAgVN8O3KAJ4fMI=
|
||||
github.com/sergeymakinen/go-bmp v1.0.0 h1:SdGTzp9WvCV0A1V0mBeaS7kQAwNLdVJbmHlqNWq0R+M=
|
||||
github.com/sergeymakinen/go-bmp v1.0.0/go.mod h1:/mxlAQZRLxSvJFNIEGGLBE/m40f3ZnUifpgVDlcUIEY=
|
||||
github.com/sergeymakinen/go-ico v1.0.0-beta.0 h1:m5qKH7uPKLdrygMWxbamVn+tl2HfiA3K6MFJw4GfZvQ=
|
||||
@@ -97,6 +105,10 @@ github.com/sirupsen/logrus v1.0.5/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjM
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c h1:km8GpoQut05eY3GiYWEedbTT0qnSxrCjsVbb7yKY1KE=
|
||||
github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c/go.mod h1:cNQ3dwVJtS5Hmnjxy6AgTPd0Inb3pW05ftPSX7NZO7Q=
|
||||
github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef h1:Ch6Q+AZUxDBCVqdkI8FSpFyZDtCVBc2VmejdNrm5rRQ=
|
||||
github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef/go.mod h1:nXTWP6+gD5+LUJ8krVhhoeHjvHTutPxMYl5SvkcnJNE=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
@@ -123,11 +135,11 @@ golang.org/x/crypto v0.0.0-20180426230345-b49d69b5da94/go.mod h1:6SG95UA2DQfeDnf
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
|
||||
golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
|
||||
golang.org/x/image v0.24.0 h1:AN7zRgVsbvmTfNyqIbbOraYL8mSwcKncEj8ofjgzcMQ=
|
||||
golang.org/x/image v0.24.0/go.mod h1:4b/ITuLfqYq1hqZcjofwctIhi7sZh2WaCjvsBNjjya8=
|
||||
golang.org/x/image v0.36.0 h1:Iknbfm1afbgtwPTmHnS2gTM/6PPZfH+z2EFuOkSbqwc=
|
||||
golang.org/x/image v0.36.0/go.mod h1:YsWD2TyyGKiIX1kZlu9QfKIsQ4nAAK9bdgdrIsE7xy4=
|
||||
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
|
||||
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||
golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c=
|
||||
golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181102091132-c10e9556a7bc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
@@ -137,8 +149,8 @@ golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
|
||||
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
|
||||
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -152,14 +164,14 @@ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
|
||||
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
|
||||
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
|
||||
golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk=
|
||||
golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.25.0 h1:oFU9pkj/iJgs+0DT+VMHrx+oBKs/LJMV+Uvg78sl+fE=
|
||||
golang.org/x/tools v0.25.0/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg=
|
||||
golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc=
|
||||
golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
|
||||
|
||||
+72
-10
@@ -1,13 +1,22 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/boxes-ltd/imaging"
|
||||
"github.com/crazy3lf/colorconv"
|
||||
"github.com/diamondburned/gotk4/pkg/gdk/v4"
|
||||
"github.com/diamondburned/gotk4/pkg/gdkpixbuf/v2"
|
||||
"github.com/diamondburned/gotk4/pkg/glib/v2"
|
||||
"github.com/diamondburned/gotk4/pkg/gtk/v4"
|
||||
"github.com/diamondburned/gotk4/pkg/pango"
|
||||
"github.com/rrivera/identicon"
|
||||
"gosrc.io/xmpp/stanza"
|
||||
"image"
|
||||
"image/png"
|
||||
xmpp_color "mellium.im/xmpp/color"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func scrollToBottomAfterUpdate(scrolledWindow *gtk.ScrolledWindow) {
|
||||
@@ -62,7 +71,7 @@ func switchToTab(jid string, w *gtk.Window) {
|
||||
gen := gtk.NewBox(gtk.OrientationVertical, 0)
|
||||
|
||||
i := 0
|
||||
mm.Range(func(k, v any) bool {
|
||||
rangeOrdered(&mm, (func(k, v any) bool {
|
||||
i++
|
||||
userbox := gtk.NewBox(gtk.OrientationHorizontal, 0)
|
||||
|
||||
@@ -71,6 +80,13 @@ func switchToTab(jid string, w *gtk.Window) {
|
||||
var ocu OccupantID
|
||||
u.Get(&mu)
|
||||
u.Get(&ocu)
|
||||
|
||||
if mu.MucUserItem.Role == "moderator" {
|
||||
gen.Prepend(userbox)
|
||||
} else {
|
||||
gen.Append(userbox)
|
||||
}
|
||||
|
||||
//id := ocu.ID
|
||||
//if id == "" {
|
||||
id := JidMustParse(u.From).Resource
|
||||
@@ -90,7 +106,29 @@ func switchToTab(jid string, w *gtk.Window) {
|
||||
ok := u.Get(&hats)
|
||||
if ok {
|
||||
for _, hat := range hats.Hats {
|
||||
tag := gtk.NewImageFromPaintable(clientAssets["tag"])
|
||||
var val float64
|
||||
if hat.Hue != "" {
|
||||
tval, _ := strconv.Atoi(hat.Hue)
|
||||
val = float64(tval)
|
||||
} else {
|
||||
xc := xmpp_color.String(hat.URI, 255, loadedConfig.CVD)
|
||||
r, g, b, _ := xc.RGBA()
|
||||
val, _, _ = colorconv.RGBToHSV(uint8(r), uint8(g), uint8(b))
|
||||
|
||||
}
|
||||
tB := tagBytes
|
||||
img, _, _ := image.Decode(bytes.NewReader(tB))
|
||||
i_rgba := imaging.AdjustHue(img, val)
|
||||
|
||||
var buf bytes.Buffer
|
||||
png.Encode(&buf, i_rgba)
|
||||
|
||||
tB = buf.Bytes()
|
||||
|
||||
loader := gdkpixbuf.NewPixbufLoader()
|
||||
loader.Write(tB)
|
||||
loader.Close()
|
||||
tag := gtk.NewPictureForPaintable(gdk.NewTextureForPixbuf(loader.Pixbuf()))
|
||||
tag.SetTooltipText(hat.Title)
|
||||
userbox.Prepend(tag)
|
||||
}
|
||||
@@ -262,10 +300,12 @@ func switchToTab(jid string, w *gtk.Window) {
|
||||
|
||||
win.SetTitle(JidMustParse(u.From).Resource)
|
||||
nick.AddCSSClass("author")
|
||||
nick.SetSelectable(true)
|
||||
profile_box.Append(nick)
|
||||
profile_box.Append(ver_text)
|
||||
fr := gtk.NewLabel(u.From)
|
||||
fr.AddCSSClass("jid")
|
||||
fr.SetSelectable(true)
|
||||
profile_box.Append(fr)
|
||||
profile_box.Append(ver_text)
|
||||
|
||||
@@ -300,6 +340,7 @@ func switchToTab(jid string, w *gtk.Window) {
|
||||
if mu.MucUserItem.JID != "" {
|
||||
ji := (gtk.NewLabel(mu.MucUserItem.JID))
|
||||
ji.AddCSSClass("jid")
|
||||
ji.SetSelectable(true)
|
||||
profile_box.Append(ji)
|
||||
}
|
||||
profile_box.Append(gtk.NewLabel("Connected with role " + mu.MucUserItem.Role))
|
||||
@@ -397,13 +438,13 @@ func switchToTab(jid string, w *gtk.Window) {
|
||||
im.AddCSSClass("author_img")
|
||||
profile_box.Prepend(im)
|
||||
} else {
|
||||
im := gtk.NewImageFromPaintable(clientAssets["DefaultAvatar"])
|
||||
im := createIdenticon(u.From)
|
||||
im.SetPixelSize(80)
|
||||
im.AddCSSClass("author_img")
|
||||
profile_box.Prepend(im)
|
||||
}
|
||||
} else {
|
||||
im := gtk.NewImageFromPaintable(clientAssets["DefaultAvatar"])
|
||||
im := createIdenticon(u.From)
|
||||
im.SetPixelSize(80)
|
||||
im.AddCSSClass("author_img")
|
||||
profile_box.Prepend(im)
|
||||
@@ -418,13 +459,8 @@ func switchToTab(jid string, w *gtk.Window) {
|
||||
userbox.AddController(gesture)
|
||||
userbox.AddController(mod_gesture)
|
||||
|
||||
if mu.MucUserItem.Role == "moderator" {
|
||||
gen.Prepend(userbox)
|
||||
} else {
|
||||
gen.Append(userbox)
|
||||
}
|
||||
return true
|
||||
})
|
||||
}))
|
||||
|
||||
headerBox := gtk.NewBox(gtk.OrientationHorizontal, 0)
|
||||
if i >= 500 {
|
||||
@@ -450,3 +486,29 @@ func switchToTab(jid string, w *gtk.Window) {
|
||||
func showErrorDialog(err error) {
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
|
||||
func createIdenticon(word string) *gtk.Image { // This function generates an identicon
|
||||
if !loadedConfig.Identicons {
|
||||
i := gtk.NewImageFromPaintable(clientAssets["DefaultAvatar"])
|
||||
i.AddCSSClass(loadedConfig.CVD.String()+"_CVD")
|
||||
return i
|
||||
}
|
||||
|
||||
gen, _ := identicon.New("github", 5, 3)
|
||||
ii, _ := gen.Draw(word)
|
||||
im := ii.Image(25)
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
err := png.Encode(buf, im)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
loader := gdkpixbuf.NewPixbufLoader()
|
||||
loader.Write(buf.Bytes())
|
||||
loader.Close()
|
||||
i := gtk.NewImageFromPaintable(gdk.NewTextureForPixbuf(loader.Pixbuf()))
|
||||
i.AddCSSClass(loadedConfig.CVD.String() + "_CVD")
|
||||
return i
|
||||
|
||||
}
|
||||
|
||||
+24
-11
@@ -16,6 +16,7 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func generatePresenceWidget(p stanza.Packet) gtk.Widgetter {
|
||||
@@ -95,7 +96,7 @@ func generateMessageWidget(p stanza.Packet) gtk.Widgetter {
|
||||
rc_box := gtk.NewBox(gtk.OrientationVertical, 0)
|
||||
|
||||
reactions := gtk.NewBox(gtk.OrientationHorizontal, 0)
|
||||
reaction := []string{"👍", "👎", "♥️", "🤣", "😭"}
|
||||
reaction := []string{"👍", "👎", "♥️", "🤣", "💀"}
|
||||
for _, v := range reaction {
|
||||
like := gtk.NewButton()
|
||||
like.SetLabel(v)
|
||||
@@ -117,7 +118,15 @@ func generateMessageWidget(p stanza.Packet) gtk.Widgetter {
|
||||
|
||||
quote := gtk.NewButtonWithLabel("Quote")
|
||||
quote.ConnectClicked(func() {
|
||||
message_en.SetText("> " + m.Body + "\n")
|
||||
lines := strings.Split(m.Body, "\n")
|
||||
for i, line := range lines {
|
||||
quoteline:= "> " + line
|
||||
lines[i] = quoteline
|
||||
}
|
||||
|
||||
newstr := strings.Join(lines, "\n") + "\n\n"
|
||||
|
||||
message_en.SetText(newstr)
|
||||
})
|
||||
rc_box.Append(quote)
|
||||
|
||||
@@ -170,13 +179,13 @@ func generateMessageWidget(p stanza.Packet) gtk.Widgetter {
|
||||
im.AddCSSClass("author_img")
|
||||
authorBox.Append(im)
|
||||
} else {
|
||||
im := gtk.NewImageFromPaintable(clientAssets["DefaultAvatar"])
|
||||
im := createIdenticon(m.From)
|
||||
im.SetPixelSize(40)
|
||||
im.AddCSSClass("author_img")
|
||||
authorBox.Append(im)
|
||||
}
|
||||
} else {
|
||||
im := gtk.NewImageFromPaintable(clientAssets["DefaultAvatar"])
|
||||
im := createIdenticon(m.From)
|
||||
im.SetPixelSize(40)
|
||||
im.AddCSSClass("author_img")
|
||||
authorBox.Append(im)
|
||||
@@ -251,25 +260,27 @@ func getAvatar(j, hash string) *gtk.Image { // TODO: This function probably shou
|
||||
oghash := hash
|
||||
p, err := ensureCache()
|
||||
if err != nil {
|
||||
return gtk.NewImageFromPaintable(clientAssets["FailedAvatar"])
|
||||
return createIdenticon(j)
|
||||
}
|
||||
|
||||
if hash == "" {
|
||||
fmt.Println("Hash is nil!")
|
||||
return gtk.NewImageFromPaintable(clientAssets["DefaultAvatar"])
|
||||
return createIdenticon(j)
|
||||
}
|
||||
|
||||
_, ok := invalidImages[hash]
|
||||
if ok {
|
||||
fmt.Println("Image is invalid")
|
||||
return gtk.NewImageFromPaintable(clientAssets["FailedAvatar"])
|
||||
return createIdenticon(j)
|
||||
}
|
||||
|
||||
hash = filepath.Join(p, sanitizefilename.Sanitize(hash))
|
||||
|
||||
_, err = os.ReadFile(hash)
|
||||
if err == nil {
|
||||
return newImageFromPath(hash)
|
||||
i := newImageFromPath(hash)
|
||||
i.AddCSSClass(loadedConfig.CVD.String()+"_CVD")
|
||||
return i
|
||||
}
|
||||
|
||||
iqResp, err := stanza.NewIQ(stanza.Attrs{
|
||||
@@ -294,14 +305,14 @@ func getAvatar(j, hash string) *gtk.Image { // TODO: This function probably shou
|
||||
result := <-mychan
|
||||
card, ok := result.Payload.(*VCard)
|
||||
if !ok {
|
||||
return gtk.NewImageFromPaintable(clientAssets["DefaultAvatar"])
|
||||
return createIdenticon(j)
|
||||
}
|
||||
|
||||
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[oghash] = true
|
||||
return gtk.NewImageFromPaintable(clientAssets["FailedAvatar"])
|
||||
return createIdenticon(j)
|
||||
}
|
||||
|
||||
data, err := base64.StdEncoding.DecodeString(base64_data)
|
||||
@@ -314,5 +325,7 @@ func getAvatar(j, hash string) *gtk.Image { // TODO: This function probably shou
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return newImageFromPath(hash)
|
||||
i := newImageFromPath(hash)
|
||||
i.AddCSSClass(loadedConfig.CVD.String()+"_CVD")
|
||||
return i
|
||||
}
|
||||
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
// Generic helpers
|
||||
package main
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"sort"
|
||||
)
|
||||
|
||||
func rangeOrdered(m *sync.Map, fn func(k, v any) bool) {
|
||||
var keys []string
|
||||
|
||||
m.Range(func(k, v any) bool {
|
||||
keys = append(keys, k.(string))
|
||||
return true
|
||||
})
|
||||
|
||||
sort.Strings(keys)
|
||||
|
||||
for _, k := range keys {
|
||||
v, _ := m.Load(k)
|
||||
if !fn(k, v) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,8 @@ var connectionIcon *gtk.Image
|
||||
var mStatus *gtk.Label
|
||||
var mIcon *gtk.Image
|
||||
|
||||
var typingStatus *gtk.Label
|
||||
|
||||
var pingStatus *gtk.Label
|
||||
|
||||
// var msgs *gtk.ListBox
|
||||
@@ -225,7 +227,9 @@ func main() {
|
||||
if ok {
|
||||
if JidMustParse(fm.From).Bare() == JidMustParse(m.From).Bare() {
|
||||
p = sc.Forwarded.Stanza
|
||||
orig := m.To
|
||||
m = sc.Forwarded.Stanza.(stanza.Message)
|
||||
m.To = orig
|
||||
} else {
|
||||
panic(fmt.Sprintln("Impersonation: ", fm.From, m.From))
|
||||
}
|
||||
@@ -245,6 +249,19 @@ func main() {
|
||||
}
|
||||
}
|
||||
}
|
||||
composing := stanza.StateComposing{}
|
||||
ok = m.Get(&composing)
|
||||
if ok && current == JidMustParse(m.From).Bare() {
|
||||
typingStatus.SetText(fmt.Sprintf("%s is typing...", m.From))
|
||||
return
|
||||
}
|
||||
|
||||
inactive := stanza.StateInactive{}
|
||||
ok = m.Get(&inactive)
|
||||
if ok && current == JidMustParse(m.From).Bare() {
|
||||
typingStatus.SetText("")
|
||||
return
|
||||
}
|
||||
|
||||
glib.IdleAdd(func() {
|
||||
//uiQueue <- func() {
|
||||
@@ -674,22 +691,97 @@ func activate(app *gtk.Application) {
|
||||
btn.ConnectClicked(func() {
|
||||
t := jid_entry.Text()
|
||||
_, ok := tabs.Load(t)
|
||||
jm := func() {
|
||||
|
||||
err := joinMuc(client, clientroot.Session.BindJid, t, nick_entry.Text())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
createTab(t, true)
|
||||
b := gtk.NewLabel(t)
|
||||
gesture1 := gtk.NewGestureClick()
|
||||
gesture1.SetButton(1)
|
||||
gesture1.Connect("pressed", func() {
|
||||
switchToTab(t, &window.Window)
|
||||
})
|
||||
|
||||
b.AddController(gesture1)
|
||||
menu.Append(b)
|
||||
}
|
||||
if !ok {
|
||||
err := joinMuc(client, clientroot.Session.BindJid, t, nick_entry.Text())
|
||||
// First check the MUC's disco and see if it's semianon
|
||||
allowed := true
|
||||
fmt.Println("Attempting to get Disco info")
|
||||
|
||||
myIQ, err := stanza.NewIQ(stanza.Attrs{
|
||||
Type: "get",
|
||||
From: clientroot.Session.BindJid,
|
||||
To: t,
|
||||
Id: "dicks",
|
||||
Lang: "en",
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
createTab(t, true)
|
||||
b := gtk.NewLabel(t)
|
||||
gesture1 := gtk.NewGestureClick()
|
||||
gesture1.SetButton(1)
|
||||
gesture1.Connect("pressed", func() {
|
||||
switchToTab(t, &window.Window)
|
||||
})
|
||||
myIQ.Payload = &stanza.DiscoInfo{}
|
||||
|
||||
b.AddController(gesture1)
|
||||
menu.Append(b)
|
||||
ctx := context.TODO()
|
||||
mychan, err := client.SendIQ(ctx, myIQ)
|
||||
if err == nil {
|
||||
result := <-mychan
|
||||
res, ok := result.Payload.(*stanza.DiscoInfo)
|
||||
if ok {
|
||||
semianon := false
|
||||
features := res.Features
|
||||
for _, feature := range features {
|
||||
if feature.Var == "muc_nonanonymous" {
|
||||
semianon = false
|
||||
break
|
||||
} else if feature.Var == "muc_semianonymous" {
|
||||
semianon = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !semianon {
|
||||
allowed = false
|
||||
warning_win := gtk.NewWindow()
|
||||
warning_win.SetTitle("Warning")
|
||||
warning_win.SetDefaultSize(400, 400)
|
||||
warning_win.SetResizable(false)
|
||||
|
||||
warning_box := gtk.NewBox(gtk.OrientationVertical, 0)
|
||||
warning_label := gtk.NewLabel("This muc is not semi-anonymous. Your JID will be revealed to non-moderators if you join. Continue?")
|
||||
|
||||
buttons := gtk.NewBox(gtk.OrientationHorizontal, 0)
|
||||
join_button := gtk.NewButtonWithLabel("Join")
|
||||
join_button.ConnectClicked(func() {
|
||||
warning_win.SetVisible(false)
|
||||
jm()
|
||||
})
|
||||
|
||||
cancel_button := gtk.NewButtonWithLabel("Cancel")
|
||||
cancel_button.ConnectClicked(func() {
|
||||
warning_win.SetVisible(false)
|
||||
})
|
||||
|
||||
buttons.Append(join_button)
|
||||
buttons.Append(cancel_button)
|
||||
|
||||
warning_box.Append(warning_label)
|
||||
warning_box.Append(buttons)
|
||||
warning_win.SetChild(warning_box)
|
||||
warning_win.Present()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if allowed {
|
||||
jm()
|
||||
}
|
||||
}
|
||||
win.SetVisible(false)
|
||||
})
|
||||
@@ -884,7 +976,7 @@ func activate(app *gtk.Application) {
|
||||
end := start + len("@everyone")
|
||||
|
||||
new_mention := new(Mention)
|
||||
new_mention.Type = "urn:xmpp:mentions:0#channel"
|
||||
new_mention.Mentions = "urn:xmpp:mentions:0#channel"
|
||||
|
||||
new_mention.Begin = start
|
||||
new_mention.End = end
|
||||
@@ -915,6 +1007,9 @@ func activate(app *gtk.Application) {
|
||||
|
||||
box.Append(entry_box)
|
||||
|
||||
typingStatus = gtk.NewLabel("")
|
||||
box.Append(typingStatus)
|
||||
|
||||
window.SetChild(box)
|
||||
|
||||
window.SetVisible(true)
|
||||
|
||||
@@ -61,3 +61,15 @@
|
||||
color: white;
|
||||
background-color: red;
|
||||
}
|
||||
|
||||
.RedGreen_CVD {
|
||||
filter: hue-rotate(30deg) saturate(120%) contrast(110%);
|
||||
}
|
||||
|
||||
.Blue_CVD {
|
||||
filter: hue-rotate(30deg);
|
||||
}
|
||||
|
||||
.None_CVD {
|
||||
|
||||
}
|
||||
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"image"
|
||||
"image/png"
|
||||
"github.com/srwiley/oksvg"
|
||||
"github.com/srwiley/rasterx"
|
||||
)
|
||||
|
||||
func SVGToPNG(svgData []byte) ([]byte, error) {
|
||||
// Parse SVG
|
||||
icon, err := oksvg.ReadIconStream(bytes.NewReader(svgData))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse SVG: %w", err)
|
||||
}
|
||||
|
||||
w := int(icon.ViewBox.W)
|
||||
h := int(icon.ViewBox.H)
|
||||
if w == 0 || h == 0 {
|
||||
w, h = 100, 100
|
||||
}
|
||||
|
||||
// Rasterize into an RGBA image
|
||||
rgba := image.NewRGBA(image.Rect(0, 0, w, h))
|
||||
scanner := rasterx.NewScannerGV(w, h, rgba, rgba.Bounds())
|
||||
dasher := rasterx.NewDasher(w, h, scanner)
|
||||
|
||||
icon.SetTarget(0, 0, float64(w), float64(h))
|
||||
icon.Draw(dasher, 1.0)
|
||||
|
||||
// Encode to PNG bytes
|
||||
var buf bytes.Buffer
|
||||
if err := png.Encode(&buf, rgba); err != nil {
|
||||
return nil, fmt.Errorf("failed to encode PNG: %w", err)
|
||||
}
|
||||
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
@@ -20,6 +20,7 @@ type lambdaConfig struct {
|
||||
Nick string
|
||||
JoinBookmarks bool
|
||||
CVD color.CVD
|
||||
Identicons bool
|
||||
}
|
||||
|
||||
type mucUnit struct {
|
||||
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
package main
|
||||
|
||||
var lambda_version string = "26w11a"
|
||||
var lambda_version string = "26w15a"
|
||||
|
||||
+13
-8
@@ -5,17 +5,22 @@ import (
|
||||
"gosrc.io/xmpp/stanza"
|
||||
)
|
||||
|
||||
// Experimental implementation of XEP-XXXX: Explicit Mentions
|
||||
// https://git.isekai.rocks/snit/protoxeps/tree/explicit-mentions.xml
|
||||
// Implementation of XEP-0513: Explicit Mentions
|
||||
// https://xmpp.org/extensions/xep-0513.html
|
||||
|
||||
type NoPing struct{}
|
||||
type Active struct{}
|
||||
|
||||
type Mention struct {
|
||||
stanza.MsgExtension
|
||||
XMLName xml.Name `xml:"urn:xmpp:mentions:0 mention"`
|
||||
URI string `xml:"uri,attr,omitempty"`
|
||||
Begin int `xml:"begin,attr,omitempty"`
|
||||
End int `xml:"end,attr,omitempty"`
|
||||
Type string `xml:"type,attr"`
|
||||
Target string `xml:"target,attr,omitempty"`
|
||||
XMLName xml.Name `xml:"urn:xmpp:mentions:0 mention"`
|
||||
URI string `xml:"uri,attr,omitempty"`
|
||||
Begin int `xml:"begin,attr,omitempty"`
|
||||
End int `xml:"end,attr,omitempty"`
|
||||
Mentions string `xml:"mentions,attr"`
|
||||
OccupantID string `xml:"occupantid,attr,omitempty"`
|
||||
NoPing NoPing `xml:"noping,omitempty"`
|
||||
Active Active `xml:"active,omitempty"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
||||
Reference in New Issue
Block a user