nice version now
This commit is contained in:
127
src/main.rs
127
src/main.rs
@@ -1,6 +1,6 @@
|
||||
|
||||
use clap::Command;
|
||||
use colored::{Color, Colorize};
|
||||
use colored::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::error::Error;
|
||||
use std::io::{stdout, Write};
|
||||
@@ -8,13 +8,6 @@ use std::sync::{Arc, Mutex};
|
||||
use termion::{clear, cursor, event::Key, input::TermRead, raw::IntoRawMode, terminal_size};
|
||||
use tokio::time::{sleep, Duration};
|
||||
|
||||
const BORDER_COLOR: Color = Color::TrueColor { r: 117, g: 142, b: 205 }; // #758ECD
|
||||
const REF_COLOR: Color = Color::TrueColor { r: 113, g: 137, b: 255 }; // #7189FF
|
||||
const TEXT_COLOR: Color = Color::TrueColor { r: 193, g: 206, b: 254 }; // #C1CEFE
|
||||
const ATTR_COLOR: Color = Color::TrueColor { r: 160, g: 221, b: 255 }; // #A0DDFF
|
||||
const NEXT_BTN_COLOR: Color = Color::TrueColor { r: 98, g: 76, b: 171 }; // #624CAB
|
||||
const QUIT_BTN_COLOR: Color = Color::TrueColor { r: 160, g: 221, b: 255 }; // #A0DDFF
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
struct BibleVerse {
|
||||
translation: Translation,
|
||||
@@ -70,102 +63,97 @@ fn word_wrap(text: &str, max_width: usize) -> Vec<String> {
|
||||
|
||||
fn display_verse(verse: &BibleVerse, term_width: u16, term_height: u16) {
|
||||
let max_width = std::cmp::min(80, term_width as usize - 10);
|
||||
let box_width = max_width + 8;
|
||||
let box_inner_width = max_width;
|
||||
let box_width = box_inner_width + 2;
|
||||
|
||||
let reference = format!("{} {}:{}",
|
||||
verse.random_verse.book,
|
||||
verse.random_verse.chapter,
|
||||
verse.random_verse.verse);
|
||||
|
||||
let wrapped_text = word_wrap(&verse.random_verse.text, max_width - 4);
|
||||
let wrapped_text = word_wrap(&verse.random_verse.text, box_inner_width);
|
||||
let attribution = format!("{} ({})", verse.translation.name, verse.translation.identifier);
|
||||
|
||||
let box_height = wrapped_text.len() + 7;
|
||||
let box_height = wrapped_text.len() + 6;
|
||||
let start_y = (term_height as usize / 2).saturating_sub(box_height / 2);
|
||||
let start_x = (term_width as usize / 2).saturating_sub(box_width / 2);
|
||||
|
||||
print!("{}{}", clear::All, cursor::Goto(1, 1));
|
||||
|
||||
// Top border
|
||||
print!("{}", cursor::Goto(start_x as u16, start_y as u16));
|
||||
println!(
|
||||
"{}{}{}",
|
||||
"╔".color(BORDER_COLOR).bold(),
|
||||
"═".repeat(box_width - 2).color(BORDER_COLOR).bold(),
|
||||
"╗".color(BORDER_COLOR).bold()
|
||||
"╔".truecolor(117, 142, 205).bold(),
|
||||
"═".repeat(box_inner_width).truecolor(117, 142, 205).bold(),
|
||||
"╗".truecolor(117, 142, 205).bold()
|
||||
);
|
||||
|
||||
// Reference
|
||||
let centered_ref = format!("{:^width$}", reference, width = box_inner_width);
|
||||
print!("{}", cursor::Goto(start_x as u16, (start_y + 1) as u16));
|
||||
println!(
|
||||
"{}{}{}",
|
||||
"║".color(BORDER_COLOR).bold(),
|
||||
" ".repeat(box_width - 2),
|
||||
"║".color(BORDER_COLOR).bold()
|
||||
"║".truecolor(117, 142, 205).bold(),
|
||||
centered_ref.truecolor(113, 137, 255).bold(),
|
||||
"║".truecolor(117, 142, 205).bold()
|
||||
);
|
||||
|
||||
// Empty line
|
||||
print!("{}", cursor::Goto(start_x as u16, (start_y + 2) as u16));
|
||||
let centered_ref = format!("{:^width$}", reference, width = box_width - 2);
|
||||
println!(
|
||||
"{}{}{}",
|
||||
"║".color(BORDER_COLOR).bold(),
|
||||
centered_ref.color(REF_COLOR).bold(),
|
||||
"║".color(BORDER_COLOR).bold()
|
||||
);
|
||||
|
||||
print!("{}", cursor::Goto(start_x as u16, (start_y + 3) as u16));
|
||||
println!(
|
||||
"{}{}{}",
|
||||
"║".color(BORDER_COLOR).bold(),
|
||||
" ".repeat(box_width - 2),
|
||||
"║".color(BORDER_COLOR).bold()
|
||||
"║".truecolor(117, 142, 205).bold(),
|
||||
" ".repeat(box_inner_width),
|
||||
"║".truecolor(117, 142, 205).bold()
|
||||
);
|
||||
|
||||
// Verse text
|
||||
for (i, line) in wrapped_text.iter().enumerate() {
|
||||
print!("{}", cursor::Goto(start_x as u16, (start_y + 4 + i) as u16));
|
||||
let padding = (box_width - 2 - line.len()) / 2;
|
||||
let left_padding = " ".repeat(padding);
|
||||
let right_padding = " ".repeat(box_width - 2 - padding - line.len());
|
||||
let centered = format!("{:^width$}", line, width = box_inner_width);
|
||||
print!("{}", cursor::Goto(start_x as u16, (start_y + 3 + i) as u16));
|
||||
println!(
|
||||
"{}{}{}{}",
|
||||
"║".color(BORDER_COLOR).bold(),
|
||||
left_padding,
|
||||
line.color(TEXT_COLOR),
|
||||
format!("{}{}", right_padding, "║").color(BORDER_COLOR).bold()
|
||||
"{}{}{}",
|
||||
"║".truecolor(117, 142, 205).bold(),
|
||||
centered.truecolor(160, 221, 255),
|
||||
"║".truecolor(117, 142, 205).bold()
|
||||
);
|
||||
}
|
||||
|
||||
// Empty line
|
||||
print!(
|
||||
"{}{}{}",
|
||||
cursor::Goto(start_x as u16, (start_y + 3 + wrapped_text.len()) as u16),
|
||||
"║".truecolor(117, 142, 205).bold(),
|
||||
" ".repeat(box_inner_width),
|
||||
);
|
||||
println!("{}", "║".truecolor(117, 142, 205).bold());
|
||||
|
||||
// Attribution
|
||||
let centered_attr = format!("{:^width$}", attribution, width = box_inner_width);
|
||||
print!("{}", cursor::Goto(start_x as u16, (start_y + 4 + wrapped_text.len()) as u16));
|
||||
println!(
|
||||
"{}{}{}",
|
||||
"║".color(BORDER_COLOR).bold(),
|
||||
" ".repeat(box_width - 2),
|
||||
"║".color(BORDER_COLOR).bold()
|
||||
"║".truecolor(117, 142, 205).bold(),
|
||||
centered_attr.truecolor(193, 206, 254).italic(),
|
||||
"║".truecolor(117, 142, 205).bold()
|
||||
);
|
||||
|
||||
// Bottom border
|
||||
print!("{}", cursor::Goto(start_x as u16, (start_y + 5 + wrapped_text.len()) as u16));
|
||||
let centered_attr = format!("{:^width$}", attribution, width = box_width - 2);
|
||||
println!(
|
||||
"{}{}{}",
|
||||
"║".color(BORDER_COLOR).bold(),
|
||||
centered_attr.color(ATTR_COLOR).italic(),
|
||||
"║".color(BORDER_COLOR).bold()
|
||||
"╚".truecolor(117, 142, 205).bold(),
|
||||
"═".repeat(box_inner_width).truecolor(117, 142, 205).bold(),
|
||||
"╝".truecolor(117, 142, 205).bold()
|
||||
);
|
||||
|
||||
print!("{}", cursor::Goto(start_x as u16, (start_y + 6 + wrapped_text.len()) as u16));
|
||||
println!(
|
||||
"{}{}{}",
|
||||
"╚".color(BORDER_COLOR).bold(),
|
||||
"═".repeat(box_width - 2).color(BORDER_COLOR).bold(),
|
||||
"╝".color(BORDER_COLOR).bold()
|
||||
);
|
||||
// Buttons
|
||||
print!("{}", cursor::Goto(start_x as u16 + 2, (start_y + 7 + wrapped_text.len()) as u16));
|
||||
print!("{}", "[N]ext Verse".truecolor(98, 76, 171).bold());
|
||||
|
||||
print!("{}", cursor::Goto(start_x as u16 + 4, (start_y + 8 + wrapped_text.len()) as u16));
|
||||
print!("{}", "[N]ext Verse".color(NEXT_BTN_COLOR).bold());
|
||||
|
||||
print!("{}", cursor::Goto(start_x as u16 + box_width as u16 - 15, (start_y + 8 + wrapped_text.len()) as u16));
|
||||
print!("{}", "[Q]uit".color(QUIT_BTN_COLOR).bold());
|
||||
|
||||
print!("{}", cursor::Goto(start_x as u16 + (box_width / 2) as u16 - 15, (start_y + 10 + wrapped_text.len()) as u16));
|
||||
print!("{}", "Press N for next verse or Q to quit".color(REF_COLOR));
|
||||
print!("{}", cursor::Goto(start_x as u16 + box_width as u16 - 14, (start_y + 7 + wrapped_text.len()) as u16));
|
||||
print!("{}", "[Q]uit".truecolor(98, 76, 171).bold());
|
||||
|
||||
stdout().flush().unwrap();
|
||||
}
|
||||
@@ -173,16 +161,18 @@ fn display_verse(verse: &BibleVerse, term_width: u16, term_height: u16) {
|
||||
async fn display_loading_animation(loading: Arc<Mutex<bool>>, term_width: u16, term_height: u16) {
|
||||
let spinner_frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
||||
let mut frame_index = 0;
|
||||
|
||||
let message = "Loading Bible verse";
|
||||
let message_len = message.len() + 2;
|
||||
|
||||
while *loading.lock().unwrap() {
|
||||
let spinner = spinner_frames[frame_index].color(NEXT_BTN_COLOR).bold();
|
||||
let spinner = spinner_frames[frame_index].cyan().bold();
|
||||
|
||||
let x_pos = (term_width as usize / 2).saturating_sub(message_len / 2);
|
||||
let y_pos = term_height as usize / 2;
|
||||
|
||||
print!("{}", cursor::Goto(x_pos as u16, y_pos as u16));
|
||||
print!("{} {}", spinner, message.color(REF_COLOR).bold());
|
||||
print!("{} {}", spinner, message.cyan().bold());
|
||||
stdout().flush().unwrap();
|
||||
|
||||
frame_index = (frame_index + 1) % spinner_frames.len();
|
||||
@@ -203,6 +193,7 @@ async fn main() -> Result<(), Box<dyn Error>> {
|
||||
stdout.flush()?;
|
||||
|
||||
let mut stdin = termion::async_stdin().keys();
|
||||
|
||||
let (term_width, term_height) = terminal_size()?;
|
||||
let loading = Arc::new(Mutex::new(true));
|
||||
let loading_clone = loading.clone();
|
||||
@@ -225,14 +216,17 @@ async fn main() -> Result<(), Box<dyn Error>> {
|
||||
if let Some(Ok(key)) = stdin.next() {
|
||||
match key {
|
||||
Key::Char('q') | Key::Char('Q') | Key::Esc => {
|
||||
// Proper cleanup
|
||||
write!(stdout, "{}{}", clear::All, cursor::Show)?;
|
||||
stdout.flush()?;
|
||||
return Ok(());
|
||||
}
|
||||
},
|
||||
Key::Char('n') | Key::Char('N') | Key::Char(' ') => {
|
||||
key_pressed = true;
|
||||
|
||||
let loading = Arc::new(Mutex::new(true));
|
||||
let loading_clone = loading.clone();
|
||||
|
||||
write!(stdout, "{}", clear::All)?;
|
||||
stdout.flush()?;
|
||||
|
||||
@@ -245,17 +239,18 @@ async fn main() -> Result<(), Box<dyn Error>> {
|
||||
*loading.lock().unwrap() = false;
|
||||
animation_task.await?;
|
||||
current_verse = verse;
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
*loading.lock().unwrap() = false;
|
||||
animation_task.await?;
|
||||
|
||||
write!(stdout, "{}{}", clear::All, cursor::Show)?;
|
||||
stdout.flush()?;
|
||||
eprintln!("{} {}", "Error fetching verse:".bold().color(QUIT_BTN_COLOR), e);
|
||||
eprintln!("{} {}", "Error fetching verse:".bold().red(), e);
|
||||
return Err(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user