99 StyleSheet ,
1010 Text ,
1111 TextInput ,
12+ TouchableOpacity ,
1213 TouchableWithoutFeedback ,
1314 View ,
1415} from 'react-native' ;
@@ -82,9 +83,64 @@ const spinnerStyles = StyleSheet.create({
8283 } ,
8384} ) ;
8485
86+ function ErrorBanner ( {
87+ message,
88+ onDismiss,
89+ } : {
90+ message : string | null ;
91+ onDismiss : ( ) => void ;
92+ } ) {
93+ if ( ! message ) return null ;
94+ return (
95+ < View style = { errorBannerStyles . container } >
96+ < Text style = { errorBannerStyles . message } numberOfLines = { 3 } >
97+ { message }
98+ </ Text >
99+ < TouchableOpacity
100+ onPress = { onDismiss }
101+ style = { errorBannerStyles . closeButton }
102+ >
103+ < Text style = { errorBannerStyles . closeText } > ✕</ Text >
104+ </ TouchableOpacity >
105+ </ View >
106+ ) ;
107+ }
108+
109+ const errorBannerStyles = StyleSheet . create ( {
110+ container : {
111+ backgroundColor : '#FEE2E2' ,
112+ borderLeftWidth : 4 ,
113+ borderLeftColor : '#EF4444' ,
114+ borderRadius : 8 ,
115+ marginHorizontal : 16 ,
116+ marginVertical : 8 ,
117+ paddingVertical : 10 ,
118+ paddingLeft : 12 ,
119+ paddingRight : 8 ,
120+ flexDirection : 'row' ,
121+ alignItems : 'center' ,
122+ } ,
123+ message : {
124+ flex : 1 ,
125+ color : '#991B1B' ,
126+ fontSize : 14 ,
127+ lineHeight : 20 ,
128+ } ,
129+ closeButton : {
130+ padding : 4 ,
131+ marginLeft : 8 ,
132+ } ,
133+ closeText : {
134+ color : '#991B1B' ,
135+ fontSize : 16 ,
136+ fontWeight : '600' ,
137+ } ,
138+ } ) ;
139+
85140function App ( ) {
86141 const [ userInput , setUserInput ] = useState ( '' ) ;
87142 const [ isTextInputFocused , setIsTextInputFocused ] = useState ( false ) ;
143+ const [ error , setError ] = useState < string | null > ( null ) ;
88144 const textInputRef = useRef < TextInput > ( null ) ;
89145 const scrollViewRef = useRef < ScrollView > ( null ) ;
90146
@@ -97,9 +153,7 @@ function App() {
97153 // } });
98154
99155 useEffect ( ( ) => {
100- if ( llm . error ) {
101- console . log ( 'LLM error:' , llm . error ) ;
102- }
156+ if ( llm . error ) setError ( String ( llm . error ) ) ;
103157 } , [ llm . error ] ) ;
104158
105159 const sendMessage = async ( ) => {
@@ -110,7 +164,7 @@ function App() {
110164 try {
111165 await llm . sendMessage ( userInput ) ;
112166 } catch ( e ) {
113- console . error ( e ) ;
167+ setError ( e instanceof Error ? e . message : String ( e ) ) ;
114168 }
115169 } ;
116170
@@ -122,11 +176,12 @@ function App() {
122176 keyboardVerticalOffset = { Platform . OS === 'ios' ? 100 : 0 }
123177 >
124178 < Spinner
125- visible = { ! llm . isReady }
179+ visible = { ! llm . isReady && ! llm . error }
126180 textContent = { `Loading model ${ ( llm . downloadProgress * 100 ) . toFixed ( 0 ) } %` }
127181 />
128182
129183 < SafeAreaView style = { styles . content } >
184+ < ErrorBanner message = { error } onDismiss = { ( ) => setError ( null ) } />
130185 { llm . messageHistory . length > 0 || llm . isGenerating ? (
131186 < ScrollView
132187 ref = { scrollViewRef }
0 commit comments