retrix/src/ui/login.rs

171 lines
4.3 KiB
Rust

//! The login prompt
use iced::{
widget::{button::State as ButtonState, text_input::State as InputState},
Button, Column, Command, Container, Element, Length, Space, Text, TextInput, Toggler,
};
use self::Message::*;
use crate::{matrix, style};
/// Data for the login prompt
#[derive(Debug, Default)]
pub struct Login {
/// The username
user: String,
/// The password
password: String,
/// Whether the password should be visible.
show_password: bool,
/// The homeserver URL.
homeserver: String,
/// Whether we're waiting for a response to a login attempt
waiting: bool,
/// The text of an error message
error: Option<String>,
/// Widget state
state: State,
}
/// Login prompt widget state
#[derive(Debug, Default)]
pub struct State {
/// State for the login input
user: InputState,
/// State from the password input
password: InputState,
/// State for the homeserver input
homeserver: InputState,
/// State for the login button
login: ButtonState,
}
/// Notification to change the state for the login view.
#[derive(Debug, Clone)]
pub enum Message {
/// The login input changed.
InputUser(String),
/// The password input changed.
InputPassword(String),
/// The homerserver input changed.
InputHomeserver(String),
/// The "show password" toggle has been switched.
TogglePassword(bool),
/// Triggers login.
Login,
/// A login attempt failed.
LoginFailed(String),
/// Login completed.
LoggedIn(matrix_sdk::Client),
/// Hide the error message.
ResetError,
}
impl Login {
/// Update state
pub fn update(&mut self, message: Message) -> Command<super::Message> {
match message {
InputUser(input) => self.user = input,
InputPassword(input) => self.password = input,
InputHomeserver(input) => self.homeserver = input,
TogglePassword(toggle) => self.show_password = toggle,
Login => {
self.waiting = true;
let homeserver = self.homeserver.clone();
let user = self.user.clone();
let password = self.password.clone();
let command = async move {
let client = match matrix::login(&homeserver, &user, &password).await {
Ok(client) => client,
Err(e) => return LoginFailed(e.to_string()),
};
LoggedIn(client)
};
return Command::perform(command, super::Message::from);
}
LoginFailed(error) => {
self.waiting = false;
self.error = Some(error);
}
LoggedIn(_) => (),
ResetError => self.error = None,
};
Command::none()
}
/// Generate widgets for this view
pub fn view(&mut self) -> Element<super::Message> {
let error_message: iced::Element<_> = match self.error {
Some(ref error) => Container::new(Text::new(error.clone()))
.center_x()
.width(Length::Fill)
.padding(5)
.style(style::container::Error)
.into(),
None => Space::new(0.into(), 0.into()).into(),
};
let user_input =
TextInput::new(&mut self.state.user, "alice", &self.user, |i| InputUser(i).into())
.padding(5);
let mut password_input =
TextInput::new(&mut self.state.password, "verysecret", &self.password, |i| {
InputPassword(i).into()
})
.padding(5);
if !self.show_password {
password_input = password_input.password();
}
let password_toggle =
Toggler::new(self.show_password, String::from("show password"), |b| {
TogglePassword(b).into()
})
.text_size(15);
let homeserver_input = TextInput::new(
&mut self.state.homeserver,
"https://matrix.org",
&self.homeserver,
|i| InputHomeserver(i).into(),
)
.padding(5);
let login_button = Button::new(
&mut self.state.login,
Text::new("Log in")
.horizontal_alignment(iced::alignment::Horizontal::Center)
.width(Length::Fill),
)
.on_press(Message::Login.into())
.width(Length::Fill);
let mut column = Column::new()
.width(500.into())
.push(error_message)
.push(Text::new("User name"))
.push(user_input)
.push(Space::with_height(10.into()))
.push(Text::new("Password"))
.push(password_input)
.push(password_toggle)
.push(Space::with_height(5.into()))
.push(Text::new("Homeserver address"))
.push(homeserver_input)
.push(login_button);
if self.waiting {
column = column.push(Text::new("Logging in"));
}
Container::new(column).center_x().center_y().width(Length::Fill).height(Length::Fill).into()
}
}
impl From<Message> for super::Message {
fn from(message: Message) -> Self {
super::Message::Login(message)
}
}