Skip to content

Commit 66a5c4c

Browse files
author
GitLab CI
committed
fix: null safety and parameter flexibility for bridge mode
- drag: support coordinate-based drag (start_x/end_x) alongside key-based - edge_swipe: default edge/direction params instead of null cast - assert_text: allow missing key param, fallback to element/text - execute_batch: accept both 'actions' and 'commands' param names - native_gesture: accept 'type'/'name' as alias for 'gesture' - native_key_combo: accept List<String> or String for keys param - get_widget_properties: require key/element with helpful error - get_text_value: allow nullable key in FlutterSkillClient
1 parent 4a64e44 commit 66a5c4c

7 files changed

Lines changed: 48 additions & 15 deletions

File tree

lib/src/cli/server.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -672,7 +672,7 @@ class FlutterMcpServer {
672672
/// Execute a batch of actions in sequence
673673
Future<Map<String, dynamic>> _executeBatch(
674674
Map<String, dynamic> args, FlutterSkillClient client) async {
675-
final actions = args['actions'] as List<dynamic>;
675+
final actions = (args['actions'] ?? args['commands'] ?? []) as List<dynamic>;
676676
final stopOnFailure = args['stop_on_failure'] ?? true;
677677

678678
final results = <Map<String, dynamic>>[];

lib/src/cli/tool_handlers/bf_batch.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,8 @@ extension _BfBatch on FlutterMcpServer {
104104
});
105105
}
106106
final fc = _asFlutterClient(client!, 'edge_swipe');
107-
final edge = args['edge'] as String;
108-
final direction = args['direction'] as String;
107+
final edge = args['edge'] as String? ?? 'left';
108+
final direction = args['direction'] as String? ?? 'right';
109109
final distance = (args['distance'] as num?)?.toDouble() ?? 200;
110110
final result = await fc.edgeSwipe(
111111
edge: edge, direction: direction, distance: distance);

lib/src/cli/tool_handlers/bf_inspection.dart

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,8 +179,18 @@ extension _BfInspection on FlutterMcpServer {
179179
final maxDepth = args['max_depth'] ?? 10;
180180
return await fc.getWidgetTree(maxDepth: maxDepth);
181181
case 'get_widget_properties':
182+
if (client is BridgeDriver) {
183+
return await client.callMethod('get_widget_properties', {
184+
'key': args['key'] as String?,
185+
'element': args['element'] as String?,
186+
});
187+
}
182188
final fc = _asFlutterClient(client!, 'get_widget_properties');
183-
return await fc.getWidgetProperties(args['key']);
189+
final wpKey = (args['key'] ?? args['element'] ?? '') as String;
190+
if (wpKey.isEmpty) {
191+
return {"success": false, "error": "key or element parameter required"};
192+
}
193+
return await fc.getWidgetProperties(wpKey);
184194
case 'get_text_content':
185195
if (client is BridgeDriver) {
186196
final text = await client.getText();

lib/src/cli/tool_handlers/bf_interaction.dart

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -118,23 +118,44 @@ extension _BfInteraction on FlutterMcpServer {
118118
return success ? "Swiped ${args['direction']}" : "Swipe failed";
119119
case 'drag':
120120
if (client is BridgeDriver) {
121+
// Support both key-based and coordinate-based drag
122+
if (args['start_x'] != null) {
123+
final result = await client.callMethod('drag', {
124+
'start_x': (args['start_x'] as num).toDouble(),
125+
'start_y': (args['start_y'] as num).toDouble(),
126+
'end_x': (args['end_x'] as num).toDouble(),
127+
'end_y': (args['end_y'] as num).toDouble(),
128+
});
129+
return result;
130+
}
121131
final result = await client.callMethod(
122132
'drag', {'from_key': args['from_key'], 'to_key': args['to_key']});
123133
return result['success'] == true ? "Dragged" : "Drag failed";
124134
}
125135
final fc = _asFlutterClient(client!, 'drag');
126-
final success =
127-
await fc.drag(fromKey: args['from_key'], toKey: args['to_key']);
136+
// Support coordinate-based drag via swipeCoordinates for FlutterClient
137+
if (args['start_x'] != null) {
138+
final result = await fc.swipeCoordinates(
139+
(args['start_x'] as num).toDouble(),
140+
(args['start_y'] as num).toDouble(),
141+
(args['end_x'] as num).toDouble(),
142+
(args['end_y'] as num).toDouble(),
143+
);
144+
return result;
145+
}
146+
final success = await fc.drag(
147+
fromKey: args['from_key'] as String? ?? '',
148+
toKey: args['to_key'] as String? ?? '');
128149
return success ? "Dragged" : "Drag failed";
129150

130151
// State & Validation
131152
case 'get_text_value':
132153
if (client is BridgeDriver) {
133-
final text = await client.getText(key: args['key']);
154+
final text = await client.getText(key: args['key'] as String?);
134155
return {"success": true, "text": text};
135156
}
136157
final fc = _asFlutterClient(client!, 'get_text_value');
137-
return await fc.getTextValue(args['key']);
158+
return await fc.getTextValue(args['key'] as String?);
138159
case 'get_checkbox_state':
139160
if (client is BridgeDriver) {
140161
return await client

lib/src/cli/tool_handlers/flutter_helpers.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -312,11 +312,11 @@ extension _FlutterHelpers on FlutterMcpServer {
312312
/// Assert text content
313313
Future<Map<String, dynamic>> _assertText(
314314
Map<String, dynamic> args, FlutterSkillClient client) async {
315-
final key = args['key'] as String;
316-
final expected = args['expected'] as String;
315+
final key = args['key'] as String? ?? args['element'] as String? ?? '';
316+
final expected = args['expected'] as String? ?? args['text'] as String? ?? '';
317317
final useContains = args['contains'] ?? false;
318318

319-
final actual = await client.getTextValue(key);
319+
final actual = await client.getTextValue(key.isEmpty ? null : key);
320320

321321
bool matches;
322322
if (useContains) {

lib/src/cli/tool_handlers/native_handlers.dart

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ extension _NativeHandlers on FlutterMcpServer {
263263
},
264264
};
265265
}
266-
final gesture = args['gesture'] as String;
266+
final gesture = (args['gesture'] ?? args['type'] ?? args['name']) as String;
267267
final result = await driver.gesture(gesture).timeout(
268268
const Duration(seconds: 15),
269269
onTimeout: () => NativeResult(
@@ -303,7 +303,9 @@ extension _NativeHandlers on FlutterMcpServer {
303303
},
304304
};
305305
}
306-
final keys = args['keys'] as String;
306+
// Accept both String ("shift+a") and List (["shift", "a"])
307+
final rawKeys = args['keys'];
308+
final keys = rawKeys is List ? rawKeys.join('+') : rawKeys as String;
307309
final result = await driver.keyCombo(keys).timeout(
308310
const Duration(seconds: 10),
309311
onTimeout: () => NativeResult(

lib/src/drivers/flutter_driver.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -261,9 +261,9 @@ URI: $wsUri''');
261261

262262
// ==================== STATE & VALIDATION ====================
263263

264-
Future<String?> getTextValue(String key) async {
264+
Future<String?> getTextValue(String? key) async {
265265
final result = await _call('ext.flutter.flutter_skill.getTextValue', {
266-
'key': key,
266+
if (key != null) 'key': key,
267267
});
268268
return result['value'];
269269
}

0 commit comments

Comments
 (0)