mxr_tui/ui/
subscriptions_page.rs1use crate::app::{ActivePane, SubscriptionEntry};
2use crate::theme::Theme;
3use ratatui::prelude::*;
4use ratatui::widgets::*;
5
6pub struct SubscriptionsPageView<'a> {
7 pub entries: &'a [SubscriptionEntry],
8 pub selected_index: usize,
9 pub scroll_offset: usize,
10 pub active_pane: &'a ActivePane,
11 pub preview_blocks: &'a [crate::ui::message_view::ThreadMessageBlock],
12 pub message_scroll_offset: u16,
13}
14
15pub fn draw(frame: &mut Frame, area: Rect, view: &SubscriptionsPageView<'_>, theme: &Theme) {
16 let chunks = Layout::default()
17 .direction(Direction::Horizontal)
18 .constraints([Constraint::Percentage(42), Constraint::Percentage(58)])
19 .split(area);
20
21 let is_focused = *view.active_pane == ActivePane::MailList;
22 let border_style = theme.border_style(is_focused);
23
24 let items = view
25 .entries
26 .iter()
27 .map(|entry| {
28 let label = entry
29 .summary
30 .sender_name
31 .as_deref()
32 .filter(|name| !name.trim().is_empty())
33 .unwrap_or(entry.summary.sender_email.as_str());
34 let count = entry.summary.message_count.to_string();
35 let width = chunks[0].width.saturating_sub(4) as usize;
36 let name_part = format!(
37 " {}",
38 truncate(label, width.saturating_sub(count.len() + 1))
39 );
40 let padding = width.saturating_sub(name_part.len() + count.len());
41 ListItem::new(format!("{}{}{}", name_part, " ".repeat(padding), count))
42 })
43 .collect::<Vec<_>>();
44
45 let list = List::new(items)
46 .block(
47 Block::bordered()
48 .title(format!(" Subscriptions ({}) ", view.entries.len()))
49 .border_type(BorderType::Rounded)
50 .border_style(border_style),
51 )
52 .highlight_style(theme.highlight_style());
53
54 let mut state = ListState::default()
55 .with_selected((!view.entries.is_empty()).then_some(view.selected_index))
56 .with_offset(view.scroll_offset);
57 frame.render_stateful_widget(list, chunks[0], &mut state);
58
59 crate::ui::message_view::draw(
60 frame,
61 chunks[1],
62 view.preview_blocks,
63 view.message_scroll_offset,
64 view.active_pane,
65 theme,
66 );
67}
68
69fn truncate(value: &str, width: usize) -> String {
70 if value.chars().count() <= width {
71 return value.to_string();
72 }
73 value
74 .chars()
75 .take(width.saturating_sub(3))
76 .collect::<String>()
77 + "..."
78}