#pragma once #include #include #include #include #include #include #include #include #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 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 reply_to_message_id = std::nullopt); void forward_message( std::int64_t source_chat_id, const std::vector& 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 reply_to_message_id = std::nullopt); bool preview_clipboard_photo_message( std::int64_t chat_id, const std::string& caption, std::optional 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 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 forward_target_chat_ids() const; [[nodiscard]] std::optional 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 parse_compose_command(const std::string& value) const; [[nodiscard]] std::optional> parse_forward_command(const std::string& value) const; [[nodiscard]] std::optional 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 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 highlighted_chat_id() const; [[nodiscard]] std::optional open_chat_id() const; [[nodiscard]] std::string current_auth_label() const; TdClient td_; std::map users_; std::map chats_; std::vector 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 attachment_viewer_lines_; std::vector attachment_viewer_animation_frames_; json authorization_state_ = json::object(); std::optional pending_attachment_open_; std::optional pending_attachment_download_; std::optional attachment_viewer_attachment_; std::optional 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 forward_message_ids_; }; } // namespace telegram_tui