aboutsummaryrefslogtreecommitdiff
path: root/src/ui/login.rs
blob: 8a854185e98684ec7c348efd1907153b8a10ef53 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
use eframe::egui;
use std::sync::mpsc::Receiver;

use crate::api::ApiClient;
use crate::models::LoginResponse;
use crate::session::SessionManager;

pub struct LoginScreen {
    server_url: String,
    username: String,
    password: String,

    remember_server: bool,
    remember_username: bool,

    error_message: Option<String>,
    is_logging_in: bool,

    // For async operations
    login_receiver: Option<Receiver<Result<(String, LoginResponse), String>>>,
}

impl LoginScreen {
    pub fn new(session_manager: &SessionManager) -> Self {
        let server_url = session_manager
            .get_saved_server_url()
            .unwrap_or_else(|| "http://localhost:5777".to_string()); // Reminder to myself : Fucking remove this before release

        let username = session_manager.get_saved_username().unwrap_or_default();

        let remember_username = !username.is_empty();

        Self {
            server_url,
            username,
            password: String::new(),
            remember_server: true,
            remember_username,
            error_message: None,
            is_logging_in: false,
            login_receiver: None,
        }
    }

    pub fn show(&mut self, ctx: &egui::Context, on_success: &mut Option<(String, LoginResponse)>) {
        // Check if we have a login result from async operation
        if let Some(receiver) = &self.login_receiver {
            match receiver.try_recv() {
                Ok(result) => {
                    log::info!("UI thread: Received login result!");
                    self.is_logging_in = false;
                    self.login_receiver = None;

                    match result {
                        Ok((server_url, login_response)) => {
                            log::info!("UI thread: Login successful, setting on_success");
                            *on_success = Some((server_url, login_response));
                        }
                        Err(err) => {
                            log::error!("UI thread: Login failed: {} tried suicide yet maybe that actually works?", err);
                            self.error_message = Some(err);
                        }
                    }
                }
                Err(std::sync::mpsc::TryRecvError::Empty) => {
                    // Still waiting, request repaint to check again
                    ctx.request_repaint();
                }
                Err(std::sync::mpsc::TryRecvError::Disconnected) => {
                    log::error!("UI thread: Channel disconnected!");
                    self.is_logging_in = false;
                    self.login_receiver = None;
                    self.error_message = Some("Connection error".to_string());
                }
            }
        }

        egui::CentralPanel::default().show(ctx, |ui| {
            // Center the login form both horizontally and vertically bruh
            let available_size = ui.available_size();
            let panel_width = available_size.x.min(500.0);

            ui.allocate_ui_with_layout(
                available_size,
                egui::Layout::top_down(egui::Align::Center),
                |ui| {
                    // Add vertical spacing to center
                    ui.add_space(available_size.y * 0.15);

                    // Logo/Title
                    ui.heading(egui::RichText::new("BeepZone Login").size(48.0).strong());
                    ui.label(
                        egui::RichText::new(format!(
                            "BeepZone Desktop Client eGUI EMO Edition - v{}",
                            env!("CARGO_PKG_VERSION")
                        ))
                        .size(18.0),
                    );

                    ui.add_space(30.0);

                    // Login form
                    egui::Frame::new()
                        .fill(ctx.style().visuals.window_fill)
                        .stroke(ctx.style().visuals.window_stroke)
                        .corner_radius(12.0)
                        .inner_margin(32.0)
                        .show(ui, |ui| {
                            ui.set_width(panel_width * 0.8);

                            // Server URL
                            ui.horizontal(|ui: &mut egui::Ui| {
                                ui.label("BeepZone Sekel API URL:");
                                ui.add_space(10.0);
                            });
                            ui.text_edit_singleline(&mut self.server_url);
                            ui.add_space(8.0);

                            // Username field
                            ui.label("Username:");
                            ui.text_edit_singleline(&mut self.username);
                            ui.add_space(8.0);

                            // Password field
                            ui.label("Password:");
                            let password_response = ui
                                .add(egui::TextEdit::singleline(&mut self.password).password(true));

                            // Enter key to submit
                            if password_response.lost_focus()
                                && ui.input(|i| i.key_pressed(egui::Key::Enter))
                            {
                                self.do_login();
                            }

                            ui.add_space(12.0);

                            // Remember options
                            ui.checkbox(&mut self.remember_server, "Remember Sekel URL");
                            ui.checkbox(&mut self.remember_username, "Remember Username");

                            ui.add_space(16.0);

                            // Error message
                            if let Some(error) = &self.error_message {
                                ui.label(format!("Error: {}", error));
                                ui.add_space(12.0);
                            }

                            // Login button
                            ui.add_enabled_ui(!self.is_logging_in, |ui| {
                                let button_text = if self.is_logging_in {
                                    "Logging in..."
                                } else {
                                    "Login"
                                };

                                if ui
                                    .add_sized(
                                        [ui.available_width(), 40.0],
                                        egui::Button::new(button_text),
                                    )
                                    .clicked()
                                {
                                    self.do_login();
                                }
                            });

                            if self.is_logging_in {
                                ui.add_space(8.0);
                                ui.horizontal(|ui| {
                                    ui.spinner();
                                    ui.label("Connecting to server...");
                                });
                            }
                        });

                    ui.add_space(20.0);
                    ui.label(
                        egui::RichText::new("- The only based Sigma Inventory System -")
                            .size(12.0)
                            .color(egui::Color32::GRAY),
                    );

                    // Debug info
                    if self.is_logging_in {
                        ui.add_space(10.0);
                        ui.label(
                            egui::RichText::new(format!("Connecting to: {}", self.server_url))
                                .size(10.0)
                                .color(egui::Color32::GRAY),
                        );
                    }
                },
            );
        });
    }

