diff --git a/example/lib/main.dart b/example/lib/main.dart index a7a4767..2431e0f 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,3 +1,4 @@ +import 'package:example/stage_data/my_list_tile_widget_stage.dart'; import 'package:example/stage_data/my_other_widget_stage.dart'; import 'package:example/stage_data/my_widget_stage.dart'; import 'package:flutter/material.dart'; @@ -20,6 +21,7 @@ class _MyAppState extends State { final widgetsOnStage = [ MyWidgetStageData(), MyOtherWidgetStageData(), + MyListTileWidgetStage(), ]; @override diff --git a/example/lib/stage_data/my_list_tile_widget_stage.dart b/example/lib/stage_data/my_list_tile_widget_stage.dart new file mode 100644 index 0000000..7e3b319 --- /dev/null +++ b/example/lib/stage_data/my_list_tile_widget_stage.dart @@ -0,0 +1,115 @@ +import 'package:flutter/material.dart'; +import 'package:widget_stage/widget_stage.dart'; + +class MyListTileWidgetStage extends WidgetStageData { + MyListTileWidgetStage() + : _tileCount = IntFieldConfigurator(value: 1, name: 'tileCount'), + _listPadding = PaddingFieldConfigurator(value: EdgeInsets.zero, name: 'listPadding'), + _title = StringFieldConfigurator(value: 'My List Tile', name: 'title'), + _stageColor = ColorFieldConfigurator(value: Colors.transparent, name: 'stageColor'), + _circleColor = ColorFieldConfigurator(value: Colors.purple, name: 'circleColor'), + _tileColor = ColorFieldConfiguratorNullable(value: Colors.cyan, name: 'tileColor'), + _textColor = ColorFieldConfiguratorNullable(value: Colors.white, name: 'textColor'), + _borderRadius = DoubleFieldConfiguratorNullable(value: 10, name: 'borderRadius'), + _tileGap = DoubleFieldConfigurator(value: 0, name: 'tileSpace'); + + @override + List get widgetConfigurators { + return [ + _title, + _circleColor, + _tileColor, + _borderRadius, + _textColor, + ]; + } + + @override + List get stageConfigurators { + return [ + _tileCount, + _tileGap, + _listPadding, + _stageColor, + _circleColor, + ]; + } + + @override + String get name => 'MyListTileWidget'; + + final IntFieldConfigurator _tileCount; + final DoubleFieldConfigurator _tileGap; + final DoubleFieldConfiguratorNullable _borderRadius; + final PaddingFieldConfigurator _listPadding; + final StringFieldConfigurator _title; + final ColorFieldConfigurator _stageColor; + final ColorFieldConfigurator _circleColor; + final ColorFieldConfiguratorNullable _textColor; + final ColorFieldConfiguratorNullable _tileColor; + + @override + Widget widgetBuilder(BuildContext context) { + return ColoredBox( + color: _stageColor.value, + child: ListView.separated( + padding: _listPadding.value, + itemCount: _tileCount.value, + separatorBuilder: (_, __) => SizedBox(height: _tileGap.value), + itemBuilder: (context, index) { + return _MyTitleTileWidget( + title: _title.value, + index: index, + circleColor: _circleColor.value, + tileColor: _tileColor.value, + borderRadius: _borderRadius.value, + textColor: _textColor.value, + ); + }, + ), + ); + } +} + +class _MyTitleTileWidget extends StatelessWidget { + const _MyTitleTileWidget({ + required this.index, + required this.title, + required this.circleColor, + this.tileColor, + this.borderRadius, + this.textColor, + }); + + final String title; + final Color circleColor; + final Color? tileColor; + final int index; + final double? borderRadius; + final Color? textColor; + + @override + Widget build(BuildContext context) { + return Material( + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(borderRadius ?? 0), + color: tileColor, + ), + child: ListTile( + title: Text(title), + leading: CircleAvatar( + radius: 15, + backgroundColor: circleColor, + child: Text( + '${index + 1}', + style: TextStyle( + color: textColor, + ), + ), + ), + ), + ), + ); + } +} diff --git a/example/lib/stage_data/my_other_widget_stage.dart b/example/lib/stage_data/my_other_widget_stage.dart index 890ea4f..96db5c6 100644 --- a/example/lib/stage_data/my_other_widget_stage.dart +++ b/example/lib/stage_data/my_other_widget_stage.dart @@ -22,10 +22,13 @@ class MyOtherWidgetStageData extends WidgetStageData { } @override - List get fieldConfigurators { + List get widgetConfigurators { return [ _text, _padding, ]; } + + @override + List get stageConfigurators => []; } diff --git a/example/lib/stage_data/my_widget_stage.dart b/example/lib/stage_data/my_widget_stage.dart index 778e0c4..27aabd5 100644 --- a/example/lib/stage_data/my_widget_stage.dart +++ b/example/lib/stage_data/my_widget_stage.dart @@ -32,7 +32,7 @@ class MyWidgetStageData extends WidgetStageData { } @override - List get fieldConfigurators { + List get widgetConfigurators { return [ _color, _text, @@ -40,4 +40,7 @@ class MyWidgetStageData extends WidgetStageData { _nullableBool, ]; } + + @override + List get stageConfigurators => []; } diff --git a/lib/src/widget_stage.dart b/lib/src/widget_stage.dart index e7a4677..8e8e2f9 100644 --- a/lib/src/widget_stage.dart +++ b/lib/src/widget_stage.dart @@ -29,11 +29,15 @@ class _WidgetStageState extends State { @override Widget build(BuildContext context) { + final stageConfigurators = _stageController.selectedWidget?.stageConfigurators ?? []; + final widgetConfigurators = _stageController.selectedWidget?.widgetConfigurators ?? []; + return Scaffold( body: Column( children: [ Expanded( child: Row( + crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( child: Stage( @@ -48,13 +52,19 @@ class _WidgetStageState extends State { SizedBox( width: 400, child: ConfigurationBar( - fields: _stageController.selectedWidget?.fieldConfigurators.map((configurator) { - return FieldConfiguratorWidget( - fieldConfigurator: configurator, - child: configurator.build(context), - ); - }).toList() ?? - [], + fields: [ + _ConfiguratorGroup( + title: 'Stage Arguments', + configurators: stageConfigurators, + ), + const SizedBox( + height: 20, + ), + _ConfiguratorGroup( + title: 'Widget Arguments', + configurators: widgetConfigurators, + ), + ], ), ), ], @@ -66,6 +76,53 @@ class _WidgetStageState extends State { } } +class _ConfiguratorGroup extends StatelessWidget { + const _ConfiguratorGroup({ + required this.title, + this.configurators, + }); + + final String title; + final List? configurators; + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + padding: const EdgeInsets.only(bottom: 4.0), + decoration: BoxDecoration( + border: Border( + bottom: BorderSide(color: Colors.grey.shade400), + ), + ), + width: double.infinity, + child: Text( + textAlign: TextAlign.center, + title, + style: TextStyle( + color: Colors.grey.shade400, + ), + ), + ), + const SizedBox( + height: 8, + ), + ...?configurators?.map((configurator) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 4), + child: FieldConfiguratorWidget( + fieldConfigurator: configurator, + child: configurator.build(context), + ), + ); + }), + ], + ); + } +} + /// The actual stage to display the widget. class Stage extends StatelessWidget { const Stage({ @@ -146,12 +203,18 @@ class StageController extends ChangeNotifier { WidgetStageData? get selectedWidget => _selectedWidget; void selectWidget(WidgetStageData selectedWidget) { - for (final fieldConfigurator in _selectedWidget?.fieldConfigurators ?? []) { - fieldConfigurator.removeListener(notifyListeners); + for (final widgetConfigurator in _selectedWidget?.widgetConfigurators ?? []) { + widgetConfigurator.removeListener(notifyListeners); + } + for (final stageConfigurator in _selectedWidget?.stageConfigurators ?? []) { + stageConfigurator.removeListener(notifyListeners); } _selectedWidget = selectedWidget; - for (final fieldConfigurator in _selectedWidget?.fieldConfigurators ?? []) { - fieldConfigurator.addListener(notifyListeners); + for (final widgetConfigurator in _selectedWidget?.widgetConfigurators ?? []) { + widgetConfigurator.addListener(notifyListeners); + } + for (final stageConfigurator in _selectedWidget?.stageConfigurators ?? []) { + stageConfigurator.addListener(notifyListeners); } notifyListeners(); } diff --git a/lib/src/widget_stage_data.dart b/lib/src/widget_stage_data.dart index 01b174c..b21556a 100644 --- a/lib/src/widget_stage_data.dart +++ b/lib/src/widget_stage_data.dart @@ -71,7 +71,14 @@ abstract class WidgetStageData { /// Return the widget you want to put on stage and use Widget widgetBuilder(BuildContext context); - List get fieldConfigurators; + /// [FieldConfigurator]s that affect arguments of the widget displayed on the stage, + /// as opposed to [stageConfigurators] which affect its surroundings or the stage itself. + List get widgetConfigurators; + + /// [FieldConfigurator]s that affect the stage itself and/or provide additional configurations + /// surrounding the [Widget] on the stage (e.g. outer [Padding] or a counter, in case the [Widget] is + /// an [Iterable]. + List get stageConfigurators; Size? get stageSize => const Size(600, 800); }