16 Commits
3a ... 3.1a

Author SHA1 Message Date
bf8c4bd51e Add the ability to view images sent by others 2025-08-05 16:12:47 +01:00
467ae7e108 modernize message sending 2025-08-05 13:08:47 +01:00
a3203ef08c bump deps 2025-08-05 13:03:41 +01:00
8e386ebf50 Merge branch 'master' of https://github.com/sunglocto/pi 2025-08-05 13:01:04 +01:00
b8e271e0b9 bump deps 2025-08-05 13:00:55 +01:00
sunglocto
a144a065f4 Update README.md 2025-08-05 11:58:55 +00:00
5317400b47 Merge branch 'master' of https://github.com/sunglocto/pi 2025-08-05 12:56:25 +01:00
69b726b130 add account login screen, bump version number 2025-08-05 12:55:22 +01:00
sunglocto
4136889709 Update README.md 2025-08-05 09:16:48 +00:00
612eccddf2 Merge branch 'master' of https://github.com/sunglocto/pi 2025-08-04 19:20:02 +01:00
f9281c9075 disable ability to join rooms 2025-08-04 19:19:30 +01:00
sunglocto
8c721af1f3 Update README.md 2025-08-04 18:15:28 +00:00
sunglocto
4fd82f1ef9 Update README.md 2025-08-04 18:14:05 +00:00
sunglocto
838c8b6eeb Update README.md 2025-08-04 18:11:24 +00:00
sunglocto
255bc3749c Update README.md 2025-08-04 18:08:37 +00:00
sunglocto
d466c297f0 Update README.md 2025-08-04 18:07:37 +00:00
5 changed files with 305 additions and 135 deletions

2
.gitignore vendored
View File

@@ -24,8 +24,6 @@ profile.cov
go.work go.work
go.work.sum go.work.sum
go.sum
# env file # env file
.env .env
pi.json pi.json

View File

