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
This commit is contained in:
ouwou 2021-11-24 03:14:41 -05:00
parent a51a54bc59
commit 4326c5e29b
22 changed files with 181 additions and 230 deletions

3
.gitmodules vendored
View File

@ -7,9 +7,6 @@
[submodule "ci/gtk-for-windows"]
path = ci/gtk-for-windows
url = https://github.com/tschoonj/GTK-for-Windows-Runtime-Environment-Installer
[submodule "subprojects/simpleini"]
path = subprojects/simpleini
url = https://github.com/brofield/simpleini
[submodule "subprojects/ixwebsocket"]
path = subprojects/ixwebsocket
url = https://github.com/machinezone/ixwebsocket

View File

@ -22,13 +22,6 @@ if (NOT IXWebSocket_FOUND)
include_directories(IXWEBSOCKET_INCLUDE_DIRS)
endif()
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(subprojects/simpleini)
endif()
if(MINGW OR WIN32)
link_libraries(ws2_32)
endif()

View File

@ -32,7 +32,7 @@ Current features:
### 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
@ -75,7 +75,6 @@ On Linux, `css` and `res` can also be loaded from `~/.local/share/abaddon` or `/
* [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:
@ -178,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
@ -199,8 +204,6 @@ 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
#### style
* linkcolor (string) - color to use for links in messages

View File

@ -1,15 +0,0 @@
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)

View File

@ -23,12 +23,12 @@
Abaddon::Abaddon()
: m_settings(Platform::FindConfigFile())
, 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,10 +54,6 @@ Abaddon::Abaddon()
});
}
Abaddon::~Abaddon() {
m_settings.Close();
}
Abaddon &Abaddon::Get() {
static Abaddon instance;
return instance;
@ -85,7 +81,7 @@ int Abaddon::StartGTK() {
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 created!", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
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();
}
@ -133,14 +129,19 @@ int Abaddon::StartGTK() {
ActionReloadCSS();
m_gtk_app->signal_shutdown().connect(sigc::mem_fun(*this, &Abaddon::StopDiscord), false);
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);
@ -248,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() {
@ -367,7 +368,7 @@ void Abaddon::SetupUserMenu() {
}
void Abaddon::SaveState() {
if (!m_settings.GetSaveState()) return;
if (!GetSettings().SaveState) return;
AbaddonApplicationState state;
state.ActiveChannel = m_main_window->GetChatActiveChannel();
@ -387,7 +388,7 @@ void Abaddon::SaveState() {
}
void Abaddon::LoadState() {
if (!m_settings.GetSaveState()) return;
if (!GetSettings().SaveState) return;
const auto data = ReadWholeFile(GetStateCachePath("/state.json"));
if (data.empty()) return;
@ -491,7 +492,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;
}
}
@ -698,7 +699,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();

View File

@ -263,11 +263,9 @@ void ChannelList::UpdateGuild(Snowflake id) {
const auto guild = Abaddon::Get().GetDiscordClient().GetGuild(id);
if (!iter || !guild.has_value()) return;
static const bool show_animations = Abaddon::Get().GetSettings().GetShowAnimations();
(*iter)[m_columns.m_name] = "<b>" + Glib::Markup::escape_text(guild->Name) + "</b>";
(*iter)[m_columns.m_icon] = img.GetPlaceholder(GuildIconSize);
if (show_animations && guild->HasAnimatedIcon()) {
if (Abaddon::Get().GetSettings().ShowAnimations && guild->HasAnimatedIcon()) {
const auto cb = [this, id](const Glib::RefPtr<Gdk::PixbufAnimation> &pb) {
auto iter = GetIteratorForGuildFromID(id);
if (iter) (*iter)[m_columns.m_icon_anim] = pb;
@ -436,9 +434,7 @@ Gtk::TreeModel::iterator ChannelList::AddGuild(const GuildData &guild) {
guild_row[m_columns.m_name] = "<b>" + Glib::Markup::escape_text(guild.Name) + "</b>";
guild_row[m_columns.m_icon] = img.GetPlaceholder(GuildIconSize);
static const bool show_animations = Abaddon::Get().GetSettings().GetShowAnimations();
if (show_animations && guild.HasAnimatedIcon()) {
if (Abaddon::Get().GetSettings().ShowAnimations && guild.HasAnimatedIcon()) {
const auto cb = [this, id = guild.ID](const Glib::RefPtr<Gdk::PixbufAnimation> &pb) {
auto iter = GetIteratorForGuildFromID(id);
if (iter) (*iter)[m_columns.m_icon_anim] = pb;
@ -998,7 +994,7 @@ void CellRendererChannels::render_vfunc_guild(const Cairo::RefPtr<Cairo::Context
m_renderer_text.render(cr, widget, background_area, text_cell_area, flags);
const static bool hover_only = Abaddon::Get().GetSettings().GetAnimatedGuildHoverOnly();
const bool hover_only = Abaddon::Get().GetSettings().AnimatedGuildHoverOnly;
const bool is_hovered = flags & Gtk::CELL_RENDERER_PRELIT;
auto anim = m_property_pixbuf_animation.get_value();
@ -1069,7 +1065,7 @@ void CellRendererChannels::render_vfunc_category(const Cairo::RefPtr<Cairo::Cont
cr->move_to(x1, y1);
cr->line_to(x2, y2);
cr->line_to(x3, y3);
static const auto expander_color = Gdk::RGBA(Abaddon::Get().GetSettings().GetChannelsExpanderColor());
const auto expander_color = Gdk::RGBA(Abaddon::Get().GetSettings().ChannelsExpanderColor);
cr->set_source_rgb(expander_color.get_red(), expander_color.get_green(), expander_color.get_blue());
cr->stroke();
@ -1115,7 +1111,7 @@ void CellRendererChannels::render_vfunc_channel(const Cairo::RefPtr<Cairo::Conte
Gdk::Rectangle text_cell_area(text_x, text_y, text_w, text_h);
const static auto nsfw_color = Gdk::RGBA(Abaddon::Get().GetSettings().GetNSFWChannelColor());
const auto nsfw_color = Gdk::RGBA(Abaddon::Get().GetSettings().NSFWChannelColor);
if (m_property_nsfw.get_value())
m_renderer_text.property_foreground_rgba() = nsfw_color;
m_renderer_text.render(cr, widget, background_area, text_cell_area, flags);

View File

@ -357,7 +357,7 @@ Gtk::Widget *ChatMessageItemContainer::CreateEmbedComponent(const EmbedData &emb
}
return false;
});
static auto color = Abaddon::Get().GetSettings().GetLinkColor();
static auto color = Abaddon::Get().GetSettings().LinkColor;
title_label->override_color(Gdk::RGBA(color));
title_label->set_markup("<b>" + Glib::Markup::escape_text(*embed.Title) + "</b>");
}
@ -798,7 +798,6 @@ void ChatMessageItemContainer::HandleCustomEmojis(Gtk::TextView &tv) {
int mstart, mend;
if (!match.fetch_pos(0, mstart, mend)) break;
const bool is_animated = match.fetch(0)[1] == 'a';
const bool show_animations = Abaddon::Get().GetSettings().GetShowAnimations();
const auto chars_start = g_utf8_pointer_to_offset(text.c_str(), text.c_str() + mstart);
const auto chars_end = g_utf8_pointer_to_offset(text.c_str(), text.c_str() + mend);
@ -806,7 +805,7 @@ void ChatMessageItemContainer::HandleCustomEmojis(Gtk::TextView &tv) {
auto end_it = buf->get_iter_at_offset(chars_end);
startpos = mend;
if (is_animated && show_animations) {
if (is_animated && Abaddon::Get().GetSettings().ShowAnimations) {
const auto mark_start = buf->create_mark(start_it, false);
end_it.backward_char();
const auto mark_end = buf->create_mark(end_it, false);
@ -845,11 +844,8 @@ void ChatMessageItemContainer::HandleCustomEmojis(Gtk::TextView &tv) {
}
void ChatMessageItemContainer::HandleEmojis(Gtk::TextView &tv) {
static const bool stock_emojis = Abaddon::Get().GetSettings().GetShowStockEmojis();
static const bool custom_emojis = Abaddon::Get().GetSettings().GetShowCustomEmojis();
if (stock_emojis) HandleStockEmojis(tv);
if (custom_emojis) HandleCustomEmojis(tv);
if (Abaddon::Get().GetSettings().ShowStockEmojis) HandleStockEmojis(tv);
if (Abaddon::Get().GetSettings().ShowCustomEmojis) HandleCustomEmojis(tv);
}
void ChatMessageItemContainer::CleanupEmojis(Glib::RefPtr<Gtk::TextBuffer> buf) {
@ -969,9 +965,6 @@ void ChatMessageItemContainer::HandleLinks(Gtk::TextView &tv) {
auto buf = tv.get_buffer();
Glib::ustring text = GetText(buf);
// i'd like to let this be done thru css like .message-link { color: #bitch; } but idk how
static auto link_color = Abaddon::Get().GetSettings().GetLinkColor();
int startpos = 0;
Glib::MatchInfo match;
while (rgx->match(text, startpos, match)) {
@ -980,7 +973,7 @@ void ChatMessageItemContainer::HandleLinks(Gtk::TextView &tv) {
std::string link = match.fetch(0);
auto tag = buf->create_tag();
m_link_tagmap[tag] = link;
tag->property_foreground_rgba() = Gdk::RGBA(link_color);
tag->property_foreground_rgba() = Gdk::RGBA(Abaddon::Get().GetSettings().LinkColor);
tag->set_property("underline", 1); // stupid workaround for vcpkg bug (i think)
const auto chars_start = g_utf8_pointer_to_offset(text.c_str(), text.c_str() + mstart);
@ -1138,7 +1131,7 @@ ChatMessageHeader::ChatMessageHeader(const Message &data)
m_content_box_ev.add_events(Gdk::ENTER_NOTIFY_MASK | Gdk::LEAVE_NOTIFY_MASK);
m_meta_ev.add_events(Gdk::ENTER_NOTIFY_MASK | Gdk::LEAVE_NOTIFY_MASK);
m_avatar_ev.add_events(Gdk::ENTER_NOTIFY_MASK | Gdk::LEAVE_NOTIFY_MASK);
if (Abaddon::Get().GetSettings().GetShowAnimations()) {
if (Abaddon::Get().GetSettings().ShowAnimations) {
m_content_box_ev.signal_enter_notify_event().connect(on_enter_cb);
m_content_box_ev.signal_leave_notify_event().connect(on_leave_cb);
m_meta_ev.signal_enter_notify_event().connect(on_enter_cb);

View File

@ -257,8 +257,7 @@ FriendsListFriendRow::FriendsListFriendRow(RelationshipType type, const UserData
auto &discord = Abaddon::Get().GetDiscordClient();
discord.signal_presence_update().connect(sigc::mem_fun(*this, &FriendsListFriendRow::OnPresenceUpdate));
static bool show_animations = Abaddon::Get().GetSettings().GetShowAnimations();
if (data.HasAnimatedAvatar() && show_animations) {
if (data.HasAnimatedAvatar() && Abaddon::Get().GetSettings().ShowAnimations) {
img->SetAnimated(true);
img->SetURL(data.GetAvatarURL("gif", "32"));
} else {

View File

@ -14,8 +14,7 @@ MemberListUserRow::MemberListUserRow(const std::optional<GuildData> &guild, cons
m_avatar = Gtk::manage(new LazyImage(16, 16));
m_status_indicator = Gtk::manage(new StatusIndicator(ID));
static bool crown = Abaddon::Get().GetSettings().GetShowOwnerCrown();
if (crown && guild.has_value() && guild->OwnerID == data.ID) {
if (Abaddon::Get().GetSettings().ShowOwnerCrown && guild.has_value() && guild->OwnerID == data.ID) {
try {
const static auto crown_path = Abaddon::GetResPath("/crown.png");
auto pixbuf = Gdk::Pixbuf::create_from_file(crown_path, 12, 12);
@ -40,9 +39,8 @@ MemberListUserRow::MemberListUserRow(const std::optional<GuildData> &guild, cons
m_label->set_single_line_mode(true);
m_label->set_ellipsize(Pango::ELLIPSIZE_END);
static bool show_discriminator = Abaddon::Get().GetSettings().GetShowMemberListDiscriminators();
std::string display = data.Username;
if (show_discriminator)
if (Abaddon::Get().GetSettings().ShowMemberListDiscriminators)
display += "#" + data.Discriminator;
if (guild.has_value()) {
if (const auto col_id = data.GetHoistedRole(guild->ID, true); col_id.IsValid()) {

View File

@ -67,7 +67,7 @@ FriendPickerDialogItem::FriendPickerDialogItem(Snowflake user_id)
m_name.set_single_line_mode(true);
m_avatar.property_pixbuf() = Abaddon::Get().GetImageManager().GetPlaceholder(32);
if (user.HasAnimatedAvatar() && Abaddon::Get().GetSettings().GetShowAnimations()) {
if (user.HasAnimatedAvatar() && Abaddon::Get().GetSettings().ShowAnimations) {
auto cb = [this](const Glib::RefPtr<Gdk::PixbufAnimation> &pb) {
m_avatar.property_pixbuf_animation() = pb;
};

View File

@ -1303,13 +1303,11 @@ void DiscordClient::HandleGatewayHello(const GatewayMessage &msg) {
// perhaps this should be set by the main class
std::string DiscordClient::GetAPIURL() {
static const auto url = Abaddon::Get().GetSettings().GetAPIBaseURL();
return url;
return Abaddon::Get().GetSettings().APIBaseURL;
}
std::string DiscordClient::GetGatewayURL() {
static const auto url = Abaddon::Get().GetSettings().GetGatewayURL();
return url;
return Abaddon::Get().GetSettings().GatewayURL;
}
DiscordError DiscordClient::GetCodeFromResponse(const http::response_type &response) {

View File

@ -142,7 +142,7 @@ void FileCacheWorkerThread::loop() {
m_cv.wait(lock);
}
static const auto concurrency = static_cast<size_t>(Abaddon::Get().GetSettings().GetCacheHTTPConcurrency());
static const auto concurrency = static_cast<size_t>(Abaddon::Get().GetSettings().CacheHTTPConcurrency);
if (m_handles.size() < concurrency) {
std::optional<QueueEntry> entry;
m_queue_mutex.lock();

View File

@ -2,7 +2,7 @@
#include <filesystem>
#include <fstream>
SettingsManager::SettingsManager(std::string filename)
SettingsManager::SettingsManager(std::string_view filename)
: m_filename(filename) {
if (!std::filesystem::exists(filename)) {
std::fstream fs;
@ -10,106 +10,106 @@ SettingsManager::SettingsManager(std::string filename)
fs.close();
}
auto rc = m_ini.LoadFile(filename.c_str());
m_ok = rc == SI_OK;
try {
m_ok = m_file.load_from_file(m_filename, Glib::KEY_FILE_KEEP_COMMENTS);
} catch (const Glib::Error &e) {
fprintf(stderr, "error opening settings KeyFile: %s\n", e.what().c_str());
m_ok = false;
}
if (m_ok) ReadSettings();
}
void SettingsManager::Reload() {
m_ok = m_ini.LoadFile(m_filename.c_str()) == SI_OK;
}
void SettingsManager::ReadSettings() {
#define SMBOOL(section, key, var) \
try { \
m_settings.var = m_file.get_boolean(section, key); \
} catch (...) {}
#define SMSTR(section, key, var) \
try { \
m_settings.var = m_file.get_string(section, key); \
} catch (...) {}
#define SMINT(section, key, var) \
try { \
m_settings.var = m_file.get_integer(section, key); \
} catch (...) {}
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());
}
SMSTR("discord", "api_base", APIBaseURL);
SMSTR("discord", "gateway", GatewayURL);
SMSTR("discord", "token", DiscordToken);
SMBOOL("discord", "memory_db", UseMemoryDB);
SMBOOL("discord", "prefetch", Prefetch);
SMSTR("gui", "css", MainCSS);
SMBOOL("gui", "animated_guild_hover_only", AnimatedGuildHoverOnly);
SMBOOL("gui", "animations", ShowAnimations);
SMBOOL("gui", "custom_emojis", ShowCustomEmojis);
SMBOOL("gui", "member_list_discriminator", ShowMemberListDiscriminators);
SMBOOL("gui", "owner_crown", ShowOwnerCrown);
SMBOOL("gui", "save_state", SaveState);
SMBOOL("gui", "stock_emojis", ShowStockEmojis);
SMINT("http", "concurrent", CacheHTTPConcurrency);
SMSTR("http", "user_agent", UserAgent);
SMSTR("style", "expandercolor", ChannelsExpanderColor);
SMSTR("style", "linkcolor", LinkColor);
SMSTR("style", "nsfwchannelcolor", NSFWChannelColor);
int SettingsManager::GetSettingInt(const std::string &section, const std::string &key, int fallback) const {
return std::stoul(GetSettingString(section, key, std::to_string(fallback)));
}
#undef SMBOOL
#undef SMSTR
#undef SMINT
bool SettingsManager::GetSettingBool(const std::string &section, const std::string &key, bool fallback) const {
return GetSettingString(section, key, fallback ? "true" : "false") != "false";
m_read_settings = m_settings;
}
bool SettingsManager::IsValid() const {
return m_ok;
}
SettingsManager::Settings &SettingsManager::GetSettings() {
return m_settings;
}
void SettingsManager::Close() {
m_ini.SaveFile(m_filename.c_str());
}
if (m_ok) {
// save anything that changed
// (futureproofing since only DiscordToken can actually change)
#define SMSTR(section, key, var) \
if (m_settings.var != m_read_settings.var) \
m_file.set_string(section, key, m_settings.var);
#define SMBOOL(section, key, var) \
if (m_settings.var != m_read_settings.var) \
m_file.set_boolean(section, key, m_settings.var);
#define SMINT(section, key, var) \
if (m_settings.var != m_read_settings.var) \
m_file.set_integer(section, key, m_settings.var);
bool SettingsManager::GetUseMemoryDB() const {
return GetSettingBool("discord", "memory_db", false);
}
SMSTR("discord", "api_base", APIBaseURL);
SMSTR("discord", "gateway", GatewayURL);
SMSTR("discord", "token", DiscordToken);
SMBOOL("discord", "memory_db", UseMemoryDB);
SMBOOL("discord", "prefetch", Prefetch);
SMSTR("gui", "css", MainCSS);
SMBOOL("gui", "animated_guild_hover_only", AnimatedGuildHoverOnly);
SMBOOL("gui", "animations", ShowAnimations);
SMBOOL("gui", "custom_emojis", ShowCustomEmojis);
SMBOOL("gui", "member_list_discriminator", ShowMemberListDiscriminators);
SMBOOL("gui", "owner_crown", ShowOwnerCrown);
SMBOOL("gui", "save_state", SaveState);
SMBOOL("gui", "stock_emojis", ShowStockEmojis);
SMINT("http", "concurrent", CacheHTTPConcurrency);
SMSTR("http", "user_agent", UserAgent);
SMSTR("style", "expandercolor", ChannelsExpanderColor);
SMSTR("style", "linkcolor", LinkColor);
SMSTR("style", "nsfwchannelcolor", NSFWChannelColor);
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");
}
#undef SMSTR
#undef SMBOOL
#undef SMINT
std::string SettingsManager::GetDiscordToken() const {
return GetSettingString("discord", "token");
}
bool SettingsManager::GetShowMemberListDiscriminators() const {
return GetSettingBool("gui", "member_list_discriminator", true);
}
bool SettingsManager::GetShowStockEmojis() const {
#ifdef _WIN32
return GetSettingBool("gui", "stock_emojis", false);
#else
return GetSettingBool("gui", "stock_emojis", true);
#endif
}
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);
}
bool SettingsManager::GetSaveState() const {
return GetSettingBool("gui", "save_state", true);
try {
if (!m_file.save_to_file(m_filename))
fputs("failed to save settings KeyFile", stderr);
} catch (const Glib::Error &e) {
fprintf(stderr, "failed to save settings KeyFile: %s\n", e.what().c_str());
}
}
}

View File

@ -1,62 +1,55 @@
#pragma once
#include <string>
#include <type_traits>
#include <SimpleIni.h>
#include <glibmm/keyfile.h>
class SettingsManager {
public:
SettingsManager(std::string filename);
void Reload();
struct Settings {
// [discord]
std::string APIBaseURL { "https://discord.com/api/v9" };
std::string GatewayURL { "wss://gateway.discord.gg/?v=9&encoding=json&compress=zlib-stream" };
std::string DiscordToken;
bool UseMemoryDB { false };
bool Prefetch { false };
// [gui]
std::string MainCSS { "main.css" };
bool AnimatedGuildHoverOnly { true };
bool ShowAnimations { true };
bool ShowCustomEmojis { true };
bool ShowMemberListDiscriminators { true };
bool ShowOwnerCrown { true };
bool SaveState { true };
#ifdef _WIN32
bool ShowStockEmojis { false };
#else
bool ShowStockEmojis { true };
#endif
// [http]
int CacheHTTPConcurrency { 20 };
std::string UserAgent { "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36" };
// [style]
// TODO: convert to StyleProperty
std::string LinkColor { "rgba(40, 200, 180, 255)" };
std::string ChannelsExpanderColor { "rgba(255, 83, 112, 255)" };
std::string NSFWChannelColor { "#ed6666" };
};
SettingsManager(std::string_view filename);
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;
bool GetSaveState() 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());
}
Settings &GetSettings();
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;
void ReadSettings();
private:
bool m_ok;
std::string m_filename;
CSimpleIniA m_ini;
Glib::KeyFile m_file;
Settings m_settings;
Settings m_read_settings;
};

View File

@ -130,8 +130,7 @@ void GuildSettingsEmojisPane::AddEmojiRow(const EmojiData &emoji) {
else
row[m_columns.m_col_available] = "Yes";
static bool show_animations = Abaddon::Get().GetSettings().GetShowAnimations();
if (show_animations && emoji.IsAnimated.has_value() && *emoji.IsAnimated) {
if (Abaddon::Get().GetSettings().ShowAnimations && emoji.IsAnimated.has_value() && *emoji.IsAnimated) {
const auto cb = [this, id = emoji.ID](const Glib::RefPtr<Gdk::PixbufAnimation> &pb) {
for (auto &row : m_model->children()) {
if (static_cast<Snowflake>(row[m_columns.m_col_id]) == id) {

View File

@ -81,7 +81,7 @@ GuildSettingsInfoPane::GuildSettingsInfoPane(Snowflake id)
void GuildSettingsInfoPane::FetchGuildIcon(const GuildData &guild) {
m_guild_icon.property_pixbuf() = Abaddon::Get().GetImageManager().GetPlaceholder(32);
if (guild.HasIcon()) {
if (Abaddon::Get().GetSettings().GetShowAnimations() && guild.HasAnimatedIcon()) {
if (Abaddon::Get().GetSettings().ShowAnimations && guild.HasAnimatedIcon()) {
auto cb = [this](const Glib::RefPtr<Gdk::PixbufAnimation> &pixbuf) {
m_guild_icon.property_pixbuf_animation() = pixbuf;
};

View File

@ -99,7 +99,7 @@ GuildSettingsMembersListItem::GuildSettingsMembersListItem(const GuildData &guil
auto &discord = Abaddon::Get().GetDiscordClient();
if (member.User->HasAnimatedAvatar() && Abaddon::Get().GetSettings().GetShowAnimations())
if (member.User->HasAnimatedAvatar() && Abaddon::Get().GetSettings().ShowAnimations)
m_avatar.SetURL(member.User->GetAvatarURL("gif", "32"));
else
m_avatar.SetURL(member.User->GetAvatarURL("png", "32"));
@ -113,8 +113,7 @@ GuildSettingsMembersListItem::GuildSettingsMembersListItem(const GuildData &guil
discord.signal_guild_member_update().connect(sigc::track_obj(member_update_cb, *this));
UpdateColor();
static bool crown = Abaddon::Get().GetSettings().GetShowOwnerCrown();
if (crown && guild.OwnerID == member.User->ID) {
if (Abaddon::Get().GetSettings().ShowOwnerCrown && guild.OwnerID == member.User->ID) {
try {
const static auto crown_path = Abaddon::GetResPath("/crown.png");
auto pixbuf = Gdk::Pixbuf::create_from_file(crown_path, 12, 12);

View File

@ -9,10 +9,9 @@ MutualFriendItem::MutualFriendItem(const UserData &user)
m_avatar.set_margin_end(10);
const auto show_animations = Abaddon::Get().GetSettings().GetShowAnimations();
auto &img = Abaddon::Get().GetImageManager();
m_avatar.property_pixbuf() = img.GetPlaceholder(24);
if (user.HasAnimatedAvatar() && show_animations) {
if (user.HasAnimatedAvatar() && Abaddon::Get().GetSettings().ShowAnimations) {
auto cb = [this](const Glib::RefPtr<Gdk::PixbufAnimation> &pb) {
m_avatar.property_pixbuf_animation() = pb;
};

View File

@ -13,11 +13,10 @@ MutualGuildItem::MutualGuildItem(const MutualGuildData &guild)
// discord will return info (id + nick) for "deleted" guilds from this endpoint. strange !
const auto data = Abaddon::Get().GetDiscordClient().GetGuild(guild.ID);
if (data.has_value()) {
const auto show_animations = Abaddon::Get().GetSettings().GetShowAnimations();
auto &img = Abaddon::Get().GetImageManager();
m_icon.property_pixbuf() = img.GetPlaceholder(24);
if (data->HasIcon()) {
if (data->HasAnimatedIcon() && show_animations) {
if (data->HasAnimatedIcon() && Abaddon::Get().GetSettings().ShowAnimations) {
auto cb = [this](const Glib::RefPtr<Gdk::PixbufAnimation> &pb) {
m_icon.property_pixbuf_animation() = pb;
};

View File

@ -44,7 +44,6 @@ ProfileWindow::ProfileWindow(Snowflake user_id)
return false;
});
static const bool show_animations = Abaddon::Get().GetSettings().GetShowAnimations();
auto &img = Abaddon::Get().GetImageManager();
m_avatar.property_pixbuf() = img.GetPlaceholder(64);
auto icon_cb = [this](const Glib::RefPtr<Gdk::Pixbuf> &pb) {
@ -52,7 +51,7 @@ ProfileWindow::ProfileWindow(Snowflake user_id)
};
img.LoadFromURL(user.GetAvatarURL("png", "64"), sigc::track_obj(icon_cb, *this));
if (show_animations && user.HasAnimatedAvatar()) {
if (Abaddon::Get().GetSettings().ShowAnimations && user.HasAnimatedAvatar()) {
auto cb = [this](const Glib::RefPtr<Gdk::PixbufAnimation> &pb) {
m_avatar.property_pixbuf_animation() = pb;
};

@ -1 +0,0 @@
Subproject commit 67156f64b3447ce1eb81d6be44d29132fb49b70a