feat(settings): Appearance category + custom-control escape hatch (T-452)
Add the one bespoke control the schema engine defers to. New SettingsControlContribution routes a WidgetBuilder into a kernel SettingsControlRegistry under a customId; a SettingsFieldKind.custom field names that id, and the renderer draws the registered widget full-width (label on top, no scope tag — the control owns its own apply + scope). The theme-picker extension uses it: an Appearance category whose theme field is custom, backed by AppearanceThemeControl — base-theme chips + a high-contrast toggle that apply live through ThemeController (persisted by theme_persistence). Reuses the shared theme_families helpers. Tests: control registry (register/dup/unregister), the renderer's custom-field path, and the Appearance contribution + live theme apply. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -187,5 +187,21 @@ void main() {
|
||||
expect(resp.ok, isTrue);
|
||||
expect(resp.data['selected'], 'forest');
|
||||
});
|
||||
|
||||
test('contributes an Appearance category + theme.picker control (T-452)', () {
|
||||
final ext = ThemePickerExtension();
|
||||
final cat = ext.contributions.whereType<SettingsCategoryContribution>().firstWhere((c) => c.id == 'appearance').category;
|
||||
expect(cat.title, 'Appearance');
|
||||
expect(ext.contributions.whereType<SettingsControlContribution>().any((c) => c.customId == 'theme.picker'), isTrue);
|
||||
});
|
||||
|
||||
testWidgets('AppearanceThemeControl lists base themes and applies a pick (T-452)', (tester) async {
|
||||
await tester.pumpWidget(harness(f, const SizedBox(width: 420, child: AppearanceThemeControl())));
|
||||
expect(find.text('summer-night'), findsOneWidget);
|
||||
expect(find.text('forest'), findsOneWidget);
|
||||
await tester.tap(find.text('forest'));
|
||||
await tester.pump();
|
||||
expect(f.services.theme.currentName, 'forest');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user