Skip to main content

mxr_tui/ui/
subscriptions_page.rs

1use 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}