diff --git a/src/main.rs b/src/main.rs index 380b924..1ad18c8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -115,7 +115,30 @@ impl App { } } - fn format_line<'a>(text: &str, prefix: &'a str, prefix_style: Style, max_width: usize) -> Text<'a> { + fn format_line<'a>(entry: &ConversationEntry, max_width: usize) -> Text<'a> { + let prefix = match entry { + ConversationEntry::Eva(_) => "Eva: ", + ConversationEntry::User(_) => "Argee: ", + ConversationEntry::ShipComputer(_) => "Ship Computer: ", + _ => "", + }; + + let style = match entry { + ConversationEntry::Eva(_) => Style::new().fg(style::Color::Cyan), + ConversationEntry::User(_) => Style::new().fg(style::Color::Magenta), + ConversationEntry::ShipComputer(_) => Style::new().fg(style::Color::Green), + ConversationEntry::StageDirection(_) => Style::new().fg(style::Color::Yellow), + ConversationEntry::SystemMessage(_) => Style::new().fg(style::Color::DarkGray), + }; + + let text = match entry { + ConversationEntry::Eva(text) => text, + ConversationEntry::ShipComputer(text) => text, + ConversationEntry::StageDirection(text) => text, + ConversationEntry::SystemMessage(text) => text, + ConversationEntry::User(text) => text + }; + let avail_width = max_width - prefix.len(); let indent = " ".repeat(prefix.len()); let wrap_options = textwrap::Options::new(avail_width).initial_indent(prefix).subsequent_indent(&indent); @@ -124,7 +147,7 @@ impl App { .enumerate() .map(|(idx, s)| { if idx == 0 { - Line::from_iter([Span::from(prefix).style(prefix_style), Span::from(s[prefix.len()..].to_string())]) + Line::from_iter([Span::from(prefix).style(style), Span::from(s[prefix.len()..].to_string())]) } else { Line::from(s.to_string()) } @@ -136,13 +159,7 @@ impl App { fn draw_conversation(&mut self, frame: &mut Frame, area: Rect) { let width = area.width.into(); let items: Vec = self.scene.conversation().iter().rev().map(|entry| { - match entry { - ConversationEntry::User(text) => Self::format_line(text, "Argee: ", Style::new().fg(style::Color::Magenta), width), - ConversationEntry::Eva(text) => Self::format_line(text, "Eva: ", Style::new().fg(style::Color::Cyan), width), - ConversationEntry::ShipComputer(text) => Self::format_line(text, "Ship Computer: ", Style::new().fg(style::Color::Green), width), - ConversationEntry::StageDirection(text) => Self::format_line(text, "", Style::new(), width).style(ratatui::style::Color::Yellow), - ConversationEntry::SystemMessage(text) => Self::format_line(text, "", Style::new(), width).style(ratatui::style::Color::DarkGray) - } + Self::format_line(entry, width) }).collect(); // TODO: Would be nice to be able to scroll a longer conversation with the scroll wheel, or with page up/down frame.render_stateful_widget( @@ -166,12 +183,31 @@ impl App { .block(borders); frame.render_widget(list, area); } else { + let wrap_options = textwrap::Options::new(area.width as usize).subsequent_indent("..."); + let options: Vec = self.scene.reply_options().iter().map(|option| { + let mut contents: Vec = vec![]; + + if let Some(direction) = &option.stage_direction { + let padded = format!("({})", direction); + let mut wrapped_direction: Vec = textwrap::wrap(&padded, wrap_options.clone()) + .iter() + .map(|x| { Line::from(x.to_string()).fg(style::Color::Yellow)}).collect(); + contents.append(&mut wrapped_direction); + } + + let mut text: Vec = textwrap::wrap(&option.text, wrap_options.clone()) + .iter() + .map(|x| { Line::from(x.to_string())}).collect(); + contents.append(&mut text); + Text::from_iter(contents) + }).collect(); frame.render_stateful_widget( - List::new(self.scene.reply_options().clone()) + List::new(options) .block(borders) .style(ratatui::style::Color::White) - .highlight_symbol("> ") - .highlight_style(style::Style::new().bold().fg(style::Color::Cyan)), + .highlight_symbol("> ".fg(Color::Cyan)) + .highlight_style(style::Style::new().bold().bg(style::Color::DarkGray)) + .repeat_highlight_symbol(true), area, &mut self.reply_state ); @@ -199,24 +235,37 @@ impl App { fn draw_status(&self, frame: &mut Frame, area: Rect) { let minutes_remaining = self.direction.time_remaining.num_seconds() / 60; - let time_style = if minutes_remaining == 0 { - Style::new().fg(ratatui::style::Color::Red).bold().rapid_blink() - } else if minutes_remaining <= 5 { - Style::new().fg(ratatui::style::Color::Red).bold().slow_blink() - } else if minutes_remaining <= 10 { + + let negative = self.direction.time_remaining.abs() != self.direction.time_remaining; + + + let time_style = if minutes_remaining <= 0 || negative { + Style::new().fg(ratatui::style::Color::LightRed).bold() + } else if minutes_remaining < 5 { + Style::new().fg(ratatui::style::Color::LightRed).bold() + } else if minutes_remaining < 10 { ratatui::style::Color::Red.into() - } else if minutes_remaining <= 25 { + } else if minutes_remaining < 25 { ratatui::style::Color::Yellow.into() - } else if minutes_remaining <= 60 { + } else if minutes_remaining < 60 { ratatui::style::Color::Green.into() } else { ratatui::style::Color::Blue.into() }; + + let formatted_time = if negative { + format!("-{:0>2}:{:0>2}:{:0>2}", self.direction.time_remaining.num_hours().abs(), self.direction.time_remaining.num_minutes().abs()% 60, self.direction.time_remaining.num_seconds().abs() % 60) + } else { + format!("{:0>2}:{:0>2}:{:0>2}", self.direction.time_remaining.num_hours(), self.direction.time_remaining.num_minutes() % 60, self.direction.time_remaining.num_seconds() % 60) + }; + let status_line = Line::from_iter([ Span::from(format!("Episode {}", self.direction.episode_number)).style(ratatui::style::Color::LightBlue), Span::from(" | ").style(ratatui::style::Color::DarkGray), - // FIXME: Looks weird with negative numbers, and it doesn't actually blink in the vscode terminal. - Span::from(format!("Time Remaining: {:0>2}:{:0>2}:{:0>2}", self.direction.time_remaining.num_hours(), self.direction.time_remaining.num_minutes() % 60, self.direction.time_remaining.num_seconds() % 60)).style(time_style) + Span::from(format!("{} tracks", self.direction.current_playlist.len())).style(ratatui::style::Color::LightBlue), + Span::from(" | ").style(ratatui::style::Color::DarkGray), + Span::from(format!("Time Remaining: {}", formatted_time)).style(time_style), + Span::from(" | ").style(ratatui::style::Color::DarkGray), ]); frame.render_widget(status_line, area); }