mirror of
https://github.com/talwat/lowfi
synced 2025-12-19 13:13:21 +00:00
style: improve structure of clock code
This commit is contained in:
parent
11a6debcc4
commit
ea24b7d8b3
@ -35,11 +35,11 @@ pub struct Args {
|
|||||||
#[clap(long, short)]
|
#[clap(long, short)]
|
||||||
minimalist: bool,
|
minimalist: bool,
|
||||||
|
|
||||||
/// Exclude borders in UI.
|
/// Exclude window borders.
|
||||||
#[clap(long, short)]
|
#[clap(long, short)]
|
||||||
borderless: bool,
|
borderless: bool,
|
||||||
|
|
||||||
/// Include a small clock in the UI.
|
/// Include a clock.
|
||||||
#[clap(long, short)]
|
#[clap(long, short)]
|
||||||
clock: bool,
|
clock: bool,
|
||||||
|
|
||||||
|
|||||||
@ -8,50 +8,50 @@
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod components {
|
mod components {
|
||||||
use crate::ui;
|
use crate::ui::interface;
|
||||||
|
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn format_duration_works() {
|
fn format_duration_works() {
|
||||||
let d = Duration::from_secs(62);
|
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]
|
#[test]
|
||||||
fn format_duration_zero() {
|
fn format_duration_zero() {
|
||||||
let d = Duration::from_secs(0);
|
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]
|
#[test]
|
||||||
fn format_duration_hours_wrap() {
|
fn format_duration_hours_wrap() {
|
||||||
let d = Duration::from_secs(3661); // 1:01:01
|
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]
|
#[test]
|
||||||
fn audio_bar_contains_percentage() {
|
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.contains("50%"));
|
||||||
assert!(s.starts_with(" volume:"));
|
assert!(s.starts_with(" volume:"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn audio_bar_muted_volume() {
|
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%"));
|
assert!(s.contains("0%"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn audio_bar_full_volume() {
|
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%"));
|
assert!(s.contains("100%"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn controls_has_items() {
|
fn controls_has_items() {
|
||||||
let s = ui::components::controls(30);
|
let s = interface::components::controls(30);
|
||||||
assert!(s.contains("[s]"));
|
assert!(s.contains("[s]"));
|
||||||
assert!(s.contains("[p]"));
|
assert!(s.contains("[p]"));
|
||||||
assert!(s.contains("[q]"));
|
assert!(s.contains("[q]"));
|
||||||
@ -60,7 +60,7 @@ mod components {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod window {
|
mod window {
|
||||||
use crate::ui::window::Window;
|
use crate::ui::interface::Window;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn new_border_strings() {
|
fn new_border_strings() {
|
||||||
|
|||||||
17
src/ui.rs
17
src/ui.rs
@ -1,21 +1,16 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::{
|
use crate::{player::Current, ui, Args};
|
||||||
player::Current,
|
|
||||||
ui::{self, interface::Clock, window::Window},
|
|
||||||
Args,
|
|
||||||
};
|
|
||||||
use tokio::{
|
use tokio::{
|
||||||
sync::{broadcast, mpsc::Sender},
|
sync::{broadcast, mpsc::Sender},
|
||||||
task::JoinHandle,
|
task::JoinHandle,
|
||||||
time::Instant,
|
time::Instant,
|
||||||
};
|
};
|
||||||
pub mod components;
|
|
||||||
pub mod environment;
|
pub mod environment;
|
||||||
pub use environment::Environment;
|
pub use environment::Environment;
|
||||||
pub mod input;
|
pub mod input;
|
||||||
pub mod interface;
|
pub mod interface;
|
||||||
pub mod window;
|
|
||||||
|
|
||||||
#[cfg(feature = "mpris")]
|
#[cfg(feature = "mpris")]
|
||||||
pub mod mpris;
|
pub mod mpris;
|
||||||
@ -169,8 +164,8 @@ impl Handle {
|
|||||||
params: interface::Params,
|
params: interface::Params,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let mut interval = tokio::time::interval(params.delta);
|
let mut interval = tokio::time::interval(params.delta);
|
||||||
let mut window = Window::new(state.width, params.borderless);
|
let mut window = interface::Window::new(state.width, params.borderless);
|
||||||
let mut clock = params.clock.then(|| Clock::new(&mut window));
|
let mut clock = params.clock.then(|| interface::Clock::new(&mut window));
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
if let Ok(message) = rx.try_recv() {
|
if let Ok(message) = rx.try_recv() {
|
||||||
@ -182,9 +177,7 @@ impl Handle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(x) = clock.as_mut() {
|
clock.as_mut().map(|x| x.update(&mut window));
|
||||||
x.update(&mut window)
|
|
||||||
}
|
|
||||||
interface::draw(&mut state, &mut window, params)?;
|
interface::draw(&mut state, &mut window, params)?;
|
||||||
interval.tick().await;
|
interval.tick().await;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,39 +1,12 @@
|
|||||||
use crate::{
|
use crate::{ui, Args};
|
||||||
ui::{self, components, window::Window},
|
|
||||||
Args,
|
|
||||||
};
|
|
||||||
use std::{env, time::Duration};
|
use std::{env, time::Duration};
|
||||||
use tokio::time::Instant;
|
|
||||||
|
|
||||||
/// An extremely simple clock to be used alongside the [`Window`].
|
pub mod clock;
|
||||||
pub struct Clock(Instant);
|
pub mod components;
|
||||||
|
pub mod window;
|
||||||
|
|
||||||
impl Clock {
|
pub use clock::Clock;
|
||||||
/// Small shorthand for getting the local time now, and formatting it.
|
pub use window::Window;
|
||||||
#[inline]
|
|
||||||
fn now() -> chrono::format::DelayedFormat<chrono::format::StrftimeItems<'static>> {
|
|
||||||
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())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// UI-specific parameters and options.
|
/// UI-specific parameters and options.
|
||||||
#[derive(Copy, Clone, Debug, Default)]
|
#[derive(Copy, Clone, Debug, Default)]
|
||||||
@ -47,7 +20,7 @@ pub struct Params {
|
|||||||
/// Whether the visual part of the UI should be enabled.
|
/// Whether the visual part of the UI should be enabled.
|
||||||
/// This only applies if the MPRIS feature is enabled.
|
/// This only applies if the MPRIS feature is enabled.
|
||||||
pub enabled: bool,
|
pub enabled: bool,
|
||||||
|
|
||||||
/// Whether to include the clock on the top bar.
|
/// Whether to include the clock on the top bar.
|
||||||
pub clock: bool,
|
pub clock: bool,
|
||||||
|
|
||||||
|
|||||||
33
src/ui/interface/clock.rs
Normal file
33
src/ui/interface/clock.rs
Normal file
@ -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::format::StrftimeItems<'static>> {
|
||||||
|
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())
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -11,6 +11,8 @@ use crossterm::{
|
|||||||
use std::fmt::Write as _;
|
use std::fmt::Write as _;
|
||||||
use unicode_segmentation::UnicodeSegmentation as _;
|
use unicode_segmentation::UnicodeSegmentation as _;
|
||||||
|
|
||||||
|
use crate::ui;
|
||||||
|
|
||||||
/// Represents an abstraction for drawing the actual lowfi window itself.
|
/// Represents an abstraction for drawing the actual lowfi window itself.
|
||||||
///
|
///
|
||||||
/// The main purpose of this struct is just to add the fancy border,
|
/// The main purpose of this struct is just to add the fancy border,
|
||||||
@ -72,7 +74,7 @@ impl Window {
|
|||||||
content: Vec<String>,
|
content: Vec<String>,
|
||||||
space: bool,
|
space: bool,
|
||||||
testing: bool,
|
testing: bool,
|
||||||
) -> super::Result<(String, u16)> {
|
) -> ui::Result<(String, u16)> {
|
||||||
let linefeed = if testing { "\n" } else { "\r\n" };
|
let linefeed = if testing { "\n" } else { "\r\n" };
|
||||||
let len: u16 = content.len().try_into()?;
|
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.
|
/// Actually draws the window, with each element in `content` being on a new line.
|
||||||
pub fn draw(&mut self, content: Vec<String>, space: bool) -> super::Result<()> {
|
pub fn draw(&mut self, content: Vec<String>, space: bool) -> ui::Result<()> {
|
||||||
let (rendered, height) = self.render(content, space, false)?;
|
let (rendered, height) = self.render(content, space, false)?;
|
||||||
|
|
||||||
crossterm::execute!(
|
crossterm::execute!(
|
||||||
Loading…
x
Reference in New Issue
Block a user