//! Compose bar / input box rendering use crate::app::App; use crate::app::InputMode; use crate::app::methods::{compose::ComposeMethods, messages::MessageMethods}; use crate::tdlib::TdClientTrait; use crate::ui::components; use ratatui::{ layout::Rect, style::{Color, Modifier, Style}, text::{Line, Span}, widgets::{Block, Borders, Paragraph}, Frame, }; /// Renders input field with cursor at the specified position fn render_input_with_cursor( prefix: &str, text: &str, cursor_pos: usize, color: Color, ) -> Line<'static> { components::render_input_field(prefix, text, cursor_pos, color) } /// Renders input box with support for different modes (forward/select/edit/reply/normal) pub fn render(f: &mut Frame, area: Rect, app: &App) { let (input_line, input_title): (Line, &str) = if app.is_forwarding() { // Режим пересылки - показываем превью сообщения let forward_preview = app .get_forwarding_message() .map(|m| { let text_preview: String = m.text().chars().take(40).collect(); let ellipsis = if m.text().chars().count() > 40 { "..." } else { "" }; format!("↪ {}{}", text_preview, ellipsis) }) .unwrap_or_else(|| "↪ ...".to_string()); let line = Line::from(Span::styled(forward_preview, Style::default().fg(Color::Cyan))); (line, " Выберите чат ← ") } else if app.is_selecting_message() { // Режим выбора сообщения - подсказка зависит от возможностей let selected_msg = app.get_selected_message(); let can_edit = selected_msg .as_ref() .map(|m| m.can_be_edited() && m.is_outgoing()) .unwrap_or(false); let can_delete = selected_msg .as_ref() .map(|m| m.can_be_deleted_only_for_self() || m.can_be_deleted_for_all_users()) .unwrap_or(false); let hint = match (can_edit, can_delete) { (true, true) => "↑↓ · Enter ред. · r ответ · f перслть · y копир. · d удал. · Esc", (true, false) => "↑↓ · Enter ред. · r ответ · f переслть · y копир. · Esc", (false, true) => "↑↓ · r ответ · f переслать · y копир. · d удалить · Esc", (false, false) => "↑↓ · r ответить · f переслать · y копировать · Esc", }; ( Line::from(Span::styled(hint, Style::default().fg(Color::Cyan))), " Выбор сообщения ", ) } else if app.is_editing() { // Режим редактирования if app.message_input.is_empty() { let line = Line::from(vec![ Span::raw("✏ "), Span::styled("█", Style::default().fg(Color::Magenta)), Span::styled(" Введите новый текст...", Style::default().fg(Color::Gray)), ]); (line, " Редактирование (Esc отмена) ") } else { let line = render_input_with_cursor( "✏ ", &app.message_input, app.cursor_position, Color::Magenta, ); (line, " Редактирование (Esc отмена) ") } } else if app.is_replying() { // Режим ответа на сообщение let reply_preview = app .get_replying_to_message() .map(|m| { let sender = if m.is_outgoing() { "Вы" } else { m.sender_name() }; let text_preview: String = m.text().chars().take(30).collect(); let ellipsis = if m.text().chars().count() > 30 { "..." } else { "" }; format!("{}: {}{}", sender, text_preview, ellipsis) }) .unwrap_or_else(|| "...".to_string()); if app.message_input.is_empty() { let line = Line::from(vec![ Span::styled("↪ ", Style::default().fg(Color::Cyan)), Span::styled(reply_preview, Style::default().fg(Color::Gray)), Span::raw(" "), Span::styled("█", Style::default().fg(Color::Yellow)), ]); (line, " Ответ (Esc отмена) ") } else { let short_preview: String = reply_preview.chars().take(15).collect(); let prefix = format!("↪ {} > ", short_preview); let line = render_input_with_cursor( &prefix, &app.message_input, app.cursor_position, Color::Yellow, ); (line, " Ответ (Esc отмена) ") } } else if app.input_mode == InputMode::Normal { // Normal mode — dim, no cursor if app.message_input.is_empty() { let line = Line::from(vec![ Span::styled("> Press i to type...", Style::default().fg(Color::DarkGray)), ]); (line, "") } else { let draft_preview: String = app.message_input.chars().take(60).collect(); let ellipsis = if app.message_input.chars().count() > 60 { "..." } else { "" }; let line = Line::from(Span::styled( format!("> {}{}", draft_preview, ellipsis), Style::default().fg(Color::DarkGray), )); (line, "") } } else { // Insert mode — active, with cursor if app.message_input.is_empty() { let line = Line::from(vec![ Span::raw("> "), Span::styled("█", Style::default().fg(Color::Yellow)), Span::styled(" Введите сообщение...", Style::default().fg(Color::Gray)), ]); (line, "") } else { let line = render_input_with_cursor( "> ", &app.message_input, app.cursor_position, Color::Yellow, ); (line, "") } }; let input_block = if input_title.is_empty() { let border_style = if app.input_mode == InputMode::Insert { Style::default().fg(Color::Green) } else { Style::default().fg(Color::DarkGray) }; Block::default().borders(Borders::ALL).border_style(border_style) } else { let title_color = if app.is_replying() || app.is_forwarding() { Color::Cyan } else { Color::Magenta }; Block::default() .borders(Borders::ALL) .title(input_title) .title_style( Style::default() .fg(title_color) .add_modifier(Modifier::BOLD), ) }; let input = Paragraph::new(input_line) .block(input_block) .wrap(ratatui::widgets::Wrap { trim: false }); f.render_widget(input, area); }