Skip to main content

ferroui_android/
stubs.rs

1use ferroui_base::media::imaging::{BitmapEncoderOptions, PngBitmapEncoderOptions};
2use ferroui_base::platform::SharedBitmapImpl;
3use ferroui_controls::platform::{
4    IPlatformIconLoader, ITopLevelImpl, ITrayIconImpl, IWindowIconImpl, IWindowImpl, IWindowingPlatform,
5};
6use std::fs::File;
7use std::io;
8use std::rc::Rc;
9use std::sync::Arc;
10
11/// The windowing platform of Android. There are no windows: content is
12/// shown by a view in an activity.
13#[derive(Default)]
14pub struct WindowingPlatformStub;
15
16impl IWindowingPlatform for WindowingPlatformStub {
17    fn create_window(&self) -> Rc<dyn IWindowImpl> {
18        panic!("Specified method is not supported.");
19    }
20
21    fn create_embeddable_top_level(&self) -> Rc<dyn ITopLevelImpl> {
22        self.create_embeddable_window()
23    }
24
25    fn create_embeddable_window(&self) -> Rc<dyn IWindowImpl> {
26        panic!("Specified method is not supported.");
27    }
28
29    fn create_tray_icon(&self) -> Option<Rc<dyn ITrayIconImpl>> {
30        None
31    }
32
33    fn get_windows_z_order(&self, _windows: &[Rc<dyn IWindowImpl>], _z_order: &mut [i64]) {
34        panic!("Specified method is not supported.");
35    }
36}
37
38/// The icon loader of a platform without window icons: an icon keeps the
39/// bytes it was loaded from, so that it can be saved.
40#[derive(Default)]
41pub struct PlatformIconLoaderStub;
42
43impl IPlatformIconLoader for PlatformIconLoaderStub {
44    fn load_icon_from_file(&self, file_name: &str) -> io::Result<Rc<dyn IWindowIconImpl>> {
45        let mut file = File::open(file_name)?;
46        self.load_icon_from_stream(&mut file)
47    }
48
49    fn load_icon_from_stream(&self, stream: &mut dyn io::Read) -> io::Result<Rc<dyn IWindowIconImpl>> {
50        let mut ms = Vec::new();
51        stream.read_to_end(&mut ms)?;
52        Ok(Rc::new(IconStub::new(ms)))
53    }
54
55    fn load_icon_from_bitmap(&self, bitmap: Arc<SharedBitmapImpl>) -> Rc<dyn IWindowIconImpl> {
56        let mut stream = Vec::new();
57        // A bitmap that cannot be encoded gives an icon without bytes: the contract has no
58        // failure for this member, and the icon is never shown.
59        if bitmap.save(&mut stream, &BitmapEncoderOptions::Png(PngBitmapEncoderOptions::DEFAULT)).is_err() {
60            stream.clear();
61        }
62        Rc::new(IconStub::new(stream))
63    }
64}
65
66pub(crate) struct IconStub {
67    ms: Vec<u8>,
68}
69
70impl IconStub {
71    pub(crate) fn new(stream: Vec<u8>) -> Self {
72        Self { ms: stream }
73    }
74}
75
76impl IWindowIconImpl for IconStub {
77    fn save(&self, output_stream: &mut dyn io::Write) -> io::Result<()> {
78        output_stream.write_all(&self.ms)
79    }
80}
81
82#[cfg(test)]
83mod tests {
84    // Not from the reference, which has no tests of the stubs.
85    use super::*;
86
87    #[test]
88    fn there_is_no_tray_icon() {
89        assert!(WindowingPlatformStub.create_tray_icon().is_none());
90    }
91
92    #[test]
93    #[should_panic(expected = "Specified method is not supported")]
94    fn windows_cannot_be_created() {
95        WindowingPlatformStub.create_window();
96    }
97
98    #[test]
99    #[should_panic(expected = "Specified method is not supported")]
100    fn embeddable_top_levels_cannot_be_created() {
101        WindowingPlatformStub.create_embeddable_top_level();
102    }
103
104    #[test]
105    #[should_panic(expected = "Specified method is not supported")]
106    fn the_z_order_of_windows_is_not_available() {
107        WindowingPlatformStub.get_windows_z_order(&[], &mut []);
108    }
109
110    #[test]
111    fn an_icon_of_a_stream_saves_the_bytes_of_the_stream() {
112        let loader = PlatformIconLoaderStub;
113        let icon = loader.load_icon_from_stream(&mut io::Cursor::new(vec![1, 2, 3])).unwrap();
114        let mut output = Vec::new();
115
116        icon.save(&mut output).unwrap();
117        icon.save(&mut output).unwrap();
118
119        assert_eq!(output, [1, 2, 3, 1, 2, 3]);
120    }
121
122    #[test]
123    fn a_missing_file_is_an_error() {
124        assert!(PlatformIconLoaderStub.load_icon_from_file("/nonexistent/icon.png").is_err());
125    }
126}