    fn do_login(&mut self) {
        // Validate inputs
        if self.server_url.trim().is_empty() {
            self.error_message =
                Some("Server URL is required!? Perhaps enter it you know?".to_string());
            return;
        }

        if self.username.trim().is_empty() || self.password.trim().is_empty() {
            self.error_message = Some(
                "Username and password are required!? Please enter both you know?".to_string(),
            );
            return;
        }

        self.error_message = None;
        self.is_logging_in = true;

        // Clone data for background thread
        let server_url = self.server_url.clone();
        let username = self.username.clone();
        let password = self.password.clone();

        log::info!("Trying to sign in as : {}", username);

        // Create channel for communication
        let (tx, rx) = std::sync::mpsc::channel();
        self.login_receiver = Some(rx);

        // Spawn background thread to perform login
        std::thread::spawn(move || {
            log::info!("Background thread: Connecting to {}", server_url);
            let result = match ApiClient::new(server_url.clone()) {
                Ok(client) => {
                    log::info!("Background thread: API client created, attempting login...");
                    match client.login_password(&username, &password) {
                        Ok(response) => {
                            log::info!(
                                "Background thread: Got response, success={}",
                                response.success
                            );
                            if response.success {
                                log::info!(
                                    "Login successfulf for user: {}",
                                    response.user.username
                                );
                                Ok((server_url, response))
                            } else {
                                let error = "Login failed gay credentials".to_string();
                                log::error!("{}", error);
                                Err(error)
                            }
                        }
                        Err(e) => {
                            let error = format!("Notwork error: {}", e);
                            log::error!("{}", error);
                            Err(error)
                        }
                    }
                }
                Err(e) => {
                    let error = format!("Failed at connecting to server somehow: {}", e);
                    log::error!("{}", error);
                    Err(error)
                }
            };

            log::info!("Background thread: Sending result back to UI");
            if let Err(e) = tx.send(result) {
                log::error!("Background thread: Failed to send result: {:?}", e);
            }
        });
    }
}