implement log-in modal
This commit is contained in:
parent
0ae95d1e7d
commit
5a2fae397c
|
@ -1,2 +1,3 @@
|
||||||
/target
|
/target
|
||||||
|
.vscode
|
||||||
macaw.db
|
macaw.db
|
||||||
|
|
|
@ -33,6 +33,17 @@ version = "2.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
|
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aes"
|
||||||
|
version = "0.8.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"cipher",
|
||||||
|
"cpufeatures",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ahash"
|
name = "ahash"
|
||||||
version = "0.7.8"
|
version = "0.7.8"
|
||||||
|
@ -371,6 +382,15 @@ dependencies = [
|
||||||
"generic-array",
|
"generic-array",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "block-padding"
|
||||||
|
version = "0.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "block2"
|
name = "block2"
|
||||||
version = "0.5.1"
|
version = "0.5.1"
|
||||||
|
@ -463,6 +483,15 @@ dependencies = [
|
||||||
"wayland-client",
|
"wayland-client",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cbc"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6"
|
||||||
|
dependencies = [
|
||||||
|
"cipher",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.2.13"
|
version = "1.2.13"
|
||||||
|
@ -498,6 +527,16 @@ version = "0.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
|
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cipher"
|
||||||
|
version = "0.4.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
|
||||||
|
dependencies = [
|
||||||
|
"crypto-common",
|
||||||
|
"inout",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "circular"
|
name = "circular"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
|
@ -1980,6 +2019,16 @@ dependencies = [
|
||||||
"hashbrown 0.15.2",
|
"hashbrown 0.15.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "inout"
|
||||||
|
version = "0.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01"
|
||||||
|
dependencies = [
|
||||||
|
"block-padding",
|
||||||
|
"generic-array",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "instant"
|
name = "instant"
|
||||||
version = "0.1.13"
|
version = "0.1.13"
|
||||||
|
@ -2254,6 +2303,7 @@ dependencies = [
|
||||||
"iced",
|
"iced",
|
||||||
"jid",
|
"jid",
|
||||||
"luz",
|
"luz",
|
||||||
|
"secret-service",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-stream",
|
"tokio-stream",
|
||||||
"tracing",
|
"tracing",
|
||||||
|
@ -2475,6 +2525,30 @@ dependencies = [
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num"
|
||||||
|
version = "0.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23"
|
||||||
|
dependencies = [
|
||||||
|
"num-bigint",
|
||||||
|
"num-complex",
|
||||||
|
"num-integer",
|
||||||
|
"num-iter",
|
||||||
|
"num-rational",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-bigint"
|
||||||
|
version = "0.4.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
|
||||||
|
dependencies = [
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-bigint-dig"
|
name = "num-bigint-dig"
|
||||||
version = "0.8.4"
|
version = "0.8.4"
|
||||||
|
@ -2492,6 +2566,15 @@ dependencies = [
|
||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-complex"
|
||||||
|
version = "0.4.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-integer"
|
name = "num-integer"
|
||||||
version = "0.1.46"
|
version = "0.1.46"
|
||||||
|
@ -2512,6 +2595,17 @@ dependencies = [
|
||||||
"num-traits",
|
"num-traits",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-rational"
|
||||||
|
version = "0.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824"
|
||||||
|
dependencies = [
|
||||||
|
"num-bigint",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-traits"
|
name = "num-traits"
|
||||||
version = "0.2.19"
|
version = "0.2.19"
|
||||||
|
@ -3491,6 +3585,25 @@ dependencies = [
|
||||||
"tiny-skia",
|
"tiny-skia",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "secret-service"
|
||||||
|
version = "4.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e4d35ad99a181be0a60ffcbe85d680d98f87bdc4d7644ade319b87076b9dbfd4"
|
||||||
|
dependencies = [
|
||||||
|
"aes",
|
||||||
|
"cbc",
|
||||||
|
"futures-util",
|
||||||
|
"generic-array",
|
||||||
|
"hkdf",
|
||||||
|
"num",
|
||||||
|
"once_cell",
|
||||||
|
"rand",
|
||||||
|
"serde",
|
||||||
|
"sha2",
|
||||||
|
"zbus",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "security-framework"
|
name = "security-framework"
|
||||||
version = "2.11.1"
|
version = "2.11.1"
|
||||||
|
@ -4246,6 +4359,7 @@ dependencies = [
|
||||||
"signal-hook-registry",
|
"signal-hook-registry",
|
||||||
"socket2",
|
"socket2",
|
||||||
"tokio-macros",
|
"tokio-macros",
|
||||||
|
"tracing",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -5454,6 +5568,7 @@ dependencies = [
|
||||||
"serde_repr",
|
"serde_repr",
|
||||||
"sha1",
|
"sha1",
|
||||||
"static_assertions",
|
"static_assertions",
|
||||||
|
"tokio",
|
||||||
"tracing",
|
"tracing",
|
||||||
"uds_windows",
|
"uds_windows",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
|
|
|
@ -11,4 +11,4 @@ tokio = "1.43.0"
|
||||||
tokio-stream = "0.1.17"
|
tokio-stream = "0.1.17"
|
||||||
tracing-subscriber = "0.3.19"
|
tracing-subscriber = "0.3.19"
|
||||||
tracing = "0.1.41"
|
tracing = "0.1.41"
|
||||||
|
secret-service = { version = "4.0.0", features = ["rt-tokio-crypto-rust"] }
|
||||||
|
|
478
src/main.rs
478
src/main.rs
|
@ -1,38 +1,127 @@
|
||||||
|
use std::borrow::Cow;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
|
use std::fmt::Debug;
|
||||||
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
use iced::futures::{SinkExt, Stream, StreamExt};
|
use iced::futures::{SinkExt, Stream, StreamExt};
|
||||||
use iced::widget::{button, column, row, text, text_input};
|
use iced::widget::text::{Fragment, IntoFragment};
|
||||||
use iced::{stream, Element, Subscription, Task, Theme};
|
use iced::widget::{
|
||||||
|
button, center, column, container, mouse_area, opaque, row, stack, text, text_input, Text,
|
||||||
|
};
|
||||||
|
use iced::{stream, Color, Element, Subscription, Task, Theme};
|
||||||
use jid::JID;
|
use jid::JID;
|
||||||
use luz::chat::{Chat, Message as ChatMessage};
|
use luz::chat::{Chat, Message as ChatMessage};
|
||||||
use luz::presence::{Offline, Presence};
|
use luz::presence::{Offline, Presence};
|
||||||
use luz::CommandMessage;
|
use luz::CommandMessage;
|
||||||
use luz::{roster::Contact, user::User, LuzHandle, UpdateMessage};
|
use luz::{roster::Contact, user::User, LuzHandle, UpdateMessage};
|
||||||
use tokio::sync::oneshot;
|
use tokio::sync::{mpsc, oneshot};
|
||||||
use tokio_stream::wrappers::ReceiverStream;
|
use tokio_stream::wrappers::ReceiverStream;
|
||||||
|
use tracing::info;
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct Macaw {
|
pub struct Macaw {
|
||||||
client: Option<LuzHandle>,
|
client: Account,
|
||||||
roster: HashMap<JID, Contact>,
|
roster: HashMap<JID, Contact>,
|
||||||
users: HashMap<JID, User>,
|
users: HashMap<JID, User>,
|
||||||
presences: HashMap<JID, Presence>,
|
presences: HashMap<JID, Presence>,
|
||||||
chats: HashMap<JID, (Chat, Vec<ChatMessage>)>,
|
chats: HashMap<JID, (Chat, Vec<ChatMessage>)>,
|
||||||
subscription_requests: HashSet<JID>,
|
subscription_requests: HashSet<JID>,
|
||||||
connection_status: Option<Presence>,
|
}
|
||||||
|
|
||||||
|
pub struct Creds {
|
||||||
|
jid: String,
|
||||||
|
password: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Macaw {
|
||||||
|
pub fn new(client: Option<Client>) -> Self {
|
||||||
|
let account;
|
||||||
|
if let Some(client) = client {
|
||||||
|
account = Account::LoggedIn(client);
|
||||||
|
} else {
|
||||||
|
account = Account::LoggedOut {
|
||||||
|
jid: "".to_string(),
|
||||||
|
password: "".to_string(),
|
||||||
|
error: None,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Self {
|
||||||
|
client: account,
|
||||||
|
roster: HashMap::new(),
|
||||||
|
users: HashMap::new(),
|
||||||
|
presences: HashMap::new(),
|
||||||
|
chats: HashMap::new(),
|
||||||
|
subscription_requests: HashSet::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Account {
|
||||||
|
LoggedIn(Client),
|
||||||
|
LoggedOut {
|
||||||
|
jid: String,
|
||||||
|
password: String,
|
||||||
|
error: Option<Error>,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum Error {
|
||||||
|
InvalidJID(String),
|
||||||
|
DatabaseConnection,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct Client {
|
||||||
|
client: LuzHandle,
|
||||||
|
jid: JID,
|
||||||
|
connection_status: Presence,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DerefMut for Client {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.client
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for Client {
|
||||||
|
type Target = LuzHandle;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.client
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> iced::Result {
|
fn main() -> iced::Result {
|
||||||
tracing_subscriber::fmt::init();
|
tracing_subscriber::fmt::init();
|
||||||
|
|
||||||
iced::application("Macaw", Macaw::update, Macaw::view)
|
let client: Option<(JID, LuzHandle, mpsc::Receiver<UpdateMessage>)> = None;
|
||||||
.subscription(Macaw::subscription)
|
|
||||||
.run()
|
if let Some((jid, luz_handle, update_recv)) = client {
|
||||||
|
let stream = ReceiverStream::new(update_recv);
|
||||||
|
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()),
|
||||||
|
})),
|
||||||
|
// TODO: autoconnect config
|
||||||
|
Task::stream(stream),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
iced::application("Macaw", Macaw::update, Macaw::view)
|
||||||
|
.run_with(|| (Macaw::new(None), Task::none()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
enum Message {
|
enum Message {
|
||||||
ClientCreated(LuzHandle),
|
LoginModal(LoginModalMessage),
|
||||||
|
ClientCreated(Client),
|
||||||
Luz(UpdateMessage),
|
Luz(UpdateMessage),
|
||||||
Roster(HashMap<JID, Contact>),
|
Roster(HashMap<JID, Contact>),
|
||||||
Connect,
|
Connect,
|
||||||
|
@ -40,27 +129,15 @@ enum Message {
|
||||||
OpenChat(JID),
|
OpenChat(JID),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
enum LoginModalMessage {
|
||||||
|
JID(String),
|
||||||
|
Password(String),
|
||||||
|
Submit,
|
||||||
|
Error(Error),
|
||||||
|
}
|
||||||
|
|
||||||
impl Macaw {
|
impl Macaw {
|
||||||
fn stream() -> impl Stream<Item = Message> {
|
|
||||||
stream::channel(100, |mut output| async {
|
|
||||||
let (luz, recv) = LuzHandle::new(
|
|
||||||
"test@blos.sm".try_into().unwrap(),
|
|
||||||
"slayed".to_string(),
|
|
||||||
"./macaw.db",
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
output.send(Message::ClientCreated(luz)).await;
|
|
||||||
let stream = ReceiverStream::new(recv);
|
|
||||||
let stream = stream.map(|message| Message::Luz(message)).map(Ok);
|
|
||||||
stream.forward(output).await;
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn subscription(&self) -> Subscription<Message> {
|
|
||||||
Subscription::run(Macaw::stream)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update(&mut self, message: Message) -> Task<Message> {
|
fn update(&mut self, message: Message) -> Task<Message> {
|
||||||
match message {
|
match message {
|
||||||
Message::Luz(update_message) => match update_message {
|
Message::Luz(update_message) => match update_message {
|
||||||
|
@ -68,18 +145,35 @@ impl Macaw {
|
||||||
tracing::error!("Luz error: {:?}", error);
|
tracing::error!("Luz error: {:?}", error);
|
||||||
Task::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
UpdateMessage::Online(online, vec) => {
|
UpdateMessage::Online(online, vec) => match &mut self.client {
|
||||||
self.connection_status = Some(Presence::Online(online));
|
Account::LoggedIn(client) => {
|
||||||
let mut roster = HashMap::new();
|
client.connection_status = Presence::Online(online);
|
||||||
for contact in vec {
|
let mut roster = HashMap::new();
|
||||||
roster.insert(contact.user_jid.clone(), contact);
|
for contact in vec {
|
||||||
|
roster.insert(contact.user_jid.clone(), contact);
|
||||||
|
}
|
||||||
|
self.roster = roster;
|
||||||
|
Task::none()
|
||||||
}
|
}
|
||||||
self.roster = roster;
|
Account::LoggedOut {
|
||||||
Task::none()
|
jid,
|
||||||
}
|
password,
|
||||||
|
error,
|
||||||
|
} => Task::none(),
|
||||||
|
},
|
||||||
UpdateMessage::Offline(offline) => {
|
UpdateMessage::Offline(offline) => {
|
||||||
self.connection_status = Some(Presence::Offline(offline));
|
// TODO: update all contacts' presences to unknown (offline)
|
||||||
Task::none()
|
match &mut self.client {
|
||||||
|
Account::LoggedIn(client) => {
|
||||||
|
client.connection_status = Presence::Offline(offline);
|
||||||
|
Task::none()
|
||||||
|
}
|
||||||
|
Account::LoggedOut {
|
||||||
|
jid,
|
||||||
|
password,
|
||||||
|
error,
|
||||||
|
} => Task::none(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
UpdateMessage::FullRoster(vec) => {
|
UpdateMessage::FullRoster(vec) => {
|
||||||
let mut macaw_roster = HashMap::new();
|
let mut macaw_roster = HashMap::new();
|
||||||
|
@ -118,13 +212,13 @@ impl Macaw {
|
||||||
Task::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Message::ClientCreated(luz_handle) => {
|
// TODO: NEXT
|
||||||
let cloned: LuzHandle = luz_handle.clone();
|
Message::ClientCreated(client) => {
|
||||||
self.client = Some(cloned);
|
self.client = Account::LoggedIn(client.clone());
|
||||||
let (send, recv) = oneshot::channel();
|
let (send, recv) = oneshot::channel();
|
||||||
Task::perform(
|
Task::perform(
|
||||||
async move {
|
async move {
|
||||||
luz_handle.send(CommandMessage::GetRoster(send)).await;
|
client.client.send(CommandMessage::GetRoster(send)).await;
|
||||||
recv.await
|
recv.await
|
||||||
},
|
},
|
||||||
|result| {
|
|result| {
|
||||||
|
@ -141,64 +235,262 @@ impl Macaw {
|
||||||
self.roster = hash_map;
|
self.roster = hash_map;
|
||||||
Task::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
Message::Connect => {
|
Message::Connect => match &self.client {
|
||||||
let client = self.client.clone();
|
Account::LoggedIn(client) => {
|
||||||
Task::future(async move {
|
let client = client.client.clone();
|
||||||
client.clone().unwrap().send(CommandMessage::Connect).await;
|
Task::future(async move {
|
||||||
})
|
client.send(CommandMessage::Connect).await;
|
||||||
.discard()
|
})
|
||||||
}
|
.discard()
|
||||||
Message::Disconnect => {
|
}
|
||||||
let client = self.client.clone();
|
Account::LoggedOut {
|
||||||
Task::future(async move {
|
jid,
|
||||||
client
|
password,
|
||||||
.clone()
|
error,
|
||||||
.unwrap()
|
} => Task::none(),
|
||||||
.send(CommandMessage::Disconnect(Offline::default()))
|
},
|
||||||
.await;
|
Message::Disconnect => match &self.client {
|
||||||
})
|
Account::LoggedIn(client) => {
|
||||||
.discard()
|
let client = client.client.clone();
|
||||||
}
|
Task::future(async move {
|
||||||
|
client
|
||||||
|
.send(CommandMessage::Disconnect(Offline::default()))
|
||||||
|
.await;
|
||||||
|
})
|
||||||
|
.discard()
|
||||||
|
}
|
||||||
|
Account::LoggedOut {
|
||||||
|
jid,
|
||||||
|
password,
|
||||||
|
error,
|
||||||
|
} => Task::none(),
|
||||||
|
},
|
||||||
Message::OpenChat(jid) => todo!(),
|
Message::OpenChat(jid) => todo!(),
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view(&self) -> Element<Message> {
|
fn view(&self) -> Element<Message> {
|
||||||
let mut contacts: Vec<Element<Message>> = Vec::new();
|
let ui = {
|
||||||
for (_, contact) in &self.roster {
|
let mut contacts: Vec<Element<Message>> = Vec::new();
|
||||||
contacts.push(
|
for (_, contact) in &self.roster {
|
||||||
button(match &contact.user_jid.localpart {
|
let jid: Cow<'_, str> = (&contact.user_jid).into();
|
||||||
Some(u) => u,
|
contacts.push(
|
||||||
None => "no username",
|
button(text(jid))
|
||||||
})
|
.on_press(Message::OpenChat(contact.user_jid.clone()))
|
||||||
.on_press(Message::OpenChat(contact.user_jid.clone()))
|
.into(),
|
||||||
.into(),
|
);
|
||||||
);
|
}
|
||||||
}
|
let column = column(contacts);
|
||||||
let column = column(contacts);
|
let connection_status = match &self.client {
|
||||||
let connection_status = match &self.connection_status {
|
Account::LoggedIn(client) => match &client.connection_status {
|
||||||
Some(s) => match s {
|
Presence::Online(_online) => "online",
|
||||||
Presence::Online(online) => "connected",
|
Presence::Offline(_offline) => "disconnected",
|
||||||
Presence::Offline(offline) => "disconnected",
|
},
|
||||||
},
|
Account::LoggedOut {
|
||||||
None => "no account",
|
jid: _,
|
||||||
|
password: _,
|
||||||
|
error,
|
||||||
|
} => "disconnected",
|
||||||
|
};
|
||||||
|
// match &self.client.as_ref().map(|client| &client.connection_status) {
|
||||||
|
// Some(s) => match s {
|
||||||
|
// Presence::Online(online) => "connected",
|
||||||
|
// Presence::Offline(offline) => "disconnected",
|
||||||
|
// },
|
||||||
|
// None => "no account",
|
||||||
|
// };
|
||||||
|
let client_jid: Cow<'_, str> = match &self.client {
|
||||||
|
Account::LoggedIn(client) => (&client.jid).into(),
|
||||||
|
Account::LoggedOut {
|
||||||
|
jid: _,
|
||||||
|
password: _,
|
||||||
|
error,
|
||||||
|
} => Cow::from("no account"),
|
||||||
|
// map(|client| (&client.jid).into());
|
||||||
|
};
|
||||||
|
column![
|
||||||
|
row![
|
||||||
|
text(client_jid),
|
||||||
|
text(connection_status),
|
||||||
|
button("connect").on_press(Message::Connect),
|
||||||
|
button("disconnect").on_press(Message::Disconnect)
|
||||||
|
],
|
||||||
|
text("Buddy List:"),
|
||||||
|
//
|
||||||
|
//
|
||||||
|
column,
|
||||||
|
]
|
||||||
};
|
};
|
||||||
column![
|
|
||||||
row![
|
// temporarily center to fill space
|
||||||
text("test@blos.sm"),
|
let ui = center(ui).into();
|
||||||
text(connection_status),
|
|
||||||
button("connect").on_press(Message::Connect),
|
match &self.client {
|
||||||
button("disconnect").on_press(Message::Disconnect)
|
Account::LoggedIn(_client) => ui,
|
||||||
],
|
Account::LoggedOut {
|
||||||
text("Buddy List:"),
|
jid,
|
||||||
//
|
password,
|
||||||
//
|
error,
|
||||||
column,
|
} => {
|
||||||
]
|
let signup = container(
|
||||||
.into()
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn theme(&self) -> Theme {
|
fn theme(&self) -> Theme {
|
||||||
Theme::Dark
|
Theme::Dark
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn modal<'a, Message>(
|
||||||
|
base: impl Into<Element<'a, Message>>,
|
||||||
|
content: impl Into<Element<'a, Message>>,
|
||||||
|
// on_blur: 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()
|
||||||
|
}
|
||||||
|
})) // .on_press(on_blur)
|
||||||
|
)
|
||||||
|
]
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue