Move the login logic to a separate component

This commit is contained in:
Bnyro 2023-07-01 11:55:13 +02:00
parent 0755f2a0de
commit 206bb2ab83
3 changed files with 145 additions and 84 deletions

View File

@ -0,0 +1,124 @@
use gtk::prelude::*;
use relm4::prelude::*;
use crate::{
api,
settings::{self, get_current_account},
};
pub struct LoginPage {}
#[derive(Debug)]
pub enum LoginPageInput {
Login(String, String, String),
Cancel,
}
#[relm4::component(pub)]
impl SimpleComponent for LoginPage {
type Init = ();
type Input = LoginPageInput;
type Output = crate::AppMsg;
view! {
gtk::Box {
set_hexpand: true,
set_orientation: gtk::Orientation::Vertical,
set_spacing: 12,
set_margin_all: 20,
set_valign: gtk::Align::Center,
set_hexpand: true,
gtk::Label {
set_text: "Login",
add_css_class: "font-bold",
},
#[name(username)]
gtk::Entry {
set_placeholder_text: Some("Username or E-Mail"),
},
#[name(password)]
gtk::PasswordEntry {
set_placeholder_text: Some("Password"),
set_show_peek_icon: true,
},
#[name(totp_token)]
gtk::Entry {
set_placeholder_text: Some("Totp token (Optional)"),
},
gtk::Box {
set_orientation: gtk::Orientation::Horizontal,
set_halign: gtk::Align::End,
gtk::Button {
set_label: "Cancel",
connect_clicked => LoginPageInput::Cancel,
set_margin_end: 10,
},
gtk::Button {
set_label: "Login",
connect_clicked[sender, username, password, totp_token] => move |_| {
let username_text = username.text().as_str().to_string();
username.set_text("");
let password_text = password.text().as_str().to_string();
password.set_text("");
let totp_token_text = totp_token.text().as_str().to_string();
totp_token.set_text("");
sender.input(LoginPageInput::Login(username_text, password_text, totp_token_text));
},
},
}
}
}
fn init(
_init: Self::Init,
root: &Self::Root,
sender: ComponentSender<Self>,
) -> ComponentParts<Self> {
let model = Self {};
let widgets = view_output!();
ComponentParts { model, widgets }
}
fn update(&mut self, message: Self::Input, sender: ComponentSender<Self>) {
match message {
LoginPageInput::Login(username, password, totp_token) => {
if get_current_account().instance_url.is_empty() {
return;
}
let token = if totp_token.is_empty() {
None
} else {
Some(totp_token)
};
let _ = sender.output(crate::AppMsg::UpdateState(crate::AppState::Loading));
std::thread::spawn(move || {
let message = match api::auth::login(username, password, token) {
Ok(login) => {
if let Some(token) = login.jwt {
let mut account = settings::get_current_account();
account.jwt = Some(token);
settings::update_current_account(account.clone());
if let Ok(site) = api::site::fetch_site() {
let user = site.my_user.unwrap().local_user_view.person;
account.name = user.name;
account.id = user.id.0;
settings::update_current_account(account);
}
crate::AppMsg::LoggedIn
} else {
crate::AppMsg::ShowMessage("Wrong credentials!".to_string())
}
}
Err(err) => crate::AppMsg::ShowMessage(err.to_string()),
};
let _ = sender.output(message);
});
}
LoginPageInput::Cancel => {
let _ = sender.output(crate::AppMsg::StartFetchPosts(None, true));
}
}
}
}

View File

@ -5,6 +5,7 @@ pub mod community_row;
pub mod inbox_page; pub mod inbox_page;
pub mod instance_row; pub mod instance_row;
pub mod instances_page; pub mod instances_page;
pub mod login_page;
pub mod mention_row; pub mod mention_row;
pub mod post_page; pub mod post_page;
pub mod post_row; pub mod post_row;

View File

