Format remaining C++ sources
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -9,19 +9,20 @@ namespace telegram_tui {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
std::string format_download_progress(std::int64_t downloaded_size, std::int64_t size_bytes, bool is_downloaded) {
|
std::string format_download_progress(std::int64_t downloaded_size, std::int64_t size_bytes,
|
||||||
|
bool is_downloaded) {
|
||||||
if (is_downloaded) {
|
if (is_downloaded) {
|
||||||
return "100%";
|
return "100%";
|
||||||
}
|
}
|
||||||
if (size_bytes > 0) {
|
if (size_bytes > 0) {
|
||||||
const auto downloaded = std::min(downloaded_size, size_bytes);
|
const auto downloaded = std::min(downloaded_size, size_bytes);
|
||||||
return std::to_string(static_cast<int>((downloaded * 100) / size_bytes)) + "% " +
|
return std::to_string(static_cast<int>((downloaded * 100) / size_bytes)) + "% " +
|
||||||
format_file_size(downloaded) + "/" + format_file_size(size_bytes);
|
format_file_size(downloaded) + "/" + format_file_size(size_bytes);
|
||||||
}
|
}
|
||||||
return format_file_size(downloaded_size);
|
return format_file_size(downloaded_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
bool App::process_updates() {
|
bool App::process_updates() {
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
@@ -36,7 +37,7 @@ bool App::process_updates() {
|
|||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void App::handle_td_object(const json& object) {
|
void App::handle_td_object(const json &object) {
|
||||||
const std::string type = safe_string(object, "@type");
|
const std::string type = safe_string(object, "@type");
|
||||||
if (type == "updateAuthorizationState") {
|
if (type == "updateAuthorizationState") {
|
||||||
authorization_state_ = object.value("authorization_state", json::object());
|
authorization_state_ = object.value("authorization_state", json::object());
|
||||||
@@ -48,7 +49,7 @@ void App::handle_td_object(const json& object) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (type == "updateChatOnlineMemberCount") {
|
if (type == "updateChatOnlineMemberCount") {
|
||||||
ChatInfo& chat = chats_[safe_i64(object, "chat_id")];
|
ChatInfo &chat = chats_[safe_i64(object, "chat_id")];
|
||||||
chat.id = safe_i64(object, "chat_id");
|
chat.id = safe_i64(object, "chat_id");
|
||||||
chat.online_member_count = safe_i32(object, "online_member_count");
|
chat.online_member_count = safe_i32(object, "online_member_count");
|
||||||
chat.has_online_member_count = true;
|
chat.has_online_member_count = true;
|
||||||
@@ -59,15 +60,19 @@ void App::handle_td_object(const json& object) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (type == "updateUserStatus") {
|
if (type == "updateUserStatus") {
|
||||||
update_user_status(safe_i64(object, "user_id"), object.value("status", json::object()));
|
update_user_status(safe_i64(object, "user_id"),
|
||||||
|
object.value("status", json::object()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (type == "updateBasicGroup" || type == "basicGroup") {
|
if (type == "updateBasicGroup" || type == "basicGroup") {
|
||||||
upsert_basic_group(type == "basicGroup" ? object : object.value("basic_group", json::object()));
|
upsert_basic_group(type == "basicGroup"
|
||||||
|
? object
|
||||||
|
: object.value("basic_group", json::object()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (type == "updateSupergroup" || type == "supergroup") {
|
if (type == "updateSupergroup" || type == "supergroup") {
|
||||||
upsert_supergroup(type == "supergroup" ? object : object.value("supergroup", json::object()));
|
upsert_supergroup(
|
||||||
|
type == "supergroup" ? object : object.value("supergroup", json::object()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (type == "updateNewChat") {
|
if (type == "updateNewChat") {
|
||||||
@@ -75,27 +80,28 @@ void App::handle_td_object(const json& object) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (type == "updateChatTitle") {
|
if (type == "updateChatTitle") {
|
||||||
ChatInfo& chat = chats_[safe_i64(object, "chat_id")];
|
ChatInfo &chat = chats_[safe_i64(object, "chat_id")];
|
||||||
chat.id = safe_i64(object, "chat_id");
|
chat.id = safe_i64(object, "chat_id");
|
||||||
chat.title = safe_string(object, "title");
|
chat.title = safe_string(object, "title");
|
||||||
resort_chats();
|
resort_chats();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (type == "updateChatPosition") {
|
if (type == "updateChatPosition") {
|
||||||
ChatInfo& chat = chats_[safe_i64(object, "chat_id")];
|
ChatInfo &chat = chats_[safe_i64(object, "chat_id")];
|
||||||
chat.id = safe_i64(object, "chat_id");
|
chat.id = safe_i64(object, "chat_id");
|
||||||
apply_chat_position(chat, object.value("position", json::object()));
|
apply_chat_position(chat, object.value("position", json::object()));
|
||||||
resort_chats();
|
resort_chats();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (type == "updateChatLastMessage") {
|
if (type == "updateChatLastMessage") {
|
||||||
ChatInfo& chat = chats_[safe_i64(object, "chat_id")];
|
ChatInfo &chat = chats_[safe_i64(object, "chat_id")];
|
||||||
chat.id = safe_i64(object, "chat_id");
|
chat.id = safe_i64(object, "chat_id");
|
||||||
chat.last_message_preview = preview_message(object.value("last_message", json::object()));
|
chat.last_message_preview =
|
||||||
|
preview_message(object.value("last_message", json::object()));
|
||||||
if (object.contains("positions") && object.at("positions").is_array()) {
|
if (object.contains("positions") && object.at("positions").is_array()) {
|
||||||
chat.in_main_list = false;
|
chat.in_main_list = false;
|
||||||
chat.main_order = 0;
|
chat.main_order = 0;
|
||||||
for (const auto& position : object.at("positions")) {
|
for (const auto &position : object.at("positions")) {
|
||||||
apply_chat_position(chat, position);
|
apply_chat_position(chat, position);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -103,14 +109,14 @@ void App::handle_td_object(const json& object) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (type == "updateChatReadInbox") {
|
if (type == "updateChatReadInbox") {
|
||||||
ChatInfo& chat = chats_[safe_i64(object, "chat_id")];
|
ChatInfo &chat = chats_[safe_i64(object, "chat_id")];
|
||||||
chat.id = safe_i64(object, "chat_id");
|
chat.id = safe_i64(object, "chat_id");
|
||||||
chat.unread_count = safe_i32(object, "unread_count");
|
chat.unread_count = safe_i32(object, "unread_count");
|
||||||
chat.last_read_inbox_message_id = safe_i64(object, "last_read_inbox_message_id");
|
chat.last_read_inbox_message_id = safe_i64(object, "last_read_inbox_message_id");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (type == "updateChatReadOutbox") {
|
if (type == "updateChatReadOutbox") {
|
||||||
ChatInfo& chat = chats_[safe_i64(object, "chat_id")];
|
ChatInfo &chat = chats_[safe_i64(object, "chat_id")];
|
||||||
chat.id = safe_i64(object, "chat_id");
|
chat.id = safe_i64(object, "chat_id");
|
||||||
chat.last_read_outbox_message_id = safe_i64(object, "last_read_outbox_message_id");
|
chat.last_read_outbox_message_id = safe_i64(object, "last_read_outbox_message_id");
|
||||||
return;
|
return;
|
||||||
@@ -136,11 +142,12 @@ void App::handle_td_object(const json& object) {
|
|||||||
if (chat_it == chats_.end()) {
|
if (chat_it == chats_.end()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (auto& message : chat_it->second.messages) {
|
for (auto &message : chat_it->second.messages) {
|
||||||
if (message.id == message_id) {
|
if (message.id == message_id) {
|
||||||
const json content = object.value("new_content", json::object());
|
const json content = object.value("new_content", json::object());
|
||||||
message.text = content_to_text(content, true);
|
message.text = content_to_text(content, true);
|
||||||
if (const auto attachment = parse_attachment(content); attachment.has_value()) {
|
if (const auto attachment = parse_attachment(content);
|
||||||
|
attachment.has_value()) {
|
||||||
message.has_attachment = true;
|
message.has_attachment = true;
|
||||||
message.attachment = *attachment;
|
message.attachment = *attachment;
|
||||||
} else {
|
} else {
|
||||||
@@ -158,14 +165,14 @@ void App::handle_td_object(const json& object) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
std::set<std::int64_t> deleted;
|
std::set<std::int64_t> deleted;
|
||||||
for (const auto& id : object.value("message_ids", json::array())) {
|
for (const auto &id : object.value("message_ids", json::array())) {
|
||||||
if (id.is_number_integer()) {
|
if (id.is_number_integer()) {
|
||||||
deleted.insert(id.get<std::int64_t>());
|
deleted.insert(id.get<std::int64_t>());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::vector<MessageInfo> kept;
|
std::vector<MessageInfo> kept;
|
||||||
kept.reserve(chat_it->second.messages.size());
|
kept.reserve(chat_it->second.messages.size());
|
||||||
for (const auto& message : chat_it->second.messages) {
|
for (const auto &message : chat_it->second.messages) {
|
||||||
if (deleted.find(message.id) == deleted.end()) {
|
if (deleted.find(message.id) == deleted.end()) {
|
||||||
kept.push_back(message);
|
kept.push_back(message);
|
||||||
}
|
}
|
||||||
@@ -178,8 +185,8 @@ void App::handle_td_object(const json& object) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (type == "updateOption" || type == "ok" || type == "userFullInfo" ||
|
if (type == "updateOption" || type == "ok" || type == "userFullInfo" ||
|
||||||
type == "updateHavePendingNotifications" || type == "updateUnreadMessageCount" ||
|
type == "updateHavePendingNotifications" || type == "updateUnreadMessageCount" ||
|
||||||
type == "updateUnreadChatCount") {
|
type == "updateUnreadChatCount") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (type == "error") {
|
if (type == "error") {
|
||||||
@@ -235,29 +242,29 @@ void App::handle_td_object(const json& object) {
|
|||||||
|
|
||||||
void App::request_more_chats() {
|
void App::request_more_chats() {
|
||||||
td_.send({
|
td_.send({
|
||||||
{"@type", "getChats"},
|
{"@type", "getChats"},
|
||||||
{"chat_list", {{"@type", "chatListMain"}}},
|
{"chat_list", {{"@type", "chatListMain"}}},
|
||||||
{"limit", kChatPageSize},
|
{"limit", kChatPageSize},
|
||||||
{"@extra", "main_chats"},
|
{"@extra", "main_chats"},
|
||||||
});
|
});
|
||||||
status_line_ = "Loading chats...";
|
status_line_ = "Loading chats...";
|
||||||
}
|
}
|
||||||
|
|
||||||
bool App::request_chat_history(std::int64_t chat_id, bool force) {
|
bool App::request_chat_history(std::int64_t chat_id, bool force) {
|
||||||
ChatInfo& chat = chats_[chat_id];
|
ChatInfo &chat = chats_[chat_id];
|
||||||
chat.id = chat_id;
|
chat.id = chat_id;
|
||||||
if (chat.history_loading && !force) {
|
if (chat.history_loading && !force) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
chat.history_loading = true;
|
chat.history_loading = true;
|
||||||
td_.send({
|
td_.send({
|
||||||
{"@type", "getChatHistory"},
|
{"@type", "getChatHistory"},
|
||||||
{"chat_id", chat_id},
|
{"chat_id", chat_id},
|
||||||
{"from_message_id", 0},
|
{"from_message_id", 0},
|
||||||
{"offset", 0},
|
{"offset", 0},
|
||||||
{"limit", kHistoryBatchSize},
|
{"limit", kHistoryBatchSize},
|
||||||
{"only_local", false},
|
{"only_local", false},
|
||||||
{"@extra", "history:" + std::to_string(chat_id)},
|
{"@extra", "history:" + std::to_string(chat_id)},
|
||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -283,7 +290,7 @@ void App::mark_chat_messages_as_read(std::int64_t chat_id) {
|
|||||||
|
|
||||||
std::vector<std::int64_t> unread_message_ids;
|
std::vector<std::int64_t> unread_message_ids;
|
||||||
unread_message_ids.reserve(chat_it->second.messages.size());
|
unread_message_ids.reserve(chat_it->second.messages.size());
|
||||||
for (const auto& message : chat_it->second.messages) {
|
for (const auto &message : chat_it->second.messages) {
|
||||||
if (message.is_outgoing || message.id == 0) {
|
if (message.is_outgoing || message.id == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -295,18 +302,18 @@ void App::mark_chat_messages_as_read(std::int64_t chat_id) {
|
|||||||
|
|
||||||
if (!unread_message_ids.empty()) {
|
if (!unread_message_ids.empty()) {
|
||||||
td_.send({
|
td_.send({
|
||||||
{"@type", "viewMessages"},
|
{"@type", "viewMessages"},
|
||||||
{"chat_id", chat_id},
|
{"chat_id", chat_id},
|
||||||
{"message_ids", unread_message_ids},
|
{"message_ids", unread_message_ids},
|
||||||
{"source", {{"@type", "messageSourceChatHistory"}}},
|
{"source", {{"@type", "messageSourceChatHistory"}}},
|
||||||
{"force_read", true},
|
{"force_read", true},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
td_.send({
|
td_.send({
|
||||||
{"@type", "toggleChatIsMarkedAsUnread"},
|
{"@type", "toggleChatIsMarkedAsUnread"},
|
||||||
{"chat_id", chat_id},
|
{"chat_id", chat_id},
|
||||||
{"is_marked_as_unread", false},
|
{"is_marked_as_unread", false},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -316,11 +323,11 @@ void App::mark_message_as_read(std::int64_t chat_id, std::int64_t message_id) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
td_.send({
|
td_.send({
|
||||||
{"@type", "viewMessages"},
|
{"@type", "viewMessages"},
|
||||||
{"chat_id", chat_id},
|
{"chat_id", chat_id},
|
||||||
{"message_ids", json::array({message_id})},
|
{"message_ids", json::array({message_id})},
|
||||||
{"source", {{"@type", "messageSourceChatHistory"}}},
|
{"source", {{"@type", "messageSourceChatHistory"}}},
|
||||||
{"force_read", true},
|
{"force_read", true},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -330,12 +337,12 @@ void App::set_open_chat(std::int64_t chat_id) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const bool changed_chat = open_chat_id_ != chat_id;
|
const bool changed_chat = open_chat_id_ != chat_id;
|
||||||
ChatInfo& chat = chats_[chat_id];
|
ChatInfo &chat = chats_[chat_id];
|
||||||
chat.id = chat_id;
|
chat.id = chat_id;
|
||||||
if (tdlib_open_chat_id_ != 0 && tdlib_open_chat_id_ != chat_id) {
|
if (tdlib_open_chat_id_ != 0 && tdlib_open_chat_id_ != chat_id) {
|
||||||
td_.send({
|
td_.send({
|
||||||
{"@type", "closeChat"},
|
{"@type", "closeChat"},
|
||||||
{"chat_id", tdlib_open_chat_id_},
|
{"chat_id", tdlib_open_chat_id_},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -347,8 +354,8 @@ void App::set_open_chat(std::int64_t chat_id) {
|
|||||||
|
|
||||||
if (tdlib_open_chat_id_ != chat_id) {
|
if (tdlib_open_chat_id_ != chat_id) {
|
||||||
td_.send({
|
td_.send({
|
||||||
{"@type", "openChat"},
|
{"@type", "openChat"},
|
||||||
{"chat_id", chat_id},
|
{"chat_id", chat_id},
|
||||||
});
|
});
|
||||||
tdlib_open_chat_id_ = chat_id;
|
tdlib_open_chat_id_ = chat_id;
|
||||||
}
|
}
|
||||||
@@ -358,25 +365,25 @@ void App::set_open_chat(std::int64_t chat_id) {
|
|||||||
if (changed_chat) {
|
if (changed_chat) {
|
||||||
request_chat_details(chat_id);
|
request_chat_details(chat_id);
|
||||||
const bool should_request_history =
|
const bool should_request_history =
|
||||||
auto_reload_chat_history_ || !chat.history_loaded || chat.messages.empty();
|
auto_reload_chat_history_ || !chat.history_loaded || chat.messages.empty();
|
||||||
const bool requested = should_request_history &&
|
const bool requested = should_request_history &&
|
||||||
request_chat_history(chat_id, auto_reload_chat_history_);
|
request_chat_history(chat_id, auto_reload_chat_history_);
|
||||||
if (requested) {
|
if (requested) {
|
||||||
status_line_ = auto_reload_chat_history_ && chat.history_loaded
|
status_line_ = auto_reload_chat_history_ && chat.history_loaded
|
||||||
? "Reloading chat history..."
|
? "Reloading chat history..."
|
||||||
: "Loading chat history...";
|
: "Loading chat history...";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void App::sync_chat_ids_from_response(const json& response) {
|
void App::sync_chat_ids_from_response(const json &response) {
|
||||||
if (!response.contains("chat_ids") || !response.at("chat_ids").is_array()) {
|
if (!response.contains("chat_ids") || !response.at("chat_ids").is_array()) {
|
||||||
status_line_ = "Chat list response missing chat ids.";
|
status_line_ = "Chat list response missing chat ids.";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::int64_t> chat_ids;
|
std::vector<std::int64_t> chat_ids;
|
||||||
for (const auto& entry : response.at("chat_ids")) {
|
for (const auto &entry : response.at("chat_ids")) {
|
||||||
if (!entry.is_number_integer()) {
|
if (!entry.is_number_integer()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -384,8 +391,8 @@ void App::sync_chat_ids_from_response(const json& response) {
|
|||||||
chat_ids.push_back(chat_id);
|
chat_ids.push_back(chat_id);
|
||||||
if (chats_.find(chat_id) == chats_.end()) {
|
if (chats_.find(chat_id) == chats_.end()) {
|
||||||
td_.send({
|
td_.send({
|
||||||
{"@type", "getChat"},
|
{"@type", "getChat"},
|
||||||
{"chat_id", chat_id},
|
{"chat_id", chat_id},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -393,7 +400,8 @@ void App::sync_chat_ids_from_response(const json& response) {
|
|||||||
if (!chat_ids.empty()) {
|
if (!chat_ids.empty()) {
|
||||||
sorted_chat_ids_ = std::move(chat_ids);
|
sorted_chat_ids_ = std::move(chat_ids);
|
||||||
if (selected_chat_index_ >= static_cast<int>(sorted_chat_ids_.size())) {
|
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);
|
selected_chat_index_ =
|
||||||
|
std::max(0, static_cast<int>(sorted_chat_ids_.size()) - 1);
|
||||||
}
|
}
|
||||||
if (!open_chat_id().has_value()) {
|
if (!open_chat_id().has_value()) {
|
||||||
const auto chat_id = highlighted_chat_id();
|
const auto chat_id = highlighted_chat_id();
|
||||||
@@ -410,10 +418,11 @@ void App::sync_chat_ids_from_response(const json& response) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void App::append_message(std::int64_t chat_id, MessageInfo message) {
|
void App::append_message(std::int64_t chat_id, MessageInfo message) {
|
||||||
ChatInfo& chat = chats_[chat_id];
|
ChatInfo &chat = chats_[chat_id];
|
||||||
chat.id = chat_id;
|
chat.id = chat_id;
|
||||||
auto existing = std::find_if(chat.messages.begin(), chat.messages.end(),
|
auto existing =
|
||||||
[&](const MessageInfo& item) { return item.id == message.id; });
|
std::find_if(chat.messages.begin(), chat.messages.end(),
|
||||||
|
[&](const MessageInfo &item) { return item.id == message.id; });
|
||||||
if (existing != chat.messages.end()) {
|
if (existing != chat.messages.end()) {
|
||||||
*existing = std::move(message);
|
*existing = std::move(message);
|
||||||
} else {
|
} else {
|
||||||
@@ -421,18 +430,18 @@ void App::append_message(std::int64_t chat_id, MessageInfo message) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::sort(chat.messages.begin(), chat.messages.end(),
|
std::sort(chat.messages.begin(), chat.messages.end(),
|
||||||
[](const MessageInfo& lhs, const MessageInfo& rhs) {
|
[](const MessageInfo &lhs, const MessageInfo &rhs) {
|
||||||
if (lhs.date != rhs.date) {
|
if (lhs.date != rhs.date) {
|
||||||
return lhs.date < rhs.date;
|
return lhs.date < rhs.date;
|
||||||
}
|
}
|
||||||
return lhs.id < rhs.id;
|
return lhs.id < rhs.id;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (kMaxMessagesPerChat > 0 && chat.messages.size() > kMaxMessagesPerChat) {
|
if (kMaxMessagesPerChat > 0 && chat.messages.size() > kMaxMessagesPerChat) {
|
||||||
chat.messages.erase(
|
chat.messages.erase(chat.messages.begin(),
|
||||||
chat.messages.begin(),
|
chat.messages.begin() +
|
||||||
chat.messages.begin() +
|
static_cast<std::ptrdiff_t>(chat.messages.size() -
|
||||||
static_cast<std::ptrdiff_t>(chat.messages.size() - kMaxMessagesPerChat));
|
kMaxMessagesPerChat));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -446,20 +455,18 @@ void App::remove_message(std::int64_t chat_id, std::int64_t message_id) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& messages = chat_it->second.messages;
|
auto &messages = chat_it->second.messages;
|
||||||
messages.erase(
|
messages.erase(
|
||||||
std::remove_if(
|
std::remove_if(messages.begin(), messages.end(),
|
||||||
messages.begin(),
|
[&](const MessageInfo &item) { return item.id == message_id; }),
|
||||||
messages.end(),
|
messages.end());
|
||||||
[&](const MessageInfo& item) { return item.id == message_id; }),
|
|
||||||
messages.end());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void App::merge_history(std::int64_t chat_id, const json& messages) {
|
void App::merge_history(std::int64_t chat_id, const json &messages) {
|
||||||
ChatInfo& chat = chats_[chat_id];
|
ChatInfo &chat = chats_[chat_id];
|
||||||
chat.history_loading = false;
|
chat.history_loading = false;
|
||||||
chat.history_loaded = true;
|
chat.history_loaded = true;
|
||||||
for (const auto& message : messages) {
|
for (const auto &message : messages) {
|
||||||
append_message(chat_id, parse_message(message));
|
append_message(chat_id, parse_message(message));
|
||||||
}
|
}
|
||||||
if (chat_id == open_chat_id_) {
|
if (chat_id == open_chat_id_) {
|
||||||
@@ -468,13 +475,14 @@ void App::merge_history(std::int64_t chat_id, const json& messages) {
|
|||||||
status_line_ = "History loaded.";
|
status_line_ = "History loaded.";
|
||||||
}
|
}
|
||||||
|
|
||||||
void App::update_attachment_file(const json& file) {
|
void App::update_attachment_file(const json &file) {
|
||||||
const std::int32_t file_id = safe_i32(file, "id");
|
const std::int32_t file_id = safe_i32(file, "id");
|
||||||
if (file_id == 0) {
|
if (file_id == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::int64_t size_bytes = std::max(safe_i64(file, "size"), safe_i64(file, "expected_size"));
|
const std::int64_t size_bytes =
|
||||||
|
std::max(safe_i64(file, "size"), safe_i64(file, "expected_size"));
|
||||||
const json local = file.value("local", json::object());
|
const json local = file.value("local", json::object());
|
||||||
const std::string local_path = safe_string(local, "path");
|
const std::string local_path = safe_string(local, "path");
|
||||||
const std::int64_t downloaded_size = safe_i64(local, "downloaded_size");
|
const std::int64_t downloaded_size = safe_i64(local, "downloaded_size");
|
||||||
@@ -483,9 +491,9 @@ void App::update_attachment_file(const json& file) {
|
|||||||
const bool can_be_downloaded = local.value("can_be_downloaded", false);
|
const bool can_be_downloaded = local.value("can_be_downloaded", false);
|
||||||
const bool can_be_deleted = local.value("can_be_deleted", false);
|
const bool can_be_deleted = local.value("can_be_deleted", false);
|
||||||
|
|
||||||
for (auto& [chat_id, chat] : chats_) {
|
for (auto &[chat_id, chat] : chats_) {
|
||||||
(void) chat_id;
|
(void)chat_id;
|
||||||
for (auto& message : chat.messages) {
|
for (auto &message : chat.messages) {
|
||||||
if (!message.has_attachment || message.attachment.file_id != file_id) {
|
if (!message.has_attachment || message.attachment.file_id != file_id) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -502,7 +510,8 @@ void App::update_attachment_file(const json& file) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (pending_attachment_open_.has_value() && pending_attachment_open_->file_id == file_id) {
|
if (pending_attachment_open_.has_value() && pending_attachment_open_->file_id == file_id) {
|
||||||
pending_attachment_open_->size_bytes = size_bytes > 0 ? size_bytes : pending_attachment_open_->size_bytes;
|
pending_attachment_open_->size_bytes =
|
||||||
|
size_bytes > 0 ? size_bytes : pending_attachment_open_->size_bytes;
|
||||||
pending_attachment_open_->downloaded_size = downloaded_size;
|
pending_attachment_open_->downloaded_size = downloaded_size;
|
||||||
pending_attachment_open_->local_path = local_path;
|
pending_attachment_open_->local_path = local_path;
|
||||||
pending_attachment_open_->is_downloading_active = is_downloading_active;
|
pending_attachment_open_->is_downloading_active = is_downloading_active;
|
||||||
@@ -510,11 +519,11 @@ void App::update_attachment_file(const json& file) {
|
|||||||
pending_attachment_open_->can_be_downloaded = can_be_downloaded;
|
pending_attachment_open_->can_be_downloaded = can_be_downloaded;
|
||||||
pending_attachment_open_->can_be_deleted = can_be_deleted;
|
pending_attachment_open_->can_be_deleted = can_be_deleted;
|
||||||
if (!is_downloaded && is_downloading_active) {
|
if (!is_downloaded && is_downloading_active) {
|
||||||
status_line_ = "Downloading attachment to open " +
|
status_line_ =
|
||||||
format_download_progress(
|
"Downloading attachment to open " +
|
||||||
pending_attachment_open_->downloaded_size,
|
format_download_progress(pending_attachment_open_->downloaded_size,
|
||||||
pending_attachment_open_->size_bytes,
|
pending_attachment_open_->size_bytes,
|
||||||
pending_attachment_open_->is_downloaded);
|
pending_attachment_open_->is_downloaded);
|
||||||
}
|
}
|
||||||
if (is_downloaded && !local_path.empty()) {
|
if (is_downloaded && !local_path.empty()) {
|
||||||
open_attachment(*pending_attachment_open_);
|
open_attachment(*pending_attachment_open_);
|
||||||
@@ -522,9 +531,10 @@ void App::update_attachment_file(const json& file) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pending_attachment_download_.has_value() && pending_attachment_download_->file_id == file_id) {
|
if (pending_attachment_download_.has_value() &&
|
||||||
|
pending_attachment_download_->file_id == file_id) {
|
||||||
pending_attachment_download_->size_bytes =
|
pending_attachment_download_->size_bytes =
|
||||||
size_bytes > 0 ? size_bytes : pending_attachment_download_->size_bytes;
|
size_bytes > 0 ? size_bytes : pending_attachment_download_->size_bytes;
|
||||||
pending_attachment_download_->downloaded_size = downloaded_size;
|
pending_attachment_download_->downloaded_size = downloaded_size;
|
||||||
pending_attachment_download_->local_path = local_path;
|
pending_attachment_download_->local_path = local_path;
|
||||||
pending_attachment_download_->is_downloading_active = is_downloading_active;
|
pending_attachment_download_->is_downloading_active = is_downloading_active;
|
||||||
@@ -533,10 +543,10 @@ void App::update_attachment_file(const json& file) {
|
|||||||
pending_attachment_download_->can_be_deleted = can_be_deleted;
|
pending_attachment_download_->can_be_deleted = can_be_deleted;
|
||||||
if (!is_downloaded && is_downloading_active) {
|
if (!is_downloaded && is_downloading_active) {
|
||||||
status_line_ = "Downloading attachment to ~/Downloads " +
|
status_line_ = "Downloading attachment to ~/Downloads " +
|
||||||
format_download_progress(
|
format_download_progress(
|
||||||
pending_attachment_download_->downloaded_size,
|
pending_attachment_download_->downloaded_size,
|
||||||
pending_attachment_download_->size_bytes,
|
pending_attachment_download_->size_bytes,
|
||||||
pending_attachment_download_->is_downloaded);
|
pending_attachment_download_->is_downloaded);
|
||||||
}
|
}
|
||||||
if (is_downloaded && !local_path.empty()) {
|
if (is_downloaded && !local_path.empty()) {
|
||||||
export_attachment_to_downloads(*pending_attachment_download_);
|
export_attachment_to_downloads(*pending_attachment_download_);
|
||||||
@@ -545,4 +555,4 @@ void App::update_attachment_file(const json& file) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace telegram_tui
|
} // namespace telegram_tui
|
||||||
|
|||||||
@@ -6,4 +6,4 @@ namespace telegram_tui {
|
|||||||
|
|
||||||
using json = nlohmann::json;
|
using json = nlohmann::json;
|
||||||
|
|
||||||
} // namespace telegram_tui
|
} // namespace telegram_tui
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ int main() {
|
|||||||
try {
|
try {
|
||||||
telegram_tui::App app;
|
telegram_tui::App app;
|
||||||
return app.run();
|
return app.run();
|
||||||
} catch (const std::exception& error) {
|
} catch (const std::exception &error) {
|
||||||
endwin();
|
endwin();
|
||||||
std::fprintf(stderr, "fatal: %s\n", error.what());
|
std::fprintf(stderr, "fatal: %s\n", error.what());
|
||||||
return 1;
|
return 1;
|
||||||
|
|||||||
@@ -22,4 +22,4 @@ std::string UserInfo::display_name() const {
|
|||||||
return "Unknown";
|
return "Unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace telegram_tui
|
} // namespace telegram_tui
|
||||||
|
|||||||
@@ -98,4 +98,4 @@ enum class InputMode {
|
|||||||
LastName,
|
LastName,
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace telegram_tui
|
} // namespace telegram_tui
|
||||||
|
|||||||
@@ -9,16 +9,16 @@ namespace telegram_tui {
|
|||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
void configure_tdlib_logging() {
|
void configure_tdlib_logging() {
|
||||||
const char* stream_request =
|
const char *stream_request =
|
||||||
R"({"@type":"setLogStream","log_stream":{"@type":"logStreamEmpty"}})";
|
R"({"@type":"setLogStream","log_stream":{"@type":"logStreamEmpty"}})";
|
||||||
const char* verbosity_request =
|
const char *verbosity_request =
|
||||||
R"({"@type":"setLogVerbosityLevel","new_verbosity_level":0})";
|
R"({"@type":"setLogVerbosityLevel","new_verbosity_level":0})";
|
||||||
|
|
||||||
td_json_client_execute(nullptr, stream_request);
|
td_json_client_execute(nullptr, stream_request);
|
||||||
td_json_client_execute(nullptr, verbosity_request);
|
td_json_client_execute(nullptr, verbosity_request);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
TdClient::TdClient() {
|
TdClient::TdClient() {
|
||||||
configure_tdlib_logging();
|
configure_tdlib_logging();
|
||||||
@@ -31,14 +31,14 @@ TdClient::~TdClient() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TdClient::send(const json& request) {
|
void TdClient::send(const json &request) {
|
||||||
const std::string payload = request.dump();
|
const std::string payload = request.dump();
|
||||||
td_json_client_send(client_, payload.c_str());
|
td_json_client_send(client_, payload.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<json> TdClient::execute(const json& request) {
|
std::optional<json> TdClient::execute(const json &request) {
|
||||||
const std::string payload = request.dump();
|
const std::string payload = request.dump();
|
||||||
const char* raw = td_json_client_execute(client_, payload.c_str());
|
const char *raw = td_json_client_execute(client_, payload.c_str());
|
||||||
if (raw == nullptr) {
|
if (raw == nullptr) {
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
@@ -51,7 +51,7 @@ std::optional<json> TdClient::execute(const json& request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::optional<json> TdClient::receive(double timeout_seconds) {
|
std::optional<json> TdClient::receive(double timeout_seconds) {
|
||||||
const char* raw = td_json_client_receive(client_, timeout_seconds);
|
const char *raw = td_json_client_receive(client_, timeout_seconds);
|
||||||
if (raw == nullptr) {
|
if (raw == nullptr) {
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
@@ -63,4 +63,4 @@ std::optional<json> TdClient::receive(double timeout_seconds) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace telegram_tui
|
} // namespace telegram_tui
|
||||||
|
|||||||
@@ -7,19 +7,19 @@
|
|||||||
namespace telegram_tui {
|
namespace telegram_tui {
|
||||||
|
|
||||||
class TdClient {
|
class TdClient {
|
||||||
public:
|
public:
|
||||||
TdClient();
|
TdClient();
|
||||||
~TdClient();
|
~TdClient();
|
||||||
|
|
||||||
TdClient(const TdClient&) = delete;
|
TdClient(const TdClient &) = delete;
|
||||||
TdClient& operator=(const TdClient&) = delete;
|
TdClient &operator=(const TdClient &) = delete;
|
||||||
|
|
||||||
void send(const json& request);
|
void send(const json &request);
|
||||||
[[nodiscard]] std::optional<json> execute(const json& request);
|
[[nodiscard]] std::optional<json> execute(const json &request);
|
||||||
[[nodiscard]] std::optional<json> receive(double timeout_seconds);
|
[[nodiscard]] std::optional<json> receive(double timeout_seconds);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void* client_ = nullptr;
|
void *client_ = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace telegram_tui
|
} // namespace telegram_tui
|
||||||
|
|||||||
67
src/util.cpp
67
src/util.cpp
@@ -33,7 +33,8 @@ bool is_utf8_continuation(unsigned char ch) {
|
|||||||
return (ch & 0xC0U) == 0x80U;
|
return (ch & 0xC0U) == 0x80U;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::uint32_t decode_utf8_codepoint(const std::string& text, std::size_t offset, std::size_t* size_out = nullptr) {
|
std::uint32_t decode_utf8_codepoint(const std::string &text, std::size_t offset,
|
||||||
|
std::size_t *size_out = nullptr) {
|
||||||
if (offset >= text.size()) {
|
if (offset >= text.size()) {
|
||||||
if (size_out != nullptr) {
|
if (size_out != nullptr) {
|
||||||
*size_out = 0;
|
*size_out = 0;
|
||||||
@@ -62,23 +63,23 @@ std::uint32_t decode_utf8_codepoint(const std::string& text, std::size_t offset,
|
|||||||
}
|
}
|
||||||
if (size == 2) {
|
if (size == 2) {
|
||||||
return ((lead & 0x1FU) << 6) |
|
return ((lead & 0x1FU) << 6) |
|
||||||
(static_cast<unsigned char>(text[offset + 1]) & 0x3FU);
|
(static_cast<unsigned char>(text[offset + 1]) & 0x3FU);
|
||||||
}
|
}
|
||||||
if (size == 3) {
|
if (size == 3) {
|
||||||
return ((lead & 0x0FU) << 12) |
|
return ((lead & 0x0FU) << 12) |
|
||||||
((static_cast<unsigned char>(text[offset + 1]) & 0x3FU) << 6) |
|
((static_cast<unsigned char>(text[offset + 1]) & 0x3FU) << 6) |
|
||||||
(static_cast<unsigned char>(text[offset + 2]) & 0x3FU);
|
(static_cast<unsigned char>(text[offset + 2]) & 0x3FU);
|
||||||
}
|
}
|
||||||
return ((lead & 0x07U) << 18) |
|
return ((lead & 0x07U) << 18) |
|
||||||
((static_cast<unsigned char>(text[offset + 1]) & 0x3FU) << 12) |
|
((static_cast<unsigned char>(text[offset + 1]) & 0x3FU) << 12) |
|
||||||
((static_cast<unsigned char>(text[offset + 2]) & 0x3FU) << 6) |
|
((static_cast<unsigned char>(text[offset + 2]) & 0x3FU) << 6) |
|
||||||
(static_cast<unsigned char>(text[offset + 3]) & 0x3FU);
|
(static_cast<unsigned char>(text[offset + 3]) & 0x3FU);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
std::string get_env(const char* name) {
|
std::string get_env(const char *name) {
|
||||||
const char* value = std::getenv(name);
|
const char *value = std::getenv(name);
|
||||||
return value == nullptr ? std::string() : std::string(value);
|
return value == nullptr ? std::string() : std::string(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,7 +95,7 @@ std::string trim_copy(std::string value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::string single_line(std::string text) {
|
std::string single_line(std::string text) {
|
||||||
for (char& c : text) {
|
for (char &c : text) {
|
||||||
if (c == '\n' || c == '\r' || c == '\t') {
|
if (c == '\n' || c == '\r' || c == '\t') {
|
||||||
c = ' ';
|
c = ' ';
|
||||||
}
|
}
|
||||||
@@ -102,16 +103,16 @@ std::string single_line(std::string text) {
|
|||||||
return trim_copy(std::move(text));
|
return trim_copy(std::move(text));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_decimal_number(const std::string& value) {
|
bool is_decimal_number(const std::string &value) {
|
||||||
return !value.empty() &&
|
return !value.empty() && std::all_of(value.begin(), value.end(),
|
||||||
std::all_of(value.begin(), value.end(), [](unsigned char ch) { return std::isdigit(ch); });
|
[](unsigned char ch) { return std::isdigit(ch); });
|
||||||
}
|
}
|
||||||
|
|
||||||
std::filesystem::path data_root() {
|
std::filesystem::path data_root() {
|
||||||
if (const char* xdg = std::getenv("XDG_DATA_HOME"); xdg != nullptr && *xdg != '\0') {
|
if (const char *xdg = std::getenv("XDG_DATA_HOME"); xdg != nullptr && *xdg != '\0') {
|
||||||
return std::filesystem::path(xdg) / "telegram-tui";
|
return std::filesystem::path(xdg) / "telegram-tui";
|
||||||
}
|
}
|
||||||
if (const char* home = std::getenv("HOME"); home != nullptr && *home != '\0') {
|
if (const char *home = std::getenv("HOME"); home != nullptr && *home != '\0') {
|
||||||
return std::filesystem::path(home) / ".local" / "share" / "telegram-tui";
|
return std::filesystem::path(home) / ".local" / "share" / "telegram-tui";
|
||||||
}
|
}
|
||||||
return std::filesystem::current_path() / ".telegram-tui-data";
|
return std::filesystem::current_path() / ".telegram-tui-data";
|
||||||
@@ -130,16 +131,16 @@ StoredConfig load_app_config() {
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
return StoredConfig{
|
return StoredConfig{
|
||||||
safe_string(config, "api_id"),
|
safe_string(config, "api_id"),
|
||||||
safe_string(config, "api_hash"),
|
safe_string(config, "api_hash"),
|
||||||
config.value("auto_reload_chat_history", false),
|
config.value("auto_reload_chat_history", false),
|
||||||
};
|
};
|
||||||
} catch (const json::exception&) {
|
} catch (const json::exception &) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool save_app_config(const StoredConfig& config) {
|
bool save_app_config(const StoredConfig &config) {
|
||||||
const std::filesystem::path path = data_root() / "config.json";
|
const std::filesystem::path path = data_root() / "config.json";
|
||||||
try {
|
try {
|
||||||
if (path.has_parent_path()) {
|
if (path.has_parent_path()) {
|
||||||
@@ -161,26 +162,26 @@ bool save_app_config(const StoredConfig& config) {
|
|||||||
}
|
}
|
||||||
output << document.dump(2) << '\n';
|
output << document.dump(2) << '\n';
|
||||||
return static_cast<bool>(output);
|
return static_cast<bool>(output);
|
||||||
} catch (const std::exception&) {
|
} catch (const std::exception &) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string safe_string(const json& object, const char* key) {
|
std::string safe_string(const json &object, const char *key) {
|
||||||
if (!object.contains(key) || !object.at(key).is_string()) {
|
if (!object.contains(key) || !object.at(key).is_string()) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
return object.at(key).get<std::string>();
|
return object.at(key).get<std::string>();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::int64_t safe_i64(const json& object, const char* key) {
|
std::int64_t safe_i64(const json &object, const char *key) {
|
||||||
if (!object.contains(key) || !object.at(key).is_number_integer()) {
|
if (!object.contains(key) || !object.at(key).is_number_integer()) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return object.at(key).get<std::int64_t>();
|
return object.at(key).get<std::int64_t>();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::int32_t safe_i32(const json& object, const char* key) {
|
std::int32_t safe_i32(const json &object, const char *key) {
|
||||||
if (!object.contains(key) || !object.at(key).is_number_integer()) {
|
if (!object.contains(key) || !object.at(key).is_number_integer()) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -228,7 +229,7 @@ std::string format_file_size(std::int64_t size_bytes) {
|
|||||||
return "?";
|
return "?";
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr const char* units[] = {"B", "KB", "MB", "GB", "TB"};
|
static constexpr const char *units[] = {"B", "KB", "MB", "GB", "TB"};
|
||||||
double size = static_cast<double>(size_bytes);
|
double size = static_cast<double>(size_bytes);
|
||||||
std::size_t unit_index = 0;
|
std::size_t unit_index = 0;
|
||||||
while (size >= 1024.0 && unit_index + 1 < std::size(units)) {
|
while (size >= 1024.0 && unit_index + 1 < std::size(units)) {
|
||||||
@@ -243,7 +244,7 @@ std::string format_file_size(std::int64_t size_bytes) {
|
|||||||
return stream.str();
|
return stream.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> wrap_text(const std::string& text, int width) {
|
std::vector<std::string> wrap_text(const std::string &text, int width) {
|
||||||
if (width <= 1) {
|
if (width <= 1) {
|
||||||
return {text};
|
return {text};
|
||||||
}
|
}
|
||||||
@@ -286,7 +287,7 @@ std::vector<std::string> wrap_text(const std::string& text, int width) {
|
|||||||
return lines;
|
return lines;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t utf8_byte_index_from_utf16_offset(const std::string& text, std::size_t utf16_offset) {
|
std::size_t utf8_byte_index_from_utf16_offset(const std::string &text, std::size_t utf16_offset) {
|
||||||
std::size_t byte_index = 0;
|
std::size_t byte_index = 0;
|
||||||
std::size_t utf16_units = 0;
|
std::size_t utf16_units = 0;
|
||||||
while (byte_index < text.size() && utf16_units < utf16_offset) {
|
while (byte_index < text.size() && utf16_units < utf16_offset) {
|
||||||
@@ -305,7 +306,7 @@ std::size_t utf8_byte_index_from_utf16_offset(const std::string& text, std::size
|
|||||||
return byte_index;
|
return byte_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t utf8_prev_index(const std::string& text, std::size_t byte_index) {
|
std::size_t utf8_prev_index(const std::string &text, std::size_t byte_index) {
|
||||||
if (byte_index == 0 || text.empty()) {
|
if (byte_index == 0 || text.empty()) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -317,7 +318,7 @@ std::size_t utf8_prev_index(const std::string& text, std::size_t byte_index) {
|
|||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t utf8_next_index(const std::string& text, std::size_t byte_index) {
|
std::size_t utf8_next_index(const std::string &text, std::size_t byte_index) {
|
||||||
if (byte_index >= text.size()) {
|
if (byte_index >= text.size()) {
|
||||||
return text.size();
|
return text.size();
|
||||||
}
|
}
|
||||||
@@ -327,7 +328,7 @@ std::size_t utf8_next_index(const std::string& text, std::size_t byte_index) {
|
|||||||
return std::min(text.size(), byte_index + std::max<std::size_t>(1, size));
|
return std::min(text.size(), byte_index + std::max<std::size_t>(1, size));
|
||||||
}
|
}
|
||||||
|
|
||||||
int utf8_display_width(const std::string& text, std::size_t byte_limit) {
|
int utf8_display_width(const std::string &text, std::size_t byte_limit) {
|
||||||
const std::size_t limit = std::min(byte_limit, text.size());
|
const std::size_t limit = std::min(byte_limit, text.size());
|
||||||
int width = 0;
|
int width = 0;
|
||||||
std::size_t index = 0;
|
std::size_t index = 0;
|
||||||
@@ -351,7 +352,7 @@ int utf8_display_width(const std::string& text, std::size_t byte_limit) {
|
|||||||
return width;
|
return width;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pop_utf8_back(std::string& text) {
|
void pop_utf8_back(std::string &text) {
|
||||||
if (text.empty()) {
|
if (text.empty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -363,4 +364,4 @@ void pop_utf8_back(std::string& text) {
|
|||||||
text.erase(start);
|
text.erase(start);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace telegram_tui
|
} // namespace telegram_tui
|
||||||
|
|||||||
28
src/util.h
28
src/util.h
@@ -15,25 +15,27 @@ struct StoredConfig {
|
|||||||
bool auto_reload_chat_history = false;
|
bool auto_reload_chat_history = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
[[nodiscard]] std::string get_env(const char* name);
|
[[nodiscard]] std::string get_env(const char *name);
|
||||||
[[nodiscard]] std::string trim_copy(std::string value);
|
[[nodiscard]] std::string trim_copy(std::string value);
|
||||||
[[nodiscard]] std::string single_line(std::string text);
|
[[nodiscard]] std::string single_line(std::string text);
|
||||||
[[nodiscard]] bool is_decimal_number(const std::string& value);
|
[[nodiscard]] bool is_decimal_number(const std::string &value);
|
||||||
[[nodiscard]] std::filesystem::path data_root();
|
[[nodiscard]] std::filesystem::path data_root();
|
||||||
[[nodiscard]] StoredConfig load_app_config();
|
[[nodiscard]] StoredConfig load_app_config();
|
||||||
bool save_app_config(const StoredConfig& config);
|
bool save_app_config(const StoredConfig &config);
|
||||||
[[nodiscard]] std::string safe_string(const json& object, const char* key);
|
[[nodiscard]] std::string safe_string(const json &object, const char *key);
|
||||||
[[nodiscard]] std::int64_t safe_i64(const json& object, const char* key);
|
[[nodiscard]] std::int64_t safe_i64(const json &object, const char *key);
|
||||||
[[nodiscard]] std::int32_t safe_i32(const json& object, const char* key);
|
[[nodiscard]] std::int32_t safe_i32(const json &object, const char *key);
|
||||||
[[nodiscard]] std::string format_time(std::int32_t unix_time);
|
[[nodiscard]] std::string format_time(std::int32_t unix_time);
|
||||||
[[nodiscard]] std::string format_date(std::int32_t unix_time);
|
[[nodiscard]] std::string format_date(std::int32_t unix_time);
|
||||||
[[nodiscard]] std::string format_datetime(std::int32_t unix_time);
|
[[nodiscard]] std::string format_datetime(std::int32_t unix_time);
|
||||||
[[nodiscard]] std::string format_file_size(std::int64_t size_bytes);
|
[[nodiscard]] std::string format_file_size(std::int64_t size_bytes);
|
||||||
[[nodiscard]] std::vector<std::string> wrap_text(const std::string& text, int width);
|
[[nodiscard]] std::vector<std::string> wrap_text(const std::string &text, int width);
|
||||||
[[nodiscard]] std::size_t utf8_byte_index_from_utf16_offset(const std::string& text, std::size_t utf16_offset);
|
[[nodiscard]] std::size_t utf8_byte_index_from_utf16_offset(const std::string &text,
|
||||||
[[nodiscard]] std::size_t utf8_prev_index(const std::string& text, std::size_t byte_index);
|
std::size_t utf16_offset);
|
||||||
[[nodiscard]] std::size_t utf8_next_index(const std::string& text, std::size_t byte_index);
|
[[nodiscard]] std::size_t utf8_prev_index(const std::string &text, std::size_t byte_index);
|
||||||
[[nodiscard]] int utf8_display_width(const std::string& text, std::size_t byte_limit = std::string::npos);
|
[[nodiscard]] std::size_t utf8_next_index(const std::string &text, std::size_t byte_index);
|
||||||
void pop_utf8_back(std::string& text);
|
[[nodiscard]] int utf8_display_width(const std::string &text,
|
||||||
|
std::size_t byte_limit = std::string::npos);
|
||||||
|
void pop_utf8_back(std::string &text);
|
||||||
|
|
||||||
} // namespace telegram_tui
|
} // namespace telegram_tui
|
||||||
|
|||||||
Reference in New Issue
Block a user