mirror of
https://github.com/block/buzz.git
synced 2026-11-12 04:12:21 +00:00
## Summary Mobile kept offering archived people and agents as choices: Add members (including adding an agent to a Solo chat), New DM, the `@` mention chooser, Search › People and the Agents page. An archived agent that shares a live agent's name also forced a qualifier onto the live one, because names were told apart across both. The members sheet listed archived members among live ones with nothing to mark them. Now, matching desktop: - Archived people and agents are left out of those choices. History (messages, activity, profiles) still shows them. - The members sheet moves archived members out of People and Agents into their own "Archived · N" section after both: archived people, then archived agents. Each row reads "Archived · Member" (or Agent) in place of the role, status or "Working…" line. A screen reader reads it with the name. The members preview on the channel info page (the first five members above "See all") follows the same order and label. - Nothing is hidden or marked while the community's archive list is unknown or cannot be read, and you are never hidden from yourself. ### Related issue None found. The desktop members dialog gets the same Archived section in https://github.com/block/buzz-app/pull/3203. ### Testing Widget and provider tests cover each surface, the unknown-archive case, the viewer rule and a community switch. Each test fails without its change. Android emulator, local relay, fictional names. Each archived person or agent has a live namesake. History rows still show archived identities, as intended. **`@` mention chooser, typing "@Sc" (Scout `qsfn` is archived)** | Before | After | | --- | --- | | <img src="https://github.com/user-attachments/assets/6693729c-66c1-4433-8a7b-4f0e948057ee" width="320"> | <img src="https://github.com/user-attachments/assets/eb4f80be-780e-4dbe-8b2b-e6a5b6c3ca97" width="320"> | **`@` mention chooser, typing "@Ca" (Casey Lee `9mhy` is archived)** | Before | After | | --- | --- | | <img src="https://github.com/user-attachments/assets/b6d409cd-7af1-4da7-b5b9-deece5e21de5" width="320"> | <img src="https://github.com/user-attachments/assets/60e21387-791b-4233-b8e6-1a29f94e6810" width="320"> | **Add members, searching "Morgan" (Morgan Reyes `ssc2` is archived)** | Before | After | | --- | --- | | <img src="https://github.com/user-attachments/assets/1222a923-5e43-4263-843d-57564bdc7af3" width="320"> | <img src="https://github.com/user-attachments/assets/dbe58278-788d-4a89-83bf-f0b4bc119c5e" width="320"> | **Add members, searching "Atlas" (Atlas `85gl` is archived)** | Before | After | | --- | --- | | <img src="https://github.com/user-attachments/assets/55c67a21-4cf5-47c5-b6ac-1ba80d68a3ec" width="320"> | <img src="https://github.com/user-attachments/assets/54b19ab3-fa2f-4933-8b67-1056d6e3b3a4" width="320"> | **New DM, no query yet** | Before | After | | --- | --- | | <img src="https://github.com/user-attachments/assets/6a26fd49-4a06-47bd-ba37-37e5898ab344" width="320"> | <img src="https://github.com/user-attachments/assets/3f33eb2b-f27a-4528-91c0-ac76d3fdf44b" width="320"> | **New DM, searching "Morgan"** | Before | After | | --- | --- | | <img src="https://github.com/user-attachments/assets/22d2d617-3074-4910-8c39-e0778e47a879" width="320"> | <img src="https://github.com/user-attachments/assets/fa00b160-e350-49af-94d0-beb15c357bef" width="320"> | **Search › People, "Morgan"** | Before | After | | --- | --- | | <img src="https://github.com/user-attachments/assets/83a28f2b-9b22-4d0c-8728-8a2dfb10e634" width="320"> | <img src="https://github.com/user-attachments/assets/573aed3f-75ab-478f-8c11-bedab5c6ce4f" width="320"> | **Agents page** | Before | After | | --- | --- | | <img src="https://github.com/user-attachments/assets/d7980f95-825c-4d1a-ad67-95f906a52e9a" width="320"> | <img src="https://github.com/user-attachments/assets/6252c38a-b2ec-48dc-ab4e-824ea29bbd85" width="320"> | **Channel info, members preview** | Before | After | | --- | --- | | <img src="https://github.com/user-attachments/assets/8744cdfd-c073-4ade-bd53-9d5e137cee60" width="320"> | <img src="https://github.com/user-attachments/assets/5240b1be-13d5-4f22-85a9-8375f1d8ac18" width="320"> | **Members sheet, top** | Before | After | | --- | --- | | <img src="https://github.com/user-attachments/assets/c9241478-99b1-452e-ad41-8c38fe080182" width="320"> | <img src="https://github.com/user-attachments/assets/3c6f9247-60c6-47df-94b0-9175f25805bb" width="320"> | **Members sheet, scrolled to the end** | Before | After | | --- | --- | | <img src="https://github.com/user-attachments/assets/7da7fcc8-28ea-4c7a-904e-91ca5a068d23" width="320"> | <img src="https://github.com/user-attachments/assets/024f676e-8150-457d-b7d0-67fa1a680f8d" width="320"> | ## Details - The archive reader (the community's NIP-IA archive list, signed by the relay's NIP-11 `self` key) moves from `shared/me` to `shared/identity_archives`, since it is no longer Solo-only. `hiddenArchivedIdentitiesProvider` is the single rule the surfaces read. - Pulling to refresh on the Agents page also rereads the archive list. Other views reuse the last list, as on desktop; it is also reread on reconnect and when the agent inventory changes. - A refresh keeps the last known list. After a community or account switch, the previous community's list does not apply: nobody is hidden until the new list arrives. - The shared chooser drops archived identities before names are compared, which covers Add members, New DM and mentions. - Search › People asks the relay for 24 people and shows the first 8 that are not archived, so archived matches do not push live people out. - The channel info preview shows the label on one line, so with a long name the role after "Archived" can be cut off. A screen reader still reads it in full. - Not changed: typing a full `@Name` by hand (without the chooser) still resolves against archived channel members too, so an archived namesake can still make a typed name ambiguous. Picking from the chooser is unaffected. Possible follow-up. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Signed-off-by: Logan Johnson <loganj@squareup.com> Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
85 lines
2.8 KiB
Dart
85 lines
2.8 KiB
Dart
import 'package:buzz/features/agents/agent_card.dart';
|
|
import 'package:buzz/features/agents/agents_page.dart';
|
|
import 'package:buzz/shared/identity_archives/identity_archives.dart';
|
|
import 'package:buzz/shared/profile/user_cache_provider.dart';
|
|
import 'package:buzz/shared/profile/user_profile.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|
|
|
import 'agents_harness.dart';
|
|
import '../../helpers/remote_agents_fixture.dart';
|
|
|
|
void main() {
|
|
testWidgets('directory sorts names ignoring case and reorders after rename', (
|
|
tester,
|
|
) async {
|
|
final h = await AgentsHarness.create();
|
|
final existing = existingDesktopKeys.public;
|
|
await h.open(tester, directory: [existing, fakeAgent]);
|
|
final container = ProviderScope.containerOf(
|
|
tester.element(find.byType(AgentsPage)),
|
|
);
|
|
final profiles = container.read(userCacheProvider.notifier);
|
|
profiles.put(UserProfile(pubkey: existing, displayName: 'Zulu'));
|
|
profiles.put(UserProfile(pubkey: fakeAgent, displayName: 'alpha'));
|
|
await tester.pumpAndSettle();
|
|
expect(
|
|
tester
|
|
.widgetList<AgentCard>(find.byType(AgentCard))
|
|
.map((card) => card.name),
|
|
['alpha', 'Zulu'],
|
|
);
|
|
profiles.put(UserProfile(pubkey: existing, displayName: 'aardvark'));
|
|
await tester.pumpAndSettle();
|
|
expect(
|
|
tester
|
|
.widgetList<AgentCard>(find.byType(AgentCard))
|
|
.map((card) => card.name),
|
|
['aardvark', 'alpha'],
|
|
);
|
|
});
|
|
|
|
testWidgets('leaves archived agents out of the directory until restored', (
|
|
tester,
|
|
) async {
|
|
final h = await AgentsHarness.create();
|
|
final existing = existingDesktopKeys.public;
|
|
var archived = {fakeAgent};
|
|
await h.open(
|
|
tester,
|
|
directory: [existing, fakeAgent],
|
|
overrides: [
|
|
identityArchivesProvider.overrideWith((ref) async => archived),
|
|
],
|
|
);
|
|
final container = ProviderScope.containerOf(
|
|
tester.element(find.byType(AgentsPage)),
|
|
);
|
|
final profiles = container.read(userCacheProvider.notifier);
|
|
profiles.put(UserProfile(pubkey: existing, displayName: 'Zulu'));
|
|
profiles.put(UserProfile(pubkey: fakeAgent, displayName: 'alpha'));
|
|
await tester.pumpAndSettle();
|
|
expect(
|
|
tester
|
|
.widgetList<AgentCard>(find.byType(AgentCard))
|
|
.map((card) => card.name),
|
|
['Zulu'],
|
|
);
|
|
// Restored elsewhere: pulling to refresh rereads the archive list.
|
|
archived = {};
|
|
await tester.fling(
|
|
find.byType(CustomScrollView).first,
|
|
const Offset(0, 400),
|
|
1000,
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(
|
|
tester
|
|
.widgetList<AgentCard>(find.byType(AgentCard))
|
|
.map((card) => card.name),
|
|
['alpha', 'Zulu'],
|
|
);
|
|
});
|
|
}
|