diff --git a/src/main.rs b/src/main.rs index 81e8816..27b42bd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -35,11 +35,11 @@ pub struct Args { #[clap(long, short)] minimalist: bool, - /// Exclude borders in UI. + /// Exclude window borders. #[clap(long, short)] borderless: bool, - /// Include a small clock in the UI. + /// Include a clock. #[clap(long, short)] clock: bool, diff --git a/src/tests/ui.rs b/src/tests/ui.rs index 85d39e7..cef20be 100644 --- a/src/tests/ui.rs +++ b/src/tests/ui.rs @@ -8,50 +8,50 @@ #[cfg(test)] mod components { - use crate::ui; + use crate::ui::interface; use std::time::Duration; #[test] fn format_duration_works() { let d = Duration::from_secs(62); - assert_eq!(ui::components::format_duration(&d), "01:02"); + assert_eq!(interface::components::format_duration(&d), "01:02"); } #[test] fn format_duration_zero() { let d = Duration::from_secs(0); - assert_eq!(ui::components::format_duration(&d), "00:00"); + assert_eq!(interface::components::format_duration(&d), "00:00"); } #[test] fn format_duration_hours_wrap() { let d = Duration::from_secs(3661); // 1:01:01 - assert_eq!(ui::components::format_duration(&d), "61:01"); + assert_eq!(interface::components::format_duration(&d), "61:01"); } #[test] fn audio_bar_contains_percentage() { - let s = ui::components::audio_bar(10, 0.5, "50%"); + let s = interface::components::audio_bar(10, 0.5, "50%"); assert!(s.contains("50%")); assert!(s.starts_with(" volume:")); } #[test] fn audio_bar_muted_volume() { - let s = ui::components::audio_bar(8, 0.0, "0%"); + let s = interface::components::audio_bar(8, 0.0, "0%"); assert!(s.contains("0%")); } #[test] fn audio_bar_full_volume() { - let s = ui::components::audio_bar(10, 1.0, "100%"); + let s = interface::components::audio_bar(10, 1.0, "100%"); assert!(s.contains("100%")); } #[test] fn controls_has_items() { - let s = ui::components::controls(30); + let s = interface::components::controls(30); assert!(s.contains("[s]")); assert!(s.contains("[p]")); assert!(s.contains("[q]")); @@ -60,7 +60,7 @@ mod components { #[cfg(test)] mod window { - use crate::ui::window::Window; + use crate::ui::interface::Window; #[test] fn new_border_strings() { diff --git a/src/ui.rs b/src/ui.rs index 1520e68..7e8ea9d 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -1,21 +1,16 @@ use std::sync::Arc; -use crate::{ - player::Current, - ui::{self, interface::Clock, window::Window}, - Args, -}; +use crate::{player::Current, ui, Args}; use tokio::{ sync::{broadcast, mpsc::Sender}, task::JoinHandle, time::Instant, }; -pub mod components; + pub mod environment; pub use environment::Environment; pub mod input; pub mod interface; -pub mod window; #[cfg(feature = "mpris")] pub mod mpris; @@ -169,8 +164,8 @@ impl Handle { params: interface::Params, ) -> Result<()> { let mut interval = tokio::time::interval(params.delta); - let mut window = Window::new(state.width, params.borderless); - let mut clock = params.clock.then(|| Clock::new(&mut window)); + let mut window = interface::Window::new(state.width, params.borderless); + let mut clock = params.clock.then(|| interface::Clock::new(&mut window)); loop { if let Ok(message) = rx.try_recv() { @@ -182,9 +177,7 @@ impl Handle { } } - if let Some(x) = clock.as_mut() { - x.update(&mut window) - } + clock.as_mut().map(|x| x.update(&mut window)); interface::draw(&mut state, &mut window, params)?; interval.tick().await; } diff --git a/src/ui/interface.rs b/src/ui/interface.rs index db86b92..f7a1a08 100644 --- a/src/ui/interface.rs +++ b/src/ui/interface.rs @@ -1,39 +1,12 @@ -use crate::{ - ui::{self, components, window::Window}, - Args, -}; +use crate::{ui, Args}; use std::{env, time::Duration}; -use tokio::time::Instant; -/// An extremely simple clock to be used alongside the [`Window`]. -pub struct Clock(Instant); +pub mod clock; +pub mod components; +pub mod window; -impl Clock { - /// Small shorthand for getting the local time now, and formatting it. - #[inline] - fn now() -> chrono::format::DelayedFormat> { - chrono::Local::now().format("%H:%M:%S") - } - - /// Checks if the last update was long enough ago, and if so, - /// updates the displayed clock. - /// - /// This is to avoid constant calls to [`chrono::Local::now`], which - /// is somewhat expensive because of timezones. - pub fn update(&mut self, window: &mut Window) { - if self.0.elapsed().as_millis() >= 500 { - window.display(Self::now(), 8); - self.0 = Instant::now(); - } - } - - /// Simply creates a new clock, and renders it's initial state to the window top. - pub fn new(window: &mut Window) -> Self { - window.display(Self::now(), 8); - - Self(Instant::now()) - } -} +pub use clock::Clock; +pub use window::Window; /// UI-specific parameters and options. #[derive(Copy, Clone, Debug, Default)] @@ -47,7 +20,7 @@ pub struct Params { /// Whether the visual part of the UI should be enabled. /// This only applies if the MPRIS feature is enabled. pub enabled: bool, - + /// Whether to include the clock on the top bar. pub clock: bool, diff --git a/src/ui/interface/clock.rs b/src/ui/interface/clock.rs new file mode 100644 index 0000000..64d57d1 --- /dev/null +++ b/src/ui/interface/clock.rs @@ -0,0 +1,33 @@ +use tokio::time::Instant; + +use super::window::Window; + +/// An extremely simple clock to be used alongside the [`Window`]. +pub struct Clock(Instant); + +impl Clock { + /// Small shorthand for getting the local time now, and formatting it. + #[inline] + fn now() -> chrono::format::DelayedFormat> { + chrono::Local::now().format("%H:%M:%S") + } + + /// Checks if the last update was long enough ago, and if so, + /// updates the displayed clock. + /// + /// This is to avoid constant calls to [`chrono::Local::now`], which + /// is somewhat expensive because of timezones. + pub fn update(&mut self, window: &mut Window) { + if self.0.elapsed().as_millis() >= 200 { + window.display(Self::now(), 8); + self.0 = Instant::now(); + } + } + + /// Simply creates a new clock, and renders it's initial state to the top of the window. + pub fn new(window: &mut Window) -> Self { + window.display(Self::now(), 8); + + Self(Instant::now()) + } +} diff --git a/src/ui/components.rs b/src/ui/interface/components.rs similarity index 100% rename from src/ui/components.rs rename to src/ui/interface/components.rs diff --git a/src/ui/window.rs b/src/ui/interface/window.rs similarity index 98% rename from src/ui/window.rs rename to src/ui/interface/window.rs index 2413e33..eaecc77 100644 --- a/src/ui/window.rs +++ b/src/ui/interface/window.rs @@ -11,6 +11,8 @@ use crossterm::{ use std::fmt::Write as _; use unicode_segmentation::UnicodeSegmentation as _; +use crate::ui; + /// Represents an abstraction for drawing the actual lowfi window itself. /// /// The main purpose of this struct is just to add the fancy border, @@ -72,7 +74,7 @@ impl Window { content: Vec, space: bool, testing: bool, - ) -> super::Result<(String, u16)> { + ) -> ui::Result<(String, u16)> { let linefeed = if testing { "\n" } else { "\r\n" }; let len: u16 = content.len().try_into()?; @@ -110,7 +112,7 @@ impl Window { } /// Actually draws the window, with each element in `content` being on a new line. - pub fn draw(&mut self, content: Vec, space: bool) -> super::Result<()> { + pub fn draw(&mut self, content: Vec, space: bool) -> ui::Result<()> { let (rendered, height) = self.render(content, space, false)?; crossterm::execute!(