fix(profile): the handle's hint says it is private until the profile is public (ADR 0020, D5)
All checks were successful
CI / check (push) Successful in 29m38s
CI / deploy (push) Successful in 2m3s

A handle alone is private: its page and `profiles.byHandle` answer as
for a handle nobody has until its person fills in their profile or
publishes something. The hint under it said "Others find you as @…"
all the same, also after removing a profile (D27). It now says it is
private until then, by the rule the instance's `isPublic` applies.

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-25 00:21:35 +02:00
commit 885ba79210
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64
7 changed files with 44 additions and 6 deletions

View file

@ -485,6 +485,8 @@
"publicProfileHandleHint": "Buchstaben, Ziffern und Unterstriche, bis zu 30", "publicProfileHandleHint": "Buchstaben, Ziffern und Unterstriche, bis zu 30",
"publicProfileAddress": "Andere finden dich als @{address}", "publicProfileAddress": "Andere finden dich als @{address}",
"@publicProfileAddress": {"placeholders": {"address": {"type": "String"}}}, "@publicProfileAddress": {"placeholders": {"address": {"type": "String"}}},
"publicProfileAddressPrivate": "Privat, bis du dein Profil ausfüllst oder etwas veröffentlichst; dann finden dich andere als @{address}.",
"@publicProfileAddressPrivate": {"placeholders": {"address": {"type": "String"}}},
"publicProfileHandleFixed": "Fest, seit du veröffentlicht hast: Andere verweisen darauf.", "publicProfileHandleFixed": "Fest, seit du veröffentlicht hast: Andere verweisen darauf.",
"publicProfileBio": "Über dich", "publicProfileBio": "Über dich",
"publicProfileLinks": "Links", "publicProfileLinks": "Links",

View file

@ -550,6 +550,8 @@
"publicProfileHandleHint": "Letters, digits and underscores, up to 30", "publicProfileHandleHint": "Letters, digits and underscores, up to 30",
"publicProfileAddress": "Others find you as @{address}", "publicProfileAddress": "Others find you as @{address}",
"@publicProfileAddress": {"placeholders": {"address": {"type": "String"}}}, "@publicProfileAddress": {"placeholders": {"address": {"type": "String"}}},
"publicProfileAddressPrivate": "Private until you fill in your profile or publish something; then others find you as @{address}.",
"@publicProfileAddressPrivate": {"placeholders": {"address": {"type": "String"}}},
"publicProfileHandleFixed": "Fixed since you published: others refer to it.", "publicProfileHandleFixed": "Fixed since you published: others refer to it.",
"publicProfileBio": "Bio", "publicProfileBio": "Bio",
"publicProfileLinks": "Links", "publicProfileLinks": "Links",

View file

@ -2914,6 +2914,12 @@ abstract class AppLocalizations {
/// **'Others find you as @{address}'** /// **'Others find you as @{address}'**
String publicProfileAddress(String address); String publicProfileAddress(String address);
/// No description provided for @publicProfileAddressPrivate.
///
/// In en, this message translates to:
/// **'Private until you fill in your profile or publish something; then others find you as @{address}.'**
String publicProfileAddressPrivate(String address);
/// No description provided for @publicProfileHandleFixed. /// No description provided for @publicProfileHandleFixed.
/// ///
/// In en, this message translates to: /// In en, this message translates to:

View file

@ -1766,6 +1766,11 @@ class AppLocalizationsDe extends AppLocalizations {
return 'Andere finden dich als @$address'; return 'Andere finden dich als @$address';
} }
@override
String publicProfileAddressPrivate(String address) {
return 'Privat, bis du dein Profil ausfüllst oder etwas veröffentlichst; dann finden dich andere als @$address.';
}
@override @override
String get publicProfileHandleFixed => String get publicProfileHandleFixed =>
'Fest, seit du veröffentlicht hast: Andere verweisen darauf.'; 'Fest, seit du veröffentlicht hast: Andere verweisen darauf.';

View file

@ -1750,6 +1750,11 @@ class AppLocalizationsEn extends AppLocalizations {
return 'Others find you as @$address'; return 'Others find you as @$address';
} }
@override
String publicProfileAddressPrivate(String address) {
return 'Private until you fill in your profile or publish something; then others find you as @$address.';
}
@override @override
String get publicProfileHandleFixed => String get publicProfileHandleFixed =>
'Fixed since you published: others refer to it.'; 'Fixed since you published: others refer to it.';

