24 Commits
Author SHA1 Message Date
Sunglocto 23288e3dfa minor spelling mistake (world implodes) 2026-08-23 20:36:42 +01:00
Sunglocto 6d95c8419c add hiatus note 2026-08-23 20:35:28 +01:00
Sunglocto a31d9e766d Add april fools joke 2026-03-31 07:39:06 +01:00
Sunglocto 542ade77b2 Modify corrected message appearance and make notification text less insane 2026-01-25 16:45:42 +00:00
Sunglocto 183ec02918 set notification title to pi 2026-01-13 16:59:32 +00:00
Sunglocto 881b72cb15 Add experimental stanza sender and allow sending empty messages upon confirmation 2026-01-12 16:36:05 +00:00
Sunglocto 4d0e29550c Use better notification lib 2026-01-11 09:12:13 +00:00
Sunglocto b926173f43 Merge branch 'master' of https://forge.sunglocto.net/sunglocto/pi-im 2026-01-11 08:54:27 +00:00
Sunglocto 2667b0ccfd Colored nicks 2026-01-11 08:54:13 +00:00
Sunglocto 3aa8054dc0 Fix AUR link (oof that's embarassing, it's been like that for months) 2026-01-10 15:16:48 +00:00
Sunglocto ad9a0ea9a8 fix app icon 2026-01-10 14:56:28 +00:00
Sunglocto de40a5dec8 changes to follow 7bab52f033 2026-01-10 14:44:27 +00:00
Sunglocto 78c7f0175d changes to follow 7bab52f033 2026-01-10 14:43:57 +00:00
Sunglocto 7bab52f033 Remove loading gif garbage 2026-01-10 14:42:06 +00:00
Sunglocto 652fd3ea19 sending retractions 2026-01-10 14:38:58 +00:00
Sunglocto 536ce4cae6 indicator when user is on note to self 2026-01-10 14:02:18 +00:00
Sunglocto 202e3ba6b1 Format code 2026-01-06 07:08:15 +00:00
Sunglocto 7f01f38436 Bump version number 2026-01-06 05:48:42 +00:00
Sunglocto 4afe2de35d fix some timeline glitching 2026-01-05 13:57:12 +00:00
Sunglocto 04083a5ec4 attempt to fix presence 2026-01-05 06:47:23 +00:00
Sunglocto 02dcd4b453 Make sure MUCs are joined with legacy history enabled 2026-01-02 13:48:14 +00:00
Sunglocto 85b82b2d3b Make bookmarks manager show an indicator when a bookamrk does not have a name, fix capitalisation on system tray, use legacy history when joining new room and bump Fyne version to 2.7.1 2026-01-02 12:41:05 +00:00
Sunglocto a847ba5cdd Add blocking 2026-01-02 11:40:32 +00:00
Sunglocto d5ec58be68 blocking 2026-01-02 11:37:33 +00:00
5 changed files with 327 additions and 96 deletions

No files matched your search

