diff options
Diffstat (limited to '')
| -rw-r--r-- | src/user.rs | 153 |
1 files changed, 153 insertions, 0 deletions
diff --git a/src/user.rs b/src/user.rs new file mode 100644 index 0000000..e277efd --- /dev/null +++ b/src/user.rs @@ -0,0 +1,153 @@ +// SPDX-FileCopyrightText: 2025 cel <cel@bunny.garden> +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +use std::ops::{Deref, DerefMut}; + +use filamento::user::{User, UserStoreFields}; +use jid::BareJID; +use leptos::prelude::*; +use reactive_stores::{ArcStore, Store}; + +use crate::{ + client::Client, + roster::{Roster, RosterStoreFields}, + state_store::{StateListener, StateStore}, +}; + +#[derive(Clone, Copy)] +pub struct MacawUser { + pub user: ArenaItem<ArcMacawUser>, + // TODO: just store avatar src in user + // pub avatar: String, + // pub avatar: RwSignal<String>, +} + +impl MacawUser { + pub fn get(&self) -> ArcStore<User> { + self.try_get_value().unwrap().get().0 + } + + pub fn avatar(&self) -> ArcRwSignal<String> { + self.try_get_value().unwrap().get().1 + } +} + +impl Deref for MacawUser { + type Target = ArenaItem<ArcMacawUser>; + + fn deref(&self) -> &Self::Target { + &self.user + } +} + +impl DerefMut for MacawUser { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.user + } +} + +impl From<ArcMacawUser> for MacawUser { + fn from(value: ArcMacawUser) -> Self { + Self { + user: ArenaItem::new_with_storage(value), + // avatar: value.avatar.into(), + } + } +} + +impl From<MacawUser> for ArcMacawUser { + fn from(value: MacawUser) -> Self { + value.user.try_get_value().unwrap() + } +} + +#[derive(Clone)] +pub struct ArcMacawUser { + pub user: StateListener<BareJID, (ArcStore<User>, ArcRwSignal<String>)>, +} + +impl ArcMacawUser { + pub async fn got_user(user: User) -> Self { + let user_state_store: StateStore<BareJID, (ArcStore<User>, ArcRwSignal<String>)> = + 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<BareJID, (ArcStore<User>, ArcRwSignal<String>)>; + + 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::<Client>().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<User>) -> String { + if let Some(avatar) = &user.read().avatar { + let client = use_context::<Client>().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<User>, note_to_self: bool) -> String { + let roster: Store<Roster> = 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() + } +} |
