use super::component::MessageDetails;
use crate::theme::ThemeManager;
use tuirealm::{
Frame,
ratatui::{
layout::{Alignment, Rect},
style::{Color, Modifier, Style},
text::{Line, Span},
widgets::{Block, BorderType, Borders, Paragraph, Wrap},
},
};
pub fn render_message_details(details: &mut MessageDetails, frame: &mut Frame, area: Rect) {
let content_height = area.height.saturating_sub(2); let visible_lines = content_height as usize;
details.visible_lines = visible_lines;
let content_lines = create_content_lines(details, visible_lines);
let block = create_block(details);
let paragraph = Paragraph::new(content_lines)
.block(block)
.wrap(Wrap { trim: false });
frame.render_widget(paragraph, area);
let status_bar = create_status_bar(details);
let status_area = calculate_status_area(area);
frame.render_widget(status_bar, status_area);
}
fn create_block(details: &MessageDetails) -> Block {
let border_color = if details.is_focused {
if details.is_editing {
Color::Red } else {
ThemeManager::primary_accent() }
} else {
Color::White };
let title = if details.is_editing {
if details.is_dirty {
" ✏️ Message Details - EDITING (modified) "
} else {
" ✏️ Message Details - EDITING "
}
} else {
" 📄 Message Details "
};
Block::default()
.borders(Borders::ALL)
.border_type(BorderType::Rounded)
.border_style(Style::default().fg(border_color))
.title(title)
.title_alignment(Alignment::Center)
.title_style(
Style::default()
.fg(ThemeManager::title_accent())
.add_modifier(Modifier::BOLD),
)
}
fn create_content_lines(details: &MessageDetails, visible_lines: usize) -> Vec<Line> {
let mut lines = Vec::new();
let start = details.scroll_offset;
let end = (start + visible_lines).min(details.message_content.len());
for (display_line, line_idx) in (start..end).enumerate() {
if let Some(content) = details.message_content.get(line_idx) {
let line = create_single_line(details, content, display_line);
lines.push(line);
}
}
while lines.len() < visible_lines {
lines.push(Line::from(""));
}
lines
}
fn create_single_line<'a>(
details: &MessageDetails,
content: &'a str,
display_line: usize,
) -> Line<'a> {
let is_cursor_line = details.is_focused && display_line == details.cursor_line;
if is_cursor_line {
Line::from(create_cursor_highlighted_spans(details, content))
} else {
Line::from(content)
}
}
fn create_cursor_highlighted_spans<'a>(
details: &MessageDetails,
content: &'a str,
) -> Vec<Span<'a>> {
let mut spans = Vec::new();
let cursor_pos = details.cursor_col;
let (before_cursor, at_and_after_cursor) = content.split_at(cursor_pos.min(content.len()));
if !before_cursor.is_empty() {
spans.push(Span::styled(
before_cursor,
Style::default().fg(ThemeManager::text_primary()),
));
}
if let Some(cursor_char) = at_and_after_cursor.chars().next() {
spans.push(Span::styled(
cursor_char.to_string(),
Style::default()
.bg(ThemeManager::selection_bg()) .fg(ThemeManager::selection_fg())
.add_modifier(Modifier::REVERSED),
));
let after_cursor = &at_and_after_cursor[cursor_char.len_utf8()..];
if !after_cursor.is_empty() {
spans.push(Span::styled(
after_cursor,
Style::default().fg(ThemeManager::text_primary()),
));
}
} else {
spans.push(Span::styled(
" ",
Style::default()
.bg(ThemeManager::selection_bg())
.fg(ThemeManager::selection_fg())
.add_modifier(Modifier::REVERSED),
));
}
spans
}
fn create_status_bar(details: &MessageDetails) -> Paragraph {
let status_text = if details.is_editing {
let keys = crate::config::get_config_or_panic().keys();
let repeat_info = if let Some(count) = details.repeat_count {
if count == 1 {
" | Will send 1 time".to_string()
} else {
format!(" | Will send {count} times")
}
} else {
String::new()
};
format!(
"Ln {}, Col {} | EDIT MODE{} | Ctrl+{}: Send | Ctrl+{}: Replace | ESC: Cancel",
details.cursor_line + details.scroll_offset + 1,
details.cursor_col + 1,
repeat_info,
keys.send_edited_message(),
keys.replace_edited_message()
)
} else {
format!(
"Ln {}, Col {} | Press 'e' or 'i' to edit | ESC: Back to messages",
details.cursor_line + details.scroll_offset + 1,
details.cursor_col + 1
)
};
Paragraph::new(status_text)
.style(
Style::default().fg(if details.is_focused {
if details.is_editing {
Color::Red } else {
ThemeManager::primary_accent() }
} else {
Color::White }), )
.alignment(Alignment::Center)
}
fn calculate_status_area(area: Rect) -> Rect {
Rect {
x: area.x,
y: area.y + area.height.saturating_sub(1),
width: area.width,
height: 1,
}
}