feat: Added download and loading

This commit is contained in:
Fándly Gergő 2022-07-04 10:05:36 +03:00
parent ed47ff673f
commit 4250284f1b
10 changed files with 131 additions and 61 deletions

View File

@ -285,6 +285,8 @@ dependencies {
} else { } else {
implementation jscFlavor implementation jscFlavor
} }
implementation project(':react-native-fs')
} }
if (isNewArchitectureEnabled()) { if (isNewArchitectureEnabled()) {

View File

@ -2,6 +2,8 @@
package="com.browses3"> package="com.browses3">
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application <application
android:name=".MainApplication" android:name=".MainApplication"
@ -9,7 +11,8 @@
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round" android:roundIcon="@mipmap/ic_launcher_round"
android:allowBackup="false" android:allowBackup="false"
android:theme="@style/AppTheme"> android:theme="@style/AppTheme"
android:requestLegacyExternalStorage="true">
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:label="@string/app_name" android:label="@string/app_name"

View File

@ -2,6 +2,8 @@ rootProject.name = 'BrowseS3'
apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings) apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings)
include ':app' include ':app'
includeBuild('../node_modules/react-native-gradle-plugin') includeBuild('../node_modules/react-native-gradle-plugin')
include ':react-native-fs'
project(':react-native-fs').projectDir = new File(settingsDir, '../node_modules/react-native-fs/android')
if (settings.hasProperty("newArchEnabled") && settings.newArchEnabled == "true") { if (settings.hasProperty("newArchEnabled") && settings.newArchEnabled == "true") {
include(":ReactAndroid") include(":ReactAndroid")

90
package-lock.json generated
View File

@ -17,10 +17,10 @@
"pretty-bytes": "^6.0.0", "pretty-bytes": "^6.0.0",
"react": "18.0.0", "react": "18.0.0",
"react-native": "0.69.1", "react-native": "0.69.1",
"react-native-fs": "^2.20.0",
"react-native-keyboard-aware-scroll-view": "^0.9.5", "react-native-keyboard-aware-scroll-view": "^0.9.5",
"react-native-safe-area-context": "^4.3.1", "react-native-safe-area-context": "^4.3.1",
"react-native-screens": "^3.14.0", "react-native-screens": "^3.14.0"
"rn-fetch-blob": "^0.12.0"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.12.9", "@babel/core": "^7.12.9",
@ -12840,6 +12840,24 @@
"nullthrows": "^1.1.1" "nullthrows": "^1.1.1"
} }
}, },
"node_modules/react-native-fs": {
"version": "2.20.0",
"resolved": "https://registry.npmjs.org/react-native-fs/-/react-native-fs-2.20.0.tgz",
"integrity": "sha512-VkTBzs7fIDUiy/XajOSNk0XazFE9l+QlMAce7lGuebZcag5CnjszB+u4BdqzwaQOdcYb5wsJIsqq4kxInIRpJQ==",
"dependencies": {
"base-64": "^0.1.0",
"utf8": "^3.0.0"
},
"peerDependencies": {
"react-native": "*",
"react-native-windows": "*"
},
"peerDependenciesMeta": {
"react-native-windows": {
"optional": true
}
}
},
"node_modules/react-native-gradle-plugin": { "node_modules/react-native-gradle-plugin": {
"version": "0.0.7", "version": "0.0.7",
"resolved": "https://registry.npmjs.org/react-native-gradle-plugin/-/react-native-gradle-plugin-0.0.7.tgz", "resolved": "https://registry.npmjs.org/react-native-gradle-plugin/-/react-native-gradle-plugin-0.0.7.tgz",
@ -13278,31 +13296,6 @@
"url": "https://github.com/sponsors/isaacs" "url": "https://github.com/sponsors/isaacs"
} }
}, },
"node_modules/rn-fetch-blob": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/rn-fetch-blob/-/rn-fetch-blob-0.12.0.tgz",
"integrity": "sha512-+QnR7AsJ14zqpVVUbzbtAjq0iI8c9tCg49tIoKO2ezjzRunN7YL6zFSFSWZm6d+mE/l9r+OeDM3jmb2tBb2WbA==",
"dependencies": {
"base-64": "0.1.0",
"glob": "7.0.6"
}
},
"node_modules/rn-fetch-blob/node_modules/glob": {
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.0.6.tgz",
"integrity": "sha512-f8c0rE8JiCxpa52kWPAOa3ZaYEnzofDzCQLCn3Vdk0Z5OVLq3BsRFJI4S4ykpeVW6QMGBUkMeUpoEgWnMTnw5Q==",
"dependencies": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.0.2",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
},
"engines": {
"node": "*"
}
},
"node_modules/rsvp": { "node_modules/rsvp": {
"version": "4.8.5", "version": "4.8.5",
"resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz", "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz",
@ -15196,6 +15189,11 @@
"react": "^16.8.0 || ^17.0.0 || ^18.0.0" "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
} }
}, },
"node_modules/utf8": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz",
"integrity": "sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ=="
},
"node_modules/util-deprecate": { "node_modules/util-deprecate": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
@ -25180,6 +25178,15 @@
"nullthrows": "^1.1.1" "nullthrows": "^1.1.1"
} }
}, },
"react-native-fs": {
"version": "2.20.0",
"resolved": "https://registry.npmjs.org/react-native-fs/-/react-native-fs-2.20.0.tgz",
"integrity": "sha512-VkTBzs7fIDUiy/XajOSNk0XazFE9l+QlMAce7lGuebZcag5CnjszB+u4BdqzwaQOdcYb5wsJIsqq4kxInIRpJQ==",
"requires": {
"base-64": "^0.1.0",
"utf8": "^3.0.0"
}
},
"react-native-gradle-plugin": { "react-native-gradle-plugin": {
"version": "0.0.7", "version": "0.0.7",
"resolved": "https://registry.npmjs.org/react-native-gradle-plugin/-/react-native-gradle-plugin-0.0.7.tgz", "resolved": "https://registry.npmjs.org/react-native-gradle-plugin/-/react-native-gradle-plugin-0.0.7.tgz",
@ -25503,30 +25510,6 @@
"glob": "^7.1.3" "glob": "^7.1.3"
} }
}, },
"rn-fetch-blob": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/rn-fetch-blob/-/rn-fetch-blob-0.12.0.tgz",
"integrity": "sha512-+QnR7AsJ14zqpVVUbzbtAjq0iI8c9tCg49tIoKO2ezjzRunN7YL6zFSFSWZm6d+mE/l9r+OeDM3jmb2tBb2WbA==",
"requires": {
"base-64": "0.1.0",
"glob": "7.0.6"
},
"dependencies": {
"glob": {
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.0.6.tgz",
"integrity": "sha512-f8c0rE8JiCxpa52kWPAOa3ZaYEnzofDzCQLCn3Vdk0Z5OVLq3BsRFJI4S4ykpeVW6QMGBUkMeUpoEgWnMTnw5Q==",
"requires": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.0.2",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
}
}
}
},
"rsvp": { "rsvp": {
"version": "4.8.5", "version": "4.8.5",
"resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz", "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz",
@ -27019,6 +27002,11 @@
"integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==",
"requires": {} "requires": {}
}, },
"utf8": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz",
"integrity": "sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ=="
},
"util-deprecate": { "util-deprecate": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",

View File

@ -19,10 +19,10 @@
"pretty-bytes": "^6.0.0", "pretty-bytes": "^6.0.0",
"react": "18.0.0", "react": "18.0.0",
"react-native": "0.69.1", "react-native": "0.69.1",
"react-native-fs": "^2.20.0",
"react-native-keyboard-aware-scroll-view": "^0.9.5", "react-native-keyboard-aware-scroll-view": "^0.9.5",
"react-native-safe-area-context": "^4.3.1", "react-native-safe-area-context": "^4.3.1",
"react-native-screens": "^3.14.0", "react-native-screens": "^3.14.0"
"rn-fetch-blob": "^0.12.0"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.12.9", "@babel/core": "^7.12.9",

View File

@ -41,7 +41,6 @@ const useSettings = () => {
ToastAndroid.show('Successfully saved settings', ToastAndroid.SHORT); ToastAndroid.show('Successfully saved settings', ToastAndroid.SHORT);
}) })
.catch(e => { .catch(e => {
console.log(e);
ToastAndroid.show('Failed to save settings', ToastAndroid.SHORT); ToastAndroid.show('Failed to save settings', ToastAndroid.SHORT);
throw e; throw e;
}); });

