@@ -5,7 +5,7 @@ import { AudioLines, CornerDownLeft, Paperclip, X, Loader2 } from 'lucide-react-
55import { StopIcon } from '@/components/ui/StopIcon' ;
66import { useColorScheme } from 'nativewind' ;
77import * as React from 'react' ;
8- import { Keyboard , Pressable , ScrollView , TextInput , View , ViewStyle , type ViewProps , type NativeSyntheticEvent , type TextInputContentSizeChangeEventData , type TextInputSelectionChangeEventData } from 'react-native' ;
8+ import { Keyboard , Pressable , ScrollView , TextInput , View , ViewStyle , Platform , TouchableOpacity , type ViewProps , type NativeSyntheticEvent , type TextInputContentSizeChangeEventData , type TextInputSelectionChangeEventData } from 'react-native' ;
99import Animated , {
1010 useAnimatedStyle ,
1111 useSharedValue ,
@@ -25,6 +25,15 @@ const AnimatedView = Animated.createAnimatedComponent(View);
2525// Spring config - defined once outside component
2626const SPRING_CONFIG = { damping : 15 , stiffness : 400 } ;
2727
28+ // Android hit slop for better touch targets
29+ const ANDROID_HIT_SLOP = Platform . OS === 'android' ? { top : 10 , bottom : 10 , left : 10 , right : 10 } : undefined ;
30+
31+ // #region agent log
32+ const debugLog = ( location : string , message : string , data : any , hypothesisId : string ) => {
33+ fetch ( 'http://127.0.0.1:7242/ingest/75c4e084-f8e3-4454-ac60-13feff134172' , { method :'POST' , headers :{ 'Content-Type' :'application/json' } , body :JSON . stringify ( { location, message, data, timestamp :Date . now ( ) , sessionId :'debug-session' , hypothesisId} ) } ) . catch ( ( ) => { } ) ;
34+ } ;
35+ // #endregion
36+
2837export interface ChatInputRef {
2938 focus : ( ) => void ;
3039}
@@ -375,10 +384,11 @@ export const ChatInput = React.memo(React.forwardRef<ChatInputRef, ChatInputProp
375384 < View
376385 className = "relative rounded-[30px] overflow-hidden bg-card border border-border"
377386 style = { containerStyle }
387+ collapsable = { false }
378388 { ...props }
379389 >
380390 < View className = "absolute inset-0" />
381- < View className = "p-4 flex-1" >
391+ < View className = "p-4 flex-1" collapsable = { false } >
382392 { isRecording ? (
383393 < RecordingMode
384394 audioLevels = { audioLevels }
@@ -470,6 +480,7 @@ const RecordingMode = React.memo(({
470480 onPress = { onCancelRecording }
471481 className = "bg-primary/5 rounded-full items-center justify-center"
472482 style = { [ { width : 40 , height : 40 } , cancelAnimatedStyle ] }
483+ hitSlop = { ANDROID_HIT_SLOP }
473484 >
474485 < Icon as = { X } size = { 16 } className = "text-foreground" strokeWidth = { 2 } />
475486 </ AnimatedPressable >
@@ -479,6 +490,7 @@ const RecordingMode = React.memo(({
479490 onPress = { onSendAudio }
480491 className = "bg-primary rounded-full items-center justify-center"
481492 style = { [ { width : 40 , height : 40 } , stopAnimatedStyle ] }
493+ hitSlop = { ANDROID_HIT_SLOP }
482494 >
483495 < Icon as = { CornerDownLeft } size = { 16 } className = "text-primary-foreground" strokeWidth = { 2 } />
484496 </ AnimatedPressable >
@@ -549,6 +561,7 @@ const NormalMode = React.memo(({
549561 < ScrollView
550562 showsVerticalScrollIndicator = { false }
551563 keyboardShouldPersistTaps = "handled"
564+ nestedScrollEnabled = { true }
552565 >
553566 < TextInput
554567 ref = { textInputRef }
@@ -567,28 +580,34 @@ const NormalMode = React.memo(({
567580 onContentSizeChange = { handleContentSizeChange }
568581 className = "text-foreground text-base"
569582 style = { textInputStyle }
583+ textAlignVertical = "top"
584+ underlineColorAndroid = "transparent"
570585 />
571586 </ ScrollView >
572587 </ View >
573588
574589 < View className = "absolute bottom-4 left-4 right-4 flex-row items-center justify-between" >
575590 < View className = "flex-row items-center gap-2" >
576- < AnimatedPressable
577- onPressIn = { onAttachPressIn }
578- onPressOut = { onAttachPressOut }
591+ { /* Use TouchableOpacity on Android - AnimatedPressable blocks touches */ }
592+ < TouchableOpacity
579593 onPress = { ( ) => {
594+ // #region agent log
595+ debugLog ( 'ChatInput.tsx:attachPress' , 'ATTACH BUTTON PRESSED' , { isAuthenticated, isDisabled } , 'H8' ) ;
596+ // #endregion
580597 if ( ! isAuthenticated ) {
581598 console . warn ( '⚠️ User not authenticated - cannot attach' ) ;
582599 return ;
583600 }
584601 onAttachPress ?.( ) ;
585602 } }
586603 disabled = { isDisabled }
587- className = "border border-border rounded-[18px] w-10 h-10 items-center justify-center"
588- style = { attachButtonStyle }
604+ style = { { width : 40 , height : 40 , borderWidth : 1 , borderRadius : 18 , alignItems : 'center' , justifyContent : 'center' , opacity : isDisabled ? 0.4 : 1 } }
605+ className = "border-border"
606+ hitSlop = { ANDROID_HIT_SLOP }
607+ activeOpacity = { 0.7 }
589608 >
590609 < Icon as = { Paperclip } size = { 16 } className = "text-foreground" />
591- </ AnimatedPressable >
610+ </ TouchableOpacity >
592611 </ View >
593612
594613 < View className = "flex-row items-center gap-2" >
@@ -597,13 +616,19 @@ const NormalMode = React.memo(({
597616 compact = { false }
598617 />
599618
600- < AnimatedPressable
601- onPressIn = { onSendPressIn }
602- onPressOut = { onSendPressOut }
603- onPress = { onButtonPress }
619+ { /* Use TouchableOpacity on Android - AnimatedPressable blocks touches */ }
620+ < TouchableOpacity
621+ onPress = { ( ) => {
622+ // #region agent log
623+ debugLog ( 'ChatInput.tsx:sendPress' , 'SEND/MIC BUTTON PRESSED' , { isSendingMessage, isTranscribing, isAgentRunning } , 'H8' ) ;
624+ // #endregion
625+ onButtonPress ( ) ;
626+ } }
604627 disabled = { isSendingMessage || isTranscribing }
605- className = { `rounded-[18px] items-center justify-center ${ isAgentRunning ? 'bg-foreground' : 'bg-primary' } ` }
606- style = { [ { width : 40 , height : 40 } , sendAnimatedStyle ] }
628+ style = { { width : 40 , height : 40 , borderRadius : 18 , alignItems : 'center' , justifyContent : 'center' } }
629+ className = { isAgentRunning ? 'bg-foreground' : 'bg-primary' }
630+ hitSlop = { ANDROID_HIT_SLOP }
631+ activeOpacity = { 0.7 }
607632 >
608633 { isSendingMessage || isTranscribing ? (
609634 < AnimatedView style = { rotationAnimatedStyle } >
@@ -616,7 +641,7 @@ const NormalMode = React.memo(({
616641 < Icon as = { ButtonIcon as any } size = { buttonIconSize } className = { buttonIconClass } strokeWidth = { 2 } />
617642 )
618643 ) }
619- </ AnimatedPressable >
644+ </ TouchableOpacity >
620645 </ View >
621646 </ View >
622647 </ >
0 commit comments