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/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/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/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..b9f85a37
--- /dev/null
+++ b/apps/box/src/screens/Settings/AutoPinPairing/AutoPinPairing.screen.tsx
@@ -0,0 +1,160 @@
+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, navigation }: 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);
+
+ 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',
+ 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(
+ alertTitle,
+ `${alertMsg} Return to FxFiles?`,
+ [
+ { text: 'Stay Here', style: 'cancel' },
+ {
+ text: 'Open FxFiles',
+ onPress: () => {
+ navigation.navigate(Routes.Settings);
+ Linking.openURL(finalUrl);
+ },
+ },
+ ]
+ );
+ } else {
+ Alert.alert(alertTitle, alertMsg);
+ }
+ } 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/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: {
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