remove members by key
This commit is contained in:
parent
ae210d5352
commit
c945fb7c43
2 changed files with 49 additions and 23 deletions
|
|
@ -663,13 +663,28 @@ pub fn Avatar(
|
||||||
// Effect to draw the avatar when canvas is ready or appearance changes
|
// Effect to draw the avatar when canvas is ready or appearance changes
|
||||||
Effect::new(move |_| {
|
Effect::new(move |_| {
|
||||||
// Subscribe to redraw trigger so this effect re-runs when images load
|
// Subscribe to redraw trigger so this effect re-runs when images load
|
||||||
let _ = redraw_trigger.get();
|
let trigger_count = redraw_trigger.get();
|
||||||
|
|
||||||
// Get current values from signals
|
// Get current values from signals
|
||||||
let m = member.get();
|
let m = member.get();
|
||||||
let layout = layout_memo.get();
|
let layout = layout_memo.get();
|
||||||
|
|
||||||
|
// Debug: log avatar redraw
|
||||||
|
web_sys::console::log_1(
|
||||||
|
&format!(
|
||||||
|
"[Avatar Redraw] user={} trigger={} pos=({:.1}, {:.1}) screen=({:.1}, {:.1})",
|
||||||
|
m.member.display_name,
|
||||||
|
trigger_count,
|
||||||
|
m.member.position_x,
|
||||||
|
m.member.position_y,
|
||||||
|
layout.canvas_screen_x,
|
||||||
|
layout.canvas_screen_y,
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
|
);
|
||||||
|
|
||||||
let Some(canvas) = canvas_ref.get() else {
|
let Some(canvas) = canvas_ref.get() else {
|
||||||
|
web_sys::console::log_1(&"[Avatar Redraw] canvas not ready".into());
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -716,7 +731,11 @@ pub fn Avatar(
|
||||||
|
|
||||||
// Set onload handler to trigger redraw when image loads
|
// Set onload handler to trigger redraw when image loads
|
||||||
let trigger = set_redraw_trigger;
|
let trigger = set_redraw_trigger;
|
||||||
|
let path_for_log = normalized_path.clone();
|
||||||
let onload = Closure::once(Box::new(move || {
|
let onload = Closure::once(Box::new(move || {
|
||||||
|
web_sys::console::log_1(
|
||||||
|
&format!("[Avatar] Image loaded: {}", path_for_log).into(),
|
||||||
|
);
|
||||||
trigger.update(|v| *v += 1);
|
trigger.update(|v| *v += 1);
|
||||||
}) as Box<dyn FnOnce()>);
|
}) as Box<dyn FnOnce()>);
|
||||||
img.set_onload(Some(onload.as_ref().unchecked_ref()));
|
img.set_onload(Some(onload.as_ref().unchecked_ref()));
|
||||||
|
|
|
||||||
|
|
@ -468,14 +468,14 @@ pub fn RealmSceneViewer(
|
||||||
})
|
})
|
||||||
.into();
|
.into();
|
||||||
|
|
||||||
let members_by_key = Signal::derive(move || {
|
// Create indexed members for z-ordering (index determines stacking)
|
||||||
sorted_members.get().into_iter().enumerate()
|
let indexed_members = Signal::derive(move || {
|
||||||
.map(|(idx, m)| (member_key(&m), (idx, m)))
|
sorted_members
|
||||||
.collect::<HashMap<_, _>>()
|
.get()
|
||||||
});
|
.into_iter()
|
||||||
|
.enumerate()
|
||||||
let member_keys = Memo::new(move |_| {
|
.map(|(idx, m)| (idx, m))
|
||||||
sorted_members.get().iter().map(member_key).collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
});
|
});
|
||||||
|
|
||||||
let scene_name = scene.name.clone();
|
let scene_name = scene.name.clone();
|
||||||
|
|
@ -511,33 +511,40 @@ pub fn RealmSceneViewer(
|
||||||
</div>
|
</div>
|
||||||
<div class="avatars-container absolute inset-0" style=format!("z-index: {}; pointer-events: none; overflow: visible;", Z_AVATARS_CONTAINER)>
|
<div class="avatars-container absolute inset-0" style=format!("z-index: {}; pointer-events: none; overflow: visible;", Z_AVATARS_CONTAINER)>
|
||||||
<Show when=move || scales_ready.get() fallback=|| ()>
|
<Show when=move || scales_ready.get() fallback=|| ()>
|
||||||
{move || {
|
<For
|
||||||
member_keys.get().into_iter().map(|key| {
|
each=move || indexed_members.get()
|
||||||
let member_signal = Signal::derive(move || {
|
key=|(_, m)| member_key(m)
|
||||||
members_by_key.get().get(&key).map(|(_, m)| m.clone()).expect("member key should exist")
|
children=move |(idx, initial_member)| {
|
||||||
|
let key = member_key(&initial_member);
|
||||||
|
let z_index = (idx as i32) + Z_AVATAR_BASE;
|
||||||
|
|
||||||
|
// Per-member Memo: only fires when THIS member's data changes
|
||||||
|
let member_memo: Memo<ChannelMemberWithAvatar> = Memo::new(move |_| {
|
||||||
|
sorted_members
|
||||||
|
.get()
|
||||||
|
.into_iter()
|
||||||
|
.find(|m| member_key(m) == key)
|
||||||
|
.unwrap_or_else(|| initial_member.clone())
|
||||||
});
|
});
|
||||||
let z_index_signal = Signal::derive(move || {
|
|
||||||
members_by_key.get().get(&key).map(|(idx, _)| (*idx as i32) + Z_AVATAR_BASE).unwrap_or(Z_AVATAR_BASE)
|
// Bubble signal for this member
|
||||||
});
|
let bubble_signal: Signal<Option<ActiveBubble>> = Signal::derive(move || {
|
||||||
let z = z_index_signal.get_untracked();
|
|
||||||
// Derive bubble signal for this member
|
|
||||||
let bubble_signal = Signal::derive(move || {
|
|
||||||
active_bubbles.get().get(&key).cloned()
|
active_bubbles.get().get(&key).cloned()
|
||||||
});
|
});
|
||||||
|
|
||||||
view! {
|
view! {
|
||||||
<Avatar
|
<Avatar
|
||||||
member=member_signal
|
member=member_memo.into()
|
||||||
transform=scene_transform
|
transform=scene_transform
|
||||||
prop_size=prop_size
|
prop_size=prop_size
|
||||||
z_index=z
|
z_index=z_index
|
||||||
text_em_size=text_em_size
|
text_em_size=text_em_size
|
||||||
screen_bounds=screen_bounds
|
screen_bounds=screen_bounds
|
||||||
active_bubble=bubble_signal
|
active_bubble=bubble_signal
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
}).collect_view()
|
}
|
||||||
}}
|
/>
|
||||||
{move || {
|
{move || {
|
||||||
let Some(fading_signal) = fading_members else {
|
let Some(fading_signal) = fading_members else {
|
||||||
return Vec::new().into_iter().collect_view();
|
return Vec::new().into_iter().collect_view();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue