use std::collections::HashMap;
use chrono::Utc;
use filamento::presence::{Offline, Presence, PresenceType, Show};
use indexmap::IndexMap;
use jid::BareJID;
use leptos::prelude::*;
use reactive_stores::Store;
#[derive(Store)]
pub struct UserPresences {
#[store(key: BareJID = |(jid, _)| jid.clone())]
pub user_presences: HashMap<BareJID, ArcRwSignal<Presences>>,
}
impl UserPresences {
pub fn clear(&mut self) {
for (_user, presences) in &mut self.user_presences {
presences.set(Presences::new())
}
}
// TODO: should be a bare jid
pub fn get_user_presences(&mut self, user: &BareJID) -> ArcRwSignal<Presences> {
if let Some(presences) = self.user_presences.get(user) {
presences.clone()
} else {
let presences = Presences::new();
let signal = ArcRwSignal::new(presences);
self.user_presences.insert(user.clone(), signal.clone());
signal
}
}
}
impl UserPresences {
pub fn new() -> Self {
Self {
user_presences: HashMap::new(),
}
}
}
pub struct Presences {
/// presences are sorted by time, first by type, then by last activity.
presences: IndexMap<String, Presence>
}
impl Presences {
pub fn new() -> Self {
Self {
presences: IndexMap::new(),
}
}
/// gets the highest priority presence
pub fn presence(&self) -> Option<(String, Presence)> {
if let Some((resource, presence)) = self.presences.iter().filter(|(_resource, presence)| if let PresenceType::Online(online) = &presence.presence {
online.show == Some(Show::DoNotDisturb)
} else {
false
}).next() {
return Some((resource.clone(), presence.clone()))
}
if let Some((resource, presence)) = self.presences.iter().filter(|(_resource, presence)| if let PresenceType::Online(online) = &presence.presence {
online.show == Some(Show::Chat)
} else {
false
}).next() {
return Some((resource.clone(), presence.clone()))
}
if let Some((resource, presence)) = self.presences.iter().filter(|(_resource, presence)| if let PresenceType::Online(online) = &presence.presence {
online.show == None
} else {
false
}).next() {
return Some((resource.clone(), presence.clone()))
}
if let Some((resource, presence)) = self.presences.iter().filter(|(_resource, presence)| if let PresenceType::Online(online) = &presence.presence {
online.show == Some(Show::Away)
} else {
false
}).next() {
return Some((resource.clone(), presence.clone()))
}
if let Some((resource, presence)) = self.presences.iter().filter(|(_resource, presence)| if let PresenceType::Online(online) = &presence.presence {
online.show == Some(Show::ExtendedAway)
} else {
false
}).next() {
return Some((resource.clone(), presence.clone()))
}
if let Some((resource, presence)) = self.presences.iter().filter(|(_resource, presence)| if let PresenceType::Offline(_offline) = &presence.presence {
true
} else {
false
}).next() {
return Some((resource.clone(), presence.clone()))
} else {
None
}
}
pub fn update_presence(&mut self, resource: String, presence: Presence) {
let index = match self.presences.binary_search_by(|_, existing_presence| {
presence.timestamp
.cmp(
&existing_presence.timestamp
)
}) {
Ok(i) => i,
Err(i) => i,
};
self.presences.insert_before(
// TODO: check if this logic is correct
index,
resource,
presence,
);
}
pub fn resource_presence(&mut self, resource: String) -> Presence {
if let Some(presence) = self.presences.get(&resource) {
presence.clone()
} else {
Presence {
timestamp: Utc::now(),
presence: PresenceType::Offline(Offline::default()),
}
}
}
}