Skip to main content

veloren_voxygen/menu/main/ui/
credentials.rs

1use super::{Imgs, LoginInfo, Message, TEXT_COLOR};
2use crate::ui::{
3    fonts::IcedFonts as Fonts,
4    ice::{
5        Element, style,
6        widget::{BackgroundContainer, Image, Padding},
7    },
8};
9
10use credentialstore::CredentialStatus;
11use i18n::Localization;
12use iced::{Align, Button, Column, Container, Length, Space, Text, TextInput, button, text_input};
13
14const INPUT_WIDTH: u16 = 230;
15const INPUT_TEXT_SIZE: u16 = 20;
16
17/// Credential prompt for the connecting screen
18#[derive(Default)]
19pub struct Prompt {
20    pub(super) error: Option<String>,
21    secure_service_button: button::State,
22    submit_button: button::State,
23    username: text_input::State,
24    password: text_input::State,
25}
26
27impl Prompt {
28    pub(super) fn view(
29        &mut self,
30        fonts: &Fonts,
31        imgs: &Imgs,
32        login_info: &LoginInfo,
33        auth_server: &Option<String>,
34        i18n: &Localization,
35        button_style: style::button::Style,
36    ) -> Element<'_, Message> {
37        let title_text = Text::new("Login").size(fonts.cyri.scale(25));
38        let password_required = auth_server.is_some();
39        let msg = if let Some(auth_server) = auth_server {
40            i18n.get_msg_ctx("main-login-enter-credentials", &i18n::fluent_args! {
41                "server" => auth_server
42            })
43        } else {
44            i18n.get_msg("main-login-enter-username")
45        };
46        let msg_text = Text::new(msg)
47            .size(fonts.cyri.scale(15))
48            .width(Length::Fill);
49        let input_text_size = fonts.cyri.scale(INPUT_TEXT_SIZE);
50
51        let username = BackgroundContainer::new(
52            Image::new(imgs.input_bg)
53                .width(Length::Units(INPUT_WIDTH))
54                .fix_aspect_ratio(),
55            TextInput::new(
56                &mut self.username,
57                &i18n.get_msg("main-username"),
58                &login_info.username,
59                Message::Username,
60            )
61            .size(input_text_size)
62            .on_submit(if password_required {
63                Message::FocusPassword
64            } else {
65                Message::CredentialsSubmit
66            }),
67        )
68        .padding(Padding::new().horizontal(7).top(5));
69
70        let mut inputs = vec![username.into()];
71        if password_required {
72            inputs.push(
73                BackgroundContainer::new(
74                    Image::new(imgs.input_bg)
75                        .width(Length::Units(INPUT_WIDTH))
76                        .fix_aspect_ratio(),
77                    TextInput::new(
78                        &mut self.password,
79                        &i18n.get_msg("main-password"),
80                        &login_info.password,
81                        Message::Password,
82                    )
83                    .size(input_text_size)
84                    .password()
85                    .on_submit(Message::CredentialsSubmit),
86                )
87                .padding(Padding::new().horizontal(7).top(5))
88                .into(),
89            );
90
91            if login_info.secure_service_status > CredentialStatus::Disabled {
92                let text_color = if login_info.secure_service_status == CredentialStatus::Ready {
93                    TEXT_COLOR
94                } else {
95                    // XAG 102 (Inactive Elements)
96                    iced::Color::from_rgba(1.0, 1.0, 1.0, 0.4)
97                };
98                let checkmark = if login_info.use_secure_service {
99                    "[X]"
100                } else {
101                    "[ ]"
102                };
103                let password_text =
104                    format!("{checkmark} {}", i18n.get_msg("main-remember-password"));
105                let checkbox = Button::new(
106                    &mut self.secure_service_button,
107                    Text::new(password_text)
108                        .size(input_text_size)
109                        .color(text_color)
110                        .width(Length::Fill)
111                        .horizontal_alignment(iced::HorizontalAlignment::Center),
112                );
113                let checkbox = if login_info.secure_service_status == CredentialStatus::Ready {
114                    checkbox.on_press(Message::UseSecureService(!login_info.use_secure_service))
115                } else {
116                    checkbox
117                };
118
119                inputs.push(checkbox.into());
120            };
121        }
122
123        let inputs = Column::with_children(inputs)
124            .spacing(5)
125            .align_items(Align::Center)
126            .width(Length::Fill);
127
128        let submit = Button::new(
129            &mut self.submit_button,
130            Text::new(i18n.get_msg("common-okay"))
131                .size(input_text_size)
132                .width(Length::Fill)
133                .height(Length::Fill)
134                .horizontal_alignment(iced::HorizontalAlignment::Center)
135                .vertical_alignment(iced::VerticalAlignment::Center),
136        )
137        .width(Length::Units(INPUT_WIDTH))
138        .height(Length::Units(35))
139        .style(button_style)
140        .on_press(Message::CredentialsSubmit);
141
142        let submit = Container::new(submit).width(Length::Fill).center_x();
143
144        let mut children = vec![title_text.into(), msg_text.into()];
145        if let Some(error) = self.error.as_deref() {
146            children.push(
147                Text::new(error)
148                    .color(iced::Color::from_rgb(1.0, 0.7, 0.3))
149                    .size(fonts.cyri.scale(15))
150                    .into(),
151            );
152        }
153        children.extend([
154            Space::new(Length::Shrink, Length::Units(16)).into(),
155            inputs.into(),
156            submit.into(),
157        ]);
158
159        let content = Column::with_children(children)
160            .spacing(4)
161            .max_width(320)
162            .width(Length::Fill)
163            .height(Length::Shrink);
164
165        let prompt_window = Container::new(content)
166            .style(
167                style::container::Style::color_with_double_cornerless_border(
168                    (22, 18, 16, 255).into(),
169                    (11, 11, 11, 255).into(),
170                    (54, 46, 38, 255).into(),
171                ),
172            )
173            .padding(20);
174
175        Container::new(prompt_window)
176            .width(Length::Fill)
177            .height(Length::Fill)
178            .center_x()
179            .center_y()
180            .into()
181    }
182
183    pub(super) fn focus_username(&mut self) {
184        self.password = text_input::State::new();
185        self.username = text_input::State::focused();
186        self.username.move_cursor_to_end();
187    }
188
189    pub(super) fn focus_password(&mut self) {
190        self.username = text_input::State::new();
191        self.password = text_input::State::focused();
192        self.password.move_cursor_to_end();
193    }
194
195    pub(super) fn tab(&mut self, password_required: bool) {
196        if self.username.is_focused() && password_required {
197            self.focus_password();
198        } else {
199            self.focus_username();
200        }
201    }
202}