fret_ui_kit/primitives/
switch.rs1use std::sync::Arc;
10
11use fret_runtime::Model;
12use fret_ui::element::PressableA11y;
13use fret_ui::{ElementContext, UiHost};
14
15pub fn switch_a11y(label: Option<Arc<str>>, checked: bool) -> PressableA11y {
17 PressableA11y {
18 role: Some(fret_core::SemanticsRole::Switch),
19 label,
20 checked: Some(checked),
21 ..Default::default()
22 }
23}
24
25pub fn switch_use_checked_model<H: UiHost>(
28 cx: &mut ElementContext<'_, H>,
29 controlled: Option<Model<bool>>,
30 default_checked: impl FnOnce() -> bool,
31) -> crate::primitives::controllable_state::ControllableModel<bool> {
32 crate::primitives::controllable_state::use_controllable_model(cx, controlled, default_checked)
33}
34
35pub fn switch_checked_from_optional_bool(value: Option<bool>) -> bool {
41 value.unwrap_or(false)
42}
43
44pub fn toggle_optional_bool(value: Option<bool>) -> Option<bool> {
46 Some(!switch_checked_from_optional_bool(value))
47}
48
49#[cfg(test)]
50mod tests {
51 use super::*;
52
53 use std::cell::Cell;
54
55 use fret_app::App;
56 use fret_core::{AppWindowId, Point, Px, Rect, Size};
57
58 fn bounds() -> Rect {
59 Rect::new(
60 Point::new(Px(0.0), Px(0.0)),
61 Size::new(Px(200.0), Px(120.0)),
62 )
63 }
64
65 #[test]
66 fn switch_use_checked_model_prefers_controlled_and_does_not_call_default() {
67 let window = AppWindowId::default();
68 let mut app = App::new();
69 let b = bounds();
70
71 let controlled = app.models_mut().insert(true);
72 let called = Cell::new(0);
73
74 fret_ui::elements::with_element_cx(&mut app, window, b, "test", |cx| {
75 let out = switch_use_checked_model(cx, Some(controlled.clone()), || {
76 called.set(called.get() + 1);
77 false
78 });
79 assert!(out.is_controlled());
80 assert_eq!(out.model(), controlled);
81 });
82
83 assert_eq!(called.get(), 0);
84 }
85
86 #[test]
87 fn switch_a11y_sets_role_and_checked() {
88 let a11y = switch_a11y(Some(Arc::from("Airplane mode")), true);
89 assert_eq!(a11y.role, Some(fret_core::SemanticsRole::Switch));
90 assert_eq!(a11y.checked, Some(true));
91 assert_eq!(a11y.label.as_deref(), Some("Airplane mode"));
92 }
93
94 #[test]
95 fn optional_bool_maps_to_checked_state() {
96 assert_eq!(switch_checked_from_optional_bool(None), false);
97 assert_eq!(switch_checked_from_optional_bool(Some(false)), false);
98 assert_eq!(switch_checked_from_optional_bool(Some(true)), true);
99 }
100
101 #[test]
102 fn toggle_optional_bool_inverts_and_sets_some() {
103 assert_eq!(toggle_optional_bool(None), Some(true));
104 assert_eq!(toggle_optional_bool(Some(false)), Some(true));
105 assert_eq!(toggle_optional_bool(Some(true)), Some(false));
106 }
107}