People tab rewrite: recency sort, profile-post Discover, bio modal,
per-author feed filter, ignore primitive The old People tab was built on network-layer presence (`is_online`, `last_seen` from the mesh), which was lost when v0.6.1 anonymized the network id from the posting id. Every named follow is authored under a posting id that doesn't appear in the connection-layer tables; the "Online" section listed nobody useful and Discover depended on the same broken signal. Replaced with signals derived from signed content: - Following is sorted by most-recent-post timestamp (the real meaning of "activity" in a post-anonymization world). - Discover lists named peers we've received signed profile posts from (via Phase 2d), filtered by follows / ignores / self. - Click-a-name surfaces a bio modal with View Posts / Follow / Message / Ignore actions. - Author-scoped feed filter (`View Posts` on any person) renders a "Showing posts from X" banner with a Clear button. - Ignore is a new local-only primitive; ignored peers' posts and profiles are excluded everywhere and the ignored list is editable in Settings. Core changes: - New `ignored_peers(node_id, ignored_at)` table + storage helpers (`add_ignored_peer`, `remove_ignored_peer`, `list_ignored_peers`, `is_ignored_peer`). Schema created fresh; no migration since the table is purely additive and empty on prior installs. - All 6 feed-query sites now also exclude `author IN ignored_peers`. - New `Storage::last_activity_for_authors(&[NodeId])` — one batched query returning max post timestamp per author, excluding non-feed intents (Control / Profile / Announcement / GroupKeyDistribute). - New `Storage::list_discoverable_profiles(&self_id)` — named profile rows where node_id is not self, not in follows, not in ignored, and `public_visible = 1`. Sorted by profile `updated_at` DESC. - New `Storage::delete_setting(key)` — missing counterpart to set/get. - Node wrappers: `last_activity_for_follows`, `ignore_peer` (also drops any follow + social route for the ignored peer), `unignore_peer`, `list_ignored_peers`, `list_discoverable_profiles`. - `list_follows` Tauri command now sources `last_activity_ms` from the posts-driven batched query rather than the network peer record. Tauri commands: `list_discover`, `ignore_peer`, `unignore_peer`, `list_ignored_peers`. Frontend: - Following list: see-new-activity button pattern (staged data + explicit user click to rearrange, so the list doesn't reorder under a tap mid-scroll). Periodic people-tab polling stages + lights up the button; clicking it re-renders. - Discover: rewrites the old peer-table-based list to a profile-post feed. Each card shows name + bio + profile-update age, plus Follow / Posts / Ignore actions. - Bio modal: reuses the existing generic popover. Loads display name + bio via `resolve_display`, shows follow state, offers View Posts / Follow-or-Unfollow / Message / Ignore-or-Unignore. - Author filter: banner renders at the top of the feed when active; clear button restores full feed. Filter state is a single `authorFilterNodeId` field consumed by `filterFeedPosts`. - Settings → Ignored section lists ignored peers with unignore buttons. 124 / 124 core tests pass.
This commit is contained in:
parent
e74bd4e6c6
commit
2ce668aa58
5 changed files with 595 additions and 168 deletions
|
|
@ -1444,6 +1444,47 @@ impl Node {
|
|||
storage.list_follows()
|
||||
}
|
||||
|
||||
/// Batch: for each followed author, return the last-post timestamp we
|
||||
/// hold locally. Used by the Following UI to sort by recency (which
|
||||
/// replaces the broken "online" indicator since the network/posting
|
||||
/// key split anonymized presence).
|
||||
pub async fn last_activity_for_follows(&self) -> anyhow::Result<std::collections::HashMap<NodeId, u64>> {
|
||||
let storage = self.storage.get().await;
|
||||
let follows = storage.list_follows()?;
|
||||
storage.last_activity_for_authors(&follows)
|
||||
}
|
||||
|
||||
// ---- Ignored peers ----
|
||||
|
||||
pub async fn ignore_peer(&self, node_id: &NodeId) -> anyhow::Result<()> {
|
||||
let storage = self.storage.get().await;
|
||||
storage.add_ignored_peer(node_id)?;
|
||||
// If the peer was in follows, also drop them — ignoring implies
|
||||
// no-longer-following. Best-effort; errors are logged by callers.
|
||||
let _ = storage.remove_follow(node_id);
|
||||
let _ = storage.remove_social_route(node_id);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn unignore_peer(&self, node_id: &NodeId) -> anyhow::Result<()> {
|
||||
let storage = self.storage.get().await;
|
||||
storage.remove_ignored_peer(node_id)
|
||||
}
|
||||
|
||||
pub async fn list_ignored_peers(&self) -> anyhow::Result<Vec<NodeId>> {
|
||||
let storage = self.storage.get().await;
|
||||
storage.list_ignored_peers()
|
||||
}
|
||||
|
||||
// ---- Discover ----
|
||||
|
||||
/// Named peers we aren't following and haven't ignored — driven entirely
|
||||
/// by signed profile posts we've received through the CDN.
|
||||
pub async fn list_discoverable_profiles(&self) -> anyhow::Result<Vec<PublicProfile>> {
|
||||
let storage = self.storage.get().await;
|
||||
storage.list_discoverable_profiles(&self.default_posting_id)
|
||||
}
|
||||
|
||||
// ---- Profiles ----
|
||||
|
||||
/// Set the default posting identity's profile (display_name, bio,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue