feat(base)!: removing a profile makes it private (ADR 0020, D27)
Some checks failed
CI / check (push) Failing after 30m48s
CI / deploy (push) Has been skipped

Every account keeps a handle now, so removing a public profile no
longer deletes it and frees the handle: it takes away what the profile
shows and leaves it private, as a profile is until its person goes
public (D5).

- `profile.remove` and the register's `removeProfile` (members ask the
  register) empty the display name, bio, links with their checks and
  the avatar, keep the row with its handle, and return what is left,
  null for none. `/@handle` and `profiles.byHandle` then answer as for
  a handle nobody has. Once the person has published, removing is
  refused as before.
- Learn: the profile form starts afresh from what is left, "Remove
  profile" shows only while something is filled in, and the dialog says
  the handle stays.
- The module's README and ADR 0020 amended.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
Tizian 「ティツィアーン」 2026-10-24 18:26:56 +02:00
commit d5651c5beb
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64

View file

@ -212,25 +212,56 @@ void main() {
expect(find.text('Remove profile'), findsNothing);
});
testWidgets('removing a profile asks first, then frees its handle', (
tester,
) async {
testWidgets('removing a profile asks first, then makes it private: the '
'handle stays, what was filled in goes (ADR 0020, D27)', (tester) async {
final profiles = FakeProfileGateway(
profile: const PublicProfile(
handle: 'raisondetredev',
address: 'raisondetredev@halkyon.eu',
displayName: 'Raison',
bio: 'Learning Japanese.',
links: ['https://halkyon.app'],
),
);
await showProfile(tester, profiles);
expect(find.widgetWithText(TextField, 'Raison'), findsOneWidget);
await tester.tap(find.text('Remove profile'));
await tester.pumpAndSettle();
expect(find.text('Remove your public profile?'), findsOneWidget);
expect(find.textContaining('Your handle stays yours'), findsOneWidget);
await tester.tap(find.text('Remove profile').last);
await tester.pumpAndSettle();
expect(find.text('Profile removed.'), findsOneWidget);
expect(profiles.profile, isNull);
expect(profiles.profile?.handle, 'raisondetredev');
expect(profiles.profile?.displayName, '');
expect(find.text('@raisondetredev'), findsOneWidget);
// The form starts afresh from what is left.
expect(find.widgetWithText(TextField, 'Raison'), findsNothing);
expect(find.widgetWithText(TextField, 'Learning Japanese.'), findsNothing);
expect(
find.widgetWithText(TextField, 'https://halkyon.app'),
findsNothing,
);
// Nothing is left to remove.
expect(find.text('Remove profile'), findsNothing);
});
testWidgets('offers no removing while nothing is filled in: the handle '
'alone is private already', (tester) async {
await showProfile(
tester,
FakeProfileGateway(
profile: const PublicProfile(
handle: 'raisondetredev',
address: 'raisondetredev@halkyon.eu',
),
),
);
expect(find.text('@raisondetredev'), findsOneWidget);
expect(find.text('Remove profile'), findsNothing);
});
testWidgets('a saved profile takes a picture as its avatar, and gives it '