Skip to content

Commit

Permalink
feat: merged Example and added cancel E2E test
Browse files Browse the repository at this point in the history
  • Loading branch information
reime005 committed Jan 3, 2020
1 parent 45eab97 commit d324a5a
Show file tree
Hide file tree
Showing 11 changed files with 459 additions and 14 deletions.
127 changes: 124 additions & 3 deletions example/RNBackgroundExample/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@

import React, { useState } from "react";
import {
Alert,
SafeAreaView,
StyleSheet,
ScrollView,
View,
Text,
StatusBar,
ActivityIndicator,
Button,
Platform,
TouchableOpacity
} from "react-native";
Expand All @@ -23,6 +24,8 @@ import { Header, Colors } from "react-native/Libraries/NewAppScreen";

import Upload from "react-native-background-upload";

import ImagePicker from 'react-native-image-picker'

import RNFS from "react-native-fs";

const url10SecDelayPut = `http://${Platform.OS === 'ios' ? 'localhost' : '10.0.2.2'}:8080/10secDelay`;
Expand All @@ -49,6 +52,85 @@ const App: () => React$Node = () => {
const [delay10Completed, set10SecDelayCompleted] = useState(false);
const [delay5Completed, set5SecDelayCompleted] = useState(false);

const [isImagePickerShowing, setIsImagePickerShowing] = useState(false);
const [uploadId, setUploadId] = useState(null);
const [progress, setProgress] = useState(null);

const onPressUpload = options => {
if (isImagePickerShowing) {
return
}

setIsImagePickerShowing(true);

const imagePickerOptions = {
takePhotoButtonTitle: null,
title: 'Upload Media',
chooseFromLibraryButtonTitle: 'Choose From Library'
}

ImagePicker.showImagePicker(imagePickerOptions, (response) => {
let didChooseVideo = true

console.log('ImagePicker response: ', response)
const { customButton, didCancel, error, path, uri } = response

if (didCancel) {
didChooseVideo = false
}

if (error) {
console.warn('ImagePicker error:', response)
didChooseVideo = false
}

// TODO: Should this happen higher?
setIsImagePickerShowing(false)

if (!didChooseVideo) {
return
}

let finalPath = Platform.OS === 'android' ? path : uri;

if (finalPath) { // Video is stored locally on the device
Upload.getFileInfo(finalPath).then((metadata) => {
const uploadOpts = Object.assign({
path: finalPath,
method: 'POST',
headers: {
'content-type': metadata.mimeType // server requires a content-type header
}
}, options)

Upload.startUpload(uploadOpts).then((uploadId) => {
console.log(`Upload started with options: ${JSON.stringify(uploadOpts)}`)
setUploadId(uploadId);
setProgress(0);
Upload.addListener('progress', uploadId, (data) => {
if (data.progress % 5 === 0) {
setProgress(+data.progress);
}
console.log(`Progress: ${data.progress}%`)
})
Upload.addListener('error', uploadId, (data) => {
console.log(`Error: ${data.error}%`)
})
Upload.addListener('completed', uploadId, (data) => {
console.log('Completed!')
})
}).catch(function(err) {
setUploadId(null);
setProgress(null);
console.log('Upload error!', err)
})
})
} else { // Video is stored in google cloud
Alert.alert("Video not found");
}
})
}

return (
<>
<StatusBar barStyle="dark-content" />
Expand All @@ -67,14 +149,16 @@ const App: () => React$Node = () => {
<View style={styles.sectionContainer}>
<TouchableOpacity
testID="10_sec_delay_button"
onPress={async () => {
onPress={() => {
const options = {
...commonOptions,
url: url10SecDelayPut,
};

Upload.startUpload(options)
.then(uploadId => {
setUploadId(uploadId);

Upload.addListener(
"completed",
uploadId,
Expand Down Expand Up @@ -104,14 +188,16 @@ const App: () => React$Node = () => {
<View style={styles.sectionContainer}>
<TouchableOpacity
testID="5_sec_delay_button"
onPress={async () => {
onPress={() => {
const options = {
...commonOptions,
url: url5secDelayFail,
};

Upload.startUpload(options)
.then(uploadId => {
setUploadId(uploadId);

Upload.addListener(
"completed",
uploadId,
Expand Down Expand Up @@ -141,6 +227,41 @@ const App: () => React$Node = () => {
<Text>Finished!!!</Text>
</View>
)}

<Button
title="Tap To Upload Multipart"
onPress={() => onPressUpload({
url: `http://${Platform.OS === 'ios' ? 'localhost' : '10.0.2.2'}:3000/upload_multipart`,
field: 'uploaded_media',
type: 'multipart'
})}
/>

<View style={{ height: 32 }}/>
<Text style={{ textAlign: 'center' }}>
{ `Current Upload ID: ${uploadId === null ? 'none' : uploadId}` }
</Text>
<Text style={{ textAlign: 'center' }}>
{ `Progress: ${progress === null ? 'none' : `${progress}%`}` }
</Text>
<View/>
<Button
testID="cancel_button"
title="Tap to Cancel Upload"
onPress={() => {
if (!uploadId) {
console.log('Nothing to cancel!')
return
}

Upload.cancelUpload(uploadId).then(() => {
console.log(`Upload ${uploadId} canceled`)
setUploadId(null);
setProgress(null);
})

}}
/>
</View>
</View>
</ScrollView>
Expand Down
161 changes: 161 additions & 0 deletions example/RNBackgroundExample/Upload.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
/**
* Sample React Native App
* https://github.com/facebook/react-native
* @flow
*/

import React, { Component } from 'react'
import { throttle } from 'lodash'
import {
AppRegistry,
Button,
Platform,
StyleSheet,
Text,
View
} from 'react-native'
import Upload from 'react-native-background-upload'
import ImagePicker from 'react-native-image-picker'

export default class ReactNativeBackgroundUploadExample extends Component {

constructor(props) {
super(props)
this.state = {
isImagePickerShowing: false,
uploadId: null,
progress: null,
}
}

handleProgress = throttle((progress) => {
this.setState({ progress })
}, 200)

startUpload = (opts) => {
Upload.getFileInfo(opts.path).then((metadata) => {
const options = Object.assign({
method: 'POST',
headers: {
'content-type': metadata.mimeType // server requires a content-type header
}
}, opts)

Upload.startUpload(options).then((uploadId) => {
console.log(`Upload started with options: ${JSON.stringify(options)}`)
this.setState({ uploadId, progress: 0 })
Upload.addListener('progress', uploadId, (data) => {
this.handleProgress(+data.progress)
console.log(`Progress: ${data.progress}%`)
})
Upload.addListener('error', uploadId, (data) => {
console.log(`Error: ${data.error}%`)
})
Upload.addListener('completed', uploadId, (data) => {
console.log('Completed!')
})
}).catch(function(err) {
this.setState({ uploadId: null, progress: null })
console.log('Upload error!', err)
})
})
}

onPressUpload = (options) => {
if (this.state.isImagePickerShowing) {
return
}

this.setState({ isImagePickerShowing: true })

const imagePickerOptions = {
takePhotoButtonTitle: null,
title: 'Upload Media',
chooseFromLibraryButtonTitle: 'Choose From Library'
}

ImagePicker.showImagePicker(imagePickerOptions, (response) => {
let didChooseVideo = true

console.log('ImagePicker response: ', response)
const { customButton, didCancel, error, path, uri } = response

if (didCancel) {
didChooseVideo = false
}

if (error) {
console.warn('ImagePicker error:', response)
didChooseVideo = false
}

// TODO: Should this happen higher?
this.setState({ isImagePickerShowing: false })

if (!didChooseVideo) {
return
}

if (Platform.OS === 'android') {
if (path) { // Video is stored locally on the device
// TODO: What here?
this.startUpload(Object.assign({ path }, options))
} else { // Video is stored in google cloud
// TODO: What here?
this.props.onVideoNotFound()
}
} else {
this.startUpload(Object.assign({ path: uri }, options))
}
})
}

cancelUpload = () => {
if (!this.state.uploadid) {
console.log('Nothing to cancel!')
return
}

Upload.cancelUpload(this.state.uploadId).then((props) => {
console.log(`Upload ${this.state.uploadId} canceled`)
this.setState({ uploadId: null, progress: null })
})
}

render() {
return (
<View>
<View>
<Button
title="Tap To Upload Raw"
onPress={() => this.onPressUpload({
url: 'http://localhost:3000/upload_raw',
type: 'raw'
})}
/>
<View/>
<Button
title="Tap To Upload Multipart"
onPress={() => this.onPressUpload({
url: 'http://localhost:3000/upload_multipart',
field: 'uploaded_media',
type: 'multipart'
})}
/>
<View style={{ height: 32 }}/>
<Text style={{ textAlign: 'center' }}>
{ `Current Upload ID: ${this.state.uploadId === null ? 'none' : this.state.uploadId}` }
</Text>
<Text style={{ textAlign: 'center' }}>
{ `Progress: ${this.state.progress === null ? 'none' : `${this.state.progress}%`}` }
</Text>
<View/>
<Button
title="Tap to Cancel Upload"
onPress={this.cancelUpload}
/>
</View>
</View>
)
}
}
2 changes: 1 addition & 1 deletion example/RNBackgroundExample/android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ import com.android.build.OutputFile
project.ext.react = [
entryFile: "index.js",
enableHermes: false, // clean and rebuild if changing
bundleInDebug: true,
bundleInDebug: false,
]

apply from: "../../node_modules/react-native/react.gradle"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

<application
android:name=".MainApplication"
android:label="@string/app_name"
Expand Down
Loading

0 comments on commit d324a5a

Please sign in to comment.