1use crate::button::{Button, ButtonMessages, ButtonOptions, ButtonShape, SceneBuilderButtonExt};
6use crate::constants::constants::{
7 BACKGROUND_WHITE, BUTTON_SPACE, LEFT_MARGIN_SPACE, TEXT_COLOR, TEXT_FONT_SIZE, TITLE_COLOR,
8 TITLE_FONT_SIZE,
9};
10use crate::generic_view::ButtonInfo;
11use crate::text_field::{SceneBuilderTextFieldExt, TextField, TextFieldOptions, TextVisibility};
12use anyhow::Error;
13use carnelian::drawing::load_font;
14use carnelian::render::Context as RenderContext;
15use carnelian::scene::facets::{TextFacetOptions, TextHorizontalAlignment, TextVerticalAlignment};
16use carnelian::scene::layout::{
17 CrossAxisAlignment, Flex, FlexOptions, MainAxisAlignment, MainAxisSize,
18};
19use carnelian::scene::scene::{Scene, SceneBuilder};
20use carnelian::{
21 input, make_message, AppSender, Message, MessageTarget, Point, Size, ViewAssistant,
22 ViewAssistantContext, ViewKey,
23};
24use euclid::size2;
25use std::path::PathBuf;
26
27const TEXT_FIELD_WIDTH: f32 = 895.0;
28
29pub struct SceneDetails {
30 pub(crate) scene: Scene,
31 password_field: TextField,
32 buttons: Vec<Button>,
33}
34
35pub struct CheckNetworkViewAssistant {
37 app_sender: AppSender,
38 view_key: ViewKey,
39 title_text: String,
40 body_text: String,
41 network: String,
42 password: String,
43 privacy: bool,
44 button_infos: Vec<ButtonInfo>,
45 scene_details: Option<SceneDetails>,
46}
47
48impl CheckNetworkViewAssistant {
49 pub fn new(
50 app_sender: AppSender,
51 view_key: ViewKey,
52 title_text: String,
53 body_text: String,
54 network: String,
55 password: String,
56 button_infos: Vec<ButtonInfo>,
57 ) -> Result<CheckNetworkViewAssistant, Error> {
58 Ok(CheckNetworkViewAssistant {
59 app_sender: app_sender,
60 view_key,
61 scene_details: None,
62 title_text,
63 body_text,
64 network,
65 password,
66 privacy: true,
67 button_infos,
68 })
69 }
70
71 fn button_press(&mut self, text: &String) {
72 for button_info in &self.button_infos {
73 if button_info.text == text {
75 #[cfg(feature = "debug_logging")]
76 println!("====== Generating event: {:?}", button_info.event);
77 self.app_sender.queue_message(
78 MessageTarget::View(self.view_key),
79 make_message(button_info.event.clone()),
80 )
81 }
82 }
83 if let Some(scene_details) = &mut self.scene_details {
84 if scene_details.password_field.get_title() == text {
85 self.privacy = !self.privacy;
86 self.scene_details = None;
87 }
88 }
89 }
90
91 pub fn check_network_scene(&mut self, context: &ViewAssistantContext) -> SceneDetails {
92 let target_size = context.size;
93 let mut builder = SceneBuilder::new().background_color(BACKGROUND_WHITE);
94 let mut buttons: Vec<Button> = Vec::new();
95 let face = load_font(PathBuf::from("/pkg/data/fonts/Roboto-Regular.ttf")).expect("Font");
96 let mut password_field: Option<TextField> = None;
97 builder.group().column().max_size().main_align(MainAxisAlignment::SpaceEvenly).contents(
98 |builder| {
99 builder.start_group(
100 "left row for margin space",
101 Flex::with_options_ptr(FlexOptions::row(
102 MainAxisSize::Min,
103 MainAxisAlignment::Start,
104 CrossAxisAlignment::Start,
105 )),
106 );
107 builder.space(size2(LEFT_MARGIN_SPACE, 10.0));
108 builder.start_group(
109 "main column",
110 Flex::with_options_ptr(FlexOptions::column(
111 MainAxisSize::Min,
112 MainAxisAlignment::Start,
113 CrossAxisAlignment::Start,
114 )),
115 );
116 builder.space(size2(10.0, 30.0));
117 builder.text(
118 face.clone(),
119 &self.title_text,
120 TITLE_FONT_SIZE,
121 Point::zero(),
122 TextFacetOptions {
123 horizontal_alignment: TextHorizontalAlignment::Left,
124 vertical_alignment: TextVerticalAlignment::Bottom,
125 color: TITLE_COLOR,
126 ..TextFacetOptions::default()
127 },
128 );
129 builder.space(size2(10.0, 30.0));
130 builder.text(
131 face.clone(),
132 &self.body_text,
133 TEXT_FONT_SIZE,
134 Point::zero(),
135 TextFacetOptions {
136 horizontal_alignment: TextHorizontalAlignment::Left,
137 vertical_alignment: TextVerticalAlignment::Bottom,
138 color: TEXT_COLOR,
139 ..TextFacetOptions::default()
140 },
141 );
142 builder.space(size2(1.0, 50.0));
143 builder.text_field(
144 "Network".to_string(),
145 self.network.clone(),
146 TextVisibility::Always,
147 size2(TEXT_FIELD_WIDTH, TEXT_FONT_SIZE * 3.0),
148 TextFieldOptions { text_size: TEXT_FONT_SIZE, ..TextFieldOptions::default() },
149 );
150 builder.space(size2(10.0, 40.0));
151 password_field = Some(builder.text_field(
152 "Password".to_string(),
153 self.password.clone(),
154 TextVisibility::Toggleable(!self.privacy),
155 size2(TEXT_FIELD_WIDTH, TEXT_FONT_SIZE * 3.0),
156 TextFieldOptions { text_size: TEXT_FONT_SIZE, ..TextFieldOptions::default() },
157 ));
158 builder.space(size2(10.0, 50.0));
159 buttons.append(&mut self.add_buttons(builder, &self.button_infos));
160
161 builder.end_group(); builder.end_group(); },
164 );
165 let mut scene = builder.build();
166 for button in &mut buttons {
167 button.set_focused(&mut scene, true);
168 }
169 password_field.as_mut().unwrap().set_focused(&mut scene, true);
170 scene.layout(target_size);
171 SceneDetails { scene, password_field: password_field.unwrap(), buttons }
172 }
173
174 fn add_buttons(
175 &self,
176 builder: &mut SceneBuilder,
177 button_infos: &Vec<ButtonInfo>,
178 ) -> Vec<Button> {
179 let mut buttons: Vec<Button> = Vec::new();
180 if !button_infos.is_empty() {
181 builder.start_group(
182 "Button Row",
183 Flex::with_options_ptr(FlexOptions::row(
184 MainAxisSize::Max,
185 MainAxisAlignment::End,
186 CrossAxisAlignment::End,
187 )),
188 );
189 for button_info in button_infos {
190 buttons.push(builder.button(
191 button_info.text,
192 None,
193 ButtonOptions {
194 shape: ButtonShape::Oval,
195 bg_fg_swapped: button_info.reversed,
196 ..ButtonOptions::default()
197 },
198 ));
199 builder.space(size2(BUTTON_SPACE, 10.0));
200 }
201 builder.space(size2(117.0, 10.0));
203 builder.end_group(); }
205 buttons
206 }
207}
208
209impl ViewAssistant for CheckNetworkViewAssistant {
210 fn resize(&mut self, _new_size: &Size) -> Result<(), Error> {
211 self.scene_details = None;
212 Ok(())
213 }
214
215 fn render(
216 &mut self,
217 render_context: &mut RenderContext,
218 ready_event: zx::Event,
219 context: &ViewAssistantContext,
220 ) -> Result<(), Error> {
221 let mut scene_details =
222 self.scene_details.take().unwrap_or_else(|| self.check_network_scene(context));
223 scene_details.scene.render(render_context, ready_event, context)?;
224 self.scene_details = Some(scene_details);
225 context.request_render();
226 Ok(())
227 }
228
229 fn handle_message(&mut self, message: Message) {
230 if let Some(button_message) = message.downcast_ref::<ButtonMessages>() {
231 match button_message {
232 ButtonMessages::Pressed(_time, button_text) => {
233 #[cfg(feature = "debug_logging")]
234 println!("====== Received button press: {}", button_text);
235 self.button_press(button_text);
236 }
237 }
238 }
239 }
240
241 fn handle_pointer_event(
242 &mut self,
243 context: &mut ViewAssistantContext,
244 _event: &input::Event,
245 pointer_event: &input::pointer::Event,
246 ) -> Result<(), Error> {
247 if let Some(scene_details) = self.scene_details.as_mut() {
248 for button in &mut scene_details.buttons {
249 button.handle_pointer_event(&mut scene_details.scene, context, &pointer_event);
250 }
251 scene_details.password_field.handle_pointer_event(
253 &mut scene_details.scene,
254 context,
255 &pointer_event,
256 );
257 }
258 Ok(())
259 }
260}