This commit is contained in:
2026-04-23 17:00:41 +03:00
commit ac28065d2a
17 changed files with 5401 additions and 0 deletions

186
src/app.h Normal file
View File

@@ -0,0 +1,186 @@
#pragma once
#include <cstdint>
#include <chrono>
#include <filesystem>
#include <map>
#include <optional>
#include <tuple>
#include <string>
#include <vector>
#include "json.h"
#include "models.h"
#include "td_client.h"
namespace telegram_tui {
class App {
public:
App();
int run();
private:
void init_curses();
void shutdown_curses();
bool process_updates();
void handle_td_object(const json& object);
void handle_authorization_state();
void send_tdlib_parameters();
void send_check_phone_number();
void persist_config();
void request_chat_details(std::int64_t chat_id);
void set_open_chat(std::int64_t chat_id);
void open_forward_target_menu(std::int64_t source_chat_id, std::vector<std::int64_t> message_ids);
void start_input(InputMode mode, std::string prompt, bool hidden);
void clear_input();
void submit_input();
void send_message(std::int64_t chat_id, const std::string& text, std::optional<std::int64_t> reply_to_message_id = std::nullopt);
void forward_message(
std::int64_t source_chat_id,
const std::vector<std::int64_t>& message_ids,
std::int64_t target_chat_id);
void send_photo_message(
std::int64_t chat_id,
const std::string& photo_path,
const std::string& caption,
std::optional<std::int64_t> reply_to_message_id = std::nullopt);
bool preview_clipboard_photo_message(
std::int64_t chat_id,
const std::string& caption,
std::optional<std::int64_t> reply_to_message_id = std::nullopt);
void request_more_chats();
bool request_chat_history(std::int64_t chat_id, bool force);
bool request_open_chat_history(bool force);
void sync_chat_ids_from_response(const json& response);
void mark_chat_messages_as_read(std::int64_t chat_id);
void mark_message_as_read(std::int64_t chat_id, std::int64_t message_id);
void update_user_status(std::int64_t user_id, const json& status);
void upsert_user(const json& user);
void upsert_basic_group(const json& basic_group);
void upsert_supergroup(const json& supergroup);
void upsert_chat(const json& chat_object);
void apply_chat_position(ChatInfo& chat, const json& position);
void resort_chats();
void append_message(std::int64_t chat_id, MessageInfo message);
void remove_message(std::int64_t chat_id, std::int64_t message_id);
void merge_history(std::int64_t chat_id, const json& messages);
void update_attachment_file(const json& file);
void start_reply_to_latest_message();
void request_attachment_download(const AttachmentInfo& attachment, bool open_after_download);
void open_attachment(const AttachmentInfo& attachment);
void download_attachment(const AttachmentInfo& attachment);
void delete_attachment(const AttachmentInfo& attachment);
bool export_attachment_to_downloads(const AttachmentInfo& attachment);
bool play_video_attachment(const AttachmentInfo& attachment);
void refresh_attachment_viewer_content(const AttachmentInfo& attachment);
[[nodiscard]] std::vector<std::string> attachment_animation_frames(const AttachmentInfo& attachment) const;
bool advance_attachment_animation();
[[nodiscard]] std::string attachment_preview_path(const AttachmentInfo& attachment) const;
[[nodiscard]] bool has_inline_attachment_preview(const AttachmentInfo& attachment, int width, int height) const;
void clear_attachment_preview_graphics();
void render_attachment_preview_graphics(int top, int left, int width, int height);
void reset_attachment_viewer_send_preview();
[[nodiscard]] std::vector<std::int64_t> forward_target_chat_ids() const;
[[nodiscard]] std::optional<AttachmentInfo> selected_attachment() const;
[[nodiscard]] std::string render_attachment_preview(const AttachmentInfo& attachment, int width, int height) const;
[[nodiscard]] std::string build_attachment_preview_graphics(const AttachmentInfo& attachment, int width, int height) const;
[[nodiscard]] std::tuple<bool, std::int64_t, std::string> parse_compose_command(const std::string& value) const;
[[nodiscard]] std::optional<std::vector<std::int64_t>> parse_forward_command(const std::string& value) const;
[[nodiscard]] std::optional<std::size_t> find_message_index(const ChatInfo& chat, std::int64_t message_id) const;
[[nodiscard]] std::string format_message_ref(const ChatInfo& chat, std::int64_t message_id) const;
[[nodiscard]] std::string sender_label(const json& sender) const;
[[nodiscard]] std::string user_status_label(std::int64_t user_id) const;
[[nodiscard]] std::string forward_origin_label(const json& forward_info) const;
[[nodiscard]] std::string via_bot_label(std::int64_t via_bot_user_id) const;
[[nodiscard]] std::string preview_message(const json& message) const;
[[nodiscard]] std::optional<AttachmentInfo> parse_attachment(const json& content) const;
[[nodiscard]] std::string content_to_text(const json& content, bool decorate) const;
[[nodiscard]] MessageInfo parse_message(const json& message) const;
[[nodiscard]] std::string format_open_chat_header(const ChatInfo& chat) const;
void handle_key(int ch);
void handle_wide_char(wint_t ch);
void handle_input_key(int ch);
void handle_forward_target_menu_key(int ch);
void handle_help_menu_key(int ch);
void handle_attachments_menu_key(int ch);
void handle_attachment_action_menu_key(int ch);
void handle_attachment_viewer_key(int ch);
void draw();
void init_colors();
void draw_chat_pane(int top, int height, int width);
void draw_message_pane(int top, int height, int left, int width);
void draw_help_menu(int height, int width);
void draw_forward_target_menu(int height, int width);
void draw_attachments_menu(int height, int width);
void draw_attachment_action_menu(int height, int width);
void draw_attachment_viewer(int height, int width);
[[nodiscard]] std::optional<std::int64_t> highlighted_chat_id() const;
[[nodiscard]] std::optional<std::int64_t> open_chat_id() const;
[[nodiscard]] std::string current_auth_label() const;
TdClient td_;
std::map<std::int64_t, UserInfo> users_;
std::map<std::int64_t, ChatInfo> chats_;
std::vector<std::int64_t> sorted_chat_ids_;
std::filesystem::path database_dir_;
std::filesystem::path files_dir_;
bool running_ = true;
bool authorized_ = false;
bool attachments_menu_open_ = false;
bool attachment_action_menu_open_ = false;
bool attachment_viewer_open_ = false;
bool forward_target_menu_open_ = false;
bool help_menu_open_ = false;
bool input_hidden_ = false;
bool auto_reload_chat_history_ = false;
bool use_test_dc_ = false;
FocusPane focus_ = FocusPane::Chats;
InputMode input_mode_ = InputMode::None;
int selected_chat_index_ = 0;
int message_scroll_ = 0;
int attachment_category_index_ = 0;
int attachment_selection_index_ = 0;
int attachment_action_index_ = 0;
int attachment_viewer_scroll_ = 0;
int forward_target_index_ = 0;
std::int64_t open_chat_id_ = 0;
std::int64_t tdlib_open_chat_id_ = 0;
std::int64_t my_user_id_ = 0;
std::int64_t forward_source_chat_id_ = 0;
std::size_t input_cursor_ = 0;
std::string api_id_;
std::string api_hash_;
std::string phone_number_;
std::string pending_first_name_;
std::string input_prompt_;
std::string input_buffer_;
std::string status_line_ = "Starting TDLib...";
std::string attachment_preview_graphics_data_;
std::string attachment_viewer_title_;
std::string attachment_preview_signature_;
std::vector<std::string> attachment_viewer_lines_;
std::vector<std::string> attachment_viewer_animation_frames_;
json authorization_state_ = json::object();
std::optional<AttachmentInfo> pending_attachment_open_;
std::optional<AttachmentInfo> pending_attachment_download_;
std::optional<AttachmentInfo> attachment_viewer_attachment_;
std::optional<std::int64_t> attachment_viewer_send_reply_to_message_id_;
std::chrono::steady_clock::time_point attachment_viewer_next_frame_at_{};
std::int64_t attachment_viewer_send_chat_id_ = 0;
bool attachment_preview_graphics_visible_ = false;
bool attachment_preview_graphics_is_sixel_ = false;
bool attachment_viewer_send_on_enter_ = false;
bool attachment_viewer_is_animated_ = false;
std::size_t attachment_viewer_frame_index_ = 0;
std::string attachment_viewer_send_caption_;
std::vector<std::int64_t> forward_message_ids_;
};
} // namespace telegram_tui