init
This commit is contained in:
269
src/app_chats.cpp
Normal file
269
src/app_chats.cpp
Normal file
@@ -0,0 +1,269 @@
|
||||
#include "app.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
namespace telegram_tui {
|
||||
|
||||
namespace {
|
||||
|
||||
std::string join_with_separator_local(const std::vector<std::string>& parts, const char* separator) {
|
||||
std::string joined;
|
||||
for (const auto& part : parts) {
|
||||
if (part.empty()) {
|
||||
continue;
|
||||
}
|
||||
if (!joined.empty()) {
|
||||
joined += separator;
|
||||
}
|
||||
joined += part;
|
||||
}
|
||||
return joined;
|
||||
}
|
||||
|
||||
std::string format_user_status(const json& status) {
|
||||
const std::string type = safe_string(status, "@type");
|
||||
if (type == "userStatusOnline") {
|
||||
return "online";
|
||||
}
|
||||
if (type == "userStatusOffline") {
|
||||
const std::int32_t was_online = safe_i32(status, "was_online");
|
||||
return was_online > 0 ? ("last seen " + format_datetime(was_online)) : "offline";
|
||||
}
|
||||
if (type == "userStatusRecently") {
|
||||
return "last seen recently";
|
||||
}
|
||||
if (type == "userStatusLastWeek") {
|
||||
return "last seen within a week";
|
||||
}
|
||||
if (type == "userStatusLastMonth") {
|
||||
return "last seen within a month";
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
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) {
|
||||
if (username.is_string()) {
|
||||
const std::string value = username.get<std::string>();
|
||||
if (!value.empty()) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return safe_string(object, "username");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
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) {
|
||||
if (user.is_null()) {
|
||||
return;
|
||||
}
|
||||
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");
|
||||
info.username = primary_username(user);
|
||||
info.status = format_user_status(user.value("status", json::object()));
|
||||
}
|
||||
|
||||
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_) {
|
||||
if (chat.basic_group_id != basic_group_id) {
|
||||
continue;
|
||||
}
|
||||
chat.id = chat_id;
|
||||
chat.username.clear();
|
||||
chat.member_count = member_count;
|
||||
chat.has_member_count = true;
|
||||
}
|
||||
}
|
||||
|
||||
void App::upsert_supergroup(const json& supergroup) {
|
||||
if (supergroup.is_null()) {
|
||||
return;
|
||||
}
|
||||
const std::int64_t supergroup_id = safe_i64(supergroup, "id");
|
||||
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_) {
|
||||
if (chat.supergroup_id != supergroup_id) {
|
||||
continue;
|
||||
}
|
||||
chat.id = chat_id;
|
||||
chat.is_channel = is_channel;
|
||||
chat.username = username;
|
||||
chat.member_count = member_count;
|
||||
chat.has_member_count = true;
|
||||
}
|
||||
}
|
||||
|
||||
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];
|
||||
chat.id = chat_id;
|
||||
if (chat_object.contains("title")) {
|
||||
chat.title = safe_string(chat_object, "title");
|
||||
}
|
||||
const json type = chat_object.value("type", json::object());
|
||||
const std::string type_name = safe_string(type, "@type");
|
||||
const std::int64_t previous_private_user_id = chat.private_user_id;
|
||||
const std::int64_t previous_basic_group_id = chat.basic_group_id;
|
||||
const std::int64_t previous_supergroup_id = chat.supergroup_id;
|
||||
chat.private_user_id = 0;
|
||||
chat.basic_group_id = 0;
|
||||
chat.supergroup_id = 0;
|
||||
chat.is_channel = false;
|
||||
if (type_name == "chatTypePrivate" || type_name == "chatTypeSecret") {
|
||||
chat.private_user_id = safe_i64(type, "user_id");
|
||||
chat.username.clear();
|
||||
chat.has_member_count = false;
|
||||
chat.has_online_member_count = false;
|
||||
chat.member_count = 0;
|
||||
chat.online_member_count = 0;
|
||||
} else if (type_name == "chatTypeBasicGroup") {
|
||||
chat.basic_group_id = safe_i64(type, "basic_group_id");
|
||||
chat.username.clear();
|
||||
} else if (type_name == "chatTypeSupergroup") {
|
||||
chat.supergroup_id = safe_i64(type, "supergroup_id");
|
||||
chat.is_channel = type.value("is_channel", false);
|
||||
if (chat.supergroup_id != previous_supergroup_id) {
|
||||
chat.username.clear();
|
||||
}
|
||||
} else {
|
||||
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.details_requested = false;
|
||||
}
|
||||
chat.unread_count = safe_i32(chat_object, "unread_count");
|
||||
chat.last_read_inbox_message_id = safe_i64(chat_object, "last_read_inbox_message_id");
|
||||
chat.last_read_outbox_message_id = safe_i64(chat_object, "last_read_outbox_message_id");
|
||||
if (chat_object.contains("last_message")) {
|
||||
chat.last_message_preview = preview_message(chat_object.at("last_message"));
|
||||
}
|
||||
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")) {
|
||||
apply_chat_position(chat, position);
|
||||
}
|
||||
}
|
||||
if (open_chat_id_ == chat.id) {
|
||||
request_chat_details(chat.id);
|
||||
}
|
||||
resort_chats();
|
||||
}
|
||||
|
||||
void App::apply_chat_position(ChatInfo& chat, const json& position) {
|
||||
if (!position.is_object()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const json chat_list = position.value("list", json::object());
|
||||
if (safe_string(chat_list, "@type") != "chatListMain") {
|
||||
return;
|
||||
}
|
||||
chat.in_main_list = true;
|
||||
chat.main_order = safe_i64(position, "order");
|
||||
}
|
||||
|
||||
void App::resort_chats() {
|
||||
if (sorted_chat_ids_.empty()) {
|
||||
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_) {
|
||||
if (!chat.in_main_list) {
|
||||
continue;
|
||||
}
|
||||
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;
|
||||
});
|
||||
|
||||
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::vector<std::string> parts;
|
||||
if (!chat.title.empty()) {
|
||||
parts.push_back(chat.title);
|
||||
}
|
||||
|
||||
if (chat.private_user_id != 0) {
|
||||
const auto user_it = users_.find(chat.private_user_id);
|
||||
if (user_it != users_.end()) {
|
||||
if (!user_it->second.username.empty()) {
|
||||
parts.push_back("@" + user_it->second.username);
|
||||
}
|
||||
const std::string status = user_status_label(chat.private_user_id);
|
||||
if (!status.empty()) {
|
||||
parts.push_back(status);
|
||||
}
|
||||
parts.push_back("id:" + std::to_string(user_it->second.id));
|
||||
} else {
|
||||
parts.push_back("id:" + std::to_string(chat.private_user_id));
|
||||
}
|
||||
return join_with_separator_local(parts, " | ");
|
||||
}
|
||||
if (!chat.username.empty()) {
|
||||
parts.push_back("@" + chat.username);
|
||||
}
|
||||
if (chat.has_member_count) {
|
||||
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");
|
||||
}
|
||||
parts.push_back("id:" + std::to_string(chat.id));
|
||||
return join_with_separator_local(parts, " | ");
|
||||
}
|
||||
|
||||
} // namespace telegram_tui
|
||||
Reference in New Issue
Block a user