Compare commits

...

35 Commits

Author SHA1 Message Date
knotteye 4d5b8e6bc1 Bump version to 1.0.3 2021-04-25 17:48:11 -05:00
knotteye ac324d0402 Properly mark chats as read 2021-04-25 17:33:07 -05:00
knotteye 2ede34c207 Open new chats when we don't have one yet
Set notification icon properly
2021-04-25 16:53:38 -05:00
knotteye 26e904b5e9 Ask for new 2fa codes when one doesn't work 2021-04-25 16:13:59 -05:00
knotteye 0e34a3b196 Handle cases of bad login info 2021-04-25 16:03:55 -05:00
knotteye e73f9afa6c Add new assets and ship with makefile 2021-04-25 15:53:05 -05:00
knotteye a510f5faf3 Add sound to notifications, and a silence option
Add an optional color icon
Compute PFP height from screen height instead of fixing it at 50
2021-04-25 15:48:15 -05:00
knotteye 4560215d7a Handle bad acctList settings 2021-04-25 15:06:00 -05:00
knotteye 4b55caca87 Fix .deb 2021-04-25 14:50:04 -05:00
knotteye a82116b1b5 Switch to running from source for dpkg 2021-04-25 14:37:20 -05:00
knotteye 51eea001d7 ignore a thing 2021-04-24 18:09:21 -05:00
knotteye edd5d87477 figure out .deb files for real haha totally this time 2021-04-24 18:08:54 -05:00
knotteye ab57a11a25 Update linux info 2021-04-24 15:57:31 -05:00
knotteye ade5c0d6d0 Manually clean up on debian 2021-04-24 15:43:29 -05:00
knotteye 691c79fc9a Update version, oops 2021-04-24 15:39:48 -05:00
knotteye 51ee61ff26 Tweak windows build targets 2021-04-24 15:38:35 -05:00
knotteye 863a0ef45c Update postinst script debian 2021-04-24 15:26:40 -05:00
knotteye 1cd48d60ce Pack up the windows installer 2021-04-24 15:25:05 -05:00
knotteye 3119434b29 fix an issue with makefile not making 2021-04-24 15:21:38 -05:00
knotteye 80fd4acb51 Ignore windows build system outputs 2021-04-24 15:09:12 -05:00
knotteye d3e9f3ac6f Clean up build system 2021-04-24 15:08:45 -05:00
knotteye 1c633628ee Update version 2021-04-24 15:08:24 -05:00
knotteye d3f3f5933e Change compile options to dynamically get file location 2021-04-22 15:00:35 -05:00
knotteye 1e1ee7cae5 Update 'README.md' 2021-04-19 19:23:40 -05:00
knotteye 724a31d4ab Better windows build system using pynsist. Add recipe for installer,
update docs, ignore the output directory, and add a patch that needs to
prepend plchat.py before building.
2021-04-19 18:11:21 -06:00
knotteye 27106a9bb4 fix deb/DEBIAN for real this time 2021-04-19 16:34:15 -05:00
knotteye a4f5e25994 .deb: fix dependencies 2021-04-18 20:09:42 -05:00
knotteye d32a4d5a06 Add .deb target 2021-04-18 19:57:22 -05:00
knotteye 8af9de903c Add some hidden dependencies 2021-04-18 19:41:23 -05:00
knotteye 7f2533c1be Update deb skeleton 2021-04-18 19:40:58 -05:00
Matilde Park 373c1c0820 build: always use python3 2021-04-18 12:45:06 -05:00
knotteye c57aae2368 update windows productver 2021-04-17 23:39:30 -05:00
knotteye fd9f3f7079 Merge branch 'master' of https://git.waldn.net/git/knotteye//plchat 2021-04-17 23:37:38 -05:00
knotteye 55691ff2bf Add totp support 2021-04-17 23:34:34 -05:00
knotteye dcab538e3f Update 'README.md' 2021-04-17 18:28:13 -05:00
12 changed files with 363 additions and 49 deletions

5
.gitignore vendored
View File

@ -1,3 +1,8 @@
__pycache__
plchat.build
dist
build
plchatdeb.py
plchatwindows.py
deb/**/*
!deb/DEBIAN

View File

