diff --git a/src/main.rs b/src/main.rs
index 9e3dab3..e93034b 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,15 +1,18 @@
#![allow(non_snake_case)]
-use std::collections::HashMap;
-use std::future::Future;
-use std::str::FromStr;
-use futures_util::stream::StreamExt;
+mod types;
+mod widgets;
+mod xmpp_interface;
+
+use crate::dioxus_elements::div;
+use dioxus::html::button;
use dioxus::prelude::*;
use dioxus_desktop::Config;
-use log::info;
-use tokio::select;
-use xmpp::{BareJid, ClientBuilder, ClientType};
-use xmpp::parsers::message::MessageType;
+use futures_util::stream::StreamExt;
+use jid::BareJid;
+use std::future::Future;
+use std::str::FromStr;
+use widgets::App;
const STYLESHEET: &str = r#"
body {
@@ -28,351 +31,42 @@ const STYLESHEET: &str = r#"
height: 100%;
}
+ .login-form {
+ margin: auto;
+ text-align: center;
+ }
+
+ .login-form input[type=text], .login-form input[type=password] {
+ display: block;
+ padding: 2mm;
+ margin: 2mm 0;
+ }
+
+ .login-form input[type=checkbox] {
+ vertical-align: middle;
+ padding: 2mm;
+ margin: 2mm;
+ }
+
+ .login-form button {
+ display: block;
+ padding: 2mm;
+ margin: 2mm 0;
+ width: 100%;
+ box-sizing: border-box;
+ }
"#;
fn main() {
env_logger::init();
- let entry = keyring::Entry::new("dergchat", "dergchat").expect("Failed to create keyring entry");
-
- entry.set_password("topS3cr3tP4$$w0rd").expect("Failed to set password");
- let password = entry.get_password().expect("Failed to get password");
- println!("My password is '{}'", password);
- entry.delete_password().expect("Failed to delete password");
-
hot_reload_init!();
// launch the dioxus app in a webview
- dioxus_desktop::launch_cfg(App,
- Config::default()
- .with_custom_head(format!(r#""#, STYLESHEET))
- .with_background_color((32, 64, 32, 255)));
-}
-
-#[derive(Props)]
-struct RoomListProps<'a> {
- rooms: Vec,
- on_room_picked: EventHandler<'a, BareJid>,
- on_room_left: EventHandler<'a, BareJid>,
-}
-
-/// A Dioxus component that renders a list of rooms
-fn RoomList<'a>(cx: Scope<'a, RoomListProps>) -> Element<'a> {
- render! {
- ul {
- list_style: "none",
- flex_grow: 1,
- margin: 0,
- padding: 0,
- for room in cx.props.rooms.iter() {
- rsx! { li {
- display: "flex",
- flex_direction: "row",
-
- onclick: |evt| cx.props.on_room_picked.call(room.to_owned()),
-
- div {
- flex_grow: 1,
- "{room}"
- }
-
- button {
-
- onclick: |evt| {
- evt.stop_propagation();
- cx.props.on_room_left.call(room.to_owned());
- },
- "X"
- }
- } }
- }
- }
- }
-}
-
-#[derive(Debug, Clone)]
-struct Message {
- sender: String,
- body: String,
-}
-
-#[derive(Props)]
-struct RoomViewProps<'a> {
- room: BareJid,
- messages: Vec,
- on_message_sent: EventHandler<'a, String>,
-}
-
-#[derive(Props)]
-struct SendMessageProps<'a> {
- on_message_sent: EventHandler<'a, String>,
-}
-
-fn RoomView<'a>(cx: Scope<'a, RoomViewProps>) -> Element<'a> {
-
- let message = use_state(cx, || "".to_owned());
-
- render! {
- div {
- padding: "5mm",
- flex_grow: 1,
- display: "flex",
- background_color: "#166322",
- flex_direction: "column",
- h2 {
- margin: 0,
- padding: 0,
- border_bottom: "1px solid lightgray",
- "{cx.props.room}"
- }
- ul {
- flex_grow: 1,
- overflow_y: "scroll",
- for message in cx.props.messages.iter() {
- rsx! { li {
- "{message.sender}: {message.body}"
- } }
- }
- }
- SendMessage {
- on_message_sent: |x:String| cx.props.on_message_sent.call(x),
- }
- }
- }
-}
-
-fn SendMessage<'a>(cx: Scope<'a, SendMessageProps>) -> Element<'a> {
-
- let message = use_state(cx, || "".to_owned());
-
- render! {
- div {
- display: "flex",
- flex_direction: "row",
- textarea {
- resize: "none",
- flex_grow: 1,
- oninput: |evt| {
- message.set(evt.value.clone());
- }
- }
- button {
- height: "100%",
- onclick: move |_| {
- cx.props.on_message_sent.call(message.current().to_string());
- },
- "Send"
- }
- }
- }
-}
-
-async fn handle_event(event: xmpp::Event,
- agent: &mut xmpp::Agent,
- messages: &mut UseRef>>) {
- match event {
- xmpp::Event::JoinRoom(jid, conference) => {
- println!("Will auto-join room: {}", &jid);
- agent.join_room(jid, None, None, "en/us", "online").await;
- }
- xmpp::Event::RoomJoined(room_jid) => {
- println!("Joined room: {}", &room_jid);
- messages.with_mut(move |m| { m.entry(room_jid.clone()).or_insert(vec![]); });
- }
- xmpp::Event::RoomLeft(room_jid) => {
- println!("Left room: {}", &room_jid);
- messages.with_mut(move |m| { m.remove(&room_jid); });
- }
- xmpp::Event::ChatMessage(id, sender, body) => {
- println!("Message from {}: {}", &sender, &body.0);
- messages.with_mut(move |m| {
- m.entry(sender.clone()).or_insert(vec![]).push(Message {
- sender: sender.to_string(),
- body: body.0,
- });
- });
- }
- xmpp::Event::RoomMessage(id, room_jid, sender_nick, body) => {
- println!("Message in {} from {}: {}", &room_jid, &sender_nick, &body.0);
- messages.with_mut(move |m| m.entry(room_jid.clone()).or_insert(vec![]).push(Message {
- sender: sender_nick,
- body: body.0,
- }));
- }
- xmpp::Event::RoomPrivateMessage(id, room_jid, sender_nick, body) => {
- println!("Private message in {} from {}: {}", &room_jid, &sender_nick, &body.0);
- messages.with_mut(move |m| m.entry(room_jid.clone()).or_insert(vec![]).push(Message {
- sender: sender_nick,
- body: body.0,
- }));
- }
- _ => {
- log::debug!("Received unsupported event {:?}", event);
- }
- }
-}
-
-#[derive(Debug)]
-enum NetworkCommand {
- JoinRoom { room: BareJid },
- LeaveRoom { room: BareJid },
- SendMessage { recipient: BareJid, message: String },
-}
-
-#[derive(Props)]
-struct RoomJoinProps<'a> {
- on_join_room: EventHandler<'a, String>,
-}
-
-fn RoomJoinWidget<'a>(cx: Scope<'a, RoomJoinProps>) -> Element<'a> {
-
- let room = use_state(cx, || "".to_owned());
-
- render! {
- div {
- display: "flex",
- flex_direction: "row",
- input {
- flex_grow: 1,
- display: "block",
- oninput: |evt| {
- room.set(evt.value.clone());
- }
- }
- button {
- onclick: move |_| cx.props.on_join_room.call(room.current().to_string()),
- "Join"
- }
- }
- }
-}
-
-// define a component that renders a div with the text "Hello, world!"
-fn App(cx: Scope) -> Element {
-
- let messages = use_ref(cx, || HashMap::new());
- let current_room = use_state(cx, || None::);
-
- let cr = use_coroutine(cx,
- |rx: UnboundedReceiver| run_xmpp(messages.clone(), rx),
+ dioxus_desktop::launch_cfg(
+ App,
+ Config::default()
+ .with_custom_head(format!(r#""#, STYLESHEET))
+ .with_background_color((32, 64, 32, 255)),
);
-
- render! {
- div {
- margin: 0,
- padding: 0,
- display: "flex",
- width: "100%",
- height: "100%",
-
- div {
- padding: "5mm",
- background_color: "#1d852d",
- display: "flex",
- flex_direction: "column",
- div {
- border_bottom: "1px solid lightgray",
- "Mizah"
- }
- RoomList {
- rooms: messages.read().keys().cloned().collect(),
- on_room_picked: move |x:BareJid| {
- println!("Room selected: {:?}", x);
- current_room.set(Some(x));
- },
- on_room_left: move |x:BareJid| {
- println!("Leaving room: {:?}", x);
- cr.send(NetworkCommand::LeaveRoom { room: x });
- },
- }
- RoomJoinWidget {
- on_join_room: move |x:String| {
- println!("Joining room: {:?}", x);
- cr.send(NetworkCommand::JoinRoom { room: BareJid::from_str(&x).unwrap() });
- },
- }
- }
-
- if let Some(room) = current_room.get() {
- let messages = messages.read().get(&room).expect("Selected non-existant room").to_vec();
-
- rsx! {
- RoomView {
- room: room.clone(),
- messages: messages,
- on_message_sent: move |x:String| {
- println!("Message sent: {:?}", x);
- cr.send(NetworkCommand::SendMessage { recipient: room.clone(), message: x });
- },
- }
- }
-
- } else {
-
- rsx! {
- div {
- padding: "5mm",
- flex_grow: 1,
- display: "flex",
- background_color: "#166322",
- "No room selected. Pick one from the list on the left."
- }
- }
-
- }
- }
- }
}
-
-fn run_xmpp(mut room_data: UseRef>>,
- mut commands: UnboundedReceiver) -> impl Future