Skip to main content

ferroui_android/
application_lifetime.rs

1use ferroui_base::logging::{LogArea, LogEventLevel, Logger};
2use ferroui_base::Ref;
3use ferroui_controls::application_lifetimes::{
4    IActivityApplicationLifetime, IApplicationLifetime, ISingleViewApplicationLifetime,
5};
6use ferroui_controls::Control;
7use std::any::Any;
8use std::cell::RefCell;
9use std::rc::Rc;
10
11/// The lifetime of an Android application: every main activity asks the
12/// factory for its main view.
13#[derive(Default)]
14pub struct ApplicationLifetime {
15    main_view: RefCell<Option<Ref<Control>>>,
16    main_view_factory: RefCell<Option<Rc<dyn Fn() -> Ref<Control>>>>,
17}
18
19impl ApplicationLifetime {
20    pub fn new() -> Rc<Self> {
21        Rc::new(Self::default())
22    }
23}
24
25impl IApplicationLifetime for ApplicationLifetime {
26    fn as_any(&self) -> &dyn Any {
27        self
28    }
29
30    fn as_single_view_application_lifetime(&self) -> Option<&dyn ISingleViewApplicationLifetime> {
31        Some(self)
32    }
33
34    fn as_activity_application_lifetime(&self) -> Option<&dyn IActivityApplicationLifetime> {
35        Some(self)
36    }
37}
38
39impl IActivityApplicationLifetime for ApplicationLifetime {
40    fn main_view_factory(&self) -> Option<Rc<dyn Fn() -> Ref<Control>>> {
41        self.main_view_factory.borrow().clone()
42    }
43
44    fn set_main_view_factory(&self, value: Option<Rc<dyn Fn() -> Ref<Control>>>) {
45        let previous = self.main_view_factory.replace(value);
46        drop(previous);
47    }
48}
49
50impl ISingleViewApplicationLifetime for ApplicationLifetime {
51    fn main_view(&self) -> Option<Ref<Control>> {
52        self.main_view.borrow().clone()
53    }
54
55    fn set_main_view(&self, value: Option<Ref<Control>>) {
56        let previous = self.main_view.replace(value.clone());
57        drop(previous);
58
59        if let Some(logger) = Logger::try_get(LogEventLevel::Warning, LogArea::ANDROID_PLATFORM) {
60            logger.log(
61                None,
62                "ISingleViewApplicationLifetime.MainView is not fully supported on Android. \
63                 Consider setting IActivityApplicationLifetime.MainViewFactory.",
64            );
65        }
66        match value {
67            Some(main_view) => self.set_main_view_factory(Some(Rc::new(move || main_view.clone()))),
68            None => self.set_main_view_factory(None),
69        }
70    }
71}
72
73#[cfg(test)]
74mod tests {
75    // Not from the reference, which has no tests of the lifetime.
76    use super::*;
77
78    #[test]
79    fn the_lifetime_is_a_single_view_and_an_activity_lifetime() {
80        let lifetime = ApplicationLifetime::new();
81        let lifetime: &dyn IApplicationLifetime = &*lifetime;
82
83        assert!(lifetime.as_single_view_application_lifetime().is_some());
84        assert!(lifetime.as_activity_application_lifetime().is_some());
85        assert!(lifetime.as_controlled_application_lifetime().is_none());
86        assert!(lifetime.as_classic_desktop_style_application_lifetime().is_none());
87    }
88
89    #[test]
90    fn a_lifetime_starts_without_a_view_and_without_a_factory() {
91        let lifetime = ApplicationLifetime::new();
92
93        assert!(lifetime.main_view().is_none());
94        assert!(lifetime.main_view_factory().is_none());
95    }
96
97    #[test]
98    fn clearing_the_main_view_clears_the_factory() {
99        let lifetime = ApplicationLifetime::new();
100        lifetime.set_main_view_factory(Some(Rc::new(|| panic!("not called"))));
101
102        lifetime.set_main_view(None);
103
104        assert!(lifetime.main_view_factory().is_none());
105    }
106}