@@ -1,6 +1,10 @@
<center>
<img src="https://github.com/sunglocto/pi/blob/255bc3749c089e3945871ddf19dd17d14a83f9ff/pi.png">
</center>
# π # π
[![Go](https://github.com/sunglocto/pi/actions/workflows/go.yml/badge.svg)](https://github.com/sunglocto/pi/actions/workflows/go.yml) [![Go](https://github.com/sunglocto/pi/actions/workflows/go.yml/badge.svg)](https://github.com/sunglocto/pi/actions/workflows/go.yml)
## the XMPP client from hell
Experimental and extremely weird XMPP client made with Go. No solicitors. Experimental and extremely weird XMPP client made with Go. No solicitors.
@@ -14,17 +18,29 @@ pi is an extremely opinionated client. It aims to have as little extra windows a
## διαμόρφωση ## διαμόρφωση
(configuration) (configuration)
In order to use pi, you currently have to create a `pi.json` file in the working directory of the executable. Here is how one looks like: When you launch pi, you will be greeted with a create account screen. You will then be able to enter your XMPP account details and then relaunch the application to log in.
If you want to add MUCs or DMs, you must configure the program. Here is the general idea:
```json ```json
{ {
"Host":"example.com:5222", "Login": {
"User":"user@example.com", "Host": "example.com:5222",
"Password":"123456", "User": "user@example.com",
"DisplayName":"user", "Password": "123456",
"NoTLS":false, "DisplayName": "user",
"StartTLS":true, "NoTLS": false,
"Mucs":["room@muc.example.com"] "StartTLS": true,
"Mucs": [
"room1@group.example.com",
"room2@group.example.com"
]
},
"DMs": [
"mike@example.com",
"louis@example.com"
],
"Notifications": false
} }
``` ```
@@ -51,6 +67,9 @@ go build .
vim pi.json vim pi.json
./pi ./pi
``` ```
> Uh, Windows???
Eventually. Don't count on it.
Static executable snapshots are also provided for GNU/Linux systems. Static executable snapshots are also provided for GNU/Linux systems.
@@ -58,3 +77,20 @@ Static executable snapshots are also provided for GNU/Linux systems.
(usage) (usage)
TODO TODO
# επιπλέον
(extra)
Pi version numbers are the digits of Pi followed by a letter indicating the phase of development the program is in.
For example, the version string:
`3.14a`
Is the third version produced in the alpha phase.
The digits of Pi will reset back to `3` when moving to a new phase.
If the number gets too long, it will reset to one digit of 2π. Once that gets to long, it will be digits of 3π and etc.
Named after [Psi](https://github.com/psi-im/psi).

33
go.mod
View File

@@ -7,12 +7,12 @@ require (
fyne.io/x/fyne v0.0.0-20250418202416-58a230ad1acb fyne.io/x/fyne v0.0.0-20250418202416-58a230ad1acb
github.com/mbaklor/fyne-catppuccin v0.0.2 github.com/mbaklor/fyne-catppuccin v0.0.2
mellium.im/xmpp v0.22.0 mellium.im/xmpp v0.22.0
pain.agency/oasis-sdk v0.0.0-20250803100711-2ed1355344d4 pain.agency/oasis-sdk v0.0.0-20250805052243-df6be3f9f629
) )
require ( require (
fyne.io/systray v1.11.0 // indirect fyne.io/systray v1.11.0 // indirect
github.com/BurntSushi/toml v1.4.0 // indirect github.com/BurntSushi/toml v1.5.0 // indirect
github.com/catppuccin/go v0.3.0 // indirect github.com/catppuccin/go v0.3.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fredbi/uri v1.1.0 // indirect github.com/fredbi/uri v1.1.0 // indirect
@@ -22,31 +22,30 @@ require (
github.com/fyne-io/image v0.1.1 // 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.1.0 // indirect
github.com/go-gl/gl v0.0.0-20231021071112-07e5d0ea2e71 // 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-gl/glfw/v3.3/glfw v0.0.0-20250301202403-da16c1255728 // indirect
github.com/go-text/render v0.2.0 // indirect github.com/go-text/render v0.2.0 // indirect
github.com/go-text/typesetting v0.2.1 // indirect github.com/go-text/typesetting v0.3.0 // indirect
github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/hack-pad/go-indexeddb v0.3.2 // indirect github.com/hack-pad/go-indexeddb v0.3.2 // indirect
github.com/hack-pad/safejs v0.1.0 // indirect github.com/hack-pad/safejs v0.1.1 // indirect
github.com/jeandeaual/go-locale v0.0.0-20250612000132-0ef82f21eade // indirect github.com/jeandeaual/go-locale v0.0.0-20250612000132-0ef82f21eade // indirect
github.com/jsummers/gobmp v0.0.0-20230614200233-a9de23ed2e25 // indirect github.com/jsummers/gobmp v0.0.0-20230614200233-a9de23ed2e25 // indirect
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
github.com/nicksnyder/go-i18n/v2 v2.5.1 // indirect github.com/nicksnyder/go-i18n/v2 v2.6.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // 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/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c // indirect github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c // indirect
github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef // indirect github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef // indirect
github.com/stretchr/testify v1.10.0 // indirect github.com/stretchr/testify v1.10.0 // indirect
github.com/yuin/goldmark v1.7.8 // indirect github.com/yuin/goldmark v1.7.13 // indirect
golang.org/x/crypto v0.36.0 // indirect golang.org/x/crypto v0.40.0 // indirect
golang.org/x/image v0.24.0 // indirect golang.org/x/image v0.29.0 // indirect
golang.org/x/mod v0.21.0 // indirect golang.org/x/mod v0.26.0 // indirect
golang.org/x/net v0.37.0 // indirect golang.org/x/net v0.42.0 // indirect
golang.org/x/sync v0.12.0 // indirect golang.org/x/sync v0.16.0 // indirect
golang.org/x/sys v0.31.0 // indirect golang.org/x/sys v0.34.0 // indirect
golang.org/x/text v0.23.0 // indirect golang.org/x/text v0.27.0 // indirect
golang.org/x/tools v0.25.0 // indirect golang.org/x/tools v0.35.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
mellium.im/reader v0.1.0 // indirect mellium.im/reader v0.1.0 // indirect
mellium.im/sasl v0.3.2 // indirect mellium.im/sasl v0.3.2 // indirect

68
go.sum
View File

@@ -4,8 +4,8 @@ fyne.io/systray v1.11.0 h1:D9HISlxSkx+jHSniMBR6fCFOUjk1x/OOOJLa9lJYAKg=
fyne.io/systray v1.11.0/go.mod h1:RVwqP9nYMo7h5zViCBHri2FgjXF7H2cub7MAq4NSoLs= fyne.io/systray v1.11.0/go.mod h1:RVwqP9nYMo7h5zViCBHri2FgjXF7H2cub7MAq4NSoLs=
fyne.io/x/fyne v0.0.0-20250418202416-58a230ad1acb h1:2BazNmb/kwgqRdvE9L+NgW8sfoWGn3iy1Ox8R4+CSmc= fyne.io/x/fyne v0.0.0-20250418202416-58a230ad1acb h1:2BazNmb/kwgqRdvE9L+NgW8sfoWGn3iy1Ox8R4+CSmc=
fyne.io/x/fyne v0.0.0-20250418202416-58a230ad1acb/go.mod h1:u3LF1EkElytjOT8OHxft16trctGndF9qpsoH6YIDOUU= fyne.io/x/fyne v0.0.0-20250418202416-58a230ad1acb/go.mod h1:u3LF1EkElytjOT8OHxft16trctGndF9qpsoH6YIDOUU=
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0= github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/catppuccin/go v0.3.0 h1:d+0/YicIq+hSTo5oPuRi5kOpqkVA5tAsU6dNhvRu+aY= github.com/catppuccin/go v0.3.0 h1:d+0/YicIq+hSTo5oPuRi5kOpqkVA5tAsU6dNhvRu+aY=
github.com/catppuccin/go v0.3.0/go.mod h1:8IHJuMGaUUjQM82qBrGNBv7LFq6JI3NnQCF6MOlZjpc= github.com/catppuccin/go v0.3.0/go.mod h1:8IHJuMGaUUjQM82qBrGNBv7LFq6JI3NnQCF6MOlZjpc=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
@@ -26,24 +26,24 @@ 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.1.0/go.mod h1:dJ9oEkPiWhnTFNCmRgEze+YNprJF7YRbpjgpWS4kzoI=
github.com/go-gl/gl v0.0.0-20231021071112-07e5d0ea2e71 h1:5BVwOaUSBTlVZowGO6VZGw2H/zl9nrd3eCZfYV+NfQA= 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/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-20250301202403-da16c1255728 h1:RkGhqHxEVAvPM0/R+8g7XRwQnHatO0KAuVcwHo8q9W8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20240506104042-037f3cc74f2a/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20250301202403-da16c1255728/go.mod h1:SyRD8YfuKk+ZXlDqYiqe1qMSqjNgtHzBTG810KUagMc=
github.com/go-text/render v0.2.0 h1:LBYoTmp5jYiJ4NPqDc2pz17MLmA3wHw1dZSVGcOdeAc= 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/render v0.2.0/go.mod h1:CkiqfukRGKJA5vZZISkjSYrcdtgKQWRa2HIzvwNN5SU=
github.com/go-text/typesetting v0.2.1 h1:x0jMOGyO3d1qFAPI0j4GSsh7M0Q3Ypjzr4+CEVg82V8= github.com/go-text/typesetting v0.3.0 h1:OWCgYpp8njoxSRpwrdd1bQOxdjOXDj9Rqart9ML4iF4=
github.com/go-text/typesetting v0.2.1/go.mod h1:mTOxEwasOFpAMBjEQDhdWRckoLLeI/+qrQeBCTGEt6M= github.com/go-text/typesetting v0.3.0/go.mod h1:qjZLkhRgOEYMhU9eHBr3AR4sfnGJvOXNLt8yRAySFuY=
github.com/go-text/typesetting-utils v0.0.0-20241103174707-87a29e9e6066 h1:qCuYC+94v2xrb1PoS4NIDe7DGYtLnU2wWiQe9a1B1c0= github.com/go-text/typesetting-utils v0.0.0-20241103174707-87a29e9e6066 h1:qCuYC+94v2xrb1PoS4NIDe7DGYtLnU2wWiQe9a1B1c0=
github.com/go-text/typesetting-utils v0.0.0-20241103174707-87a29e9e6066/go.mod h1:DDxDdQEnB70R8owOx3LVpEFvpMK9eeH1o2r0yZhFI9o= github.com/go-text/typesetting-utils v0.0.0-20241103174707-87a29e9e6066/go.mod h1:DDxDdQEnB70R8owOx3LVpEFvpMK9eeH1o2r0yZhFI9o=
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/pprof v0.0.0-20211214055906-6f57359322fd h1:1FjCyPC+syAzJ5/2S8fqdZK1R22vvA0J7JZKcuOIQ7Y= github.com/google/pprof v0.0.0-20211214055906-6f57359322fd h1:1FjCyPC+syAzJ5/2S8fqdZK1R22vvA0J7JZKcuOIQ7Y=
github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg= github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/hack-pad/go-indexeddb v0.3.2 h1:DTqeJJYc1usa45Q5r52t01KhvlSN02+Oq+tQbSBI91A= github.com/hack-pad/go-indexeddb v0.3.2 h1:DTqeJJYc1usa45Q5r52t01KhvlSN02+Oq+tQbSBI91A=
github.com/hack-pad/go-indexeddb v0.3.2/go.mod h1:QvfTevpDVlkfomY498LhstjwbPW6QC4VC/lxYb0Kom0= 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.1 h1:d5qPO0iQ7h2oVtpzGnLExE+Wn9AtytxIfltcS2b9KD8=
github.com/hack-pad/safejs v0.1.0/go.mod h1:HdS+bKF1NrE72VoXZeWzxFOVQVUSqZJAG0xNCnb+Tio= github.com/hack-pad/safejs v0.1.1/go.mod h1:HdS+bKF1NrE72VoXZeWzxFOVQVUSqZJAG0xNCnb+Tio=
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 h1:FmusiCI1wHw+XQbvL9M+1r/C3SPqKrmBaIOYwVfQoDE=
github.com/jeandeaual/go-locale v0.0.0-20250612000132-0ef82f21eade/go.mod h1:ZDXo8KHryOWSIqnsb/CiDq7hQUYryCgdVnxbj8tDG7o= 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= github.com/jsummers/gobmp v0.0.0-20230614200233-a9de23ed2e25 h1:YLvr1eE6cdCqjOe972w/cYF+FjW34v27+9Vo5106B4M=
@@ -54,40 +54,40 @@ github.com/mbaklor/fyne-catppuccin v0.0.2 h1:yMNnYkmFwjKJkFQvCd1uNKZDs07ZC85wTke
github.com/mbaklor/fyne-catppuccin v0.0.2/go.mod h1:ZBIy4dV1yMj+7oEaZYkXm5OfYESmXuPWwNcuUmD1Njo= github.com/mbaklor/fyne-catppuccin v0.0.2/go.mod h1:ZBIy4dV1yMj+7oEaZYkXm5OfYESmXuPWwNcuUmD1Njo=
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ= 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/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
github.com/nicksnyder/go-i18n/v2 v2.5.1 h1:IxtPxYsR9Gp60cGXjfuR/llTqV8aYMsC472zD0D1vHk= github.com/nicksnyder/go-i18n/v2 v2.6.0 h1:C/m2NNWNiTB6SK4Ao8df5EWm3JETSTIGNXBpMJTxzxQ=
github.com/nicksnyder/go-i18n/v2 v2.5.1/go.mod h1:DrhgsSDZxoAfvVrBVLXoxZn/pN5TXqaDbq7ju94viiQ= github.com/nicksnyder/go-i18n/v2 v2.6.0/go.mod h1:88sRqr0C6OPyJn0/KRNaEz1uWorjxIKP7rUUcvycecE=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/pkg/profile v1.7.0 h1:hnbDkaNWPCLMO9wGLdBFTIZvzDrDfBM2072E1S9gJkA= github.com/pkg/profile v1.7.0 h1:hnbDkaNWPCLMO9wGLdBFTIZvzDrDfBM2072E1S9gJkA=
github.com/pkg/profile v1.7.0/go.mod h1:8Uer0jas47ZQMJ7VD+OHknK4YDY07LPUC6dEvqDjvNo= github.com/pkg/profile v1.7.0/go.mod h1:8Uer0jas47ZQMJ7VD+OHknK4YDY07LPUC6dEvqDjvNo=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 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/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rymdport/portal v0.4.1 h1:2dnZhjf5uEaeDjeF/yBIeeRo6pNI2QAKm7kq1w/kbnA= github.com/rymdport/portal v0.4.2 h1:7jKRSemwlTyVHHrTGgQg7gmNPJs88xkbKcIL3NlcmSU=
github.com/rymdport/portal v0.4.1/go.mod h1:kFF4jslnJ8pD5uCi17brj/ODlfIidOxlgUDTO5ncnC4= github.com/rymdport/portal v0.4.2/go.mod h1:kFF4jslnJ8pD5uCi17brj/ODlfIidOxlgUDTO5ncnC4=
github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c h1:km8GpoQut05eY3GiYWEedbTT0qnSxrCjsVbb7yKY1KE= 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/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 h1:Ch6Q+AZUxDBCVqdkI8FSpFyZDtCVBc2VmejdNrm5rRQ=
github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef/go.mod h1:nXTWP6+gD5+LUJ8krVhhoeHjvHTutPxMYl5SvkcnJNE= github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef/go.mod h1:nXTWP6+gD5+LUJ8krVhhoeHjvHTutPxMYl5SvkcnJNE=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= 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/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/yuin/goldmark v1.7.8 h1:iERMLn0/QJeHFhxSt3p6PeN9mGnvIKSpG9YYorDMnic= github.com/yuin/goldmark v1.7.13 h1:GPddIs617DnBLFFVJFgpo1aBfe/4xcvMc3SB5t/D0pA=
github.com/yuin/goldmark v1.7.8/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= github.com/yuin/goldmark v1.7.13/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg=
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM=
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY=
golang.org/x/image v0.24.0 h1:AN7zRgVsbvmTfNyqIbbOraYL8mSwcKncEj8ofjgzcMQ= golang.org/x/image v0.29.0 h1:HcdsyR4Gsuys/Axh0rDEmlBmB68rW1U9BUdB3UVHsas=
golang.org/x/image v0.24.0/go.mod h1:4b/ITuLfqYq1hqZcjofwctIhi7sZh2WaCjvsBNjjya8= golang.org/x/image v0.29.0/go.mod h1:RVJROnf3SLK8d26OW91j4FrIHGbsJ8QnbEocVTOWQDA=
golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= golang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg=
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ=
golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c= golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs=
golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8=
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4=
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU=
golang.org/x/tools v0.25.0 h1:oFU9pkj/iJgs+0DT+VMHrx+oBKs/LJMV+Uvg78sl+fE= golang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0=
golang.org/x/tools v0.25.0/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg= golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -101,5 +101,5 @@ mellium.im/xmlstream v0.15.4 h1:gLKxcWl4rLMUpKgtzrTBvr4OexPeO/edYus+uK3F6ZI=
mellium.im/xmlstream v0.15.4/go.mod h1:yXaCW2++fmVO4L9piKVkyLDqnCmictVYF7FDQW8prb4= mellium.im/xmlstream v0.15.4/go.mod h1:yXaCW2++fmVO4L9piKVkyLDqnCmictVYF7FDQW8prb4=
mellium.im/xmpp v0.22.0 h1:UthQVSwEAr7SNrmyc90c2ykGpVHxjn/3yw8Ey4+Im8s= mellium.im/xmpp v0.22.0 h1:UthQVSwEAr7SNrmyc90c2ykGpVHxjn/3yw8Ey4+Im8s=
mellium.im/xmpp v0.22.0/go.mod h1:WSjq12nhREFD88Vy/0WD6Q8inE8t6a8w7QjzwivWitw= mellium.im/xmpp v0.22.0/go.mod h1:WSjq12nhREFD88Vy/0WD6Q8inE8t6a8w7QjzwivWitw=
pain.agency/oasis-sdk v0.0.0-20250803100711-2ed1355344d4 h1:xnVzsKcBlIrGVBijWXDPy69AYjaWp1/pssURj2KZInk= pain.agency/oasis-sdk v0.0.0-20250805052243-df6be3f9f629 h1:NE+Z2HQzc77nw7l7DsSDSi0x9l+YfLfXBYerK+GsPrQ=
pain.agency/oasis-sdk v0.0.0-20250803100711-2ed1355344d4/go.mod h1:H5t2HizGTrQbu+e2Q6YJcRzMOlP1kC52p+0a+N/efiQ= pain.agency/oasis-sdk v0.0.0-20250805052243-df6be3f9f629/go.mod h1:eyvDgfpHo+9bdB/AkMEMZ3ETeoSONTULVx9X4w9kGAU=

283
main.go
View File

@@ -2,45 +2,42 @@ package main
import ( import (
"encoding/json" "encoding/json"
"encoding/xml"
"fmt" "fmt"
"image/color" "image/color"
"io" "io"
_ "io/fs"
"log" "log"
"net/url" "net/url"
_ "net/url"
"os" "os"
"strings" "strings"
"fyne.io/fyne/v2" "fyne.io/fyne/v2"
"fyne.io/fyne/v2/app" "fyne.io/fyne/v2/app"
"fyne.io/fyne/v2/canvas" "fyne.io/fyne/v2/canvas"
_ "fyne.io/fyne/v2/canvas"
"fyne.io/fyne/v2/container" "fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/dialog" "fyne.io/fyne/v2/dialog"
"fyne.io/fyne/v2/storage" "fyne.io/fyne/v2/storage"
_ "fyne.io/fyne/v2/storage"
"fyne.io/fyne/v2/theme" "fyne.io/fyne/v2/theme"
"fyne.io/fyne/v2/widget" "fyne.io/fyne/v2/widget"
_ "fyne.io/x/fyne/theme"
catppuccin "github.com/mbaklor/fyne-catppuccin" catppuccin "github.com/mbaklor/fyne-catppuccin"
"mellium.im/xmpp/jid" "mellium.im/xmpp/jid"
"mellium.im/xmpp/muc" "mellium.im/xmpp/muc"
"mellium.im/xmpp/stanza"
oasisSdk "pain.agency/oasis-sdk" oasisSdk "pain.agency/oasis-sdk"
) )
var version string = "3a" var version string = "3.1a"
// by sunglocto // by sunglocto
// license AGPL // license AGPL
type Message struct { type Message struct {
Author string Author string
Content string Content string
ID string ID string
ReplyID string ReplyID string
ImageURL string ImageURL string
Raw oasisSdk.XMPPChatMessage Raw oasisSdk.XMPPChatMessage
} }
type MucTab struct { type MucTab struct {
@@ -51,11 +48,21 @@ type MucTab struct {
isMuc bool isMuc bool
} }
type piConfig struct {
Login oasisSdk.LoginInfo
DMs []string
Notifications bool
}
var config piConfig
var login oasisSdk.LoginInfo
var DMs []string
var chatTabs = make(map[string]*MucTab) var chatTabs = make(map[string]*MucTab)
var tabs *container.AppTabs var tabs *container.AppTabs
var selectedId widget.ListItemID var selectedId widget.ListItemID
var replying bool = false var replying bool = false
var notifications bool = true var notifications bool
var connection bool = true var connection bool = true
type myTheme struct{} type myTheme struct{}
@@ -117,18 +124,19 @@ func addChatTab(isMuc bool, chatJid jid.JID, nick string) {
vbox := co.(*fyne.Container) vbox := co.(*fyne.Container)
author := vbox.Objects[0].(*widget.Label) author := vbox.Objects[0].(*widget.Label)
content := vbox.Objects[1].(*widget.RichText) content := vbox.Objects[1].(*widget.RichText)
//image := vbox.Objects[2].(*canvas.Image)
btn := vbox.Objects[2].(*widget.Button) btn := vbox.Objects[2].(*widget.Button)
btn.Hidden = true // Hide by default btn.Hidden = true // Hide by default
msgContent := tabData.Messages[i].Content msgContent := tabData.Messages[i].Content
if tabData.Messages[i].ImageURL != "" { if tabData.Messages[i].ImageURL != "" {
btn.Hidden = false btn.Hidden = false
btn.OnTapped = func(){fyne.Do(func() { btn.OnTapped = func() {
u, _ := storage.ParseURI(tabData.Messages[i].ImageURL) fyne.Do(func() {
image := canvas.NewImageFromURI(u) u, _ := storage.ParseURI(tabData.Messages[i].ImageURL)
image.FillMode = canvas.ImageFillOriginal image := canvas.NewImageFromURI(u)
dialog.ShowCustom("Image", "Close", image, w) image.FillMode = canvas.ImageFillOriginal
})} dialog.ShowCustom("Image", "Close", image, w)
})
}
} }
// Check if the message is a quote // Check if the message is a quote
lines := strings.Split(msgContent, "\n") lines := strings.Split(msgContent, "\n")
@@ -160,31 +168,84 @@ func addChatTab(isMuc bool, chatJid jid.JID, nick string) {
tabs.Append(tabItem) tabs.Append(tabItem)
} }
func main() { func dropToSignInPage(reason string) {
login := oasisSdk.LoginInfo{} a = app.New()
w = a.NewWindow("Welcome to Pi")
w.Resize(fyne.NewSize(500, 500))
rt := widget.NewRichTextFromMarkdown("# Welcome to pi\nIt appears you do not have a valid account configured. Let's create one!")
footer := widget.NewRichTextFromMarkdown(fmt.Sprintf("Reason for being dropped to the sign-in page:\n\n```%s```", reason))
userEntry := widget.NewEntry()
userEntry.SetPlaceHolder("Your JID")
serverEntry := widget.NewEntry()
serverEntry.SetPlaceHolder("Server and port")
passwordEntry := widget.NewPasswordEntry()
passwordEntry.SetPlaceHolder("Your Password")
nicknameEntry := widget.NewEntry()
nicknameEntry.SetPlaceHolder("Your Nickname")
DMs := []string{} userView := widget.NewFormItem("", userEntry)
serverView := widget.NewFormItem("", serverEntry)
passwordView := widget.NewFormItem("", passwordEntry)
nicknameView := widget.NewFormItem("", nicknameEntry)
items := []*widget.FormItem{
serverView,
userView,
passwordView,
nicknameView,
}
btn := widget.NewButton("Create an account", func() {
dialog.ShowForm("Create an account", "Create", "Dismiss", items, func(b bool) {
if b {
config := piConfig{}
config.Login.Host = serverEntry.Text
config.Login.User = userEntry.Text
config.Login.Password = passwordEntry.Text
config.Login.DisplayName = nicknameEntry.Text
config.Notifications = true
bytes, err := json.MarshalIndent(config, "", " ")
if err != nil {
dialog.ShowError(err, w)
return
}
os.Create("pi.json")
os.WriteFile("pi.json", bytes, os.FileMode(os.O_RDWR)) // TODO: See if this works on non-unix like systems
a.SendNotification(fyne.NewNotification("Done", "Relaunch the application"))
w.Close()
}
}, w)
})
btn2 := widget.NewButton("Close pi", func() {
w.Close()
})
w.SetContent(container.NewVBox(rt, btn, btn2,footer))
w.ShowAndRun()
}
func main() {
config = piConfig{}
bytes, err := os.ReadFile("./pi.json") bytes, err := os.ReadFile("./pi.json")
if err != nil { if err != nil {
a = app.New() dropToSignInPage(err.Error())
w = a.NewWindow("Error")
w.Resize(fyne.NewSize(500, 500))
dialog.ShowInformation("Error", fmt.Sprintf("Please make sure there is a file named pi.json in the same directory you are running this executable...\n%s", err.Error()), w)
w.ShowAndRun()
return return
} }
err = json.Unmarshal(bytes, &login)
if err != nil {
fyne.Do(func() { err = json.Unmarshal(bytes, &config)
a = app.New() if err != nil {
w = a.NewWindow("Error") dropToSignInPage(fmt.Sprintf("Your pi.json file is invalid:\n%s", err.Error()))
w.Resize(fyne.NewSize(500, 500)) return
dialog.ShowError(err, w)
w.ShowAndRun()
})
} }
login = config.Login
DMs = config.DMs
notifications = config.Notifications
client, err := oasisSdk.CreateClient( client, err := oasisSdk.CreateClient(
&login, &login,
func(client *oasisSdk.XmppClient, msg *oasisSdk.XMPPChatMessage) { func(client *oasisSdk.XmppClient, msg *oasisSdk.XMPPChatMessage) {
@@ -199,7 +260,7 @@ func main() {
} }
var img string = "" var img string = ""
if strings.Contains(str, "https://") { if strings.Contains(str, "https://") {
lines := strings.Split(str, " ") lines := strings.Split(str, "\n")
for i, line := range lines { for i, line := range lines {
s := strings.Split(line, " ") s := strings.Split(line, " ")
for j, v := range s { for j, v := range s {
@@ -220,11 +281,11 @@ func main() {
replyID = msg.Reply.ID replyID = msg.Reply.ID
} }
myMessage := Message{ myMessage := Message{
Author: msg.From.Resourcepart(), Author: msg.From.Resourcepart(),
Content: str, Content: str,
ID: msg.ID, ID: msg.ID,
ReplyID: replyID, ReplyID: replyID,
Raw: *msg, Raw: *msg,
ImageURL: img, ImageURL: img,
} }
@@ -238,6 +299,7 @@ func main() {
} }
}, },
func(client *oasisSdk.XmppClient, _ *muc.Channel, msg *oasisSdk.XMPPChatMessage) { func(client *oasisSdk.XmppClient, _ *muc.Channel, msg *oasisSdk.XMPPChatMessage) {
var ImageID string = ""
mucJidStr := msg.From.Bare().String() mucJidStr := msg.From.Bare().String()
if tab, ok := chatTabs[mucJidStr]; ok { if tab, ok := chatTabs[mucJidStr]; ok {
@@ -248,13 +310,16 @@ func main() {
} }
} }
if strings.Contains(str, "https://") { if strings.Contains(str, "https://") {
lines := strings.Split(str, " ") lines := strings.Split(str, "\n")
for i, line := range lines { for i, line := range lines {
s := strings.Split(line, " ") s := strings.Split(line, " ")
for j, v := range s { for j, v := range s {
_, err := url.Parse(v) _, err := url.Parse(v)
if err == nil && strings.HasPrefix(v, "https://") { if err == nil && strings.HasPrefix(v, "https://") {
s[j] = fmt.Sprintf("[%s](%s)", v, v) s[j] = fmt.Sprintf("[%s](%s)", v, v)
if strings.HasSuffix(v, ".png") || strings.HasSuffix(v, ".jp") || strings.HasSuffix(v, ".webp") {
ImageID = v
}
} }
} }
lines[i] = strings.Join(s, " ") lines[i] = strings.Join(s, " ")
@@ -275,6 +340,7 @@ func main() {
ID: msg.ID, ID: msg.ID,
ReplyID: replyID, ReplyID: replyID,
Raw: *msg, Raw: *msg,
ImageURL: ImageID,
} }
tab.Messages = append(tab.Messages, myMessage) tab.Messages = append(tab.Messages, myMessage)
fyne.Do(func() { fyne.Do(func() {
@@ -286,7 +352,6 @@ func main() {
} }
}, },
func(_ *oasisSdk.XmppClient, from jid.JID, state oasisSdk.ChatState) { func(_ *oasisSdk.XmppClient, from jid.JID, state oasisSdk.ChatState) {
//fromStr := from.String()
switch state { switch state {
case oasisSdk.ChatStateActive: case oasisSdk.ChatStateActive:
case oasisSdk.ChatStateComposing: case oasisSdk.ChatStateComposing:
@@ -367,22 +432,8 @@ func main() {
client.ReplyToEvent(&m, text) client.ReplyToEvent(&m, text)
return return
} }
var typ stanza.MessageType
if isMuc { err = client.SendText(jid.MustParse(activeMucJid), text)
typ = stanza.GroupChatMessage
} else {
typ = stanza.ChatMessage
}
msg := oasisSdk.XMPPChatMessage{
Message: stanza.Message{
To: jid.MustParse(activeMucJid),
Type: typ,
},
ChatMessageBody: oasisSdk.ChatMessageBody{
Body: &text,
},
}
err := client.Session.Encode(client.Ctx, msg)
if err != nil { if err != nil {
dialog.ShowError(err, w) dialog.ShowError(err, w)
} }
@@ -402,11 +453,21 @@ func main() {
entry.SetText("") entry.SetText("")
}) })
mit := fyne.NewMenuItem("about pi", func() { mit := fyne.NewMenuItem("about pi", func() {
dialog.ShowInformation("about pi", fmt.Sprintf("the XMPP client from hell\n\npi is an experimental XMPP client\nwritten by Sunglocto in Go.\n\nVersion %s", version), w) dialog.ShowInformation("about pi", fmt.Sprintf("the XMPP client from hell\n\npi is an experimental XMPP client\nwritten by Sunglocto in Go.\n\nVersion %s", version), w)
}) })
reconnect := fyne.NewMenuItem("reconnect", func() {
go func(){
err := client.Connect()
if err != nil {
fyne.Do(func(){
dialog.ShowError(err, w)
})
}
}()
})
mia := fyne.NewMenuItem("configure message view", func() { mia := fyne.NewMenuItem("configure message view", func() {
ch := widget.NewCheck("", func(b bool) {}) ch := widget.NewCheck("", func(b bool) {})
ch2 := widget.NewCheck("", func(b bool) {}) ch2 := widget.NewCheck("", func(b bool) {})
@@ -433,7 +494,23 @@ func main() {
} }
}, w) }, w)
}) })
mib := fyne.NewMenuItem("Join a room", func() {
jtb := fyne.NewMenuItem("jump to bottom", func() {
selectedScroller, ok := tabs.Selected().Content.(*widget.List)
if !ok {
return
}
selectedScroller.ScrollToBottom()
})
jtt := fyne.NewMenuItem("jump to top", func() {
selectedScroller, ok := tabs.Selected().Content.(*widget.List)
if !ok {
return
}
selectedScroller.ScrollToTop()
})
/*mib := fyne.NewMenuItem("Join a room", func() {
nickEntry := widget.NewEntry() nickEntry := widget.NewEntry()
nickEntry.SetText(login.DisplayName) nickEntry.SetText(login.DisplayName)
roomEntry := widget.NewEntry() roomEntry := widget.NewEntry()
@@ -460,27 +537,59 @@ func main() {
addChatTab(true, roomJid, nick) addChatTab(true, roomJid, nick)
} }
}, w) }, w)
}) })*/
mic := fyne.NewMenuItem("upload a file", func() { mic := fyne.NewMenuItem("upload a file", func() {
var link string
var bytes []byte
var toperr error
var topreader fyne.URIReadCloser
dialog.ShowFileOpen(func(reader fyne.URIReadCloser, err error) { dialog.ShowFileOpen(func(reader fyne.URIReadCloser, err error) {
if err != nil {
dialog.ShowError(err, w)
}
bytes, err := io.ReadAll(reader)
link, err := client.UploadFileFromBytes(reader.URI().String(), bytes)
if err != nil { if err != nil {
dialog.ShowError(err, w) dialog.ShowError(err, w)
return return
} }
if reader == nil {
return
}
bytes, toperr = io.ReadAll(reader)
topreader = reader
if toperr != nil {
dialog.ShowError(toperr, w)
return
}
progress := make(chan oasisSdk.UploadProgress)
myprogressbar := widget.NewProgressBar()
dialog.ShowCustom("Uploading file", "Hide", myprogressbar, w)
go func() {
client.UploadFileFromBytes(client.Ctx, topreader.URI().Name(), bytes, progress)
}()
for update := range progress {
myprogressbar.Value = float64(update.Percentage)
myprogressbar.Refresh()
if update.Error != nil {
dialog.ShowError(update.Error, w)
return
}
if update.GetURL != "" {
link = update.GetURL
}
}
a.Clipboard().SetContent(link) a.Clipboard().SetContent(link)
dialog.ShowInformation("file successfully uploaded\nURL copied to your clipboard", link, w) dialog.ShowInformation("file successfully uploaded\nURL copied to your clipboard", link, w)
}, w) }, w)
}) })
menu_help := fyne.NewMenu("π", mit) menu_help := fyne.NewMenu("π", mit, reconnect)
menu_changeroom := fyne.NewMenu("β", mib, mic) menu_changeroom := fyne.NewMenu("β", mic)
menu_configureview := fyne.NewMenu("γ", mia, mis) menu_configureview := fyne.NewMenu("γ", mia, mis, jtt, jtb)
bit := fyne.NewMenuItem("mark selected message as read", func() { bit := fyne.NewMenuItem("mark selected message as read", func() {
selectedScroller, ok := tabs.Selected().Content.(*widget.List) selectedScroller, ok := tabs.Selected().Content.(*widget.List)
if !ok { if !ok {
@@ -501,7 +610,35 @@ func main() {
bia := fyne.NewMenuItem("toggle replying to message", func() { bia := fyne.NewMenuItem("toggle replying to message", func() {
replying = !replying replying = !replying
}) })
menu_messageoptions := fyne.NewMenu("Σ", bit, bia)
bic := fyne.NewMenuItem("show message XML", func() {
pre := widget.NewLabel("")
selectedScroller, ok := tabs.Selected().Content.(*widget.List)
if !ok {
return
}
var activeChatJid string
for jid, tabData := range chatTabs {
if tabData.Scroller == selectedScroller {
activeChatJid = jid
break
}
}
m := chatTabs[activeChatJid].Messages[selectedId].Raw
bytes, err := xml.MarshalIndent(m, "", " ")
if err != nil {
dialog.ShowError(err, w)
return
}
pre.SetText(string(bytes))
pre.Selectable = true
pre.Refresh()
dialog.ShowCustom("Message", "Close", pre, w)
})
menu_messageoptions := fyne.NewMenu("Σ", bit, bia, bic)
ma := fyne.NewMainMenu(menu_help, menu_changeroom, menu_configureview, menu_messageoptions) ma := fyne.NewMainMenu(menu_help, menu_changeroom, menu_configureview, menu_messageoptions)
w.SetMainMenu(ma) w.SetMainMenu(ma)