use std::io::Write;
use chrono::{Local, TimeZone};
use termion::{clear, color, cursor, style};
use crate::slack::SlackMessage;
pub struct MessageViewer {
channel_name: String,
}
impl MessageViewer {
pub fn new(channel_name: &str) -> Self {
Self {
channel_name: channel_name.to_string(),
}
}
pub fn display<W: Write>(&self, stdout: &mut W, messages: &[SlackMessage]) {
write!(stdout, "{}{}", clear::All, cursor::Goto(1, 1)).unwrap();
write!(
stdout,
"{}{}#{} - Latest {} messages{}{}",
style::Bold,
color::Fg(color::Cyan),
self.channel_name,
messages.len(),
style::Reset,
color::Fg(color::Reset)
)
.unwrap();
write!(stdout, "{}", cursor::Goto(1, 2)).unwrap();
write!(stdout, "{}", "─".repeat(60)).unwrap();
let mut line = 3u16;
for message in messages.iter().rev() {
let timestamp = self.format_timestamp(&message.ts);
let user = message.user.as_deref().unwrap_or("unknown");
write!(stdout, "{}", cursor::Goto(1, line)).unwrap();
write!(
stdout,
"{}{}[{}] {}{}{}",
color::Fg(color::Green),
style::Bold,
timestamp,
user,
style::Reset,
color::Fg(color::Reset)
)
.unwrap();
line += 1;
for text_line in message.text.lines() {
write!(stdout, "{}", cursor::Goto(1, line)).unwrap();
write!(stdout, " {}", text_line).unwrap();
line += 1;
}
line += 1; }
write!(stdout, "{}", cursor::Goto(1, line)).unwrap();
write!(stdout, "{}", "─".repeat(60)).unwrap();
stdout.flush().unwrap();
}
fn format_timestamp(&self, ts: &str) -> String {
let epoch_secs: f64 = ts.parse().unwrap_or(0.0);
let secs = epoch_secs as i64;
match Local.timestamp_opt(secs, 0) {
chrono::LocalResult::Single(dt) => dt.format("%Y-%m-%d %H:%M").to_string(),
_ => ts.to_string(),
}
}
}
pub fn print_messages(channel_name: &str, messages: &[SlackMessage]) {
println!("#{} - Latest {} messages", channel_name, messages.len());
println!("{}", "─".repeat(60));
for message in messages.iter().rev() {
let timestamp = format_timestamp_simple(&message.ts);
let user = message.user.as_deref().unwrap_or("unknown");
println!("[{}] {}", timestamp, user);
for line in message.text.lines() {
println!(" {}", line);
}
println!();
}
}
fn format_timestamp_simple(ts: &str) -> String {
let epoch_secs: f64 = ts.parse().unwrap_or(0.0);
let secs = epoch_secs as i64;
match Local.timestamp_opt(secs, 0) {
chrono::LocalResult::Single(dt) => dt.format("%Y-%m-%d %H:%M").to_string(),
_ => ts.to_string(),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn message_viewer_new() {
let viewer = MessageViewer::new("general");
assert_eq!(viewer.channel_name, "general");
}
#[test]
fn format_timestamp_valid() {
let viewer = MessageViewer::new("test");
let ts = "1609459200.000000"; let result = viewer.format_timestamp(ts);
assert!(!result.is_empty());
}
}