103 Commits

Author SHA1 Message Date
ouwou
f9864a24ed update readme 2022-01-27 00:15:26 -05:00
ouwou
738d50dd43 add setting to not show unread stuff 2022-01-26 18:44:31 -05:00
ouwou
7d49f934bc muted dms dont contribute to unread count 2022-01-26 18:43:47 -05:00
ouwou
fbb5522861 bump vcpkg 2022-01-23 20:27:08 -05:00
ouwou
0ce509f80e add settings for some colors 2022-01-21 00:41:35 -05:00
ouwou
b6b215ee6f add mark as unread/toggle mute for threads 2022-01-20 02:45:28 -05:00
ouwou
d7f3ee9f98 handle mute/unmute updates for threads 2022-01-20 01:52:48 -05:00
ouwou
2328c8bafe handle initial muted state for threads 2022-01-20 01:40:27 -05:00
ouwou
dfd642bb82 show unread indicators for threads 2022-01-20 01:34:36 -05:00
ouwou
6c9bf4ff81 add toggle mute dm menu item 2022-01-15 01:51:11 -05:00
ouwou
604f2ffe3d show count of unread dms in header 2022-01-08 20:03:12 -05:00
ouwou
4e0b22375f handle mute/unmute for dms 2022-01-08 18:35:46 -05:00
ouwou
9d0c7691d8 fix initial read state for dms 2022-01-05 20:34:44 -05:00
ouwou
cef28e94ea add missing reset 2022-01-05 04:06:02 -05:00
ouwou
40106ddeb1 handle mutable categories 2022-01-05 03:52:20 -05:00
ouwou
8695562cb4 Merge branch 'master' into unread 2022-01-02 00:07:32 -05:00
ouwou
5338eab3a5 speed up connection speed a good bit
loading save state was slow so now theres a temporary lookup table
2021-12-31 16:42:06 -05:00
ouwou
d7bb6049e1 add mute/unmute guild menu item 2021-12-30 01:24:55 -05:00
ouwou
ea7464722b handle change of mute state for guilds 2021-12-29 23:51:12 -05:00
ouwou
d6da646d87 validate iso8601 when parsing to snowflake 2021-12-29 22:15:04 -05:00
ouwou
17c1f913df actually deserialize mute_config 2021-12-28 03:11:59 -05:00
ouwou
6c94e75513 take mute_config.end_time into account for muted entries 2021-12-28 02:58:31 -05:00
ouwou
801894abc6 messages sent by user shouldnt count as new unreads 2021-12-28 02:21:46 -05:00
ouwou
207c004228 take muted channels into account for unread guild indicator 2021-12-25 03:07:11 -05:00
ouwou
36f73a6106 check view permissions for channels in read state 2021-12-25 02:59:01 -05:00
ouwou
41d80af128 mark more channels as unread properly 2021-12-25 02:37:31 -05:00
ouwou
145504bdd6 add mark all as read 2021-12-22 01:44:26 -05:00
ouwou
9fd0d404a1 mark channel being switched off as read when switching 2021-12-20 02:13:18 -05:00
ouwou
b75599e55d fix bad if statement causing UB 2021-12-20 01:45:43 -05:00
ouwou
67062d6ed8 unread indicator for dm channels 2021-12-18 03:24:44 -05:00
ouwou
c43d49ed54 grey out muted channels in list 2021-12-18 02:17:43 -05:00
ouwou
e9867173c9 inline unread rendering 2021-12-18 02:06:16 -05:00
ouwou
f580535d35 add mute/unmute channel menu item 2021-12-18 01:58:29 -05:00
ouwou
1d7529e609 handle mute/unmute of channels (USER_GUILD_SETTINGS_UPDATE) 2021-12-17 02:34:14 -05:00
ouwou
1fb7ca0007 hide unread indicator for muted channels 2021-12-16 00:58:17 -05:00
ouwou
b576bd0fcc make fallback for config file go in home directory if possible (#52) 2021-12-15 17:43:11 -05:00
ouwou
a5332efcfb fix compile 2021-12-12 21:14:20 -05:00
ouwou
15954830e2 hide guild unread indicator for muted guilds 2021-12-10 03:26:33 -05:00
ouwou
46ab760a56 render total mentions on guild, redraw on message create 2021-12-10 01:41:19 -05:00
ouwou
0b0135268e basic channel mentions count indicator 2021-12-10 00:15:39 -05:00
ouwou
511fb445d1 rudimentary guild unread indicator 2021-12-09 02:54:59 -05:00
ouwou
bcfb2146cd mark guild as read (shift+esc) 2021-12-08 19:12:35 -05:00
ouwou
a1b662a325 make mark guild as read actually work properly 2021-12-07 02:51:29 -05:00
ouwou
14b5bf7d0d reorder menu items 2021-12-06 17:35:44 -05:00
ouwou
d288989386 mark guild as read 2021-12-06 03:04:22 -05:00
ouwou
d63941797f mark channels as unread on MESSAGE_CREATE 2021-12-05 04:07:30 -05:00
ouwou
1ea2811713 dont send acks for channels known to be read 2021-12-05 04:00:02 -05:00
ouwou
af56784797 basic unread indicators for channels 2021-12-05 03:57:26 -05:00
ouwou
2461406887 split channel CellRenderer into its own sources 2021-12-04 02:21:08 -05:00
ouwou
8e11dd97e9 dont make requests for inaccessible channels 2021-12-01 03:42:15 -05:00
ouwou
2690febf20 fix corrupted disk image sqlite error (fixes #51) 2021-11-29 21:51:15 -05:00
ouwou
af3d278825 rename find module (fixes #50) 2021-11-29 17:16:11 -05:00
ouwou
e02107feea actually retrieve roles for guilds
FetchRoles isnt needed anymore cuz full roles are fetched now
2021-11-28 22:42:55 -05:00
ouwou
192b043e7a fix distortion of non-1:1 emojis 2021-11-28 22:40:41 -05:00
ouwou
8c72d4c18d dont print identify message to console
mainly since i feel its only a matter of time before someone copy pastes it somewhere and itd be my fault
also typedef -> using
2021-11-25 02:57:11 -05:00
ouwou
0da913cd4a remove unnecessary copying left over from debugging 2021-11-25 02:32:39 -05:00
ouwou
fb3d69c5e7 bump build number in identify 2021-11-24 22:36:39 -05:00
ouwou
c40208ac66 update readme 2021-11-24 22:24:40 -05:00
ouwou
069c22e9cd add fetching private archived threads 2021-11-24 20:31:34 -05:00
ouwou
8f30bb33a3 fix build 2021-11-24 03:29:29 -05:00
ouwou
4326c5e29b remove SimpleIni as a dependency
use Glib::KeyFile instead which is basically the same file format
also read into and save from struct once, cuz its faster and less redundant
2021-11-24 03:15:22 -05:00
Dylam De La Torre
a51a54bc59 Restructure source and resource files (#46)
importantly, res is now res/res and css is now res/css
2021-11-23 04:21:56 +00:00
ouwou
d88079000a normalize include paths 2021-11-20 22:29:03 -05:00
ouwou
574cbc35d8 merge store 2021-11-20 18:48:15 -05:00
ouwou
fc76a15c46 fix sqlite error messages 2021-11-19 01:08:03 -05:00
Dylam De La Torre
9d21df8e1b Fix warnings shown by GCC (#47)
* fix all warnings shown by GCC
2021-11-16 19:38:14 +00:00
ouwou
1da2c57376 fix retrieving message references
and also add a reset statement i forgot (raii might be good here...)
2021-11-16 02:37:12 -05:00
ouwou
409af292af Merge branch 'master' into store 2021-11-14 02:27:23 -05:00
ouwou
108002248c presence of ThreadMember means user added to private thread 2021-11-13 03:09:17 -05:00
ouwou
43795f4c87 dont call StopDiscord in destructor
since the destructor is run during static destruction it can cause issues
it's redundant anyways as StopDiscord is slotted into Gtk::Application::signal_shutdown
2021-11-13 00:25:54 -05:00
ouwou
2257ff9798 fix double close of store throwing 2021-11-06 01:10:56 -04:00
ouwou
c40b8a4122 add files that should have been pushed with last commit
oops
2021-11-04 01:48:13 -04:00
ouwou
1f445742b4 preserve channel list expansion and active channel (#36)
also check getenv in platform
2021-11-04 01:39:56 -04:00
ouwou
d629846220 Merge branch 'master' of https://github.com/uowuo/abaddon 2021-11-02 21:01:58 -04:00
ouwou
b26b2d4be0 remove channel row css classes from readme 2021-11-02 21:01:54 -04:00
South
b65c09411a fix typo (#41) 2021-11-01 23:56:47 +00:00
ouwou
a51b813f70 some snowflake IsValid checks
mainly so i could debug something easier
2021-10-30 02:47:14 -04:00
ouwou
1078d94b73 fix big mistake that made it not run 2021-10-30 02:46:50 -04:00
ouwou
12c105623c templatize some stuff 2021-10-29 01:35:16 -04:00
ouwou
d950460e14 try to fix some more compilation errors/warnings 2021-10-28 04:19:05 -04:00
ouwou
2c2686946d try to fix weird ambiguous int stuff 2021-10-28 02:33:13 -04:00
ouwou
9175da2cf0 take care of some warnings 2021-10-28 02:19:13 -04:00
ouwou
14d025a342 dont use functions that dont actually exist 2021-10-28 02:08:29 -04:00
ouwou
c98b62caca fix syntax error 2021-10-28 00:42:04 -04:00
ouwou
d425997c26 rewrite store
this probably should have been broken up into smaller commits. oh well
2021-10-28 00:31:35 -04:00
ouwou
84b1b62e0e fix UB when all reactions on a msg are removed and one is added again 2021-10-27 03:01:53 -04:00
ouwou
b248e0ae9a set action versions 2021-10-18 23:56:36 -04:00
ouwou
f1a39c006f fix potential crash when loading channel with no messages 2021-10-16 16:54:25 -04:00
ouwou
3e34f785c6 Merge pull request #39 from Zander671/master
Fix another unchecked optional
2021-10-12 18:41:10 +00:00
Alexander Rosenberg
9694813724 Fix another unchecked optional 2021-10-12 03:30:26 -07:00
ouwou
3393526876 make ixwebsocket find module work 2021-10-11 02:10:18 -04:00
ouwou
b6424c9d37 update simpleini submodule 2021-10-11 01:40:51 -04:00
ouwou
bf560ae9d2 use find modules for ixwebsocket/simpleini 2021-10-11 01:03:31 -04:00
ouwou
fa1a007dc1 fix unchecked optionals
also discard exceptions in file cache futures
2021-10-08 17:52:38 -04:00
ouwou
abc0a7931e skip audit log entries with no target id 2021-10-06 02:57:15 -04:00
ouwou
ad523f37c5 preserve scroll position when loading history
it still jumps around a bit sometimes but its acceptable. hopefully there is a better solution
2021-10-06 02:30:30 -04:00
ouwou
cf33d53809 add relative to root #includes 2021-10-06 02:27:06 -04:00
ouwou
e8b1bcd216 remove FOUND_VAR
should also fix compilation in some situations because of sigc++
2021-10-06 00:55:21 -04:00
ouwou
dead7f2f6a fix #includes (#35) 2021-10-06 00:50:25 -04:00
ouwou
df6b01a632 dont purge on socket close 2021-09-29 01:14:33 -04:00
ouwou
9755090c8c try and fix potential crash on ROLE_UPDATE 2021-09-24 01:55:41 -04:00
ouwou
3815d97f5f use GTK emoji rendering by default on Windows 2021-09-21 01:49:36 -04:00
ouwou
7cb4a75ca7 update README with new info 2021-09-21 01:48:49 -04:00
241 changed files with 5272 additions and 3030 deletions

View File

@@ -15,17 +15,17 @@ jobs:
submodules: true
- name: Fetch CMake
uses: lukka/get-cmake@latest
uses: lukka/get-cmake@v3.21.2
- name: Fetch dependencies
uses: lukka/run-vcpkg@main
uses: lukka/run-vcpkg@v7
with:
vcpkgArguments: gtkmm nlohmann-json zlib sqlite3 glibmm openssl ixwebsocket curl
vcpkgDirectory: ${{ github.workspace }}/ci/vcpkg/
vcpkgTriplet: x64-windows
- name: Build
uses: lukka/run-cmake@main
uses: lukka/run-cmake@v3
with:
useVcpkgToolchainFile: true
vcpkgTriplet: x64-windows
@@ -41,9 +41,9 @@ jobs:
del /f /s /q "${{ runner.workspace }}\build\.ninja_log"
del /f /s /q "${{ runner.workspace }}\build\abaddon.ilk"
del /f /s /q "${{ runner.workspace }}\build\CMakeCache.txt"
xcopy /E /I "${{ github.workspace }}\css" "${{ runner.workspace }}\build\css"
xcopy /E /I "${{ github.workspace }}\res" "${{ runner.workspace }}\build\res"
xcopy /E /I "${{ github.workspace }}\fonts" "${{ runner.workspace }}\build\fonts"
xcopy /E /I "${{ github.workspace }}\res\css" "${{ runner.workspace }}\build\css"
xcopy /E /I "${{ github.workspace }}\res\res" "${{ runner.workspace }}\build\res"
xcopy /E /I "${{ github.workspace }}\res\fonts" "${{ runner.workspace }}\build\fonts"
mkdir "${{ runner.workspace }}\build\share"
xcopy /E /I "${{ github.workspace }}\ci\gtk-for-windows\gtk-nsis-pack\share\glib-2.0" "${{ runner.workspace }}\build\share\glib-2.0"
copy "${{ github.workspace }}\ci\vcpkg\installed\x64-windows\tools\glib\gspawn-win64-helper.exe" "${{ runner.workspace }}\build\gspawn-win64-helper.exe"
@@ -66,7 +66,7 @@ jobs:
submodules: true
- name: Fetch CMake
uses: lukka/get-cmake@latest
uses: lukka/get-cmake@v3.21.2
- name: Fetch dependencies
run: |
@@ -74,7 +74,7 @@ jobs:
brew install nlohmann-json
- name: Build
uses: lukka/run-cmake@main
uses: lukka/run-cmake@v3
with:
buildDirectory: ${{ runner.workspace }}/build
cmakeBuildType: ${{ matrix.buildtype }}
@@ -83,8 +83,8 @@ jobs:
run: |
mkdir "${{ runner.workspace }}/artifactdir"
cp "${{runner.workspace}}/build/abaddon" "${{ runner.workspace }}/artifactdir/abaddon"
cp -r "${{ github.workspace }}/css" "${{ runner.workspace }}/artifactdir/css"
cp -r "${{ github.workspace }}/res" "${{ runner.workspace }}/artifactdir/res"
cp -r "${{ github.workspace }}/res/css" "${{ runner.workspace }}/artifactdir/css"
cp -r "${{ github.workspace }}/res/res" "${{ runner.workspace }}/artifactdir/res"
- name: Upload build
uses: actions/upload-artifact@v2
@@ -104,7 +104,7 @@ jobs:
submodules: true
- name: Fetch CMake
uses: lukka/get-cmake@latest
uses: lukka/get-cmake@v3.21.2
- name: Fetch dependencies
run: |
@@ -123,7 +123,7 @@ jobs:
sudo apt-get install libcurl4-gnutls-dev
- name: Build
uses: lukka/run-cmake@main
uses: lukka/run-cmake@v3
env:
CC: gcc-9
CXX: g++-9
@@ -136,8 +136,8 @@ jobs:
run: |
mkdir "${{ runner.workspace }}/artifactdir"
cp "${{runner.workspace}}/build/abaddon" "${{ runner.workspace }}/artifactdir/abaddon"
cp -r "${{ github.workspace }}/css" "${{ runner.workspace }}/artifactdir/css"
cp -r "${{ github.workspace }}/res" "${{ runner.workspace }}/artifactdir/res"
cp -r "${{ github.workspace }}/res/css" "${{ runner.workspace }}/artifactdir/css"
cp -r "${{ github.workspace }}/res/res" "${{ runner.workspace }}/artifactdir/res"
- name: Upload build
uses: actions/upload-artifact@v2

9
.gitmodules vendored
View File

@@ -1,15 +1,12 @@
[submodule "vcpkg"]
path = ci/vcpkg
url = https://github.com/microsoft/vcpkg/
[submodule "thirdparty/simpleini"]
path = thirdparty/simpleini
url = https://github.com/brofield/simpleini
[submodule "thirdparty/IXWebSocket"]
path = thirdparty/IXWebSocket
url = https://github.com/machinezone/ixwebsocket
[submodule "ci/vcpkg"]
path = ci/vcpkg
url = https://github.com/microsoft/vcpkg
[submodule "ci/gtk-for-windows"]
path = ci/gtk-for-windows
url = https://github.com/tschoonj/GTK-for-Windows-Runtime-Environment-Installer
[submodule "subprojects/ixwebsocket"]
path = subprojects/ixwebsocket
url = https://github.com/machinezone/ixwebsocket

View File

@@ -7,24 +7,21 @@ set(ABADDON_RESOURCE_DIR "/usr/share/abaddon" CACHE PATH "Fallback directory for
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/")
set(USE_TLS TRUE)
set(USE_OPEN_SSL TRUE)
find_package(nlohmann_json REQUIRED)
find_package(CURL)
find_package(ZLIB REQUIRED)
find_package(SQLite3 REQUIRED)
find_package(gtkmm REQUIRED)
find_path(IXWEBSOCKET_INCLUDE_DIRS ixwebsocket/IXWebSocket.h)
find_library(IXWEBSOCKET_LIBRARY ixwebsocket)
if (NOT IXWEBSOCKET_LIBRARY)
add_subdirectory(thirdparty/IXWebSocket)
set(USE_TLS TRUE)
set(USE_OPEN_SSL TRUE)
find_package(IXWebSocket QUIET)
if (NOT IXWebSocket_FOUND)
message("ixwebsocket was not found and will be included as a submodule")
add_subdirectory(subprojects/ixwebsocket)
include_directories(IXWEBSOCKET_INCLUDE_DIRS)
endif()
include_directories(thirdparty/simpleini)
if(MINGW OR WIN32)
link_libraries(ws2_32)
endif()
@@ -37,27 +34,16 @@ if(WIN32)
link_libraries(${Fontconfig_LIBRARIES})
endif()
configure_file(${PROJECT_SOURCE_DIR}/config.h.in ${PROJECT_BINARY_DIR}/config.h)
configure_file(${PROJECT_SOURCE_DIR}/src/config.h.in ${PROJECT_BINARY_DIR}/config.h)
file(GLOB ABADDON_SOURCES
"*.h"
"*.hpp"
"*.cpp"
"discord/*.hpp"
"discord/*.cpp"
"components/*.hpp"
"components/*.cpp"
"windows/*.hpp"
"windows/*.cpp"
"windows/guildsettings/*.hpp"
"windows/guildsettings/*.cpp"
"windows/profile/*.hpp"
"windows/profile/*.cpp"
"dialogs/*.hpp"
"dialogs/*.cpp"
file(GLOB_RECURSE ABADDON_SOURCES
"src/*.h"
"src/*.hpp"
"src/*.cpp"
)
add_executable(abaddon ${ABADDON_SOURCES})
target_include_directories(abaddon PUBLIC ${PROJECT_SOURCE_DIR}/src)
target_include_directories(abaddon PUBLIC ${PROJECT_BINARY_DIR})
target_include_directories(abaddon PUBLIC ${GTKMM_INCLUDE_DIRS})
target_include_directories(abaddon PUBLIC ${ZLIB_INCLUDE_DIRS})
@@ -70,8 +56,8 @@ if ((CMAKE_CXX_COMPILER_ID STREQUAL "GNU") OR
target_link_libraries(abaddon stdc++fs)
endif()
if (IXWEBSOCKET_LIBRARY)
target_link_libraries(abaddon ${IXWEBSOCKET_LIBRARY})
if (IXWebSocket_LIBRARIES)
target_link_libraries(abaddon ${IXWebSocket_LIBRARIES})
find_library(MBEDTLS_X509_LIBRARY mbedx509)
find_library(MBEDTLS_TLS_LIBRARY mbedtls)
find_library(MBEDTLS_CRYPTO_LIBRARY mbedcrypto)

View File

@@ -4,14 +4,15 @@ Alternative Discord client made in C++ with GTK
<img src="/.readme/s3.png">
[😎Discord Server](https://discord.gg/wkCU3vuzG5)
<a href="https://discord.gg/wkCU3vuzG5"><img src="https://discord.com/api/guilds/858156817711890443/widget.png?style=shield"></a>
Current features:
* Not Electron
* Handles most types of chat messages including embeds, images, and replies
* Completely styleable/customizable with CSS (if you have a system GTK theme it won't really use it though)
* Identifies to gateway as the web client unlike other clients so less likely to be falsely flagged as spam<sup>1</sup>
* Identifies to Discord as the web client unlike other clients so less likely to be falsely flagged as spam<sup>1</sup>
* Set status
* Unread and mention indicators
* Start new DMs and group DMs
* View user profiles (notes, mutual servers, mutual friends)
* Kick, ban, and unban members
@@ -20,15 +21,19 @@ Current features:
* Manage emojis
* View audit log
* Emojis<sup>2</sup>
* Thread support<sup>3</sup>
* Animated avatars, server icons, emojis (can be turned off)
1 - Other third-party clients send the IDENTIFY message that bots use which makes Discord more likely to think you are selfbotting or spamming. However, Discord still loves to ban people's accounts for no good reason, even users of the official clients. If you want to be really careful avoid joining servers really fast or cold DMing people.
2 - Getting emojis to function properly on GTK is still something I've yet to figure out ([#5](../../issues/5)). Unicode emojis are manually searched for and replaced in several places as opposed to allowing GTK to figure it out since GTK's way of doing it doesn't work very well.
1 - Abaddon tries its best to make Discord think it's a legitimate web client. Some of the things done to do this include: using a browser user agent, sending the same IDENTIFY message that the official web client does, using API v9 endpoints in all cases, and not using endpoints the web client does not normally use. There are still a few smaller inconsistencies, however. For example the web client sends lots of telemetry via the `/science` endpoint (uBlock origin stops this) as well as in the headers of all requests. **In any case,** you should use an official client for joining servers, sending new DMs, or managing your friends list if you are afraid of being caught in Discord's spam filters (unlikely).
2 - Unicode emojis are substituted manually as opposed to rendered by GTK on non-Windows platforms. This can be changed with the `stock_emojis` setting as shown at the bottom of this README. A CBDT-based font using Twemoji is provided to allow GTK to render emojis natively on Windows.
3 - There are some inconsistencies with thread state that might be encountered in some more uncommon cases, but they are the result of fundamental issues with Discord's thread implementation.
### Building manually (recommended if not on Windows):
#### Windows:
1. `git clone https://github.com/uowuo/abaddon && cd abaddon`
2. `vcpkg install gtkmm:x64-windows nlohmann-json:x64-windows ixwebsocket:x64-windows zlib:x64-windows simpleini:x64-windows sqlite3:x64-windows openssl:x64-windows curl:x64-windows`
2. `vcpkg install gtkmm:x64-windows nlohmann-json:x64-windows ixwebsocket:x64-windows zlib:x64-windows sqlite3:x64-windows openssl:x64-windows curl:x64-windows`
3. `mkdir build && cd build`
4. `cmake -G"Visual Studio 16 2019" -A x64 -DCMAKE_TOOLCHAIN_FILE=c:\path\to\vcpkg\scripts\buildsystems\vcpkg.cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DVCPKG_TARGET_TRIPLET=x64-windows ..`
5. Build with Visual Studio
@@ -49,14 +54,19 @@ Or, do steps 1 and 2, and open CMakeLists.txt in Visual Studio if `vcpkg integra
4. `cmake ..`
5. `make`
### Downloads (from CI):
### Downloads:
Latest release version: https://github.com/uowuo/abaddon/releases/latest
**CI:**
- Windows: [here](https://nightly.link/uowuo/abaddon/workflows/ci/master/build-windows-RelWithDebInfo.zip)
- MacOS: [here](https://nightly.link/uowuo/abaddon/workflows/ci/master/build-macos-RelWithDebInfo.zip) unsigned, unpackaged, requires gtkmm3 (e.g. from homebrew)
- Linux: [here](https://nightly.link/uowuo/abaddon/workflows/ci/master/build-linux-MinSizeRel.zip) unpackaged (for now), requires gtkmm3. built on Ubuntu 18.04 + gcc9
⚠️ If you use Windows, make sure to start from the directory containing `css` and `res`
If you don't use Windows, `css` and `res` can be loaded from `/usr/share/abaddon`
On Linux, `css` and `res` can also be loaded from `~/.local/share/abaddon` or `/usr/share/abaddon`
`abaddon.ini` will also be automatically used if located at `~/.config/abaddon/abaddon.ini` and there is no `abaddon.ini` in the working directory
@@ -66,12 +76,10 @@ If you don't use Windows, `css` and `res` can be loaded from `/usr/share/abaddon
* [IXWebSocket](https://github.com/machinezone/IXWebSocket)
* [libcurl](https://curl.se/)
* [zlib](https://zlib.net/)
* [simpleini](https://github.com/brofield/simpleini)
* [SQLite3](https://www.sqlite.org/index.html)
### TODO:
* Voice support
* Unread indicators
* User activities
* Nicknames
* More server management stuff
@@ -84,12 +92,6 @@ If you don't use Windows, `css` and `res` can be loaded from `/usr/share/abaddon
.app-popup - Additional class for `.app-window`s when the window is not the main window
.channel-list - Container of the channel list
.channel-row - All rows within the channel container
.channel-row-channel - Only rows containing a channel
.channel-row-category - Only rows containing a category
.channel-row-guild - Only rows containing a guild
.channel-row-label - All labels within the channel container
.nsfw - Applied to channel row labels and their container for NSFW channels
.messages - Container of user messages
.message-container - The container which holds a user's messages
@@ -175,18 +177,24 @@ Used in profile popup:
### Settings
Settings are configured (for now) by editing abaddon.ini
The format is similar to the standard Windows ini format **except**:
* `#` is used to begin comments as opposed to `;`
* Section and key names are case-sensitive
You should edit these while the client is closed even though there's an option to reload while running
This listing is organized by section.
For example, memory_db would be set by adding `memory_db = true` under the line `[discord]`
#### discord
* gateway (string) - override url for Discord gateway. must be json format and use zlib stream compression
* api_base (string) - override base url for Discord API
* memory_db (true or false, default false) - if true, Discord data will be kept in memory as opposed to on disk
* token (string) - Discord token used to login, this can be set from the menu
* prefetch (true or false, default false) - if true, new messages will cause the avatar and image attachments to be automatically downloaded
#### http
* user_agent (string) - sets the user-agent to use in HTTP requests to the Discord API (not including media/images)
* concurrent (int, default 10) - how many images can be concurrently retrieved
* concurrent (int, default 20) - how many images can be concurrently retrieved
#### gui
* member_list_discriminator (true or false, default true) - show user discriminators in the member list
@@ -196,13 +204,15 @@ For example, memory_db would be set by adding `memory_db = true` under the line
* animations (true or false, default true) - use animated images where available (e.g. server icons, emojis, avatars). false means static images will be used
* animated_guild_hover_only (true or false, default true) - only animate guild icons when the guild is being hovered over
* owner_crown (true or false, default true) - show a crown next to the owner
* gateway (string) - override url for Discord gateway. must be json format and use zlib stream compression
* api_base (string) - override base url for Discord API
* unreads (true or false, default true) - show unread indicators and mention badges
#### style
* linkcolor (string) - color to use for links in messages
* expandercolor (string) - color to use for the expander in the channel list
* nsfwchannelcolor (string) - color to use for NSFW channels in the channel list
* channelcolor (string) - color to use for SFW channels in the channel list
* mentionbadgecolor (string) - background color for mention badges
* mentionbadgetextcolor (string) - color to use for number displayed on mention badges
### Environment variables

View File

@@ -31,7 +31,6 @@ set(HARFBUZZ_INCLUDE_DIRS ${HARFBUZZ_INCLUDE_DIR};${HARFBUZZ_CONFIG_INCLUDE_DIRS
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(HarfBuzz
FOUND_VAR HARFBUZZ_FOUND
REQUIRED_VARS
HARFBUZZ_LIBRARY
HARFBUZZ_INCLUDE_DIR

View File

@@ -0,0 +1,30 @@
set(IXWebSocket_LIBRARY_NAME ixwebsocket)
find_path(IXWebSocket_INCLUDE_DIR
NAMES ixwebsocket/IXWebSocket.h
HINTS /usr/include
/usr/local/include
/opt/local/include
PATH_SUFFIXES ${IXWebSocket_LIBRARY_NAME})
find_library(IXWebSocket_LIBRARY
NAMES ${IXWebSocket_LIBRARY_NAME}
PATH_SUFFIXES ${IXWebSocket_LIBRARY_NAME}
${IXWebSocket_LIBRARY_NAME}/include)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(IXWebSocket
REQUIRED_VARS
IXWebSocket_LIBRARY
IXWebSocket_INCLUDE_DIR)
mark_as_advanced(IXWebSocket_LIBRARY IXWebSocket_INCLUDE_DIR)
if (IXWebSocket_FOUND)
find_package(OpenSSL QUIET)
set(IXWebSocket_INCLUDE_DIRS "${IXWebSocket_INCLUDE_DIR};${OPENSSL_INCLUDE_DIR}")
set(IXWebSocket_LIBRARIES "${IXWebSocket_LIBRARY};${OPENSSL_LIBRARIES}")
endif()

View File

@@ -31,7 +31,6 @@ set(ATK_INCLUDE_DIRS ${ATK_INCLUDE_DIR};${ATK_CONFIG_INCLUDE_DIRS})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(atk
FOUND_VAR ATK_FOUND
REQUIRED_VARS
ATK_LIBRARY
ATK_INCLUDE_DIR

View File

@@ -42,7 +42,6 @@ set(ATKMM_INCLUDE_DIRS ${ATKMM_INCLUDE_DIR};${ATKMM_CONFIG_INCLUDE_DIR};${ATK_IN
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(atkmm
FOUND_VAR ATKMM_FOUND
REQUIRED_VARS
ATKMM_LIBRARY
ATKMM_INCLUDE_DIRS

View File

@@ -31,7 +31,6 @@ set(CAIRO_INCLUDE_DIRS ${CAIRO_INCLUDE_DIR};${CAIRO_CONFIG_INCLUDE_DIRS})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(cairo
FOUND_VAR CAIRO_FOUND
REQUIRED_VARS
CAIRO_LIBRARY
CAIRO_INCLUDE_DIR

View File

@@ -45,7 +45,6 @@ set(CAIROMM_INCLUDE_DIRS ${CAIROMM_INCLUDE_DIR};${CAIROMM_CONFIG_INCLUDE_DIRS};$
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(cairomm
FOUND_VAR CAIROMM_FOUND
REQUIRED_VARS
CAIROMM_LIBRARY
CAIROMM_INCLUDE_DIR

View File

@@ -40,7 +40,6 @@ set(GDKMM_INCLUDE_DIRS ${GDKMM_INCLUDE_DIR};${GDKMM_CONFIG_INCLUDE_DIRS};${GDKMM
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(gdkmm
FOUND_VAR GDKMM_FOUND
REQUIRED_VARS
GDKMM_LIBRARY
GDKMM_INCLUDE_DIRS

View File

@@ -33,7 +33,6 @@ set(GDKPIXBUF_INCLUDE_DIRS ${GDKPIXBUF_INCLUDE_DIR};${GDKPIXBUF_CONFIG_INCLUDE_D
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(gdkpixbuf
FOUND_VAR GDKPIXBUF_FOUND
REQUIRED_VARS
GDKPIXBUF_LIBRARY
GDKPIXBUF_INCLUDE_DIR

View File

@@ -50,7 +50,6 @@ endif()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(glib
FOUND_VAR GLIB_FOUND
REQUIRED_VARS
GLIB_LIBRARIES
GLIB_INCLUDE_DIRS

View File

@@ -60,7 +60,6 @@ set(GLIBMM_INCLUDE_DIRS ${GLIBMM_INCLUDE_DIR};${GLIBMM_CONFIG_INCLUDE_DIR};${GIO
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(glibmm
FOUND_VAR GLIBMM_FOUND
REQUIRED_VARS
GLIBMM_LIBRARY
GLIBMM_INCLUDE_DIR

View File

@@ -47,7 +47,6 @@ set(GTK_INCLUDE_DIRS ${GTK_INCLUDE_DIR};${GDK_CONFIG_INCLUDE_DIR};${GDKPIXBUF_IN
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(gtk
FOUND_VAR GTK_FOUND
REQUIRED_VARS
GTK_LIBRARY
GTK_INCLUDE_DIR

View File

@@ -51,7 +51,6 @@ set(GTKMM_INCLUDE_DIRS ${GTKMM_INCLUDE_DIR};${GTKMM_CONFIG_INCLUDE_DIR};${GDKMM
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(gtkmm
FOUND_VAR GTKMM_FOUND
REQUIRED_VARS
GTKMM_LIB
GTKMM_INCLUDE_DIRS

View File

@@ -1,17 +0,0 @@
find_path(IXWEBSOCKET_INCLUDE_DIR
NAMES ixwebsocket/IXWebSocket.h)
find_library(IXWEBSOCKET_LIBRARY
NAMES ixwebsocket
HINTS ${IXWEBSOCKET_LIBRARY_ROOT})
set(IXWEBSOCKET_LIBRARIES ${IXWEBSOCKET_LIBRARY})
set(IXWEBSOCKET_INCLUDE_DIRS ${IXWEBSOCKET_INCLUDE_DIR})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(ixwebsocket
FOUND_VAR IXWEBSOCKET_FOUND
REQUIRED_VARS
IXWEBSOCKET_LIBRARY
IXWEBSOCKET_INCLUDE_DIR
VERSION_VAR IXWEBSOCKET_VERSION)

View File

@@ -22,7 +22,6 @@ set(NLOHMANN_JSON_LIBRARIES "")
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(nlohmann_json
FOUND_VAR NLOHMANN_JSON_FOUND
REQUIRED_VARS
NLOHMANN_JSON_INCLUDE_DIR
VERSION_VAR NLOHMANN_JSON_VERSION)

View File

@@ -69,7 +69,6 @@ set(PANGO_INCLUDE_DIRS ${PANGO_INCLUDE_DIR};${PANGO_CONFIG_INCLUDE_DIRS};${HARFB
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(pango
FOUND_VAR PANGO_FOUND
REQUIRED_VARS
PANGO_LIBRARY
PANGO_INCLUDE_DIR

View File

@@ -56,7 +56,6 @@ set(PANGOMM_INCLUDE_DIRS ${PANGOMM_INCLUDE_DIR};${PANGOMM_CONFIG_INCLUDE_DIR};${
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(pangomm
FOUND_VAR PANGOMM_FOUND
REQUIRED_VARS
PANGOMM_LIBRARY
PANGOMM_INCLUDE_DIRS

View File

@@ -32,7 +32,6 @@ set(SIGC++_INCLUDE_DIRS ${SIGC++_INCLUDE_DIR};${SIGC++_CONFIG_INCLUDE_DIR})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(sigc++
FOUND_VAR SIGC++_FOUND
REQUIRED_VARS
SIGC++_INCLUDE_DIR
SIGC++_LIBRARY

File diff suppressed because it is too large Load Diff

View File

@@ -1,172 +0,0 @@
#pragma once
#include "../util.hpp"
#include "objects.hpp"
#include <unordered_map>
#include <unordered_set>
#include <mutex>
#include <filesystem>
#include <sqlite3.h>
#ifdef GetMessage // fuck you windows.h
#undef GetMessage
#endif
class Store {
public:
Store(bool mem_store = false);
~Store();
bool IsValid() const;
void SetUser(Snowflake id, const UserData &user);
void SetChannel(Snowflake id, const ChannelData &chan);
void SetGuild(Snowflake id, const GuildData &guild);
void SetRole(Snowflake id, const RoleData &role);
void SetMessage(Snowflake id, const Message &message);
void SetGuildMember(Snowflake guild_id, Snowflake user_id, const GuildMember &data);
void SetPermissionOverwrite(Snowflake channel_id, Snowflake id, const PermissionOverwrite &perm);
void SetEmoji(Snowflake id, const EmojiData &emoji);
void SetBan(Snowflake guild_id, Snowflake user_id, const BanData &ban);
// slap const on everything even tho its not *really* const
std::optional<ChannelData> GetChannel(Snowflake id) const;
std::optional<EmojiData> GetEmoji(Snowflake id) const;
std::optional<GuildData> GetGuild(Snowflake id) const;
std::optional<GuildMember> GetGuildMember(Snowflake guild_id, Snowflake user_id) const;
std::optional<Message> GetMessage(Snowflake id) const;
std::optional<PermissionOverwrite> GetPermissionOverwrite(Snowflake channel_id, Snowflake id) const;
std::optional<RoleData> GetRole(Snowflake id) const;
std::optional<UserData> GetUser(Snowflake id) const;
std::optional<BanData> GetBan(Snowflake guild_id, Snowflake user_id) const;
std::vector<BanData> GetBans(Snowflake guild_id) const;
std::vector<Message> GetLastMessages(Snowflake id, size_t num) const;
std::vector<Snowflake> GetChannelMessageIDs(Snowflake id) const;
std::vector<Message> GetPinnedMessages(Snowflake channel_id) const;
std::vector<ChannelData> GetActiveThreads(Snowflake channel_id) const; // public
void ClearGuild(Snowflake id);
void ClearChannel(Snowflake id);
void ClearBan(Snowflake guild_id, Snowflake user_id);
using users_type = std::unordered_map<Snowflake, UserData>;
using channels_type = std::unordered_map<Snowflake, ChannelData>;
using guilds_type = std::unordered_map<Snowflake, GuildData>;
using roles_type = std::unordered_map<Snowflake, RoleData>;
using messages_type = std::unordered_map<Snowflake, Message>;
using members_type = std::unordered_map<Snowflake, std::unordered_map<Snowflake, GuildMember>>; // [guild][user]
using permission_overwrites_type = std::unordered_map<Snowflake, std::unordered_map<Snowflake, PermissionOverwrite>>; // [channel][user/role]
using emojis_type = std::unordered_map<Snowflake, EmojiData>;
const std::unordered_set<Snowflake> &GetChannels() const;
const std::unordered_set<Snowflake> &GetGuilds() const;
void ClearAll();
void BeginTransaction();
void EndTransaction();
private:
Message GetMessageBound(sqlite3_stmt *stmt) const;
void SetMessageInteractionPair(Snowflake message_id, const MessageInteractionData &interaction);
std::unordered_set<Snowflake> m_channels;
std::unordered_set<Snowflake> m_guilds;
bool CreateTables();
bool CreateStatements();
void Cleanup();
template<typename T>
void Bind(sqlite3_stmt *stmt, int index, const std::optional<T> &opt) const;
template<typename T>
typename std::enable_if<std::is_enum<T>::value, void>::type
Bind(sqlite3_stmt *stmt, int index, T val) const;
void Bind(sqlite3_stmt *stmt, int index, int num) const;
void Bind(sqlite3_stmt *stmt, int index, uint64_t num) const;
void Bind(sqlite3_stmt *stmt, int index, const std::string &str) const;
void Bind(sqlite3_stmt *stmt, int index, bool val) const;
void Bind(sqlite3_stmt *stmt, int index, std::nullptr_t) const;
bool RunInsert(sqlite3_stmt *stmt);
bool FetchOne(sqlite3_stmt *stmt) const;
template<typename T>
void Get(sqlite3_stmt *stmt, int index, std::optional<T> &out) const;
template<typename T>
typename std::enable_if<std::is_enum<T>::value, void>::type
Get(sqlite3_stmt *stmt, int index, T &out) const;
void Get(sqlite3_stmt *stmt, int index, int &out) const;
void Get(sqlite3_stmt *stmt, int index, uint64_t &out) const;
void Get(sqlite3_stmt *stmt, int index, std::string &out) const;
void Get(sqlite3_stmt *stmt, int index, bool &out) const;
void Get(sqlite3_stmt *stmt, int index, Snowflake &out) const;
bool IsNull(sqlite3_stmt *stmt, int index) const;
void Reset(sqlite3_stmt *stmt) const;
std::filesystem::path m_db_path;
mutable sqlite3 *m_db;
mutable int m_db_err;
mutable sqlite3_stmt *m_set_user_stmt;
mutable sqlite3_stmt *m_get_user_stmt;
mutable sqlite3_stmt *m_set_perm_stmt;
mutable sqlite3_stmt *m_get_perm_stmt;
mutable sqlite3_stmt *m_set_msg_stmt;
mutable sqlite3_stmt *m_get_msg_stmt;
mutable sqlite3_stmt *m_set_role_stmt;
mutable sqlite3_stmt *m_get_role_stmt;
mutable sqlite3_stmt *m_set_emote_stmt;
mutable sqlite3_stmt *m_get_emote_stmt;
mutable sqlite3_stmt *m_set_member_stmt;
mutable sqlite3_stmt *m_get_member_stmt;
mutable sqlite3_stmt *m_set_guild_stmt;
mutable sqlite3_stmt *m_get_guild_stmt;
mutable sqlite3_stmt *m_set_chan_stmt;
mutable sqlite3_stmt *m_get_chan_stmt;
mutable sqlite3_stmt *m_set_ban_stmt;
mutable sqlite3_stmt *m_get_ban_stmt;
mutable sqlite3_stmt *m_clear_ban_stmt;
mutable sqlite3_stmt *m_get_bans_stmt;
mutable sqlite3_stmt *m_set_msg_interaction_stmt;
mutable sqlite3_stmt *m_get_last_msgs_stmt;
mutable sqlite3_stmt *m_get_msg_ids_stmt;
mutable sqlite3_stmt *m_get_pins_stmt;
mutable sqlite3_stmt *m_get_threads_stmt;
mutable sqlite3_stmt *m_clear_chan_stmt;
};
template<typename T>
inline void Store::Bind(sqlite3_stmt *stmt, int index, const std::optional<T> &opt) const {
if (opt.has_value())
Bind(stmt, index, *opt);
else
sqlite3_bind_null(stmt, index);
}
template<typename T>
inline typename std::enable_if<std::is_enum<T>::value, void>::type
Store::Bind(sqlite3_stmt *stmt, int index, T val) const {
Bind(stmt, index, static_cast<typename std::underlying_type<T>::type>(val));
}
template<typename T>
inline void Store::Get(sqlite3_stmt *stmt, int index, std::optional<T> &out) const {
if (sqlite3_column_type(stmt, index) == SQLITE_NULL)
out = std::nullopt;
else {
T v;
Get(stmt, index, v);
out = std::optional<T>(v);
}
}
template<typename T>
inline typename std::enable_if<std::is_enum<T>::value, void>::type
Store::Get(sqlite3_stmt *stmt, int index, T &out) const {
out = static_cast<T>(sqlite3_column_int(stmt, index));
}

View File

Before

Width:  |  Height:  |  Size: 7.9 KiB

After

Width:  |  Height:  |  Size: 7.9 KiB

View File

Before

Width:  |  Height:  |  Size: 7.0 KiB

After

Width:  |  Height:  |  Size: 7.0 KiB

View File

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 48 KiB

View File

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

Before

Width:  |  Height:  |  Size: 6.5 KiB

After

Width:  |  Height:  |  Size: 6.5 KiB

View File

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

View File

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 6.9 KiB

View File

Before

Width:  |  Height:  |  Size: 8.2 KiB

After

Width:  |  Height:  |  Size: 8.2 KiB

View File

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 8.8 KiB

View File

Before

Width:  |  Height:  |  Size: 7.0 KiB

After

Width:  |  Height:  |  Size: 7.0 KiB

View File

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

Before

Width:  |  Height:  |  Size: 6.5 KiB

After

Width:  |  Height:  |  Size: 6.5 KiB

View File

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

Before

Width:  |  Height:  |  Size: 7.1 KiB

After

Width:  |  Height:  |  Size: 7.1 KiB

View File

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

View File

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

View File

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

View File

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

Before

Width:  |  Height:  |  Size: 7.0 KiB

After

Width:  |  Height:  |  Size: 7.0 KiB

View File

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

View File

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

View File

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

View File

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 6.9 KiB

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View File

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@@ -1,107 +0,0 @@
#include "settings.hpp"
#include <filesystem>
#include <fstream>
SettingsManager::SettingsManager(std::string filename)
: m_filename(filename) {
if (!std::filesystem::exists(filename)) {
std::fstream fs;
fs.open(filename, std::ios::out);
fs.close();
}
auto rc = m_ini.LoadFile(filename.c_str());
m_ok = rc == SI_OK;
}
void SettingsManager::Reload() {
m_ok = m_ini.LoadFile(m_filename.c_str()) == SI_OK;
}
std::string SettingsManager::GetSettingString(const std::string &section, const std::string &key, std::string fallback) const {
return m_ini.GetValue(section.c_str(), key.c_str(), fallback.c_str());
}
int SettingsManager::GetSettingInt(const std::string &section, const std::string &key, int fallback) const {
return std::stoul(GetSettingString(section, key, std::to_string(fallback)));
}
bool SettingsManager::GetSettingBool(const std::string &section, const std::string &key, bool fallback) const {
return GetSettingString(section, key, fallback ? "true" : "false") != "false";
}
bool SettingsManager::IsValid() const {
return m_ok;
}
void SettingsManager::Close() {
m_ini.SaveFile(m_filename.c_str());
}
bool SettingsManager::GetUseMemoryDB() const {
return GetSettingBool("discord", "memory_db", false);
}
std::string SettingsManager::GetUserAgent() const {
return GetSettingString("http", "user_agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36");
}
std::string SettingsManager::GetDiscordToken() const {
return GetSettingString("discord", "token");
}
bool SettingsManager::GetShowMemberListDiscriminators() const {
return GetSettingBool("gui", "member_list_discriminator", true);
}
bool SettingsManager::GetShowStockEmojis() const {
return GetSettingBool("gui", "stock_emojis", true);
}
bool SettingsManager::GetShowCustomEmojis() const {
return GetSettingBool("gui", "custom_emojis", true);
}
std::string SettingsManager::GetLinkColor() const {
return GetSettingString("style", "linkcolor", "rgba(40, 200, 180, 255)");
}
std::string SettingsManager::GetChannelsExpanderColor() const {
return GetSettingString("style", "expandercolor", "rgba(255, 83, 112, 255)");
}
std::string SettingsManager::GetNSFWChannelColor() const {
return GetSettingString("style", "nsfwchannelcolor", "#ed6666");
}
int SettingsManager::GetCacheHTTPConcurrency() const {
return GetSettingInt("http", "concurrent", 20);
}
bool SettingsManager::GetPrefetch() const {
return GetSettingBool("discord", "prefetch", false);
}
std::string SettingsManager::GetMainCSS() const {
return GetSettingString("gui", "css", "main.css");
}
bool SettingsManager::GetShowAnimations() const {
return GetSettingBool("gui", "animations", true);
}
bool SettingsManager::GetShowOwnerCrown() const {
return GetSettingBool("gui", "owner_crown", true);
}
std::string SettingsManager::GetGatewayURL() const {
return GetSettingString("discord", "gateway", "wss://gateway.discord.gg/?v=9&encoding=json&compress=zlib-stream");
}
std::string SettingsManager::GetAPIBaseURL() const {
return GetSettingString("discord", "api_base", "https://discord.com/api/v9");
}
bool SettingsManager::GetAnimatedGuildHoverOnly() const {
return GetSettingBool("gui", "animated_guild_hover_only", true);
}

View File

@@ -1,61 +0,0 @@
#pragma once
#include <string>
#include <type_traits>
#include <SimpleIni.h>
class SettingsManager {
public:
SettingsManager(std::string filename);
void Reload();
void Close();
bool GetUseMemoryDB() const;
std::string GetUserAgent() const;
std::string GetDiscordToken() const;
bool GetShowMemberListDiscriminators() const;
bool GetShowStockEmojis() const;
bool GetShowCustomEmojis() const;
int GetCacheHTTPConcurrency() const;
bool GetPrefetch() const;
std::string GetMainCSS() const;
bool GetShowAnimations() const;
bool GetShowOwnerCrown() const;
std::string GetGatewayURL() const;
std::string GetAPIBaseURL() const;
bool GetAnimatedGuildHoverOnly() const;
// i would like to use Gtk::StyleProperty for this, but it will not work on windows
// #1 it's missing from the project files for the version used by vcpkg
// #2 it's still broken and doesn't function even when added to the solution
// #3 it's a massive pain in the ass to try and bump the version to a functioning version
// because they switch build systems to nmake/meson (took months to get merged in vcpkg)
// #4 c++ build systems sucks
// three options are: use gtk4 with updated vcpkg, try and port it myself, or use msys2 instead of vcpkg
// im leaning towards msys
std::string GetLinkColor() const;
std::string GetChannelsExpanderColor() const;
std::string GetNSFWChannelColor() const;
bool IsValid() const;
template<typename T>
void SetSetting(std::string section, std::string key, T value) {
m_ini.SetValue(section.c_str(), key.c_str(), std::to_string(value).c_str());
m_ini.SaveFile(m_filename.c_str());
}
void SetSetting(std::string section, std::string key, std::string value) {
m_ini.SetValue(section.c_str(), key.c_str(), value.c_str());
m_ini.SaveFile(m_filename.c_str());
}
private:
std::string GetSettingString(const std::string &section, const std::string &key, std::string fallback = "") const;
int GetSettingInt(const std::string &section, const std::string &key, int fallback) const;
bool GetSettingBool(const std::string &section, const std::string &key, bool fallback) const;
private:
bool m_ok;
std::string m_filename;
CSimpleIniA m_ini;
};

View File

@@ -23,12 +23,12 @@
Abaddon::Abaddon()
: m_settings(Platform::FindConfigFile())
, m_emojis(GetResPath("/emojis.bin"))
, m_discord(m_settings.GetUseMemoryDB()) { // stupid but easy
, m_discord(GetSettings().UseMemoryDB) // stupid but easy
, m_emojis(GetResPath("/emojis.bin")) {
LoadFromSettings();
// todo: set user agent for non-client(?)
std::string ua = m_settings.GetUserAgent();
std::string ua = GetSettings().UserAgent;
m_discord.SetUserAgent(ua);
m_discord.signal_gateway_ready().connect(sigc::mem_fun(*this, &Abaddon::DiscordOnReady));
@@ -43,7 +43,7 @@ Abaddon::Abaddon()
m_discord.signal_thread_update().connect(sigc::mem_fun(*this, &Abaddon::DiscordOnThreadUpdate));
m_discord.signal_message_sent().connect(sigc::mem_fun(*this, &Abaddon::DiscordOnMessageSent));
m_discord.signal_disconnected().connect(sigc::mem_fun(*this, &Abaddon::DiscordOnDisconnect));
if (m_settings.GetPrefetch())
if (GetSettings().Prefetch)
m_discord.signal_message_create().connect([this](const Message &message) {
if (message.Author.HasAvatar())
m_img_mgr.Prefetch(message.Author.GetAvatarURL());
@@ -54,11 +54,6 @@ Abaddon::Abaddon()
});
}
Abaddon::~Abaddon() {
m_settings.Close();
m_discord.Stop();
}
Abaddon &Abaddon::Get() {
static Abaddon instance;
return instance;
@@ -83,9 +78,30 @@ int Abaddon::StartGTK() {
m_main_window = std::make_unique<MainWindow>();
m_main_window->set_title(APP_TITLE);
m_main_window->UpdateComponents();
m_main_window->set_position(Gtk::WIN_POS_CENTER);
if (!m_settings.IsValid()) {
Gtk::MessageDialog dlg(*m_main_window, "The settings file could not be opened!", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
dlg.set_position(Gtk::WIN_POS_CENTER);
dlg.run();
}
if (!m_emojis.Load()) {
Gtk::MessageDialog dlg(*m_main_window, "The emoji file couldn't be loaded!", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
dlg.set_position(Gtk::WIN_POS_CENTER);
dlg.run();
}
if (!m_discord.IsStoreValid()) {
Gtk::MessageDialog dlg(*m_main_window, "The Discord cache could not be created!", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
dlg.set_position(Gtk::WIN_POS_CENTER);
dlg.run();
return 1;
}
// store must be checked before this can be called
m_main_window->UpdateComponents();
// crashes for some stupid reason if i put it somewhere else
SetupUserMenu();
@@ -113,35 +129,19 @@ int Abaddon::StartGTK() {
ActionReloadCSS();
m_gtk_app->signal_shutdown().connect([&]() {
StopDiscord();
});
if (!m_settings.IsValid()) {
Gtk::MessageDialog dlg(*m_main_window, "The settings file could not be created!", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
dlg.set_position(Gtk::WIN_POS_CENTER);
dlg.run();
}
if (!m_emojis.Load()) {
Gtk::MessageDialog dlg(*m_main_window, "The emoji file couldn't be loaded!", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
dlg.set_position(Gtk::WIN_POS_CENTER);
dlg.run();
}
if (!m_discord.IsStoreValid()) {
Gtk::MessageDialog dlg(*m_main_window, "The Discord cache could not be created!", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
dlg.set_position(Gtk::WIN_POS_CENTER);
dlg.run();
return 1;
}
m_gtk_app->signal_shutdown().connect(sigc::mem_fun(*this, &Abaddon::OnShutdown), false);
m_main_window->show();
return m_gtk_app->run(*m_main_window);
}
void Abaddon::OnShutdown() {
StopDiscord();
m_settings.Close();
}
void Abaddon::LoadFromSettings() {
std::string token = m_settings.GetDiscordToken();
std::string token = GetSettings().DiscordToken;
if (token.size()) {
m_discord_token = token;
m_discord.UpdateToken(m_discord_token);
@@ -154,6 +154,7 @@ void Abaddon::StartDiscord() {
void Abaddon::StopDiscord() {
m_discord.Stop();
SaveState();
}
bool Abaddon::IsDiscordActive() const {
@@ -176,6 +177,7 @@ const DiscordClient &Abaddon::GetDiscordClient() const {
void Abaddon::DiscordOnReady() {
m_main_window->UpdateComponents();
LoadState();
}
void Abaddon::DiscordOnMessageCreate(const Message &message) {
@@ -247,8 +249,8 @@ void Abaddon::DiscordOnThreadUpdate(const ThreadUpdateData &data) {
}
}
const SettingsManager &Abaddon::GetSettings() const {
return m_settings;
SettingsManager::Settings &Abaddon::GetSettings() {
return m_settings.GetSettings();
}
Glib::RefPtr<Gtk::CssProvider> Abaddon::GetStyleProvider() {
@@ -268,7 +270,7 @@ void Abaddon::ShowUserMenu(const GdkEvent *event, Snowflake id, Snowflake guild_
if (guild.has_value() && user.has_value()) {
const auto roles = user->GetSortedRoles();
m_user_menu_roles->set_visible(roles.size() > 0);
for (const auto role : roles) {
for (const auto &role : roles) {
auto *item = Gtk::manage(new Gtk::MenuItem(role.Name));
if (role.Color != 0) {
Gdk::RGBA color;
@@ -365,6 +367,44 @@ void Abaddon::SetupUserMenu() {
m_user_menu->show_all();
}
void Abaddon::SaveState() {
if (!GetSettings().SaveState) return;
AbaddonApplicationState state;
state.ActiveChannel = m_main_window->GetChatActiveChannel();
state.Expansion = m_main_window->GetChannelList()->GetExpansionState();
const auto path = GetStateCachePath();
if (!util::IsFolder(path)) {
std::error_code ec;
std::filesystem::create_directories(path, ec);
}
auto *fp = std::fopen(GetStateCachePath("/state.json").c_str(), "wb");
if (fp == nullptr) return;
const auto s = nlohmann::json(state).dump(4);
std::fwrite(s.c_str(), 1, s.size(), fp);
std::fclose(fp);
}
void Abaddon::LoadState() {
if (!GetSettings().SaveState) {
// call with empty data to purge the temporary table
m_main_window->GetChannelList()->UseExpansionState({});
return;
}
const auto data = ReadWholeFile(GetStateCachePath("/state.json"));
if (data.empty()) return;
try {
AbaddonApplicationState state = nlohmann::json::parse(data.begin(), data.end());
m_main_window->GetChannelList()->UseExpansionState(state.Expansion);
ActionChannelOpened(state.ActiveChannel);
} catch (const std::exception &e) {
printf("failed to load application state: %s\n", e.what());
}
}
void Abaddon::ManageHeapWindow(Gtk::Window *window) {
window->signal_hide().connect([this, window]() {
delete window;
@@ -422,6 +462,11 @@ std::string Abaddon::GetResPath() {
return path;
}
std::string Abaddon::GetStateCachePath() {
const static auto path = Platform::FindStateCacheFolder() + "/state";
return path;
}
std::string Abaddon::GetCSSPath(const std::string &path) {
return GetCSSPath() + path;
}
@@ -430,6 +475,10 @@ std::string Abaddon::GetResPath(const std::string &path) {
return GetResPath() + path;
}
std::string Abaddon::GetStateCachePath(const std::string &path) {
return GetStateCachePath() + path;
}
void Abaddon::ActionConnect() {
if (!m_discord.IsStarted())
StartDiscord();
@@ -447,7 +496,7 @@ void Abaddon::ActionSetToken() {
m_discord_token = dlg.GetToken();
m_discord.UpdateToken(m_discord_token);
m_main_window->UpdateComponents();
m_settings.SetSetting("discord", "token", m_discord_token);
GetSettings().DiscordToken = m_discord_token;
}
}
@@ -461,12 +510,15 @@ void Abaddon::ActionJoinGuildDialog() {
}
void Abaddon::ActionChannelOpened(Snowflake id) {
if (id == m_main_window->GetChatActiveChannel()) return;
if (!id.IsValid() || id == m_main_window->GetChatActiveChannel()) return;
m_main_window->GetChatWindow()->SetTopic("");
const auto channel = m_discord.GetChannel(id);
if (!channel.has_value()) return;
const bool can_access = channel->IsDM() || m_discord.HasChannelPermission(m_discord.GetUserData().ID, id, Permission::VIEW_CHANNEL);
if (channel->Type == ChannelType::GUILD_TEXT || channel->Type == ChannelType::GUILD_NEWS)
m_main_window->set_title(std::string(APP_TITLE) + " - #" + *channel->Name);
else {
@@ -482,23 +534,28 @@ void Abaddon::ActionChannelOpened(Snowflake id) {
}
m_main_window->UpdateChatActiveChannel(id);
if (m_channels_requested.find(id) == m_channels_requested.end()) {
m_discord.FetchMessagesInChannel(id, [this, id](const std::vector<Message> &msgs) {
m_main_window->UpdateChatWindowContents();
m_channels_requested.insert(id);
});
// dont fire requests we know will fail
if (can_access) {
m_discord.FetchMessagesInChannel(id, [this, id](const std::vector<Message> &msgs) {
m_main_window->UpdateChatWindowContents();
m_channels_requested.insert(id);
});
}
} else {
m_main_window->UpdateChatWindowContents();
}
if (channel->IsThread()) {
m_discord.SendThreadLazyLoad(id);
if (channel->ThreadMetadata->IsArchived)
m_main_window->GetChatWindow()->SetTopic("This thread is archived. Sending a message will unarchive it");
} else if (channel->Type != ChannelType::DM && channel->Type != ChannelType::GROUP_DM && channel->GuildID.has_value()) {
m_discord.SendLazyLoad(id);
if (can_access) {
if (channel->IsThread()) {
m_discord.SendThreadLazyLoad(id);
if (channel->ThreadMetadata->IsArchived)
m_main_window->GetChatWindow()->SetTopic("This thread is archived. Sending a message will unarchive it");
} else if (channel->Type != ChannelType::DM && channel->Type != ChannelType::GROUP_DM && channel->GuildID.has_value()) {
m_discord.SendLazyLoad(id);
if (m_discord.IsVerificationRequired(*channel->GuildID))
ShowGuildVerificationGateDialog(*channel->GuildID);
if (m_discord.IsVerificationRequired(*channel->GuildID))
ShowGuildVerificationGateDialog(*channel->GuildID);
}
}
}
@@ -510,16 +567,9 @@ void Abaddon::ActionChatLoadHistory(Snowflake id) {
return;
Snowflake before_id = m_main_window->GetChatOldestListedMessage();
auto knownset = m_discord.GetMessageIDsForChannel(id);
std::vector<Snowflake> knownvec(knownset.begin(), knownset.end());
std::sort(knownvec.begin(), knownvec.end());
auto latest = std::find_if(knownvec.begin(), knownvec.end(), [&before_id](Snowflake x) -> bool { return x == before_id; });
int distance = std::distance(knownvec.begin(), latest);
auto msgs = m_discord.GetMessagesBefore(id, before_id);
if (distance >= 50) {
std::vector<Message> msgs;
for (auto it = knownvec.begin() + distance - 50; it != knownvec.begin() + distance; it++)
msgs.push_back(*m_discord.GetMessage(*it));
if (msgs.size() >= 50) {
m_main_window->UpdateChatPrependHistory(msgs);
return;
}
@@ -661,7 +711,7 @@ bool Abaddon::ShowConfirm(const Glib::ustring &prompt, Gtk::Window *window) {
void Abaddon::ActionReloadCSS() {
try {
Gtk::StyleContext::remove_provider_for_screen(Gdk::Screen::get_default(), m_css_provider);
m_css_provider->load_from_path(GetCSSPath("/" + m_settings.GetMainCSS()));
m_css_provider->load_from_path(GetCSSPath("/" + GetSettings().MainCSS));
Gtk::StyleContext::add_provider_for_screen(Gdk::Screen::get_default(), m_css_provider, GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
Gtk::StyleContext::remove_provider_for_screen(Gdk::Screen::get_default(), m_css_low_provider);

View File

@@ -14,7 +14,6 @@
class Abaddon {
private:
Abaddon();
~Abaddon();
Abaddon(const Abaddon &) = delete;
Abaddon &operator=(const Abaddon &) = delete;
Abaddon(Abaddon &&) = delete;
@@ -24,6 +23,8 @@ public:
static Abaddon &Get();
int StartGTK();
void OnShutdown();
void StartDiscord();
void StopDiscord();
@@ -74,7 +75,7 @@ public:
void DiscordOnDisconnect(bool is_reconnecting, GatewayCloseCode close_code);
void DiscordOnThreadUpdate(const ThreadUpdateData &data);
const SettingsManager &GetSettings() const;
SettingsManager::Settings &GetSettings();
Glib::RefPtr<Gtk::CssProvider> GetStyleProvider();
@@ -84,13 +85,17 @@ public:
static std::string GetCSSPath();
static std::string GetResPath();
static std::string GetStateCachePath();
static std::string GetCSSPath(const std::string &path);
static std::string GetResPath(const std::string &path);
static std::string GetStateCachePath(const std::string &path);
protected:
void ShowGuildVerificationGateDialog(Snowflake guild_id);
void SetupUserMenu();
void SaveState();
void LoadState();
Snowflake m_shown_user_menu_id;
Snowflake m_shown_user_menu_guild_id;

View File

@@ -61,7 +61,6 @@ void CellRendererPixbufAnimation::render_vfunc(const Cairo::RefPtr<Cairo::Contex
Gtk::CellRendererState flags) {
Gtk::Requisition minimum, natural;
get_preferred_size(widget, minimum, natural);
auto alloc = widget.get_allocation();
int xpad, ypad;
get_padding(xpad, ypad);
int pix_x = cell_area.get_x() + xpad;

Some files were not shown because too many files have changed in this diff Show More