fix(friends): clear the "Rescanning…" status when the pass completes
The manual Rescan set a persistent "Rescanning friends…" status but nothing ever cleared it: the probe pass emits per-friend presence events with no "done" signal, so the banner stuck forever (an offline friend's probe can take up to the 10s IO timeout, and there was no terminal event after). Core now emits a `FriendsRescanned` UiEvent after the manual pass finishes (only the on-demand button, never the 15s auto-refresh, so the status bar isn't churned each interval). The GUI replaces the transient banner with "Friends rescanned." — guarded so it won't clobber a status the user has since triggered. Invisible mode probes no one, so the button now explains that instead of showing a banner that resolves with nothing changed. 469 lib tests pass, clippy clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+17
-1
@@ -1700,6 +1700,14 @@ fn update(state: &mut AppState, message: AppMessage) -> Task<AppMessage> {
|
||||
UiEvent::FriendPresence { id, presence } => {
|
||||
state.friend_presence.insert(id, presence);
|
||||
}
|
||||
UiEvent::FriendsRescanned => {
|
||||
// The manual pass finished; replace the transient "Rescanning…"
|
||||
// banner, but only if it's still showing (don't clobber a status
|
||||
// the user has since triggered, e.g. by joining a room).
|
||||
if state.status_message == "Rescanning friends…" {
|
||||
state.status_message = "Friends rescanned.".to_string();
|
||||
}
|
||||
}
|
||||
UiEvent::PresenceModeReverted { mode } => {
|
||||
// Core corrected the committed presence mode. Mirror + persist so
|
||||
// the picker reflects the discovery state the endpoint actually has.
|
||||
@@ -1898,10 +1906,18 @@ fn update(state: &mut AppState, message: AppMessage) -> Task<AppMessage> {
|
||||
}
|
||||
}
|
||||
AppMessage::RefreshFriends => {
|
||||
// Kick an immediate presence pass; the list updates as replies land.
|
||||
// Kick an immediate presence pass; the list updates as replies land and
|
||||
// the banner clears on the FriendsRescanned completion event. While
|
||||
// Invisible we probe no one, so say why instead of a banner that resolves
|
||||
// with nothing changed.
|
||||
if state.config.presence_mode == PresenceMode::Invisible {
|
||||
state.status_message =
|
||||
"You're invisible — turn on presence to scan friends.".to_string();
|
||||
} else {
|
||||
let _ = state.controller.send(CoreCommand::RefreshFriends);
|
||||
state.status_message = "Rescanning friends…".to_string();
|
||||
}
|
||||
}
|
||||
AppMessage::JoinFriendRoom(ticket) => {
|
||||
// Join via the friend's member ticket (same path as a manual join).
|
||||
let input_device = state.selected_input.as_ref().map(|d| d.name.clone());
|
||||
|
||||
@@ -296,6 +296,11 @@ pub enum UiEvent {
|
||||
/// joinable gathering (with a one-click ticket). Emitted by the outbound ping
|
||||
/// scheduler; absence of a recent event = treat as offline.
|
||||
FriendPresence { id: EndpointId, presence: FriendPresence },
|
||||
/// A manual "Rescan" pass finished (every friend has been probed and its
|
||||
/// per-friend `FriendPresence` already emitted). Lets the GUI clear the
|
||||
/// transient "Rescanning…" status. Sent only for the on-demand button, not the
|
||||
/// periodic auto-refresh, so the status bar isn't churned every interval.
|
||||
FriendsRescanned,
|
||||
/// Core corrected the committed presence posture. Usually the Discoverable
|
||||
/// time-box elapsed and the core auto-reverted to `Normal`; on discovery apply
|
||||
/// failure, this carries the previous truthful mode. The GUI must mirror +
|
||||
|
||||
+13
-7
@@ -2509,14 +2509,20 @@ async fn run_core_loop(
|
||||
CoreCommand::RefreshFriends => {
|
||||
// Manual "Rescan": run an immediate probe pass (same as a scheduler
|
||||
// tick), detached so it can't block command handling. Honour
|
||||
// Invisible — stay fully dark and touch no friend's machine.
|
||||
if *presence_mode.lock().unwrap() != crate::presence::PresenceMode::Invisible {
|
||||
tokio::spawn(probe_friends_once(
|
||||
net.endpoint.clone(),
|
||||
friends.lock().unwrap().clone(),
|
||||
ui_tx.clone(),
|
||||
));
|
||||
// Invisible — stay fully dark and touch no friend's machine. A
|
||||
// `FriendsRescanned` event always follows so the UI's transient
|
||||
// "Rescanning…" status clears even when probing was skipped.
|
||||
let visible =
|
||||
*presence_mode.lock().unwrap() != crate::presence::PresenceMode::Invisible;
|
||||
let endpoint = net.endpoint.clone();
|
||||
let snapshot = friends.lock().unwrap().clone();
|
||||
let tx = ui_tx.clone();
|
||||
tokio::spawn(async move {
|
||||
if visible {
|
||||
probe_friends_once(endpoint, snapshot, tx.clone()).await;
|
||||
}
|
||||
let _ = tx.send(UiEvent::FriendsRescanned).await;
|
||||
});
|
||||
}
|
||||
|
||||
CoreCommand::SetPresenceMode(mode) => {
|
||||
|
||||
Reference in New Issue
Block a user