dramatically simplify alarm handling
This commit is contained in:
parent
b347386e99
commit
628a8e73d6
3 changed files with 23 additions and 53 deletions
|
@ -1,14 +1,6 @@
|
||||||
use std::ffi::OsString;
|
|
||||||
|
|
||||||
pub const AIRHORN: &[u8] = include_bytes!("../airhorn_alarm.mp3");
|
pub const AIRHORN: &[u8] = include_bytes!("../airhorn_alarm.mp3");
|
||||||
pub const PREDATOR_FONT: &[u8] = include_bytes!("../Predator.ttf");
|
pub const PREDATOR_FONT: &[u8] = include_bytes!("../Predator.ttf");
|
||||||
|
|
||||||
pub mod cli;
|
pub mod cli;
|
||||||
pub mod timer;
|
pub mod timer;
|
||||||
mod util;
|
mod util;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub(crate) enum Alarm {
|
|
||||||
Airhon,
|
|
||||||
User(OsString),
|
|
||||||
}
|
|
||||||
|
|
10
src/timer.rs
10
src/timer.rs
|
@ -5,7 +5,7 @@ use eframe::{App, CreationContext};
|
||||||
use egui::{Color32, Direction, FontId, Layout, RichText, Ui};
|
use egui::{Color32, Direction, FontId, Layout, RichText, Ui};
|
||||||
use egui_extras::{Size, StripBuilder};
|
use egui_extras::{Size, StripBuilder};
|
||||||
|
|
||||||
use crate::{cli::Cli, util::*, Alarm, PREDATOR_FONT};
|
use crate::{cli::Cli, util::*, AIRHORN, PREDATOR_FONT};
|
||||||
|
|
||||||
const MIN_REPAINT: Duration = Duration::from_millis(100);
|
const MIN_REPAINT: Duration = Duration::from_millis(100);
|
||||||
const MAX_REPAINT: Duration = Duration::from_millis(250);
|
const MAX_REPAINT: Duration = Duration::from_millis(250);
|
||||||
|
@ -25,7 +25,7 @@ pub struct Timer {
|
||||||
duration: Duration,
|
duration: Duration,
|
||||||
state: TimerState,
|
state: TimerState,
|
||||||
tstart: Instant, // so we can blink
|
tstart: Instant, // so we can blink
|
||||||
alarm: Option<Alarm>,
|
alarm: Option<Vec<u8>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
@ -96,9 +96,11 @@ impl Timer {
|
||||||
};
|
};
|
||||||
|
|
||||||
let alarm = if let Some(path) = cli.alarm {
|
let alarm = if let Some(path) = cli.alarm {
|
||||||
Some(Alarm::User(path))
|
let buffer = std::fs::read(&path)
|
||||||
|
.unwrap_or_else(|_| panic!("Could not open {:?} for reading.", path));
|
||||||
|
Some(buffer)
|
||||||
} else if cli.airhorn {
|
} else if cli.airhorn {
|
||||||
Some(Alarm::Airhon)
|
Some(AIRHORN.to_owned())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
58
src/util.rs
58
src/util.rs
|
@ -1,55 +1,15 @@
|
||||||
use std::{
|
use std::{io::Cursor, time::Duration};
|
||||||
ffi::OsStr,
|
|
||||||
fs::File,
|
|
||||||
io::{Cursor, Read, Seek},
|
|
||||||
time::Duration,
|
|
||||||
};
|
|
||||||
|
|
||||||
use egui::{Color32, Direction, FontId, Layout, RichText};
|
use egui::{Color32, Direction, FontId, Layout, RichText};
|
||||||
use egui_extras::{Size, Strip};
|
use egui_extras::{Size, Strip};
|
||||||
use rodio::{source::Source, Decoder, OutputStream};
|
use rodio::{source::Source, Decoder, OutputStream};
|
||||||
|
|
||||||
use crate::{Alarm, AIRHORN};
|
|
||||||
|
|
||||||
fn format_digits(digits: u64, size: f32, color: Color32) -> RichText {
|
fn format_digits(digits: u64, size: f32, color: Color32) -> RichText {
|
||||||
RichText::new(format!("{:02}", digits))
|
RichText::new(format!("{:02}", digits))
|
||||||
.font(FontId::monospace(size))
|
.font(FontId::monospace(size))
|
||||||
.color(color)
|
.color(color)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn alarm(source: Alarm) {
|
|
||||||
if let Alarm::User(path) = source {
|
|
||||||
play_user(&path)
|
|
||||||
} else {
|
|
||||||
let source = Cursor::new(AIRHORN.to_owned());
|
|
||||||
let decoder = Decoder::new(source).unwrap();
|
|
||||||
play_alarm(decoder);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn play_user(path: &OsStr) {
|
|
||||||
let mut f = File::open(path).unwrap_or_else(|_| panic!("Could not open file {:?}", path));
|
|
||||||
let metadata = std::fs::metadata(path).expect("unable to read metadata");
|
|
||||||
let mut buffer = vec![0; metadata.len() as usize];
|
|
||||||
f.read_exact(&mut buffer).expect("buffer overflow");
|
|
||||||
let file = Cursor::new(buffer);
|
|
||||||
let source = Decoder::new(file).unwrap();
|
|
||||||
play_alarm(source);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn play_alarm<S: Read + Seek + Send + 'static>(source: Decoder<S>) {
|
|
||||||
let (_stream, stream_handle) = OutputStream::try_default().unwrap();
|
|
||||||
|
|
||||||
let dur = if let Some(dur) = source.total_duration() {
|
|
||||||
dur
|
|
||||||
} else {
|
|
||||||
Duration::from_secs(10)
|
|
||||||
};
|
|
||||||
|
|
||||||
let _ = stream_handle.play_raw(source.convert_samples());
|
|
||||||
std::thread::sleep(dur);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn display_digits(strip: &mut Strip, dur: Duration, color: Color32, size: f32) {
|
pub(crate) fn display_digits(strip: &mut Strip, dur: Duration, color: Color32, size: f32) {
|
||||||
let hours = dur.as_secs() / 3600;
|
let hours = dur.as_secs() / 3600;
|
||||||
let minutes = (dur.as_secs() / 60) % 60;
|
let minutes = (dur.as_secs() / 60) % 60;
|
||||||
|
@ -75,3 +35,19 @@ pub(crate) fn display_digits(strip: &mut Strip, dur: Duration, color: Color32, s
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn alarm(source: Vec<u8>) {
|
||||||
|
let source = Cursor::new(source);
|
||||||
|
let source = Decoder::new(source).unwrap();
|
||||||
|
|
||||||
|
let (_stream, stream_handle) = OutputStream::try_default().unwrap();
|
||||||
|
|
||||||
|
let dur = if let Some(dur) = source.total_duration() {
|
||||||
|
dur
|
||||||
|
} else {
|
||||||
|
Duration::from_secs(10)
|
||||||
|
};
|
||||||
|
|
||||||
|
let _ = stream_handle.play_raw(source.convert_samples());
|
||||||
|
std::thread::sleep(dur);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue