update to support user expire, timeout, and disconnect
This commit is contained in:
parent
fe65835f4a
commit
5fcd49e847
16 changed files with 744 additions and 238 deletions
|
|
@ -12,13 +12,15 @@ use leptos_router::hooks::use_params_map;
|
|||
use uuid::Uuid;
|
||||
|
||||
use crate::components::{
|
||||
ActiveBubble, AvatarEditorPopup, Card, ChatInput, ChatMessage, EmotionKeybindings,
|
||||
ActiveBubble, AvatarEditorPopup, Card, ChatInput, EmotionKeybindings, FadingMember,
|
||||
InventoryPopup, KeybindingsPopup, MessageLog, RealmHeader, RealmSceneViewer, SettingsPopup,
|
||||
ViewerSettings, DEFAULT_BUBBLE_TIMEOUT_MS,
|
||||
ViewerSettings,
|
||||
};
|
||||
#[cfg(feature = "hydrate")]
|
||||
use crate::components::use_channel_websocket;
|
||||
use crate::utils::{parse_bounds_dimensions, LocalStoragePersist};
|
||||
use crate::components::{use_channel_websocket, ChatMessage, DEFAULT_BUBBLE_TIMEOUT_MS, FADE_DURATION_MS};
|
||||
use crate::utils::LocalStoragePersist;
|
||||
#[cfg(feature = "hydrate")]
|
||||
use crate::utils::parse_bounds_dimensions;
|
||||
use chattyness_db::models::{
|
||||
AvatarWithPaths, ChannelMemberWithAvatar, EmotionAvailability, LooseProp, RealmRole,
|
||||
RealmWithUserRole, Scene,
|
||||
|
|
@ -82,6 +84,9 @@ pub fn RealmPage() -> impl IntoView {
|
|||
// Loose props state
|
||||
let (loose_props, set_loose_props) = signal(Vec::<LooseProp>::new());
|
||||
|
||||
// Fading members state (members that are fading out after timeout disconnect)
|
||||
let (fading_members, set_fading_members) = signal(Vec::<FadingMember>::new());
|
||||
|
||||
// Track user's current position for saving on beforeunload
|
||||
let (current_position, set_current_position) = signal((400.0_f64, 300.0_f64));
|
||||
|
||||
|
|
@ -173,6 +178,15 @@ pub fn RealmPage() -> impl IntoView {
|
|||
// WebSocket connection for real-time updates
|
||||
#[cfg(feature = "hydrate")]
|
||||
let on_members_update = Callback::new(move |new_members: Vec<ChannelMemberWithAvatar>| {
|
||||
// When members are updated (including rejoins), remove any matching fading members
|
||||
set_fading_members.update(|fading| {
|
||||
fading.retain(|f| {
|
||||
!new_members.iter().any(|m| {
|
||||
m.member.user_id == f.member.member.user_id
|
||||
&& m.member.guest_session_id == f.member.member.guest_session_id
|
||||
})
|
||||
});
|
||||
});
|
||||
set_members.set(new_members);
|
||||
});
|
||||
|
||||
|
|
@ -217,6 +231,19 @@ pub fn RealmPage() -> impl IntoView {
|
|||
});
|
||||
});
|
||||
|
||||
// Callback when a member starts fading (timeout disconnect)
|
||||
#[cfg(feature = "hydrate")]
|
||||
let on_member_fading = Callback::new(move |fading: FadingMember| {
|
||||
set_fading_members.update(|members| {
|
||||
// Remove any existing entry for this user (shouldn't happen, but be safe)
|
||||
members.retain(|m| {
|
||||
m.member.member.user_id != fading.member.member.user_id
|
||||
|| m.member.member.guest_session_id != fading.member.member.guest_session_id
|
||||
});
|
||||
members.push(fading);
|
||||
});
|
||||
});
|
||||
|
||||
#[cfg(feature = "hydrate")]
|
||||
let (_ws_state, ws_sender) = use_channel_websocket(
|
||||
slug,
|
||||
|
|
@ -226,6 +253,7 @@ pub fn RealmPage() -> impl IntoView {
|
|||
on_loose_props_sync,
|
||||
on_prop_dropped,
|
||||
on_prop_picked_up,
|
||||
on_member_fading,
|
||||
);
|
||||
|
||||
// Set channel ID and scene dimensions when scene loads
|
||||
|
|
@ -246,16 +274,21 @@ pub fn RealmPage() -> impl IntoView {
|
|||
});
|
||||
}
|
||||
|
||||
// Cleanup expired speech bubbles every 5 seconds
|
||||
// Cleanup expired speech bubbles and fading members every second
|
||||
#[cfg(feature = "hydrate")]
|
||||
{
|
||||
use gloo_timers::callback::Interval;
|
||||
|
||||
let cleanup_interval = Interval::new(5000, move || {
|
||||
let cleanup_interval = Interval::new(1000, move || {
|
||||
let now = js_sys::Date::now() as i64;
|
||||
// Clean up expired bubbles
|
||||
set_active_bubbles.update(|bubbles| {
|
||||
bubbles.retain(|_, bubble| bubble.expires_at > now);
|
||||
});
|
||||
// Clean up completed fading members
|
||||
set_fading_members.update(|members| {
|
||||
members.retain(|m| now - m.fade_start < FADE_DURATION_MS);
|
||||
});
|
||||
});
|
||||
// Keep interval alive
|
||||
std::mem::forget(cleanup_interval);
|
||||
|
|
@ -638,6 +671,7 @@ pub fn RealmPage() -> impl IntoView {
|
|||
s.save();
|
||||
});
|
||||
})
|
||||
fading_members=Signal::derive(move || fading_members.get())
|
||||
/>
|
||||
<div class="absolute bottom-0 left-0 right-0 z-10 pb-4 px-4 pointer-events-none">
|
||||
<ChatInput
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue