Compare commits
38 Commits
3.142a
...
d4433a20ed
Author | SHA1 | Date | |
---|---|---|---|
d4433a20ed | |||
80489d1877 | |||
713bde2d23 | |||
ffd6023ae2 | |||
003a156c50 | |||
402383f516 | |||
c0d19e4335 | |||
853bed70e7 | |||
21564cc70e | |||
f9ac50392e | |||
fa11b3ee87 | |||
7eabb0c30e | |||
1da705a1b0 | |||
5988eead04 | |||
2fd5f48334 | |||
d2b9f9843f | |||
65e4e3380c | |||
8e58139fcb | |||
![]() |
50caef2f39 | ||
4b64de882d | |||
dfaf56a330 | |||
02f6adad02 | |||
![]() |
a6285b0d8a | ||
6267a4a072 | |||
ac5d0aa2bf | |||
c20f77ce0f | |||
59ef99f200 | |||
56797b92eb | |||
e391ea9ad6 | |||
a02a043808 | |||
bd34df424b | |||
efa801b393 | |||
f65cf4a17d | |||
7e8ceb2b2a | |||
6ab9dd8ff8 | |||
![]() |
91881439a4 | ||
![]() |
2972c86641 | ||
e5f391edfd |
34
.github/workflows/go.yml
vendored
34
.github/workflows/go.yml
vendored
@@ -1,34 +0,0 @@
|
||||
# This workflow will build a golang project
|
||||
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go
|
||||
|
||||
name: build this now
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "master" ]
|
||||
pull_request:
|
||||
branches: [ "master" ]
|
||||
|
||||
jobs:
|
||||
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: '1.24'
|
||||
- name: Install X11 dependencies
|
||||
run: sudo apt-get update && sudo apt-get install -y libx11-dev libxcursor-dev libxrandr-dev libxinerama-dev libxi-dev libgl1-mesa-dev libglu1-mesa-dev libxxf86vm-dev
|
||||
|
||||
- name: Build
|
||||
run: go build .
|
||||
|
||||
- name: Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: pi-binary
|
||||
path: pi-im
|
||||
|
80
README.md
80
README.md
@@ -1,9 +1,7 @@
|
||||
<center>
|
||||
<img width="100" height="100" src="https://github.com/sunglocto/pi/blob/255bc3749c089e3945871ddf19dd17d14a83f9ff/pi.png">
|
||||
<img width="100" height="100" src="https://forge.sunglocto.net/sunglocto/pi-im/raw/branch/master/pi.png">
|
||||
</center>
|
||||
|
||||
[](https://github.com/sunglocto/pi/actions/workflows/go.yml)
|
||||
<img width="1920" height="1080" alt="image" src="https://github.com/user-attachments/assets/9e2d9209-6ad5-4f22-94d0-4cc18c835372" />
|
||||
<img alt="Pi screenshot" src="https://github.com/user-attachments/assets/9e2d9209-6ad5-4f22-94d0-4cc18c835372" />
|
||||
|
||||
|
||||
## the XMPP client from hell
|
||||
@@ -58,27 +56,65 @@ As of writing, pi supports basic message sending and receiving, replies, file up
|
||||
|
||||
To build pi, you will need the latest version of Go, at least 1.21. You can grab it [here](https://go.dev).
|
||||
|
||||
You must have a C compiler on your system also present. This will be the case for virtually all PC operating systems except Windows.
|
||||
|
||||
The build instructions are very simple. Simply clone the repo, fetch the repositories and build the program.
|
||||
|
||||
Here is a summary of the commands you would need to use:
|
||||
```bash
|
||||
git clone https://github.com/sunglocto/pi-im
|
||||
git clone https://forge.sunglocto.net/sunglocto/pi-im
|
||||
cd pi-im
|
||||
go mod tidy
|
||||
go build .
|
||||
./pi-im
|
||||
|
||||
```
|
||||
> Uh, Windows???
|
||||
|
||||
Eventually. Don't count on it.
|
||||
Fyne has first-class support for Windows and all of my dependencies are platform imdependent. I've built this app for Android before. If you compile it, it will most likely work with no issues.
|
||||
Windows requires more steps to setup, specifically you need an MSYS2 environment. As per [the Fyne documentation](https://docs.fyne.io/started/)
|
||||
|
||||
Static executable snapshots are also provided for GNU/Linux systems on every new version, and CI runs on every commit, producing a binary on every successful build. You're welcome.
|
||||
|
||||
The MSYS2 platform is the recommended approach for working on Windows. Proceed as follows:
|
||||
|
||||
Install MSYS2 from msys2.org
|
||||
Once installed do not use the MSYS terminal that opens
|
||||
Open “MSYS2 MinGW 64-bit” from the start menu
|
||||
|
||||
Execute the following commands (if asked for install options be sure to choose “all”):
|
||||
|
||||
$ pacman -Syu
|
||||
$ pacman -S git mingw-w64-x86_64-toolchain mingw-w64-x86_64-go
|
||||
|
||||
You will need to add ~/Go/bin to your $PATH, for MSYS2 you can paste the following command into your terminal:
|
||||
|
||||
$ echo "export PATH=\$PATH:~/Go/bin" >> ~/.bashrc
|
||||
|
||||
For the compiler to work on other terminals you will need to set up the windows %PATH% variable to find these tools. Go to the “Edit the system environment variables” control panel, tap “Advanced” and add “C:\msys64\mingw64\bin” to the Path list.
|
||||
|
||||
|
||||
<img alt="image" src="https://github.com/user-attachments/assets/5a6c188f-e890-4398-856c-e88f5804e9d2" />
|
||||
|
||||
pi has been tested on FreeBSD and NetBSD with no issues. Please read their respective Wiki entries.
|
||||
|
||||
Static executable snapshots are also provided for GNU/Linux systems on every new version.
|
||||
|
||||
## Wayland
|
||||
On BSD and Linux systems, you may want to build an executable for Wayland only, meaning it will not run through XWayland. This will increase performance and also allow drag-on-drop functionality. Most Wayland setups can run X11 apps, but no X11 setup can run Wayland apps. Because of this, all executables are shipped for use with X11. This may change in the future, but if you want to build for Wayland, it's as simple as the commands above, but just adding a `wayland` tag to the build command.
|
||||
|
||||
A Wayland-only executable will also substantially decrease the level of screen tearing and lag.
|
||||
|
||||
```bash
|
||||
git clone https://forge.sunglocto.net/sunglocto/pi-im
|
||||
cd pi-im
|
||||
go mod tidy
|
||||
go build -tags wayland .
|
||||
./pi-im
|
||||
```
|
||||
|
||||
## εγκατάσταση
|
||||
(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/pi-im), which is maintained by [snit](https://isekai.rocks/~snit).
|
||||
|
||||
## υποστήριξη
|
||||
(support)
|
||||
@@ -87,6 +123,28 @@ You can file an issue and explain the problem you are having.
|
||||
|
||||
If you would like a more instant method of communication, join the [pi XMPP room.](xmpp:pi@room.sunglocto.net?join)
|
||||
|
||||
|
||||
## αρμονία
|
||||
(compatibility)
|
||||
|
||||
pi has guaranteed support for the following operating systems:
|
||||
- Windows 10 and up
|
||||
- Most modern GNU/Linux installations
|
||||
- FreeBSD
|
||||
- NetBSD
|
||||
- MacOS
|
||||
|
||||
pi has experimental support for the following operating system:
|
||||
- Android [1]
|
||||
|
||||
pi most likely does **not** have support for the following operating systems:
|
||||
- 32-bit systems
|
||||
- iOS
|
||||
- ARM systems
|
||||
|
||||
|
||||
If you use pi on a specific operating system and it does not work, file an issue and describe the problem you have having.
|
||||
|
||||
## μαρτυρίες
|
||||
(testimonials)
|
||||
From fellow insane and schizophrenic XMPP users:
|
||||
@@ -108,7 +166,7 @@ From fellow insane and schizophrenic XMPP users:
|
||||
## επιπλέον
|
||||
(extra)
|
||||
|
||||
Pi version numbers are the digits of Pi followed by a letter indicating the phase of development the program is in.
|
||||
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:
|
||||
|
||||
@@ -121,3 +179,5 @@ 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 too long, it will be digits of 3π and etc.
|
||||
|
||||
Named after [Psi](https://github.com/psi-im/psi).
|
||||
|
||||
[1] Android is not a supported platform, however it's possible to compile and run pi for it. If you want to become suicidal, you can go for it, but pi is a primarily PC-oriented client. There are multiple mobile clients that already exist which will give you a substantially better experience.
|
||||
|
40
go.mod
40
go.mod
@@ -1,50 +1,50 @@
|
||||
module pi-im
|
||||
|
||||
go 1.24.5
|
||||
go 1.24.6
|
||||
|
||||
require (
|
||||
fyne.io/fyne/v2 v2.6.2
|
||||
fyne.io/x/fyne v0.0.0-20250418202416-58a230ad1acb
|
||||
fyne.io/fyne/v2 v2.6.3
|
||||
fyne.io/x/fyne v0.0.0-20250827163406-39fd826f385e
|
||||
github.com/rrivera/identicon v0.0.0-20240116195454-d5ba35832c0d
|
||||
mellium.im/xmpp v0.22.0
|
||||
pain.agency/oasis-sdk v0.0.0-20250809192709-a3e5dff1aa61
|
||||
pain.agency/oasis-sdk v0.0.0-20250831105702-85385dca3a95
|
||||
)
|
||||
|
||||
require (
|
||||
fyne.io/systray v1.11.0 // indirect
|
||||
github.com/BurntSushi/toml v1.5.0 // indirect
|
||||
github.com/BurntSushi/toml v1.4.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/fredbi/uri v1.1.1 // indirect
|
||||
github.com/fredbi/uri v1.1.0 // 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/go-gl/gl v0.0.0-20231021071112-07e5d0ea2e71 // indirect
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20250301202403-da16c1255728 // indirect
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20240506104042-037f3cc74f2a // indirect
|
||||
github.com/go-text/render v0.2.0 // indirect
|
||||
github.com/go-text/typesetting v0.3.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.1 // indirect
|
||||
github.com/hack-pad/safejs v0.1.0 // 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.6.0 // 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.2 // indirect
|
||||
github.com/rymdport/portal v0.4.1 // 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/yuin/goldmark v1.7.13 // indirect
|
||||
golang.org/x/crypto v0.41.0 // indirect
|
||||
golang.org/x/image v0.30.0 // indirect
|
||||
golang.org/x/mod v0.27.0 // indirect
|
||||
golang.org/x/net v0.43.0 // indirect
|
||||
golang.org/x/sync v0.16.0 // indirect
|
||||
golang.org/x/sys v0.35.0 // indirect
|
||||
golang.org/x/text v0.28.0 // indirect
|
||||
golang.org/x/tools v0.36.0 // 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
|
||||
golang.org/x/mod v0.21.0 // indirect
|
||||
golang.org/x/net v0.37.0 // indirect
|
||||
golang.org/x/sync v0.12.0 // indirect
|
||||
golang.org/x/sys v0.31.0 // indirect
|
||||
golang.org/x/text v0.23.0 // indirect
|
||||
golang.org/x/tools v0.25.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
mellium.im/reader v0.1.0 // indirect
|
||||
mellium.im/sasl v0.3.2 // indirect
|
||||
|
78
go.sum
78
go.sum
@@ -1,17 +1,17 @@
|
||||
fyne.io/fyne/v2 v2.6.2 h1:RPgwmXWn+EuP/TKwO7w5p73ILVC26qHD9j3CZUZNwgM=
|
||||
fyne.io/fyne/v2 v2.6.2/go.mod h1:9IJ8uWgzfcMossFoUkLiOrUIEtaDvF4nML114WiCtXU=
|
||||
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-20250418202416-58a230ad1acb h1:2BazNmb/kwgqRdvE9L+NgW8sfoWGn3iy1Ox8R4+CSmc=
|
||||
fyne.io/x/fyne v0.0.0-20250418202416-58a230ad1acb/go.mod h1:u3LF1EkElytjOT8OHxft16trctGndF9qpsoH6YIDOUU=
|
||||
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
|
||||
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||
fyne.io/x/fyne v0.0.0-20250827163406-39fd826f385e h1:oJM+HGkpSuq1J+JqUq/jo7KPrKj2K2/VIZlyus04w3Y=
|
||||
fyne.io/x/fyne v0.0.0-20250827163406-39fd826f385e/go.mod h1:u3LF1EkElytjOT8OHxft16trctGndF9qpsoH6YIDOUU=
|
||||
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/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/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.1 h1:xZHJC08GZNIUhbP5ImTHnt5Ya0T8FI2VAwI/37kh2Ko=
|
||||
github.com/fredbi/uri v1.1.1/go.mod h1:4+DZQ5zBjEwQCDmXW5JdIjz0PUA+yJbvtBv+u+adr5o=
|
||||
github.com/fredbi/uri v1.1.0 h1:OqLpTXtyRg9ABReqvDGdJPqZUxs8cyBDOMXBbskCaB8=
|
||||
github.com/fredbi/uri v1.1.0/go.mod h1:aYTUoAXBOq7BLfVJ8GnKmfcuURosB1xyHDIfWeC/iW4=
|
||||
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=
|
||||
@@ -24,24 +24,22 @@ 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/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-20250301202403-da16c1255728 h1:RkGhqHxEVAvPM0/R+8g7XRwQnHatO0KAuVcwHo8q9W8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20250301202403-da16c1255728/go.mod h1:SyRD8YfuKk+ZXlDqYiqe1qMSqjNgtHzBTG810KUagMc=
|
||||
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-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.3.0 h1:OWCgYpp8njoxSRpwrdd1bQOxdjOXDj9Rqart9ML4iF4=
|
||||
github.com/go-text/typesetting v0.3.0/go.mod h1:qjZLkhRgOEYMhU9eHBr3AR4sfnGJvOXNLt8yRAySFuY=
|
||||
github.com/go-text/typesetting v0.2.1 h1:x0jMOGyO3d1qFAPI0j4GSsh7M0Q3Ypjzr4+CEVg82V8=
|
||||
github.com/go-text/typesetting v0.2.1/go.mod h1:mTOxEwasOFpAMBjEQDhdWRckoLLeI/+qrQeBCTGEt6M=
|
||||
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/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
|
||||
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/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg=
|
||||
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/safejs v0.1.1 h1:d5qPO0iQ7h2oVtpzGnLExE+Wn9AtytxIfltcS2b9KD8=
|
||||
github.com/hack-pad/safejs v0.1.1/go.mod h1:HdS+bKF1NrE72VoXZeWzxFOVQVUSqZJAG0xNCnb+Tio=
|
||||
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/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=
|
||||
@@ -50,8 +48,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
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/nicksnyder/go-i18n/v2 v2.6.0 h1:C/m2NNWNiTB6SK4Ao8df5EWm3JETSTIGNXBpMJTxzxQ=
|
||||
github.com/nicksnyder/go-i18n/v2 v2.6.0/go.mod h1:88sRqr0C6OPyJn0/KRNaEz1uWorjxIKP7rUUcvycecE=
|
||||
github.com/nicksnyder/go-i18n/v2 v2.5.1 h1:IxtPxYsR9Gp60cGXjfuR/llTqV8aYMsC472zD0D1vHk=
|
||||
github.com/nicksnyder/go-i18n/v2 v2.5.1/go.mod h1:DrhgsSDZxoAfvVrBVLXoxZn/pN5TXqaDbq7ju94viiQ=
|
||||
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/pkg/profile v1.7.0 h1:hnbDkaNWPCLMO9wGLdBFTIZvzDrDfBM2072E1S9gJkA=
|
||||
@@ -60,32 +58,32 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rrivera/identicon v0.0.0-20240116195454-d5ba35832c0d h1:l3+2LWCbVxn5itfvXAfH9n4YL9jh8l1g5zcncbIc1cs=
|
||||
github.com/rrivera/identicon v0.0.0-20240116195454-d5ba35832c0d/go.mod h1:TbpErkob6SY7cyozRVSGoB3OlO2qOAgVN8O3KAJ4fMI=
|
||||
github.com/rymdport/portal v0.4.2 h1:7jKRSemwlTyVHHrTGgQg7gmNPJs88xkbKcIL3NlcmSU=
|
||||
github.com/rymdport/portal v0.4.2/go.mod h1:kFF4jslnJ8pD5uCi17brj/ODlfIidOxlgUDTO5ncnC4=
|
||||
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/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c h1:km8GpoQut05eY3GiYWEedbTT0qnSxrCjsVbb7yKY1KE=
|
||||
github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c/go.mod h1:cNQ3dwVJtS5Hmnjxy6AgTPd0Inb3pW05ftPSX7NZO7Q=
|
||||
github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef h1:Ch6Q+AZUxDBCVqdkI8FSpFyZDtCVBc2VmejdNrm5rRQ=
|
||||
github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef/go.mod h1:nXTWP6+gD5+LUJ8krVhhoeHjvHTutPxMYl5SvkcnJNE=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/yuin/goldmark v1.7.13 h1:GPddIs617DnBLFFVJFgpo1aBfe/4xcvMc3SB5t/D0pA=
|
||||
github.com/yuin/goldmark v1.7.13/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg=
|
||||
golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4=
|
||||
golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc=
|
||||
golang.org/x/image v0.30.0 h1:jD5RhkmVAnjqaCUXfbGBrn3lpxbknfN9w2UhHHU+5B4=
|
||||
golang.org/x/image v0.30.0/go.mod h1:SAEUTxCCMWSrJcCy/4HwavEsfZZJlYxeHLc6tTiAe/c=
|
||||
golang.org/x/mod v0.27.0 h1:kb+q2PyFnEADO2IEF935ehFUXlWiNjJWtRNgBLSfbxQ=
|
||||
golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc=
|
||||
golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
|
||||
golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
|
||||
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
|
||||
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
|
||||
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
|
||||
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
|
||||
golang.org/x/tools v0.36.0 h1:kWS0uv/zsvHEle1LbV5LE8QujrxB3wfQyxHfhOk0Qkg=
|
||||
golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s=
|
||||
github.com/yuin/goldmark v1.7.8 h1:iERMLn0/QJeHFhxSt3p6PeN9mGnvIKSpG9YYorDMnic=
|
||||
github.com/yuin/goldmark v1.7.8/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
|
||||
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
|
||||
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
|
||||
golang.org/x/image v0.24.0 h1:AN7zRgVsbvmTfNyqIbbOraYL8mSwcKncEj8ofjgzcMQ=
|
||||
golang.org/x/image v0.24.0/go.mod h1:4b/ITuLfqYq1hqZcjofwctIhi7sZh2WaCjvsBNjjya8=
|
||||
golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
|
||||
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||
golang.org/x/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.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=
|
||||
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
||||
golang.org/x/tools v0.25.0 h1:oFU9pkj/iJgs+0DT+VMHrx+oBKs/LJMV+Uvg78sl+fE=
|
||||
golang.org/x/tools v0.25.0/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg=
|
||||
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/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
@@ -99,5 +97,5 @@ mellium.im/xmlstream v0.15.4 h1:gLKxcWl4rLMUpKgtzrTBvr4OexPeO/edYus+uK3F6ZI=
|
||||
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/go.mod h1:WSjq12nhREFD88Vy/0WD6Q8inE8t6a8w7QjzwivWitw=
|
||||
pain.agency/oasis-sdk v0.0.0-20250809192709-a3e5dff1aa61 h1:7zb69SAfLAJhXoqXZaS0pq/p1Y9W19Pm4FjcwWjTVoE=
|
||||
pain.agency/oasis-sdk v0.0.0-20250809192709-a3e5dff1aa61/go.mod h1:eyvDgfpHo+9bdB/AkMEMZ3ETeoSONTULVx9X4w9kGAU=
|
||||
pain.agency/oasis-sdk v0.0.0-20250831105702-85385dca3a95 h1:BcB7/hnMnQIU+pERvQRGFMt9i0/o8XCnHbK1kYG3/K4=
|
||||
pain.agency/oasis-sdk v0.0.0-20250831105702-85385dca3a95/go.mod h1:eyvDgfpHo+9bdB/AkMEMZ3ETeoSONTULVx9X4w9kGAU=
|
||||
|
500
main.go
500
main.go
@@ -22,20 +22,21 @@ import (
|
||||
"fyne.io/fyne/v2/storage"
|
||||
"fyne.io/fyne/v2/theme"
|
||||
"fyne.io/fyne/v2/widget"
|
||||
"github.com/rrivera/identicon"
|
||||
extraWidgets "fyne.io/x/fyne/widget"
|
||||
"github.com/rrivera/identicon"
|
||||
|
||||
// xmpp - required
|
||||
"mellium.im/xmpp/disco"
|
||||
_ "mellium.im/xmpp/disco"
|
||||
"mellium.im/xmpp/jid"
|
||||
"mellium.im/xmpp/muc"
|
||||
_ "mellium.im/xmpp/stanza"
|
||||
oasisSdk "pain.agency/oasis-sdk"
|
||||
// gui - optional
|
||||
// catppuccin "github.com/mbaklor/fyne-catppuccin"
|
||||
// TODO: integrated theme switcher
|
||||
)
|
||||
|
||||
var version string = "3.142a"
|
||||
var version string = "3i"
|
||||
var statBar widget.Label
|
||||
var chatInfo fyne.Container
|
||||
var chatSidebar fyne.Container
|
||||
@@ -105,6 +106,7 @@ type piConfig struct {
|
||||
Login oasisSdk.LoginInfo
|
||||
DMs []string
|
||||
Notifications bool
|
||||
JoinBookmarks bool
|
||||
}
|
||||
|
||||
var config piConfig
|
||||
@@ -161,14 +163,18 @@ func CreateUITab(chatJidStr string) ChatTabUI {
|
||||
content.Wrapping = fyne.TextWrapWord
|
||||
content.Selectable = true
|
||||
icon := theme.FileVideoIcon()
|
||||
replytext := widget.NewLabel("> fallback reply text")
|
||||
replytext.Hide()
|
||||
replytext.Importance = widget.SuccessImportance
|
||||
btn := widget.NewButtonWithIcon("View media", icon, func() {
|
||||
|
||||
})
|
||||
return container.NewVBox(container.NewHBox(ico, author), content, btn)
|
||||
return container.NewVBox(replytext, container.NewHBox(ico, author), content, btn)
|
||||
},
|
||||
func(i widget.ListItemID, co fyne.CanvasObject) {
|
||||
vbox := co.(*fyne.Container)
|
||||
authorBox := vbox.Objects[0].(*fyne.Container)
|
||||
authorBox := vbox.Objects[1].(*fyne.Container)
|
||||
replytext := vbox.Objects[0].(*widget.Label)
|
||||
// generate a Icon
|
||||
|
||||
gen, _ := identicon.New("github", 5, 3)
|
||||
@@ -181,8 +187,8 @@ func CreateUITab(chatJidStr string) ChatTabUI {
|
||||
// Icon generate end
|
||||
|
||||
author := authorBox.Objects[1].(*widget.Label)
|
||||
content := vbox.Objects[1].(*widget.Label)
|
||||
btn := vbox.Objects[2].(*widget.Button)
|
||||
content := vbox.Objects[2].(*widget.Label)
|
||||
btn := vbox.Objects[3].(*widget.Button)
|
||||
if chatTabs[chatJidStr].Messages[i].Important {
|
||||
//content.Importance = widget.DangerImportance TODO: Fix highlighting messages with mentions, it's currently broken
|
||||
}
|
||||
@@ -199,7 +205,8 @@ func CreateUITab(chatJidStr string) ChatTabUI {
|
||||
})
|
||||
return
|
||||
}
|
||||
if strings.HasSuffix(chatTabs[chatJidStr].Messages[i].ImageURL, "mp4") || strings.HasSuffix(chatTabs[chatJidStr].Messages[i].ImageURL, "mp3") {
|
||||
|
||||
if strings.HasSuffix(chatTabs[chatJidStr].Messages[i].ImageURL, "mp4") || strings.HasSuffix(chatTabs[chatJidStr].Messages[i].ImageURL, "mp3") || strings.HasSuffix(chatTabs[chatJidStr].Messages[i].ImageURL, "gif") || strings.HasSuffix(chatTabs[chatJidStr].Messages[i].ImageURL, "webp") { // FIXME: This code is fucking terrible // TODO: Could check mime?
|
||||
url, err := url.Parse(chatTabs[chatJidStr].Messages[i].ImageURL)
|
||||
if err != nil {
|
||||
fyne.Do(func() {
|
||||
@@ -232,7 +239,21 @@ func CreateUITab(chatJidStr string) ChatTabUI {
|
||||
//content.ParseMarkdown(msgContent)
|
||||
content.SetText(msgContent)
|
||||
if chatTabs[chatJidStr].Messages[i].ReplyID != "PICLIENT:UNAVAILABLE" {
|
||||
author.SetText(fmt.Sprintf("%s > %s", chatTabs[chatJidStr].Messages[i].Author, jid.MustParse(chatTabs[chatJidStr].Messages[i].Raw.Reply.To).Resourcepart()))
|
||||
reply := chatTabs[chatJidStr].Messages[i].Raw.Reply
|
||||
guy := jid.MustParse(reply.To).Resourcepart()
|
||||
// TODO: EXPERIMENTALLY GET REPLIED TO TEXT
|
||||
|
||||
|
||||
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", chatTabs[chatJidStr].Messages[i].Content))
|
||||
guy = chatTabs[chatJidStr].Messages[i].Author
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
author.SetText(fmt.Sprintf("%s > %s", chatTabs[chatJidStr].Messages[i].Author, guy))
|
||||
} else {
|
||||
author.SetText(chatTabs[chatJidStr].Messages[i].Author)
|
||||
}
|
||||
@@ -287,7 +308,7 @@ func addChatTab(isMuc bool, chatJid jid.JID, nick string) {
|
||||
var icon fyne.Resource
|
||||
if isMuc {
|
||||
icon = theme.HomeIcon()
|
||||
} else{
|
||||
} else {
|
||||
icon = theme.AccountIcon()
|
||||
}
|
||||
|
||||
@@ -297,7 +318,7 @@ func addChatTab(isMuc bool, chatJid jid.JID, nick string) {
|
||||
}
|
||||
|
||||
func dropToSignInPage(reason string) {
|
||||
w = a.NewWindow("Welcome to Pi")
|
||||
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))
|
||||
@@ -367,6 +388,7 @@ func main() {
|
||||
|
||||
config = piConfig{}
|
||||
a = app.NewWithID("pi-im")
|
||||
//a.Settings().SetTheme(&myTheme{})
|
||||
reader, err := a.Storage().Open("pi.xml")
|
||||
if err != nil {
|
||||
dropToSignInPage(err.Error())
|
||||
@@ -391,69 +413,16 @@ func main() {
|
||||
notifications = config.Notifications
|
||||
|
||||
client, err := oasisSdk.CreateClient(
|
||||
&login,
|
||||
func(client *oasisSdk.XmppClient, msg *oasisSdk.XMPPChatMessage) {
|
||||
fmt.Println(msg)
|
||||
userJidStr := msg.From.Bare().String()
|
||||
tab, ok := chatTabs[userJidStr]
|
||||
fmt.Println(msg.From.String())
|
||||
if ok {
|
||||
str := *msg.CleanedBody
|
||||
if notifications {
|
||||
a.SendNotification(fyne.NewNotification(fmt.Sprintf("%s says", userJidStr), str))
|
||||
}
|
||||
var img string = ""
|
||||
if strings.Contains(str, "https://") {
|
||||
lines := strings.Split(str, "\n")
|
||||
for i, line := range lines {
|
||||
s := strings.Split(line, " ")
|
||||
for _, v := range s {
|
||||
_, err := url.Parse(v)
|
||||
if err == nil && strings.HasPrefix(v, "https://") {
|
||||
if strings.HasSuffix(v, ".png") || strings.HasSuffix(v, ".jpg") || strings.HasSuffix(v, ".jpeg") || strings.HasSuffix(v, ".webp") || strings.HasSuffix(v, ".mp4") {
|
||||
img = v
|
||||
}
|
||||
}
|
||||
}
|
||||
lines[i] = strings.Join(s, " ")
|
||||
}
|
||||
str = strings.Join(lines, " ")
|
||||
}
|
||||
var replyID string
|
||||
if msg.Reply == nil {
|
||||
replyID = "PICLIENT:UNAVAILABLE"
|
||||
} else {
|
||||
replyID = msg.Reply.ID
|
||||
}
|
||||
myMessage := Message{
|
||||
Author: msg.From.Resourcepart(),
|
||||
Content: str,
|
||||
ID: msg.ID,
|
||||
ReplyID: replyID,
|
||||
Raw: *msg,
|
||||
ImageURL: img,
|
||||
}
|
||||
&login)
|
||||
|
||||
tab.Messages = append(tab.Messages, myMessage)
|
||||
fyne.Do(func() {
|
||||
UITabs[userJidStr].Scroller.Refresh()
|
||||
if scrollDownOnNewMessage {
|
||||
UITabs[userJidStr].Scroller.ScrollToBottom()
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
func(client *oasisSdk.XmppClient, muc *muc.Channel, msg *oasisSdk.XMPPChatMessage) {
|
||||
// HACK: IGNORING ALL MESSAGES FROM CLASSIC MUC HISTORY IN PREPARATION OF MAM SUPPORT
|
||||
ignore := false
|
||||
correction := false
|
||||
important := false
|
||||
for _, v := range msg.Unknown {
|
||||
if v.XMLName.Local == "delay" { // Classic history message
|
||||
//ignore = true
|
||||
//fmt.Println("ignoring!")
|
||||
//return //what is blud doing
|
||||
}
|
||||
client.SetDmHandler(func(client *oasisSdk.XmppClient, msg *oasisSdk.XMPPChatMessage) {
|
||||
correction := false
|
||||
userJidStr := msg.From.Bare().String()
|
||||
tab, ok := chatTabs[userJidStr]
|
||||
if ok {
|
||||
str := *msg.CleanedBody
|
||||
if notifications {
|
||||
a.SendNotification(fyne.NewNotification(fmt.Sprintf("%s says", userJidStr), str))
|
||||
}
|
||||
|
||||
for _, v := range msg.Unknown {
|
||||
@@ -463,105 +432,186 @@ func main() {
|
||||
}
|
||||
}
|
||||
|
||||
var ImageID string = ""
|
||||
mucJidStr := msg.From.Bare().String()
|
||||
if tab, ok := chatTabs[mucJidStr]; ok {
|
||||
chatTabs[mucJidStr].Muc = muc
|
||||
str := *msg.CleanedBody
|
||||
if strings.Contains(str, login.DisplayName) {
|
||||
fmt.Println(str)
|
||||
important = true
|
||||
}
|
||||
if !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))
|
||||
}
|
||||
}
|
||||
if strings.Contains(str, "https://") {
|
||||
lines := strings.Split(str, "\n")
|
||||
for i, line := range lines {
|
||||
s := strings.Split(line, " ")
|
||||
for _, v := range s {
|
||||
_, err := url.Parse(v)
|
||||
if err == nil && strings.HasPrefix(v, "https://") {
|
||||
if strings.HasSuffix(v, ".png") || strings.HasSuffix(v, ".jpg") || strings.HasSuffix(v, ".jpeg") || strings.HasSuffix(v, ".webp") || strings.HasSuffix(v, ".mp4") || strings.HasSuffix(v, ".mp3") {
|
||||
ImageID = v
|
||||
}
|
||||
var img string = ""
|
||||
if strings.Contains(str, "https://") {
|
||||
lines := strings.Split(str, "\n")
|
||||
for i, line := range lines {
|
||||
s := strings.Split(line, " ")
|
||||
for _, v := range s {
|
||||
_, err := url.Parse(v)
|
||||
if err == nil && strings.HasPrefix(v, "https://") {
|
||||
if strings.HasSuffix(v, ".png") || strings.HasSuffix(v, ".jpg") || strings.HasSuffix(v, ".jpeg") || strings.HasSuffix(v, ".webp") || strings.HasSuffix(v, ".mp4") || strings.HasSuffix(v, ".gif") {
|
||||
img = v
|
||||
}
|
||||
}
|
||||
lines[i] = strings.Join(s, " ")
|
||||
}
|
||||
str = strings.Join(lines, " ")
|
||||
fmt.Println(str)
|
||||
}
|
||||
fmt.Println(msg.ID)
|
||||
var replyID string
|
||||
if msg.Reply == nil {
|
||||
replyID = "PICLIENT:UNAVAILABLE"
|
||||
} else {
|
||||
replyID = msg.Reply.To
|
||||
lines[i] = strings.Join(s, " ")
|
||||
}
|
||||
str = strings.Join(lines, " ")
|
||||
}
|
||||
var replyID string
|
||||
if msg.Reply == nil {
|
||||
replyID = "PICLIENT:UNAVAILABLE"
|
||||
} else {
|
||||
replyID = msg.Reply.ID
|
||||
}
|
||||
|
||||
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 + " (edited)"
|
||||
fyne.Do(func() {
|
||||
UITabs[mucJidStr].Scroller.Refresh()
|
||||
})
|
||||
return
|
||||
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 + " (edited)"
|
||||
fyne.Do(func() {
|
||||
UITabs[userJidStr].Scroller.Refresh()
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
myMessage := Message{
|
||||
Author: msg.From.Resourcepart(),
|
||||
Content: str,
|
||||
ID: msg.ID,
|
||||
ReplyID: replyID,
|
||||
Raw: *msg,
|
||||
ImageURL: img,
|
||||
}
|
||||
|
||||
tab.Messages = append(tab.Messages, myMessage)
|
||||
fyne.Do(func() {
|
||||
UITabs[userJidStr].Scroller.Refresh()
|
||||
if scrollDownOnNewMessage {
|
||||
UITabs[userJidStr].Scroller.ScrollToBottom()
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
client.SetGroupChatHandler(func(client *oasisSdk.XmppClient, muc *muc.Channel, msg *oasisSdk.XMPPChatMessage) {
|
||||
// HACK: IGNORING ALL MESSAGES FROM CLASSIC MUC HISTORY IN PREPARATION OF MAM SUPPORT
|
||||
ignore := false
|
||||
correction := false
|
||||
important := false
|
||||
donotnotify := false
|
||||
for _, v := range msg.Unknown {
|
||||
if v.XMLName.Local == "delay" { // Classic history message
|
||||
donotnotify = true
|
||||
//ignore = true
|
||||
//fmt.Println("ignoring!")
|
||||
//return //what is blud doing
|
||||
}
|
||||
}
|
||||
|
||||
for _, v := range msg.Unknown {
|
||||
if v.XMLName.Local == "replace" {
|
||||
correction = true
|
||||
break // dont need to look at more fields
|
||||
}
|
||||
}
|
||||
|
||||
var ImageID string = ""
|
||||
mucJidStr := msg.From.Bare().String()
|
||||
if tab, ok := chatTabs[mucJidStr]; ok {
|
||||
chatTabs[mucJidStr].Muc = muc
|
||||
str := *msg.CleanedBody
|
||||
if strings.Contains(str, login.DisplayName) {
|
||||
fmt.Println(str)
|
||||
important = true
|
||||
}
|
||||
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))
|
||||
}
|
||||
}
|
||||
if strings.Contains(str, "https://") {
|
||||
lines := strings.Split(str, "\n")
|
||||
for i, line := range lines {
|
||||
s := strings.Split(line, " ")
|
||||
for _, v := range s {
|
||||
_, err := url.Parse(v)
|
||||
if err == nil && strings.HasPrefix(v, "https://") {
|
||||
if strings.HasSuffix(v, ".png") || strings.HasSuffix(v, ".jpg") || strings.HasSuffix(v, ".jpeg") || strings.HasSuffix(v, ".webp") || strings.HasSuffix(v, ".mp4") || strings.HasSuffix(v, ".mp3") || strings.HasSuffix(v, ".gif") {
|
||||
ImageID = v
|
||||
}
|
||||
}
|
||||
}
|
||||
lines[i] = strings.Join(s, " ")
|
||||
}
|
||||
str = strings.Join(lines, " ")
|
||||
fmt.Println(str)
|
||||
}
|
||||
fmt.Println(msg.ID)
|
||||
var replyID string
|
||||
if msg.Reply == nil {
|
||||
replyID = "PICLIENT:UNAVAILABLE"
|
||||
} else {
|
||||
replyID = msg.Reply.To
|
||||
}
|
||||
|
||||
myMessage := Message{
|
||||
Author: msg.From.Resourcepart(),
|
||||
Content: str,
|
||||
ID: msg.ID,
|
||||
ReplyID: replyID,
|
||||
Raw: *msg,
|
||||
ImageURL: ImageID,
|
||||
Important: important,
|
||||
}
|
||||
if !ignore {
|
||||
tab.Messages = append(tab.Messages, myMessage)
|
||||
}
|
||||
fyne.Do(func() {
|
||||
UITabs[mucJidStr].Scroller.Refresh()
|
||||
if scrollDownOnNewMessage {
|
||||
UITabs[mucJidStr].Scroller.ScrollToBottom()
|
||||
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 + " (edited)"
|
||||
fyne.Do(func() {
|
||||
UITabs[mucJidStr].Scroller.Refresh()
|
||||
})
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
func(_ *oasisSdk.XmppClient, from jid.JID, state oasisSdk.ChatState) {
|
||||
switch state {
|
||||
case oasisSdk.ChatStateComposing:
|
||||
fyne.Do(func() {
|
||||
statBar.SetText(fmt.Sprintf("%s is typing...", from.Resourcepart()))
|
||||
})
|
||||
case oasisSdk.ChatStatePaused:
|
||||
|
||||
fyne.Do(func() {
|
||||
statBar.SetText(fmt.Sprintf("%s has stopped typing.", from.Resourcepart()))
|
||||
})
|
||||
case oasisSdk.ChatStateInactive:
|
||||
fyne.Do(func() {
|
||||
statBar.SetText(fmt.Sprintf("%s is idle", from.Resourcepart()))
|
||||
})
|
||||
case oasisSdk.ChatStateGone:
|
||||
fyne.Do(func() {
|
||||
statBar.SetText(fmt.Sprintf("%s is gone", from.Resourcepart()))
|
||||
})
|
||||
default:
|
||||
fyne.Do(func() {
|
||||
statBar.SetText("")
|
||||
})
|
||||
myMessage := Message{
|
||||
Author: msg.From.Resourcepart(),
|
||||
Content: str,
|
||||
ID: msg.ID,
|
||||
ReplyID: replyID,
|
||||
Raw: *msg,
|
||||
ImageURL: ImageID,
|
||||
Important: important,
|
||||
}
|
||||
},
|
||||
if !ignore {
|
||||
tab.Messages = append(tab.Messages, myMessage)
|
||||
}
|
||||
fyne.Do(func() {
|
||||
UITabs[mucJidStr].Scroller.Refresh()
|
||||
if scrollDownOnNewMessage {
|
||||
UITabs[mucJidStr].Scroller.ScrollToBottom()
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
client.SetChatstateHandler(func(_ *oasisSdk.XmppClient, from jid.JID, state oasisSdk.ChatState) {
|
||||
switch state {
|
||||
case oasisSdk.ChatStateComposing:
|
||||
fyne.Do(func() {
|
||||
statBar.SetText(fmt.Sprintf("%s is typing...", from.Resourcepart()))
|
||||
})
|
||||
case oasisSdk.ChatStatePaused:
|
||||
|
||||
fyne.Do(func() {
|
||||
statBar.SetText(fmt.Sprintf("%s has stopped typing.", from.Resourcepart()))
|
||||
})
|
||||
case oasisSdk.ChatStateInactive:
|
||||
fyne.Do(func() {
|
||||
statBar.SetText(fmt.Sprintf("%s is idle", from.Resourcepart()))
|
||||
})
|
||||
case oasisSdk.ChatStateGone:
|
||||
fyne.Do(func() {
|
||||
statBar.SetText(fmt.Sprintf("%s is gone", from.Resourcepart()))
|
||||
})
|
||||
default:
|
||||
fyne.Do(func() {
|
||||
statBar.SetText("")
|
||||
})
|
||||
}
|
||||
})
|
||||
client.SetDeliveryReceiptHandler(
|
||||
func(_ *oasisSdk.XmppClient, from jid.JID, id string) {
|
||||
fmt.Printf("Delivered %s to %s", id, from.String())
|
||||
},
|
||||
})
|
||||
|
||||
client.SetReadReceiptHandler(
|
||||
func(_ *oasisSdk.XmppClient, from jid.JID, id string) {
|
||||
for _, tab := range chatTabs {
|
||||
for i := len(tab.Messages) - 1; i >= 0; i-- {
|
||||
@@ -576,8 +626,8 @@ func main() {
|
||||
}
|
||||
}
|
||||
fmt.Printf("%s has seen %s\n", from.String(), id)
|
||||
},
|
||||
)
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
log.Fatalln("Could not create client - " + err.Error())
|
||||
}
|
||||
@@ -600,7 +650,7 @@ func main() {
|
||||
}()
|
||||
|
||||
a = app.New()
|
||||
//a.Settings().SetTheme(myTheme{})
|
||||
//a.Settings().SetTheme(&myTheme{})
|
||||
w = a.NewWindow("pi")
|
||||
w.Resize(fyne.NewSize(500, 500))
|
||||
|
||||
@@ -647,12 +697,15 @@ func main() {
|
||||
|
||||
url, uerr := url.Parse(strings.Split(text, " ")[0])
|
||||
if uerr == nil && strings.HasPrefix(strings.Split(text, " ")[0], "https://") {
|
||||
//err = client.SendImage(jid.MustParse(activeMucJid).Bare(), text, url.String(), &text)
|
||||
err = client.SendSingleFileMessage(jid.MustParse(activeMucJid).Bare(), url.String(), nil)
|
||||
if err != nil {
|
||||
dialog.ShowError(err, w)
|
||||
}
|
||||
return
|
||||
dialog.ShowConfirm("Confirm", "Do you want to embed this link into your message?", func(b bool) {
|
||||
if b {
|
||||
err = client.SendSingleFileMessage(jid.MustParse(activeMucJid).Bare(), url.String(), nil)
|
||||
if err != nil {
|
||||
dialog.ShowError(err, w)
|
||||
}
|
||||
return
|
||||
}
|
||||
}, w)
|
||||
}
|
||||
err = client.SendText(jid.MustParse(activeMucJid).Bare(), text)
|
||||
|
||||
@@ -735,6 +788,7 @@ func main() {
|
||||
return
|
||||
}
|
||||
selectedScroller.ScrollToBottom()
|
||||
selectedScroller.Refresh()
|
||||
})
|
||||
|
||||
jtt := fyne.NewMenuItem("jump to top", func() {
|
||||
@@ -743,6 +797,7 @@ func main() {
|
||||
return
|
||||
}
|
||||
selectedScroller.ScrollToTop()
|
||||
selectedScroller.Refresh()
|
||||
})
|
||||
|
||||
w.SetOnDropped(func(p fyne.Position, u []fyne.URI) {
|
||||
@@ -916,31 +971,66 @@ func main() {
|
||||
|
||||
})
|
||||
|
||||
servDisc := fyne.NewMenuItem("Disco features", func() {
|
||||
var search jid.JID
|
||||
dialog.ShowEntryDialog("Disco features", "JID: ", func(s string) { // TODO: replace with undeprecated widget
|
||||
search, err = jid.Parse(s)
|
||||
if err != nil {
|
||||
dialog.ShowError(err, w)
|
||||
return
|
||||
}
|
||||
/*
|
||||
servDisc := fyne.NewMenuItem("Disco features", func() {
|
||||
//var search jid.JID
|
||||
dialog.ShowEntryDialog("Disco features", "JID: ", func(s string) { // TODO: replace with undeprecated widgetd
|
||||
d := dialog.NewCustom("Please wait", "Close", widget.NewLabel("..."), w)
|
||||
d.Show()
|
||||
go func() {
|
||||
//search, err = jid.Parse(s)
|
||||
//if err != nil {
|
||||
// d.Hide()
|
||||
// dialog.ShowError(err, w)
|
||||
// return
|
||||
//}
|
||||
txt := `<iq from='ringen@muc.isekai.rocks/sunglocto'
|
||||
to='ringen@muc.iskai.rocks/snit'
|
||||
type='get'
|
||||
id='vc2'>
|
||||
<vCard xmlns='vcard-temp'/>
|
||||
</iq>`
|
||||
var stan stanza.IQ
|
||||
xml.Unmarshal([]byte(txt), &stan)
|
||||
if err != nil {
|
||||
d.Hide()
|
||||
dialog.ShowError(err, w)
|
||||
return
|
||||
}
|
||||
r, err := client.Session.EncodeIQ(client.Ctx, stan)
|
||||
if err != nil {
|
||||
d.Hide()
|
||||
dialog.ShowError(err, w)
|
||||
return
|
||||
}
|
||||
ra, _ := r.Token()
|
||||
t, _ := xml.MarshalIndent(ra, "", "\t")
|
||||
fmt.Println(string(t))
|
||||
d.Hide()
|
||||
/*
|
||||
|
||||
myBox := container.NewGridWithColumns(1, widget.NewLabel("Items"))
|
||||
info, err := disco.GetInfo(client.Ctx, "", search, client.Session)
|
||||
if err != nil {
|
||||
dialog.ShowError(err, w)
|
||||
return
|
||||
}
|
||||
m := info.Features
|
||||
for _, v := range m {
|
||||
myBox.Add(widget.NewLabel(v.Var))
|
||||
myBox.Refresh()
|
||||
}
|
||||
myBox := container.NewGridWithColumns(1, widget.NewLabel("Items"))
|
||||
info, err := disco.GetInfo(client.Ctx, "", search, client.Session)
|
||||
if err != nil {
|
||||
d.Hide()
|
||||
dialog.ShowError(err, w)
|
||||
return
|
||||
}
|
||||
m := info.Identity
|
||||
bytes, err := xml.MarshalIndent(m, "", "\t")
|
||||
if err != nil {
|
||||
d.Hide()
|
||||
dialog.ShowError(err, w)
|
||||
return
|
||||
}
|
||||
fyne.Do(func() {d.Hide()})
|
||||
myBox.Objects = append(myBox.Objects, widget.NewLabel(string(bytes)))
|
||||
dialog.ShowCustom("Service discovery", "cancel", myBox, w)
|
||||
}()
|
||||
|
||||
dialog.ShowCustom("Features", "cancel", myBox, w)
|
||||
|
||||
}, w)
|
||||
})
|
||||
}, w)
|
||||
})
|
||||
*/
|
||||
|
||||
savedata := fyne.NewMenuItem("DEBUG: Save tab data to disk", func() {
|
||||
d := []ChatTab{}
|
||||
@@ -955,9 +1045,31 @@ func main() {
|
||||
os.Create("test.xml")
|
||||
os.WriteFile("text.xml", b, os.ModeAppend)
|
||||
})
|
||||
menu_help := fyne.NewMenu("π", mit, reconnect, savedata)
|
||||
menu_help := fyne.NewMenu("π", mit, reconnect, savedata, fyne.NewMenuItem("Join rooms in bookmarks", func() {
|
||||
// FIXME: Race condition
|
||||
client.FetchBookmarks()
|
||||
rooms := client.BookmarkCache()
|
||||
for _, v := range rooms {
|
||||
go func() {
|
||||
if v.Autojoin == true {
|
||||
joinjid, err := v.JID.WithResource(login.DisplayName)
|
||||
if err != nil {
|
||||
dialog.ShowError(err, w)
|
||||
return
|
||||
}
|
||||
room, err := client.MucClient.Join(client.Ctx, joinjid, client.Session)
|
||||
if err != nil {
|
||||
dialog.ShowError(err, w)
|
||||
return
|
||||
}
|
||||
client.MucChannels[v.JID.String()] = room
|
||||
addChatTab(true, v.JID, login.DisplayName)
|
||||
}
|
||||
}()
|
||||
}
|
||||
}))
|
||||
|
||||
menu_changeroom := fyne.NewMenu("Α", mic, servDisc, beginADM, joinARoom, leaveRoom)
|
||||
menu_changeroom := fyne.NewMenu("Α", mic, beginADM, joinARoom, leaveRoom)
|
||||
menu_configureview := fyne.NewMenu("Β", mia, mis, jtt, jtb)
|
||||
hafjag := fyne.NewMenuItem("Hafjag", func() {
|
||||
entry.Text = "Hafjag"
|
||||
@@ -1017,8 +1129,7 @@ func main() {
|
||||
})
|
||||
|
||||
bic := fyne.NewMenuItem("show message XML", func() {
|
||||
pre := widget.NewMultiLineEntry()
|
||||
|
||||
pre := widget.NewLabel("")
|
||||
selectedScroller, ok := AppTabs.Selected().Content.(*widget.List)
|
||||
if !ok {
|
||||
return
|
||||
@@ -1039,11 +1150,12 @@ func main() {
|
||||
return
|
||||
}
|
||||
pre.SetText(string(bytes))
|
||||
pre.Selectable = true
|
||||
pre.Refresh()
|
||||
dialog.ShowCustom("Message", "Close", pre, w)
|
||||
})
|
||||
|
||||
red := fyne.NewMenuItem("show people who have read this message", func() {
|
||||
red := fyne.NewMenuItem("show read receipts on message", func() {
|
||||
pre := container.NewVBox()
|
||||
|
||||
selectedScroller, ok := AppTabs.Selected().Content.(*widget.List)
|
||||
|
Reference in New Issue
Block a user