From 7ae15f61ddb1b5f6676f43b92f5ee1d40609176d Mon Sep 17 00:00:00 2001 From: Erick Zanardo Date: Fri, 9 Aug 2024 20:20:50 -0300 Subject: [PATCH 1/4] feat: Adding position component attributes to devtools --- .../connectors/component_tree_connector.dart | 13 +++- ...sition_attributes_component_connector.dart | 69 ++++++++++++++++ .../lib/src/devtools/dev_tools_connector.dart | 20 +++++ .../lib/src/devtools/dev_tools_service.dart | 2 + packages/flame_devtools/lib/repository.dart | 52 +++++++++++++ .../lib/widgets/component_tree.dart | 8 ++ .../incremental_number_form_field.dart | 78 +++++++++++++++++++ .../position_component_attributes_form.dart | 74 ++++++++++++++++++ 8 files changed, 315 insertions(+), 1 deletion(-) create mode 100644 packages/flame/lib/src/devtools/connectors/position_attributes_component_connector.dart create mode 100644 packages/flame_devtools/lib/widgets/incremental_number_form_field.dart create mode 100644 packages/flame_devtools/lib/widgets/position_component_attributes_form.dart diff --git a/packages/flame/lib/src/devtools/connectors/component_tree_connector.dart b/packages/flame/lib/src/devtools/connectors/component_tree_connector.dart index 0e1ea1abb6a..4bcc9f03f6b 100644 --- a/packages/flame/lib/src/devtools/connectors/component_tree_connector.dart +++ b/packages/flame/lib/src/devtools/connectors/component_tree_connector.dart @@ -30,15 +30,24 @@ class ComponentTreeNode { final int id; final String name; final String toStringText; + final bool isPositionComponent; final List children; - ComponentTreeNode(this.id, this.name, this.toStringText, this.children); + ComponentTreeNode( + this.id, + this.name, + this.toStringText, + // ignore: avoid_positional_boolean_parameters + this.isPositionComponent, + this.children, + ); ComponentTreeNode.fromComponent(Component component) : this( component.hashCode, component.runtimeType.toString(), component.toString(), + component is PositionComponent, component.children.map(ComponentTreeNode.fromComponent).toList(), ); @@ -47,6 +56,7 @@ class ComponentTreeNode { json['id'] as int, json['name'] as String, json['toString'] as String, + json['isPositionComponent'] as bool, (json['children'] as List) .map((e) => ComponentTreeNode.fromJson(e as Map)) .toList(), @@ -57,6 +67,7 @@ class ComponentTreeNode { 'id': id, 'name': name, 'toString': toStringText, + 'isPositionComponent': isPositionComponent, 'children': children.map((e) => e.toJson()).toList(), }; } diff --git a/packages/flame/lib/src/devtools/connectors/position_attributes_component_connector.dart b/packages/flame/lib/src/devtools/connectors/position_attributes_component_connector.dart new file mode 100644 index 00000000000..f5f15615cdd --- /dev/null +++ b/packages/flame/lib/src/devtools/connectors/position_attributes_component_connector.dart @@ -0,0 +1,69 @@ +import 'dart:convert'; +import 'dart:developer'; + +import 'package:flame/components.dart'; +import 'package:flame/src/devtools/dev_tools_connector.dart'; + +class PositionAttributesComponentConnector extends DevToolsConnector { + @override + void init() { + registerExtension( + 'ext.flame_devtools.getPositionComponentAttributes', + (method, parameters) async { + final id = int.tryParse(parameters['id'] ?? ''); + + final positionComponent = findGameComponent(id); + + if (positionComponent != null) { + return ServiceExtensionResponse.result( + json.encode({ + 'id': id, + 'x': positionComponent.x, + 'y': positionComponent.y, + 'width': positionComponent.width, + 'height': positionComponent.height, + }), + ); + } else { + return ServiceExtensionResponse.error( + ServiceExtensionResponse.extensionError, + 'No PositionComponent found with id: $id', + ); + } + }, + ); + + registerExtension( + 'ext.flame_devtools.setPositionComponentAttributes', + (method, parameters) async { + final id = int.tryParse(parameters['id'] ?? ''); + final attribute = parameters['attribute']; + + final positionComponent = findGameComponent(id); + + if (positionComponent != null) { + if (attribute == 'x') { + positionComponent.x = double.parse(parameters['value']!); + } else if (attribute == 'y') { + positionComponent.y = double.parse(parameters['value']!); + } else if (attribute == 'width') { + positionComponent.width = double.parse(parameters['value']!); + } else if (attribute == 'height') { + positionComponent.height = double.parse(parameters['value']!); + } else { + return ServiceExtensionResponse.error( + ServiceExtensionResponse.extensionError, + 'Invalid attribute: $attribute', + ); + } + return ServiceExtensionResponse.result('Success'); + } else { + return ServiceExtensionResponse.error( + ServiceExtensionResponse.extensionError, + 'No PositionComponent found with id: $id', + ); + } + }, + ); + } +} diff --git a/packages/flame/lib/src/devtools/dev_tools_connector.dart b/packages/flame/lib/src/devtools/dev_tools_connector.dart index d2ca9659488..0dfe51c42d1 100644 --- a/packages/flame/lib/src/devtools/dev_tools_connector.dart +++ b/packages/flame/lib/src/devtools/dev_tools_connector.dart @@ -1,5 +1,6 @@ import 'dart:developer'; +import 'package:flame/components.dart'; import 'package:flame/debug.dart'; import 'package:flame/game.dart'; import 'package:flutter/foundation.dart'; @@ -29,4 +30,23 @@ abstract class DevToolsConnector { /// Here you can do clean-up before a new game is set in the connector. void disposeGame() {} + + /// Finds a component in the game tree by its id. + /// + /// Returns the component if found, otherwise null. + T? findGameComponent(int? id) { + T? component; + game.propagateToChildren( + (c) { + if (c.hashCode == id) { + component = c; + return false; + } + return true; + }, + includeSelf: true, + ); + + return component; + } } diff --git a/packages/flame/lib/src/devtools/dev_tools_service.dart b/packages/flame/lib/src/devtools/dev_tools_service.dart index b73250a16e7..786c3a2d2ba 100644 --- a/packages/flame/lib/src/devtools/dev_tools_service.dart +++ b/packages/flame/lib/src/devtools/dev_tools_service.dart @@ -4,6 +4,7 @@ import 'package:flame/src/devtools/connectors/component_snapshot_connector.dart' import 'package:flame/src/devtools/connectors/component_tree_connector.dart'; import 'package:flame/src/devtools/connectors/debug_mode_connector.dart'; import 'package:flame/src/devtools/connectors/game_loop_connector.dart'; +import 'package:flame/src/devtools/connectors/position_attributes_component_connector.dart'; import 'package:flame/src/devtools/dev_tools_connector.dart'; /// When [DevToolsService] is initialized by the [FlameGame] it will call @@ -37,6 +38,7 @@ class DevToolsService { ComponentTreeConnector(), GameLoopConnector(), ComponentSnapshotConnector(), + PositionAttributesComponentConnector(), ]; /// This method is called every time a new game is set in the service and it diff --git a/packages/flame_devtools/lib/repository.dart b/packages/flame_devtools/lib/repository.dart index 8bb08c98edd..635b4509b48 100644 --- a/packages/flame_devtools/lib/repository.dart +++ b/packages/flame_devtools/lib/repository.dart @@ -76,4 +76,56 @@ sealed class Repository { ); return snapshotResponse.json!['snapshot'] as String?; } + + static Future getPositionComponentAttributes({ + int? id, + }) async { + final potentialPositionComponentResponse = + await serviceManager.callServiceExtensionOnMainIsolate( + 'ext.flame_devtools.getPositionComponentAttributes', + args: {'id': id}, + ); + + return PositionComponentAttributes.fromJson( + potentialPositionComponentResponse.json!, + ); + } + + static Future setPositionComponentAttribute({ + required String attribute, + required dynamic value, + int? id, + }) async { + await serviceManager.callServiceExtensionOnMainIsolate( + 'ext.flame_devtools.setPositionComponentAttributes', + args: { + 'id': id, + 'attribute': attribute, + 'value': value, + }, + ); + } +} + +class PositionComponentAttributes { + final double x; + final double y; + final double width; + final double height; + + PositionComponentAttributes({ + required this.x, + required this.y, + required this.width, + required this.height, + }); + + factory PositionComponentAttributes.fromJson(Map json) { + return PositionComponentAttributes( + x: json['x'] as double, + y: json['y'] as double, + width: json['width'] as double, + height: json['height'] as double, + ); + } } diff --git a/packages/flame_devtools/lib/widgets/component_tree.dart b/packages/flame_devtools/lib/widgets/component_tree.dart index 687511422e1..0e1fb7abee3 100644 --- a/packages/flame_devtools/lib/widgets/component_tree.dart +++ b/packages/flame_devtools/lib/widgets/component_tree.dart @@ -3,6 +3,7 @@ import 'package:devtools_app_shared/ui.dart' as devtools_ui; import 'package:flame_devtools/widgets/component_snapshot.dart'; import 'package:flame_devtools/widgets/component_tree_model.dart'; import 'package:flame_devtools/widgets/debug_mode_button.dart'; +import 'package:flame_devtools/widgets/position_component_attributes_form.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; @@ -152,6 +153,13 @@ class ComponentSection extends ConsumerWidget { 'Children: ${node.children.length}', style: textStyle, ), + if (node.isPositionComponent) + Padding( + padding: const EdgeInsets.symmetric(vertical: 8), + child: PositionComponentAttributesForm( + componentId: node.id, + ), + ), Text( 'toString:\n${node.toStringText}', style: textStyle, diff --git a/packages/flame_devtools/lib/widgets/incremental_number_form_field.dart b/packages/flame_devtools/lib/widgets/incremental_number_form_field.dart new file mode 100644 index 00000000000..3cf30c9a1fd --- /dev/null +++ b/packages/flame_devtools/lib/widgets/incremental_number_form_field.dart @@ -0,0 +1,78 @@ +import 'package:flutter/material.dart'; + +class IncrementalNumberFormField extends StatefulWidget { + const IncrementalNumberFormField({ + required this.initialValue, + required this.label, + this.onChanged, + super.key, + }); + + final String label; + final T initialValue; + final void Function(T)? onChanged; + + @override + State> createState() => + _IncrementalNumberFormFieldState(); +} + +class _IncrementalNumberFormFieldState + extends State> { + late final _controller = TextEditingController() + ..text = widget.initialValue.toString(); + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + T _parse() { + if (T is double) { + return double.parse(_controller.text) as T; + } else { + return int.parse(_controller.text) as T; + } + } + + void _update(T v) { + widget.onChanged?.call(v); + setState(() { + _controller.text = v.toString(); + }); + } + + @override + Widget build(BuildContext context) { + return Row( + children: [ + IconButton( + onPressed: () { + _update(_parse() - 1 as T); + }, + icon: const Icon(Icons.remove), + ), + const SizedBox(width: 8), + SizedBox( + width: 100, + child: TextField( + decoration: InputDecoration( + labelText: widget.label, + ), + controller: _controller, + // TODO(erickzanardo): Implement this + // onChanged: (v) => _update(v as T), + ), + ), + const SizedBox(width: 8), + IconButton( + onPressed: () { + _update(_parse() + 1 as T); + }, + icon: const Icon(Icons.add), + ), + ], + ); + } +} diff --git a/packages/flame_devtools/lib/widgets/position_component_attributes_form.dart b/packages/flame_devtools/lib/widgets/position_component_attributes_form.dart new file mode 100644 index 00000000000..325af45b0bc --- /dev/null +++ b/packages/flame_devtools/lib/widgets/position_component_attributes_form.dart @@ -0,0 +1,74 @@ +import 'package:flame_devtools/repository.dart'; +import 'package:flame_devtools/widgets/incremental_number_form_field.dart'; +import 'package:flutter/material.dart'; + +class PositionComponentAttributesForm extends StatefulWidget { + const PositionComponentAttributesForm({ + required this.componentId, + super.key, + }); + + final int componentId; + + @override + State createState() => + _PositionComponentAttributesFormState(); +} + +class _PositionComponentAttributesFormState + extends State { + late Future _attributesFuture; + + @override + void initState() { + super.initState(); + + _attributesFuture = Repository.getPositionComponentAttributes( + id: widget.componentId, + ); + } + + @override + Widget build(BuildContext context) { + return FutureBuilder( + future: _attributesFuture, + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.done && + snapshot.hasData) { + final data = snapshot.data!; + return Column( + children: [ + IncrementalNumberFormField( + label: 'X', + initialValue: data.x, + onChanged: (v) { + Repository.setPositionComponentAttribute( + id: widget.componentId, + attribute: 'x', + value: v, + ); + }, + ), + const SizedBox(height: 8), + IncrementalNumberFormField( + label: 'Y', + initialValue: data.y, + ), + const SizedBox(height: 8), + IncrementalNumberFormField( + label: 'Width', + initialValue: data.width, + ), + const SizedBox(height: 8), + IncrementalNumberFormField( + label: 'Height', + initialValue: data.height, + ), + ], + ); + } + return const Text('Loading attributes...'); + }, + ); + } +} From d7fc31073aac24068604d3525a1ce4b16cad638e Mon Sep 17 00:00:00 2001 From: Erick Zanardo Date: Sat, 10 Aug 2024 19:21:21 -0300 Subject: [PATCH 2/4] final touches --- .../incremental_number_form_field.dart | 44 +++++++--- .../position_component_attributes_form.dart | 86 ++++++++++++++----- 2 files changed, 96 insertions(+), 34 deletions(-) diff --git a/packages/flame_devtools/lib/widgets/incremental_number_form_field.dart b/packages/flame_devtools/lib/widgets/incremental_number_form_field.dart index 3cf30c9a1fd..13aa65eee4b 100644 --- a/packages/flame_devtools/lib/widgets/incremental_number_form_field.dart +++ b/packages/flame_devtools/lib/widgets/incremental_number_form_field.dart @@ -22,6 +22,8 @@ class _IncrementalNumberFormFieldState late final _controller = TextEditingController() ..text = widget.initialValue.toString(); + String? errorText; + @override void dispose() { _controller.dispose(); @@ -29,18 +31,42 @@ class _IncrementalNumberFormFieldState } T _parse() { - if (T is double) { + if (T == double) { return double.parse(_controller.text) as T; } else { return int.parse(_controller.text) as T; } } + void _tryUpdate(String value) { + try { + final value = _parse(); + _update(value); + } on Exception catch (_) { + setState(() { + errorText = 'Invalid number'; + }); + } + } + void _update(T v) { - widget.onChanged?.call(v); setState(() { - _controller.text = v.toString(); + errorText = null; }); + + widget.onChanged?.call(v); + } + + void _increment() { + final value = _parse() + 1 as T; + _update(value); + _controller.text = value.toString(); + } + + void _decrement() { + final value = _parse() - 1 as T; + _update(value); + _controller.text = value.toString(); } @override @@ -48,9 +74,7 @@ class _IncrementalNumberFormFieldState return Row( children: [ IconButton( - onPressed: () { - _update(_parse() - 1 as T); - }, + onPressed: _decrement, icon: const Icon(Icons.remove), ), const SizedBox(width: 8), @@ -59,17 +83,15 @@ class _IncrementalNumberFormFieldState child: TextField( decoration: InputDecoration( labelText: widget.label, + errorText: errorText, ), controller: _controller, - // TODO(erickzanardo): Implement this - // onChanged: (v) => _update(v as T), + onChanged: _tryUpdate, ), ), const SizedBox(width: 8), IconButton( - onPressed: () { - _update(_parse() + 1 as T); - }, + onPressed: _increment, icon: const Icon(Icons.add), ), ], diff --git a/packages/flame_devtools/lib/widgets/position_component_attributes_form.dart b/packages/flame_devtools/lib/widgets/position_component_attributes_form.dart index 325af45b0bc..ccd32f647a2 100644 --- a/packages/flame_devtools/lib/widgets/position_component_attributes_form.dart +++ b/packages/flame_devtools/lib/widgets/position_component_attributes_form.dart @@ -28,6 +28,17 @@ class _PositionComponentAttributesFormState ); } + @override + void didUpdateWidget(PositionComponentAttributesForm oldWidget) { + super.didUpdateWidget(oldWidget); + + if (oldWidget.componentId != widget.componentId) { + _attributesFuture = Repository.getPositionComponentAttributes( + id: widget.componentId, + ); + } + } + @override Widget build(BuildContext context) { return FutureBuilder( @@ -38,31 +49,60 @@ class _PositionComponentAttributesFormState final data = snapshot.data!; return Column( children: [ - IncrementalNumberFormField( - label: 'X', - initialValue: data.x, - onChanged: (v) { - Repository.setPositionComponentAttribute( - id: widget.componentId, - attribute: 'x', - value: v, - ); - }, - ), - const SizedBox(height: 8), - IncrementalNumberFormField( - label: 'Y', - initialValue: data.y, - ), - const SizedBox(height: 8), - IncrementalNumberFormField( - label: 'Width', - initialValue: data.width, + Row( + children: [ + IncrementalNumberFormField( + label: 'X', + initialValue: data.x, + onChanged: (v) { + Repository.setPositionComponentAttribute( + id: widget.componentId, + attribute: 'x', + value: v, + ); + }, + ), + const SizedBox(width: 8), + IncrementalNumberFormField( + label: 'Y', + initialValue: data.y, + onChanged: (v) { + Repository.setPositionComponentAttribute( + id: widget.componentId, + attribute: 'y', + value: v, + ); + }, + ), + ], ), const SizedBox(height: 8), - IncrementalNumberFormField( - label: 'Height', - initialValue: data.height, + Row( + children: [ + IncrementalNumberFormField( + label: 'Width', + initialValue: data.width, + onChanged: (v) { + Repository.setPositionComponentAttribute( + id: widget.componentId, + attribute: 'width', + value: v, + ); + }, + ), + const SizedBox(width: 8), + IncrementalNumberFormField( + label: 'Height', + initialValue: data.height, + onChanged: (v) { + Repository.setPositionComponentAttribute( + id: widget.componentId, + attribute: 'height', + value: v, + ); + }, + ), + ], ), ], ); From ffae9b9f19f43692b5470f5a38bbee25feb7b333 Mon Sep 17 00:00:00 2001 From: Erick Zanardo Date: Sun, 11 Aug 2024 21:01:25 -0300 Subject: [PATCH 3/4] PR suggestions --- ...ition_component_attributes_connector.dart} | 6 +- .../lib/src/devtools/dev_tools_connector.dart | 2 +- .../lib/src/devtools/dev_tools_service.dart | 4 +- ...osition_component_attributes_provider.dart | 7 + .../incremental_number_form_field.dart | 10 ++ .../position_component_attributes_form.dart | 169 ++++++++---------- 6 files changed, 96 insertions(+), 102 deletions(-) rename packages/flame/lib/src/devtools/connectors/{position_attributes_component_connector.dart => position_component_attributes_connector.dart} (90%) create mode 100644 packages/flame_devtools/lib/providers/position_component_attributes_provider.dart diff --git a/packages/flame/lib/src/devtools/connectors/position_attributes_component_connector.dart b/packages/flame/lib/src/devtools/connectors/position_component_attributes_connector.dart similarity index 90% rename from packages/flame/lib/src/devtools/connectors/position_attributes_component_connector.dart rename to packages/flame/lib/src/devtools/connectors/position_component_attributes_connector.dart index f5f15615cdd..4839f2f18d0 100644 --- a/packages/flame/lib/src/devtools/connectors/position_attributes_component_connector.dart +++ b/packages/flame/lib/src/devtools/connectors/position_component_attributes_connector.dart @@ -4,7 +4,7 @@ import 'dart:developer'; import 'package:flame/components.dart'; import 'package:flame/src/devtools/dev_tools_connector.dart'; -class PositionAttributesComponentConnector extends DevToolsConnector { +class PositionComponentAttributesConnector extends DevToolsConnector { @override void init() { registerExtension( @@ -12,7 +12,7 @@ class PositionAttributesComponentConnector extends DevToolsConnector { (method, parameters) async { final id = int.tryParse(parameters['id'] ?? ''); - final positionComponent = findGameComponent(id); + final positionComponent = findComponent(id); if (positionComponent != null) { return ServiceExtensionResponse.result( @@ -39,7 +39,7 @@ class PositionAttributesComponentConnector extends DevToolsConnector { final id = int.tryParse(parameters['id'] ?? ''); final attribute = parameters['attribute']; - final positionComponent = findGameComponent(id); + final positionComponent = findComponent(id); if (positionComponent != null) { if (attribute == 'x') { diff --git a/packages/flame/lib/src/devtools/dev_tools_connector.dart b/packages/flame/lib/src/devtools/dev_tools_connector.dart index 0dfe51c42d1..2bcb26b68d3 100644 --- a/packages/flame/lib/src/devtools/dev_tools_connector.dart +++ b/packages/flame/lib/src/devtools/dev_tools_connector.dart @@ -34,7 +34,7 @@ abstract class DevToolsConnector { /// Finds a component in the game tree by its id. /// /// Returns the component if found, otherwise null. - T? findGameComponent(int? id) { + T? findComponent(int? id) { T? component; game.propagateToChildren( (c) { diff --git a/packages/flame/lib/src/devtools/dev_tools_service.dart b/packages/flame/lib/src/devtools/dev_tools_service.dart index 786c3a2d2ba..8cdbd067e74 100644 --- a/packages/flame/lib/src/devtools/dev_tools_service.dart +++ b/packages/flame/lib/src/devtools/dev_tools_service.dart @@ -4,7 +4,7 @@ import 'package:flame/src/devtools/connectors/component_snapshot_connector.dart' import 'package:flame/src/devtools/connectors/component_tree_connector.dart'; import 'package:flame/src/devtools/connectors/debug_mode_connector.dart'; import 'package:flame/src/devtools/connectors/game_loop_connector.dart'; -import 'package:flame/src/devtools/connectors/position_attributes_component_connector.dart'; +import 'package:flame/src/devtools/connectors/position_component_attributes_connector.dart'; import 'package:flame/src/devtools/dev_tools_connector.dart'; /// When [DevToolsService] is initialized by the [FlameGame] it will call @@ -38,7 +38,7 @@ class DevToolsService { ComponentTreeConnector(), GameLoopConnector(), ComponentSnapshotConnector(), - PositionAttributesComponentConnector(), + PositionComponentAttributesConnector(), ]; /// This method is called every time a new game is set in the service and it diff --git a/packages/flame_devtools/lib/providers/position_component_attributes_provider.dart b/packages/flame_devtools/lib/providers/position_component_attributes_provider.dart new file mode 100644 index 00000000000..351a0eb781e --- /dev/null +++ b/packages/flame_devtools/lib/providers/position_component_attributes_provider.dart @@ -0,0 +1,7 @@ +import 'package:flame_devtools/repository.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +final positionComponentAttributesProvider = + FutureProvider.family((ref, id) async { + return Repository.getPositionComponentAttributes(id: id); +}); diff --git a/packages/flame_devtools/lib/widgets/incremental_number_form_field.dart b/packages/flame_devtools/lib/widgets/incremental_number_form_field.dart index 13aa65eee4b..ba2a735544c 100644 --- a/packages/flame_devtools/lib/widgets/incremental_number_form_field.dart +++ b/packages/flame_devtools/lib/widgets/incremental_number_form_field.dart @@ -24,6 +24,16 @@ class _IncrementalNumberFormFieldState String? errorText; + @override + void didUpdateWidget(covariant IncrementalNumberFormField oldWidget) { + super.didUpdateWidget(oldWidget); + + if (oldWidget.initialValue != widget.initialValue) { + _controller.text = widget.initialValue.toString(); + errorText = null; + } + } + @override void dispose() { _controller.dispose(); diff --git a/packages/flame_devtools/lib/widgets/position_component_attributes_form.dart b/packages/flame_devtools/lib/widgets/position_component_attributes_form.dart index ccd32f647a2..8941319eee3 100644 --- a/packages/flame_devtools/lib/widgets/position_component_attributes_form.dart +++ b/packages/flame_devtools/lib/widgets/position_component_attributes_form.dart @@ -1,8 +1,10 @@ +import 'package:flame_devtools/providers/position_component_attributes_provider.dart'; import 'package:flame_devtools/repository.dart'; import 'package:flame_devtools/widgets/incremental_number_form_field.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; -class PositionComponentAttributesForm extends StatefulWidget { +class PositionComponentAttributesForm extends ConsumerWidget { const PositionComponentAttributesForm({ required this.componentId, super.key, @@ -11,103 +13,78 @@ class PositionComponentAttributesForm extends StatefulWidget { final int componentId; @override - State createState() => - _PositionComponentAttributesFormState(); -} - -class _PositionComponentAttributesFormState - extends State { - late Future _attributesFuture; - - @override - void initState() { - super.initState(); - - _attributesFuture = Repository.getPositionComponentAttributes( - id: widget.componentId, + Widget build(BuildContext context, WidgetRef ref) { + final attributesData = ref.watch( + positionComponentAttributesProvider( + componentId, + ), ); - } - @override - void didUpdateWidget(PositionComponentAttributesForm oldWidget) { - super.didUpdateWidget(oldWidget); - - if (oldWidget.componentId != widget.componentId) { - _attributesFuture = Repository.getPositionComponentAttributes( - id: widget.componentId, - ); - } - } - - @override - Widget build(BuildContext context) { - return FutureBuilder( - future: _attributesFuture, - builder: (context, snapshot) { - if (snapshot.connectionState == ConnectionState.done && - snapshot.hasData) { - final data = snapshot.data!; - return Column( - children: [ - Row( - children: [ - IncrementalNumberFormField( - label: 'X', - initialValue: data.x, - onChanged: (v) { - Repository.setPositionComponentAttribute( - id: widget.componentId, - attribute: 'x', - value: v, - ); - }, - ), - const SizedBox(width: 8), - IncrementalNumberFormField( - label: 'Y', - initialValue: data.y, - onChanged: (v) { - Repository.setPositionComponentAttribute( - id: widget.componentId, - attribute: 'y', - value: v, - ); - }, - ), - ], - ), - const SizedBox(height: 8), - Row( - children: [ - IncrementalNumberFormField( - label: 'Width', - initialValue: data.width, - onChanged: (v) { - Repository.setPositionComponentAttribute( - id: widget.componentId, - attribute: 'width', - value: v, - ); - }, - ), - const SizedBox(width: 8), - IncrementalNumberFormField( - label: 'Height', - initialValue: data.height, - onChanged: (v) { - Repository.setPositionComponentAttribute( - id: widget.componentId, - attribute: 'height', - value: v, - ); - }, - ), - ], - ), - ], - ); - } - return const Text('Loading attributes...'); + return attributesData.when( + error: (e, s) => const Text( + 'Error loading component attributes', + ), + loading: () => const Center(child: CircularProgressIndicator()), + data: (attributes) { + return Column( + children: [ + Row( + children: [ + IncrementalNumberFormField( + label: 'X', + initialValue: attributes.x, + onChanged: (v) { + Repository.setPositionComponentAttribute( + id: componentId, + attribute: 'x', + value: v, + ); + }, + ), + const SizedBox(width: 8), + IncrementalNumberFormField( + label: 'Y', + initialValue: attributes.y, + onChanged: (v) { + Repository.setPositionComponentAttribute( + id: componentId, + attribute: 'y', + value: v, + ); + }, + ), + ], + ), + const SizedBox(height: 8), + Row( + children: [ + IncrementalNumberFormField( + label: 'Width', + initialValue: attributes.width, + onChanged: (v) { + Repository.setPositionComponentAttribute( + id: componentId, + attribute: 'width', + value: v, + ); + }, + ), + const SizedBox(width: 8), + IncrementalNumberFormField( + label: 'Height', + initialValue: attributes.height, + onChanged: (v) { + Repository.setPositionComponentAttribute( + id: componentId, + attribute: 'height', + value: v, + ); + }, + ), + ], + ), + ], + ); }, ); } From 8739385ffbb2565f654c290b6e4a47acb3fbf1bc Mon Sep 17 00:00:00 2001 From: Erick Zanardo Date: Sun, 11 Aug 2024 21:07:39 -0300 Subject: [PATCH 4/4] PR suggestions --- .../lib/widgets/position_component_attributes_form.dart | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/flame_devtools/lib/widgets/position_component_attributes_form.dart b/packages/flame_devtools/lib/widgets/position_component_attributes_form.dart index 8941319eee3..92f54c57e18 100644 --- a/packages/flame_devtools/lib/widgets/position_component_attributes_form.dart +++ b/packages/flame_devtools/lib/widgets/position_component_attributes_form.dart @@ -27,7 +27,12 @@ class PositionComponentAttributesForm extends ConsumerWidget { loading: () => const Center(child: CircularProgressIndicator()), data: (attributes) { return Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ + Text( + 'Position', + style: Theme.of(context).textTheme.labelLarge, + ), Row( children: [ IncrementalNumberFormField( @@ -56,6 +61,10 @@ class PositionComponentAttributesForm extends ConsumerWidget { ], ), const SizedBox(height: 8), + Text( + 'Size', + style: Theme.of(context).textTheme.labelLarge, + ), Row( children: [ IncrementalNumberFormField(