rust_kanban/ui/rendering/view/
signup.rs1use crate::{
2 app::{
3 state::{AppStatus, Focus, KeyBindingEnum},
4 App,
5 },
6 constants::HIDDEN_PASSWORD_SYMBOL,
7 ui::{
8 rendering::{
9 common::{
10 draw_crab_pattern, draw_title, render_blank_styled_canvas_with_margin,
11 render_close_button,
12 },
13 utils::{
14 calculate_viewport_corrected_cursor_position, centered_rect_with_length,
15 check_if_active_and_get_style, get_mouse_focusable_field_style,
16 },
17 view::Signup,
18 },
19 Renderable,
20 },
21};
22use ratatui::{
23 layout::{Alignment, Constraint, Direction, Layout},
24 text::{Line, Span},
25 widgets::{Block, BorderType, Borders, Clear, Paragraph},
26 Frame,
27};
28
29impl Renderable for Signup {
30 fn render(rect: &mut Frame, app: &mut App, is_active: bool) {
31 if is_active {
32 if app.state.focus == Focus::EmailIDField
33 || app.state.focus == Focus::PasswordField
34 || app.state.focus == Focus::ConfirmPasswordField
35 {
36 if app.state.app_status != AppStatus::UserInput {
37 app.state.app_status = AppStatus::UserInput;
38 }
39 } else if app.state.app_status != AppStatus::Initialized {
40 app.state.app_status = AppStatus::Initialized;
41 }
42 }
43
44 let main_chunks = Layout::default()
45 .direction(Direction::Vertical)
46 .constraints([Constraint::Length(3), Constraint::Fill(1)].as_ref())
47 .split(rect.area());
48
49 let chunks = Layout::default()
50 .direction(Direction::Horizontal)
51 .constraints([
52 Constraint::Fill(1),
53 Constraint::Length(2),
54 Constraint::Length(50),
55 ])
56 .split(main_chunks[1]);
57
58 let info_box = centered_rect_with_length(30, 10, chunks[0]);
59
60 let info_chunks = Layout::default()
61 .direction(Direction::Vertical)
62 .constraints(
63 [
64 Constraint::Length(1),
65 Constraint::Length(1),
66 Constraint::Length(3),
67 ]
68 .as_ref(),
69 )
70 .margin(1)
71 .split(info_box);
72
73 let form_chunks = Layout::default()
74 .direction(Direction::Vertical)
75 .constraints([
76 Constraint::Length((chunks[2].height - 15) / 2),
77 Constraint::Length(3),
78 Constraint::Length(3),
79 Constraint::Length(3),
80 Constraint::Length(3),
81 Constraint::Length(3),
82 Constraint::Length((chunks[2].height - 15) / 2),
83 ])
84 .margin(1)
85 .split(chunks[2]);
86
87 let show_password_chunks = Layout::default()
88 .direction(Direction::Horizontal)
89 .constraints([
90 Constraint::Length(form_chunks[3].width - 7),
91 Constraint::Length(5),
92 ])
93 .margin(1)
94 .split(form_chunks[4]);
95
96 let submit_button_chunks = Layout::default()
97 .direction(Direction::Horizontal)
98 .constraints([
99 Constraint::Length((form_chunks[4].width - 12) / 2),
100 Constraint::Length(12),
101 Constraint::Length((form_chunks[4].width - 12) / 2),
102 ])
103 .split(form_chunks[5]);
104
105 let email_id_field_style = get_mouse_focusable_field_style(
106 app,
107 Focus::EmailIDField,
108 &form_chunks[1],
109 is_active,
110 true,
111 );
112
113 let password_field_style = get_mouse_focusable_field_style(
114 app,
115 Focus::PasswordField,
116 &form_chunks[2],
117 is_active,
118 true,
119 );
120
121 let confirm_password_field_style = get_mouse_focusable_field_style(
122 app,
123 Focus::ConfirmPasswordField,
124 &form_chunks[3],
125 is_active,
126 true,
127 );
128
129 let show_password_checkbox_style = get_mouse_focusable_field_style(
130 app,
131 Focus::ExtraFocus,
132 &show_password_chunks[1],
133 is_active,
134 false,
135 );
136
137 let submit_button_style = get_mouse_focusable_field_style(
138 app,
139 Focus::SubmitButton,
140 &submit_button_chunks[1],
141 is_active,
142 false,
143 );
144
145 let general_style = check_if_active_and_get_style(
146 is_active,
147 app.current_theme.inactive_text_style,
148 app.current_theme.general_style,
149 );
150 let help_key_style = check_if_active_and_get_style(
151 is_active,
152 app.current_theme.inactive_text_style,
153 app.current_theme.help_key_style,
154 );
155 let help_text_style = check_if_active_and_get_style(
156 is_active,
157 app.current_theme.inactive_text_style,
158 app.current_theme.help_text_style,
159 );
160
161 let crab_paragraph = draw_crab_pattern(
162 chunks[0],
163 app.current_theme.inactive_text_style,
164 is_active,
165 app.config.disable_animations,
166 );
167
168 let info_border = Block::default()
169 .borders(Borders::ALL)
170 .border_type(BorderType::Rounded)
171 .border_style(general_style);
172
173 let info_paragraph = Paragraph::new("Sign Up")
174 .style(general_style)
175 .block(Block::default())
176 .alignment(Alignment::Center);
177
178 let accept_key = app
179 .get_first_keybinding(KeyBindingEnum::Accept)
180 .unwrap_or("".to_string());
181 let next_focus_key = app
182 .get_first_keybinding(KeyBindingEnum::NextFocus)
183 .unwrap_or("".to_string());
184 let prv_focus_key = app
185 .get_first_keybinding(KeyBindingEnum::PrvFocus)
186 .unwrap_or("".to_string());
187
188 let help_spans = vec![
189 Span::styled("Press ", help_text_style),
190 Span::styled(next_focus_key, help_key_style),
191 Span::styled(" or ", help_text_style),
192 Span::styled(prv_focus_key, help_key_style),
193 Span::styled(" to change focus. Press ", help_text_style),
194 Span::styled(accept_key, help_key_style),
195 Span::styled(" to submit.", help_text_style),
196 ];
197
198 let help_paragraph = Paragraph::new(Line::from(help_spans))
199 .style(general_style)
200 .block(Block::default())
201 .alignment(Alignment::Center)
202 .wrap(ratatui::widgets::Wrap { trim: true });
203
204 let separator = Block::default()
205 .borders(Borders::ALL)
206 .border_type(BorderType::Rounded)
207 .border_style(general_style);
208
209 let email_id_block = Block::default()
210 .style(email_id_field_style)
211 .borders(Borders::ALL)
212 .border_type(BorderType::Rounded);
213
214 let password_block = Block::default()
215 .style(password_field_style)
216 .borders(Borders::ALL)
217 .border_type(BorderType::Rounded);
218
219 let confirm_password_block = Block::default()
220 .style(confirm_password_field_style)
221 .borders(Borders::ALL)
222 .border_type(BorderType::Rounded);
223
224 app.state
225 .text_buffers
226 .email_id
227 .set_placeholder_text("Email ID");
228
229 app.state.text_buffers.email_id.set_block(email_id_block);
230
231 app.state
232 .text_buffers
233 .password
234 .set_placeholder_text("Password");
235
236 app.state.text_buffers.password.set_block(password_block);
237
238 app.state
239 .text_buffers
240 .confirm_password
241 .set_placeholder_text("Confirm Password");
242
243 app.state
244 .text_buffers
245 .confirm_password
246 .set_block(confirm_password_block);
247
248 let show_password_paragraph = Paragraph::new("Show Password")
249 .style(general_style)
250 .block(Block::default())
251 .alignment(Alignment::Right);
252
253 let show_password_checkbox_value = if app.state.show_password {
254 "[X]"
255 } else {
256 "[ ]"
257 };
258
259 let show_password_checkbox_paragraph = Paragraph::new(show_password_checkbox_value)
260 .style(show_password_checkbox_style)
261 .block(Block::default())
262 .alignment(Alignment::Center);
263
264 let submit_button = Paragraph::new("Submit")
265 .style(submit_button_style)
266 .block(
267 Block::default()
268 .borders(Borders::ALL)
269 .border_type(BorderType::Rounded),
270 )
271 .alignment(Alignment::Center);
272
273 rect.render_widget(draw_title(app, main_chunks[0], is_active), main_chunks[0]);
274 rect.render_widget(crab_paragraph, chunks[0]);
275 rect.render_widget(Clear, info_box);
276 render_blank_styled_canvas_with_margin(rect, app, info_box, is_active, -1);
277 rect.render_widget(info_border, info_box);
278 rect.render_widget(info_paragraph, info_chunks[0]);
279 rect.render_widget(help_paragraph, info_chunks[2]);
280 rect.render_widget(separator, chunks[1]);
281 rect.render_widget(app.state.text_buffers.email_id.widget(), form_chunks[1]);
282
283 if app.state.show_password {
284 rect.render_widget(app.state.text_buffers.password.widget(), form_chunks[2]);
285 rect.render_widget(
286 app.state.text_buffers.confirm_password.widget(),
287 form_chunks[3],
288 );
289 } else {
290 if app.state.text_buffers.password.is_empty() {
291 rect.render_widget(app.state.text_buffers.password.widget(), form_chunks[2]);
292 } else {
293 let hidden_text = HIDDEN_PASSWORD_SYMBOL
294 .to_string()
295 .repeat(app.state.text_buffers.password.get_joined_lines().len());
296 let hidden_paragraph = Paragraph::new(hidden_text)
297 .style(password_field_style)
298 .block(
299 Block::default()
300 .borders(Borders::ALL)
301 .border_type(BorderType::Rounded),
302 );
303 rect.render_widget(hidden_paragraph, form_chunks[2]);
304 }
305 if app.state.text_buffers.confirm_password.is_empty() {
306 rect.render_widget(
307 app.state.text_buffers.confirm_password.widget(),
308 form_chunks[3],
309 );
310 } else {
311 let hidden_text = HIDDEN_PASSWORD_SYMBOL.to_string().repeat(
313 app.state
314 .text_buffers
315 .confirm_password
316 .get_joined_lines()
317 .len(),
318 );
319 let hidden_paragraph = Paragraph::new(hidden_text)
320 .style(confirm_password_field_style)
321 .block(
322 Block::default()
323 .borders(Borders::ALL)
324 .border_type(BorderType::Rounded),
325 );
326 rect.render_widget(hidden_paragraph, form_chunks[3]);
327 }
328 }
329
330 rect.render_widget(show_password_paragraph, show_password_chunks[0]);
331 rect.render_widget(show_password_checkbox_paragraph, show_password_chunks[1]);
332 rect.render_widget(submit_button, submit_button_chunks[1]);
333 if app.config.enable_mouse_support {
334 render_close_button(rect, app, is_active)
335 }
336
337 if app.state.app_status == AppStatus::UserInput {
338 match app.state.focus {
339 Focus::EmailIDField => {
340 let (x_pos, y_pos) = calculate_viewport_corrected_cursor_position(
341 &app.state.text_buffers.email_id,
342 &app.config.show_line_numbers,
343 &form_chunks[1],
344 );
345 rect.set_cursor_position((x_pos, y_pos));
346 }
347 Focus::PasswordField => {
348 let (x_pos, y_pos) = calculate_viewport_corrected_cursor_position(
349 &app.state.text_buffers.password,
350 &app.config.show_line_numbers,
351 &form_chunks[2],
352 );
353 rect.set_cursor_position((x_pos, y_pos));
354 }
355 Focus::ConfirmPasswordField => {
356 let (x_pos, y_pos) = calculate_viewport_corrected_cursor_position(
357 &app.state.text_buffers.confirm_password,
358 &app.config.show_line_numbers,
359 &form_chunks[3],
360 );
361 rect.set_cursor_position((x_pos, y_pos));
362 }
363 _ => {}
364 }
365 }
366 }
367}