+9 -1
View File
@@ -1,3 +1,11 @@
# Notice
Pi is on hiatus for the time being. The reason why being that the libraries that Pi uses, being the Oasis SDK and the Mellium libraries, have multiple fundamental issues and bugs that are unlikely to be fixed. In addition, I began writing this project with a much less consolidated knowledge of Go and programming in general, meaning there are core architectural issues with this project. Regardless, you are still free to use Pi, and I may even rewrite the project to add some new features. Who knows.
I mostly work on [Lambda](https://forge.sunglocto.net/sunglocto/lambda) these days, which has already surpassed Pi in terms of features and usability.
<hr/>
<center>
<img width="100" height="100" src="https://forge.sunglocto.net/sunglocto/pi-im/raw/branch/master/pi.png">
</center>
@@ -112,7 +120,7 @@ go build -tags wayland .
## εγκατάσταση
(installation)
pi currently has no consolidated way of installing it. There is an [Arch User Repository package available](https://aur.archlinux.org/pi-im), which is maintained by [snit](https://isekai.rocks/~snit).
pi currently has no consolidated way of installing it. There is an [Arch User Repository package available](https://aur.archlinux.org/packages/pi-im), which is maintained by [snit](https://isekai.rocks/~snit).
## υποστήριξη
(support)
+17 -9
View File
@@ -3,41 +3,49 @@ module pi-im
go 1.25.1
require (
fyne.io/fyne/v2 v2.6.3
fyne.io/x/fyne v0.0.0-20250910205345-ecc79984d005
fyne.io/fyne/v2 v2.7.1
fyne.io/x/fyne v0.0.0-20251214153509-fa68a7d234d5
github.com/gen2brain/beeep v0.11.2
github.com/makeworld-the-better-one/go-isemoji v1.3.0
github.com/rrivera/identicon v0.0.0-20240116195454-d5ba35832c0d
github.com/shreve/musicwand v0.0.1
github.com/sunglocto/oasis-sdk v0.0.0-20251128101950-083ea4658d9c
github.com/sunglocto/oasis-sdk v0.0.0-20260103142308-7f1848e2aac0
mellium.im/xmpp v0.22.0
)
require (
fyne.io/systray v1.11.0 // indirect
github.com/BurntSushi/toml v1.4.0 // indirect
fyne.io/systray v1.11.1-0.20250603113521-ca66a66d8b58 // indirect
git.sr.ht/~jackmordaunt/go-toast v1.1.2 // indirect
github.com/BurntSushi/toml v1.5.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fredbi/uri v1.1.0 // indirect
github.com/esiqveland/notify v0.13.3 // indirect
github.com/fredbi/uri v1.1.1 // indirect
github.com/fsnotify/fsnotify v1.9.0 // indirect
github.com/fyne-io/gl-js v0.2.0 // indirect
github.com/fyne-io/glfw-js v0.3.0 // indirect
github.com/fyne-io/image v0.1.1 // indirect
github.com/fyne-io/oksvg v0.1.0 // indirect
github.com/fyne-io/oksvg v0.2.0 // indirect
github.com/go-gl/gl v0.0.0-20231021071112-07e5d0ea2e71 // indirect
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20240506104042-037f3cc74f2a // indirect
github.com/go-ole/go-ole v1.3.0 // indirect
github.com/go-text/render v0.2.0 // indirect
github.com/go-text/typesetting v0.2.1 // indirect
github.com/godbus/dbus/v5 v5.1.0 // indirect
github.com/hack-pad/go-indexeddb v0.3.2 // indirect
github.com/hack-pad/safejs v0.1.0 // indirect
github.com/jackmordaunt/icns/v3 v3.0.1 // indirect
github.com/jeandeaual/go-locale v0.0.0-20250612000132-0ef82f21eade // indirect
github.com/jsummers/gobmp v0.0.0-20230614200233-a9de23ed2e25 // indirect
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
github.com/nicksnyder/go-i18n/v2 v2.5.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rymdport/portal v0.4.1 // indirect
github.com/rymdport/portal v0.4.2 // indirect
github.com/sergeymakinen/go-bmp v1.0.0 // indirect
github.com/sergeymakinen/go-ico v1.0.0-beta.0 // indirect
github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c // indirect
github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef // indirect
github.com/stretchr/testify v1.10.0 // indirect
github.com/stretchr/testify v1.11.1 // indirect
github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af // indirect
github.com/yuin/goldmark v1.7.8 // indirect
golang.org/x/crypto v0.36.0 // indirect
golang.org/x/image v0.24.0 // indirect
+40 -22
View File
@@ -1,20 +1,24 @@
fyne.io/fyne/v2 v2.6.3 h1:cvtM2KHeRuH+WhtHiA63z5wJVBkQ9+Ay0UMl9PxFHyA=
fyne.io/fyne/v2 v2.6.3/go.mod h1:NGSurpRElVoI1G3h+ab2df3O5KLGh1CGbsMMcX0bPIs=
fyne.io/systray v1.11.0 h1:D9HISlxSkx+jHSniMBR6fCFOUjk1x/OOOJLa9lJYAKg=
fyne.io/systray v1.11.0/go.mod h1:RVwqP9nYMo7h5zViCBHri2FgjXF7H2cub7MAq4NSoLs=
fyne.io/x/fyne v0.0.0-20250910205345-ecc79984d005 h1:CmdApAnt07juL0dhcFReFGpADUdRjjm0eDVJDS01uKE=
fyne.io/x/fyne v0.0.0-20250910205345-ecc79984d005/go.mod h1:kQFmF5meMIXnyCioLoCrXol5opruSS/PHYGKMBIE3SU=
fyne.io/fyne/v2 v2.7.1 h1:ja7rNHWWEooha4XBIZNnPP8tVFwmTfwMJdpZmLxm2Zc=
fyne.io/fyne/v2 v2.7.1/go.mod h1:xClVlrhxl7D+LT+BWYmcrW4Nf+dJTvkhnPgji7spAwE=
fyne.io/systray v1.11.1-0.20250603113521-ca66a66d8b58 h1:eA5/u2XRd8OUkoMqEv3IBlFYSruNlXD8bRHDiqm0VNI=
fyne.io/systray v1.11.1-0.20250603113521-ca66a66d8b58/go.mod h1:RVwqP9nYMo7h5zViCBHri2FgjXF7H2cub7MAq4NSoLs=
fyne.io/x/fyne v0.0.0-20251214153509-fa68a7d234d5 h1:kDuBckHtdKTNV+jq0AornXroGSd/GMq06dBNXOWfmyY=
fyne.io/x/fyne v0.0.0-20251214153509-fa68a7d234d5/go.mod h1:kQFmF5meMIXnyCioLoCrXol5opruSS/PHYGKMBIE3SU=
git.sr.ht/~jackmordaunt/go-toast v1.1.2 h1:/yrfI55LRt1M7H1vkaw+NaH1+L1CDxrqDltwm5euVuE=
git.sr.ht/~jackmordaunt/go-toast v1.1.2/go.mod h1:jA4OqHKTQ4AFBdwrSnwnskUIIS3HYzlJSgdzCKqfavo=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
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=
github.com/esiqveland/notify v0.13.3 h1:QCMw6o1n+6rl+oLUfg8P1IIDSFsDEb2WlXvVvIJbI/o=
github.com/esiqveland/notify v0.13.3/go.mod h1:hesw/IRYTO0x99u1JPweAl4+5mwXJibQVUcP0Iu5ORE=
github.com/felixge/fgprof v0.9.3 h1:VvyZxILNuCiUCSXtPtYmmtGvb65nqXh2QFWc0Wpf2/g=
github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNun8eiPw=
github.com/fredbi/uri v1.1.0 h1:OqLpTXtyRg9ABReqvDGdJPqZUxs8cyBDOMXBbskCaB8=
github.com/fredbi/uri v1.1.0/go.mod h1:aYTUoAXBOq7BLfVJ8GnKmfcuURosB1xyHDIfWeC/iW4=
github.com/fredbi/uri v1.1.1 h1:xZHJC08GZNIUhbP5ImTHnt5Ya0T8FI2VAwI/37kh2Ko=
github.com/fredbi/uri v1.1.1/go.mod h1:4+DZQ5zBjEwQCDmXW5JdIjz0PUA+yJbvtBv+u+adr5o=
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/fyne-io/gl-js v0.2.0 h1:+EXMLVEa18EfkXBVKhifYB6OGs3HwKO3lUElA0LlAjs=
@@ -23,12 +27,16 @@ github.com/fyne-io/glfw-js v0.3.0 h1:d8k2+Y7l+zy2pc7wlGRyPfTgZoqDf3AI4G+2zOWhWUk
github.com/fyne-io/glfw-js v0.3.0/go.mod h1:Ri6te7rdZtBgBpxLW19uBpp3Dl6K9K/bRaYdJ22G8Jk=
github.com/fyne-io/image v0.1.1 h1:WH0z4H7qfvNUw5l4p3bC1q70sa5+YWVt6HCj7y4VNyA=
github.com/fyne-io/image v0.1.1/go.mod h1:xrfYBh6yspc+KjkgdZU/ifUC9sPA5Iv7WYUBzQKK7JM=
github.com/fyne-io/oksvg v0.1.0 h1:7EUKk3HV3Y2E+qypp3nWqMXD7mum0hCw2KEGhI1fnBw=
github.com/fyne-io/oksvg v0.1.0/go.mod h1:dJ9oEkPiWhnTFNCmRgEze+YNprJF7YRbpjgpWS4kzoI=
github.com/fyne-io/oksvg v0.2.0 h1:mxcGU2dx6nwjJsSA9PCYZDuoAcsZ/OuJlvg/Q9Njfo8=
github.com/fyne-io/oksvg v0.2.0/go.mod h1:dJ9oEkPiWhnTFNCmRgEze+YNprJF7YRbpjgpWS4kzoI=
github.com/gen2brain/beeep v0.11.2 h1:+KfiKQBbQCuhfJFPANZuJ+oxsSKAYNe88hIpJuyKWDA=
github.com/gen2brain/beeep v0.11.2/go.mod h1:jQVvuwnLuwOcdctHn/uyh8horSBNJ8uGb9Cn2W4tvoc=
github.com/go-gl/gl v0.0.0-20231021071112-07e5d0ea2e71 h1:5BVwOaUSBTlVZowGO6VZGw2H/zl9nrd3eCZfYV+NfQA=
github.com/go-gl/gl v0.0.0-20231021071112-07e5d0ea2e71/go.mod h1:9YTyiznxEY1fVinfM7RvRcjRHbw2xLBJ3AAGIT0I4Nw=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20240506104042-037f3cc74f2a h1:vxnBhFDDT+xzxf1jTJKMKZw3H0swfWk9RpWbBbDK5+0=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20240506104042-037f3cc74f2a/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
github.com/go-text/render v0.2.0 h1:LBYoTmp5jYiJ4NPqDc2pz17MLmA3wHw1dZSVGcOdeAc=
github.com/go-text/render v0.2.0/go.mod h1:CkiqfukRGKJA5vZZISkjSYrcdtgKQWRa2HIzvwNN5SU=
github.com/go-text/typesetting v0.2.1 h1:x0jMOGyO3d1qFAPI0j4GSsh7M0Q3Ypjzr4+CEVg82V8=
@@ -44,6 +52,8 @@ github.com/hack-pad/go-indexeddb v0.3.2 h1:DTqeJJYc1usa45Q5r52t01KhvlSN02+Oq+tQb
github.com/hack-pad/go-indexeddb v0.3.2/go.mod h1:QvfTevpDVlkfomY498LhstjwbPW6QC4VC/lxYb0Kom0=
github.com/hack-pad/safejs v0.1.0 h1:qPS6vjreAqh2amUqj4WNG1zIw7qlRQJ9K10eDKMCnE8=
github.com/hack-pad/safejs v0.1.0/go.mod h1:HdS+bKF1NrE72VoXZeWzxFOVQVUSqZJAG0xNCnb+Tio=
github.com/jackmordaunt/icns/v3 v3.0.1 h1:xxot6aNuGrU+lNgxz5I5H0qSeCjNKp8uTXB1j8D4S3o=
github.com/jackmordaunt/icns/v3 v3.0.1/go.mod h1:5sHL59nqTd2ynTnowxB/MDQFhKNqkK8X687uKNygaSQ=
github.com/jeandeaual/go-locale v0.0.0-20250612000132-0ef82f21eade h1:FmusiCI1wHw+XQbvL9M+1r/C3SPqKrmBaIOYwVfQoDE=
github.com/jeandeaual/go-locale v0.0.0-20250612000132-0ef82f21eade/go.mod h1:ZDXo8KHryOWSIqnsb/CiDq7hQUYryCgdVnxbj8tDG7o=
github.com/jsummers/gobmp v0.0.0-20230614200233-a9de23ed2e25 h1:YLvr1eE6cdCqjOe972w/cYF+FjW34v27+9Vo5106B4M=
@@ -65,8 +75,12 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
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/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/rymdport/portal v0.4.1 h1:2dnZhjf5uEaeDjeF/yBIeeRo6pNI2QAKm7kq1w/kbnA=
github.com/rymdport/portal v0.4.1/go.mod h1:kFF4jslnJ8pD5uCi17brj/ODlfIidOxlgUDTO5ncnC4=
github.com/rymdport/portal v0.4.2 h1:7jKRSemwlTyVHHrTGgQg7gmNPJs88xkbKcIL3NlcmSU=
github.com/rymdport/portal v0.4.2/go.mod h1:kFF4jslnJ8pD5uCi17brj/ODlfIidOxlgUDTO5ncnC4=
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=
github.com/sergeymakinen/go-ico v1.0.0-beta.0/go.mod h1:wQ47mTczswBO5F0NoDt7O0IXgnV4Xy3ojrroMQzyhUk=
github.com/shreve/musicwand v0.0.1 h1:uF1GDmk6b9xZPAGJU3iWBSqKruyVeyVs/cqM6YzaJ3k=
github.com/shreve/musicwand v0.0.1/go.mod h1:y7oBkMLTfGmpIxoKQFwXlzWLtffcQIpX/1no+iNPxwQ=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
@@ -75,15 +89,18 @@ github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c/go.mod h1:cNQ3dwVJtS
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.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/sunglocto/oasis-sdk v0.0.0-20251128095406-3c003b830815 h1:HsI7kxYauygjRK15Iwf3FlZnU8XJwRPSmbtoNfeyBYk=
github.com/sunglocto/oasis-sdk v0.0.0-20251128095406-3c003b830815/go.mod h1:Y5iPruMLvqNwGVqB+n/+wylQjCTPKQx37I/PyLWhuzk=
github.com/sunglocto/oasis-sdk v0.0.0-20251128100941-f53b1dabbcac h1:pVarwnSbjNSDpeQer/SERztTEpkl6Cnb5xuyxXmb50k=
github.com/sunglocto/oasis-sdk v0.0.0-20251128100941-f53b1dabbcac/go.mod h1:Y5iPruMLvqNwGVqB+n/+wylQjCTPKQx37I/PyLWhuzk=
github.com/sunglocto/oasis-sdk v0.0.0-20251128101950-083ea4658d9c h1:peWSGIl0xBvx3sJR3+kHV1xOe1X8dbQ9xtvEXyXogCo=
github.com/sunglocto/oasis-sdk v0.0.0-20251128101950-083ea4658d9c/go.mod h1:Y5iPruMLvqNwGVqB+n/+wylQjCTPKQx37I/PyLWhuzk=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/sunglocto/oasis-sdk v0.0.0-20260103142308-7f1848e2aac0 h1:7zNLaQVg8jYYrNZ6KqBv23k/RYu58p3wL9YS72B+eNM=
github.com/sunglocto/oasis-sdk v0.0.0-20260103142308-7f1848e2aac0/go.mod h1:Y5iPruMLvqNwGVqB+n/+wylQjCTPKQx37I/PyLWhuzk=
github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af h1:6yITBqGTE2lEeTPG04SN9W+iWHCRyHqlVYILiSXziwk=
github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af/go.mod h1:4F09kP5F+am0jAwlQLddpoMDM+iewkxxt6nxUQ5nq5o=
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
github.com/yuin/goldmark v1.7.8 h1:iERMLn0/QJeHFhxSt3p6PeN9mGnvIKSpG9YYorDMnic=
github.com/yuin/goldmark v1.7.8/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
@@ -97,6 +114,7 @@ golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c=
golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
+261 -52
View File
@@ -3,9 +3,13 @@ package main
import (
//core - required
"context"
_ "embed"
"encoding/xml"
"errors"
"fmt"
"image/color"
_ "image/jpeg"
_ "image/png"
"io"
"log"
"math/rand/v2"
@@ -24,20 +28,27 @@ import (
"fyne.io/fyne/v2/storage"
"fyne.io/fyne/v2/theme"
"fyne.io/fyne/v2/widget"
extraWidgets "fyne.io/x/fyne/widget"
"fyne.io/fyne/v2/layout"
"github.com/gen2brain/beeep"
"github.com/makeworld-the-better-one/go-isemoji"
"github.com/rrivera/identicon"
"github.com/shreve/musicwand/pkg/mpris"
// xmpp - required
oasisSdk "github.com/sunglocto/oasis-sdk"
"mellium.im/xmpp/bookmarks"
xmppColor "mellium.im/xmpp/color"
"mellium.im/xmpp/jid"
"mellium.im/xmpp/muc"
oasisSdk "github.com/sunglocto/oasis-sdk"
"mellium.im/xmpp/pubsub"
"mellium.im/xmpp/stanza"
// TODO: integrated theme switcher
)
var version string = "3.1i"
//go:embed pi.png
var iconBytes []byte
var version string = "3.14i"
var statBar widget.Label
var chatInfo fyne.Container
var chatSidebar fyne.Container
@@ -45,6 +56,8 @@ var replyNameIcon string = ">"
var replyBodyIcon string = ">"
var newlineIcon string = " |-> "
var agreesToSendingHotFuckIntoChannel bool = false
var sendEmpty bool = false
var OccupantIdsToBlock = make(map[string]string)
// by sunglocto
// license AGPL
@@ -55,6 +68,7 @@ type Message struct {
ID string
ReplyID string
ImageURL string
Corrected bool
Raw oasisSdk.XMPPChatMessage
Important bool
Readers []jid.JID
@@ -158,14 +172,14 @@ func CreateUITab(chatJidStr string) ChatTabUI {
im := ii.Image(25)
ico := canvas.NewImageFromImage(im)
ico.FillMode = canvas.ImageFillOriginal
author := widget.NewLabel("author")
author := canvas.NewText("author", color.RGBA{255, 255, 255, 255})
author.TextStyle.Bold = true
author.Selectable = true
// author.Selectable = true
content := widget.NewLabel("content")
content.Wrapping = fyne.TextWrapWord
content.Selectable = true
content.Importance = widget.MediumImportance
//content.SizeName = fyne.ThemeSizeName(theme.SizeNameText)
content.SizeName = fyne.ThemeSizeName(theme.SizeNameText)
icon := theme.FileVideoIcon()
replytext := widget.NewLabel(">fallback reply text")
replytext.Hide()
@@ -176,12 +190,17 @@ func CreateUITab(chatJidStr string) ChatTabUI {
btn := widget.NewButtonWithIcon("View media", icon, func() {
})
btn.Hide()
reactions := container.NewHBox()
return container.NewVBox(replytext, container.NewHBox(ico, author), content, btn, reactions)
pencil := widget.NewButtonWithIcon("", theme.DocumentCreateIcon(), func(){})
pencil.Hidden = true
return container.NewVBox(replytext, container.NewHBox(ico, author, layout.NewSpacer(), pencil), content, btn, reactions)
},
func(i widget.ListItemID, co fyne.CanvasObject) {
vbox := co.(*fyne.Container)
authorBox := vbox.Objects[1].(*fyne.Container)
replytext := vbox.Objects[0].(*widget.Label)
@@ -194,10 +213,31 @@ func CreateUITab(chatJidStr string) ChatTabUI {
authorBox.Objects[0].(*canvas.Image).FillMode = canvas.ImageFillOriginal
authorBox.Objects[0].Refresh()
pencil := authorBox.Objects[3].(*widget.Button)
// Icon generate end
author := authorBox.Objects[1].(*widget.Label)
author := authorBox.Objects[1].(*canvas.Text)
col := xmppColor.String(chatTabs[chatJidStr].Messages[i].Author, 0, xmppColor.None)
author.Color = col
content := vbox.Objects[2].(*widget.Label)
unknown_tags := chatTabs[chatJidStr].Messages[i].Raw.Unknown
for _, v := range unknown_tags {
if v.XMLName.Local == "occupant-id" {
for _, attr := range v.Attrs {
if attr.Name.Local == "id" {
reason, ok := OccupantIdsToBlock[attr.Value]
if ok {
author.Text = ("Ignored user")
content.SetText("This user is ignored due to: " + reason)
content.Importance = widget.LowImportance
return // message is from blocked user
}
}
}
}
}
btn := vbox.Objects[3].(*widget.Button)
reactions := vbox.Objects[4].(*fyne.Container)
reactions = container.NewVBox()
@@ -210,7 +250,20 @@ func CreateUITab(chatJidStr string) ChatTabUI {
if chatTabs[chatJidStr].Messages[i].Important {
content.Importance = widget.DangerImportance
} else {
content.Importance = widget.MediumImportance
}
if chatTabs[chatJidStr].Messages[i].Corrected {
pencil.Hidden = false
pencil.OnTapped = func() {
dialog.ShowInformation("Original", *chatTabs[chatJidStr].Messages[i].Raw.CleanedBody, w)
}
} else {
pencil.Hidden = true
}
btn.Hidden = true // Hide by default
msgContent := chatTabs[chatJidStr].Messages[i].Content
if chatTabs[chatJidStr].Messages[i].Raw.OutOfBandMedia != nil {
@@ -270,27 +323,31 @@ func CreateUITab(chatJidStr string) ChatTabUI {
for i := len(chatTabs[chatJidStr].Messages) - 1; i >= 0; i-- {
if reply.ID == chatTabs[chatJidStr].Messages[i].Raw.StanzaID.ID {
replytext.Show()
replytext.SetText(fmt.Sprintf("%s %s", replyBodyIcon, strings.ReplaceAll(chatTabs[chatJidStr].Messages[i].Content, "\n", newlineIcon)))
replytext.Text = fmt.Sprintf("%s %s", replyBodyIcon, strings.ReplaceAll(chatTabs[chatJidStr].Messages[i].Content, "\n", newlineIcon))
guy = chatTabs[chatJidStr].Messages[i].Author
break
}
}
author.SetText(fmt.Sprintf("%s %s %s", chatTabs[chatJidStr].Messages[i].Author, replyNameIcon, guy))
author.Text = (fmt.Sprintf("%s %s %s", chatTabs[chatJidStr].Messages[i].Author, replyNameIcon, guy))
} else {
author.SetText(chatTabs[chatJidStr].Messages[i].Author)
author.Text = (chatTabs[chatJidStr].Messages[i].Author)
replytext.Hide()
}
sl := strings.Split(msgContent, " ")
content.SizeName = fyne.ThemeSizeName(theme.SizeNameText)
if len(sl) == 1 && isemoji.IsEmoji(sl[0]) {
content.SizeName = fyne.ThemeSizeName(theme.SizeNameHeadingText)
content.Refresh()
} else {
content.SizeName = fyne.ThemeSizeName(theme.SizeNameText)
content.Refresh()
}
if sl[0] == "/me" {
author.SetText(author.Text + " " + strings.Join(sl[1:], " "))
author.Text = (author.Text + " " + strings.Join(sl[1:], " "))
content.SetText(" ")
}
@@ -408,7 +465,9 @@ func dropToSignInPage(reason string) {
dialog.ShowError(err, w)
return
}
a.SendNotification(fyne.NewNotification("Done", "Relaunch the application"))
// a.SendNotification(fyne.NewNotification("Done", "Relaunch the application"))
beeep.Notify("Done", "Relaunch the application", iconBytes)
a.Quit()
//w.Close()
}
@@ -423,9 +482,12 @@ func dropToSignInPage(reason string) {
}
func main() {
beeep.AppName = "pi"
muc.Since(time.Now())
config = piConfig{}
res := fyne.NewStaticResource("image", iconBytes)
a = app.NewWithID("pi-im")
a.SetIcon(res)
reader, err := a.Storage().Open("pi.xml")
if err != nil {
dropToSignInPage(err.Error())
@@ -465,7 +527,8 @@ func main() {
if ok {
str := *msg.CleanedBody
if notifications {
a.SendNotification(fyne.NewNotification(fmt.Sprintf("%s says", userJidStr), str))
// a.SendNotification(fyne.NewNotification(fmt.Sprintf("%s says", userJidStr), str))
beeep.Notify("Direct message", fmt.Sprintf("%s says:\n%s", userJidStr, str), iconBytes)
}
for _, v := range msg.Unknown {
@@ -503,7 +566,9 @@ func main() {
if correction {
for i := len(tab.Messages) - 1; i > 0; i-- {
if tab.Messages[i].Raw.From.String() == msg.From.String() {
tab.Messages[i].Content = *msg.CleanedBody + " (corrected)"
// tab.Messages[i].Content = *msg.CleanedBody + " (corrected)"
tab.Messages[i].Content = *msg.CleanedBody
tab.Messages[i].Corrected = true
fyne.Do(func() {
UITabs[userJidStr].Scroller.Refresh()
})
@@ -571,7 +636,8 @@ func main() {
}
if !donotnotify && !ignore && notifications {
if !correction && msg.From.String() != client.JID.String() && strings.Contains(str, login.DisplayName) || (msg.Reply != nil && strings.Contains(msg.Reply.To, login.DisplayName)) {
a.SendNotification(fyne.NewNotification(fmt.Sprintf("Mentioned in %s", mucJidStr), str))
// a.SendNotification(fyne.NewNotification(fmt.Sprintf("Mentioned in %s", mucJidStr), str))
beeep.Notify(fmt.Sprintf("Mentioned in %s by %s", jid.MustParse(mucJidStr).Localpart(), msg.From.Resourcepart()), str, iconBytes)
}
}
if strings.Contains(str, "https://") {
@@ -612,7 +678,9 @@ func main() {
if correction {
for i := len(tab.Messages) - 1; i > 0; i-- {
if tab.Messages[i].Raw.From.String() == msg.From.String() {
tab.Messages[i].Content = *msg.CleanedBody + " (corrected)"
// tab.Messages[i].Content = *msg.CleanedBody + " (corrected)"
tab.Messages[i].Content = *msg.CleanedBody
tab.Messages[i].Corrected = true
fyne.Do(func() {
UITabs[mucJidStr].Scroller.Refresh()
})
@@ -636,6 +704,10 @@ func main() {
}
important = false
fyne.Do(func() {
_, ok := UITabs[mucJidStr]
if !ok {
return
}
UITabs[mucJidStr].Scroller.Refresh()
if scrollDownOnNewMessage {
tab, ok := UITabs[mucJidStr]
@@ -674,7 +746,7 @@ func main() {
})
client.SetPresenceHandler(func(client *oasisSdk.XmppClient, from jid.JID, p oasisSdk.UserPresence) {
log.Println(p.Type)
fmt.Println(p.Header.Type == stanza.UnavailablePresence)
bareAcc := from.Bare()
tab, ok := chatTabs[bareAcc.String()]
if !ok {
@@ -684,6 +756,7 @@ func main() {
}
if tab.isMuc {
fmt.Println(p.Type)
tab.Members[from.String()] = p
}
})
@@ -757,7 +830,7 @@ func main() {
w = a.NewWindow("pi")
w.SetCloseIntercept(func() {
w.RequestFocus()
dialog.ShowConfirm("Close pi", "You hit the close button. Do you want Pi to close completely (confirm) or minimize to the tray? (cancel)", func(b bool) {
dialog.ShowConfirm("Close pi", "You hit the close button. Do you want Pi to close completely?", func(b bool) {
if b {
w.Close()
a.Quit()
@@ -768,6 +841,7 @@ func main() {
}, w)
})
w.Resize(fyne.NewSize(500, 500))
w.SetIcon(res)
entry := NewCustomMultiLineEntry()
entry.SetPlaceHolder("Say something, you know you want to.\nCtrl+Enter for newline")
@@ -776,7 +850,13 @@ func main() {
SendCallback := func() {
text := entry.Text
if AppTabs.Selected() == nil || AppTabs.Selected().Content == nil || text == "" {
if text == "" {
dialog.ShowConfirm("Empty message", "Send an empty message?", func(b bool) {
sendEmpty = b
}, w)
}
if AppTabs.Selected() == nil || AppTabs.Selected().Content == nil || (text == "" && !sendEmpty) {
return
}
@@ -838,6 +918,9 @@ func main() {
text = fmt.Sprintf("%s %s", text, jid.MustParse(name).Resourcepart())
}
a := pubsub.Fetch(context.TODO(), client.Session, pubsub.Query{})
log.Println(a.Item())
err = client.SendText(jid.MustParse(activeMucJid).Bare(), text)
if err != nil {
dialog.ShowError(err, w)
@@ -1026,6 +1109,34 @@ func main() {
}, w)
})
getMAM := fyne.NewMenuItem("send stanza", func() {
sendiq := false
b := container.NewVBox()
note := widget.NewRichTextFromMarkdown(fmt.Sprintf("# How to send a stanza\nThe stanza must be formed properly or the client will disconnect! Some actions such as joining rooms should be done via the client.\n Here is an example of a typical stanza:\n\n```\n<message from=’abc@example.com’ to=’xyz@example.com’ type=’chat’>\n\t<body>We have had a most delightful evening, a most excellent ball.</body>\n</message>\n```\n\nThe `from` attribute should be your JID `(%s)` and the `to` attribute should be the intended recipient. The `type` attribute can be `chat`, `groupchat`, `headline` and more.\n\nFor more information, read [RFC 6120](https://www.rfc-editor.org/rfc/rfc6120.html).", client.JID.String()))
note.Hidden = true
// note.Wrapping = fyne.TextWrapWord
b.Add(note)
isiq := widget.NewCheck("IQ stanza (get a reponse back)", func(b bool) {sendiq=b})
b.Add(isiq)
hlpbtn := widget.NewButton("Help!", func() {note.Hidden = !note.Hidden})
b.Add(hlpbtn)
entry := widget.NewMultiLineEntry()
entry.SetPlaceHolder(fmt.Sprintf("<message type='chat' from='%s' id='ilovepi' to='friend@home.org'><body>Hello from Pi!</body></message>", client.JID.String()))
b.Add(entry)
btn := widget.NewButton("Send", func() {
fmt.Println(sendiq)
msg := entry.Text
err := client.Session.Send(context.TODO(), xml.NewDecoder(strings.NewReader(msg)))
if err != nil {
dialog.ShowError(err, w)
return
}
})
b.Add(btn)
dialog.ShowCustom("Send a custom XML stanza", "Close", b, w)
})
leaveRoom := fyne.NewMenuItem("disconnect from current room", func() {
selectedScroller, ok := AppTabs.Selected().Content.(*widget.List)
if !ok {
@@ -1061,7 +1172,13 @@ func main() {
for address, bookmark := range bookmarks {
bookmarkWidget := container.NewGridWithColumns(7)
nameLabel := widget.NewLabel(bookmark.Name)
var nameLabel *widget.RichText
if bookmark.Name != "" {
nameLabel = widget.NewRichTextFromMarkdown(bookmark.Name)
} else {
nameLabel = widget.NewRichTextFromMarkdown("_no name_")
}
nameLabel.Wrapping = fyne.TextWrapBreak
bookmarkWidget.Add(nameLabel)
@@ -1081,9 +1198,8 @@ func main() {
if bookmark.Nick == "" {
bookmark.Nick = client.Login.DisplayName
}
var zero uint64 = uint64(0)
addChatTab(true, bookmark.JID, bookmark.Nick)
_, err := client.ConnectMuc(bookmark, oasisSdk.MucLegacyHistoryConfig{MaxCount: &zero}, context.TODO())
_, err := client.ConnectMuc(bookmark, oasisSdk.MucLegacyHistoryConfig{}, context.TODO())
if err != nil {
fyne.Do(func() {
joinRoomButton.Enable()
@@ -1169,14 +1285,7 @@ func main() {
joinARoom := fyne.NewMenuItem("connect to a room", func() {
dialog.ShowEntryDialog("connect to a room", "JID:", func(s string) {
i := resourcePiloadingGif
gif, err := extraWidgets.NewAnimatedGifFromResource(i)
if err != nil {
panic(err)
}
gif.Start()
gif.Show()
d := dialog.NewCustom("Please wait", "Close", gif, w)
d := dialog.NewCustom("Please wait", "Close", widget.NewProgressBarInfinite(), w)
d.Show()
go func() {
myjid, err := jid.Parse(s)
@@ -1191,8 +1300,7 @@ func main() {
mychannel.Nick = login.DisplayName
//ch, err := client.MucClient.Join(client.Ctx, joinjid, client.Session)
addChatTab(true, myjid, login.DisplayName)
num := uint64(0)
_, err = client.ConnectMuc(*mychannel, oasisSdk.MucLegacyHistoryConfig{MaxCount: &num}, context.TODO())
_, err = client.ConnectMuc(*mychannel, oasisSdk.MucLegacyHistoryConfig{}, context.TODO())
if err != nil {
d.Hide()
dialog.ShowError(err, w)
@@ -1204,16 +1312,9 @@ func main() {
}, w)
})
beginADM := fyne.NewMenuItem("Start a DM", func() {
beginADM := fyne.NewMenuItem("start a DM", func() {
dialog.ShowEntryDialog("Start a DM", "JID:", func(s string) {
i := resourcePiloadingGif
gif, err := extraWidgets.NewAnimatedGifFromResource(i)
if err != nil {
panic(err)
}
gif.Start()
gif.Show()
d := dialog.NewCustom("Please wait", "Close", gif, w)
d := dialog.NewCustom("Please wait", "Close", widget.NewLabel("Opening a DM with "+s), w)
d.Show()
go func() {
myjid, err := jid.Parse(s)
@@ -1231,7 +1332,7 @@ func main() {
menu_help := fyne.NewMenu("π", mit, reconnect, licensesbtn)
menu_changeroom := fyne.NewMenu("Α", mic, beginADM, joinARoom, leaveRoom, manageBookmarks)
menu_changeroom := fyne.NewMenu("Α", mic, beginADM, joinARoom, leaveRoom, manageBookmarks, getMAM)
menu_configureview := fyne.NewMenu("Β", mia, jtt, jtb)
hafjag := fyne.NewMenuItem("Hafjag", func() {
entry.Text = "Hafjag"
@@ -1278,6 +1379,13 @@ func main() {
entry.Text = old
})
wspeed := fyne.NewMenuItem("W Speed ❤️‍🩹❤️‍🩹", func() {
old := entry.Text
entry.Text = "W Speed ❤️‍🩹❤️‍🩹"
SendCallback()
entry.Text = old
})
exposed_suffix := fyne.NewMenuItem(".exposed", func() {
selectedScroller, ok := AppTabs.Selected().Content.(*widget.List)
if !ok {
@@ -1354,7 +1462,7 @@ func main() {
}
})
menu_jokes := fyne.NewMenu("Δ", mycurrenttime, mycurrentplayingsong, hafjag, hotfuck, agree, kai, mipipiemi, exposed_suffix)
menu_jokes := fyne.NewMenu("Δ", mycurrenttime, mycurrentplayingsong, hafjag, hotfuck, agree, kai, mipipiemi, exposed_suffix, wspeed)
bit := fyne.NewMenuItem("mark selected message as read", func() {
selectedScroller, ok := AppTabs.Selected().Content.(*widget.List)
if !ok {
@@ -1372,6 +1480,36 @@ func main() {
client.MarkAsRead(&m)
})
rec := fyne.NewMenuItem("retract selected message", func() {
selectedScroller, ok := AppTabs.Selected().Content.(*widget.List)
if !ok {
return
}
var activeMucJid string
for jid, tabData := range UITabs {
if tabData.Scroller == selectedScroller {
activeMucJid = jid
break
}
}
if !chatTabs[activeMucJid].isMuc {
return // TODO: For 1:1 DMs we use OccupantID for the ID and send message type 'chat'
}
id := chatTabs[activeMucJid].Messages[selectedId].Raw.StanzaID
if id == nil {
return
}
msg := fmt.Sprintf("<message type='groupchat' to='%s' id='retract-message-1'><retract id='%s' xmlns='urn:xmpp:message-retract:1'/><fallback xmlns='urn:xmpp:fallback:0' for='urn:xmpp:message-retract:1' /><body>This user retracted a previous message, but it's unsupported by your client.</body><store xmlns='urn:xmpp:hints'/></message>", activeMucJid, id.ID)
fmt.Println(msg)
err := client.Session.Send(context.TODO(), xml.NewDecoder(strings.NewReader(msg)))
if err != nil {
dialog.ShowError(err, w)
}
})
bia := fyne.NewMenuItem("toggle replying to message", func() {
replying = !replying
})
@@ -1403,6 +1541,48 @@ func main() {
dialog.ShowCustom("Message", "Close", pre, w)
})
blck := fyne.NewMenuItem("ignore messages from this user", func() {
selectedScroller, ok := AppTabs.Selected().Content.(*widget.List)
if !ok {
return
}
var activeChatJid string
for jid, tabData := range UITabs {
if tabData.Scroller == selectedScroller {
activeChatJid = jid
break
}
}
m := chatTabs[activeChatJid].Messages[selectedId]
unknown_tags := m.Raw.Unknown
for _, v := range unknown_tags {
if v.XMLName.Local == "occupant-id" {
for _, attr := range v.Attrs {
if attr.Name.Local == "id" {
occupant_id := attr.Value
reason, ok := OccupantIdsToBlock[occupant_id]
if !ok {
dialog.ShowConfirm("ignore user", "All messages sent by users with an occupant ID of\n"+occupant_id+"\nwill be ignored. Continue?", func(b bool) {
if b {
OccupantIdsToBlock[occupant_id] = "User requested"
}
}, w)
} else {
dialog.ShowConfirm("unignore user", "This user is currently ignored due to:\n"+reason+"\nWould you like to unignore them?", func(b bool) {
if b {
delete(OccupantIdsToBlock, occupant_id)
}
}, w)
}
}
}
}
}
})
red := fyne.NewMenuItem("show read receipts on message", func() {
pre := container.NewVBox()
@@ -1439,13 +1619,13 @@ func main() {
dialog.ShowCustom("Message", "Close", pre, w)
})
menu_messageoptions := fyne.NewMenu("Γ", bit, bia, bic, red)
menu_messageoptions := fyne.NewMenu("Γ", bit, bia, bic, rec, red, blck)
ma := fyne.NewMainMenu(menu_help, menu_changeroom, menu_configureview, menu_messageoptions, menu_jokes)
w.SetMainMenu(ma)
desk, ok := a.(desktop.App)
if ok {
desk.SetSystemTrayMenu(fyne.NewMenu("", fyne.NewMenuItem("show", w.Show)))
desk.SetSystemTrayMenu(fyne.NewMenu("", fyne.NewMenuItem("Show window", w.Show)))
}
AppTabs = container.NewDocTabs(
@@ -1479,10 +1659,11 @@ func main() {
if err != nil {
dialog.ShowError(err, w)
}
fyne.Do(func() {
AppTabs.Selected().Text = fmt.Sprintf("%s (disconnected)", AppTabs.Selected().Text)
AppTabs.Remove(ti)
delete(UITabs, activeChatJid)
})
}()
}
@@ -1494,7 +1675,18 @@ func main() {
}
}
AppTabs.OnUnselected = func(ti *container.TabItem) {
selectedScroller, ok := AppTabs.Selected().Content.(*widget.List)
if !ok {
return
}
selectedScroller.Hidden = true
}
var MainSplit *container.Split
AppTabs.OnSelected = func(ti *container.TabItem) {
chatSidebar.Resize(chatSidebar.Size())
if AppTabs.Selected() == AppTabs.Items[0] {
chatSidebar.Hidden = true
return
@@ -1504,6 +1696,8 @@ func main() {
return
}
selectedScroller.Hidden = false
var activeChatJid string
for jid, tabData := range UITabs {
if tabData.Scroller == selectedScroller {
@@ -1521,8 +1715,8 @@ func main() {
nameLabel.Truncation = fyne.TextTruncateEllipsis
memberLabel := widget.NewLabel(fmt.Sprintf("%d members ", len(tab.Members)))
memberLabel.Truncation = fyne.TextTruncateEllipsis
box := container.NewVBox(nameLabel, )
chatSidebar.Objects = []fyne.CanvasObject{}
box := container.NewVBox(nameLabel)
// chatSidebar.Objects = []fyne.CanvasObject{}
for name, p := range tab.Members {
log.Println(string(p.Type))
@@ -1564,23 +1758,28 @@ func main() {
}
s.Truncation = fyne.TextTruncateEllipsis
box.Add(s)
box.Refresh()
}
}
}
chatSidebar = *container.NewGridWithColumns(1, container.NewVScroll(box))
} else {
if activeChatJid == config.Login.User {
chatSidebar = *container.NewVBox(widget.NewRichTextFromMarkdown("# "+activeChatJid), widget.NewLabel("Hey, that's you!"))
} else {
chatSidebar = *container.NewVBox(widget.NewRichTextFromMarkdown("# " + activeChatJid))
}
}
chatSidebar.Hidden = false
chatSidebar.Refresh()
chatSidebar.Show()
MainSplit.Resize(MainSplit.Size())
}
chatSidebar.Hidden = false
statBar.SetText("")
chatInfo = *container.NewHBox(widget.NewLabel(""))
MainSplit := container.NewHSplit(AppTabs, &chatSidebar)
MainSplit = container.NewHSplit(AppTabs, &chatSidebar)
DownSplit := container.NewHSplit(entry, container.NewGridWithRows(1, sendbtn, replybtn))
BigSplit := container.NewVSplit(MainSplit, DownSplit)
@@ -1592,5 +1791,15 @@ func main() {
MasterSplit.SetOffset(1)
w.SetContent(MasterSplit)
if time.Now().Month() == time.April && time.Now().Day() == 1 {
dialog.ShowConfirm("We care about your privacy", "We and our 5832 partner(s) would like to use your data for the following purposes:\n- Selling your organs\n- Stealing your identity\n- Putting you in jail\nYou're in control of your in data.\nDo you want us to do this? We'll do it anyway if you say no.", func(b bool) {
if b {
u, err := url.Parse("https://www.youtube.com/watch?v=dQw4w9WgXcQ")
if err == nil {
a.OpenURL(u)
}
}
}, w)
}
w.ShowAndRun()
}
-12
View File
@@ -1,12 +0,0 @@
// auto-generated
// Code generated by '$ fyne bundle'. DO NOT EDIT.
package main
import "fyne.io/fyne/v2"
var resourcePiloadingGif = &fyne.StaticResource{
StaticName: "piloading.gif",
StaticContent: []byte(
"GIF87a@\x01@\x01w\x00\x00!\xff\vNETSCAPE2.0\x03\x01\x00\x00\x00!\xf9\x04\t2\x00\x00\x00,\x00\x00\x00\x00@\x01@\x01\x80\x00\x00\x00\" 4\x02\xff\x84\x8f\xa9\xcb\xed\x0f\xa3\x9c\xb4ڋ\xb3\u07bc\xfb\x0f\x86\xe2H\x96扦\xeaʶ\xee\v\xc7\xf2L\xd7\xf6\x8d\xe7\xfa\xce\xf7\xfe\x0f\f\n\x87Ģ\xf1\x88L*\x97̦\xf3\t\x8dJ\xa7Ԫ\xf5\x8a\xcdj\xb7ܮ\xf7\v\x0e\x8b\xc7\xe4\xb2\xf9\x8cN\xab\xd7\xec\xb6\xfb\r\x8f\xcb\xe7\xf4\xba\xfd\x8e\xcf\xeb\xf7\xfc\xbe\xff\x0f\x18(8HXhx\x88\x98\xa8\xb8\xc8\xd8\xe8\xf8\b\x19)9IYiy\x89\x99\xa9\xb9\xc9\xd9\xe9\xf9\t\x1a*:JZjz\x8a\x9a\xaa\xba\xca\xda\xea\xfa\n\x1b+;K[k{\x8b\x9b\xab\xbb\xcb\xdb\xeb\xfb\v\x1c,<L\\l|\x8c\x9c\xac\xbc\xcc\xdc\xec\xfc\f\x1d-=M]m}\x8d\x9d\xad\xbd\xcd\xdd\xed\xfd\r\x1e.>N^n~\x8e\x9e\xae\xbe\xce\xde\xee\xfe\x0e\x1f/?\xcf\x1c`\x7f\x8f\x9f\xaf\xbf\xcf\xdf\xef\xff\x0f\xd0\x1e\xbd\x80\x04\v\x1a<\x98o \u0085\f\x1b\x06P\xe80\xa2\xc4~\x10'Z\xb4X\xf1\xa2Ɔ\xff\x197z4\xd8\xf1\xa3\xc8\x7f!G\x9a\xd4W\xf2\xa4ʇ\xf3\xfc\x01qْ\xe2\x0f\x98\xf2h\xf6\xb0\t\x0f\xe7\x0e\x9d\xeex\xe6\xf0\xc9\x0e\xe8\r\xa1\xea\x88\xd60\x8a\x0e\xe9\f\xa5\xe6\x98\xc6pJ\x0e\xea\v\xa9⨶\xb0\xea\x00\xeb-\xad*\xb8.\xf0J\v\xec\t\xb1\b\xc8\xc62K\x02-\x00\xb5\xae؆P\xeb\x96U\xdc\x0fpe*\x9b\xeb\xa1.\xbfzvo\xf6\xcd\xfb\xf7\x18\xde\x0ez\xf7\xf1\xdd;30\x87\xc1\xa8\x18op\xec\fr\x06ɇ\r'F\\S\xf1O\xcdA9\x0f\xf5\\\x14\xf4Q\xd1II/5\xdd\x14\xf5S\xd5QYOu]\x15\xf6U\xd9\xe0(_\xb0}\x97\xf6\n\xdc\xc9xS\xf0-XwW\xe1݀K0^\f9\x04\xe5Øg%\xce\xcdy\x03\xe9\xc0\xa8\x7f\x85\xbeͺ\x02\xed\xbd\xb8\x97\xc5\xfe\x1dso\xf0%\n\xa3\\\xe6\xfd\x80\xf9\x84\xe8ɧu\xbf\x16~[\xf9o᧗t?\xbex\xc0\xfb\x83\xf7\xffױ\x1e>\x95\x9d\xe7C\x80\xf7\f\xc8^\x81\xf6\xd1'\x17\x83t-\xf8_r+M(`}\x11\x12Ca\x86,\x81\x90\x1f$\x1aR(B\x87\x8f|8a\x88\x0e\xaaB\xe2J&^\xd8\\\x8a'\xadhYn.\x8e\x04#\x81\xe3\xcd(R\x8d\tވ\xa3G:V(c\x8f\x1b\xfdx`{,z!\xa2#I\xa6\xb0$#M\x8eub*O\x9a0e\"U\xbewd0W\x8e\xb0\xa5!]Z\x18#\x8f6\x92\xf1%!e>\x98euQ\x12q\xa6 m\x12\xb6\xe6)o.\x16\xa7)s>Vg)wj\xb0g\x1f}b\xf0\xe7\x1e\x81Z0h\x1e\x85\xfe\x96')\x87N\xb0\xa8\x1d\x8dF\xf0(\x1d\x91>0\xa9\x1c\x95N\x97\xe8(\x972\xb0\xe9\x1b\x9dn\x97\xa9(\x9f&0*\x1b\xa5\xaa\x17j(\xa7\x1a\xb0j\x1a\xad\xb6\x8aƫ\xa9\x82\"k\x9a\xbf\xd4\x1a&2\xb8\x8e\xe9_\xaec\xc0zƮ;\xea:\xebN\xc5z\",\x90b\xff\x0e\xfb뱝$[d\x90\xbc\x8a\x01\xac\x19\xd0\nd\xa4\xaf\xd4:\xcbɵ\x1b.\xab,\x99\xdcn\xe2-\x82\xe16k\xab/\xe5f;m\x18Ֆ\xb1\xae\xb4\xccn\x9bnw\xe3\xda\xf0\xae\xb8\xf5b\x91/\xbaں{o&\xf1\x82\x1b-\xbc\x01c20\xb1\xfb^\xd1/\xbd\xff\x82\xd10\xc0\v[\x111\xc4\a\x9f6q.\t\xf7ڮ\xc5\x19㲱1!K\xf8\xf1\x14\x15\x7f12\x86\x17\xcbp2\x92+\xafV\xb2-)\xb7\x18s\x14-w1\xb309k\xf92\f7s\xb1\xb3\x9a5C\xf1\xf3\x16A\xdf\xda\xf3kC\xcfr\xb4\xbaI\xbbP\xb4\x16Mۻ\xb4\x13Qg15/Yﲵ.]k\xfc\xf4lU\x9f\x156\vW\xf3[\xf6ni+\xb96\x93m;\xf96\x94c\xc3\xf25\xc8qSy\xf7\x1f>✷\x1f{\x03ݷ\x9fC\xf2=\xb7\x9e\x83\x03^\xb8\xa2\x87\x1b\x1d8\x1f\x7f3\x9e\xb8\xa6\x8bKݸ\xa0\x93gc]\xb9\x1e\x8fS\x1e\xb9\xa8\x97\xa3\xdd9=\xa2\x8fNz馟\x8ezꪯ\xcez뮿\x0e{\xec\xb2\xcfN{\xed\xb6ߎ{\xee\xba\xef\xce{\xef\xbe\xff\x0e|\xf0\xc2\x0fO|\xf1\xc6\x1f\x8f|\xf2\xca/\xcf|\xf3\xce?\x0f}\xf4\xd2OO}\xf5\xd6_\x8f}\xf6\xdao\xcf}\xf7\xde\x7f\x0f~\xf8\xe2\x8fO~\xf9\xe63Q\x00\x00!\xf9\x04\t\n\x00\x00\x00,2\x00P\x00\xb4\x00\xb4\x00\x80\x00\x00\x00\" 4\x02\xff\x84\x8f\xa9\xcb\xed\x19\xa2\x9c\xb4\xda;\x9f\u07bc\xfb\x0f\x86\x10F\x96\x98\x88\xa6\xeaʎ\xe6\xfb\xb6\xf2L\xd7\xf0]\xd6\xfa\xces\xf8o\xe9\t\x87B\xa0QBL*[\xc7\xe3\xf2\t\xfd4\x8dѪ\x951\x05^\xb7\xdb\xec\x8f\v摖\xdeJ8<V\x96)gp:\xb9δ\xbb'u<2\xa7_\xc8\xf7@\xfe\xfaF\xd4\xe7\xf7W\x1584XhX\aק\x18uX\xe4\xf8\xf8\x14ٓHɷGi\x99)ƨ\xd8\xe9\xa9#zV::s\xea\x06\x8a\xfa\xb9\xf9\xa8ں\x12\xab\x17${\xc9\xfaG{+\xb2k\xe5\xcb+\x95\x9b\a\x1c\xdcQ\f\x85l\xac\xa1\xaci\xbb\x9c:<\xd7\f\x8d%\xddF]\xad\x90-x\xad\r\u008d\xe8\xfd\xed\x11.\xf9J\x9eb\x8e\x8b\x9e\xde;\xbe\xda\xee\x0e\x0eϵ\xae}\xbf\x93\x0f\xbd\xff.?[/T@q\xffT\xf4\xb3S0\xd9\xc0c\v\x895t\xf5L\xc6\xc1F\t+=dv\xd1TF\x1b\xff\x1b\x1bL\xecVљ\x19\x1a\x1f\tF\x04\xd4\xd1ZHN)%\xb6\xdc\xf6\xf2WL\x80+\xe9լ\x85\x03\xcdL|T❜'L\x8bϑ@C8\x19ʦ\xa8ў\xf6vV;\xda\xf4\xa6R\x17_\x90ʙZ\x8e)ΤX\x19\n\x8d\xfa\xb3\xab\x03\xa8[\xaf\x8a\xc58(mճhպ5\xc1v\xc3۹9\xe2>\xa0\x8b7\xac]\x04y\xfb\"\xd9\xeb\xd1o_\xc0\x81\x05\xe3%\xac\xd2\xf0\\\xc4\v\x14\x1ffLձZȑ\xb9\x96\xfdKQ/6\xa7(JV6[ȳ\x0f\xcecI\x934mS3)\xd4.\xa5\x9eS\xcd\xd1\xf5\"\xd9\x10\x89\x82\x84m\x15\xf3e<\bq\x83\xb5\x8d\x92\xb6:\xd6L\x88{\xf5\xdd\x1ayp寁7\xb7\xbc\xdc9c\xd1\x06\x8d\xb7\xa2>\\\xb8R읭\xa3\xe2\xee\x8fyW\xf0K\xb5\x17%\x9fZ:b\xf4A\xc5ce\x9f\xd5<P\xf8\xc7\xd5\x13\xa6?Z\xfe<\xfcr\xbd\x8f\xff\xe2ߖ}\x80\x01x\x97\x7f\x9e\x10X\x9a~\xee X\x98{S1\x98\x98\x80{Aؘ\x81\x99P\b\x93\x82\xe9`\xf8\x99n\x94qȗ\x85,i\xf8\x1ch\x90\x81x\x00\x8a\n\x91Ȏ\x83ۉ\x98\x1et'\xc2؞\x84v\xa9\b\x00\x8e\"\xc9\xe8\x10\x8b<\xf9\xa8\x0f\x8d\xa1\tY\x1f\x8f\xeb\x11\x99\x9f\x8b\xe7!\xd9\x1f\x90\xfc0\x19\xa0\x91\xf7AY\xa0\x93\xcb\xe0\xa8co6\xfe&\xe5\x80T&\xa8\xe4|_6\xb8%[X\x8eɥ\x89=\x86\xb9\x1f\x95YfVft]N\x88f\x85V\x1as\xe6\x9d\xc1\xe4\xc9\xe6\x82uf\xd8\xe7\x86\x7fv\xc8\x1be\x06\xf0\x19\xa7X\x88\xcey\xe3\xa0!\xea\xc9ˢjLine truncated
}