forked from OpenGamers/abaddon
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f1a39c006f | ||
|
|
3e34f785c6 | ||
|
|
9694813724 | ||
|
|
3393526876 | ||
|
|
b6424c9d37 | ||
|
|
bf560ae9d2 | ||
|
|
fa1a007dc1 | ||
|
|
abc0a7931e | ||
|
|
ad523f37c5 | ||
|
|
cf33d53809 | ||
|
|
e8b1bcd216 | ||
|
|
dead7f2f6a | ||
|
|
df6b01a632 | ||
|
|
9755090c8c | ||
|
|
3815d97f5f | ||
|
|
7cb4a75ca7 |
@@ -7,23 +7,27 @@ 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)
|
||||
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(thirdparty/IXWebSocket)
|
||||
include_directories(IXWEBSOCKET_INCLUDE_DIRS)
|
||||
endif()
|
||||
|
||||
include_directories(thirdparty/simpleini)
|
||||
add_compile_definitions(SI_NO_CONVERSION) # only CSimpleIniA is used
|
||||
find_package(simpleini QUIET)
|
||||
if (NOT simpleini_FOUND)
|
||||
message("simpleini was not found and will be included as a submodule")
|
||||
include_directories(thirdparty/simpleini)
|
||||
endif()
|
||||
|
||||
if(MINGW OR WIN32)
|
||||
link_libraries(ws2_32)
|
||||
@@ -58,6 +62,7 @@ file(GLOB ABADDON_SOURCES
|
||||
)
|
||||
|
||||
add_executable(abaddon ${ABADDON_SOURCES})
|
||||
target_include_directories(abaddon PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
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 +75,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)
|
||||
|
||||
19
README.md
19
README.md
@@ -10,7 +10,7 @@ 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
|
||||
* Start new DMs and group DMs
|
||||
* View user profiles (notes, mutual servers, mutual friends)
|
||||
@@ -20,10 +20,14 @@ 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 subtituted 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:
|
||||
@@ -49,14 +53,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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -50,7 +50,6 @@ endif()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(glib
|
||||
FOUND_VAR GLIB_FOUND
|
||||
REQUIRED_VARS
|
||||
GLIB_LIBRARIES
|
||||
GLIB_INCLUDE_DIRS
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,17 +1,30 @@
|
||||
find_path(IXWEBSOCKET_INCLUDE_DIR
|
||||
NAMES ixwebsocket/IXWebSocket.h)
|
||||
set(IXWebSocket_LIBRARY_NAME ixwebsocket)
|
||||
|
||||
find_library(IXWEBSOCKET_LIBRARY
|
||||
NAMES ixwebsocket
|
||||
HINTS ${IXWEBSOCKET_LIBRARY_ROOT})
|
||||
find_path(IXWebSocket_INCLUDE_DIR
|
||||
NAMES ixwebsocket/IXWebSocket.h
|
||||
HINTS /usr/include
|
||||
/usr/local/include
|
||||
/opt/local/include
|
||||
PATH_SUFFIXES ${IXWebSocket_LIBRARY_NAME})
|
||||
|
||||
set(IXWEBSOCKET_LIBRARIES ${IXWEBSOCKET_LIBRARY})
|
||||
set(IXWEBSOCKET_INCLUDE_DIRS ${IXWEBSOCKET_INCLUDE_DIR})
|
||||
|
||||
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
|
||||
FOUND_VAR IXWEBSOCKET_FOUND
|
||||
|
||||
find_package_handle_standard_args(IXWebSocket
|
||||
REQUIRED_VARS
|
||||
IXWEBSOCKET_LIBRARY
|
||||
IXWEBSOCKET_INCLUDE_DIR
|
||||
VERSION_VAR IXWEBSOCKET_VERSION)
|
||||
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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
15
cmake/Findsimpleini.cmake
Normal file
15
cmake/Findsimpleini.cmake
Normal file
@@ -0,0 +1,15 @@
|
||||
set(simpleini_LIBRARY_NAME simpleini)
|
||||
|
||||
find_path(simpleini_INCLUDE_DIR
|
||||
NAMES SimpleIni.h
|
||||
HINTS /usr/include
|
||||
/usr/local/include
|
||||
/opt/local/include
|
||||
PATH_SUFFIXES ${simpleini_LIBRARY_NAME})
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(simpleini
|
||||
REQUIRED_VARS
|
||||
simpleini_INCLUDE_DIR)
|
||||
|
||||
mark_as_advanced(simpleini_INCLUDE_DIR)
|
||||
@@ -227,7 +227,7 @@ void ChannelList::UpdateChannel(Snowflake id) {
|
||||
Gtk::TreeModel::iterator new_parent;
|
||||
if (channel->ParentID.has_value())
|
||||
new_parent = GetIteratorForChannelFromID(*channel->ParentID);
|
||||
else
|
||||
else if (channel->GuildID.has_value())
|
||||
new_parent = GetIteratorForGuildFromID(*channel->GuildID);
|
||||
|
||||
if (new_parent && iter->parent() != new_parent)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "chatmessage.hpp"
|
||||
#include "chatlist.hpp"
|
||||
#include "../abaddon.hpp"
|
||||
#include "../constants.hpp"
|
||||
#include "abaddon.hpp"
|
||||
#include "constants.hpp"
|
||||
|
||||
ChatList::ChatList() {
|
||||
m_list.get_style_context()->add_class("messages");
|
||||
@@ -139,7 +139,10 @@ void ChatList::ProcessNewMessage(const Message &data, bool prepend) {
|
||||
if (should_attach) {
|
||||
header = last_row;
|
||||
} else {
|
||||
const auto guild_id = *discord.GetChannel(m_active_channel)->GuildID;
|
||||
const auto chan = discord.GetChannel(m_active_channel);
|
||||
Snowflake guild_id;
|
||||
if (chan.has_value() && chan->GuildID.has_value())
|
||||
guild_id = *chan->GuildID;
|
||||
const auto user_id = data.Author.ID;
|
||||
const auto user = discord.GetUser(user_id);
|
||||
if (!user.has_value()) return;
|
||||
@@ -170,13 +173,14 @@ void ChatList::ProcessNewMessage(const Message &data, bool prepend) {
|
||||
if (!data.has_value()) return false;
|
||||
const auto channel = client.GetChannel(m_active_channel);
|
||||
|
||||
bool is_dm = channel.has_value() && (channel->Type == ChannelType::DM || channel->Type == ChannelType::GROUP_DM);
|
||||
const bool has_manage = client.HasChannelPermission(client.GetUserData().ID, m_active_channel, Permission::MANAGE_MESSAGES);
|
||||
bool has_manage = channel.has_value() && (channel->Type == ChannelType::DM || channel->Type == ChannelType::GROUP_DM);
|
||||
if (!has_manage)
|
||||
has_manage = client.HasChannelPermission(client.GetUserData().ID, m_active_channel, Permission::MANAGE_MESSAGES);
|
||||
|
||||
m_menu_edit_message->set_visible(!m_use_pinned_menu);
|
||||
m_menu_reply_to->set_visible(!m_use_pinned_menu);
|
||||
m_menu_unpin->set_visible((is_dm || has_manage) && data->IsPinned);
|
||||
m_menu_pin->set_visible((is_dm || has_manage) && !data->IsPinned);
|
||||
m_menu_unpin->set_visible(has_manage && data->IsPinned);
|
||||
m_menu_pin->set_visible(has_manage && !data->IsPinned);
|
||||
|
||||
if (data->IsDeleted()) {
|
||||
m_menu_delete_message->set_sensitive(false);
|
||||
@@ -239,7 +243,10 @@ void ChatList::RefetchMessage(Snowflake id) {
|
||||
}
|
||||
|
||||
Snowflake ChatList::GetOldestListedMessage() {
|
||||
return m_id_to_widget.begin()->first;
|
||||
if (m_id_to_widget.size() > 0)
|
||||
return m_id_to_widget.begin()->first;
|
||||
else
|
||||
return Snowflake::Invalid;
|
||||
}
|
||||
|
||||
void ChatList::UpdateMessageReactions(Snowflake id) {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#include <gtkmm.h>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include "../discord/snowflake.hpp"
|
||||
#include "discord/snowflake.hpp"
|
||||
|
||||
class ChatList : public Gtk::ScrolledWindow {
|
||||
public:
|
||||
@@ -21,7 +21,7 @@ public:
|
||||
void SetFailedByNonce(const std::string &nonce);
|
||||
std::vector<Snowflake> GetRecentAuthors();
|
||||
void SetSeparateAll(bool separate);
|
||||
void SetUsePinnedMenu(); // i think i need a better way to do menus
|
||||
void SetUsePinnedMenu(); // i think i need a better way to do menus
|
||||
void ActuallyRemoveMessage(Snowflake id); // perhaps not the best method name
|
||||
|
||||
private:
|
||||
@@ -101,6 +101,15 @@ inline void ChatList::SetMessages(Iter begin, Iter end) {
|
||||
|
||||
template<typename Iter>
|
||||
inline void ChatList::PrependMessages(Iter begin, Iter end) {
|
||||
const auto old_upper = get_vadjustment()->get_upper();
|
||||
const auto old_value = get_vadjustment()->get_value();
|
||||
for (Iter it = begin; it != end; it++)
|
||||
ProcessNewMessage(*it, true);
|
||||
// force everything to process before getting new values
|
||||
while (Gtk::Main::events_pending())
|
||||
Gtk::Main::iteration();
|
||||
const auto new_upper = get_vadjustment()->get_upper();
|
||||
if (old_value == 0.0 && (new_upper - old_upper) > 0.0)
|
||||
get_vadjustment()->set_value(new_upper - old_upper);
|
||||
// this isn't ideal
|
||||
}
|
||||
|
||||
@@ -692,7 +692,10 @@ Gtk::Widget *ChatMessageItemContainer::CreateReplyComponent(const Message &data)
|
||||
// which of course would not be an issue if i could figure out how to get fonts to work on this god-forsaken framework
|
||||
// oh well
|
||||
// but ill manually get colors for the user who is being replied to
|
||||
lbl->set_markup(get_author_markup(referenced.Author.ID, *referenced.GuildID) + ": " + text);
|
||||
if (referenced.GuildID.has_value())
|
||||
lbl->set_markup(get_author_markup(referenced.Author.ID, *referenced.GuildID) + ": " + text);
|
||||
else
|
||||
lbl->set_markup(get_author_markup(referenced.Author.ID) + ": " + text);
|
||||
}
|
||||
} else {
|
||||
lbl->set_markup("<i>reply unavailable</i>");
|
||||
@@ -1163,19 +1166,21 @@ ChatMessageHeader::ChatMessageHeader(const Message &data)
|
||||
|
||||
void ChatMessageHeader::UpdateNameColor() {
|
||||
const auto &discord = Abaddon::Get().GetDiscordClient();
|
||||
const auto guild_id = discord.GetChannel(ChannelID)->GuildID;
|
||||
const auto role_id = discord.GetMemberHoistedRole(*guild_id, UserID, true);
|
||||
const auto user = discord.GetUser(UserID);
|
||||
if (!user.has_value()) return;
|
||||
const auto role = discord.GetRole(role_id);
|
||||
const auto chan = discord.GetChannel(ChannelID);
|
||||
bool is_guild = chan.has_value() && chan->GuildID.has_value();
|
||||
if (is_guild) {
|
||||
const auto role_id = discord.GetMemberHoistedRole(*chan->GuildID, UserID, true);
|
||||
const auto role = discord.GetRole(role_id);
|
||||
|
||||
std::string md;
|
||||
if (role.has_value())
|
||||
md = "<span weight='bold' color='#" + IntToCSSColor(role->Color) + "'>" + user->GetEscapedName() + "</span>";
|
||||
else
|
||||
md = "<span weight='bold'>" + user->GetEscapedName() + "</span>";
|
||||
|
||||
m_author.set_markup(md);
|
||||
std::string md;
|
||||
if (role.has_value())
|
||||
m_author.set_markup("<span weight='bold' color='#" + IntToCSSColor(role->Color) + "'>" + user->GetEscapedName() + "</span>");
|
||||
else
|
||||
m_author.set_markup("<span weight='bold'>" + user->GetEscapedName() + "</span>");
|
||||
} else
|
||||
m_author.set_markup("<span weight='bold'>" + user->GetEscapedName() + "</span>");
|
||||
}
|
||||
|
||||
std::vector<Gtk::Widget *> ChatMessageHeader::GetChildContent() {
|
||||
|
||||
@@ -94,7 +94,7 @@ void MemberList::SetActiveChannel(Snowflake id) {
|
||||
m_guild_id = Snowflake::Invalid;
|
||||
if (m_chan_id.IsValid()) {
|
||||
const auto chan = Abaddon::Get().GetDiscordClient().GetChannel(id);
|
||||
if (chan.has_value()) m_guild_id = *chan->GuildID;
|
||||
if (chan.has_value() && chan->GuildID.has_value()) m_guild_id = *chan->GuildID;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -106,6 +106,7 @@ bool RateLimitIndicator::UpdateIndicator() {
|
||||
void RateLimitIndicator::OnMessageCreate(const Message &message) {
|
||||
auto &discord = Abaddon::Get().GetDiscordClient();
|
||||
if (message.Author.ID != discord.GetUserData().ID) return;
|
||||
if (!message.GuildID.has_value()) return;
|
||||
const bool can_bypass = discord.HasAnyChannelPermission(discord.GetUserData().ID, m_active_channel, Permission::MANAGE_MESSAGES | Permission::MANAGE_CHANNELS);
|
||||
const auto rate_limit = GetRateLimit();
|
||||
if (rate_limit > 0 && !can_bypass) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "verificationgate.hpp"
|
||||
#include "../../abaddon.hpp"
|
||||
#include "../abaddon.hpp"
|
||||
|
||||
VerificationGateDialog::VerificationGateDialog(Gtk::Window &parent, Snowflake guild_id)
|
||||
: Gtk::Dialog("Verification Required", parent, true)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
#include <gtkmm.h>
|
||||
#include <optional>
|
||||
#include "../../discord/objects.hpp"
|
||||
#include "../discord/objects.hpp"
|
||||
|
||||
class VerificationGateDialog : public Gtk::Dialog {
|
||||
public:
|
||||
|
||||
@@ -152,7 +152,8 @@ void DiscordClient::FetchMessagesInChannel(Snowflake id, sigc::slot<void(const s
|
||||
m_store.BeginTransaction();
|
||||
for (auto &msg : msgs) {
|
||||
StoreMessageData(msg);
|
||||
AddUserToGuild(msg.Author.ID, *msg.GuildID);
|
||||
if (msg.GuildID.has_value())
|
||||
AddUserToGuild(msg.Author.ID, *msg.GuildID);
|
||||
}
|
||||
m_store.EndTransaction();
|
||||
|
||||
@@ -172,7 +173,8 @@ void DiscordClient::FetchMessagesInChannelBefore(Snowflake channel_id, Snowflake
|
||||
m_store.BeginTransaction();
|
||||
for (auto &msg : msgs) {
|
||||
StoreMessageData(msg);
|
||||
AddUserToGuild(msg.Author.ID, *msg.GuildID);
|
||||
if (msg.GuildID.has_value())
|
||||
AddUserToGuild(msg.Author.ID, *msg.GuildID);
|
||||
}
|
||||
m_store.EndTransaction();
|
||||
|
||||
@@ -300,7 +302,7 @@ bool DiscordClient::HasGuildPermission(Snowflake user_id, Snowflake guild_id, Pe
|
||||
|
||||
bool DiscordClient::HasAnyChannelPermission(Snowflake user_id, Snowflake channel_id, Permission perm) const {
|
||||
const auto channel = m_store.GetChannel(channel_id);
|
||||
if (!channel.has_value()) return false;
|
||||
if (!channel.has_value() || !channel->GuildID.has_value()) return false;
|
||||
const auto base = ComputePermissions(user_id, *channel->GuildID);
|
||||
const auto overwrites = ComputeOverwrites(base, user_id, channel_id);
|
||||
return (overwrites & perm) != Permission::NONE;
|
||||
@@ -1400,7 +1402,8 @@ void DiscordClient::HandleGatewayReady(const GatewayMessage &msg) {
|
||||
void DiscordClient::HandleGatewayMessageCreate(const GatewayMessage &msg) {
|
||||
Message data = msg.Data;
|
||||
StoreMessageData(data);
|
||||
AddUserToGuild(data.Author.ID, *data.GuildID);
|
||||
if (data.GuildID.has_value())
|
||||
AddUserToGuild(data.Author.ID, *data.GuildID);
|
||||
m_signal_message_create.emit(data);
|
||||
}
|
||||
|
||||
@@ -2077,9 +2080,6 @@ void DiscordClient::HandleSocketClose(uint16_t code) {
|
||||
if (m_heartbeat_thread.joinable()) m_heartbeat_thread.join();
|
||||
m_client_connected = false;
|
||||
|
||||
m_store.ClearAll();
|
||||
m_guild_to_users.clear();
|
||||
|
||||
if (m_client_started && !m_reconnecting && close_code == GatewayCloseCode::Abnormal) {
|
||||
Glib::signal_timeout().connect_once([this] { if (m_client_started) HandleGatewayReconnect(GatewayMessage()); }, 1000);
|
||||
m_reconnecting = true;
|
||||
|
||||
@@ -17,8 +17,13 @@ Cache::Cache() {
|
||||
Cache::~Cache() {
|
||||
m_worker.stop();
|
||||
|
||||
for (auto &future : m_futures)
|
||||
if (future.valid()) future.get();
|
||||
for (auto &future : m_futures) {
|
||||
if (future.valid()) {
|
||||
try { // dont care about stored exceptions
|
||||
future.get();
|
||||
} catch (...) {}
|
||||
}
|
||||
}
|
||||
|
||||
std::error_code err;
|
||||
if (!std::filesystem::remove_all(m_tmp_path, err))
|
||||
|
||||
@@ -55,7 +55,11 @@ bool SettingsManager::GetShowMemberListDiscriminators() const {
|
||||
}
|
||||
|
||||
bool SettingsManager::GetShowStockEmojis() const {
|
||||
#ifdef _WIN32
|
||||
return GetSettingBool("gui", "stock_emojis", false);
|
||||
#else
|
||||
return GetSettingBool("gui", "stock_emojis", true);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool SettingsManager::GetShowCustomEmojis() const {
|
||||
|
||||
2
thirdparty/simpleini
vendored
2
thirdparty/simpleini
vendored
Submodule thirdparty/simpleini updated: 7bca74f653...67156f64b3
@@ -30,6 +30,8 @@ void GuildSettingsAuditLogPane::OnAuditLogFetch(const AuditLogData &data) {
|
||||
auto &discord = Abaddon::Get().GetDiscordClient();
|
||||
auto guild = *discord.GetGuild(GuildID);
|
||||
for (const auto &entry : data.Entries) {
|
||||
if (entry.TargetID == "") continue;
|
||||
|
||||
auto expander = Gtk::manage(new Gtk::Expander);
|
||||
auto label = Gtk::manage(new Gtk::Label);
|
||||
label->set_ellipsize(Pango::ELLIPSIZE_END);
|
||||
|
||||
@@ -159,15 +159,7 @@ GuildSettingsRolesPaneRolesListItem::GuildSettingsRolesPaneRolesListItem(const G
|
||||
|
||||
UpdateItem(role);
|
||||
|
||||
discord.signal_role_update().connect([this, &discord](Snowflake guild_id, Snowflake role_id) {
|
||||
if (guild_id != GuildID || role_id != RoleID) return;
|
||||
const auto role = discord.GetRole(RoleID);
|
||||
if (!role.has_value())
|
||||
printf("nullopt??? %llu\n", (uint64_t)RoleID);
|
||||
Position = role->Position;
|
||||
UpdateItem(*role);
|
||||
changed();
|
||||
});
|
||||
discord.signal_role_update().connect(sigc::mem_fun(*this, &GuildSettingsRolesPaneRolesListItem::OnRoleUpdate));
|
||||
|
||||
m_name.set_ellipsize(Pango::ELLIPSIZE_END);
|
||||
|
||||
@@ -190,6 +182,15 @@ void GuildSettingsRolesPaneRolesListItem::UpdateItem(const RoleData &role) {
|
||||
m_name.set_text(role.Name);
|
||||
}
|
||||
|
||||
void GuildSettingsRolesPaneRolesListItem::OnRoleUpdate(Snowflake guild_id, Snowflake role_id) {
|
||||
if (guild_id != GuildID || role_id != RoleID) return;
|
||||
const auto role = Abaddon::Get().GetDiscordClient().GetRole(RoleID);
|
||||
if (!role.has_value()) return;
|
||||
Position = role->Position;
|
||||
UpdateItem(*role);
|
||||
changed();
|
||||
}
|
||||
|
||||
GuildSettingsRolesPaneInfo::GuildSettingsRolesPaneInfo(Snowflake guild_id)
|
||||
: GuildID(guild_id)
|
||||
, m_layout(Gtk::ORIENTATION_VERTICAL)
|
||||
|
||||
@@ -16,6 +16,7 @@ public:
|
||||
|
||||
private:
|
||||
void UpdateItem(const RoleData &role);
|
||||
void OnRoleUpdate(Snowflake guild_id, Snowflake role_id);
|
||||
|
||||
Gtk::EventBox m_ev;
|
||||
Gtk::Label m_name;
|
||||
|
||||
Reference in New Issue
Block a user