mirror of
https://github.com/celisej567/abaddon.git
synced 2026-09-13 20:18:50 +03:00
preserve channel list expansion and active channel (#36)
also check getenv in platform
This commit is contained in:
53
abaddon.cpp
53
abaddon.cpp
@@ -56,7 +56,7 @@ Abaddon::Abaddon()
|
||||
|
||||
Abaddon::~Abaddon() {
|
||||
m_settings.Close();
|
||||
m_discord.Stop();
|
||||
StopDiscord();
|
||||
}
|
||||
|
||||
Abaddon &Abaddon::Get() {
|
||||
@@ -113,9 +113,7 @@ int Abaddon::StartGTK() {
|
||||
|
||||
ActionReloadCSS();
|
||||
|
||||
m_gtk_app->signal_shutdown().connect([&]() {
|
||||
StopDiscord();
|
||||
});
|
||||
m_gtk_app->signal_shutdown().connect(sigc::mem_fun(*this, &Abaddon::StopDiscord), false);
|
||||
|
||||
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);
|
||||
@@ -154,6 +152,7 @@ void Abaddon::StartDiscord() {
|
||||
|
||||
void Abaddon::StopDiscord() {
|
||||
m_discord.Stop();
|
||||
SaveState();
|
||||
}
|
||||
|
||||
bool Abaddon::IsDiscordActive() const {
|
||||
@@ -176,6 +175,7 @@ const DiscordClient &Abaddon::GetDiscordClient() const {
|
||||
|
||||
void Abaddon::DiscordOnReady() {
|
||||
m_main_window->UpdateComponents();
|
||||
LoadState();
|
||||
}
|
||||
|
||||
void Abaddon::DiscordOnMessageCreate(const Message &message) {
|
||||
@@ -365,6 +365,40 @@ void Abaddon::SetupUserMenu() {
|
||||
m_user_menu->show_all();
|
||||
}
|
||||
|
||||
void Abaddon::SaveState() {
|
||||
if (!m_settings.GetSaveState()) 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 (!m_settings.GetSaveState()) 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 +456,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 +469,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();
|
||||
@@ -461,7 +504,7 @@ 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("");
|
||||
|
||||
|
||||
@@ -84,13 +84,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;
|
||||
|
||||
@@ -380,6 +380,56 @@ void ChannelList::SetActiveChannel(Snowflake id) {
|
||||
}
|
||||
}
|
||||
|
||||
void ChannelList::UseExpansionState(const ExpansionStateRoot &root) {
|
||||
auto recurse = [this](auto &self, const ExpansionStateRoot &root) -> void {
|
||||
// and these are only channels
|
||||
for (const auto &[id, state] : root.Children) {
|
||||
if (const auto iter = GetIteratorForChannelFromID(id)) {
|
||||
if (state.IsExpanded)
|
||||
m_view.expand_row(m_model->get_path(iter), false);
|
||||
else
|
||||
m_view.collapse_row(m_model->get_path(iter));
|
||||
}
|
||||
|
||||
self(self, state.Children);
|
||||
}
|
||||
};
|
||||
|
||||
// top level is guild
|
||||
for (const auto &[id, state] : root.Children) {
|
||||
if (const auto iter = GetIteratorForGuildFromID(id)) {
|
||||
if (state.IsExpanded)
|
||||
m_view.expand_row(m_model->get_path(iter), false);
|
||||
else
|
||||
m_view.collapse_row(m_model->get_path(iter));
|
||||
}
|
||||
|
||||
recurse(recurse, state.Children);
|
||||
}
|
||||
}
|
||||
|
||||
ExpansionStateRoot ChannelList::GetExpansionState() const {
|
||||
ExpansionStateRoot r;
|
||||
|
||||
auto recurse = [this](auto &self, const Gtk::TreeRow &row) -> ExpansionState {
|
||||
ExpansionState r;
|
||||
|
||||
r.IsExpanded = row[m_columns.m_expanded];
|
||||
for (const auto &child : row.children())
|
||||
r.Children.Children[static_cast<Snowflake>(child[m_columns.m_id])] = self(self, child);
|
||||
|
||||
return r;
|
||||
};
|
||||
|
||||
for (const auto &child : m_model->children()) {
|
||||
const auto id = static_cast<Snowflake>(child[m_columns.m_id]);
|
||||
if (static_cast<uint64_t>(id) == 0ULL) continue; // dont save DM header
|
||||
r.Children[id] = recurse(recurse, child);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
Gtk::TreeModel::iterator ChannelList::AddGuild(const GuildData &guild) {
|
||||
auto &discord = Abaddon::Get().GetDiscordClient();
|
||||
auto &img = Abaddon::Get().GetImageManager();
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
#include <unordered_set>
|
||||
#include <unordered_map>
|
||||
#include <sigc++/sigc++.h>
|
||||
#include "../discord/discord.hpp"
|
||||
#include "discord/discord.hpp"
|
||||
#include "state.hpp"
|
||||
|
||||
constexpr static int GuildIconSize = 24;
|
||||
constexpr static int DMIconSize = 20;
|
||||
@@ -134,6 +135,10 @@ public:
|
||||
void UpdateListing();
|
||||
void SetActiveChannel(Snowflake id);
|
||||
|
||||
// channel list should be populated when this is called
|
||||
void UseExpansionState(const ExpansionStateRoot &state);
|
||||
ExpansionStateRoot GetExpansionState() const;
|
||||
|
||||
protected:
|
||||
void UpdateNewGuild(const GuildData &guild);
|
||||
void UpdateRemoveGuild(Snowflake id);
|
||||
|
||||
63
platform.cpp
63
platform.cpp
@@ -1,4 +1,5 @@
|
||||
#include "platform.hpp"
|
||||
#include "util.hpp"
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <filesystem>
|
||||
@@ -6,20 +7,6 @@
|
||||
|
||||
using namespace std::literals::string_literals;
|
||||
|
||||
bool IsFolder(std::string_view path) {
|
||||
std::error_code ec;
|
||||
const auto status = std::filesystem::status(path, ec);
|
||||
if (ec) return false;
|
||||
return status.type() == std::filesystem::file_type::directory;
|
||||
}
|
||||
|
||||
bool IsFile(std::string_view path) {
|
||||
std::error_code ec;
|
||||
const auto status = std::filesystem::status(path, ec);
|
||||
if (ec) return false;
|
||||
return status.type() == std::filesystem::file_type::regular;
|
||||
}
|
||||
|
||||
#if defined(_WIN32) && defined(_MSC_VER)
|
||||
#include <Windows.h>
|
||||
#include <Shlwapi.h>
|
||||
@@ -90,19 +77,26 @@ std::string Platform::FindConfigFile() {
|
||||
return "./abaddon.ini";
|
||||
}
|
||||
|
||||
std::string Platform::FindStateCacheFolder() {
|
||||
return ".";
|
||||
}
|
||||
|
||||
#elif defined(__linux__)
|
||||
std::string Platform::FindResourceFolder() {
|
||||
static std::string found_path;
|
||||
static bool found = false;
|
||||
if (found) return found_path;
|
||||
|
||||
const static std::string home_path = std::getenv("HOME") + "/.local/share/abaddon"s;
|
||||
const auto home_env = std::getenv("HOME");
|
||||
if (home_env != nullptr) {
|
||||
const static std::string home_path = home_env + "/.local/share/abaddon"s;
|
||||
|
||||
for (const auto &path : { "."s, home_path, std::string(ABADDON_DEFAULT_RESOURCE_DIR) }) {
|
||||
if (IsFolder(path + "/res") && IsFolder(path + "/css")) {
|
||||
found_path = path;
|
||||
found = true;
|
||||
return found_path;
|
||||
for (const auto &path : { "."s, home_path, std::string(ABADDON_DEFAULT_RESOURCE_DIR) }) {
|
||||
if (util::IsFolder(path + "/res") && util::IsFolder(path + "/css")) {
|
||||
found_path = path;
|
||||
found = true;
|
||||
return found_path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,13 +111,31 @@ std::string Platform::FindConfigFile() {
|
||||
if (x != nullptr)
|
||||
return x;
|
||||
|
||||
const auto home_path = std::string(std::getenv("HOME")) + "/.config/abaddon/abaddon.ini";
|
||||
for (const auto path : { "./abaddon.ini"s, home_path }) {
|
||||
if (IsFile(path)) return path;
|
||||
const auto home_env = std::getenv("HOME");
|
||||
if (home_env != nullptr) {
|
||||
const auto home_path = home_env + "/.config/abaddon/abaddon.ini"s;
|
||||
for (auto path : { "./abaddon.ini"s, home_path }) {
|
||||
if (util::IsFile(path)) return path;
|
||||
}
|
||||
}
|
||||
puts("can't find configuration file!");
|
||||
return "./abaddon.ini";
|
||||
}
|
||||
|
||||
std::string Platform::FindStateCacheFolder() {
|
||||
const auto home_env = std::getenv("HOME");
|
||||
if (home_env != nullptr) {
|
||||
auto home_path = home_env + "/.cache/abaddon"s;
|
||||
std::error_code ec;
|
||||
if (!util::IsFolder(home_path))
|
||||
std::filesystem::create_directories(home_path, ec);
|
||||
if (util::IsFolder(home_path))
|
||||
return home_path;
|
||||
}
|
||||
puts("can't find cache folder!");
|
||||
return ".";
|
||||
}
|
||||
|
||||
#else
|
||||
std::string Platform::FindResourceFolder() {
|
||||
puts("unknown OS, trying to load resources from cwd");
|
||||
@@ -137,4 +149,9 @@ std::string Platform::FindConfigFile() {
|
||||
puts("unknown OS, trying to load config from cwd");
|
||||
return "./abaddon.ini";
|
||||
}
|
||||
|
||||
std::string Platform::FindStateCacheFolder() {
|
||||
puts("unknown OS, setting state cache folder to cwd");
|
||||
return ".";
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -5,4 +5,5 @@ namespace Platform {
|
||||
bool SetupFonts();
|
||||
std::string FindResourceFolder();
|
||||
std::string FindConfigFile();
|
||||
std::string FindStateCacheFolder();
|
||||
}
|
||||
|
||||
@@ -109,3 +109,7 @@ std::string SettingsManager::GetAPIBaseURL() const {
|
||||
bool SettingsManager::GetAnimatedGuildHoverOnly() const {
|
||||
return GetSettingBool("gui", "animated_guild_hover_only", true);
|
||||
}
|
||||
|
||||
bool SettingsManager::GetSaveState() const {
|
||||
return GetSettingBool("gui", "save_state", true);
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ public:
|
||||
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
|
||||
|
||||
15
util.cpp
15
util.cpp
@@ -1,4 +1,5 @@
|
||||
#include "util.hpp"
|
||||
#include <filesystem>
|
||||
|
||||
Semaphore::Semaphore(int count)
|
||||
: m_count(count) {}
|
||||
@@ -200,3 +201,17 @@ void AddPointerCursor(Gtk::Widget &widget) {
|
||||
window->set_cursor(cursor);
|
||||
});
|
||||
}
|
||||
|
||||
bool util::IsFolder(std::string_view path) {
|
||||
std::error_code ec;
|
||||
const auto status = std::filesystem::status(path, ec);
|
||||
if (ec) return false;
|
||||
return status.type() == std::filesystem::file_type::directory;
|
||||
}
|
||||
|
||||
bool util::IsFile(std::string_view path) {
|
||||
std::error_code ec;
|
||||
const auto status = std::filesystem::status(path, ec);
|
||||
if (ec) return false;
|
||||
return status.type() == std::filesystem::file_type::regular;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user