Skip to main content

moltbook_cli/display/
dm.rs

1use crate::api::types::{Conversation, DmCheckResponse, DmRequest, Message};
2use crate::display::utils::{get_term_width, relative_time};
3use colored::*;
4
5/// Displays a DM request with action guidance.
6pub fn display_dm_request(req: &DmRequest) {
7    let width = get_term_width();
8    let inner_width = width.saturating_sub(4);
9
10    let from = &req.from.name;
11    let msg = req
12        .message
13        .as_deref()
14        .or(req.message_preview.as_deref())
15        .unwrap_or("");
16
17    println!(
18        "{}",
19        format!("╭{}╮", "─".repeat(width.saturating_sub(2))).dimmed()
20    );
21
22    // Calculate padding for the 'from' line
23    let from_line_len = 15 + from.chars().count();
24    let padding = inner_width.saturating_sub(from_line_len);
25
26    println!(
27        "│ 📨 Request from {} {:>p$} │",
28        from.cyan().bold(),
29        "",
30        p = padding
31    );
32    println!(
33        "{}",
34        format!("├{}┤", "─".repeat(width.saturating_sub(2))).dimmed()
35    );
36
37    if let Some(handle) = req.from.owner.as_ref().and_then(|o| o.x_handle.as_ref()) {
38        println!(
39            "│ 👑 Owner: @{:<w$} │",
40            handle.blue(),
41            w = inner_width.saturating_sub(14)
42        );
43    }
44
45    let wrapped = textwrap::fill(msg, inner_width.saturating_sub(2));
46    for line in wrapped.lines() {
47        println!("│  {:<w$}│", line, w = inner_width.saturating_sub(2));
48    }
49
50    println!(
51        "{}",
52        format!("├{}┤", "─".repeat(width.saturating_sub(2))).dimmed()
53    );
54    println!(
55        "│ Request ID: {:<w$} │",
56        req.conversation_id.dimmed(),
57        w = inner_width.saturating_sub(12)
58    );
59    println!(
60        "│ {:<w$} │",
61        format!("✔ Approve: moltbook dm-approve {}", req.conversation_id).green(),
62        w = inner_width.saturating_sub(2) + 9
63    ); // +9 roughly for ansi
64    println!(
65        "│ {:<w$} │",
66        format!("✘ Reject:  moltbook dm-reject {}", req.conversation_id).red(),
67        w = inner_width.saturating_sub(2) + 9
68    );
69    println!(
70        "{}",
71        format!("╰{}╯", "─".repeat(width.saturating_sub(2))).dimmed()
72    );
73    println!();
74}
75
76pub fn display_dm_check(response: &DmCheckResponse) {
77    let width = get_term_width();
78    println!("\n{}", "DM Activity".bright_green().bold());
79    println!("{}", "━".repeat(width).dimmed());
80
81    if !response.has_activity {
82        println!("  {}", "No new DM activity 🦞".green());
83    } else {
84        if let Some(summary) = &response.summary {
85            println!("  {}", summary.yellow());
86        }
87
88        if let Some(data) = &response.requests
89            && !data.items.is_empty()
90        {
91            println!("\n  {}", "Pending Requests:".bold());
92            for req in &data.items {
93                let from = &req.from.name;
94                let preview = req.message_preview.as_deref().unwrap_or("");
95                let conv_id = &req.conversation_id;
96
97                println!("\n    From: {}", from.cyan());
98                println!("    Message: {}", preview.dimmed());
99                println!("    Request ID: {}", conv_id);
100            }
101        }
102
103        if let Some(data) = &response.messages
104            && data.total_unread > 0
105        {
106            println!(
107                "\n  {} unread messages",
108                data.total_unread.to_string().yellow()
109            );
110        }
111    }
112    println!();
113}
114
115pub fn display_conversation(conv: &Conversation) {
116    let width = get_term_width();
117    let unread_msg = if conv.unread_count > 0 {
118        format!(" ({} unread)", conv.unread_count)
119            .yellow()
120            .to_string()
121    } else {
122        String::new()
123    };
124
125    println!(
126        "{} {}{}",
127        "💬".cyan(),
128        conv.with_agent.name.bright_cyan().bold(),
129        unread_msg
130    );
131    println!("   Conversation ID: {}", conv.conversation_id.dimmed());
132    println!(
133        "   Read: {}",
134        format!("moltbook dm-read {}", conv.conversation_id).green()
135    );
136    println!("{}", "─".repeat(width).dimmed());
137}
138
139pub fn display_message(msg: &Message, my_name: &str) {
140    let width = get_term_width();
141    let from_you = msg.sender.name == my_name;
142    let prefix = if from_you {
143        "You"
144    } else {
145        &msg.sender.name
146    };
147
148    let (icon, color) = if from_you {
149        ("📤", prefix.green())
150    } else {
151        ("📥", prefix.yellow())
152    };
153
154    let time = relative_time(&msg.created_at);
155
156    println!("\n{} {} ({})", icon, color.bold(), time.dimmed());
157
158    let wrapped = textwrap::fill(&msg.content, width.saturating_sub(4));
159    for line in wrapped.lines() {
160        println!("  {}", line);
161    }
162
163    if msg.needs_human_input {
164        println!("  {}", "⚠ Needs human input".red());
165    }
166    println!("{}", "─".repeat(width.min(40)).dimmed());
167}