View File

@ -1,11 +1,12 @@
import React, {useState, useEffect} from 'react'; import React, {useState, useEffect} from 'react';
import {ScrollView, ToastAndroid} from 'react-native'; import {ScrollView, ToastAndroid, Text} from 'react-native';
import useS3 from '../hooks/useS3'; import useS3 from '../hooks/useS3';
import Bucket from '../components/Bucket'; import Bucket from '../components/Bucket';
const Buckets = () => { const Buckets = () => {
const s3 = useS3(); const s3 = useS3();
const [buckets, setBuckets] = useState([]); const [buckets, setBuckets] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => { useEffect(() => {
if (s3 && !buckets.length) { if (s3 && !buckets.length) {
@ -16,10 +17,15 @@ const Buckets = () => {
} }
setBuckets(data.Buckets); setBuckets(data.Buckets);
setLoading(false);
}); });
} }
}, [s3]); }, [s3]);
if (loading) {
return <Text>Loading...</Text>;
}
return ( return (
<ScrollView> <ScrollView>
{buckets.map(bucket => ( {buckets.map(bucket => (

View File

@ -1,5 +1,5 @@
import React, {useState, useEffect} from 'react'; import React, {useState, useEffect} from 'react';
import {ScrollView, ToastAndroid} from 'react-native'; import {ScrollView, ToastAndroid, Text} from 'react-native';
import {useRoute} from '@react-navigation/native'; import {useRoute} from '@react-navigation/native';
import useS3 from '../hooks/useS3'; import useS3 from '../hooks/useS3';
import Directory from '../components/Directory'; import Directory from '../components/Directory';
@ -9,6 +9,7 @@ const DirectoryDetails = () => {
const route = useRoute(); const route = useRoute();
const s3 = useS3(); const s3 = useS3();
const [contents, setContents] = useState({dirs: [], files: []}); const [contents, setContents] = useState({dirs: [], files: []});
const [loading, setLoading] = useState(true);
useEffect(() => { useEffect(() => {
if (s3 && !contents.length) { if (s3 && !contents.length) {
@ -29,11 +30,16 @@ const DirectoryDetails = () => {
} }
setContents({dirs: data.CommonPrefixes, files: data.Contents}); setContents({dirs: data.CommonPrefixes, files: data.Contents});
setLoading(false);
}, },
); );
} }
}, [s3]); }, [s3]);
if (loading) {
return <Text>Loading...</Text>;
}
return ( return (
<ScrollView> <ScrollView>
{contents.dirs.map(dir => ( {contents.dirs.map(dir => (

View File

@ -1,14 +1,16 @@
import React, {useState, useEffect} from 'react'; import React, {useState, useEffect, useCallback} from 'react';
import { import {
StyleSheet, StyleSheet,
ScrollView, ScrollView,
Text, Text,
View,
Button, Button,
ToastAndroid, ToastAndroid,
PermissionsAndroid, PermissionsAndroid,
} from 'react-native'; } from 'react-native';
import {useRoute} from '@react-navigation/native'; import {useRoute} from '@react-navigation/native';
import prettyBytes from 'pretty-bytes'; import prettyBytes from 'pretty-bytes';
import RNFS from 'react-native-fs';
import useS3 from '../hooks/useS3'; import useS3 from '../hooks/useS3';
const FileDetails = () => { const FileDetails = () => {
@ -18,10 +20,10 @@ const FileDetails = () => {
useEffect(() => { useEffect(() => {
if (s3 && !data) { if (s3 && !data) {
s3.getObject( s3.headObject(
{ {
Bucket: route.params.bucket, Bucket: route.params.bucket,
Key: route.params.file Key: route.params.file,
}, },
(err, data) => { (err, data) => {
if (err) { if (err) {
@ -35,6 +37,66 @@ const FileDetails = () => {
} }
}, [s3]); }, [s3]);
const download = useCallback(() => {
PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.READ_EXTERNAL_STORAGE,
)
.then(granted => {
if (granted != PermissionsAndroid.RESULTS.GRANTED) {
throw new Error('No permission');
}
})
.then(() =>
PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE,
),
)
.then(granted => {
if (granted != PermissionsAndroid.RESULTS.GRANTED) {
throw new Error('No permission');
}
})
.then(() => {
ToastAndroid.show('Downloading...', ToastAndroid.LONG);
s3.getObject(
{
Bucket: route.params.bucket,
Key: route.params.file,
},
(err, data) => {
if (err) {
ToastAndroid.show('Failed to download file', ToastAndroid.SHORT);
return;
}
const dir = `${RNFS.DownloadDirectoryPath}/BrowseS3/${route.params.bucket}`;
const file = `${dir}/${route.params.file.replace(/\//g, '_')}`;
const fileContents = data.Body.toString('base64');
RNFS.mkdir(dir)
.then(() => RNFS.writeFile(file, fileContents, 'base64'))
.then(() => RNFS.scanFile(file))
.then(() => {
ToastAndroid.show('Download completed', ToastAndroid.SHORT);
})
.catch(e => {
ToastAndroid.show(
'Failed to download file',
ToastAndroid.SHORT,
);
});
},
);
})
.catch(() => {
ToastAndroid.show(
'You need to grant the write permission to download files',
ToastAndroid.SHORT,
);
});
}, [s3, route]);
if (!data) { if (!data) {
return <Text>Loading...</Text>; return <Text>Loading...</Text>;
} }
@ -48,6 +110,9 @@ const FileDetails = () => {
</Text> </Text>
<Text style={styles.info}>Size: {prettyBytes(data.ContentLength)}</Text> <Text style={styles.info}>Size: {prettyBytes(data.ContentLength)}</Text>
<Text style={styles.info}>Content type: {data.ContentType}</Text> <Text style={styles.info}>Content type: {data.ContentType}</Text>
<View style={styles.download}>
<Button onPress={download} title="Download" />
</View>
</ScrollView> </ScrollView>
); );
}; };

View File

@ -21,7 +21,6 @@ const SignUp = () => {
signUp(email, pass) signUp(email, pass)
.then(() => { .then(() => {
console.log('asdasd');
navigation.reset({index: 0, routes: [{name: 'Buckets'}]}); navigation.reset({index: 0, routes: [{name: 'Buckets'}]});
}) })
.catch(() => {}); .catch(() => {});