use std::ops::{Deref, DerefMut}; use filamento::user::{User, UserStoreFields}; use jid::BareJID; use reactive_stores::{ArcStore, Store}; use leptos::prelude::*; use crate::{client::Client, roster::{Roster, RosterStoreFields}, state_store::{StateListener, StateStore}}; #[derive(Clone, Copy)] pub struct MacawUser { pub user: ArenaItem, // TODO: just store avatar src in user // pub avatar: String, // pub avatar: RwSignal, } impl MacawUser { pub fn get(&self) -> ArcStore { self.try_get_value().unwrap().get().0 } pub fn avatar(&self) -> ArcRwSignal { self.try_get_value().unwrap().get().1 } } impl Deref for MacawUser { type Target = ArenaItem; fn deref(&self) -> &Self::Target { &self.user } } impl DerefMut for MacawUser { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.user } } impl From for MacawUser { fn from(value: ArcMacawUser) -> Self { Self { user: ArenaItem::new_with_storage(value), // avatar: value.avatar.into(), } } } impl From for ArcMacawUser { fn from(value: MacawUser) -> Self { value.user.try_get_value().unwrap() } } #[derive(Clone)] pub struct ArcMacawUser { pub user: StateListener, ArcRwSignal)>, } impl ArcMacawUser { pub async fn got_user(user: User) -> Self { let user_state_store: StateStore, ArcRwSignal)> = use_context().expect("no user state store"); let old_user = user_state_store.get_listener(user.jid.clone()); let user = if let Some(old_user) = old_user { old_user.update(|(old_user, _avatar)| { old_user.set(user); }); old_user } else { let avatar = fetch_avatar(user.avatar.as_deref()).await; let avatar = ArcRwSignal::new(avatar); user_state_store.store(user.jid.clone(), (ArcStore::new(user), avatar)) }; let user = ArcMacawUser { user }; user } } impl Deref for ArcMacawUser { type Target = StateListener, ArcRwSignal)>; fn deref(&self) -> &Self::Target { &self.user } } impl DerefMut for ArcMacawUser { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.user } } pub const NO_AVATAR: &str = "/assets/no-avatar.png"; pub async fn fetch_avatar(id: Option<&str>) -> String { if let Some(avatar) = id { let client = use_context::().expect("client not in context"); if let Some(data) = client.file_store.get_src(avatar).await { data } else { NO_AVATAR.to_string() } } else { NO_AVATAR.to_string() } } pub async fn get_avatar(user: Store) -> String { if let Some(avatar) = &user.read().avatar { let client = use_context::().expect("client not in context"); if let Some(data) = client.file_store.get_src(avatar).await { data } else { NO_AVATAR.to_string() } } else { NO_AVATAR.to_string() } } pub fn get_name(user: Store, note_to_self: bool) -> String { let roster: Store = use_context().expect("no roster in context"); if note_to_self { let client: Client = use_context().expect("no client in context"); if *client.jid == *user.jid().read() { return "Note to self".to_string() } } if let Some(name) = roster .contacts() .read() .get(&user.read().jid) .map(|contact| contact.read().name.clone()) .unwrap_or_default() { name.to_string() } else if let Some(nick) = &user.read().nick { nick.to_string() } else { user.read().jid.to_string() } }