diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index cb4587a..10b9d8e 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -317,6 +317,9 @@ "storeStatusAll": "Alle", "storeStatusPublished": "stabil", "storeStatusAlpha": "experimentell", + "storeStatusAlphaHelp": "Frühe Version: läuft, wird aber noch weiterentwickelt und ist nicht für den regulierten Produktivbetrieb freigegeben.", + "storeStatusPublishedHelp": "Vom Herausgeber für den allgemeinen Einsatz freigegeben.", + "storeStatusPlannedHelp": "Angekündigt, aber noch nicht verfügbar.", "storeStatusPlanned": "geplant", "storeInstalledOnly": "Installiert", "storeCategoryLabel": "Kategorie", @@ -555,7 +558,7 @@ "auditTitle": "Protokoll", "auditNoEvents": "Noch keine Ereignisse", "auditNoEventsHint": "Starten Sie einen Flow, um den Audit-Stream zu füllen.\nEreignisse erscheinen innerhalb von Sekunden.", - "auditFilterAll": "alle", + "auditFilterAll": "Alle", "auditFilterFlow": "Flow", "auditFilterStep": "Schritt", "auditFilterModule": "Modul", @@ -1778,7 +1781,7 @@ "setupReviewTitle": "Das wird Ch∆In einrichten", "setupChooseFreeText": "Oder beschreiben Sie einfach, was Sie vorhaben", "setupScenTryingOut": "Erst mal ausprobieren", - "setupScenTryingOutSub": "Ein unkomplizierter Arbeitsplatz auf diesem Rechner — ohne Signaturpflicht, ohne Schreibschutz für das Prüfprotokoll.", + "setupScenTryingOutSub": "Ein unkomplizierter Arbeitsplatz auf diesem Rechner — ohne Signaturpflicht, ohne Schreibschutz für das Prüfprotokoll. Später jederzeit hochstufbar: die Einrichtung erneut ausführen und ein reguliertes Profil wählen.", "setupScenTeamHub": "Ein Team-Server", "setupScenTeamHubSub": "Ein abgesicherter Hub für mehrere Personen — signierte Module, Ressourcen-Grenzen.", "setupScenRegulated": "Regulierter Produktivbetrieb", diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 9cd599b..094fb77 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -325,6 +325,9 @@ "storeStatusAll": "All", "storeStatusPublished": "stable", "storeStatusAlpha": "experimental", + "storeStatusAlphaHelp": "Early version: it works, but it is still evolving and not cleared for regulated production use.", + "storeStatusPublishedHelp": "Cleared by the publisher for general use.", + "storeStatusPlannedHelp": "Announced, but not available yet.", "storeStatusPlanned": "coming soon", "storeInstalledOnly": "Installed", "storeCategoryLabel": "Category", @@ -573,7 +576,7 @@ "auditTitle": "Audit", "auditNoEvents": "No events yet", "auditNoEventsHint": "Run a flow to populate the audit stream.\nEvents appear here within seconds.", - "auditFilterAll": "all", + "auditFilterAll": "All", "auditFilterFlow": "flow", "auditFilterStep": "step", "auditFilterModule": "module", @@ -1817,7 +1820,7 @@ "setupReviewTitle": "This is what Ch∆In will set up", "setupChooseFreeText": "Or just describe what you want to do", "setupScenTryingOut": "Just trying it out", - "setupScenTryingOutSub": "A straightforward workstation on this machine — no signature requirement, no write-protected audit log.", + "setupScenTryingOutSub": "A straightforward workstation on this machine — no signature requirement, no write-protected audit log. You can upgrade any time: run the setup again and pick a regulated profile.", "setupScenTeamHub": "A shared team hub", "setupScenTeamHubSub": "A secured hub for several people — signed modules, resource limits.", "setupScenRegulated": "Regulated production", diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart index 8e25421..e3779dc 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -1466,6 +1466,24 @@ abstract class AppLocalizations { /// **'experimental'** String get storeStatusAlpha; + /// No description provided for @storeStatusAlphaHelp. + /// + /// In en, this message translates to: + /// **'Early version: it works, but it is still evolving and not cleared for regulated production use.'** + String get storeStatusAlphaHelp; + + /// No description provided for @storeStatusPublishedHelp. + /// + /// In en, this message translates to: + /// **'Cleared by the publisher for general use.'** + String get storeStatusPublishedHelp; + + /// No description provided for @storeStatusPlannedHelp. + /// + /// In en, this message translates to: + /// **'Announced, but not available yet.'** + String get storeStatusPlannedHelp; + /// No description provided for @storeStatusPlanned. /// /// In en, this message translates to: @@ -2093,7 +2111,7 @@ abstract class AppLocalizations { /// No description provided for @auditFilterAll. /// /// In en, this message translates to: - /// **'all'** + /// **'All'** String get auditFilterAll; /// No description provided for @auditFilterFlow. @@ -5470,7 +5488,7 @@ abstract class AppLocalizations { /// No description provided for @setupScenTryingOutSub. /// /// In en, this message translates to: - /// **'A straightforward workstation on this machine — no signature requirement, no write-protected audit log.'** + /// **'A straightforward workstation on this machine — no signature requirement, no write-protected audit log. You can upgrade any time: run the setup again and pick a regulated profile.'** String get setupScenTryingOutSub; /// No description provided for @setupScenTeamHub. diff --git a/lib/l10n/app_localizations_de.dart b/lib/l10n/app_localizations_de.dart index 1933b5b..c3a4a7a 100644 --- a/lib/l10n/app_localizations_de.dart +++ b/lib/l10n/app_localizations_de.dart @@ -793,6 +793,18 @@ class AppLocalizationsDe extends AppLocalizations { @override String get storeStatusAlpha => 'experimentell'; + @override + String get storeStatusAlphaHelp => + 'Frühe Version: läuft, wird aber noch weiterentwickelt und ist nicht für den regulierten Produktivbetrieb freigegeben.'; + + @override + String get storeStatusPublishedHelp => + 'Vom Herausgeber für den allgemeinen Einsatz freigegeben.'; + + @override + String get storeStatusPlannedHelp => + 'Angekündigt, aber noch nicht verfügbar.'; + @override String get storeStatusPlanned => 'geplant'; @@ -1164,7 +1176,7 @@ class AppLocalizationsDe extends AppLocalizations { 'Starten Sie einen Flow, um den Audit-Stream zu füllen.\nEreignisse erscheinen innerhalb von Sekunden.'; @override - String get auditFilterAll => 'alle'; + String get auditFilterAll => 'Alle'; @override String get auditFilterFlow => 'Flow'; @@ -3237,7 +3249,7 @@ class AppLocalizationsDe extends AppLocalizations { @override String get setupScenTryingOutSub => - 'Ein unkomplizierter Arbeitsplatz auf diesem Rechner — ohne Signaturpflicht, ohne Schreibschutz für das Prüfprotokoll.'; + 'Ein unkomplizierter Arbeitsplatz auf diesem Rechner — ohne Signaturpflicht, ohne Schreibschutz für das Prüfprotokoll. Später jederzeit hochstufbar: die Einrichtung erneut ausführen und ein reguliertes Profil wählen.'; @override String get setupScenTeamHub => 'Ein Team-Server'; diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart index 781d566..b5e55b8 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -806,6 +806,17 @@ class AppLocalizationsEn extends AppLocalizations { @override String get storeStatusAlpha => 'experimental'; + @override + String get storeStatusAlphaHelp => + 'Early version: it works, but it is still evolving and not cleared for regulated production use.'; + + @override + String get storeStatusPublishedHelp => + 'Cleared by the publisher for general use.'; + + @override + String get storeStatusPlannedHelp => 'Announced, but not available yet.'; + @override String get storeStatusPlanned => 'coming soon'; @@ -1181,7 +1192,7 @@ class AppLocalizationsEn extends AppLocalizations { 'Run a flow to populate the audit stream.\nEvents appear here within seconds.'; @override - String get auditFilterAll => 'all'; + String get auditFilterAll => 'All'; @override String get auditFilterFlow => 'flow'; @@ -3237,7 +3248,7 @@ class AppLocalizationsEn extends AppLocalizations { @override String get setupScenTryingOutSub => - 'A straightforward workstation on this machine — no signature requirement, no write-protected audit log.'; + 'A straightforward workstation on this machine — no signature requirement, no write-protected audit log. You can upgrade any time: run the setup again and pick a regulated profile.'; @override String get setupScenTeamHub => 'A shared team hub'; diff --git a/lib/pages/store.dart b/lib/pages/store.dart index 6218953..d54374f 100644 --- a/lib/pages/store.dart +++ b/lib/pages/store.dart @@ -897,6 +897,25 @@ String _statusDisplayName(BuildContext ctx, String wire) { } } +/// Maturity pill with an inline explanation on hover — "experimental" +/// alone left buyers guessing what it means for production use +/// (usertest finding). Unknown wire values get a plain pill. +Widget _statusPill(BuildContext ctx, String wire) { + final l = AppLocalizations.of(ctx)!; + final pill = ChainPill( + label: _statusDisplayName(ctx, wire), + tone: _toneForStatus(wire), + ); + final help = switch (wire) { + 'published' => l.storeStatusPublishedHelp, + 'alpha' => l.storeStatusAlphaHelp, + 'planned' => l.storeStatusPlannedHelp, + _ => null, + }; + if (help == null) return pill; + return Tooltip(message: help, child: pill); +} + /// Multi-line ask-and-search input. Drives the toolbar's /// primary action: substring keyword search on every keystroke /// (cheap, identical to the legacy `_SearchField`) plus an @@ -1925,10 +1944,7 @@ class _FeaturedTile extends StatelessWidget { ), const SizedBox(width: ChainSpace.xs), if (item.status.isNotEmpty) - ChainPill( - label: _statusDisplayName(context, item.status), - tone: _toneForStatus(item.status), - ), + _statusPill(context, item.status), const Spacer(), if (item.installed) ChainPill( @@ -2114,10 +2130,7 @@ class _StoreCardState extends State<_StoreCard> { icon: Icons.check, ) else if (item.status.isNotEmpty) - ChainPill( - label: _statusDisplayName(context, item.status), - tone: _toneForStatus(item.status), - ), + _statusPill(context, item.status), ], ), const SizedBox(height: ChainSpace.sm), @@ -2490,13 +2503,7 @@ class _StoreDetailSheetState extends State<_StoreDetailSheet> { ), ), if (item.status.isNotEmpty) - ChainPill( - label: _statusDisplayName( - context, - item.status, - ), - tone: _toneForStatus(item.status), - ), + _statusPill(context, item.status), if (item.category.isNotEmpty) ChainPill( label: _categoryDisplayName( diff --git a/lib/widgets/chain_settings_dialog.dart b/lib/widgets/chain_settings_dialog.dart index 7fdf1d5..5ee7fd2 100644 --- a/lib/widgets/chain_settings_dialog.dart +++ b/lib/widgets/chain_settings_dialog.dart @@ -604,7 +604,16 @@ class _FaiSettingsDialogState extends State { Align( alignment: Alignment.centerLeft, child: OutlinedButton.icon( - onPressed: () => GuidedSetupDialog.show(context), + onPressed: () { + // One modal layer at a time: close Settings first so the + // wizard doesn't float over a half-visible dialog with + // stray text fragments around it (usertest finding). + final nav = Navigator.of(context); + nav.pop(false); + WidgetsBinding.instance.addPostFrameCallback((_) { + if (nav.context.mounted) GuidedSetupDialog.show(nav.context); + }); + }, icon: const Icon(Icons.auto_fix_high, size: 18), label: Text(l.settingsRunSetup), ), diff --git a/lib/widgets/guided_setup_dialog.dart b/lib/widgets/guided_setup_dialog.dart index 227132c..b943060 100644 --- a/lib/widgets/guided_setup_dialog.dart +++ b/lib/widgets/guided_setup_dialog.dart @@ -144,6 +144,10 @@ class GuidedSetupDialog extends StatefulWidget { return showDialog( context: context, barrierDismissible: false, + // Stronger than the default scrim: the wizard is a focused, + // multi-step flow — whatever lies beneath must read as + // background, not as competing UI. + barrierColor: Colors.black.withValues(alpha: 0.72), builder: (_) => GuidedSetupDialog(shell: shell), ); }