@@ -4,7 +4,7 @@ import 'dart:math' as math;
44// Conditionally import JS only when compiling for web
55import 'package:flutter/services.dart' ;
66import 'package:http/http.dart' as http;
7- import 'package:flutter/foundation.dart' show kIsWeb;
7+ import 'package:flutter/foundation.dart' show kIsWeb, defaultTargetPlatform, TargetPlatform ;
88import 'package:orchid/api/orchid_eth/chains.dart' ;
99import 'package:orchid/api/orchid_eth/orchid_account.dart' ;
1010import 'package:orchid/api/orchid_eth/orchid_account_detail.dart' ;
@@ -43,6 +43,19 @@ class ChatView extends StatefulWidget {
4343}
4444
4545class _ChatViewState extends State <ChatView > {
46+ // Platform detection helper
47+ bool get _isMobilePlatform {
48+ // On web, check the target platform
49+ if (kIsWeb) {
50+ // Web on mobile browsers
51+ return defaultTargetPlatform == TargetPlatform .iOS ||
52+ defaultTargetPlatform == TargetPlatform .android;
53+ }
54+ // Native mobile apps
55+ return defaultTargetPlatform == TargetPlatform .iOS ||
56+ defaultTargetPlatform == TargetPlatform .android;
57+ }
58+
4659 // UI state
4760 bool _debugMode = false ;
4861 bool _multiSelectMode = false ;
@@ -108,12 +121,14 @@ class _ChatViewState extends State<ChatView> {
108121 // Initialize the scripting extension mechanism
109122 _initScripting ();
110123
111- // Initialize keyboard listener
112- _initKeyboardListener ();
113-
114- // Register a browser-level event listener if we're running on the web
115- if (kIsWeb) {
116- _initBrowserKeyboardListeners ();
124+ // Initialize keyboard listener only on non-mobile platforms
125+ if (! _isMobilePlatform) {
126+ _initKeyboardListener ();
127+
128+ // Register a browser-level event listener if we're running on the web
129+ if (kIsWeb) {
130+ _initBrowserKeyboardListeners ();
131+ }
117132 }
118133
119134 // Initialize state manager
@@ -133,21 +148,22 @@ class _ChatViewState extends State<ChatView> {
133148 void _initBrowserKeyboardListeners () {
134149 log ('Setting up browser keyboard listener for web' );
135150
136- // Use a simple approach that doesn't rely on dart:js
137- // Register a global key handler that listens for Escape
138- RawKeyboard .instance.addListener (_handleRawKeyEvent);
151+ // Use HardwareKeyboard for listening to key events
152+ HardwareKeyboard .instance.addHandler (_handleKeyEvent);
139153
140154 log ('Browser keyboard listener initialized' );
141155 }
142156
143- void _handleRawKeyEvent ( RawKeyEvent event) {
144- if (event is RawKeyDownEvent ) {
157+ bool _handleKeyEvent ( KeyEvent event) {
158+ if (event is KeyDownEvent ) {
145159 if (event.logicalKey == LogicalKeyboardKey .escape) {
146160 if (_isProcessingRequest) {
147161 _cancelOngoingRequests ();
162+ return true ; // Handled
148163 }
149164 }
150165 }
166+ return false ; // Not handled
151167 }
152168
153169 void _initKeyboardListener () {
@@ -540,8 +556,8 @@ class _ChatViewState extends State<ChatView> {
540556
541557 log ('Starting processing request - ESC to cancel' );
542558
543- // Ensure the app has focus for keyboard events
544- if (_keyboardFocusNode.canRequestFocus) {
559+ // Ensure the app has focus for keyboard events (only on non-mobile platforms)
560+ if (! _isMobilePlatform && _keyboardFocusNode.canRequestFocus) {
545561 _keyboardFocusNode.requestFocus ();
546562 }
547563
@@ -683,16 +699,13 @@ class _ChatViewState extends State<ChatView> {
683699 // Tell the provider manager we have active, cancellable requests
684700 _providerManager.setHasCancellableRequests (true );
685701
686- // Ensure we have focus for keyboard events
687- if (_keyboardFocusNode.canRequestFocus) {
702+ // Ensure we have focus for keyboard events (only on non-mobile platforms)
703+ if (! _isMobilePlatform && _keyboardFocusNode.canRequestFocus) {
688704 _keyboardFocusNode.requestFocus ();
689705 }
690706
691707 List <ChatMessage > toolResultMessages = [];
692708 String ? modelId;
693-
694- // Store the source of this tool call invocation for debugging
695- String callSource = "direct" ;
696709
697710 try {
698711 for (final toolCall in toolCalls) {
@@ -1402,9 +1415,9 @@ class _ChatViewState extends State<ChatView> {
14021415 _accountDetail? .cancel ();
14031416 _keyboardFocusNode.dispose ();
14041417
1405- // Clean up global keyboard listener
1406- if (kIsWeb) {
1407- RawKeyboard .instance.removeListener (_handleRawKeyEvent );
1418+ // Clean up global keyboard listener (only if it was added on non-mobile platforms)
1419+ if (! _isMobilePlatform && kIsWeb) {
1420+ HardwareKeyboard .instance.removeHandler (_handleKeyEvent );
14081421 }
14091422
14101423 super .dispose ();
@@ -1416,30 +1429,21 @@ class _ChatViewState extends State<ChatView> {
14161429 var showIcons = AppSize (context).narrowerThanWidth (700 );
14171430 var showMinWidth = AppSize (context).narrowerThanWidth (minWidth);
14181431
1419- // Request focus for keyboard detection on first build
1420- WidgetsBinding .instance.addPostFrameCallback ((_) {
1421- if (_keyboardFocusNode.canRequestFocus) {
1422- _keyboardFocusNode.requestFocus ();
1423- }
1424- });
1432+ // Request focus for keyboard detection on first build (only on non-mobile platforms)
1433+ if (! _isMobilePlatform) {
1434+ WidgetsBinding .instance.addPostFrameCallback ((_) {
1435+ if (_keyboardFocusNode.canRequestFocus) {
1436+ _keyboardFocusNode.requestFocus ();
1437+ }
1438+ });
1439+ }
14251440
14261441 // Use a global key so we can access this widget from anywhere
14271442 final GlobalKey <ScaffoldState > scaffoldKey = GlobalKey <ScaffoldState >();
14281443
14291444 // Listen for key presses at the document level (more reliable in web)
1430- return Focus (
1431- autofocus: true ,
1432- onKeyEvent: (FocusNode node, KeyEvent event) {
1433- // Check for escape key
1434- if (event is KeyDownEvent && event.logicalKey == LogicalKeyboardKey .escape) {
1435- if (_isProcessingRequest) {
1436- _cancelOngoingRequests ();
1437- return KeyEventResult .handled;
1438- }
1439- }
1440- return KeyEventResult .ignored;
1441- },
1442- child: Scaffold (
1445+ // Only wrap with Focus on desktop to avoid interfering with mobile text input
1446+ Widget scaffoldWidget = Scaffold (
14431447 key: scaffoldKey,
14441448 body: SafeArea (
14451449 child: Stack (
@@ -1481,7 +1485,7 @@ class _ChatViewState extends State<ChatView> {
14811485 // Processing indicator
14821486 if (_isProcessingRequest)
14831487 GestureDetector (
1484- onTap: _cancelOngoingRequests, // Allow cancelling by tap as well
1488+ onTap: ! _isMobilePlatform ? _cancelOngoingRequests : null , // Disable tap cancellation on mobile
14851489 child: Padding (
14861490 padding: const EdgeInsets .only (top: 8.0 , bottom: 8.0 ),
14871491 child: Row (
@@ -1498,10 +1502,14 @@ class _ChatViewState extends State<ChatView> {
14981502 ),
14991503 ),
15001504 const SizedBox (width: 8 ),
1501- Text ('Processing... Press ESC or tap here to cancel' ,
1505+ Text (_isMobilePlatform
1506+ ? 'Processing...'
1507+ : 'Processing... Press ESC or tap here to cancel' ,
15021508 style: OrchidText .caption.copyWith (
15031509 color: Colors .white70,
1504- decoration: TextDecoration .underline,
1510+ decoration: _isMobilePlatform
1511+ ? TextDecoration .none
1512+ : TextDecoration .underline,
15051513 ),
15061514 ),
15071515 ],
@@ -1515,8 +1523,27 @@ class _ChatViewState extends State<ChatView> {
15151523 ],
15161524 ),
15171525 ),
1518- ),
1519- );
1526+ );
1527+
1528+ // Only wrap with Focus on desktop platforms to avoid interfering with mobile text input
1529+ if (! _isMobilePlatform) {
1530+ return Focus (
1531+ autofocus: true ,
1532+ onKeyEvent: (FocusNode node, KeyEvent event) {
1533+ // Check for escape key
1534+ if (event is KeyDownEvent && event.logicalKey == LogicalKeyboardKey .escape) {
1535+ if (_isProcessingRequest) {
1536+ _cancelOngoingRequests ();
1537+ return KeyEventResult .handled;
1538+ }
1539+ }
1540+ return KeyEventResult .ignored;
1541+ },
1542+ child: scaffoldWidget,
1543+ );
1544+ } else {
1545+ return scaffoldWidget;
1546+ }
15201547 }
15211548
15221549 Widget _buildChatPane () {
0 commit comments