diff --git a/app/lib/src/screens/host_setup_screen.dart b/app/lib/src/screens/host_setup_screen.dart index 2471ad6..3d279e2 100644 --- a/app/lib/src/screens/host_setup_screen.dart +++ b/app/lib/src/screens/host_setup_screen.dart @@ -7,6 +7,7 @@ import '../models/host_config.dart'; import '../models/plugin_info.dart'; import '../notifications/host_pairing.dart'; import '../widgets/error_message_view.dart'; +import '../widgets/text_context_menu.dart'; /// Form for entering (or editing) the SSH connection details for the dev /// machine running Herdr. @@ -372,11 +373,13 @@ class _HostSetupScreenState extends State { TextFormField( controller: _nameController, decoration: InputDecoration(labelText: l10n.hostSetupNameLabel), + contextMenuBuilder: noScanTextContextMenuBuilder, ), const SizedBox(height: 12), TextFormField( controller: _hostController, decoration: InputDecoration(labelText: l10n.hostSetupHostLabel), + contextMenuBuilder: noScanTextContextMenuBuilder, validator: (v) => (v == null || v.trim().isEmpty) ? l10n.hostSetupHostRequired : null, @@ -386,6 +389,7 @@ class _HostSetupScreenState extends State { controller: _portController, decoration: InputDecoration(labelText: l10n.hostSetupPortLabel), keyboardType: TextInputType.number, + contextMenuBuilder: noScanTextContextMenuBuilder, // Blank is allowed and defaults to 22 (see _buildConfig); only a // non-blank value has to be a valid port number. validator: (v) { @@ -402,6 +406,7 @@ class _HostSetupScreenState extends State { TextFormField( controller: _userController, decoration: InputDecoration(labelText: l10n.hostSetupUserLabel), + contextMenuBuilder: noScanTextContextMenuBuilder, validator: (v) => (v == null || v.trim().isEmpty) ? l10n.hostSetupUserRequired : null, @@ -414,6 +419,7 @@ class _HostSetupScreenState extends State { ), style: const TextStyle(fontFamily: 'monospace'), maxLines: 6, + contextMenuBuilder: noScanTextContextMenuBuilder, validator: (v) { final t = v?.trim() ?? ''; if (t.isEmpty) return l10n.hostSetupPrivateKeyRequired; @@ -430,6 +436,7 @@ class _HostSetupScreenState extends State { labelText: l10n.hostSetupPassphraseLabel, ), obscureText: true, + contextMenuBuilder: noScanTextContextMenuBuilder, ), const SizedBox(height: 12), ExpansionTile( @@ -441,6 +448,7 @@ class _HostSetupScreenState extends State { decoration: InputDecoration( labelText: l10n.hostSetupHerdrBinLabel, ), + contextMenuBuilder: noScanTextContextMenuBuilder, ), ], ), diff --git a/app/test/screens/host_setup_screen_test.dart b/app/test/screens/host_setup_screen_test.dart index 55401b4..04031fb 100644 --- a/app/test/screens/host_setup_screen_test.dart +++ b/app/test/screens/host_setup_screen_test.dart @@ -5,6 +5,7 @@ import 'package:drover/src/models/host_config.dart'; import 'package:drover/src/models/plugin_info.dart'; import 'package:drover/src/notifications/host_pairing.dart'; import 'package:drover/src/screens/host_setup_screen.dart'; +import 'package:drover/src/widgets/text_context_menu.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -21,6 +22,48 @@ const _samplePlugin = PluginInfo( ); void main() { + testWidgets('disables Scan Text for every host setup input', (tester) async { + await tester.pumpWidget( + MaterialApp( + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, + home: HostSetupScreen(onSubmit: (config) async {}), + ), + ); + final editableTexts = tester.widgetList( + find.byType(EditableText), + ); + + expect(editableTexts, hasLength(6)); + for (final editableText in editableTexts) { + expect( + editableText.contextMenuBuilder, + same(noScanTextContextMenuBuilder), + ); + } + + await tester.scrollUntilVisible( + find.byType(ExpansionTile), + 500, + scrollable: find.byType(Scrollable).first, + ); + await tester.tap(find.byType(ExpansionTile)); + await tester.pumpAndSettle(); + + final herdrBinEditableText = tester.widget( + find.descendant( + of: find.byType(ExpansionTile), + matching: find.byType(EditableText), + ), + ); + expect( + herdrBinEditableText.contextMenuBuilder, + same(noScanTextContextMenuBuilder), + ); + + await tester.pumpWidget(const SizedBox()); + }); + testWidgets('renders the demo entry when onEnterDemo is provided', ( tester, ) async {