@ -4,30 +4,60 @@ endif
ifeq ($(LIBDIR),)
LIBDIR := lib/
endif
PRODUCTVER=0100
VER = $(shell cat installer.cfg | grep version= | head -n 1 | sed s/version=//)
all: default pack
fresh: clean default pack
systemlibs: systemlibtarget pack
windows: windowstarget
dpkg: debtarget dpkg-build
windows: wtarget wpack
default:
python -m nuitka --follow-imports --enable-plugin=qt-plugins --include-qt-plugins=all --python-flag=-O -o plchat plchat.py
python3 -m nuitka --follow-imports --file-reference-choice=runtime --include-module=certifi --include-module=keyring.backends.kwallet --include-module=keyring.backends.chainer --enable-plugin=qt-plugins --include-qt-plugins=all --python-flag=-O -o plchat plchat.py
windowstarget:
python -m nuitka --follow-imports --include-module=win32ctypes --enable-plugin=qt-plugins --include-qt-plugins=all --windows-disable-console --windows-icon-from-ico=fedi.ico --windows-company-name=plchat --windows-product-name=plchat --windows-product-version=$(PRODUCTVER) --python-flag=-O -o plchat plchat.py
debtarget:
mkdir -p deb/usr/lib/plchat
echo "#!/usr/lib/plchat/venv/bin/python" > deb/usr/lib/plchat/plchatdeb.py
echo "" >> deb/usr/lib/plchat/plchatdeb.py
cat plchat.py >> deb/usr/lib/plchat/plchatdeb.py
chmod +x deb/usr/lib/plchat/plchatdeb.py
cp fedi.svg deb/usr/lib/plchat
cp fedi_color.svg deb/usr/lib/plchat
cp fedi.ico deb/usr/lib/plchat
cp notif.wav deb/usr/lib/plchat
cp send.svg deb/usr/lib/plchat
cp unread.svg deb/usr/lib/plchat
cp README.md deb/usr/lib/plchat
cp LICENSE deb/usr/lib/plchat
cp COPYING deb/usr/lib/plchat
cp audiowidget.py deb/usr/lib/plchat
cp misc.py deb/usr/lib/plchat
cp pleroma.py deb/usr/lib/plchat
cp monkeypatch.py deb/usr/lib/plchat
cp timeconvert.py deb/usr/lib/plchat
cp videowidget.py deb/usr/lib/plchat
systemlibtarget:
python -m nuitka --nofollow-imports --follow-import=misc --follow-import=monkeypatch --follow-import=pleroma --follow-import=timeconvert --follow-import=videowidget --follow-import=audiowidget --python-flag=-O -o plchat plchat.py
python3 -m nuitka --file-reference-choice=runtime --nofollow-imports --follow-import-to=misc --follow-import-to=monkeypatch --follow-import-to=pleroma --follow-import-to=timeconvert --follow-import-to=videowidget --follow-import-to=audiowidget --python-flag=-O -o plchat plchat.py
windowstarget:
cat windows.patch > plchatwindows.py
cat plchat.py >> plchatwindows.py
makensis -VERSION || die "No makensis in path"
python3 -m nsist installer.cfg
wpack:
mv build/nsis/PlChat_$(VER).exe .
zip plchat_windows.zip PlChat_$(VER).exe
pack:
mkdir dist
mv plchat dist
cp fedi.svg dist
cp notif.wav dist
cp fedi_color.svg dist
cp fedi.ico dist
cp send.svg dist
cp unread.svg dist
@ -35,14 +65,22 @@ pack:
cp LICENSE dist
cp COPYING dist
dpkg-build:
dpkg --build deb
mv deb.deb plchat.deb
clean:
rm -r dist || true
rm -r build || true
rm -r deb/usr || true
install:
mkdir $(PREFIX)$(LIBDIR)
install dist/plchat $(PREFIX)$(LIBDIR)
install dist/fedi.ico $(PREFIX)$(LIBDIR)
install dist/fedi.svg $(PREFIX)$(LIBDIR)
install dist/fedi_color.svg $(PREFIX)$(LIBDIR)
install dist/notif.wav $(PREFIX)$(LIBDIR)
install dist/send.svg $(PREFIX)$(LIBDIR)
install dist/unread.svg $(PREFIX)$(LIBDIR)
ln -sf $(PREFIX)$(LIBDIR)plchat $(PREFIX)bin/plchat

View File

@ -9,29 +9,31 @@ Run the binary or `python plchat.py`. Log in to your account on the fediverse an
Installation instructions for PlChat. If you are looking to package this program or build from source, skip to Building From Source or Packaging down below.
### Windows
Download and install [python 3.8.9](https://www.python.org/downloads/windows/) from the python.org and the [k-lite codec pack](https://www.codecguide.com/download_kl.htm). The basic version with default options should work fine.
Download and install the [k-lite codec pack](https://www.codecguide.com/download_kl.htm). The basic version with default options should work fine.
Download the latest plchat_windows.zip from https://git.waldn.net/git/knotteye/plchat/releases extract the zip file. Run setup.bat, and keep the setup-log file if something does not work. Run plchat.exe and log in!
No guarantees on Windows 7, but windows 8 and 10 should work fine.
Download the installer from https://pond.waldn.net/plchat/windows/latest.zip extract the zip file. Other versions can be found at, for example, https://pond.waldn.net/plchat/windows/1.0.1.zip . Run the installer.
### Linux
A prepackaged deb file is provided in https://git.waldn.net/git/knotteye/plchat/releases as well as a compiled binary for amd64 linux.
A prepackaged deb file is provided in https://git.waldn.net/git/knotteye/plchat/releases as ~~well as a compiled binary for amd64 linux~~. The precompiled binary was extremely not-portable and did not work well. Use a package or build from source.
If you package plchat for your distro, please let me know and I will add it here.
Gentoo: can be found in [this overlay](https://git.waldn.net/git/knotteye/overlay)
### MacOS
Nuitka does not support cross compilation and I have a working MacOS machine or VM, but it should theoretically compile and run just fine. Feel free to message me for support, and I'll be glad to link to your site if you host any binaries you build.
~~Nuitka does not support cross compilation and I do not have a working MacOS machine or VM, but it should theoretically compile and run just fine. Feel free to message me for support, and I'll be glad to link to your site if you host any binaries you build.~~
A macos binary has been provided by [~am](https://decept.org/users/am). You can find it on the releases page. Run `brew install libmagic` before running.
## Building From Source or Packaging
PlChat comes with a Makefile for compiling to a binary, but it is of course possible to run the source directly with just `python plchat.py`. The easiest way to package PlChat is just to make sure the dependencies are installed and write a script that sets the appropriate pythonpath and runs plchat.py.
Otherwise you can see below for instructions on building the binary.
### Runtime Depencies
### Runtime Dependencies
You will need the following libraries: PyQt5, Secret Service (on linux or BSD), libmagic (python-magic-bin from pypi on windows), and some codecs for qtmultimedia.
The windows codecs can be found above, and on linux you will need gstreamer and some plugins. On gentoo, `sudo emerge media-plugins/gst-plugins-base media-plugins/gst-plugins-good media-plugins/gst-plugins-bad media-plugins/gst-plugins-ugly media-plugins/gst-plugins-neon media-plugins/gst-plugins-soup media-plugins/gst-plugins-libav` should do. Other distributions are on your own.
And, obviously, a copy of python. Python3.5+ is the only thing I will support but other versions may work. End users will need the same version of python used to compile the binary. Other versions may work but this is what nuitka officially supports.
### Building
You will need the following packages from pypi: PyQt5, keyring, appdirs, python-magic(or python-magic-bin on windows), python-dateutil, requests, urllib3, and websockets.
You will need the following packages from pypi: PyQt5, keyring, notify-py, appdirs, python-magic(or python-magic-bin on windows), python-dateutil, requests, urllib3, and websockets.
You will also need all runtime dependencies listed above, as well as nuitka3 and a C compiler. Nuitka supports the following compilers:
* gcc 5.1+ or g++ 4.4+

View File

@ -1,10 +1,11 @@
Package: plchat
Version: 1.0
Version: 1.0.3
Section: net
Priority: optional
Architecture: linux-amd64
Architecture: all
Description: A pleroma chat client
Homepage: https://git.waldn.net/git/knotteye/plchat
Maintainer: Knott Eye<knotteye@airmail.cc>
Depends: python3 (>=3.8.0), PyQt5 (=5.15.2), dbus, libmagic1, python-pyqt5.qtmultimedia, libc6, libgstreamer-plugins-bad1.0-0, qtgstreamer-plugins-qt5
Suggests: gnome-keyring (>= 2.30)
Maintainer: Knott Eye <knotteye@airmail.cc>
Pre-Depends: python3 (>= 3.8.0~), python3-pip (>= 19.3), python3-venv, bash
Depends: dbus, libmagic1, libc6, gstreamer1.0-nice, gstreamer1.0-libav, gstreamer1.0-plugins-bad, gstreamer1.0-plugins-good, gstreamer1.0-plugins-ugly, gstreamer1.0-qt5, gstreamer1.0-plugins-base, gstreamer1.0-python3-plugin-loader, python3-keyring, python3-appdirs, python3-magic, python3-dateutil, python3-websockets, python3-requests, python3-dateutil, python3-urllib3
Suggests: gnome-keyring

View File

@ -1,2 +1,10 @@
#!/bin/sh
ln -sf /usr/lib/plchat/plchat /usr/bin/plchat
#!/bin/bash
mkdir -p /usr/lib/plchat
cd /usr/lib/plchat
python3 -m venv --system-site-packages venv
source venv/bin/activate
pip3 install PyQt5==5.15.4 PyQt5-Qt5 PyQt5-sip notify-py
echo "#!/bin/sh" > /usr/bin/plchat
echo "/usr/lib/plchat/venv/bin/python /usr/plib/plchat/plchatdeb.py" >> /usr/bin/plchat
chmod +x /usr/bin/plchat

View File

@ -1,2 +1,3 @@
#!/bin/sh
rm -f /usr/bin/plchat
rm -rf /usr/lib/plchat

34
fedi_color.svg Normal file
View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="196.52mm" height="196.52mm" viewBox="0 0 196.52 196.52" version="1.1" id="svg8" inkscape:version="0.92.2 2405546, 2018-03-11" sodipodi:docname="Logo_penta_connectat-imbrincat_retallats-color.svg" inkscape:export-filename="/home/nestor/Pictures/Fediversal/Logo_penta_connectat-imbrincat_retallats-color-512x.png" inkscape:export-xdpi="66.175453" inkscape:export-ydpi="66.175453">
<defs id="defs2"/>
<sodipodi:namedview id="base" pagecolor="#ffffff" bordercolor="#666666" borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="0.50411932" inkscape:cx="-209.83484" inkscape:cy="399.15332" inkscape:document-units="mm" inkscape:current-layer="layer2" showgrid="false" inkscape:snap-smooth-nodes="true" inkscape:snap-midpoints="true" inkscape:snap-global="false" inkscape:window-width="1366" inkscape:window-height="736" inkscape:window-x="0" inkscape:window-y="32" inkscape:window-maximized="1" fit-margin-top="5" fit-margin-left="5" fit-margin-right="5" fit-margin-bottom="5"/>
<metadata id="metadata5">
<rdf:RDF>
<cc:Work rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
<dc:title/>
</cc:Work>
</rdf:RDF>
</metadata>
<g inkscape:groupmode="layer" id="layer2" inkscape:label="Linies" style="display:inline" transform="translate(6.6789703,-32.495842)">
<path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#a730b8;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:41.5748024;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 181.13086,275.13672 a 68.892408,68.892408 0 0 1 -29.46484,29.32812 l 161.75781,162.38868 38.99805,-19.76368 z m 213.36328,214.1875 -38.99805,19.76367 81.96289,82.2832 a 68.892409,68.892409 0 0 1 29.47071,-29.33203 z" transform="matrix(0.26458333,0,0,0.26458333,-6.6789703,32.495842)" id="path9722" inkscape:connector-curvature="0"/>
<path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#5496be;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:41.5748024;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 581.64648,339.39062 -91.57617,46.41016 6.75196,43.18945 103.61523,-52.51367 A 68.892409,68.892409 0 0 1 581.64648,339.39062 Z M 436.9082,412.74219 220.38281,522.47656 a 68.892408,68.892408 0 0 1 18.79492,37.08985 L 443.66016,455.93359 Z" transform="matrix(0.26458333,0,0,0.26458333,-6.6789703,32.495842)" id="path9729" inkscape:connector-curvature="0"/>
<path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ce3d1a;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:41.5748024;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="M 367.27539,142.4375 262.79492,346.4082 293.64258,377.375 404.26562,161.41797 A 68.892408,68.892408 0 0 1 367.27539,142.4375 Z m -131.6543,257.02148 -52.92187,103.31446 a 68.892409,68.892409 0 0 1 36.98633,18.97851 l 46.78125,-91.32812 z" transform="matrix(0.26458333,0,0,0.26458333,-6.6789703,32.495842)" id="path9713" inkscape:connector-curvature="0"/>
<path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#d0188f;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:41.5748024;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 150.76758,304.91797 a 68.892408,68.892408 0 0 1 -34.41602,7.19531 68.892408,68.892408 0 0 1 -6.65039,-0.69531 l 30.90235,197.66211 a 68.892409,68.892409 0 0 1 34.41601,-7.19531 68.892409,68.892409 0 0 1 6.64649,0.69531 z" transform="matrix(0.26458333,0,0,0.26458333,-6.6789703,32.495842)" id="path1015" inkscape:connector-curvature="0"/>
<path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#5b36e9;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:41.5748024;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 239.3418,560.54492 a 68.892408,68.892408 0 0 1 0.7207,13.87696 68.892408,68.892408 0 0 1 -7.26758,27.17968 l 197.62891,31.71289 a 68.892409,68.892409 0 0 1 -0.72266,-13.8789 68.892409,68.892409 0 0 1 7.26953,-27.17774 z" transform="matrix(0.26458333,0,0,0.26458333,-6.6789703,32.495842)" id="path1674" inkscape:connector-curvature="0"/>
<path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#30b873;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:41.5748024;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 601.13281,377.19922 -91.21875,178.08203 a 68.892408,68.892408 0 0 1 36.99414,18.98242 L 638.125,396.18359 a 68.892409,68.892409 0 0 1 -36.99219,-18.98437 z" transform="matrix(0.26458333,0,0,0.26458333,-6.6789703,32.495842)" id="path1676" inkscape:connector-curvature="0"/>
<path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ebe305;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:41.5748024;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 476.72266,125.33008 a 68.892408,68.892408 0 0 1 -29.47071,29.33203 l 141.26563,141.81055 a 68.892409,68.892409 0 0 1 29.46875,-29.33204 z" transform="matrix(0.26458333,0,0,0.26458333,-6.6789703,32.495842)" id="path1678" inkscape:connector-curvature="0"/>
<path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#f47601;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:41.5748024;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 347.78711,104.63086 -178.57617,90.49805 a 68.892409,68.892409 0 0 1 18.79297,37.08593 l 178.57421,-90.50195 a 68.892408,68.892408 0 0 1 -18.79101,-37.08203 z" transform="matrix(0.26458333,0,0,0.26458333,-6.6789703,32.495842)" id="path1680" inkscape:connector-curvature="0"/>
<path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#57c115;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:41.5748024;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 446.92578,154.82617 a 68.892408,68.892408 0 0 1 -34.98242,7.48242 68.892408,68.892408 0 0 1 -6.0293,-0.63281 l 15.81836,101.29102 43.16211,6.92578 z m -16,167.02735 37.40039,239.48242 a 68.892409,68.892409 0 0 1 33.91406,-6.94336 68.892409,68.892409 0 0 1 7.20704,0.79101 L 474.08984,328.77734 Z" transform="matrix(0.26458333,0,0,0.26458333,-6.6789703,32.495842)" id="path9758" inkscape:connector-curvature="0"/>
<path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#dbb210;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:41.5748024;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 188.13086,232.97461 a 68.892408,68.892408 0 0 1 0.75781,14.0957 68.892408,68.892408 0 0 1 -7.16015,26.98242 l 101.36914,16.28125 19.92382,-38.9082 z m 173.73633,27.90039 -19.92578,38.91211 239.51367,38.4668 a 68.892409,68.892409 0 0 1 -0.69531,-13.71875 68.892409,68.892409 0 0 1 7.34961,-27.32422 z" transform="matrix(0.26458333,0,0,0.26458333,-6.6789703,32.495842)" id="path9760" inkscape:connector-curvature="0"/>
</g>
<g inkscape:groupmode="layer" id="layer3" inkscape:label="Nodes" style="display:inline;opacity:1" transform="translate(6.6789703,-32.495842)">
<circle style="fill:#ffca00;fill-opacity:0.99596773;stroke:none;stroke-width:0.26458332;stroke-opacity:0.96078431" id="path817" cx="106.26596" cy="51.535553" r="16.570711" transform="rotate(3.1178174)"/>
<circle id="path819" style="fill:#64ff00;fill-opacity:0.99596773;stroke:none;stroke-width:0.26458332;stroke-opacity:0.96078431" cx="171.42836" cy="110.19328" r="16.570711" transform="rotate(3.1178174)"/>
<circle id="path823" style="fill:#00a3ff;fill-opacity:0.99596773;stroke:none;stroke-width:0.26458332;stroke-opacity:0.96078431" cx="135.76379" cy="190.27704" r="16.570711" transform="rotate(3.1178174)"/>
<circle style="fill:#9500ff;fill-opacity:0.99596773;stroke:none;stroke-width:0.26458332;stroke-opacity:0.96078431" id="path825" cx="48.559471" cy="181.1138" r="16.570711" transform="rotate(3.1178174)"/>
<circle id="path827" style="fill:#ff0000;fill-opacity:0.99596773;stroke:none;stroke-width:0.26458332;stroke-opacity:0.96078431" cx="30.328812" cy="95.366837" r="16.570711" transform="rotate(3.1178174)"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 18 KiB

54
installer.cfg Normal file
View File

@ -0,0 +1,54 @@
[Application]
name=PlChat
version=1.0.3
script=plchatwindows.py
icon=fedi.ico
license_file=LICENSE
console=false
[Python]
version=3.8.9
include_msvcrt=true
[Include]
pypi_wheels = PyQt5==5.15.2
PyQt5-sip==12.8.1
appdirs==1.4.4
keyring==23.0.1
python-magic-bin==0.4.14
notify-py==0.3.1
python-dateutil==2.8.1
requests==2.25.1
urllib3==1.26.4
websockets==8.1
importlib-metadata==3.10.1
certifi==2020.12.5
chardet==4.0.0
colorama==0.4.4
idna==2.10
importlib-metadata==3.10.1
loguru==0.5.3
pywin32-ctypes==0.2.0
requests-download==0.1.2
six==1.15.0
urllib3==1.26.4
websockets==8.1
win32-setctime==1.0.3
yarg==0.1.9
zipp==3.4.1
files = COPYING
LICENSE
README.md
send.svg
unread.svg
fedi.svg
fedi.ico
packages= audiowidget
misc
monkeypatch
plchat
pleroma
timeconvert
videowidget

BIN
notif.wav Normal file

Binary file not shown.

190
plchat.py
View File

@ -37,6 +37,8 @@ APPDATA = appdirs.AppDirs('plchat', 'plchat').user_data_dir
THREADS = {}
STATIC_PREF = ''
ICON_PATH = os.path.join(os.path.dirname(__file__), "fedi.svg")
ICON_PATH_COLOR = os.path.join(os.path.dirname(__file__), "fedi_color.svg")
NOTIF_SOUND = os.path.join(os.path.dirname(__file__), 'notif.wav')
class App(QMainWindow):
settings = QSettings(APPDATA+"/settings.ini")
@ -51,10 +53,17 @@ class App(QMainWindow):
def initUI(self):
self.setWindowTitle(self.title)
self.setWindowIcon(QIcon(QPixmap(ICON_PATH)))
if self.settings.value('colorIcon', type=bool):
self.setWindowIcon(QIcon(QPixmap(ICON_PATH_COLOR)))
else:
self.setWindowIcon(QIcon(QPixmap(ICON_PATH)))
self.setGeometry(self.settings.value('left', type=int) or 10, self.settings.value('top', type=int) or 10, self.settings.value('width', type=int) or 640, self.settings.value('height', type=int) or 480)
if self.settings.value('silenceNotifications', type=bool):
Notification._notification_audio = None
self._exit = False
self.totpReady = False
self.Err = QErrorMessage()
exitAction = QAction('&Exit', self)
@ -102,9 +111,15 @@ class App(QMainWindow):
self.darkModeAction.setChecked(self.settings.value('darkMode', type=bool))
self.darkModeAction.setToolTip("Only affects chat bubbles")
self.colorIconAction = QAction("Use Color Icon", self, checkable=True, triggered=self.useColorIcon)
self.colorIconAction.setChecked(self.settings.value('colorIcon', type=bool))
self.sendNotificationsAction = QAction("Send Notifications", self, checkable=True)
self.sendNotificationsAction.setChecked(self.settings.value('sendNotifications', type=bool))
self.silenceNotifsAction = QAction("Silence Notifications", self, checkable=True, triggered=self.silenceNotifs)
self.silenceNotifsAction.setChecked(self.settings.value('silenceNotifications', type=bool))
self.fetchHeadersAction = QAction("Fetch Headers", self, checkable=True)
self.fetchHeadersAction.setChecked(self.settings.value('fetchHeaders', type=bool))
@ -127,10 +142,14 @@ class App(QMainWindow):
systraymenu.addAction(showAction)
systraymenu.addAction(hideAction)
systraymenu.addAction(self.silenceNotifsAction)
systraymenu.addAction(exitAction)
self.trayIcon = QSystemTrayIcon()
self.trayIcon.setIcon(QIcon(ICON_PATH))
if self.settings.value('colorIcon', type=bool):
self.trayIcon.setIcon(QIcon(ICON_PATH_COLOR))
else:
self.trayIcon.setIcon(QIcon(ICON_PATH))
self.trayIcon.setVisible(True)
self.trayIcon.setToolTip("PlChat")
self.trayIcon.setContextMenu(systraymenu)
@ -153,7 +172,9 @@ class App(QMainWindow):
prefsmenu.addAction(self.openInTrayAction)
prefsmenu.addAction(self.animatePicturesAction)
prefsmenu.addAction(self.darkModeAction)
prefsmenu.addAction(self.colorIconAction)
prefsmenu.addAction(self.sendNotificationsAction)
prefsmenu.addAction(self.silenceNotifsAction)
prefsmenu.addAction(self.fetchBackgroundsAction)
prefsmenu.addAction(self.fetchHeadersAction)
prefsmenu.addAction(self.twoFourTimeAction)
@ -199,9 +220,15 @@ class App(QMainWindow):
if not acctList:
self.newAcctDialog()
return
for acct in acctList:
CallThread(getAvi, None, acct['instance'])
self.initAcct(acct['instance'], acct['username'])
for ind in range(0,len(acctList)):
CallThread(getAvi, None, acctList[ind]['instance'])
try:
self.initAcct(acctList[ind]['instance'], acctList[ind]['username'])
except:
print("account info corrupted, deleting")
del acctList[ind]
if acctList:
self.settings.setValue('acctList', acctList)
def systrayClicked(self, reason):
if reason == QSystemTrayIcon.Trigger:
@ -210,6 +237,23 @@ class App(QMainWindow):
else:
self.show()
def silenceNotifs(self, dothing):
if dothing:
# Definitely not supposed to be poking around in the internals like this lul
Notification._notification_audio = None
else:
Notification.audio = NOTIF_SOUND
def useColorIcon(self, dothing):
if dothing:
self.setWindowIcon(QIcon(QPixmap(ICON_PATH_COLOR)))
if self.trayIcon:
self.trayIcon.setIcon(QIcon(ICON_PATH_COLOR))
else:
self.setWindowIcon(QIcon(QPixmap(ICON_PATH)))
if self.trayIcon:
self.trayIcon.setIcon(QIcon(ICON_PATH))
def eventLoop(self):
# Custom event loop to process queue events
self.processEvents()
@ -236,6 +280,8 @@ class App(QMainWindow):
self.settings.setValue("sendNotifications", self.sendNotificationsAction.isChecked())
self.settings.setValue("fetchHeaders", self.fetchHeadersAction.isChecked())
self.settings.setValue("twoFourTime", self.twoFourTimeAction.isChecked())
self.settings.setValue('colorIcon', self.colorIconAction.isChecked())
self.settings.setValue('silenceNotifications', self.silenceNotifsAction.isChecked())
event.accept()
self._eventloop.stop()
@ -245,6 +291,10 @@ class App(QMainWindow):
# Returns username, instance
return self.acctComboBox.currentText().split('@')[1], self.acctComboBox.currentText().split('@')[2]
def badLogin(self, name):
self.Err.showMessage("Bad login info for: "+name)
self.newAcctDialog()
def newAcctDialog(self):
dialog = LoginDialog(self)
dialog.getInput(self.initAcct)
@ -277,6 +327,20 @@ class App(QMainWindow):
self.settings.setValue('closed'+u+i, closedList)
CallThread(self.accts[u+i].addChat, self.populateChats, result['id']).start()
def getTotp(self, acct, challenge_type):
if type(challenge_type) != list:
challenge_type = [challenge_type, 'recovery']
self._eventloop.call_soon_threadsafe(self.makeTotpCard, '@'+acct.username+'@'+acct.instance, challenge_type)
while not self.totpReady:
monkeypatch.sleep(0.2)
t = self.totpReady
self.totpReady = None
return t
def makeTotpCard(self, acct, challenge_type):
dialog = TotpCard(acct, challenge_type)
dialog.getInput()
def contactDialog(self):
dialog = ContactCard(self)
dialog.show()
@ -294,7 +358,7 @@ class App(QMainWindow):
def initAcct(self, instance, username, password=None):
if password:
acct = pleroma.Account(instance, username, password)
acct = pleroma.Account(instance, username, password, totpFunc=self.getTotp)
else:
token = keyring.get_password('plchat', instance+username+'access_token')
refresh_token = keyring.get_password('plchat', instance+username+'refresh_token')
@ -304,7 +368,8 @@ class App(QMainWindow):
token=token,
refresh_token=refresh_token,
clientID=clientID,
clientSecret=clientSecret
clientSecret=clientSecret,
totpFunc=self.getTotp
)
RegisterThread(acct, self.doneRegister).start()
@ -352,7 +417,8 @@ class App(QMainWindow):
else:
self.setWindowTitle('PlChat')
self.tabs.clear()
CallThread(self.accts[u+i].listChats, self.populateChats).start()
if u and i:
CallThread(self.accts[u+i].listChats, self.populateChats).start()
def populateChats(self, chatList):
if type(chatList) == dict:
@ -392,17 +458,30 @@ class App(QMainWindow):
def handlePleromaEvent(self, acct, event):
if event['event'] == 'pleroma:chat_update':
payload = json.loads(event['payload'])
tmp = 0
tmp = -1
for ind in range(0, self.tabs.count()):
if self.tabs.widget(ind).acct == payload['account']['acct']:
self._eventloop.call_soon_threadsafe(self.tabs.widget(ind).addMessage, payload['last_message'])
tmp = ind
#self.tabs.widget(ind).addMessage(payload['last_message'])
if payload['last_message']['account_id'] != acct.flakeid and (not self.hasFocus() or payload['account']['acct'] != self.tabs.widget(self.tabs.currentIndex()).acct):
if self.sendNotificationsAction.isChecked():
CallThread(self.makeNotification, None, payload['last_message']['content'], payload['account']['acct'], payload['account']['avatar_static']).start()
app.alert(self, 0)
self._eventloop.call_soon_threadsafe(self.setUrgent, tmp)
if tmp > 0:
self._eventloop.call_soon_threadsafe(self.setUrgent, tmp)
else:
u, i = ex.getCurrentAcc()
tmp = self.tabs.count()
closedList = self.settings.value('closed'+u+i, type=list) or []
for ind in range(0,(len(closedList))):
if closedList[ind] == payload['account']['acct']:
del closedList[ind]
break
self.settings.setValue('closed'+u+i, closedList)
self._eventloop.call_soon_threadsafe(self.populateChats, payload)
while self.tabs.tabIcon(tmp).isNull():
time.sleep(0.3)
self._eventloop.call_soon_threadsafe(self.setUrgent, tmp)
def makeNotification(self, content, user, url):
path = getPic(url)
@ -429,8 +508,14 @@ class App(QMainWindow):
flip = False
if flip:
if self.trayIcon:
self.trayIcon.setIcon(QIcon(QPixmap(ICON_PATH)))
self.setWindowIcon(QIcon(QPixmap(ICON_PATH)))
if self.settings.value('colorIcon', type=bool):
self.trayIcon.setIcon(QIcon(ICON_PATH_COLOR))
else:
self.trayIcon.setIcon(QIcon(ICON_PATH))
if self.settings.value('colorIcon', type=bool):
self.setWindowIcon(QIcon(QPixmap(ICON_PATH_COLOR)))
else:
self.setWindowIcon(QIcon(QPixmap(ICON_PATH)))
self.tabs.widget(ind).markRead()
self.tabs.widget(ind).setFocus(Qt.NoFocusReason)
@ -453,8 +538,14 @@ class App(QMainWindow):
flip = False
if flip:
if self.trayIcon:
self.trayIcon.setIcon(QIcon(QPixmap(ICON_PATH)))
self.setWindowIcon(QIcon(QPixmap(ICON_PATH)))
if self.settings.value('colorIcon', type=bool):
self.trayIcon.setIcon(QIcon(ICON_PATH_COLOR))
else:
self.trayIcon.setIcon(QIcon(ICON_PATH))
if self.settings.value('colorIcon', type=bool):
self.setWindowIcon(QIcon(QPixmap(ICON_PATH_COLOR)))
else:
self.setWindowIcon(QIcon(QPixmap(ICON_PATH)))
self.tabs.widget(ind).markRead()
self.tabs.widget(ind).setFocus(Qt.NoFocusReason)
@ -641,11 +732,11 @@ class MessageArea(QWidget):
CallThread(ex.accts[u+i].getMessages, self._update, self.chatID).start()
def markRead(self):
if not self.last_read_id:
return
u, i = ex.getCurrentAcc()
if not self.last_read_id or not u or not i:
return
acc = ex.accts[u+i]
acc.markChatRead(self.chatID, self.last_read_id)
CallThread(acc.markChatRead, None, self.chatID, self.last_read_id).start()
def addPage(self):
if self.fetchingPage:
@ -665,6 +756,7 @@ class MessageArea(QWidget):
for message in messages:
if message['account_id'] == self.account['id']:
self.last_read_id = message['id']
break
for i in reversed(range(self.layout.count())):
self.layout.itemAt(i).widget().setParent(None)
for message in reversed(messages):
@ -738,13 +830,13 @@ class SingleMessage(QWidget):
p = QPixmap(path)
if p.isNull():
p = QPixmap(APPDATA+'/'+ex.getCurrentAcc()[1]+'avi.png')
p = p.scaledToHeight(50, mode=Qt.SmoothTransformation)
p = p.scaledToHeight(round(QDesktopWidget().screenGeometry(-1).height() / 21.6), mode=Qt.SmoothTransformation)
self.userPixmap = p
def setConvoPixmap(self, path):
p = QPixmap(path)
if p.isNull():
p = QPixmap(APPDATA+'/'+ex.getCurrentAcc()[1]+'avi.png')
p = p.scaledToHeight(50, mode=Qt.SmoothTransformation)
p = p.scaledToHeight(round(QDesktopWidget().screenGeometry(-1).height() / 21.6), mode=Qt.SmoothTransformation)
self.convoPixmap = p
class MessageAvatar(QLabel):
@ -1067,6 +1159,54 @@ class DetachDialog(QDialog):
self.raise_()
self.activateWindow()
class TotpCard(QDialog):
def __init__(self, acct, challenge_types, parent=None,):
super().__init__(parent=parent)
self.setWindowTitle("MFA Request")
self.result = None
self.waiting = False
QBtn = QDialogButtonBox.Ok
layout = QVBoxLayout()
self.buttonBox = QDialogButtonBox(QBtn)
self.buttonBox.accepted.connect(self.accept)
self.message = QLabel("2FA Required for "+acct)
tmp = QHBoxLayout()
tmpw = QWidget()
tmpw.setLayout(tmp)
self.comboboxlabel = QLabel("2FA Code Type:")
self.combobox = QComboBox()
self.combobox.addItems(challenge_types)
self.combobox.setDuplicatesEnabled(False)
self.combobox.setEditable(False)
tmp.addWidget(self.comboboxlabel)
tmp.addWidget(self.combobox)
self.code = QLineEdit()
self.code.setPlaceholderText('2FA Code')
layout.addWidget(self.message)
layout.addWidget(tmpw)
layout.addWidget(self.code)
layout.addWidget(self.buttonBox)
self.setLayout(layout)
self.setFocusProxy(self.code)
self.accepted.connect(self._finished)
def _finished(self):
ex.totpReady = (self.code.text(), self.combobox.currentText())
def getInput(self, *args, **kwargs):
self.exec_()
self.show()
self.raise_()
self.activateWindow()
class LoginDialog(QDialog):
def __init__(self, parent=None):
super().__init__(parent=parent)
@ -1284,7 +1424,11 @@ class RegisterThread(threading.Thread):
def run(self):
self.acct.register()
self.acct.login()
try:
self.acct.login()
except ValueError:
ex._eventloop.call_soon_threadsafe(ex.badLogin, self.acct.username+'@'+self.acct.instance)
return
NotifThread(self.acct).start()
self.acct.setChatUpdate(ex.handlePleromaEvent)
self.callback(self.acct)
@ -1321,8 +1465,8 @@ class IconLabel(QLabel):
Notification = Notify(
default_notification_title="PlChat",
default_notification_icon=ICON_PATH
#default_notification_audio=NOTIF_SOUND
default_notification_icon=ICON_PATH,
default_notification_audio=NOTIF_SOUND
)
def sendNotification(message, title=None, icon=None):

View File

@ -16,7 +16,7 @@
import re, requests, os.path, websockets, json
class Account():
def __init__(self, instance, username=' ', password='', clientID=None, clientSecret=None, token=None, refresh_token=None):
def __init__(self, instance, username=' ', password='', clientID=None, clientSecret=None, token=None, refresh_token=None, totpFunc=None):
scheme = re.compile('https?://')
self.instance = re.sub(scheme, '', instance)
if(self.instance[len(self.instance) - 1] == '/'):
@ -39,6 +39,7 @@ class Account():
self._instanceInfo = None
self.flakeid = None
self.acct = None
self.totpFunc = totpFunc
self.chat_update = None
@ -83,6 +84,23 @@ class Account():
'redirect_uris': "urn:ietf:wg:oauth:2.0:oob"
}
response = self.apiRequest('POST', '/oauth/token', request_data)
if 'error' in response and response['error'] == 'mfa_required':
if response['supported_challenge_types'] == 'totp' or 'totp' in response['supported_challenge_types']:
ctypes = response['supported_challenge_types']
mfa_token = response['mfa_token']
while True:
mfa_code, code_type = self.totpFunc(self, ctypes)
response = self.apiRequest('POST', '/oauth/mfa/challenge', {
'client_id': self.clientID,
'client_secret': self.clientSecret,
'mfa_token': mfa_token,
'challenge_type': code_type,
'code': mfa_code
})
if not 'error' in response:
break
elif 'error' in response:
raise ValueError
self.token = response['access_token']
self.refresh_token = response['refresh_token']
r = self.apiRequest('GET', '/api/v1/accounts/verify_credentials')

9
windows.patch Normal file
View File

@ -0,0 +1,9 @@
#!python3.8
import sys, os
import site
scriptdir, script = os.path.split(os.path.abspath(__file__))
pkgdir = os.path.join(scriptdir, 'pkgs')
# Ensure .pth files in pkgdir are handled properly
site.addsitedir(pkgdir)
sys.path.insert(0, pkgdir)