@ -33,10 +33,11 @@ use relm4::{
prelude::*, prelude::*,
set_global_css, set_global_css,
}; };
use settings::get_current_account;
use crate::components::login_page::LoginPage;
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
enum AppState { pub enum AppState {
Loading, Loading,
Posts, Posts,
ChooseInstance, ChooseInstance,
@ -60,6 +61,7 @@ struct App {
communities_page: Controller<CommunitiesPage>, communities_page: Controller<CommunitiesPage>,
post_page: Controller<PostPage>, post_page: Controller<PostPage>,
inbox_page: Controller<InboxPage>, inbox_page: Controller<InboxPage>,
login_page: Controller<LoginPage>,
logged_in: bool, logged_in: bool,
current_posts_type: Option<ListingType>, current_posts_type: Option<ListingType>,
current_posts_page: i64, current_posts_page: i64,
@ -70,7 +72,6 @@ struct App {
pub enum AppMsg { pub enum AppMsg {
ChooseInstance, ChooseInstance,
ShowLogin, ShowLogin,
Login(String, String, String),
LoggedIn, LoggedIn,
Logout, Logout,
ShowMessage(String), ShowMessage(String),
@ -86,7 +87,7 @@ pub enum AppMsg {
OpenInbox, OpenInbox,
OpenCommunities, OpenCommunities,
PopBackStack, PopBackStack,
ShowAbout, UpdateState(AppState),
} }
#[relm4::component] #[relm4::component]
@ -174,52 +175,8 @@ impl SimpleComponent for App {
instances_page -> gtk::Box {} instances_page -> gtk::Box {}
}, },
AppState::Login => gtk::Box { AppState::Login => gtk::Box {
set_hexpand: true, #[local_ref]
set_orientation: gtk::Orientation::Vertical, login_page -> gtk::Box {}
set_spacing: 12,
set_margin_all: 20,
set_valign: gtk::Align::Center,
set_hexpand: true,
gtk::Label {
set_text: "Login",
add_css_class: "font-bold",
},
#[name(username)]
gtk::Entry {
set_placeholder_text: Some("Username or E-Mail"),
},
#[name(password)]
gtk::PasswordEntry {
set_placeholder_text: Some("Password"),
set_show_peek_icon: true,
},
#[name(totp_token)]
gtk::Entry {
set_placeholder_text: Some("Totp token (Optional)"),
},
gtk::Box {
set_orientation: gtk::Orientation::Horizontal,
set_halign: gtk::Align::End,
gtk::Button {
set_label: "Cancel",
connect_clicked => AppMsg::StartFetchPosts(None, true),
set_margin_end: 10,
},
gtk::Button {
set_label: "Login",
connect_clicked[sender, username, password, totp_token] => move |_| {
let username_text = username.text().as_str().to_string();
username.set_text("");
let password_text = password.text().as_str().to_string();
password.set_text("");
let totp_token_text = totp_token.text().as_str().to_string();
totp_token.set_text("");
sender.input(AppMsg::Login(username_text, password_text, totp_token_text));
},
},
}
}, },
AppState::Communities => gtk::Box { AppState::Communities => gtk::Box {
#[local_ref] #[local_ref]
@ -316,6 +273,9 @@ impl SimpleComponent for App {
let about_dialog = AboutDialog::builder() let about_dialog = AboutDialog::builder()
.launch(root.toplevel_window().unwrap()) .launch(root.toplevel_window().unwrap())
.detach(); .detach();
let login_page = LoginPage::builder()
.launch(())
.forward(sender.input_sender(), |msg| msg);
let model = App { let model = App {
state, state,
@ -328,6 +288,7 @@ impl SimpleComponent for App {
post_page, post_page,
inbox_page, inbox_page,
communities_page, communities_page,
login_page,
message: None, message: None,
current_posts_type: None, current_posts_type: None,
current_posts_page: 1, current_posts_page: 1,
@ -347,6 +308,7 @@ impl SimpleComponent for App {
let post_page = model.post_page.widget(); let post_page = model.post_page.widget();
let inbox_page = model.inbox_page.widget(); let inbox_page = model.inbox_page.widget();
let communities_page = model.communities_page.widget(); let communities_page = model.communities_page.widget();
let login_page = model.login_page.widget();
let widgets = view_output!(); let widgets = view_output!();
@ -441,6 +403,10 @@ impl SimpleComponent for App {
} else { } else {
self.current_posts_page + 1 self.current_posts_page + 1
}; };
// show the loading indicator if it's the first page
if page == 1 {
self.state = AppState::Loading;
}
self.current_posts_page = page; self.current_posts_page = page;
std::thread::spawn(move || { std::thread::spawn(move || {
let message = match api::posts::list_posts(page, None, type_) { let message = match api::posts::list_posts(page, None, type_) {
@ -521,39 +487,6 @@ impl SimpleComponent for App {
AppMsg::ShowLogin => { AppMsg::ShowLogin => {
self.state = AppState::Login; self.state = AppState::Login;
} }
AppMsg::Login(username, password, totp_token) => {
if get_current_account().instance_url.is_empty() {
return;
}
let token = if totp_token.is_empty() {
None
} else {
Some(totp_token)
};
self.state = AppState::Loading;
std::thread::spawn(move || {
let message = match api::auth::login(username, password, token) {
Ok(login) => {
if let Some(token) = login.jwt {
let mut account = settings::get_current_account();
account.jwt = Some(token);
settings::update_current_account(account.clone());
if let Ok(site) = api::site::fetch_site() {
let user = site.my_user.unwrap().local_user_view.person;
account.name = user.name;
account.id = user.id.0;
settings::update_current_account(account);
}
AppMsg::LoggedIn
} else {
AppMsg::ShowMessage("Wrong credentials!".to_string())
}
}
Err(err) => AppMsg::ShowMessage(err.to_string()),
};
sender.input(message);
});
}
AppMsg::Logout => { AppMsg::Logout => {
let mut account = settings::get_current_account(); let mut account = settings::get_current_account();
account.jwt = None; account.jwt = None;
@ -570,6 +503,7 @@ impl SimpleComponent for App {
} }
AppMsg::LoggedIn => { AppMsg::LoggedIn => {
self.logged_in = true; self.logged_in = true;
self.back_queue.clear();
sender.input(AppMsg::StartFetchPosts(None, true)); sender.input(AppMsg::StartFetchPosts(None, true));
} }
AppMsg::PopBackStack => { AppMsg::PopBackStack => {
@ -581,7 +515,9 @@ impl SimpleComponent for App {
self.back_queue.remove(self.back_queue.len() - 1); self.back_queue.remove(self.back_queue.len() - 1);
} }
} }
AppMsg::ShowAbout => {} AppMsg::UpdateState(state) => {
self.state = state;
}
} }
} }
} }