679 lines
21 KiB
C++
679 lines
21 KiB
C++
#include "app.h"
|
|
|
|
#include <algorithm>
|
|
#include <set>
|
|
|
|
#include "util.h"
|
|
|
|
namespace telegram_tui {
|
|
|
|
namespace {
|
|
|
|
std::string format_download_progress(std::int64_t downloaded_size, std::int64_t size_bytes,
|
|
bool is_downloaded) {
|
|
if (is_downloaded) {
|
|
return "100%";
|
|
}
|
|
if (size_bytes > 0) {
|
|
const auto downloaded = std::min(downloaded_size, size_bytes);
|
|
return std::to_string(static_cast<int>((downloaded * 100) / size_bytes)) + "% " +
|
|
format_file_size(downloaded) + "/" + format_file_size(size_bytes);
|
|
}
|
|
return format_file_size(downloaded_size);
|
|
}
|
|
|
|
} // namespace
|
|
|
|
bool App::process_updates() {
|
|
bool changed = refresh_update_check_result();
|
|
while (true) {
|
|
auto update = td_.receive(0.0);
|
|
if (!update.has_value()) {
|
|
break;
|
|
}
|
|
changed = true;
|
|
handle_td_object(*update);
|
|
}
|
|
return changed;
|
|
}
|
|
|
|
void App::request_saved_animations(bool force) {
|
|
if (saved_animations_loading_ && !force) {
|
|
return;
|
|
}
|
|
saved_animations_loading_ = true;
|
|
td_.send({
|
|
{"@type", "getSavedAnimations"},
|
|
{"@extra", "saved_animations"},
|
|
});
|
|
if (!saved_animation_menu_open_) {
|
|
status_line_ = "Loading saved GIFs...";
|
|
}
|
|
}
|
|
|
|
void App::sync_saved_animations(const json &animations) {
|
|
saved_animations_.clear();
|
|
if (!animations.is_array()) {
|
|
saved_animations_loading_ = false;
|
|
saved_animations_loaded_ = true;
|
|
return;
|
|
}
|
|
|
|
for (const auto &item : animations) {
|
|
if (!item.is_object()) {
|
|
continue;
|
|
}
|
|
const json file = item.value("animation", json::object());
|
|
const std::int32_t file_id = safe_i32(file, "id");
|
|
if (file_id == 0) {
|
|
continue;
|
|
}
|
|
|
|
SavedAnimationInfo animation;
|
|
animation.file_id = file_id;
|
|
animation.name = safe_string(item, "file_name");
|
|
if (animation.name.empty()) {
|
|
animation.name = "animation";
|
|
}
|
|
animation.mime_type = safe_string(item, "mime_type");
|
|
animation.size_bytes = std::max(safe_i64(file, "size"), safe_i64(file, "expected_size"));
|
|
animation.downloaded_size = safe_i64(file.value("local", json::object()), "downloaded_size");
|
|
animation.duration = safe_i32(item, "duration");
|
|
animation.width = safe_i32(item, "width");
|
|
animation.height = safe_i32(item, "height");
|
|
animation.local_path = safe_string(file.value("local", json::object()), "path");
|
|
animation.is_downloading_active =
|
|
file.value("local", json::object()).value("is_downloading_active", false);
|
|
animation.can_be_downloaded =
|
|
file.value("local", json::object()).value("can_be_downloaded", false);
|
|
animation.can_be_deleted =
|
|
file.value("local", json::object()).value("can_be_deleted", false);
|
|
animation.is_downloaded =
|
|
file.value("local", json::object()).value("is_downloading_completed", false);
|
|
saved_animations_.push_back(std::move(animation));
|
|
}
|
|
|
|
if (saved_animation_selection_index_ < 0) {
|
|
saved_animation_selection_index_ = 0;
|
|
}
|
|
if (saved_animation_selection_index_ >= static_cast<int>(saved_animations_.size())) {
|
|
saved_animation_selection_index_ =
|
|
std::max(0, static_cast<int>(saved_animations_.size()) - 1);
|
|
}
|
|
saved_animations_loading_ = false;
|
|
saved_animations_loaded_ = true;
|
|
ensure_saved_animation_preview();
|
|
}
|
|
|
|
void App::ensure_saved_animation_preview() {
|
|
if (saved_animation_selection_index_ < 0 ||
|
|
saved_animation_selection_index_ >= static_cast<int>(saved_animations_.size())) {
|
|
return;
|
|
}
|
|
|
|
SavedAnimationInfo &animation =
|
|
saved_animations_[static_cast<std::size_t>(saved_animation_selection_index_)];
|
|
if (animation.file_id == 0 || animation.is_downloaded || animation.is_downloading_active ||
|
|
!animation.can_be_downloaded) {
|
|
return;
|
|
}
|
|
|
|
td_.send({
|
|
{"@type", "downloadFile"},
|
|
{"file_id", animation.file_id},
|
|
{"priority", 1},
|
|
{"offset", 0},
|
|
{"limit", 0},
|
|
{"synchronous", false},
|
|
});
|
|
}
|
|
|
|
void App::handle_td_object(const json &object) {
|
|
const std::string type = safe_string(object, "@type");
|
|
if (type == "updateAuthorizationState") {
|
|
authorization_state_ = object.value("authorization_state", json::object());
|
|
handle_authorization_state();
|
|
return;
|
|
}
|
|
if (type == "updateConnectionState") {
|
|
status_line_ = "Connection: " + safe_string(object.at("state"), "@type");
|
|
return;
|
|
}
|
|
if (type == "updateChatOnlineMemberCount") {
|
|
ChatInfo &chat = chats_[safe_i64(object, "chat_id")];
|
|
chat.id = safe_i64(object, "chat_id");
|
|
chat.online_member_count = safe_i32(object, "online_member_count");
|
|
chat.has_online_member_count = true;
|
|
return;
|
|
}
|
|
if (type == "updateUser") {
|
|
upsert_user(object.value("user", json::object()));
|
|
return;
|
|
}
|
|
if (type == "updateUserStatus") {
|
|
update_user_status(safe_i64(object, "user_id"),
|
|
object.value("status", json::object()));
|
|
return;
|
|
}
|
|
if (type == "updateBasicGroup" || type == "basicGroup") {
|
|
upsert_basic_group(type == "basicGroup"
|
|
? object
|
|
: object.value("basic_group", json::object()));
|
|
return;
|
|
}
|
|
if (type == "updateSupergroup" || type == "supergroup") {
|
|
upsert_supergroup(
|
|
type == "supergroup" ? object : object.value("supergroup", json::object()));
|
|
return;
|
|
}
|
|
if (type == "updateNewChat") {
|
|
upsert_chat(object.value("chat", json::object()));
|
|
return;
|
|
}
|
|
if (type == "updateChatTitle") {
|
|
ChatInfo &chat = chats_[safe_i64(object, "chat_id")];
|
|
chat.id = safe_i64(object, "chat_id");
|
|
chat.title = safe_string(object, "title");
|
|
resort_chats();
|
|
return;
|
|
}
|
|
if (type == "updateChatPosition") {
|
|
ChatInfo &chat = chats_[safe_i64(object, "chat_id")];
|
|
chat.id = safe_i64(object, "chat_id");
|
|
apply_chat_position(chat, object.value("position", json::object()));
|
|
resort_chats();
|
|
return;
|
|
}
|
|
if (type == "updateChatLastMessage") {
|
|
ChatInfo &chat = chats_[safe_i64(object, "chat_id")];
|
|
chat.id = safe_i64(object, "chat_id");
|
|
chat.last_message_preview =
|
|
preview_message(object.value("last_message", json::object()));
|
|
if (object.contains("positions") && object.at("positions").is_array()) {
|
|
chat.in_main_list = false;
|
|
chat.main_order = 0;
|
|
for (const auto &position : object.at("positions")) {
|
|
apply_chat_position(chat, position);
|
|
}
|
|
}
|
|
resort_chats();
|
|
return;
|
|
}
|
|
if (type == "updateChatReadInbox") {
|
|
ChatInfo &chat = chats_[safe_i64(object, "chat_id")];
|
|
chat.id = safe_i64(object, "chat_id");
|
|
chat.unread_count = safe_i32(object, "unread_count");
|
|
chat.last_read_inbox_message_id = safe_i64(object, "last_read_inbox_message_id");
|
|
return;
|
|
}
|
|
if (type == "updateChatReadOutbox") {
|
|
ChatInfo &chat = chats_[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");
|
|
return;
|
|
}
|
|
if (type == "updateNewMessage") {
|
|
const json message = object.value("message", json::object());
|
|
const std::int64_t chat_id = safe_i64(message, "chat_id");
|
|
if (chat_id == open_chat_id_ && message_scroll_ > 0) {
|
|
++message_scroll_;
|
|
}
|
|
const MessageInfo parsed = parse_message(message);
|
|
append_message(chat_id, parsed);
|
|
chats_[chat_id].last_message_preview = preview_message(message);
|
|
if (chat_id == open_chat_id_ && !parsed.is_outgoing) {
|
|
mark_message_as_read(chat_id, parsed.id);
|
|
}
|
|
return;
|
|
}
|
|
if (type == "updateMessageContent") {
|
|
const std::int64_t chat_id = safe_i64(object, "chat_id");
|
|
const std::int64_t message_id = safe_i64(object, "message_id");
|
|
auto chat_it = chats_.find(chat_id);
|
|
if (chat_it == chats_.end()) {
|
|
return;
|
|
}
|
|
for (auto &message : chat_it->second.messages) {
|
|
if (message.id == message_id) {
|
|
const json content = object.value("new_content", json::object());
|
|
message.text = content_to_text(content, true);
|
|
if (const auto attachment = parse_attachment(content);
|
|
attachment.has_value()) {
|
|
message.has_attachment = true;
|
|
message.attachment = *attachment;
|
|
} else {
|
|
message.has_attachment = false;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
if (type == "updateDeleteMessages") {
|
|
const std::int64_t chat_id = safe_i64(object, "chat_id");
|
|
auto chat_it = chats_.find(chat_id);
|
|
if (chat_it == chats_.end()) {
|
|
return;
|
|
}
|
|
std::set<std::int64_t> deleted;
|
|
for (const auto &id : object.value("message_ids", json::array())) {
|
|
if (id.is_number_integer()) {
|
|
deleted.insert(id.get<std::int64_t>());
|
|
}
|
|
}
|
|
std::vector<MessageInfo> kept;
|
|
kept.reserve(chat_it->second.messages.size());
|
|
for (const auto &message : chat_it->second.messages) {
|
|
if (deleted.find(message.id) == deleted.end()) {
|
|
kept.push_back(message);
|
|
}
|
|
}
|
|
chat_it->second.messages = std::move(kept);
|
|
return;
|
|
}
|
|
if (type == "updateFile") {
|
|
update_attachment_file(object.value("file", json::object()));
|
|
return;
|
|
}
|
|
if (type == "updateSavedAnimations") {
|
|
request_saved_animations(true);
|
|
return;
|
|
}
|
|
if (type == "updateOption" || type == "ok" || type == "userFullInfo" ||
|
|
type == "updateHavePendingNotifications" || type == "updateUnreadMessageCount" ||
|
|
type == "updateUnreadChatCount") {
|
|
return;
|
|
}
|
|
if (type == "error") {
|
|
const std::string extra = safe_string(object, "@extra");
|
|
const std::string message = safe_string(object, "message");
|
|
if (extra.rfind("history:", 0) == 0) {
|
|
const auto chat_id = static_cast<std::int64_t>(std::stoll(extra.substr(8)));
|
|
chats_[chat_id].history_loading = false;
|
|
status_line_ = "History unavailable: " + message;
|
|
return;
|
|
}
|
|
status_line_ = "TDLib error: " + message;
|
|
return;
|
|
}
|
|
if (type == "user") {
|
|
upsert_user(object);
|
|
return;
|
|
}
|
|
if (type == "chat") {
|
|
upsert_chat(object);
|
|
return;
|
|
}
|
|
if (type == "chats") {
|
|
const std::string extra = safe_string(object, "@extra");
|
|
if (extra == "main_chats") {
|
|
sync_chat_ids_from_response(object);
|
|
}
|
|
return;
|
|
}
|
|
if (type == "messages") {
|
|
const std::string extra = safe_string(object, "@extra");
|
|
if (extra.rfind("history:", 0) == 0) {
|
|
const auto chat_id = static_cast<std::int64_t>(std::stoll(extra.substr(8)));
|
|
merge_history(chat_id, object.value("messages", json::array()));
|
|
}
|
|
return;
|
|
}
|
|
if (type == "animations") {
|
|
const std::string extra = safe_string(object, "@extra");
|
|
if (extra == "saved_animations") {
|
|
sync_saved_animations(object.value("animations", json::array()));
|
|
if (saved_animation_menu_open_) {
|
|
status_line_ = saved_animations_.empty() ? "No saved GIFs." : "Saved GIFs.";
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
if (type == "updateMessageSendSucceeded") {
|
|
const json message = object.value("message", json::object());
|
|
const std::int64_t chat_id = safe_i64(message, "chat_id");
|
|
remove_message(chat_id, safe_i64(object, "old_message_id"));
|
|
append_message(chat_id, parse_message(message));
|
|
chats_[chat_id].last_message_preview = preview_message(message);
|
|
status_line_ = "Message sent.";
|
|
return;
|
|
}
|
|
|
|
const std::string extra = safe_string(object, "@extra");
|
|
if (extra == "getMe" && object.is_object()) {
|
|
my_user_id_ = safe_i64(object, "id");
|
|
}
|
|
}
|
|
|
|
void App::request_more_chats() {
|
|
td_.send({
|
|
{"@type", "getChats"},
|
|
{"chat_list", {{"@type", "chatListMain"}}},
|
|
{"limit", kChatPageSize},
|
|
{"@extra", "main_chats"},
|
|
});
|
|
status_line_ = "Loading chats...";
|
|
}
|
|
|
|
bool App::request_chat_history(std::int64_t chat_id, bool force) {
|
|
ChatInfo &chat = chats_[chat_id];
|
|
chat.id = chat_id;
|
|
if (chat.history_loading && !force) {
|
|
return false;
|
|
}
|
|
chat.history_loading = true;
|
|
td_.send({
|
|
{"@type", "getChatHistory"},
|
|
{"chat_id", chat_id},
|
|
{"from_message_id", 0},
|
|
{"offset", 0},
|
|
{"limit", kHistoryBatchSize},
|
|
{"only_local", false},
|
|
{"@extra", "history:" + std::to_string(chat_id)},
|
|
});
|
|
return true;
|
|
}
|
|
|
|
bool App::request_open_chat_history(bool force) {
|
|
const auto chat_id = open_chat_id();
|
|
if (!chat_id.has_value()) {
|
|
return false;
|
|
}
|
|
request_chat_details(*chat_id);
|
|
const bool requested = request_chat_history(*chat_id, force);
|
|
if (requested) {
|
|
status_line_ = force ? "Reloading chat history..." : "Loading chat history...";
|
|
}
|
|
return requested;
|
|
}
|
|
|
|
void App::mark_chat_messages_as_read(std::int64_t chat_id) {
|
|
auto chat_it = chats_.find(chat_id);
|
|
if (chat_it == chats_.end()) {
|
|
return;
|
|
}
|
|
|
|
std::vector<std::int64_t> unread_message_ids;
|
|
unread_message_ids.reserve(chat_it->second.messages.size());
|
|
for (const auto &message : chat_it->second.messages) {
|
|
if (message.is_outgoing || message.id == 0) {
|
|
continue;
|
|
}
|
|
if (message.id <= chat_it->second.last_read_inbox_message_id) {
|
|
continue;
|
|
}
|
|
unread_message_ids.push_back(message.id);
|
|
}
|
|
|
|
if (!unread_message_ids.empty()) {
|
|
td_.send({
|
|
{"@type", "viewMessages"},
|
|
{"chat_id", chat_id},
|
|
{"message_ids", unread_message_ids},
|
|
{"source", {{"@type", "messageSourceChatHistory"}}},
|
|
{"force_read", true},
|
|
});
|
|
}
|
|
|
|
td_.send({
|
|
{"@type", "toggleChatIsMarkedAsUnread"},
|
|
{"chat_id", chat_id},
|
|
{"is_marked_as_unread", false},
|
|
});
|
|
}
|
|
|
|
void App::mark_message_as_read(std::int64_t chat_id, std::int64_t message_id) {
|
|
if (chat_id == 0 || message_id == 0) {
|
|
return;
|
|
}
|
|
|
|
td_.send({
|
|
{"@type", "viewMessages"},
|
|
{"chat_id", chat_id},
|
|
{"message_ids", json::array({message_id})},
|
|
{"source", {{"@type", "messageSourceChatHistory"}}},
|
|
{"force_read", true},
|
|
});
|
|
}
|
|
|
|
void App::set_open_chat(std::int64_t chat_id) {
|
|
if (chat_id == 0) {
|
|
return;
|
|
}
|
|
|
|
const bool changed_chat = open_chat_id_ != chat_id;
|
|
ChatInfo &chat = chats_[chat_id];
|
|
chat.id = chat_id;
|
|
if (tdlib_open_chat_id_ != 0 && tdlib_open_chat_id_ != chat_id) {
|
|
td_.send({
|
|
{"@type", "closeChat"},
|
|
{"chat_id", tdlib_open_chat_id_},
|
|
});
|
|
}
|
|
|
|
open_chat_id_ = chat_id;
|
|
message_scroll_ = 0;
|
|
if (changed_chat) {
|
|
message_attachment_message_id_ = 0;
|
|
}
|
|
|
|
if (tdlib_open_chat_id_ != chat_id) {
|
|
td_.send({
|
|
{"@type", "openChat"},
|
|
{"chat_id", chat_id},
|
|
});
|
|
tdlib_open_chat_id_ = chat_id;
|
|
}
|
|
|
|
mark_chat_messages_as_read(chat_id);
|
|
|
|
if (changed_chat) {
|
|
request_chat_details(chat_id);
|
|
const bool should_request_history =
|
|
auto_reload_chat_history_ || !chat.history_loaded || chat.messages.empty();
|
|
const bool requested = should_request_history &&
|
|
request_chat_history(chat_id, auto_reload_chat_history_);
|
|
if (requested) {
|
|
status_line_ = auto_reload_chat_history_ && chat.history_loaded
|
|
? "Reloading chat history..."
|
|
: "Loading chat history...";
|
|
}
|
|
}
|
|
}
|
|
|
|
void App::sync_chat_ids_from_response(const json &response) {
|
|
if (!response.contains("chat_ids") || !response.at("chat_ids").is_array()) {
|
|
status_line_ = "Chat list response missing chat ids.";
|
|
return;
|
|
}
|
|
|
|
std::vector<std::int64_t> chat_ids;
|
|
for (const auto &entry : response.at("chat_ids")) {
|
|
if (!entry.is_number_integer()) {
|
|
continue;
|
|
}
|
|
const auto chat_id = entry.get<std::int64_t>();
|
|
chat_ids.push_back(chat_id);
|
|
if (chats_.find(chat_id) == chats_.end()) {
|
|
td_.send({
|
|
{"@type", "getChat"},
|
|
{"chat_id", chat_id},
|
|
});
|
|
}
|
|
}
|
|
|
|
if (!chat_ids.empty()) {
|
|
sorted_chat_ids_ = std::move(chat_ids);
|
|
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);
|
|
}
|
|
if (!open_chat_id().has_value()) {
|
|
const auto chat_id = highlighted_chat_id();
|
|
if (chat_id.has_value()) {
|
|
set_open_chat(*chat_id);
|
|
}
|
|
}
|
|
request_open_chat_history(false);
|
|
status_line_ = "Chats loaded.";
|
|
return;
|
|
}
|
|
|
|
status_line_ = "No chats loaded.";
|
|
}
|
|
|
|
void App::append_message(std::int64_t chat_id, MessageInfo message) {
|
|
ChatInfo &chat = chats_[chat_id];
|
|
chat.id = chat_id;
|
|
auto existing =
|
|
std::find_if(chat.messages.begin(), chat.messages.end(),
|
|
[&](const MessageInfo &item) { return item.id == message.id; });
|
|
if (existing != chat.messages.end()) {
|
|
*existing = std::move(message);
|
|
} else {
|
|
chat.messages.push_back(std::move(message));
|
|
}
|
|
|
|
std::sort(chat.messages.begin(), chat.messages.end(),
|
|
[](const MessageInfo &lhs, const MessageInfo &rhs) {
|
|
if (lhs.date != rhs.date) {
|
|
return lhs.date < rhs.date;
|
|
}
|
|
return lhs.id < rhs.id;
|
|
});
|
|
|
|
if (kMaxMessagesPerChat > 0 && chat.messages.size() > kMaxMessagesPerChat) {
|
|
chat.messages.erase(chat.messages.begin(),
|
|
chat.messages.begin() +
|
|
static_cast<std::ptrdiff_t>(chat.messages.size() -
|
|
kMaxMessagesPerChat));
|
|
}
|
|
}
|
|
|
|
void App::remove_message(std::int64_t chat_id, std::int64_t message_id) {
|
|
if (message_id == 0) {
|
|
return;
|
|
}
|
|
|
|
auto chat_it = chats_.find(chat_id);
|
|
if (chat_it == chats_.end()) {
|
|
return;
|
|
}
|
|
|
|
auto &messages = chat_it->second.messages;
|
|
messages.erase(
|
|
std::remove_if(messages.begin(), messages.end(),
|
|
[&](const MessageInfo &item) { return item.id == message_id; }),
|
|
messages.end());
|
|
}
|
|
|
|
void App::merge_history(std::int64_t chat_id, const json &messages) {
|
|
ChatInfo &chat = chats_[chat_id];
|
|
chat.history_loading = false;
|
|
chat.history_loaded = true;
|
|
for (const auto &message : messages) {
|
|
append_message(chat_id, parse_message(message));
|
|
}
|
|
if (chat_id == open_chat_id_) {
|
|
mark_chat_messages_as_read(chat_id);
|
|
}
|
|
status_line_ = "History loaded.";
|
|
}
|
|
|
|
void App::update_attachment_file(const json &file) {
|
|
const std::int32_t file_id = safe_i32(file, "id");
|
|
if (file_id == 0) {
|
|
return;
|
|
}
|
|
|
|
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 std::string local_path = safe_string(local, "path");
|
|
const std::int64_t downloaded_size = safe_i64(local, "downloaded_size");
|
|
const bool is_downloading_active = local.value("is_downloading_active", false);
|
|
const bool is_downloaded = local.value("is_downloading_completed", false);
|
|
const bool can_be_downloaded = local.value("can_be_downloaded", false);
|
|
const bool can_be_deleted = local.value("can_be_deleted", false);
|
|
|
|
for (auto &[chat_id, chat] : chats_) {
|
|
(void)chat_id;
|
|
for (auto &message : chat.messages) {
|
|
if (!message.has_attachment || message.attachment.file_id != file_id) {
|
|
continue;
|
|
}
|
|
if (size_bytes > 0) {
|
|
message.attachment.size_bytes = size_bytes;
|
|
}
|
|
message.attachment.downloaded_size = downloaded_size;
|
|
message.attachment.local_path = local_path;
|
|
message.attachment.is_downloading_active = is_downloading_active;
|
|
message.attachment.is_downloaded = is_downloaded;
|
|
message.attachment.can_be_downloaded = can_be_downloaded;
|
|
message.attachment.can_be_deleted = can_be_deleted;
|
|
}
|
|
}
|
|
|
|
for (auto &animation : saved_animations_) {
|
|
if (animation.file_id != file_id) {
|
|
continue;
|
|
}
|
|
if (size_bytes > 0) {
|
|
animation.size_bytes = size_bytes;
|
|
}
|
|
animation.downloaded_size = downloaded_size;
|
|
animation.local_path = local_path;
|
|
animation.is_downloading_active = is_downloading_active;
|
|
animation.is_downloaded = is_downloaded;
|
|
animation.can_be_downloaded = can_be_downloaded;
|
|
animation.can_be_deleted = can_be_deleted;
|
|
}
|
|
|
|
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_->downloaded_size = downloaded_size;
|
|
pending_attachment_open_->local_path = local_path;
|
|
pending_attachment_open_->is_downloading_active = is_downloading_active;
|
|
pending_attachment_open_->is_downloaded = is_downloaded;
|
|
pending_attachment_open_->can_be_downloaded = can_be_downloaded;
|
|
pending_attachment_open_->can_be_deleted = can_be_deleted;
|
|
if (!is_downloaded && is_downloading_active) {
|
|
status_line_ =
|
|
"Downloading attachment to open " +
|
|
format_download_progress(pending_attachment_open_->downloaded_size,
|
|
pending_attachment_open_->size_bytes,
|
|
pending_attachment_open_->is_downloaded);
|
|
}
|
|
if (is_downloaded && !local_path.empty()) {
|
|
open_attachment(*pending_attachment_open_);
|
|
pending_attachment_open_.reset();
|
|
}
|
|
}
|
|
|
|
if (pending_attachment_download_.has_value() &&
|
|
pending_attachment_download_->file_id == file_id) {
|
|
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_->local_path = local_path;
|
|
pending_attachment_download_->is_downloading_active = is_downloading_active;
|
|
pending_attachment_download_->is_downloaded = is_downloaded;
|
|
pending_attachment_download_->can_be_downloaded = can_be_downloaded;
|
|
pending_attachment_download_->can_be_deleted = can_be_deleted;
|
|
if (!is_downloaded && is_downloading_active) {
|
|
status_line_ = "Downloading attachment to ~/Downloads " +
|
|
format_download_progress(
|
|
pending_attachment_download_->downloaded_size,
|
|
pending_attachment_download_->size_bytes,
|
|
pending_attachment_download_->is_downloaded);
|
|
}
|
|
if (is_downloaded && !local_path.empty()) {
|
|
export_attachment_to_downloads(*pending_attachment_download_);
|
|
pending_attachment_download_.reset();
|
|
}
|
|
}
|
|
}
|
|
|
|
} // namespace telegram_tui
|