moltbook_cli/display/
dm.rs1use crate::api::types::{Conversation, DmCheckResponse, DmRequest, Message};
2use crate::display::utils::{get_term_width, relative_time};
3use colored::*;
4
5pub 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 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 ); 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}