Skip to main content

dioxus_audio/
components.rs

1//! Reusable visual audio components.
2
3use dioxus::prelude::*;
4
5mod devices;
6mod player;
7mod recorder;
8mod visualizer;
9mod waveform;
10
11pub use devices::{AudioInputSelector, MicrophoneStatusIndicator};
12pub use player::AudioPlayer;
13pub use recorder::RecorderControls;
14pub use visualizer::{LevelMeter, LiveWaveform, SpectrumVisualizer};
15pub use waveform::{WaveformPreview, WaveformRangeSelector};
16
17pub static STYLESHEET: Asset = asset!("/assets/dioxus-audio.css");
18
19#[component]
20pub fn AudioStyles() -> Element {
21    rsx! { document::Stylesheet { href: STYLESHEET } }
22}
23
24#[component]
25pub fn AudioScrubber(
26    position_secs: f64,
27    duration_secs: f64,
28    on_seek: EventHandler<f64>,
29    #[props(default = false)] disabled: bool,
30    #[props(default)] aria_label: Option<String>,
31) -> Element {
32    let duration_secs = finite_non_negative(duration_secs);
33    let position_secs = finite_non_negative(position_secs).min(duration_secs);
34    let progress = if duration_secs > 0.0 {
35        position_secs / duration_secs * 100.0
36    } else {
37        0.0
38    };
39    let aria_label = aria_label.unwrap_or_else(|| "Seek audio".to_string());
40
41    rsx! {
42        div { class: "dioxus-audio dioxus-audio__scrubber",
43            div { class: "dioxus-audio__scrubber-track",
44                div {
45                    class: "dioxus-audio__scrubber-fill",
46                    style: "width: {progress}%",
47                }
48            }
49            input {
50                class: "dioxus-audio__scrubber-input",
51                r#type: "range",
52                min: "0",
53                max: "{duration_secs}",
54                step: "0.01",
55                value: "{position_secs}",
56                disabled,
57                aria_label,
58                oninput: move |event| {
59                    if let Ok(value) = event.value().parse::<f64>() {
60                        on_seek.call(value);
61                    }
62                },
63            }
64        }
65    }
66}
67
68fn finite_non_negative(value: f64) -> f64 {
69    if value.is_finite() {
70        value.max(0.0)
71    } else {
72        0.0
73    }
74}