import "package:flutter/foundation.dart"; import "package:flutter/services.dart"; import "package:flutter/widgets.dart"; import "package:flutter_test/flutter_test.dart"; import "package:garage_ui/garage_ui.dart"; import "package:garage_ui/platform/cursor_lock.dart"; import "support/test_scheme.dart"; // Drag-to-scrub used to be macOS only without anybody saying so. The moment // the drag threshold was crossed the field handed everything over to // CursorLock and ignored Flutters own pointer stream forever after - and // CursorLock has no native handler off macOS, so on web (and windows/linux) // the deltas it was waiting on never turned up. The field just froze on the // value it started on. Future pumpField( WidgetTester tester, { String text = "10.0", }) async { final controller = TextEditingController(text: text); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: GarageTheme( data: ThemeData(colorScheme: testScheme), child: Center( child: SizedBox( width: 200, child: TextField( controller: controller, features: const [InputFeature.scrub()], ), ), ), ), ), ); await tester.pump(); return controller; } void main() { testWidgets("no native cursor lock - the pointer stream drives the scrub", ( tester, ) async { debugDefaultTargetPlatformOverride = TargetPlatform.linux; expect(CursorLock.isSupported, isFalse); final controller = await pumpField(tester); // real pointer moves arrive a few px at a time, so drive it that way // rather than as one giant jump. default sensitivity is 0.1/px, and the // first move only arms the drag (it's the one the click threshold eats), // so 100 counted px = +10. final gesture = await tester.startGesture( tester.getCenter(find.byType(TextField)), ); for (var i = 0; i < 21; i++) { await gesture.moveBy(const Offset(5, 0)); await tester.pump(); } await gesture.up(); await tester.pump(); expect(double.parse(controller.text), closeTo(20.0, 0.5)); debugDefaultTargetPlatformOverride = null; }); testWidgets("with a native cursor lock the pointer stream is ignored", ( tester, ) async { debugDefaultTargetPlatformOverride = TargetPlatform.macOS; const channel = MethodChannel("garage/cursor_lock"); TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger .setMockMethodCallHandler(channel, (_) async => null); final controller = await pumpField(tester); final gesture = await tester.startGesture( tester.getCenter(find.byType(TextField)), ); for (var i = 0; i < 21; i++) { await gesture.moveBy(const Offset(5, 0)); await tester.pump(); } await gesture.up(); await tester.pump(); // the native side would have sent deltas back over the channel; nothing // did here, so the value must not have budged. expect(double.parse(controller.text), closeTo(10.0, 1e-9)); debugDefaultTargetPlatformOverride = null; }); }