1
1
import { WebView } from "react-native-webview" ;
2
- import {
3
- Button ,
4
- Modal ,
5
- SafeAreaView ,
6
- StyleSheet ,
7
- Text ,
8
- View ,
9
- } from "react-native" ;
2
+ import { StyleSheet , View } from "react-native" ;
3
+ import { Button , Card , Layout , Text } from "@ui-kitten/components" ;
10
4
import { oreoWallet } from "@/data/wallet/oreowalletWallet" ;
11
5
import { Network } from "@/data/constants" ;
12
- import { useRef , useState } from "react" ;
6
+ import { useCallback , useRef , useState } from "react" ;
13
7
import * as Uint8ArrayUtils from "@/utils/uint8Array" ;
14
8
import { useFacade } from "@/data/facades" ;
15
9
import { Output } from "@/data/facades/wallet/types" ;
16
10
import SendTransactionModal from "@/components/browser/SendTransactionModal" ;
11
+ import { Image } from "expo-image" ;
17
12
import Stack from "expo-router/stack" ;
13
+ import {
14
+ BottomSheetModal ,
15
+ BottomSheetView ,
16
+ BottomSheetModalProvider ,
17
+ BottomSheetBackdrop ,
18
+ } from "@gorhom/bottom-sheet" ;
19
+ import { SettingsKey } from "@/data/settings/db" ;
18
20
19
21
type Message = {
20
22
id : number ;
@@ -112,6 +114,15 @@ class MessageHandler {
112
114
data : { address } ,
113
115
} ) ,
114
116
) ;
117
+ } else if ( message . type === "disconnect" ) {
118
+ this . updateActiveAccount ( null ) ;
119
+ postMessage ?.(
120
+ JSON . stringify ( {
121
+ id : message . id ,
122
+ type : "disconnect" ,
123
+ data : null ,
124
+ } ) ,
125
+ ) ;
115
126
} else if ( message . type === "getBalances" ) {
116
127
if ( oreoWallet . state . type !== "STARTED" || ! this . activeAccount ) {
117
128
console . error ( "Wallet not started" ) ;
@@ -191,13 +202,44 @@ export default function MenuDebugBrowser() {
191
202
const webref = useRef < WebView | null > ( null ) ;
192
203
const messageHandler = useRef ( new MessageHandler ( ) ) ;
193
204
const facade = useFacade ( ) ;
205
+ const bottomSheetModalRef = useRef < BottomSheetModal > ( null ) ;
206
+
207
+ const settings = facade . getAppSettings . useQuery ( undefined ) ;
208
+ const network = settings . data
209
+ ? BRIDGE_URLS [ settings . data [ SettingsKey . Network ] ]
210
+ : null ;
194
211
195
212
const [ accountModalVisible , setAccountModalVisible ] = useState ( false ) ;
196
213
const [ sendTransactionData , setSendTransactionData ] =
197
214
useState < GeneralTransactionData | null > ( null ) ;
198
- const accounts = facade . getAccounts . useQuery ( undefined , {
199
- enabled : accountModalVisible ,
200
- } ) ;
215
+ const account = facade . getAccount . useQuery (
216
+ { } ,
217
+ {
218
+ enabled : accountModalVisible ,
219
+ } ,
220
+ ) ;
221
+
222
+ const handlePresentModalPress = useCallback ( ( ) => {
223
+ bottomSheetModalRef . current ?. present ( ) ;
224
+ setAccountModalVisible ( true ) ;
225
+ } , [ ] ) ;
226
+
227
+ const handleDismissModalPress = useCallback ( ( ) => {
228
+ bottomSheetModalRef . current ?. dismiss ( ) ;
229
+ setAccountModalVisible ( false ) ;
230
+ } , [ ] ) ;
231
+
232
+ const renderBackdrop = useCallback (
233
+ ( props : any ) => (
234
+ < BottomSheetBackdrop
235
+ { ...props }
236
+ disappearsOnIndex = { - 1 }
237
+ appearsOnIndex = { 0 }
238
+ opacity = { 0.5 }
239
+ />
240
+ ) ,
241
+ [ ] ,
242
+ ) ;
201
243
202
244
const js = `
203
245
window.addEventListener('message', (event) => {
@@ -215,6 +257,8 @@ export default function MenuDebugBrowser() {
215
257
216
258
if (message.type === "connect") {
217
259
window.rpccalls[message.id].resolve(message.data.address);
260
+ } else if (message.type === "disconnect") {
261
+ window.rpccalls[message.id].resolve(null);
218
262
} else if (message.type === "getBalances") {
219
263
window.rpccalls[message.id].resolve(message.data.balances);
220
264
} else if (message.type === "generalTransaction") {
@@ -252,6 +296,20 @@ export default function MenuDebugBrowser() {
252
296
console.log(result);
253
297
return result;
254
298
}
299
+ async disconnect() {
300
+ const id = window.rpccounter++;
301
+ window.ReactNativeWebView.postMessage(JSON.stringify({
302
+ id,
303
+ type: "disconnect",
304
+ data: null,
305
+ }));
306
+ const result = await new Promise((resolve, reject) => {
307
+ window.rpccalls[id] = { resolve, reject };
308
+ });
309
+ this.#address = null;
310
+ console.log("Disconnected");
311
+ return null;
312
+ }
255
313
async getBalances() {
256
314
if (!this.#address) {
257
315
throw new Error("Connect first");
@@ -306,89 +364,134 @@ export default function MenuDebugBrowser() {
306
364
` ;
307
365
308
366
return (
309
- < >
367
+ < BottomSheetModalProvider >
310
368
< Stack . Screen
311
369
options = { {
312
370
headerTitle : "Bridge" ,
313
371
headerBackTitle : "Back" ,
314
372
} }
315
373
/>
316
- < View style = { styles . container } >
317
- < Modal
318
- animationType = "slide"
319
- visible = { accountModalVisible }
320
- onRequestClose = { ( ) => {
321
- messageHandler . current . updateActiveAccount ( null ) ;
322
- setAccountModalVisible ( false ) ;
323
- } }
324
- >
325
- < SafeAreaView >
326
- < View style = { { paddingTop : 40 , paddingHorizontal : 4 } } >
327
- < Text style = { { fontSize : 20 , textAlign : "center" } } >
328
- This website would like to connect to your wallet.
329
- </ Text >
330
- < Text style = { { textAlign : "center" } } >
331
- Choose an account to connect, or click Cancel.
374
+ { network && (
375
+ < View style = { styles . container } >
376
+ < BottomSheetModal
377
+ ref = { bottomSheetModalRef }
378
+ snapPoints = { [ "50%" ] }
379
+ enablePanDownToClose
380
+ backdropComponent = { renderBackdrop }
381
+ onDismiss = { ( ) => {
382
+ messageHandler . current . updateActiveAccount ( null ) ;
383
+ setAccountModalVisible ( false ) ;
384
+ } }
385
+ backgroundStyle = { styles . bottomSheetModal }
386
+ >
387
+ < BottomSheetView style = { styles . bottomSheetContent } >
388
+ < Layout style = { { flexDirection : "row" , gap : 8 } } >
389
+ < Image
390
+ source = { network + "favicon.ico" }
391
+ style = { { width : 48 , height : 48 } }
392
+ />
393
+ < Layout style = { { gap : 2 } } >
394
+ < Text category = "h5" > Iron Fish Bridge</ Text >
395
+ < Text category = "s2" appearance = "hint" >
396
+ { network }
397
+ </ Text >
398
+ </ Layout >
399
+ </ Layout >
400
+ < Text style = { styles . modalSubtitle } >
401
+ Allow this site to view your account's balances and
402
+ transactions?
332
403
</ Text >
333
- { accounts . data ?. map ( ( a ) => (
404
+ < Card >
405
+ < Text category = "h6" > { account . data ?. name } </ Text >
406
+ < Text category = "s2" appearance = "hint" >
407
+ { account . data ?. publicAddress }
408
+ </ Text >
409
+ </ Card >
410
+ < Layout
411
+ style = { { flexDirection : "row" , gap : 8 , marginBottom : 32 } }
412
+ >
334
413
< Button
335
- key = { a . name }
336
414
onPress = { ( ) => {
415
+ if ( ! account . data ) {
416
+ console . error ( "No account loaded" ) ;
417
+ return ;
418
+ }
337
419
messageHandler . current . updateActiveAccount ( {
338
- name : a . name ,
339
- address : a . publicAddress ,
420
+ name : account . data . name ,
421
+ address : account . data . publicAddress ,
340
422
} ) ;
341
- setAccountModalVisible ( false ) ;
423
+ handleDismissModalPress ( ) ;
342
424
} }
343
- title = { `${ a . name } (${ a . balances . iron . confirmed } $IRON)` }
344
- />
345
- ) ) }
346
- < Button
347
- onPress = { ( ) => {
348
- messageHandler . current . updateActiveAccount ( null ) ;
349
- setAccountModalVisible ( false ) ;
350
- } }
351
- title = "Cancel"
352
- />
353
- </ View >
354
- </ SafeAreaView >
355
- </ Modal >
356
- < SendTransactionModal
357
- sendTransactionData = { sendTransactionData }
358
- cancel = { ( ) => {
359
- messageHandler . current . rejectSendTransactionRequest ( ) ;
360
- setSendTransactionData ( null ) ;
361
- } }
362
- success = { ( hash ) => {
363
- messageHandler . current . resolveSendTransactionRequest ( hash ) ;
364
- setSendTransactionData ( null ) ;
365
- } }
366
- />
367
- < WebView
368
- source = { { uri : BRIDGE_URLS [ Network . MAINNET ] } }
369
- ref = { ( r ) => ( webref . current = r ) }
370
- injectedJavaScriptBeforeContentLoaded = { js }
371
- onMessage = { ( event ) => {
372
- messageHandler . current . handleMessage (
373
- event . nativeEvent . data ,
374
- ( ) => {
375
- setAccountModalVisible ( true ) ;
376
- } ,
377
- ( data ) => {
378
- setSendTransactionData ( data ) ;
379
- } ,
380
- webref . current ?. postMessage ,
381
- ) ;
382
- } }
383
- webviewDebuggingEnabled
384
- />
385
- </ View >
386
- </ >
425
+ style = { { flex : 1 } }
426
+ >
427
+ Confirm
428
+ </ Button >
429
+ < Button
430
+ onPress = { ( ) => {
431
+ messageHandler . current . updateActiveAccount ( null ) ;
432
+ handleDismissModalPress ( ) ;
433
+ } }
434
+ style = { { flex : 1 } }
435
+ appearance = "outline"
436
+ >
437
+ Cancel
438
+ </ Button >
439
+ </ Layout >
440
+ </ BottomSheetView >
441
+ </ BottomSheetModal >
442
+ < SendTransactionModal
443
+ sendTransactionData = { sendTransactionData }
444
+ cancel = { ( ) => {
445
+ messageHandler . current . rejectSendTransactionRequest ( ) ;
446
+ setSendTransactionData ( null ) ;
447
+ } }
448
+ success = { ( hash ) => {
449
+ messageHandler . current . resolveSendTransactionRequest ( hash ) ;
450
+ setSendTransactionData ( null ) ;
451
+ } }
452
+ />
453
+ < WebView
454
+ source = { { uri : network } }
455
+ ref = { ( r ) => ( webref . current = r ) }
456
+ injectedJavaScriptBeforeContentLoaded = { js }
457
+ onMessage = { ( event ) => {
458
+ messageHandler . current . handleMessage (
459
+ event . nativeEvent . data ,
460
+ handlePresentModalPress ,
461
+ ( data ) => {
462
+ setSendTransactionData ( data ) ;
463
+ } ,
464
+ webref . current ?. postMessage ,
465
+ ) ;
466
+ } }
467
+ webviewDebuggingEnabled
468
+ />
469
+ </ View >
470
+ ) }
471
+ </ BottomSheetModalProvider >
387
472
) ;
388
473
}
389
474
390
475
const styles = StyleSheet . create ( {
391
476
container : {
392
477
flex : 1 ,
393
478
} ,
479
+ bottomSheetModal : {
480
+ shadowColor : "#000" ,
481
+ shadowOffset : {
482
+ width : 0 ,
483
+ height : 6 ,
484
+ } ,
485
+ shadowOpacity : 0.37 ,
486
+ shadowRadius : 7.49 ,
487
+
488
+ elevation : 12 ,
489
+ } ,
490
+ bottomSheetContent : {
491
+ padding : 16 ,
492
+ gap : 16 ,
493
+ } ,
494
+ modalSubtitle : {
495
+ textAlign : "center" ,
496
+ } ,
394
497
} ) ;
0 commit comments