diff options
Diffstat (limited to 'src/main.rs')
-rw-r--r-- | src/main.rs | 293 |
1 files changed, 69 insertions, 224 deletions
diff --git a/src/main.rs b/src/main.rs index e3d3332..d583293 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,7 +7,7 @@ use iced::futures::{SinkExt, Stream, StreamExt}; use iced::widget::button::Status; use iced::widget::text::{Fragment, IntoFragment}; use iced::widget::{ - button, center, column, container, mouse_area, opaque, row, scrollable, stack, text, + button, center, checkbox, column, container, mouse_area, opaque, row, scrollable, stack, text, text_input, Column, Text, Toggler, }; use iced::Length::Fill; @@ -15,15 +15,20 @@ use iced::{stream, Color, Element, Subscription, Task, Theme}; use indexmap::{indexmap, IndexMap}; use jid::JID; use keyring::Entry; +use login_modal::LoginModal; use luz::chat::{Chat, Message as ChatMessage}; use luz::presence::{Offline, Presence}; use luz::CommandMessage; use luz::{roster::Contact, user::User, LuzHandle, UpdateMessage}; +use serde::{Deserialize, Serialize}; use tokio::sync::{mpsc, oneshot}; use tokio_stream::wrappers::ReceiverStream; -use tracing::info; +use tracing::{error, info}; use uuid::Uuid; +mod login_modal; + +#[derive(Serialize, Deserialize)] pub struct Config { auto_connect: bool, } @@ -36,6 +41,7 @@ impl Default for Config { pub struct Macaw { client: Account, + config: Config, roster: HashMap<JID, Contact>, users: HashMap<JID, User>, presences: HashMap<JID, Presence>, @@ -58,20 +64,17 @@ pub struct Creds { } impl Macaw { - pub fn new(client: Option<Client>) -> Self { + pub fn new(client: Option<Client>, config: Config) -> Self { let account; if let Some(client) = client { account = Account::LoggedIn(client); } else { - account = Account::LoggedOut { - jid: "".to_string(), - password: "".to_string(), - error: None, - }; + account = Account::LoggedOut(LoginModal::default()); } Self { client: account, + config, roster: HashMap::new(), users: HashMap::new(), presences: HashMap::new(), @@ -85,17 +88,7 @@ impl Macaw { pub enum Account { LoggedIn(Client), - LoggedOut { - jid: String, - password: String, - error: Option<Error>, - }, -} - -#[derive(Debug, Clone)] -pub enum Error { - InvalidJID(String), - DatabaseConnection, + LoggedOut(LoginModal), } #[derive(Clone, Debug)] @@ -122,6 +115,7 @@ impl Deref for Client { fn main() -> iced::Result { tracing_subscriber::fmt::init(); + let cfg = confy::load("macaw", None).unwrap(); let client: Option<(JID, LuzHandle, mpsc::Receiver<UpdateMessage>)> = None; if let Some((jid, luz_handle, update_recv)) = client { @@ -129,25 +123,28 @@ fn main() -> iced::Result { let stream = stream.map(|message| Message::Luz(message)); iced::application("Macaw", Macaw::update, Macaw::view).run_with(|| { ( - Macaw::new(Some(Client { - client: luz_handle, - // TODO: - jid, - connection_status: Presence::Offline(Offline::default()), - })), + Macaw::new( + Some(Client { + client: luz_handle, + // TODO: + jid, + connection_status: Presence::Offline(Offline::default()), + }), + cfg, + ), // TODO: autoconnect config Task::stream(stream), ) }) } else { iced::application("Macaw", Macaw::update, Macaw::view) - .run_with(|| (Macaw::new(None), Task::none())) + .run_with(|| (Macaw::new(None, cfg), Task::none())) } } #[derive(Debug, Clone)] -enum Message { - LoginModal(LoginModalMessage), +pub enum Message { + LoginModal(login_modal::Message), ClientCreated(Client), Luz(UpdateMessage), Roster(HashMap<JID, Contact>), @@ -161,14 +158,6 @@ enum Message { SendMessage(JID, String), } -#[derive(Debug, Clone)] -enum LoginModalMessage { - JID(String), - Password(String), - Submit, - Error(Error), -} - impl Macaw { fn update(&mut self, message: Message) -> Task<Message> { match message { @@ -187,11 +176,7 @@ impl Macaw { self.roster = roster; Task::none() } - Account::LoggedOut { - jid, - password, - error, - } => Task::none(), + Account::LoggedOut(login_modal) => Task::none(), }, UpdateMessage::Offline(offline) => { // TODO: update all contacts' presences to unknown (offline) @@ -200,11 +185,7 @@ impl Macaw { client.connection_status = Presence::Offline(offline); Task::none() } - Account::LoggedOut { - jid, - password, - error, - } => Task::none(), + Account::LoggedOut(login_modal) => Task::none(), } } UpdateMessage::FullRoster(vec) => { @@ -280,11 +261,7 @@ impl Macaw { }) .discard() } - Account::LoggedOut { - jid, - password, - error, - } => Task::none(), + Account::LoggedOut(login_modal) => Task::none(), }, Message::Disconnect => match &self.client { Account::LoggedIn(client) => { @@ -296,11 +273,7 @@ impl Macaw { }) .discard() } - Account::LoggedOut { - jid, - password, - error, - } => Task::none(), + Account::LoggedOut(login_modal) => Task::none(), }, Message::OpenChat(jid) => { self.open_chat = Some(OpenChat { @@ -309,105 +282,25 @@ impl Macaw { }); Task::none() } - Message::LoginModal(login_modal_message) => match login_modal_message { - LoginModalMessage::JID(j) => match &mut self.client { - Account::LoggedIn(_client) => Task::none(), - Account::LoggedOut { - jid, - password, - error, - } => { - *jid = j; - Task::none() + Message::LoginModal(login_modal_message) => match &mut self.client { + Account::LoggedIn(_client) => Task::none(), + Account::LoggedOut(login_modal) => { + let action = login_modal.update(login_modal_message); + match action { + login_modal::Action::None => Task::none(), + login_modal::Action::ClientCreated(task) => task, } - }, - LoginModalMessage::Password(p) => match &mut self.client { - Account::LoggedIn(_client) => Task::none(), - Account::LoggedOut { - jid, - password, - error, - } => { - *password = p; - Task::none() - } - }, - LoginModalMessage::Submit => match &self.client { - Account::LoggedIn(_client) => Task::none(), - Account::LoggedOut { - jid: jid_str, - password, - error, - } => { - info!("submitting login"); - let jid_str = jid_str.clone(); - let password = password.clone(); - Task::future(async move { - let jid: Result<JID, _> = jid_str.parse(); - match jid { - Ok(j) => { - let result = - LuzHandle::new(j.clone(), password.to_string(), "macaw.db") - .await; - match result { - Ok((luz_handle, receiver)) => { - let stream = ReceiverStream::new(receiver); - let stream = - stream.map(|message| Message::Luz(message)); - vec![ - Task::done(Message::ClientCreated(Client { - client: luz_handle, - jid: j, - connection_status: Presence::Offline( - Offline::default(), - ), - })), - Task::stream(stream), - ] - } - Err(e) => { - tracing::error!("error (database probably)"); - return vec![Task::done(Message::LoginModal( - LoginModalMessage::Error(Error::DatabaseConnection), - ))]; - } - } - } - Err(_) => { - tracing::error!("parsing jid"); - return vec![Task::done(Message::LoginModal( - LoginModalMessage::Error(Error::InvalidJID( - jid_str.to_string(), - )), - ))]; - } - } - }) - .then(|tasks| Task::batch(tasks)) - } - }, - LoginModalMessage::Error(e) => match &mut self.client { - Account::LoggedIn(_client) => Task::none(), - Account::LoggedOut { - jid, - password, - error, - } => { - tracing::error!("luz::new: {:?}", e); - *error = Some(e); - Task::none() - } - }, + } }, Message::GotChats(chats) => { let mut tasks = Vec::new(); let client = match &self.client { Account::LoggedIn(client) => client, - Account::LoggedOut { - jid, - password, - error, - } => panic!("no client"), + Account::LoggedOut(_) => { + // TODO: error into event tracing subscriber + error!("no client, cannot retreive chat history for chats"); + return Task::none(); + } }; for chat in chats { let client = client.clone(); @@ -455,11 +348,10 @@ impl Macaw { Message::SendMessage(jid, body) => { let client = match &self.client { Account::LoggedIn(client) => client.clone(), - Account::LoggedOut { - jid, - password, - error, - } => todo!(), + Account::LoggedOut(_) => { + error!("cannot send message when no client set up"); + return Task::none(); + } }; Task::future( async move { client.send_message(jid, luz::chat::Body { body }).await }, @@ -498,19 +390,11 @@ impl Macaw { Presence::Online(_online) => "online", Presence::Offline(_offline) => "disconnected", }, - Account::LoggedOut { - jid: _, - password: _, - error, - } => "disconnected", + Account::LoggedOut(_) => "disconnected", }; let client_jid: Cow<'_, str> = match &self.client { Account::LoggedIn(client) => (&client.jid).into(), - Account::LoggedOut { - jid: _, - password: _, - error, - } => Cow::from("no account"), + Account::LoggedOut(_) => Cow::from("no account"), // map(|client| (&client.jid).into()); }; let account_view = row![ @@ -568,7 +452,8 @@ impl Macaw { .into(); if let Some(new_chat) = &self.new_chat { - ui = modal(ui, text("new chat")); + // TODO: close new chat window + ui = modal(ui, text("new chat"), None); } // temporarily center to fill space // let ui = center(ui).into(); @@ -576,47 +461,9 @@ impl Macaw { match &self.client { Account::LoggedIn(_client) => ui.into(), - Account::LoggedOut { - jid, - password, - error, - } => { - let signup = container( - column![ - text("Log In").size(24), - column![ - column![ - text("JID").size(12), - text_input("berry@macaw.chat", &jid) - .on_input(|j| Message::LoginModal(LoginModalMessage::JID(j))) - .on_submit(Message::LoginModal(LoginModalMessage::Submit)) - .padding(5), - ] - .spacing(5), - column![ - text("Password").size(12), - text_input("", &password) - .on_input(|p| Message::LoginModal(LoginModalMessage::Password( - p - ))) - .on_submit(Message::LoginModal(LoginModalMessage::Submit)) - .secure(true) - .padding(5), - ] - .spacing(5), - button(text("Submit")) - .on_press(Message::LoginModal(LoginModalMessage::Submit)), - ] - .spacing(10) - ] - .spacing(20), - ) - .width(300) - .padding(10) - .style(container::rounded_box); - - // signup.into() - modal(ui, signup) + Account::LoggedOut(login_modal) => { + let signup = login_modal.view().map(Message::LoginModal); + modal(ui, signup, None) } } } @@ -629,27 +476,25 @@ impl Macaw { fn modal<'a, Message>( base: impl Into<Element<'a, Message>>, content: impl Into<Element<'a, Message>>, - // on_blur: Message, + on_blur: Option<Message>, ) -> Element<'a, Message> where Message: Clone + 'a, { - stack![ - base.into(), - opaque( - mouse_area(center(opaque(content)).style(|_theme| { - container::Style { - background: Some( - Color { - a: 0.8, - ..Color::BLACK - } - .into(), - ), - ..container::Style::default() + let mut mouse_area = mouse_area(center(opaque(content)).style(|_theme| { + container::Style { + background: Some( + Color { + a: 0.8, + ..Color::BLACK } - })) // .on_press(on_blur) - ) - ] - .into() + .into(), + ), + ..container::Style::default() + } + })); // .on_press(on_blur) + if let Some(on_blur) = on_blur { + mouse_area = mouse_area.on_press(on_blur) + } + stack![base.into(), opaque(mouse_area)].into() } |