Skip to main content

easyofd_core/action/
sound.rs

1//! 音频播放动作。
2//!
3//! 对应 Java: org.ofdrw.core.action.actionType.Sound
4
5use super::OfdAction;
6
7/// 音频播放动作。
8///
9/// 播放一个音频资源,对应 GB/T 33190 第 15 章的 Sound 动作。
10///
11/// 对应 Java: org.ofdrw.core.action.actionType.Sound
12#[derive(Debug, Clone)]
13pub struct Sound {
14    /// 音频资源的引用 ID。
15    ///
16    /// 对应 Java: Sound.mediaRef (String)
17    pub media_ref: String,
18
19    /// 音量(0.0 ~ 1.0)。
20    ///
21    /// 对应 Java: Sound.volume (Double)
22    pub volume: f64,
23
24    /// 是否循环播放。
25    ///
26    /// 对应 Java: Sound.repeat (Boolean)
27    pub repeat: bool,
28}
29
30impl Sound {
31    /// 创建一个新的音频播放动作。
32    ///
33    /// 对应 Java: new Sound(String mediaRef)
34    #[must_use]
35    pub fn new(media_ref: impl Into<String>) -> Self {
36        Self {
37            media_ref: media_ref.into(),
38            volume: 1.0,
39            repeat: false,
40        }
41    }
42
43    /// 设置音量。
44    ///
45    /// 对应 Java: Sound.setVolume(Double)
46    #[must_use]
47    pub fn volume(mut self, volume: f64) -> Self {
48        self.volume = volume;
49        self
50    }
51
52    /// 设置是否循环播放。
53    ///
54    /// 对应 Java: Sound.setRepeat(Boolean)
55    #[must_use]
56    pub fn repeat(mut self, repeat: bool) -> Self {
57        self.repeat = repeat;
58        self
59    }
60}
61
62impl OfdAction for Sound {
63    fn to_xml_string(&self) -> String {
64        format!(
65            "<ofd:Sound MediaRef=\"{}\" Volume=\"{}\" Repeat=\"{}\"/>",
66            self.media_ref, self.volume, self.repeat
67        )
68    }
69
70    fn clone_box(&self) -> Box<dyn OfdAction> {
71        Box::new(self.clone())
72    }
73}
74
75#[cfg(test)]
76mod tests {
77    use super::*;
78
79    #[test]
80    fn test_sound_new() {
81        let sound = Sound::new("media_001");
82        assert_eq!(sound.media_ref, "media_001");
83        assert!((sound.volume - 1.0).abs() < f64::EPSILON);
84        assert!(!sound.repeat);
85    }
86
87    #[test]
88    fn test_sound_builder() {
89        let sound = Sound::new("media_002").volume(0.5).repeat(true);
90        assert_eq!(sound.media_ref, "media_002");
91        assert!((sound.volume - 0.5).abs() < f64::EPSILON);
92        assert!(sound.repeat);
93    }
94
95    #[test]
96    fn test_sound_to_xml() {
97        let sound = Sound::new("audio_1").volume(0.8).repeat(false);
98        let xml = sound.to_xml_string();
99        assert!(xml.contains("MediaRef=\"audio_1\""));
100        assert!(xml.contains("Volume=\"0.8\""));
101        assert!(xml.contains("Repeat=\"false\""));
102        assert!(xml.contains("<ofd:Sound"));
103    }
104
105    #[test]
106    fn test_sound_clone_debug() {
107        let sound = Sound::new("m1");
108        let sound2 = sound.clone();
109        assert_eq!(sound2.media_ref, "m1");
110        let dbg = format!("{sound:?}");
111        assert!(dbg.contains("Sound"));
112    }
113}