View file

@ -342,6 +342,10 @@ class _ProfileFormState() extends State<_ProfileForm> {
onTap: fixed ? null : _chooseHandle, onTap: fixed ? null : _chooseHandle,
helperText: switch (profile) { helperText: switch (profile) {
PublicProfile(handleFixed: true) => l10n.publicProfileHandleFixed, PublicProfile(handleFixed: true) => l10n.publicProfileHandleFixed,
// Its handle alone is private (ADR 0020, D5), as the instance's
// `isPublic` has it: nothing published, nothing filled in.
final profile? when !_showsSomething(profile) =>
l10n.publicProfileAddressPrivate(profile.address),
final profile? => l10n.publicProfileAddress(profile.address), final profile? => l10n.publicProfileAddress(profile.address),
null => l10n.publicProfileHandleFirst, null => l10n.publicProfileHandleFirst,
}, },

View file

@ -16,6 +16,12 @@ import '../../support/fake_profile_gateway.dart';
import '../../support/pump_app.dart'; import '../../support/pump_app.dart';
import '../../support/test_dependencies.dart'; import '../../support/test_dependencies.dart';
/// The handle's hint while the profile is public, and while it is not.
const publicHint = 'Others find you as @raisondetredev@halkyon.eu';
const privateHint =
'Private until you fill in your profile or publish something; then '
'others find you as @raisondetredev@halkyon.eu.';
void main() { void main() {
/// Opens the Profile tab of a person whose profile the instance answers /// Opens the Profile tab of a person whose profile the instance answers
/// through [profiles]. /// through [profiles].
@ -92,10 +98,7 @@ void main() {
await tester.tap(find.widgetWithText(FilledButton, 'Choose')); await tester.tap(find.widgetWithText(FilledButton, 'Choose'));
await tester.pumpAndSettle(); await tester.pumpAndSettle();
expect( expect(find.text(publicHint), findsOneWidget);
find.text('Others find you as @raisondetredev@halkyon.eu'),
findsOneWidget,
);
expect(find.text('@raisondetredev'), findsOneWidget); expect(find.text('@raisondetredev'), findsOneWidget);
expect(profiles.profile!.displayName, 'Tizian'); expect(profiles.profile!.displayName, 'Tizian');
expect(profiles.profile!.bio, 'Learning Japanese.'); expect(profiles.profile!.bio, 'Learning Japanese.');
@ -244,12 +247,14 @@ void main() {
find.widgetWithText(TextField, 'https://halkyon.app'), find.widgetWithText(TextField, 'https://halkyon.app'),
findsNothing, findsNothing,
); );
// Nothing is left to remove. // Nothing is left to remove, and the handle is private again.
expect(find.text('Remove profile'), findsNothing); expect(find.text('Remove profile'), findsNothing);
expect(find.text(privateHint), findsOneWidget);
}); });
testWidgets('offers no removing while nothing is filled in: the handle ' testWidgets('offers no removing while nothing is filled in: the handle '
'alone is private already', (tester) async { 'alone is private already, as its hint says (ADR 0020, D5), until '
'something is filled in', (tester) async {
await showProfile( await showProfile(
tester, tester,
FakeProfileGateway( FakeProfileGateway(
@ -262,6 +267,15 @@ void main() {
expect(find.text('@raisondetredev'), findsOneWidget); expect(find.text('@raisondetredev'), findsOneWidget);
expect(find.text('Remove profile'), findsNothing); expect(find.text('Remove profile'), findsNothing);
expect(find.text(privateHint), findsOneWidget);
expect(find.text(publicHint), findsNothing);
await tester.enterText(field('Display name'), 'Tizian');
await tester.testTextInput.receiveAction(TextInputAction.done);
await tester.pumpAndSettle();
expect(find.text(publicHint), findsOneWidget);
expect(find.text(privateHint), findsNothing);
}); });
testWidgets('a saved profile takes a picture as its avatar, and gives it ' testWidgets('a saved profile takes a picture as its avatar, and gives it '