Compare commits
No commits in common. "5a2fae397cb0269cdb2b9ce5ded742a78d58cdef" and "ba101fb4938be465b5611107ef991fc6c9469b02" have entirely different histories.
5a2fae397c
...
ba101fb493
|
@ -1,3 +1,2 @@
|
||||||
/target
|
/target
|
||||||
.vscode
|
|
||||||
macaw.db
|
macaw.db
|
||||||
|
|
|
@ -33,17 +33,6 @@ 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"
|
||||||
|
@ -382,15 +371,6 @@ 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"
|
||||||
|
@ -483,15 +463,6 @@ 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"
|
||||||
|
@ -527,16 +498,6 @@ 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"
|
||||||
|
@ -2019,16 +1980,6 @@ 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"
|
||||||
|
@ -2303,7 +2254,6 @@ dependencies = [
|
||||||
"iced",
|
"iced",
|
||||||
"jid",
|
"jid",
|
||||||
"luz",
|
"luz",
|
||||||
"secret-service",
|
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-stream",
|
"tokio-stream",
|
||||||
"tracing",
|
"tracing",
|
||||||
|
@ -2525,30 +2475,6 @@ 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"
|
||||||
|
@ -2566,15 +2492,6 @@ 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"
|
||||||
|
@ -2595,17 +2512,6 @@ 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"
|
||||||
|
@ -3585,25 +3491,6 @@ 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"
|
||||||
|
@ -4359,7 +4246,6 @@ dependencies = [
|
||||||
"signal-hook-registry",
|
"signal-hook-registry",
|
||||||
"socket2",
|
"socket2",
|
||||||
"tokio-macros",
|
"tokio-macros",
|
||||||
"tracing",
|
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -5568,7 +5454,6 @@ 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,127 +1,38 @@
|
||||||
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::text::{Fragment, IntoFragment};
|
use iced::widget::{button, column, row, text, text_input};
|
||||||
use iced::widget::{
|
use iced::{stream, Element, Subscription, Task, Theme};
|
||||||
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::{mpsc, oneshot};
|
use tokio::sync::oneshot;
|
||||||
use tokio_stream::wrappers::ReceiverStream;
|
use tokio_stream::wrappers::ReceiverStream;
|
||||||
use tracing::info;
|
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
pub struct Macaw {
|
pub struct Macaw {
|
||||||
client: Account,
|
client: Option<LuzHandle>,
|
||||||
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();
|
||||||
|
|
||||||
let client: Option<(JID, LuzHandle, mpsc::Receiver<UpdateMessage>)> = None;
|
iced::application("Macaw", Macaw::update, Macaw::view)
|
||||||
|
.subscription(Macaw::subscription)
|
||||||
if let Some((jid, luz_handle, update_recv)) = client {
|
.run()
|
||||||
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 {
|
||||||
LoginModal(LoginModalMessage),
|
ClientCreated(LuzHandle),
|
||||||
ClientCreated(Client),
|
|
||||||
Luz(UpdateMessage),
|
Luz(UpdateMessage),
|
||||||
Roster(HashMap<JID, Contact>),
|
Roster(HashMap<JID, Contact>),
|
||||||
Connect,
|
Connect,
|
||||||
|
@ -129,15 +40,27 @@ 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 {
|
||||||
|
@ -145,35 +68,18 @@ impl Macaw {
|
||||||
tracing::error!("Luz error: {:?}", error);
|
tracing::error!("Luz error: {:?}", error);
|
||||||
Task::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
UpdateMessage::Online(online, vec) => match &mut self.client {
|
UpdateMessage::Online(online, vec) => {
|
||||||
Account::LoggedIn(client) => {
|
self.connection_status = Some(Presence::Online(online));
|
||||||
client.connection_status = Presence::Online(online);
|
let mut roster = HashMap::new();
|
||||||
let mut roster = HashMap::new();
|
for contact in vec {
|
||||||
for contact in vec {
|
roster.insert(contact.user_jid.clone(), contact);
|
||||||
roster.insert(contact.user_jid.clone(), contact);
|
|
||||||
}
|
|
||||||
self.roster = roster;
|
|
||||||
Task::none()
|
|
||||||
}
|
}
|
||||||
Account::LoggedOut {
|
self.roster = roster;
|
||||||
jid,
|
Task::none()
|
||||||
password,
|
}
|
||||||
error,
|
|
||||||
} => Task::none(),
|
|
||||||
},
|
|
||||||
UpdateMessage::Offline(offline) => {
|
UpdateMessage::Offline(offline) => {
|
||||||
// TODO: update all contacts' presences to unknown (offline)
|
self.connection_status = Some(Presence::Offline(offline));
|
||||||
match &mut self.client {
|
Task::none()
|
||||||
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();
|
||||||
|
@ -212,13 +118,13 @@ impl Macaw {
|
||||||
Task::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// TODO: NEXT
|
Message::ClientCreated(luz_handle) => {
|
||||||
Message::ClientCreated(client) => {
|
let cloned: LuzHandle = luz_handle.clone();
|
||||||
self.client = Account::LoggedIn(client.clone());
|
self.client = Some(cloned);
|
||||||
let (send, recv) = oneshot::channel();
|
let (send, recv) = oneshot::channel();
|
||||||
Task::perform(
|
Task::perform(
|
||||||
async move {
|
async move {
|
||||||
client.client.send(CommandMessage::GetRoster(send)).await;
|
luz_handle.send(CommandMessage::GetRoster(send)).await;
|
||||||
recv.await
|
recv.await
|
||||||
},
|
},
|
||||||
|result| {
|
|result| {
|
||||||
|
@ -235,262 +141,64 @@ impl Macaw {
|
||||||
self.roster = hash_map;
|
self.roster = hash_map;
|
||||||
Task::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
Message::Connect => match &self.client {
|
Message::Connect => {
|
||||||
Account::LoggedIn(client) => {
|
let client = self.client.clone();
|
||||||
let client = client.client.clone();
|
Task::future(async move {
|
||||||
Task::future(async move {
|
client.clone().unwrap().send(CommandMessage::Connect).await;
|
||||||
client.send(CommandMessage::Connect).await;
|
})
|
||||||
})
|
.discard()
|
||||||
.discard()
|
}
|
||||||
}
|
Message::Disconnect => {
|
||||||
Account::LoggedOut {
|
let client = self.client.clone();
|
||||||
jid,
|
Task::future(async move {
|
||||||
password,
|
client
|
||||||
error,
|
.clone()
|
||||||
} => Task::none(),
|
.unwrap()
|
||||||
},
|
.send(CommandMessage::Disconnect(Offline::default()))
|
||||||
Message::Disconnect => match &self.client {
|
.await;
|
||||||
Account::LoggedIn(client) => {
|
})
|
||||||
let client = client.client.clone();
|
.discard()
|
||||||
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 ui = {
|
let mut contacts: Vec<Element<Message>> = Vec::new();
|
||||||
let mut contacts: Vec<Element<Message>> = Vec::new();
|
for (_, contact) in &self.roster {
|
||||||
for (_, contact) in &self.roster {
|
contacts.push(
|
||||||
let jid: Cow<'_, str> = (&contact.user_jid).into();
|
button(match &contact.user_jid.localpart {
|
||||||
contacts.push(
|
Some(u) => u,
|
||||||
button(text(jid))
|
None => "no username",
|
||||||
.on_press(Message::OpenChat(contact.user_jid.clone()))
|
})
|
||||||
.into(),
|
.on_press(Message::OpenChat(contact.user_jid.clone()))
|
||||||
);
|
.into(),
|
||||||
}
|
);
|
||||||
let column = column(contacts);
|
|
||||||
let connection_status = match &self.client {
|
|
||||||
Account::LoggedIn(client) => match &client.connection_status {
|
|
||||||
Presence::Online(_online) => "online",
|
|
||||||
Presence::Offline(_offline) => "disconnected",
|
|
||||||
},
|
|
||||||
Account::LoggedOut {
|
|
||||||
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,
|
|
||||||
]
|
|
||||||
};
|
|
||||||
|
|
||||||
// temporarily center to fill space
|
|
||||||
let ui = center(ui).into();
|
|
||||||
|
|
||||||
match &self.client {
|
|
||||||
Account::LoggedIn(_client) => ui,
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
let column = column(contacts);
|
||||||
|
let connection_status = match &self.connection_status {
|
||||||
|
Some(s) => match s {
|
||||||
|
Presence::Online(online) => "connected",
|
||||||
|
Presence::Offline(offline) => "disconnected",
|
||||||
|
},
|
||||||
|
None => "no account",
|
||||||
|
};
|
||||||
|
column![
|
||||||
|
row![
|
||||||
|
text("test@blos.sm"),
|
||||||
|
text(connection_status),
|
||||||
|
button("connect").on_press(Message::Connect),
|
||||||
|
button("disconnect").on_press(Message::Disconnect)
|
||||||
|
],
|
||||||
|
text("Buddy List:"),
|
||||||
|
//
|
||||||
|
//
|
||||||
|
column,
|
||||||
|
]
|
||||||
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
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