chore(studio): RadioGroup migration + second integration test
Two clean-ups: - `fai_system_ai_editor.dart` uses the new `RadioGroup<T>` ancestor pattern Material 3 introduced after Flutter 3.32. Same UX (three radios for off/redacted/full), no deprecation warnings, `flutter analyze` is now zero-issue for the whole project. - New `install_install_planned_test.dart` asserts that installing a `planned` seed entry surfaces a clear, human-readable error class (no panic, no silent success). Locks in the failed-precondition path Studio's friendly-error mapper depends on. Integration test suite is now 3 scenarios: - capabilities_test.dart: system.approval+kind tag - install_install_planned_test.dart: planned-install error All run against a fresh `fai serve` subprocess via HubFixture, ~2 s total. Signed-off-by: flemming-it <sf@flemming.it> Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
This commit is contained in:
parent
69b54629d3
commit
21c2a0f411
2 changed files with 94 additions and 45 deletions
|
|
@ -553,53 +553,60 @@ class _PrivacyModeChips extends StatelessWidget {
|
|||
l.systemAiPrivacyFullDesc,
|
||||
),
|
||||
];
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
l.systemAiPrivacyHeader,
|
||||
style: theme.textTheme.labelSmall?.copyWith(
|
||||
color: theme.colorScheme.onSurfaceVariant,
|
||||
letterSpacing: 0.6,
|
||||
fontSize: 10,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
for (final (wire, label, desc) in modes)
|
||||
InkWell(
|
||||
onTap: () => onChanged(wire),
|
||||
borderRadius: BorderRadius.circular(FaiRadius.sm),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: FaiSpace.sm,
|
||||
horizontal: FaiSpace.sm,
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Radio<String>(
|
||||
value: wire,
|
||||
groupValue: value,
|
||||
onChanged: (v) => onChanged(v ?? wire),
|
||||
),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(label, style: theme.textTheme.bodyMedium),
|
||||
Text(
|
||||
desc,
|
||||
style: theme.textTheme.bodySmall?.copyWith(
|
||||
color: theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
// Material 3 deprecated per-Radio `groupValue` / `onChanged`
|
||||
// after Flutter 3.32. The modern pattern wraps the radios in
|
||||
// a RadioGroup<T> ancestor that owns the selection + change
|
||||
// callback; the individual Radio widgets only declare their
|
||||
// value. Same UX, no deprecation warnings.
|
||||
return RadioGroup<String>(
|
||||
groupValue: value,
|
||||
onChanged: (v) {
|
||||
if (v != null) onChanged(v);
|
||||
},
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
l.systemAiPrivacyHeader,
|
||||
style: theme.textTheme.labelSmall?.copyWith(
|
||||
color: theme.colorScheme.onSurfaceVariant,
|
||||
letterSpacing: 0.6,
|
||||
fontSize: 10,
|
||||
),
|
||||
),
|
||||
],
|
||||
const SizedBox(height: 4),
|
||||
for (final (wire, label, desc) in modes)
|
||||
InkWell(
|
||||
onTap: () => onChanged(wire),
|
||||
borderRadius: BorderRadius.circular(FaiRadius.sm),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: FaiSpace.sm,
|
||||
horizontal: FaiSpace.sm,
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Radio<String>(value: wire),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(label, style: theme.textTheme.bodyMedium),
|
||||
Text(
|
||||
desc,
|
||||
style: theme.textTheme.bodySmall?.copyWith(
|
||||
color: theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue