From 71e6a58fbdc90f65950e0fd3c41466195a86fd7f Mon Sep 17 00:00:00 2001 From: sunglocto Date: Sun, 15 Mar 2026 09:55:26 +0000 Subject: [PATCH] ban, kick and change role&affil menu, status icons in muc, blocking avatars that are invalid so we dont fetch them over and over again --- assets.go | 64 +++++++++++++++- assets/status_away.png | Bin 0 -> 794 bytes assets/status_busy.png | Bin 0 -> 751 bytes assets/status_chatty.png | Bin 0 -> 1213 bytes assets/status_online.png | Bin 0 -> 722 bytes assets/status_xa.png | Bin 0 -> 1117 bytes cache.go | 2 +- failed_load.png | Bin 5578 -> 5680 bytes gtk-helpers.go | 162 ++++++++++++++++++++++++++++++++++++++- main.go | 31 ++++++-- types.go | 4 +- version.go | 2 +- xmpp-mentions.go | 13 ++-- 13 files changed, 256 insertions(+), 22 deletions(-) create mode 100644 assets/status_away.png create mode 100644 assets/status_busy.png create mode 100644 assets/status_chatty.png create mode 100644 assets/status_online.png create mode 100644 assets/status_xa.png diff --git a/assets.go b/assets.go index a737c0f..16cbfa9 100644 --- a/assets.go +++ b/assets.go @@ -39,6 +39,27 @@ var outcastMedalB64 string = base64.StdEncoding.EncodeToString(outcastMedalBytes var cancelBytes []byte var cancelB64 string = base64.StdEncoding.EncodeToString(cancelBytes) + +//go:embed assets/status_away.png +var sABytes []byte +var sAB64 string = base64.StdEncoding.EncodeToString(sABytes) + +//go:embed assets/status_busy.png +var sBBytes []byte +var sBB64 string = base64.StdEncoding.EncodeToString(sBBytes) + +//go:embed assets/status_chatty.png +var sCBytes []byte +var sCB64 string = base64.StdEncoding.EncodeToString(sCBytes) + +//go:embed assets/status_online.png +var sOBytes []byte +var sOB64 string = base64.StdEncoding.EncodeToString(sOBytes) + +//go:embed assets/status_xa.png +var xaBytes []byte +var xaB64 string = base64.StdEncoding.EncodeToString(xaBytes) + //go:embed assets/tag.png var tagBytes []byte var tagB64 string = base64.StdEncoding.EncodeToString(tagBytes) @@ -104,7 +125,6 @@ func init() { loader.Close() clientAssets["DefaultAvatar"] = gdk.NewTextureForPixbuf(loader.Pixbuf()) - loader = gdkpixbuf.NewPixbufLoader() failedData, _ := base64.StdEncoding.DecodeString(failedB64) @@ -272,4 +292,46 @@ func init() { loader.Close() clientAssets["information"] = gdk.NewTextureForPixbuf(loader.Pixbuf()) + + loader = gdkpixbuf.NewPixbufLoader() + + sAData, _ := base64.StdEncoding.DecodeString(sAB64) + loader.Write(sAData) + loader.Close() + + clientAssets["status_away"] = gdk.NewTextureForPixbuf(loader.Pixbuf()) + + + loader = gdkpixbuf.NewPixbufLoader() + + sBData, _ := base64.StdEncoding.DecodeString(sBB64) + loader.Write(sBData) + loader.Close() + + clientAssets["status_dnd"] = gdk.NewTextureForPixbuf(loader.Pixbuf()) + + loader = gdkpixbuf.NewPixbufLoader() + + sCData, _ := base64.StdEncoding.DecodeString(sCB64) + loader.Write(sCData) + loader.Close() + + clientAssets["status_chat"] = gdk.NewTextureForPixbuf(loader.Pixbuf()) + + loader = gdkpixbuf.NewPixbufLoader() + + xaData, _ := base64.StdEncoding.DecodeString(xaB64) + loader.Write(xaData) + loader.Close() + + clientAssets["status_xa"] = gdk.NewTextureForPixbuf(loader.Pixbuf()) + + + loader = gdkpixbuf.NewPixbufLoader() + + sOData, _ := base64.StdEncoding.DecodeString(sOB64) + loader.Write(sOData) + loader.Close() + + clientAssets["status_"] = gdk.NewTextureForPixbuf(loader.Pixbuf()) } diff --git a/assets/status_away.png b/assets/status_away.png new file mode 100644 index 0000000000000000000000000000000000000000..70bcbccaae628be58539faefbc6a72a8136de45d GIT binary patch literal 794 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7SkfJR9T^zbpD<_bdda}R zAX(xXQ4*Y=R#Ki=l*-_klAn~S;F+74o*I;zm{M7IGS!BGfoYAWi(`nz>DEc{9>Iko z$JuRN`7bX1BGl3n;x^+c$3}5uVYf?%Icft|v>nk9*zDu8(Vk0p-tCh)q?lAwk@5Ob`YxubtUcc8_q3)&S zlDBoidH;KFKTdRIa+-VSt>(>DW!@VdUd0>jIyB?sn&eZm2XFAO#&s8GMxUEJX-PxT zvSOb%fA;k8>q%9mOFUzhDk>I`Of4!6a!6j^Kj&Lcm%5CJ$u@y0mqm`HYl@gfom|qe zD^K3@jJrW1zq71(yMa%DMC!2<>y;-lbG`P>T58I1*``;JyVWsxO*Myp>FOKvuFtG# znadh$>dK^TYbD%t#pBV|I^LqDne*+XQr|u@|1VxJWBub#t$MS6yp?fr=FXTQVbuWIwV z#<28>T1%+<+t4{*?$|Tj6t!BIQ^Xs_fA)u5(?wC{3lcA;A6k{$o|h%4^_i=Ur|!hp zGMlxwqE_>3AGk0D+)63$x!oKP<tgDUDAW0X#MP%q^0t;QS~wl zlJXq$)C%|ik+DkEs^M~ZJR#ytednXX|_D BUkCsI literal 0 HcmV?d00001 diff --git a/assets/status_busy.png b/assets/status_busy.png new file mode 100644 index 0000000000000000000000000000000000000000..987c806fff759fafe2a221a8d1eba225a3ace560 GIT binary patch literal 751 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7SkfJR9T^zbpD<_bdda}R zAX(xXQ4*Y=R#Ki=l*-_klAn~S;F+74o*I;zm{M7IGS!BGfvM5c#WBRNYd!F{$r~h+~-(8tkg|jNl&Yf#}a=BVf$0$?Zru_Zq>VNSp43=wdnJrtmQ$NR; z=V;4vx40GN2HTwGZhW|6zxyoSWjET?ryQtJX}wt>^!T%q)b3{KovWtvMl$keY)ax= zx7(nBsagUw2ZZG_z;C*PbVdcp7nckx8#&nXVaTH>2h{aR`rTedZeZeohM|Cwp? zoFgjJ8+3E08Jy|ZaLLSMtxs9QwzJurHxyP(Pwn~PQu9&krI4LPz0&$Lg=%i~toz%p zNJreX(m(h_@WaWi+{VtouSb7B;aPjVo^kqDzq$L&pS=ISt7TulcEvZtF7@|H6^1(+ zGEy+k3HJ>nB&s>E-{b3 zGlGkLatB;|^XBiLTJap0W!2LkaB4D0UY?u3A*zP0=BjDV{lMhtYT@kb-Wy9+G1NI- zkvwqsdCY-xM-xACN~F8`Tr3G!nCSN`G<@UIl}D;PIj?nfZ**0>_^CUA^X5s0FMAVj z%1*doeYzO9-=JxNv03 z?cOU_LfrnWb!PagoWJ6}(BTQn)7W}0MjM>xc<|}d#;`ihjkm9Mh>0#edOcJ*rYw%} z&yUT0MU&OypTEj{^~k`fw`{*hyXJvgxknzoWLk4+-qcM~pM03QrER|DNig)WpGT%PfAtr%uP&B4N6T+sVqF1 zYQw<5*q#{@Q4-ls47YguJQ{>uF6ifOi{PDa#8#=aG&992EiuhBDJ8{J zH!0CLMc2?UB~dpq#n@0c#n?E-+|wW*Wl&ykclDB|GN53Bhi+I_t0J>aGIND&o5JM6=jIvdVY&buN?( zx44re*lg!{=k~n|ZZm2=#2Wr-R+ZNa{ao{vnZYUd+{KI=uL@5wg*YwD5aEkF(CHlK zAFg2#b^1EzESVq|BhC|=B1afH&TR-aNSJJ~<#)95)|$BsmN2#*bSPm<%JD8?zM#2a z+Lx$3aRR^RbftF&TCqcR_m(36|)+h zW+pw#^9hgF-?R4Vf6s;0Isd*Cm{cg@wSXPM3 zKkYS3_4)HIeC3t-bKZV#vx=IVQ4l5gA>zWjZ3hy!FS_~oz&?j&*P=D@7T2{mzWn)g z`U<;)snd_QRozXTuJfS!9D@Wy!2+HOC2bX}crL0uxbU7L_SUG_=GrAK4Q3wZ z3opy&IDTa8+xb3Wf4=A*RgQB~O#1Em!RtO|x(29Oxl0`QEYo8@+w@R?nuzz$$3Lch zW_X}=wt{iZ7RyM%n%L9pjt6t)i19Hb1aO^Qpdrk)sJJ3thAlYkzzVJxS{Y@m2|J=Z z6&=~am+za<6q;bWuuR%TnBOts0fWSpgHDe*I=WBfo-urKf5jiZ-JO@aCf|O&YSq&# zSKKz=Ui!Xd#@bbU(OQcYz6NX0`Dm{`*SE0BaF+mELy}o}r&P{QbJmk4Ta7oo5(bqO Mp00i_>zopr0RQafp#T5? literal 0 HcmV?d00001 diff --git a/assets/status_online.png b/assets/status_online.png new file mode 100644 index 0000000000000000000000000000000000000000..947bd4b62c310bd4b02f4df393b801ff055da86c GIT binary patch literal 722 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7SkfJR9T^zbpD<_bdda}R zAX(xXQ4*Y=R#Ki=l*-_klAn~S;F+74o*I;zm{M7IGS!BGfhon)#WBR2cS;=HQ6o}P3r<53Y1{NK>g@giXRt`J{equFbVF*tEDg!o^d2NzM$JZOjJl2i6p3bhRA$ z*Y~B5C6v2>BgI%tuY=+1r-|3IrdED?Dw+7Md!F_TGp9{0vvdQN2006bg-NExoqt}Y zaw5gv|Nh*lRZ^mTT~DVq3-uN}PV5U!+x%Yo_tLY5-+WTqfA<|-H|NEaNpo!e8!;t_ zB%7ot9niHowN5O~uAoX@iVZ_a5BUBS{nXFf(`nY(^FzF_UuUQY$S2$xL@t_v(G(c>xGs#N)6 zQaXF=Tiw5B6Xol~bD6lAf_7?t_?oY%QWI-*@!l#0iEjCi0vWR|X?oi|3D+tOJ>Hw2 z%;NU4kWV6;XVZQD$iVW-vV=&VMMpI9InT8jDHrsvyQpSTe!Q^TCB~?~`RJaH#g66+ zO+CNXx9`$vzs`BbdC|v-H>8iWzfTR}I%>*)utd$?&T3~x`m0>VrYp@)mUyxqDseIT zS@QkElcQXDc4wt4%*(58TNlJ1-}(IX$A~F!J5MC;it*K-ap8Z|(xQ7m+9ySd%s=-n d=iPt)@TDfx^}al?VPIfj@O1TaS?83{1OStvM+X1^ literal 0 HcmV?d00001 diff --git a/assets/status_xa.png b/assets/status_xa.png new file mode 100644 index 0000000000000000000000000000000000000000..0e3768fdd6cb3e00d242310520332987a7a21457 GIT binary patch literal 1117 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7SkfJR9T^zbpD<_bdda}R zz**oCSR|DNig)WpGT%PfAtr%uP&B4N6T+sVqF1 zYQw<5*q#{@Q4-ls47YguJQ{>uF6ifOi{PDa#8#=aG&992EiuhBDJ8{J zH!0CLMc2?UB~dpq#n@0c#n?E-+|wW*Wl&ykclDB|GN53Bhi+p!Nw`oho3NABEwF|1Uzm#{eZQ7Q- z%umwkddbI>7xgD@tejxF=#)^wTL&gT>E)eWO03%7on?bK!(TBTyt?yz?UAe1(>~0X z;$geJdi84SX{lc&k}d4*zt`TEmy?mH(c4tC(NKbCTkQ3}FLtfVzFoHTVn#^R+H1z1 zli~!O>gLXwQxpAU=}~cp0-5ym+}yKjEe%0jUYZ<=H*Vb6aQ*uA@~#@s4SV+72@VzY zoaDg4c+T?O`}YeorDmN?TYq9Y%bemRnOx^AEuITFJ>g%vrDHnlk&5_x36tk=7IZ- zNj;50T#76yk!`7wGyIl!JpS=ty7j#UpNMOtitVq>nl^TJZOgTe~DWM4ftM$V~ literal 0 HcmV?d00001 diff --git a/cache.go b/cache.go index 267ca68..73ff099 100644 --- a/cache.go +++ b/cache.go @@ -19,7 +19,7 @@ import ( var textureCache = make(map[string]gdk.Paintabler) // Invalid images, if an image/avatar cannot be loaded on the system (e.g: incompatible format) it's put here -var invalidImages = make(map[string]bool) +var invalidImages = make(map[string]bool) func ensureCache() (string, error) { cachePath := configdir.LocalCache("lambda-im") diff --git a/failed_load.png b/failed_load.png index 291626c5acfdcec136495e0626bfe5204a858e1f..24a42d3d947dd82e96da6f7dde4ccf890ea7de63 100644 GIT binary patch delta 5240 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 delta 5138 zcmdm>b4q)|3&wikGoCJvAr*0NqqB2lu9yBhH}|;Rj+lu`nqB&nw`6t-J#BY6z3EXz zsZjJsZG#6FHpy~w@~BS}+TqGA;#t2$pyglY|1a*{H#D;rXGkyK^!SRyD;1AhTedx1 zBA9cuH|Nx}9PedvD%0<%?%cfF*t$6V-An#+clE-jI9=qru;pJvcfI7fd)3e9yq{An z|D3O}|D&PZvEx7Ld9rE>R0}^ma4dXrK{53In~lfiqO)(8aT_mh6;NZ)Sn8xy)GBZ^ zzxH)>>#tv@zZR-~ysgy0u;E|w|9^k48x@N;=p8m_WB6k5IZDZkk-@my#f1Gqjfm@e z<{3d=zV?5=Tvpe=_I&E0{BDMNh6CaIe_ee&^QW59F3AI-A0IO`C@FuResc2e99p{4=!Tz?TYxdpO?!3>%*l+tSVtMZE?}ne#J66n{sqLb2*dXQn=LoNp zXU=$O9#dj;aY>03TN4t@rnT{N?54Kda;acG>;;;Ji(T`(?>3 z0jDimOSxRW918Zg{d)duu07W}2}X84nTi=5a*PU7g8Cj?MC>lpy<7MDt&NqH*WbT? zeOyFX7@HIxuyIckX!5<>l6(8e85=`GNB4fYr_W^%PMt&iNy=G39XaP-XoFK_ef ze-|`!tZu5m_#?se#{T;Mb6viuDz*r^P7KzXnsK;|cT4&ExO-c(#kX$TmQ+_Kx9;_% zDMDv_&a7E~(`NSksx)kAaT{{8dKa&8ZZrmQo#~ES|9_qS z3S~xyRado&cFNqkeLM4h{k~coBO|B2#|<4`E?2k{^5<%-KIE?S;6NkueAa^IM2V+C zD@Dr6%P-%!A+deSmH@r!&H^kh?`tni*-?32`P;YK`x0vY&R*=L=@Pi*$gMLxU&H<5 zyv^@@>aeVOEq@>5p6#_XC_}<+W=CF6YJ_QhnD2qd z{q}i=pXWMtEO}nJF8B7MKI?Z6-o4A4HGh7(rYiG;53d@#cBTH-WLR*$&hEteJ=c~^ zagt~=J>8zj@$pc%GQ)zrn{`^dsy3{-&SA)DV{YF5?p@xkz18Nox9QrPFK!j^OxySQ z<8k@zQct5b!+aSUVx2nXX>`?Ss+#59>8QVWF|cAD`}I=swNktHlt0kU-<<3DqcQc* z-*Pk8z?NT0b&qE+eljJ<<3^C($E(|C?EE(So5cCg4=Uxh<=yRi_%P8!Q_yvye#;BS z4XXopOijAV!l76u6u9|$WnOUb+t0ABP{9rP_xGtWygj2cC1};!wY-1-{*751_OMcJO3<1qk2Ja>qBni| z&3%L0N+4;!qBnx@Le#>UXF>gp?@?N`HNSM|TC0(ek!lrbpEm0z3nrc;jRh31TQizsl?$4@)+1E(h*OWZu?f*bx8gV%q2Ux*dWH zPp0{%pDwSd3i67~FLenFdAj++BLcohdjg3v?-CEM^|9hsxb6}|zQsc&aane--p z-@R!Tzn)#)rTqHu<=3>2Wy+*O23IyW{_9;-k#=B_;fxLzhRtyYrY3D= zX*siIi$LI;XT8mFd!K&!J8Sv>JQ0RJzS8G^HUGWLFyZGx?`WyluP@z5|7(2YiScG8 z0X@;e)Cf_=Gcjt595@sgX(U}Qjr8JND&noV(^2qRbM))Y?d@+)zBJpWYx(zvc>Vo3 z)jtl#GdD!eIKS=RS>xG{c1;M%;$OA(>h&M81+mi?Yb0%);m0*&=N(88w+L9Km9+|_ zNwmf2hzYhS&X}1LzD`h}O|do6<6670ude-%i@gj1yFRvE&dc{teb}a3yj1qKKa<0^ z`~Q-U*nCY)+qun9Qe`QNV4y@>$NiJ_P8`P5QbS*E3Kev4dC#aZb6KYL(koA%sAw)t zh!ji8*40duSoBz)KVCg0qt!R_{TJbW`Cic@U;cjIw^}EdOEOCKzU3a(E+rPnfb7-3 zxep5@N*pra(O4?5KX~S{OlFOv;B?H;@O|b@Qyyi_r6JGH&264CiTCh@X{*bVx9qF` z6czsM?c;D}hkuv%o3ES7b6DW%yRTD!&d#^uWH_7O8$b8&_wZe>_b!;nvQ&iUaKn^I zkIPqCI6h*k*dKUeYC5*Ik=GZ)PrY!^!h?&(<2; zV>53%dFAfz`z#G#&g4Wt@BhEmp2ztb%g=r1y)>5uX?kcH+S&2l|2{SM_DhSW>x_?1 z@8$j+qtLgc%Q6feeZTekWFoIz-?WCOVX>^NZ2h)dk2iBK-C^?L!NF!G z20mG|}EvCW$|Ta>+#IAoA=dQ%R=x+$Mp!tAEK-PBWMIW;@;&F^=+^>c53 zySps&-n_GEw0dW#^G%&kKW((8axpd}O6asGgqF)J3;f?B z-l)-~(6S&zt95Jk^`f0I%dXeQRr6lHd^sa4D@n0sMcC>B8Fl%#ho>C{{`^=vJ+4SP z^{?-aH)}rJxDny6H1P+s;*q^BQ-ZusR+Oln-n3!EhK8h#9oMdft%=<&#^BNaAjoSj zANwnz1zP81GT$FiN<5Kbw59BA)S2_=AD@`0Y+`EK8luITw(Q3iPs8HX0!h1bZ`U`^ zHp{Jg|KsE1rAvk4rKY@29Dc*6JSZEetny$@P`M@{C!-C|0Zd06ZqUAa* zHSu_#Y{~W5@<4BI?)i4LQv2R7Ub&LFVlws0e9@a8>;O`@QhZ4MUM`*Cm%TE9SYowA{|y&1+r$PUWyc zMp4nE*z5J7oi2xz7x^jes!K^pNvf%-Sryp+bb}I;T-A$(*$jUS1=ogqJ(WG~SY2&> zxBC6w9k18zzHs+$@3(JdNohWQeuqk9mt4+lN$gm;QuEB&vsW)gTCKbM(j?VLa>?b) z8{2%HI4b6~$LO^ir=NRpxBULmBS%;m4s6SvaynIIvgfUx#r5iWJD-ZZdinBU_WHeI zGkw^CgM&@X&5v)(-R;!D$1r<)&dpEXe*E}RvskZp#}x$+hKl$1_TDt$`Ok8|*K6g> zpp`DQwY4Sx|9=1c;e)}cr$#&1ao^sSc-zeG#{=d+kHq&sD1LrUajMtBZMj|HwR8NI zYtBBqXyr=IZMlaH#D4Zanp(f`^{$ABh=lW>7o6v8R%m!$dFS$F=k52ZwAU(B9!Z_iIbhH|DE z+S5ds~~v{PV#pLsqSQ!LVTUYVO+FS_5CA3QkN{Ag-; z+(X;yZ#jyK^qCaye{XhCaxA}JYo32^&&;&?w6p-NsRz#ZxO6PH_*N^gtE(#^Bjb{u zu5L7wM{6pV%yCB%R|Ta_xwC^;ibPI3x-IwhdzLTT#1kbJEnUibJ-*(y?A@Ktwb9#^ zX8If|l$jKCjqQQ~PvF|HlizEXTHI#@ZN&&{jIIsyUX9JT`#RnOmsZ|UR*@!QHoJ#j#;+?hsHJo>pthp zmoLwlF{9z0EmOl3At#P6-@hmS{q=QE+F7YBTed9NyLWER?Y74jGAsutwT6UDmq<+8 zvSmww)!b$C|9x5h=hf=(Wn<$aYuqJD( z)Vk>HeB1AqNv9e~&YL+?@$IK7zU$$A{&iD>R)lCVIOOK$zIgM-rM})i_ud}KAg?(V zg-lbuSl7K);&HxH^?L1&=kux!EG#*}SZD=nDb zVbP^@E^YIR7cUwFnrzOm-di%WbdOk1$;JJyfi8WI73QB;o_%)F>ebv;4=-Q6+Uld$ zTw~Xtv~k7c#ZP|Qt-8AEUH;AQul_y0+0-I%<>JN09J6kXt{EK>92ak|n15`OqJf#& zHN}=2zAkg;J#XE+ckiCe%W7PQC!Bt2^s@fP<#qAz|9!N*e)sjSHB*$7ni3^G*zmvK z`(3U@;KvblyT*I>;-;KVt(X^no9(rYgUy4ho6hcf@#DIY#!`!Ut{U^tFAmU{kb9e{ zVSnc3Wsi^d%U`c;@IG|w8=;9@XZ{tk2e=G zU66lW!Z=N}p(E(b9ijJUZ<_cDIZb%~+iHJ&xBc6;Ssg#}Kh@5!xxaqrx_#?Iv_9DI zce*gmojVtlVw5I2EDds88nm*t|NZZf3@zU2|g{7Jbd_YNBHC!^XFf` zcWBp@@8RqB#QeGNs!3_-69b+|&7)OQC0{4R>)g?IV-Uy>{~GFV-kWzl;+5{=*oess z_PVwoJaB-4jg2i}ZCGHvj#&2o*SmJ*&TUnkZfUbp|7-GLuYy3P9qZWB(rPmVSs1gs zU#;FYVOv!#&+c`nuVzi%dsN@u;v0jWShoRBGw9)Vag`E zcN2ZoCVHq$@K8yJyvF)g>UaFQBi7z;8NI`HiYq7HT>9ZKzkQ9cv3%0AtffIK-`&{Q zyedkMx@mPfvF{75%BCl%zE4eCayfI)zhAFQ zo}3WO%gXW+3Y^rzCudjlqgPcnuBl;dz1PZS1|`kZt*cja&z(D0WogcuT{^E=S1oNx zJ~%xjhD|2D?MhPHk4?8PJqmw*;%SkMsVVE}O_LaS6pt)C+|IxM=8d$Qe#eg;W8*#i zgU$Fmm!j9c_p22+rl}Z(H$PpoOJ?1X>PG>>UMtg-ti)X}#_#!XhpztB%*>e_s;hr@mRP;zRJ_%(VrGZX7LLc| z3vRe9>B#WX{Q7t1%$e`~eSCCY*PX6%_-n7#+uO@KYuQbv11si7{WDkoSE9ysxWIAu x-_-w~r`j?8+TZZsdsj_Q|3|}hI{&20h4xkS`&NBoVBlh4@O1TaS?83{1OPrt?V|ty diff --git a/gtk-helpers.go b/gtk-helpers.go index f6b5e11..033ebbb 100644 --- a/gtk-helpers.go +++ b/gtk-helpers.go @@ -3,6 +3,7 @@ package main import ( "context" "fmt" + "github.com/diamondburned/gotk4/pkg/gdk/v4" "github.com/diamondburned/gotk4/pkg/glib/v2" "github.com/diamondburned/gotk4/pkg/gtk/v4" "github.com/diamondburned/gotk4/pkg/pango" @@ -82,7 +83,7 @@ func switchToTab(jid string, w *gtk.Window) { nick_label.SetOpacity(0.5) } - userbox.SetTooltipText(fmt.Sprintf("%s\n%s\n%s\nRight-click for more information", u.From, mu.MucUserItem.Role, mu.MucUserItem.Affiliation)) + userbox.SetTooltipText(fmt.Sprintf("%s\n%s\n%s\nClick for more information", u.From, mu.MucUserItem.Role, mu.MucUserItem.Affiliation)) userbox.Append(nick_label) var hats Hats @@ -95,6 +96,13 @@ func switchToTab(jid string, w *gtk.Window) { } } + status := gtk.NewImageFromPaintable(clientAssets["status_"+string(u.Show)]) + status.SetTooltipText(string(u.Show)) + + status.SetHAlign(gtk.AlignEnd) + // medal.SetHExpand(true) + userbox.Prepend(status) + medal := gtk.NewImageFromPaintable(clientAssets[mu.MucUserItem.Affiliation]) medal.SetTooltipText(mu.MucUserItem.Affiliation) @@ -103,7 +111,145 @@ func switchToTab(jid string, w *gtk.Window) { userbox.Append(medal) gesture := gtk.NewGestureClick() - gesture.SetButton(3) // Right click + gesture.SetButton(1) + + mod_gesture := gtk.NewGestureClick() + mod_gesture.SetButton(3) + + popover := gtk.NewPopover() + popover.SetHasArrow(false) + popover.SetParent(userbox) + + rc_box := gtk.NewBox(gtk.OrientationVertical, 0) + bb := gtk.NewButtonWithLabel("Ban") + kb := gtk.NewButtonWithLabel("Kick") + ab := gtk.NewButtonWithLabel("Set affil") + rb := gtk.NewButtonWithLabel("Set role") + + kb.ConnectClicked(func() { + client.SendRaw(fmt.Sprintf(` + + + + + + + `, clientroot.Session.BindJid, jid, JidMustParse(u.From).Resource)) + }) + + bb.ConnectClicked(func() { + var mu MucUser + ok = u.Get(&mu) + if ok { + if mu.MucUserItem.JID != "" { + client.SendRaw(fmt.Sprintf(` + + + + + + `, clientroot.Session.BindJid, jid, JidMustParse(mu.MucUserItem.JID).Bare())) + } + } + }) + + ab.ConnectClicked(func() { + var mu MucUser + ok = u.Get(&mu) + if ok { + if mu.MucUserItem.JID != "" { + win := gtk.NewWindow() + win.SetDefaultSize(400, 1) + win.SetResizable(false) + + box := gtk.NewBox(gtk.OrientationVertical, 0) + box.Append(gtk.NewLabel("Set "+JidMustParse(u.From).Resource+"'s affiliation")) + + the_entry := gtk.NewEntry() + the_entry.SetText(mu.MucUserItem.Affiliation) + + submit := gtk.NewButtonWithLabel("Submit") + submit.ConnectClicked(func() { + client.SendRaw(fmt.Sprintf(` + + + + + + `, clientroot.Session.BindJid, jid, the_entry.Text(), JidMustParse(mu.MucUserItem.JID).Bare())) + win.SetVisible(false) + }) + + box.Append(the_entry) + box.Append(submit) + + win.SetChild(box) + win.SetVisible(true) + }} + }) + + + rb.ConnectClicked(func() { + var mu MucUser + ok = u.Get(&mu) + if ok { + if mu.MucUserItem.JID != "" { + win := gtk.NewWindow() + win.SetDefaultSize(400, 1) + win.SetResizable(false) + + box := gtk.NewBox(gtk.OrientationVertical, 0) + box.Append(gtk.NewLabel("Set "+JidMustParse(u.From).Resource+"'s role")) + box.Append(gtk.NewLabel("Important: if you want this to be permanent, set their affiliation instead")) + + the_entry := gtk.NewEntry() + the_entry.SetText(mu.MucUserItem.Role) + + submit := gtk.NewButtonWithLabel("Submit") + submit.ConnectClicked(func() { + + client.SendRaw(fmt.Sprintf(` + + + + + + + `, clientroot.Session.BindJid, jid, JidMustParse(u.From).Resource, the_entry.Text())) + }) + + box.Append(the_entry) + box.Append(submit) + + win.SetChild(box) + win.SetVisible(true) + }} + }) + + rc_box.Append(bb) + rc_box.Append(kb) + rc_box.Append(ab) + rc_box.Append(rb) + + popover.SetChild(rc_box) + + mod_gesture.Connect("pressed", func(n_press, x, y int) { + rect := gdk.NewRectangle(x, y, 1, 1) + popover.SetPointingTo(&rect) + popover.Popup() + }) gesture.Connect("pressed", func(n_press, x, y int) { win := gtk.NewWindow() @@ -218,8 +364,13 @@ func switchToTab(jid string, w *gtk.Window) { version := ver.Version os := ver.OS - ver_text.SetText(fmt.Sprintf("%s %s %s", name, version, os)) - ver_text.RemoveCSSClass("visitor") + vr := fmt.Sprintf("%s %s %s", name, version, os) + if name == "" && version == "" && os == "" { + ver_text.SetText("Client responded with empty version") + } else { + ver_text.SetText(vr) + ver_text.RemoveCSSClass("visitor") + } } else if result.Error != nil && result.Error.Type != "" { ver_text.SetText("Got error trying to get version") ver_text.SetTooltipText(result.Error.Reason + ": " + result.Error.Text) @@ -262,7 +413,10 @@ func switchToTab(jid string, w *gtk.Window) { win.SetTransientFor(win) win.Present() }) + userbox.AddController(gesture) + userbox.AddController(mod_gesture) + if mu.MucUserItem.Role == "moderator" { gen.Prepend(userbox) } else { diff --git a/main.go b/main.go index 7c5401c..b285cd5 100644 --- a/main.go +++ b/main.go @@ -1,8 +1,8 @@ package main import ( - "strings" "os" + "strings" "sync" "context" @@ -188,8 +188,6 @@ func main() { return } - pretty.Println(m) - e := stanza.PubSubEvent{} ok = m.Get(&e) if ok { @@ -211,6 +209,15 @@ func main() { beeep.Notify("Attention", fmt.Sprintf("%s: %s", JidMustParse(m.From).Resource, m.Body), commentBytes) // TODO: Use localpart if DM } + // Handle mentions + for _, ext := range m.Extensions { + mention, ok := ext.(*Mention) + if ok { + pretty.Println(mention) + } + + } + sc := new(SentCarbon) ok = m.Get(sc) if ok { @@ -492,7 +499,7 @@ func main() { } }) - go func() { + conc := func() { time.Sleep(3 * time.Second) connectionStatus.SetText("Connecting...") connectionIcon.SetFromPaintable(clientAssets["hourglass"]) @@ -503,10 +510,13 @@ func main() { connectionStatus.SetText(fmt.Sprintf("Disconnected: %s", err.Error())) connectionIcon.SetFromPaintable(clientAssets["disconnect"]) } - }() + } app := gtk.NewApplication("net.sunglocto.lambda", gio.ApplicationFlagsNone) - app.ConnectActivate(func() { activate(app) }) + app.ConnectActivate(func() { + go conc() + activate(app) + }) if code := app.Run(os.Args); code > 0 { os.Exit(code) @@ -870,8 +880,15 @@ func activate(app *gtk.Application) { } if strings.Contains(t, "@everyone") { + start := strings.Index(t, "@everyone") + end := start + len("@everyone") + new_mention := new(Mention) - new_mention.Mentions = "urn:xmpp:mentions:0#channel" + new_mention.Type = "urn:xmpp:mentions:0#channel" + + new_mention.Begin = start + new_mention.End = end + exts = append(exts, new_mention) } else if strings.Contains(t, "@here") { new_attention := new(Attention) diff --git a/types.go b/types.go index f4204d6..4500488 100644 --- a/types.go +++ b/types.go @@ -2,6 +2,7 @@ package main import ( "github.com/diamondburned/gotk4/pkg/gtk/v4" + "mellium.im/xmpp/color" "sync" ) @@ -18,10 +19,11 @@ type lambdaConfig struct { Insecure bool Nick string JoinBookmarks bool + CVD color.CVD } type mucUnit struct { - // key: OccupantID + // key: Resource // value: last user presence Members sync.Map } diff --git a/version.go b/version.go index 069a1a6..a838089 100644 --- a/version.go +++ b/version.go @@ -1,3 +1,3 @@ package main -var lambda_version string = "0.1.0" +var lambda_version string = "26w11a" diff --git a/xmpp-mentions.go b/xmpp-mentions.go index 7344a18..29dde9e 100644 --- a/xmpp-mentions.go +++ b/xmpp-mentions.go @@ -10,13 +10,12 @@ import ( type Mention struct { stanza.MsgExtension - XMLName xml.Name `xml:"urn:xmpp:mentions:0 mention"` - Mentions string `xml:"mentions,attr,omitempty"` - URI string `xml:"uri,attr,omitempty"` - Begin int `xml:"begin,attr,omitempty"` - End int `xml:"end,attr,omitempty"` - OccupantID string `xml:"occupantid,attr,omitempty"` - JID string `xml:"ji,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"` + Type string `xml:"type,attr"` + Target string `xml:"target,attr,omitempty"` } func init() {