Refactor app modules and add clang-format
This commit is contained in:
@@ -2,15 +2,19 @@
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <curses.h>
|
||||
|
||||
#include "app_ui.h"
|
||||
#include "util.h"
|
||||
|
||||
namespace telegram_tui {
|
||||
|
||||
namespace {
|
||||
|
||||
std::string join_with_separator_local(const std::vector<std::string>& parts, const char* separator) {
|
||||
std::string join_with_separator_local(const std::vector<std::string> &parts,
|
||||
const char *separator) {
|
||||
std::string joined;
|
||||
for (const auto& part : parts) {
|
||||
for (const auto &part : parts) {
|
||||
if (part.empty()) {
|
||||
continue;
|
||||
}
|
||||
@@ -22,7 +26,7 @@ std::string join_with_separator_local(const std::vector<std::string>& parts, con
|
||||
return joined;
|
||||
}
|
||||
|
||||
std::string format_user_status(const json& status) {
|
||||
std::string format_user_status(const json &status) {
|
||||
const std::string type = safe_string(status, "@type");
|
||||
if (type == "userStatusOnline") {
|
||||
return "online";
|
||||
@@ -43,11 +47,11 @@ std::string format_user_status(const json& status) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string primary_username(const json& object) {
|
||||
std::string primary_username(const json &object) {
|
||||
const json usernames = object.value("usernames", json::object());
|
||||
const json active_usernames = usernames.value("active_usernames", json::array());
|
||||
if (active_usernames.is_array()) {
|
||||
for (const auto& username : active_usernames) {
|
||||
for (const auto &username : active_usernames) {
|
||||
if (username.is_string()) {
|
||||
const std::string value = username.get<std::string>();
|
||||
if (!value.empty()) {
|
||||
@@ -59,19 +63,19 @@ std::string primary_username(const json& object) {
|
||||
return safe_string(object, "username");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
void App::update_user_status(std::int64_t user_id, const json& status) {
|
||||
UserInfo& info = users_[user_id];
|
||||
void App::update_user_status(std::int64_t user_id, const json &status) {
|
||||
UserInfo &info = users_[user_id];
|
||||
info.id = user_id;
|
||||
info.status = format_user_status(status);
|
||||
}
|
||||
|
||||
void App::upsert_user(const json& user) {
|
||||
void App::upsert_user(const json &user) {
|
||||
if (user.is_null()) {
|
||||
return;
|
||||
}
|
||||
UserInfo& info = users_[safe_i64(user, "id")];
|
||||
UserInfo &info = users_[safe_i64(user, "id")];
|
||||
info.id = safe_i64(user, "id");
|
||||
info.first_name = safe_string(user, "first_name");
|
||||
info.last_name = safe_string(user, "last_name");
|
||||
@@ -79,13 +83,13 @@ void App::upsert_user(const json& user) {
|
||||
info.status = format_user_status(user.value("status", json::object()));
|
||||
}
|
||||
|
||||
void App::upsert_basic_group(const json& basic_group) {
|
||||
void App::upsert_basic_group(const json &basic_group) {
|
||||
if (basic_group.is_null()) {
|
||||
return;
|
||||
}
|
||||
const std::int64_t basic_group_id = safe_i64(basic_group, "id");
|
||||
const std::int32_t member_count = safe_i32(basic_group, "member_count");
|
||||
for (auto& [chat_id, chat] : chats_) {
|
||||
for (auto &[chat_id, chat] : chats_) {
|
||||
if (chat.basic_group_id != basic_group_id) {
|
||||
continue;
|
||||
}
|
||||
@@ -96,7 +100,7 @@ void App::upsert_basic_group(const json& basic_group) {
|
||||
}
|
||||
}
|
||||
|
||||
void App::upsert_supergroup(const json& supergroup) {
|
||||
void App::upsert_supergroup(const json &supergroup) {
|
||||
if (supergroup.is_null()) {
|
||||
return;
|
||||
}
|
||||
@@ -104,7 +108,7 @@ void App::upsert_supergroup(const json& supergroup) {
|
||||
const std::int32_t member_count = safe_i32(supergroup, "member_count");
|
||||
const bool is_channel = supergroup.value("is_channel", false);
|
||||
const std::string username = primary_username(supergroup);
|
||||
for (auto& [chat_id, chat] : chats_) {
|
||||
for (auto &[chat_id, chat] : chats_) {
|
||||
if (chat.supergroup_id != supergroup_id) {
|
||||
continue;
|
||||
}
|
||||
@@ -116,13 +120,13 @@ void App::upsert_supergroup(const json& supergroup) {
|
||||
}
|
||||
}
|
||||
|
||||
void App::upsert_chat(const json& chat_object) {
|
||||
void App::upsert_chat(const json &chat_object) {
|
||||
if (chat_object.is_null()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const std::int64_t chat_id = safe_i64(chat_object, "id");
|
||||
ChatInfo& chat = chats_[chat_id];
|
||||
ChatInfo &chat = chats_[chat_id];
|
||||
chat.id = chat_id;
|
||||
if (chat_object.contains("title")) {
|
||||
chat.title = safe_string(chat_object, "title");
|
||||
@@ -156,8 +160,8 @@ void App::upsert_chat(const json& chat_object) {
|
||||
chat.username.clear();
|
||||
}
|
||||
if (chat.private_user_id != previous_private_user_id ||
|
||||
chat.basic_group_id != previous_basic_group_id ||
|
||||
chat.supergroup_id != previous_supergroup_id) {
|
||||
chat.basic_group_id != previous_basic_group_id ||
|
||||
chat.supergroup_id != previous_supergroup_id) {
|
||||
chat.details_requested = false;
|
||||
}
|
||||
chat.unread_count = safe_i32(chat_object, "unread_count");
|
||||
@@ -169,7 +173,7 @@ void App::upsert_chat(const json& chat_object) {
|
||||
if (chat_object.contains("positions") && chat_object.at("positions").is_array()) {
|
||||
chat.in_main_list = false;
|
||||
chat.main_order = 0;
|
||||
for (const auto& position : chat_object.at("positions")) {
|
||||
for (const auto &position : chat_object.at("positions")) {
|
||||
apply_chat_position(chat, position);
|
||||
}
|
||||
}
|
||||
@@ -179,7 +183,7 @@ void App::upsert_chat(const json& chat_object) {
|
||||
resort_chats();
|
||||
}
|
||||
|
||||
void App::apply_chat_position(ChatInfo& chat, const json& position) {
|
||||
void App::apply_chat_position(ChatInfo &chat, const json &position) {
|
||||
if (!position.is_object()) {
|
||||
return;
|
||||
}
|
||||
@@ -194,43 +198,58 @@ void App::apply_chat_position(ChatInfo& chat, const json& position) {
|
||||
|
||||
void App::resort_chats() {
|
||||
if (sorted_chat_ids_.empty()) {
|
||||
for (const auto& [chat_id, chat] : chats_) {
|
||||
for (const auto &[chat_id, chat] : chats_) {
|
||||
if (chat.in_main_list) {
|
||||
sorted_chat_ids_.push_back(chat_id);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (const auto& [chat_id, chat] : chats_) {
|
||||
for (const auto &[chat_id, chat] : chats_) {
|
||||
if (!chat.in_main_list) {
|
||||
continue;
|
||||
}
|
||||
if (std::find(sorted_chat_ids_.begin(), sorted_chat_ids_.end(), chat_id) == sorted_chat_ids_.end()) {
|
||||
if (std::find(sorted_chat_ids_.begin(), sorted_chat_ids_.end(), chat_id) ==
|
||||
sorted_chat_ids_.end()) {
|
||||
sorted_chat_ids_.push_back(chat_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::stable_sort(sorted_chat_ids_.begin(), sorted_chat_ids_.end(),
|
||||
[&](std::int64_t lhs, std::int64_t rhs) {
|
||||
const auto left_it = chats_.find(lhs);
|
||||
const auto right_it = chats_.find(rhs);
|
||||
const bool left_has_order = left_it != chats_.end() && left_it->second.in_main_list && left_it->second.main_order > 0;
|
||||
const bool right_has_order = right_it != chats_.end() && right_it->second.in_main_list && right_it->second.main_order > 0;
|
||||
if (left_has_order != right_has_order) {
|
||||
return left_has_order;
|
||||
}
|
||||
if (left_has_order && right_has_order && left_it->second.main_order != right_it->second.main_order) {
|
||||
return left_it->second.main_order > right_it->second.main_order;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
[&](std::int64_t lhs, std::int64_t rhs) {
|
||||
const auto left_it = chats_.find(lhs);
|
||||
const auto right_it = chats_.find(rhs);
|
||||
const bool left_has_order = left_it != chats_.end() &&
|
||||
left_it->second.in_main_list &&
|
||||
left_it->second.main_order > 0;
|
||||
const bool right_has_order = right_it != chats_.end() &&
|
||||
right_it->second.in_main_list &&
|
||||
right_it->second.main_order > 0;
|
||||
if (left_has_order != right_has_order) {
|
||||
return left_has_order;
|
||||
}
|
||||
if (left_has_order && right_has_order &&
|
||||
left_it->second.main_order != right_it->second.main_order) {
|
||||
return left_it->second.main_order >
|
||||
right_it->second.main_order;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
if (selected_chat_index_ >= static_cast<int>(sorted_chat_ids_.size())) {
|
||||
selected_chat_index_ = std::max(0, static_cast<int>(sorted_chat_ids_.size()) - 1);
|
||||
}
|
||||
}
|
||||
|
||||
std::string App::format_open_chat_header(const ChatInfo& chat) const {
|
||||
std::string App::user_status_label(std::int64_t user_id) const {
|
||||
const auto user_it = users_.find(user_id);
|
||||
if (user_it == users_.end()) {
|
||||
return {};
|
||||
}
|
||||
return user_it->second.status;
|
||||
}
|
||||
|
||||
std::string App::format_open_chat_header(const ChatInfo &chat) const {
|
||||
std::vector<std::string> parts;
|
||||
if (!chat.title.empty()) {
|
||||
parts.push_back(chat.title);
|
||||
@@ -256,8 +275,8 @@ std::string App::format_open_chat_header(const ChatInfo& chat) const {
|
||||
parts.push_back("@" + chat.username);
|
||||
}
|
||||
if (chat.has_member_count) {
|
||||
parts.push_back(
|
||||
std::to_string(chat.member_count) + " " + (chat.is_channel ? "subscribers" : "members"));
|
||||
parts.push_back(std::to_string(chat.member_count) + " " +
|
||||
(chat.is_channel ? "subscribers" : "members"));
|
||||
}
|
||||
if (!chat.is_channel && chat.has_online_member_count) {
|
||||
parts.push_back(std::to_string(chat.online_member_count) + " online");
|
||||
@@ -266,4 +285,60 @@ std::string App::format_open_chat_header(const ChatInfo& chat) const {
|
||||
return join_with_separator_local(parts, " | ");
|
||||
}
|
||||
|
||||
} // namespace telegram_tui
|
||||
void App::draw_chat_pane(int top, int height, int width) {
|
||||
const int visible_rows = std::max(1, height);
|
||||
int first_index = 0;
|
||||
if (selected_chat_index_ >= visible_rows) {
|
||||
first_index = selected_chat_index_ - visible_rows + 1;
|
||||
}
|
||||
|
||||
for (int row = 0; row < visible_rows; ++row) {
|
||||
const int index = first_index + row;
|
||||
const int y = top + row;
|
||||
mvhline(y, 0, ' ', width);
|
||||
if (index >= static_cast<int>(sorted_chat_ids_.size())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto chat_id = sorted_chat_ids_[index];
|
||||
const auto chat_it = chats_.find(chat_id);
|
||||
const bool selected = index == selected_chat_index_;
|
||||
const bool is_open = open_chat_id_ == chat_id;
|
||||
if (selected) {
|
||||
attron(A_BOLD | (focus_ == FocusPane::Chats ? A_REVERSE : A_NORMAL));
|
||||
}
|
||||
if (is_open) {
|
||||
attron(COLOR_PAIR(kColorPairOpenChat));
|
||||
}
|
||||
|
||||
const bool has_chat = chat_it != chats_.end();
|
||||
const ChatInfo *chat = has_chat ? &chat_it->second : nullptr;
|
||||
std::string line = (chat != nullptr && chat->unread_count > 0) ? "[U] " : "[ ] ";
|
||||
line += is_open ? ">" : " ";
|
||||
if (chat != nullptr) {
|
||||
line += chat->title;
|
||||
} else {
|
||||
line += "Chat " + std::to_string(chat_id);
|
||||
}
|
||||
if (chat != nullptr && chat->unread_count > 0) {
|
||||
line += " [" + std::to_string(chat->unread_count) + "]";
|
||||
}
|
||||
if (chat != nullptr && !chat->last_message_preview.empty()) {
|
||||
line += " - " + chat->last_message_preview;
|
||||
}
|
||||
if (static_cast<int>(line.size()) > width - 2) {
|
||||
line.resize(static_cast<std::size_t>(width - 5));
|
||||
line += "...";
|
||||
}
|
||||
mvprintw(y, 1, "%s", line.c_str());
|
||||
|
||||
if (is_open) {
|
||||
attroff(COLOR_PAIR(kColorPairOpenChat));
|
||||
}
|
||||
if (selected) {
|
||||
attroff(A_BOLD | (focus_ == FocusPane::Chats ? A_REVERSE : A_NORMAL));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace telegram_tui
|
||||
|
||||
Reference in New Issue
Block a user