From b1fc29669b54d544e02d2d73b8dc841d43a5c92a Mon Sep 17 00:00:00 2001 From: cel 🌸 Date: Fri, 25 Apr 2025 23:00:14 +0100 Subject: initial commit --- src/lib.rs | 222 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 6 ++ 2 files changed, 228 insertions(+) create mode 100644 src/lib.rs create mode 100644 src/main.rs (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..8e4f407 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,222 @@ +use std::{ops::{Deref, DerefMut}, str::FromStr, sync::Arc, thread::sleep, time::{self, Duration}}; + +use filamento::{db::Db, files::FilesMem, UpdateMessage}; +use jid::JID; +use leptos::{logging::debug_warn, prelude::*, task::spawn_local}; +use leptos_meta::Stylesheet; +use stylance::import_style; +use thiserror::Error; +use tokio::{sync::mpsc::Receiver}; + +pub enum AppState { + LoggedOut, + LoggedIn, +} + +#[derive(Clone)] +pub struct Client { + client: filamento::Client, + jid: Arc, + file_store: FilesMem, +} + +impl Deref for Client { + type Target = filamento::Client; + + fn deref(&self) -> &Self::Target { + &self.client + } +} + +impl DerefMut for Client { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.client + } +} + +#[component] +pub fn App() -> impl IntoView { + let (app, set_app) = signal(AppState::LoggedOut); + let client: RwSignal)>, LocalStorage> = RwSignal::new_local(None); + + view! { + {move || match &*app.read() { + AppState::LoggedOut => view! { }.into_any(), + AppState::LoggedIn => { + if let Some((client, updates)) = client.write_untracked().take() { + debug_warn!("opening app"); + view! { }.into_any() + } else { + set_app.set(AppState::LoggedOut); + view! { }.into_any() + } + } + }} + } +} + +#[derive(Clone, Debug, Error)] +pub enum LoginError { + #[error("Missing Password")] + MissingPassword, + #[error("Missing JID")] + MissingJID, + #[error("Invalid JID: {0}")] + InvalidJID(#[from] jid::ParseError), +} + +#[component] +fn LoginPage(set_app: WriteSignal, set_client: RwSignal)>, LocalStorage>) -> impl IntoView { + let jid = RwSignal::new("".to_string()); + let password = RwSignal::new("".to_string()); + let remember_me = RwSignal::new(false); + let connect_on_login = RwSignal::new(true); + let (error, set_error) = signal(None::); + + let error_message = move || { + error.with(|error| { + if let Some(error) = error { + view! {
{error.to_string()}
}.into_any() + } else { + view! {}.into_any() + } + }) + }; + + let (login_pending, set_login_pending) = signal(false); + + let login = Action::new(move |_| { + async move { + set_login_pending.set(true); + + if jid.read_untracked().is_empty() { + set_error.set(Some(LoginError::MissingJID)); + set_login_pending.set(false); + return + } + + if password.read_untracked().is_empty() { + set_error.set(Some(LoginError::MissingPassword)); + set_login_pending.set(false); + return + } + + let jid = match JID::from_str(&jid.read_untracked()) { + Ok(j) => j, + Err(e) => { + set_error.set(Some(e.into())); + set_login_pending.set(false); + return + }, + }; + + // initialise the client + let db = Db::create_connect_and_migrate("mem.db").await.unwrap(); + let files_mem = FilesMem::new(); + let (client, updates) = + filamento::Client::new(jid.clone(), password.read_untracked().clone(), db, files_mem.clone()); + // TODO: remember_me + // TODO: connect on login + let client = Client { + client, + jid: Arc::new(jid), + file_store: files_mem, + }; + + // debug!("before setting app state"); + set_client.set(Some((client, updates))); + debug_warn!("going"); + set_app.set(AppState::LoggedIn); + debug_warn!("gone"); + } + }); + + view! { +
+
+
+ +

Macaw Instant Messenger

+
+ {error_message} +
+ + + + +
+ + +
+
+ + +
+ +
+
+
+ } +} + +#[component] +fn Macaw( + // TODO: logout + // app_state: WriteSignal)>, LocalStorage>, + client: Client, + mut updates: Receiver, +) -> impl IntoView { + let client = RwSignal::new_local(client); + provide_context(client); + debug_warn!("ajsdlkfjalsf"); + + let updates_routine = OnceResource::new(async move { + debug_warn!("started"); + while let Some(update) = updates.recv().await { + match update { + UpdateMessage::Online(online, items) => todo!(), + UpdateMessage::Offline(offline) => todo!(), + UpdateMessage::RosterUpdate(contact, user) => todo!(), + UpdateMessage::RosterDelete(jid) => todo!(), + UpdateMessage::Presence { from, presence } => todo!(), + UpdateMessage::Message { to, from, message } => todo!(), + UpdateMessage::MessageDelivery { id, chat, delivery } => todo!(), + UpdateMessage::SubscriptionRequest(jid) => todo!(), + UpdateMessage::NickChanged { jid, nick } => todo!(), + UpdateMessage::AvatarChanged { jid, id } => todo!(), + } + } + }); + + view! { "logged in" } +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..8b89d4d --- /dev/null +++ b/src/main.rs @@ -0,0 +1,6 @@ +use leptos::prelude::*; +use macaw_web::App; + +fn main() { + leptos::mount::mount_to_body(App) +} -- cgit