forked from OpenGamers/abaddon
rest of view threads window
This commit is contained in:
@@ -249,8 +249,22 @@ std::set<Snowflake> DiscordClient::GetChannelsInGuild(Snowflake id) const {
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<ChannelData> DiscordClient::GetPublicThreads(Snowflake channel_id) const {
|
// there is an endpoint for this but it should be synced before this is called anyways
|
||||||
return m_store.GetThreads(channel_id);
|
std::vector<ChannelData> DiscordClient::GetActiveThreads(Snowflake channel_id) const {
|
||||||
|
return m_store.GetActiveThreads(channel_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DiscordClient::GetArchivedPublicThreads(Snowflake channel_id, sigc::slot<void(DiscordError, const ArchivedThreadsResponseData &)> callback) {
|
||||||
|
m_http.MakeGET("/channels/" + std::to_string(channel_id) + "/threads/archived/public", [this, callback](const http::response_type &r) {
|
||||||
|
if (CheckCode(r)) {
|
||||||
|
const auto data = nlohmann::json::parse(r.text).get<ArchivedThreadsResponseData>();
|
||||||
|
for (const auto &thread : data.Threads)
|
||||||
|
m_store.SetChannel(thread.ID, thread);
|
||||||
|
callback(DiscordError::NONE, data);
|
||||||
|
} else {
|
||||||
|
callback(GetCodeFromResponse(r), {});
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DiscordClient::IsThreadJoined(Snowflake thread_id) const {
|
bool DiscordClient::IsThreadJoined(Snowflake thread_id) const {
|
||||||
|
|||||||
@@ -86,7 +86,8 @@ public:
|
|||||||
std::optional<RoleData> GetMemberHighestRole(Snowflake guild_id, Snowflake user_id) const;
|
std::optional<RoleData> GetMemberHighestRole(Snowflake guild_id, Snowflake user_id) const;
|
||||||
std::set<Snowflake> GetUsersInGuild(Snowflake id) const;
|
std::set<Snowflake> GetUsersInGuild(Snowflake id) const;
|
||||||
std::set<Snowflake> GetChannelsInGuild(Snowflake id) const;
|
std::set<Snowflake> GetChannelsInGuild(Snowflake id) const;
|
||||||
std::vector<ChannelData> GetPublicThreads(Snowflake channel_id) const;
|
std::vector<ChannelData> GetActiveThreads(Snowflake channel_id) const;
|
||||||
|
void GetArchivedPublicThreads(Snowflake channel_id, sigc::slot<void(DiscordError, const ArchivedThreadsResponseData &)> callback);
|
||||||
|
|
||||||
bool IsThreadJoined(Snowflake thread_id) const;
|
bool IsThreadJoined(Snowflake thread_id) const;
|
||||||
bool HasGuildPermission(Snowflake user_id, Snowflake guild_id, Permission perm) const;
|
bool HasGuildPermission(Snowflake user_id, Snowflake guild_id, Permission perm) const;
|
||||||
|
|||||||
@@ -497,3 +497,9 @@ void from_json(const nlohmann::json &j, ThreadMembersUpdateData &m) {
|
|||||||
JS_O("added_members", m.AddedMembers);
|
JS_O("added_members", m.AddedMembers);
|
||||||
JS_O("removed_member_ids", m.RemovedMemberIDs);
|
JS_O("removed_member_ids", m.RemovedMemberIDs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void from_json(const nlohmann::json &j, ArchivedThreadsResponseData &m) {
|
||||||
|
JS_D("threads", m.Threads);
|
||||||
|
JS_D("members", m.Members);
|
||||||
|
JS_D("has_more", m.HasMore);
|
||||||
|
}
|
||||||
|
|||||||
@@ -700,3 +700,11 @@ struct ThreadMembersUpdateData {
|
|||||||
|
|
||||||
friend void from_json(const nlohmann::json &j, ThreadMembersUpdateData &m);
|
friend void from_json(const nlohmann::json &j, ThreadMembersUpdateData &m);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ArchivedThreadsResponseData {
|
||||||
|
std::vector<ChannelData> Threads;
|
||||||
|
std::vector<ThreadMemberObject> Members;
|
||||||
|
bool HasMore;
|
||||||
|
|
||||||
|
friend void from_json(const nlohmann::json &j, ArchivedThreadsResponseData &m);
|
||||||
|
};
|
||||||
|
|||||||
@@ -105,6 +105,16 @@ void Store::SetChannel(Snowflake id, const ChannelData &chan) {
|
|||||||
Bind(m_set_chan_stmt, 17, chan.ParentID);
|
Bind(m_set_chan_stmt, 17, chan.ParentID);
|
||||||
Bind(m_set_chan_stmt, 18, chan.LastPinTimestamp);
|
Bind(m_set_chan_stmt, 18, chan.LastPinTimestamp);
|
||||||
|
|
||||||
|
if (chan.ThreadMetadata.has_value()) {
|
||||||
|
Bind(m_set_chan_stmt, 19, chan.ThreadMetadata->IsArchived);
|
||||||
|
Bind(m_set_chan_stmt, 20, chan.ThreadMetadata->AutoArchiveDuration);
|
||||||
|
Bind(m_set_chan_stmt, 21, chan.ThreadMetadata->ArchiveTimestamp);
|
||||||
|
} else {
|
||||||
|
Bind(m_set_chan_stmt, 19, nullptr);
|
||||||
|
Bind(m_set_chan_stmt, 20, nullptr);
|
||||||
|
Bind(m_set_chan_stmt, 21, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
if (!RunInsert(m_set_chan_stmt))
|
if (!RunInsert(m_set_chan_stmt))
|
||||||
fprintf(stderr, "channel insert failed: %s\n", sqlite3_errstr(m_db_err));
|
fprintf(stderr, "channel insert failed: %s\n", sqlite3_errstr(m_db_err));
|
||||||
|
|
||||||
@@ -499,7 +509,7 @@ std::vector<Message> Store::GetPinnedMessages(Snowflake channel_id) const {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<ChannelData> Store::GetThreads(Snowflake channel_id) const {
|
std::vector<ChannelData> Store::GetActiveThreads(Snowflake channel_id) const {
|
||||||
std::vector<ChannelData> ret;
|
std::vector<ChannelData> ret;
|
||||||
|
|
||||||
Bind(m_get_threads_stmt, 1, channel_id);
|
Bind(m_get_threads_stmt, 1, channel_id);
|
||||||
@@ -552,6 +562,12 @@ std::optional<ChannelData> Store::GetChannel(Snowflake id) const {
|
|||||||
Get(m_get_chan_stmt, 15, ret.ApplicationID);
|
Get(m_get_chan_stmt, 15, ret.ApplicationID);
|
||||||
Get(m_get_chan_stmt, 16, ret.ParentID);
|
Get(m_get_chan_stmt, 16, ret.ParentID);
|
||||||
Get(m_get_chan_stmt, 17, ret.LastPinTimestamp);
|
Get(m_get_chan_stmt, 17, ret.LastPinTimestamp);
|
||||||
|
if (!IsNull(m_get_chan_stmt, 18)) {
|
||||||
|
ret.ThreadMetadata.emplace();
|
||||||
|
Get(m_get_chan_stmt, 18, ret.ThreadMetadata->IsArchived);
|
||||||
|
Get(m_get_chan_stmt, 19, ret.ThreadMetadata->AutoArchiveDuration);
|
||||||
|
Get(m_get_chan_stmt, 20, ret.ThreadMetadata->ArchiveTimestamp);
|
||||||
|
}
|
||||||
|
|
||||||
Reset(m_get_chan_stmt);
|
Reset(m_get_chan_stmt);
|
||||||
|
|
||||||
@@ -987,7 +1003,10 @@ bool Store::CreateTables() {
|
|||||||
owner_id INTEGER,
|
owner_id INTEGER,
|
||||||
application_id INTEGER,
|
application_id INTEGER,
|
||||||
parent_id INTEGER,
|
parent_id INTEGER,
|
||||||
last_pin_timestamp TEXT
|
last_pin_timestamp TEXT,
|
||||||
|
archived BOOL, /* threads */
|
||||||
|
auto_archive INTEGER, /* threads */
|
||||||
|
archived_ts TEXT /* threads */
|
||||||
)
|
)
|
||||||
)";
|
)";
|
||||||
|
|
||||||
@@ -1156,7 +1175,7 @@ bool Store::CreateStatements() {
|
|||||||
|
|
||||||
const char *set_chan = R"(
|
const char *set_chan = R"(
|
||||||
REPLACE INTO channels VALUES (
|
REPLACE INTO channels VALUES (
|
||||||
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
|
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
|
||||||
)
|
)
|
||||||
)";
|
)";
|
||||||
|
|
||||||
@@ -1206,7 +1225,7 @@ bool Store::CreateStatements() {
|
|||||||
)";
|
)";
|
||||||
|
|
||||||
const char *get_threads = R"(
|
const char *get_threads = R"(
|
||||||
SELECT id FROM channels WHERE parent_id = ? AND type = 11
|
SELECT id FROM channels WHERE parent_id = ? AND (type = 10 OR type = 11 OR type = 12) AND archived = FALSE
|
||||||
)";
|
)";
|
||||||
|
|
||||||
m_db_err = sqlite3_prepare_v2(m_db, set_user, -1, &m_set_user_stmt, nullptr);
|
m_db_err = sqlite3_prepare_v2(m_db, set_user, -1, &m_set_user_stmt, nullptr);
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ public:
|
|||||||
std::vector<Message> GetLastMessages(Snowflake id, size_t num) const;
|
std::vector<Message> GetLastMessages(Snowflake id, size_t num) const;
|
||||||
std::vector<Snowflake> GetChannelMessageIDs(Snowflake id) const;
|
std::vector<Snowflake> GetChannelMessageIDs(Snowflake id) const;
|
||||||
std::vector<Message> GetPinnedMessages(Snowflake channel_id) const;
|
std::vector<Message> GetPinnedMessages(Snowflake channel_id) const;
|
||||||
std::vector<ChannelData> GetThreads(Snowflake channel_id) const; // public
|
std::vector<ChannelData> GetActiveThreads(Snowflake channel_id) const; // public
|
||||||
|
|
||||||
void ClearGuild(Snowflake id);
|
void ClearGuild(Snowflake id);
|
||||||
void ClearChannel(Snowflake id);
|
void ClearChannel(Snowflake id);
|
||||||
|
|||||||
107
windows/threadswindow.cpp
Normal file
107
windows/threadswindow.cpp
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
#include "threadswindow.hpp"
|
||||||
|
#include "../abaddon.hpp"
|
||||||
|
|
||||||
|
ThreadsWindow::ThreadsWindow(const ChannelData &channel)
|
||||||
|
: m_channel_id(channel.ID)
|
||||||
|
, m_box(Gtk::ORIENTATION_VERTICAL)
|
||||||
|
, m_active(channel)
|
||||||
|
, m_archived(channel) {
|
||||||
|
set_name("threads-window");
|
||||||
|
set_default_size(450, 375);
|
||||||
|
set_title("#" + *channel.Name + " - Threads");
|
||||||
|
set_position(Gtk::WIN_POS_CENTER);
|
||||||
|
get_style_context()->add_class("app-window");
|
||||||
|
get_style_context()->add_class("app-popup");
|
||||||
|
get_style_context()->add_class("threads-window");
|
||||||
|
|
||||||
|
const auto cb = [this](Snowflake id) {
|
||||||
|
Abaddon::Get().ActionChannelOpened(id);
|
||||||
|
hide();
|
||||||
|
};
|
||||||
|
m_active.signal_thread_open().connect(cb);
|
||||||
|
m_archived.signal_thread_open().connect(cb);
|
||||||
|
|
||||||
|
m_switcher.set_halign(Gtk::ALIGN_CENTER);
|
||||||
|
m_switcher.set_stack(m_stack);
|
||||||
|
|
||||||
|
m_stack.add(m_active, "active", "Active Threads");
|
||||||
|
m_stack.add(m_archived, "archived", "Archived Threads");
|
||||||
|
|
||||||
|
m_active.show();
|
||||||
|
m_archived.show();
|
||||||
|
m_switcher.show();
|
||||||
|
m_stack.show();
|
||||||
|
m_box.show();
|
||||||
|
|
||||||
|
m_box.add(m_switcher);
|
||||||
|
m_box.add(m_stack);
|
||||||
|
add(m_box);
|
||||||
|
}
|
||||||
|
|
||||||
|
ThreadListRow::ThreadListRow(const ChannelData &channel)
|
||||||
|
: ID(channel.ID)
|
||||||
|
, m_label(*channel.Name, Gtk::ALIGN_START) {
|
||||||
|
m_label.show();
|
||||||
|
add(m_label);
|
||||||
|
}
|
||||||
|
|
||||||
|
ActiveThreadsList::ActiveThreadsList(const ChannelData &channel) {
|
||||||
|
set_vexpand(true);
|
||||||
|
|
||||||
|
m_list.set_selection_mode(Gtk::SELECTION_SINGLE);
|
||||||
|
m_list.set_hexpand(true);
|
||||||
|
m_list.show();
|
||||||
|
|
||||||
|
add(m_list);
|
||||||
|
|
||||||
|
m_list.signal_button_press_event().connect([this](GdkEventButton *ev) -> bool {
|
||||||
|
if (ev->button == GDK_BUTTON_PRIMARY && ev->type == GDK_2BUTTON_PRESS) {
|
||||||
|
if (auto row = dynamic_cast<ThreadListRow *>(m_list.get_selected_row()))
|
||||||
|
m_signal_thread_open.emit(row->ID);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
const auto threads = Abaddon::Get().GetDiscordClient().GetActiveThreads(channel.ID);
|
||||||
|
for (const auto &thread : threads) {
|
||||||
|
auto row = Gtk::manage(new ThreadListRow(thread));
|
||||||
|
row->show();
|
||||||
|
m_list.add(*row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ActiveThreadsList::type_signal_thread_open ActiveThreadsList::signal_thread_open() {
|
||||||
|
return m_signal_thread_open;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArchivedThreadsList::ArchivedThreadsList(const ChannelData &channel) {
|
||||||
|
set_vexpand(true);
|
||||||
|
|
||||||
|
m_list.set_selection_mode(Gtk::SELECTION_SINGLE);
|
||||||
|
m_list.set_hexpand(true);
|
||||||
|
m_list.show();
|
||||||
|
|
||||||
|
add(m_list);
|
||||||
|
|
||||||
|
m_list.signal_button_press_event().connect([this](GdkEventButton *ev) -> bool {
|
||||||
|
if (ev->button == GDK_BUTTON_PRIMARY && ev->type == GDK_2BUTTON_PRESS) {
|
||||||
|
if (auto row = dynamic_cast<ThreadListRow *>(m_list.get_selected_row()))
|
||||||
|
m_signal_thread_open.emit(row->ID);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
Abaddon::Get().GetDiscordClient().GetArchivedPublicThreads(channel.ID, sigc::mem_fun(*this, &ArchivedThreadsList::OnPublicFetched));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ArchivedThreadsList::OnPublicFetched(DiscordError code, const ArchivedThreadsResponseData &data) {
|
||||||
|
for (const auto &thread : data.Threads) {
|
||||||
|
auto row = Gtk::manage(new ThreadListRow(thread));
|
||||||
|
row->show();
|
||||||
|
m_list.add(*row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ArchivedThreadsList::type_signal_thread_open ArchivedThreadsList::signal_thread_open() {
|
||||||
|
return m_signal_thread_open;
|
||||||
|
}
|
||||||
60
windows/threadswindow.hpp
Normal file
60
windows/threadswindow.hpp
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <gtkmm.h>
|
||||||
|
#include "../discord/objects.hpp"
|
||||||
|
|
||||||
|
class ActiveThreadsList : public Gtk::ScrolledWindow {
|
||||||
|
public:
|
||||||
|
ActiveThreadsList(const ChannelData &channel);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Gtk::ListBox m_list;
|
||||||
|
|
||||||
|
using type_signal_thread_open = sigc::signal<void, Snowflake>;
|
||||||
|
type_signal_thread_open m_signal_thread_open;
|
||||||
|
|
||||||
|
public:
|
||||||
|
type_signal_thread_open signal_thread_open();
|
||||||
|
};
|
||||||
|
|
||||||
|
class ArchivedThreadsList : public Gtk::ScrolledWindow {
|
||||||
|
public:
|
||||||
|
ArchivedThreadsList(const ChannelData &channel);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Gtk::ListBox m_list;
|
||||||
|
|
||||||
|
void OnPublicFetched(DiscordError code, const ArchivedThreadsResponseData &data);
|
||||||
|
|
||||||
|
using type_signal_thread_open = sigc::signal<void, Snowflake>;
|
||||||
|
type_signal_thread_open m_signal_thread_open;
|
||||||
|
|
||||||
|
public:
|
||||||
|
type_signal_thread_open signal_thread_open();
|
||||||
|
};
|
||||||
|
|
||||||
|
// view all threads in a channel
|
||||||
|
class ThreadsWindow : public Gtk::Window {
|
||||||
|
public:
|
||||||
|
ThreadsWindow(const ChannelData &channel);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Snowflake m_channel_id;
|
||||||
|
|
||||||
|
Gtk::StackSwitcher m_switcher;
|
||||||
|
Gtk::Stack m_stack;
|
||||||
|
|
||||||
|
Gtk::Box m_box;
|
||||||
|
|
||||||
|
ActiveThreadsList m_active;
|
||||||
|
ArchivedThreadsList m_archived;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ThreadListRow : public Gtk::ListBoxRow {
|
||||||
|
public:
|
||||||
|
ThreadListRow(const ChannelData &channel);
|
||||||
|
|
||||||
|
Snowflake ID;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Gtk::Label m_label;
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user