aboutsummaryrefslogtreecommitdiffstats
path: root/src/main.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs293
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()
}