From 454ba2311f2f5b51c33311d47209fd41155f7d6e Mon Sep 17 00:00:00 2001 From: ehsan shariati Date: Wed, 4 Mar 2026 09:57:54 -0500 Subject: [PATCH 1/2] Added support to be able to add blox details to other apps --- apps/box/ios/Podfile.lock | 6 +- .../box/src/navigation/MainTabs.navigator.tsx | 5 + apps/box/src/navigation/NavContainer.tsx | 2 + apps/box/src/navigation/navigationConfig.ts | 6 + .../AutoPinPairing/AutoPinPairing.screen.tsx | 156 ++++++++++++++++++ package.json | 2 +- yarn.lock | 10 +- 7 files changed, 178 insertions(+), 9 deletions(-) create mode 100644 apps/box/src/screens/Settings/AutoPinPairing/AutoPinPairing.screen.tsx diff --git a/apps/box/ios/Podfile.lock b/apps/box/ios/Podfile.lock index 4f69a452..0ba8b32f 100644 --- a/apps/box/ios/Podfile.lock +++ b/apps/box/ios/Podfile.lock @@ -41,7 +41,7 @@ PODS: - nanopb (~> 3.30910.0) - PromisesSwift (~> 2.1) - fmt (11.0.2) - - Fula (1.57.7) + - Fula (1.58.0) - glog (0.3.5) - GoogleDataTransport (10.1.0): - nanopb (~> 3.30910.0) @@ -2016,12 +2016,12 @@ PODS: - react-native-config/App (= 1.5.1) - react-native-config/App (1.5.1): - React-Core - - react-native-fula (1.57.7): + - react-native-fula (1.58.0): - boost - DoubleConversion - fast_float - fmt - - Fula (~> 1.57.7) + - Fula (~> 1.58.0) - glog - hermes-engine - RCT-Folly diff --git a/apps/box/src/navigation/MainTabs.navigator.tsx b/apps/box/src/navigation/MainTabs.navigator.tsx index 7e5a8ce9..2c6adcbd 100644 --- a/apps/box/src/navigation/MainTabs.navigator.tsx +++ b/apps/box/src/navigation/MainTabs.navigator.tsx @@ -44,6 +44,7 @@ import { useUserProfileStore } from '../stores/useUserProfileStore'; import { useLogger } from '../hooks'; import { useBloxsStore } from '../stores'; import { BluetoothCommandsScreen } from '../screens/Settings/Bluetooth/BluetoothCommands.screen'; +import { AutoPinPairingScreen } from '../screens/Settings/AutoPinPairing/AutoPinPairing.screen'; import Zeroconf from 'react-native-zeroconf'; import { MDNSBloxService } from '../models'; @@ -343,6 +344,10 @@ const SettingsNavigator = () => { name={Routes.BluetoothCommands} component={BluetoothCommandsScreen} /> + ({ diff --git a/apps/box/src/navigation/NavContainer.tsx b/apps/box/src/navigation/NavContainer.tsx index 2e85c9d3..3a0cf459 100644 --- a/apps/box/src/navigation/NavContainer.tsx +++ b/apps/box/src/navigation/NavContainer.tsx @@ -21,6 +21,8 @@ const linking: LinkingOptions = { screens: { [Routes.ConnectedDApps]: '/connectdapp/:appName/:bundleId/:peerId/:returnDeepLink/:accountId', + [Routes.AutoPinPairing]: + '/autopin-pair', }, }, }, diff --git a/apps/box/src/navigation/navigationConfig.ts b/apps/box/src/navigation/navigationConfig.ts index 218bdc99..c9f65ea7 100644 --- a/apps/box/src/navigation/navigationConfig.ts +++ b/apps/box/src/navigation/navigationConfig.ts @@ -49,6 +49,7 @@ export enum Routes { ComponentGallery = 'Component Gallery', BloxLogs = 'BloxLogs', BluetoothCommands = 'BluetoothCommands', + AutoPinPairing = 'AutoPinPairing', // Component Gallery Avatars = 'Avatars', @@ -103,6 +104,11 @@ export type SettingsStackParamList = { [Routes.About]: undefined; [Routes.BloxLogs]: undefined; [Routes.BluetoothCommands]: undefined; + [Routes.AutoPinPairing]: { + token?: string; + endpoint?: string; + returnUrl?: string; + }; [Routes.ComponentGallery]: NavigatorScreenParams; }; diff --git a/apps/box/src/screens/Settings/AutoPinPairing/AutoPinPairing.screen.tsx b/apps/box/src/screens/Settings/AutoPinPairing/AutoPinPairing.screen.tsx new file mode 100644 index 00000000..2c1e58fe --- /dev/null +++ b/apps/box/src/screens/Settings/AutoPinPairing/AutoPinPairing.screen.tsx @@ -0,0 +1,156 @@ +import React, { useState } from 'react'; +import { Alert, Linking } from 'react-native'; +import { + FxBox, + FxButton, + FxSafeAreaBox, + FxText, +} from '@functionland/component-library'; +import { NativeStackScreenProps } from '@react-navigation/native-stack'; +import { blockchain, fula } from '@functionland/react-native-fula'; +import { + Routes, + SettingsStackParamList, +} from '../../../navigation/navigationConfig'; +import { useBloxsStore } from '../../../stores/useBloxsStore'; +import { useDAppsStore } from '../../../stores/dAppsSettingsStore'; + +type Props = NativeStackScreenProps< + SettingsStackParamList, + Routes.AutoPinPairing +>; + +export const AutoPinPairingScreen = ({ route }: Props) => { + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + const [success, setSuccess] = useState(false); + + const bloxs = useBloxsStore((state) => state.bloxs); + const currentBloxPeerId = useBloxsStore((state) => state.currentBloxPeerId); + const addOrUpdateDApp = useDAppsStore((state) => state.addOrUpdateDApp); + + const token = route?.params?.token; + const endpoint = route?.params?.endpoint; + const returnUrl = route?.params?.returnUrl; + + const currentBlox = bloxs[currentBloxPeerId]; + const bloxName = currentBlox?.name || 'My Blox'; + + const handlePair = async () => { + if (!token || !endpoint) { + setError('Missing pairing parameters'); + return; + } + + setLoading(true); + setError(null); + + try { + await fula.isReady(false); + + const result = await blockchain.autoPinPair(token, endpoint); + + if (result?.pairing_secret) { + setSuccess(true); + + // Register as connected dApp + addOrUpdateDApp({ + name: 'FxFiles Auto-Pin', + peerId: '', + bundleId: 'land.fx.files', + bloxPeerId: currentBloxPeerId, + authorized: true, + lastUpdate: new Date(), + storageUsed: 0, + }); + + // Return to FxFiles with pairing data + if (returnUrl) { + const finalUrl = decodeURIComponent(returnUrl) + .replace('$secret', encodeURIComponent(result.pairing_secret)) + .replace('$hardwareId', encodeURIComponent(result.hardware_id || '')) + .replace('$bloxPeerId', encodeURIComponent(currentBloxPeerId || '')) + .replace('$bloxName', encodeURIComponent(bloxName)); + + Alert.alert( + 'Pairing Successful', + `Auto-pinning is now enabled on ${bloxName}. Return to FxFiles?`, + [ + { text: 'Stay Here', style: 'cancel' }, + { + text: 'Open FxFiles', + onPress: () => { + Linking.openURL(finalUrl); + }, + }, + ] + ); + } else { + Alert.alert( + 'Pairing Successful', + `Auto-pinning is now enabled on ${bloxName}.` + ); + } + } else { + setError('Unexpected response from blox'); + } + } catch (e: any) { + const msg = e?.message || e?.toString() || 'Unknown error'; + setError(msg); + } finally { + setLoading(false); + } + }; + + // Note: We intentionally don't auto-trigger pairing. + // User must read the confirmation and press the button. + + return ( + + + + Auto-Pin Pairing + + + + FxFiles wants to enable auto-pinning on your blox. This will + automatically pin your uploaded files to{' '} + {bloxName}, allowing you to + download them directly from your local network. + + + {error && ( + + {error} + + )} + + {success ? ( + + + Auto-pinning is enabled! Your files will be automatically pinned + to this blox. + + + ) : ( + + {loading ? 'Pairing...' : 'Enable Auto-Pin'} + + )} + + + ); +}; diff --git a/package.json b/package.json index a2968f15..42a34eb8 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "@babel/preset-env": "^7.27.2", "@ethersproject/shims": "^5.7.0", "@functionland/fula-sec": "^2.0.0", - "@functionland/react-native-fula": "1.57.7", + "@functionland/react-native-fula": "1.58.0", "@gorhom/bottom-sheet": "^5.2.8", "@notifee/react-native": "^9.1.8", "@react-native-async-storage/async-storage": "^2.2.0", diff --git a/yarn.lock b/yarn.lock index c2b8bbf1..0679a237 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3027,9 +3027,9 @@ __metadata: languageName: node linkType: hard -"@functionland/react-native-fula@npm:1.57.7": - version: 1.57.7 - resolution: "@functionland/react-native-fula@npm:1.57.7" +"@functionland/react-native-fula@npm:1.58.0": + version: 1.58.0 + resolution: "@functionland/react-native-fula@npm:1.58.0" dependencies: "@react-native/metro-config": ^0.80.2 text-encoding: ^0.7.0 @@ -3039,7 +3039,7 @@ __metadata: "@babel/preset-env": ^7.1.6 react: "*" react-native: 0.73.11 - checksum: 2a44a5ba30612de713ac9eee22fa55f9b9e7302c79ff45184c7635b6c11998b4e566f02a792256a6bad42b6113903e9b2fe7baf5eb72f73f686167b4e696a042 + checksum: 20a6f923495ca8572eadcd08ad5066ba0d504447257b10fe33ce84e3c5f8b3b48dba081ce447ee7200899a7a85ed2dba4cbd1266683329e026c227a62950aafa languageName: node linkType: hard @@ -13086,7 +13086,7 @@ __metadata: "@babel/preset-env": ^7.27.2 "@ethersproject/shims": ^5.7.0 "@functionland/fula-sec": ^2.0.0 - "@functionland/react-native-fula": 1.57.7 + "@functionland/react-native-fula": 1.58.0 "@gorhom/bottom-sheet": ^5.2.8 "@notifee/react-native": ^9.1.8 "@nrwl/js": 19.8.4 From 551e1b6c977baa40243115949c1a25efce056b23 Mon Sep 17 00:00:00 2001 From: ehsan shariati Date: Wed, 4 Mar 2026 23:07:50 -0500 Subject: [PATCH 2/2] handle already paired box --- apps/box/android/app/build.gradle | 4 ++-- apps/box/ios/Box.xcodeproj/project.pbxproj | 4 ++-- apps/box/package.json | 2 +- .../components/Cards/ConnectedDevicesCard.tsx | 6 ++++++ apps/box/src/i18n/locales/en/translation.json | 1 + apps/box/src/i18n/locales/zh/translation.json | 1 + apps/box/src/models/blox.ts | 1 + .../AutoPinPairing/AutoPinPairing.screen.tsx | 18 +++++++++++------- apps/box/src/stores/useBloxsStore.ts | 10 ++++++++++ 9 files changed, 35 insertions(+), 12 deletions(-) diff --git a/apps/box/android/app/build.gradle b/apps/box/android/app/build.gradle index d9130c9b..c609e394 100644 --- a/apps/box/android/app/build.gradle +++ b/apps/box/android/app/build.gradle @@ -86,8 +86,8 @@ android { applicationId "land.fx.blox" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 255 - versionName "2.4.1" + versionCode 256 + versionName "2.5.0" testBuildType System.getProperty('testBuildType', 'debug') testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' diff --git a/apps/box/ios/Box.xcodeproj/project.pbxproj b/apps/box/ios/Box.xcodeproj/project.pbxproj index af495186..0a8a01d1 100644 --- a/apps/box/ios/Box.xcodeproj/project.pbxproj +++ b/apps/box/ios/Box.xcodeproj/project.pbxproj @@ -589,7 +589,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 2.4.0; + MARKETING_VERSION = 2.5.0; OTHER_LDFLAGS = ( "$(inherited)", "-ObjC", @@ -627,7 +627,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 2.4.0; + MARKETING_VERSION = 2.5.0; OTHER_LDFLAGS = ( "$(inherited)", "-ObjC", diff --git a/apps/box/package.json b/apps/box/package.json index 518a247e..1e368c2e 100644 --- a/apps/box/package.json +++ b/apps/box/package.json @@ -1,6 +1,6 @@ { "name": "box", - "version": "2.4.1", + "version": "2.5.0", "private": true, "dependencies": { "@babel/core": "*", diff --git a/apps/box/src/components/Cards/ConnectedDevicesCard.tsx b/apps/box/src/components/Cards/ConnectedDevicesCard.tsx index e21420c7..8985e75c 100644 --- a/apps/box/src/components/Cards/ConnectedDevicesCard.tsx +++ b/apps/box/src/components/Cards/ConnectedDevicesCard.tsx @@ -88,6 +88,12 @@ export const DeviceCard = ({ {convertByteToCapacityUnit(parseInt(folderInfo?.chain, 10))} + + {t('connectedDevicesCard.userOwnData')} + + {convertByteToCapacityUnit(parseInt(folderInfo?.userOwnData, 10))} + + {used != undefined && ( {t('connectedDevicesCard.used')} diff --git a/apps/box/src/i18n/locales/en/translation.json b/apps/box/src/i18n/locales/en/translation.json index d13b7f00..de4aea1b 100644 --- a/apps/box/src/i18n/locales/en/translation.json +++ b/apps/box/src/i18n/locales/en/translation.json @@ -193,6 +193,7 @@ "capacity": "Capacity", "storedFiles": "Stored Files", "otherData": "Other Data", + "userOwnData": "User Own Data", "used": "Used", "free": "Free", "status": "Status", diff --git a/apps/box/src/i18n/locales/zh/translation.json b/apps/box/src/i18n/locales/zh/translation.json index 75ad1733..ea0f8c67 100644 --- a/apps/box/src/i18n/locales/zh/translation.json +++ b/apps/box/src/i18n/locales/zh/translation.json @@ -186,6 +186,7 @@ "capacity": "容量", "storedFiles": "存储文件", "otherData": "其他数据", + "userOwnData": "用户自有数据", "used": "已使用", "free": "可用", "status": "状态", diff --git a/apps/box/src/models/blox.ts b/apps/box/src/models/blox.ts index 41b39cd3..a7fe2160 100644 --- a/apps/box/src/models/blox.ts +++ b/apps/box/src/models/blox.ts @@ -14,6 +14,7 @@ export interface TBloxFolderSize { fula: string; chain: string; fulaCount: string; + userOwnData: string; } export type TBloxConectionStatus = | 'CONNECTED' diff --git a/apps/box/src/screens/Settings/AutoPinPairing/AutoPinPairing.screen.tsx b/apps/box/src/screens/Settings/AutoPinPairing/AutoPinPairing.screen.tsx index 2c1e58fe..b9f85a37 100644 --- a/apps/box/src/screens/Settings/AutoPinPairing/AutoPinPairing.screen.tsx +++ b/apps/box/src/screens/Settings/AutoPinPairing/AutoPinPairing.screen.tsx @@ -20,7 +20,7 @@ type Props = NativeStackScreenProps< Routes.AutoPinPairing >; -export const AutoPinPairingScreen = ({ route }: Props) => { +export const AutoPinPairingScreen = ({ route, navigation }: Props) => { const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const [success, setSuccess] = useState(false); @@ -53,6 +53,12 @@ export const AutoPinPairingScreen = ({ route }: Props) => { if (result?.pairing_secret) { setSuccess(true); + const alreadyPaired = result.status === 'already_paired'; + const alertTitle = alreadyPaired ? 'Already Paired' : 'Pairing Successful'; + const alertMsg = alreadyPaired + ? `Auto-pinning was already enabled on ${bloxName}.` + : `Auto-pinning is now enabled on ${bloxName}.`; + // Register as connected dApp addOrUpdateDApp({ name: 'FxFiles Auto-Pin', @@ -73,23 +79,21 @@ export const AutoPinPairingScreen = ({ route }: Props) => { .replace('$bloxName', encodeURIComponent(bloxName)); Alert.alert( - 'Pairing Successful', - `Auto-pinning is now enabled on ${bloxName}. Return to FxFiles?`, + alertTitle, + `${alertMsg} Return to FxFiles?`, [ { text: 'Stay Here', style: 'cancel' }, { text: 'Open FxFiles', onPress: () => { + navigation.navigate(Routes.Settings); Linking.openURL(finalUrl); }, }, ] ); } else { - Alert.alert( - 'Pairing Successful', - `Auto-pinning is now enabled on ${bloxName}.` - ); + Alert.alert(alertTitle, alertMsg); } } else { setError('Unexpected response from blox'); diff --git a/apps/box/src/stores/useBloxsStore.ts b/apps/box/src/stores/useBloxsStore.ts index dfabf11d..a798e25f 100644 --- a/apps/box/src/stores/useBloxsStore.ts +++ b/apps/box/src/stores/useBloxsStore.ts @@ -219,12 +219,18 @@ const createModeSlice: StateCreator< fula: '-1', chain: '-1', fulaCount: '-1', + userOwnData: '-1', }; let chainFolderInfo: GetFolderPathResponse = { size: '-1', folder_path: '/uniondrive/chain', }; const chainFolderSize = await fxblox.getFolderSize('/uniondrive/chain'); + let userOwnDataFolderInfo: GetFolderPathResponse = { + size: '-1', + folder_path: '/uniondrive/ipfs_datastore_local', + }; + const userOwnDataFolderSize = await fxblox.getFolderSize('/uniondrive/ipfs_datastore_local'); console.log('chainFolderSize', chainFolderSize); let fulaFolderInfo: GetDatastoreSizeResponse = { size: '-1', @@ -244,10 +250,14 @@ const createModeSlice: StateCreator< if (fulaFolderSize?.size) { fulaFolderInfo = fulaFolderSize; } + if (userOwnDataFolderSize?.size) { + userOwnDataFolderInfo = userOwnDataFolderSize; + } folderSizeInfo_tmp = { fula: fulaFolderInfo.size, fulaCount: fulaFolderInfo.count, chain: chainFolderInfo.size, + userOwnData: userOwnDataFolderInfo.size, }; set({ folderSizeInfo: {