diff --git a/lib/screens/profile/pin_entry_dialog.dart b/lib/screens/profile/pin_entry_dialog.dart index 8b2b358a..5c74e75e 100644 --- a/lib/screens/profile/pin_entry_dialog.dart +++ b/lib/screens/profile/pin_entry_dialog.dart @@ -27,6 +27,7 @@ class _PinEntryDialogState extends State with SingleTickerProvid late Animation _shakeAnimation; final _pinInputKey = GlobalKey<_TvPinInputState>(); final _cancelFocusNode = FocusNode(debugLabel: 'PinCancelButton'); + bool _completed = false; @override void initState() { @@ -56,11 +57,15 @@ class _PinEntryDialogState extends State with SingleTickerProvid } void _submit(String pin) { - Navigator.of(context).pop(pin); + if (_completed) return; + _completed = true; + Navigator.of(context).pop(pin); } void _cancel() { - Navigator.of(context).pop(null); + if (_completed) return; + _completed = true; + Navigator.of(context).pop(); } void _focusPinInput() { diff --git a/test/widgets/pin_entry_dialog_test.dart b/test/widgets/pin_entry_dialog_test.dart index 865c6f78..149d64a5 100644 --- a/test/widgets/pin_entry_dialog_test.dart +++ b/test/widgets/pin_entry_dialog_test.dart @@ -64,6 +64,68 @@ void main() { expect(find.byType(PinEntryDialog), findsNothing); }); + testWidgets('mobile duplicate submit does not pop route below PIN dialog', (tester) async { + TvDetectionService.debugSetAppleTVOverride(false); + String? pinResult; + bool? boolRouteResult; + + await tester.pumpWidget( + MaterialApp( + theme: ThemeData(platform: TargetPlatform.iOS), + home: Builder( + builder: (context) { + return Scaffold( + body: TextButton( + onPressed: () async { + boolRouteResult = await Navigator.of(context).push( + MaterialPageRoute( + builder: (routeContext) { + return Scaffold( + body: Column( + children: [ + const Text('Bool Route'), + TextButton( + onPressed: () async { + pinResult = await showPinEntryDialog(routeContext, 'Protected Profile'); + }, + child: const Text('Open PIN'), + ), + ], + ), + ); + }, + ), + ); + }, + child: const Text('Open Bool Route'), + ), + ); + }, + ), + ), + ); + + await tester.tap(find.text('Open Bool Route')); + await tester.pumpAndSettle(); + + expect(find.text('Bool Route'), findsOneWidget); + + await tester.tap(find.text('Open PIN')); + await tester.pumpAndSettle(); + + final field = find.byType(TextField); + await tester.showKeyboard(field); + await tester.enterText(field, '1234'); + await tester.testTextInput.receiveAction(TextInputAction.done); + await tester.pumpAndSettle(); + + expect(tester.takeException(), isNull); + expect(pinResult, '1234'); + expect(boolRouteResult, isNull); + expect(find.text('Bool Route'), findsOneWidget); + expect(find.byType(PinEntryDialog), findsNothing); + }); + testWidgets('D-pad keypad enters and submits PIN', (tester) async { TvDetectionService.debugSetAppleTVOverride(true); String? result;