diff --git a/src/settings.cpp b/src/settings.cpp index d1dff3f..df9b71f 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -26,87 +26,127 @@ SettingsManager::SettingsManager(const std::string &filename) m_ok = false; } + DefineSettings(); if (m_ok) ReadSettings(); } -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 (...) {} -#define SMFLT(section, key, var) \ - try { \ - m_settings.var = m_file.get_double(section, key); \ - } catch (...) {} - - SMSTR("discord", "api_base", APIBaseURL); - SMSTR("discord", "gateway", GatewayURL); - SMBOOL("discord", "memory_db", UseMemoryDB); - SMBOOL("discord", "prefetch", Prefetch); - SMBOOL("discord", "autoconnect", Autoconnect); - 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); - SMBOOL("gui", "unreads", Unreads); - SMBOOL("gui", "alt_menu", AltMenu); - SMBOOL("gui", "hide_to_tray", HideToTray); - SMBOOL("gui", "show_deleted_indicator", ShowDeletedIndicator); - SMFLT("gui", "font_scale", FontScale); - SMINT("http", "concurrent", CacheHTTPConcurrency); - SMSTR("http", "user_agent", UserAgent); - SMSTR("style", "expandercolor", ChannelsExpanderColor); - SMSTR("style", "nsfwchannelcolor", NSFWChannelColor); - SMSTR("style", "mentionbadgecolor", MentionBadgeColor); - SMSTR("style", "mentionbadgetextcolor", MentionBadgeTextColor); - SMSTR("style", "unreadcolor", UnreadIndicatorColor); - SMBOOL("notifications", "enabled", NotificationsEnabled); - SMBOOL("notifications", "playsound", NotificationsPlaySound); - SMSTR("voice", "vad", VAD); - SMBOOL("windows", "hideconsole", HideConsole); - +void SettingsManager::HandleReadToken() { #ifdef WITH_KEYCHAIN - keychain::Error error {}; + // Move to keychain if present - // convert to keychain if present in normal settings - SMSTR("discord", "token", DiscordToken); + std::string token; + try { + token = m_file.get_string("discord", "token"); + } catch (...) {} - if (!m_settings.DiscordToken.empty()) { - keychain::Error set_error {}; - - keychain::setPassword(KeychainPackage, KeychainService, KeychainUser, m_settings.DiscordToken, set_error); - if (set_error) { - printf("keychain error setting token: %s\n", set_error.message.c_str()); + if (!token.empty()) { + keychain::Error error {}; + keychain::setPassword(KeychainPackage, KeychainService, KeychainUser, token, error); + if (error) { + spdlog::get("ui")->error("Keychain error setting token: {}", error.message); } else { m_file.remove_key("discord", "token"); } } + keychain::Error error {}; m_settings.DiscordToken = keychain::getPassword(KeychainPackage, KeychainService, KeychainUser, error); if (error && error.type != keychain::ErrorType::NotFound) { - printf("keychain error reading token: %s (%d)\n", error.message.c_str(), error.code); + spdlog::get("ui")->error("Keychain error reading token: {} ({})", error.message, error.code); } #else - SMSTR("discord", "token", DiscordToken); + AddSetting("discord", "token", "", &Settings::DiscordToken); +#endif +} + +void SettingsManager::HandleWriteToken() { +#ifdef WITH_KEYCHAIN + keychain::Error error {}; + + keychain::setPassword(KeychainPackage, KeychainService, KeychainUser, m_settings.DiscordToken, error); + if (error) { + spdlog::get("ui")->error("Keychain error setting token: {}", error.message); + } +#endif + // else it will get enumerated over as part of definitions +} + +void SettingsManager::DefineSettings() { + using namespace std::string_literals; + + AddSetting("discord", "api_base", "https://discord.com/api/v9"s, &Settings::APIBaseURL); + AddSetting("discord", "gateway", "wss://gateway.discord.gg/?v=9&encoding=json&compress=zlib-stream"s, &Settings::GatewayURL); + AddSetting("discord", "memory_db", false, &Settings::UseMemoryDB); + AddSetting("discord", "prefetch", false, &Settings::Prefetch); + AddSetting("discord", "autoconnect", false, &Settings::Autoconnect); + + AddSetting("gui", "css", "main.css"s, &Settings::MainCSS); + AddSetting("gui", "animated_guild_hover_only", true, &Settings::AnimatedGuildHoverOnly); + AddSetting("gui", "animations", true, &Settings::ShowAnimations); + AddSetting("gui", "custom_emojis", true, &Settings::ShowCustomEmojis); + AddSetting("gui", "owner_crown", true, &Settings::ShowOwnerCrown); + AddSetting("gui", "save_state", true, &Settings::SaveState); + AddSetting("gui", "stock_emojis", false, &Settings::ShowStockEmojis); + AddSetting("gui", "unreads", true, &Settings::Unreads); + AddSetting("gui", "alt_menu", false, &Settings::AltMenu); + AddSetting("gui", "hide_to_try", false, &Settings::HideToTray); + AddSetting("gui", "show_deleted_indicator", true, &Settings::ShowDeletedIndicator); + AddSetting("gui", "font_scale", -1.0, &Settings::FontScale); + + AddSetting("http", "concurrent", 20, &Settings::CacheHTTPConcurrency); + AddSetting("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"s, &Settings::UserAgent); + + AddSetting("style", "expandercolor", "rgba(255, 83, 112, 0)"s, &Settings::ChannelsExpanderColor); + AddSetting("style", "nsfwchannelcolor", "#970d0d"s, &Settings::NSFWChannelColor); + AddSetting("style", "mentionbadgecolor", "rgba(184, 37, 37, 0)"s, &Settings::MentionBadgeColor); + AddSetting("style", "mentionbadgetextcolor", "rgba(251, 251, 251, 0)"s, &Settings::MentionBadgeTextColor); + AddSetting("style", "unreadcolor", "rgba(255, 255, 255, 0)"s, &Settings::UnreadIndicatorColor); + +#ifdef _WIN32 + AddSetting("notifications", "enabled", false, &Settings::NotificationsEnabled); + AddSetting("notifications", "playsound", false, &Settings::NotificationsPlaySound); + + AddSetting("windows", "hideconsole", false, &Settings::HideConsole); +#else + AddSetting("notifications", "enabled", true, &Settings::NotificationsEnabled); + AddSetting("notifications", "playsound", true, &Settings::NotificationsPlaySound); #endif -#undef SMBOOL -#undef SMSTR -#undef SMINT -#undef SMFLT +#ifdef WITH_RNNOISE + AddSetting("voice", "vad", "rnnoise"s, &Settings::VAD); +#else + AddSetting("voice", "vad", "gate", &Settings::VAD); +#endif + + HandleReadToken(); +} + +void SettingsManager::ReadSettings() { + for (auto &[k, setting] : m_definitions) { + switch (setting.Type) { + case SettingDefinition::TypeString: + try { + m_settings.*(setting.Ptr.String) = m_file.get_string(setting.Section, setting.Name); + } catch (...) {} + break; + case SettingDefinition::TypeBool: + try { + m_settings.*(setting.Ptr.Bool) = m_file.get_boolean(setting.Section, setting.Name); + } catch (...) {} + break; + case SettingDefinition::TypeDouble: + try { + m_settings.*(setting.Ptr.Double) = m_file.get_double(setting.Section, setting.Name); + } catch (...) {} + break; + case SettingDefinition::TypeInt: + try { + m_settings.*(setting.Ptr.Int) = m_file.get_integer(setting.Section, setting.Name); + } catch (...) {} + break; + } + } m_read_settings = m_settings; } @@ -121,72 +161,39 @@ SettingsManager::Settings &SettingsManager::GetSettings() { void SettingsManager::Close() { 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); -#define SMFLT(section, key, var) \ - if (m_settings.var != m_read_settings.var) \ - m_file.set_double(section, key, m_settings.var); - - SMSTR("discord", "api_base", APIBaseURL); - SMSTR("discord", "gateway", GatewayURL); - SMBOOL("discord", "memory_db", UseMemoryDB); - SMBOOL("discord", "prefetch", Prefetch); - SMBOOL("discord", "autoconnect", Autoconnect); - 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); - SMBOOL("gui", "unreads", Unreads); - SMBOOL("gui", "alt_menu", AltMenu); - SMBOOL("gui", "hide_to_tray", HideToTray); - SMBOOL("gui", "show_deleted_indicator", ShowDeletedIndicator); - SMFLT("gui", "font_scale", FontScale); - SMINT("http", "concurrent", CacheHTTPConcurrency); - SMSTR("http", "user_agent", UserAgent); - SMSTR("style", "expandercolor", ChannelsExpanderColor); - SMSTR("style", "nsfwchannelcolor", NSFWChannelColor); - SMSTR("style", "mentionbadgecolor", MentionBadgeColor); - SMSTR("style", "mentionbadgetextcolor", MentionBadgeTextColor); - SMSTR("style", "unreadcolor", UnreadIndicatorColor); - SMBOOL("notifications", "enabled", NotificationsEnabled); - SMBOOL("notifications", "playsound", NotificationsPlaySound); - SMSTR("voice", "vad", VAD); - SMBOOL("windows", "hideconsole", HideConsole); - -#ifdef WITH_KEYCHAIN - keychain::Error error {}; - - keychain::setPassword(KeychainPackage, KeychainService, KeychainUser, m_settings.DiscordToken, error); - if (error) { - printf("keychain error setting token: %s\n", error.message.c_str()); + for (auto &[k, setting] : m_definitions) { + switch (setting.Type) { + case SettingDefinition::TypeString: + if (m_settings.*(setting.Ptr.String) != m_read_settings.*(setting.Ptr.String)) { + m_file.set_string(setting.Section, setting.Name, m_settings.*(setting.Ptr.String)); + } + break; + case SettingDefinition::TypeBool: + if (m_settings.*(setting.Ptr.Bool) != m_read_settings.*(setting.Ptr.Bool)) { + m_file.set_boolean(setting.Section, setting.Name, m_settings.*(setting.Ptr.Bool)); + } + break; + case SettingDefinition::TypeDouble: + if (m_settings.*(setting.Ptr.Double) != m_read_settings.*(setting.Ptr.Double)) { + m_file.set_double(setting.Section, setting.Name, m_settings.*(setting.Ptr.Double)); + } + break; + case SettingDefinition::TypeInt: + if (m_settings.*(setting.Ptr.Int) != m_read_settings.*(setting.Ptr.Int)) { + m_file.set_integer(setting.Section, setting.Name, m_settings.*(setting.Ptr.Int)); + } + break; + } } -#else - SMSTR("discord", "token", DiscordToken); -#endif -#undef SMSTR -#undef SMBOOL -#undef SMINT -#undef SMFLT + HandleWriteToken(); try { - if (!m_file.save_to_file(m_filename)) - fputs("failed to save settings KeyFile", stderr); + if (!m_file.save_to_file(m_filename)) { + spdlog::get("ui")->error("Failed to save settings KeyFile"); + } } catch (const Glib::Error &e) { - fprintf(stderr, "failed to save settings KeyFile: %s\n", e.what().c_str()); + spdlog::get("ui")->error("Failed to save settings Keyfile: {}", e.what().c_str()); } } -} +} \ No newline at end of file diff --git a/src/settings.hpp b/src/settings.hpp index 42f4838..d8b8caf 100644 --- a/src/settings.hpp +++ b/src/settings.hpp @@ -7,61 +7,47 @@ class SettingsManager { public: 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 APIBaseURL; + std::string GatewayURL; std::string DiscordToken; - bool UseMemoryDB { false }; - bool Prefetch { false }; - bool Autoconnect { false }; + bool UseMemoryDB; + bool Prefetch; + bool Autoconnect; // [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 - bool Unreads { true }; - bool AltMenu { false }; - bool HideToTray { false }; - bool ShowDeletedIndicator { true }; - double FontScale { -1.0 }; + std::string MainCSS; + bool AnimatedGuildHoverOnly; + bool ShowAnimations; + bool ShowCustomEmojis; + bool ShowOwnerCrown; + bool SaveState; + bool ShowStockEmojis; + bool Unreads; + bool AltMenu; + bool HideToTray; + bool ShowDeletedIndicator; + double FontScale; // [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" }; + int CacheHTTPConcurrency; + std::string UserAgent; // [style] - std::string ChannelsExpanderColor { "rgba(255, 83, 112, 0)" }; - std::string NSFWChannelColor { "#970d0d" }; - std::string MentionBadgeColor { "rgba(184, 37, 37, 0)" }; - std::string MentionBadgeTextColor { "rgba(251, 251, 251, 0)" }; - std::string UnreadIndicatorColor { "rgba(255, 255, 255, 0)" }; + std::string ChannelsExpanderColor; + std::string NSFWChannelColor; + std::string MentionBadgeColor; + std::string MentionBadgeTextColor; + std::string UnreadIndicatorColor; // [notifications] -#ifdef _WIN32 - bool NotificationsEnabled { false }; - bool NotificationsPlaySound { false }; -#else - bool NotificationsEnabled { true }; - bool NotificationsPlaySound { true }; -#endif + bool NotificationsEnabled; + bool NotificationsPlaySound; // [voice] -#ifdef WITH_RNNOISE - std::string VAD { "rnnoise" }; -#else - std::string VAD { "gate" }; -#endif + std::string VAD; // [windows] - bool HideConsole { false }; + bool HideConsole; }; SettingsManager(const std::string &filename); @@ -71,8 +57,62 @@ public: Settings &GetSettings(); private: + void HandleReadToken(); + void HandleWriteToken(); + + void DefineSettings(); void ReadSettings(); + // a little weird because i dont want to have to change every line where settings are used + // why this way: i dont want to have to define a setting in multiple places and the old way was ugly + struct SettingDefinition { + using StringPtr = std::string Settings::*; + using BoolPtr = bool Settings::*; + using DoublePtr = double Settings::*; + using IntPtr = int Settings::*; + + std::string Section; + std::string Name; + + enum SettingType { + TypeString, + TypeBool, + TypeDouble, + TypeInt, + } Type; + + union { + StringPtr String; + BoolPtr Bool; + DoublePtr Double; + IntPtr Int; + } Ptr; + }; + + std::unordered_map m_definitions; + + template + void AddSetting(const char *section, const char *name, FieldType default_value, FieldType Settings::*ptr) { + m_settings.*ptr = default_value; + SettingDefinition definition; + definition.Section = section; + definition.Name = name; + if constexpr (std::is_same::value) { + definition.Type = SettingDefinition::TypeString; + definition.Ptr.String = ptr; + } else if constexpr (std::is_same::value) { + definition.Type = SettingDefinition::TypeBool; + definition.Ptr.Bool = ptr; + } else if constexpr (std::is_same::value) { + definition.Type = SettingDefinition::TypeDouble; + definition.Ptr.Double = ptr; + } else if constexpr (std::is_same::value) { + definition.Type = SettingDefinition::TypeInt; + definition.Ptr.Int = ptr; + } + m_definitions[name] = definition; + } + bool m_ok; std::string m_filename; Glib::KeyFile m_file;