* Sample React Native App
* https://github.com/facebook/react-native
*
* @format
*/
import React, {useState} from 'react';
import {
SafeAreaView,
StyleSheet,
ScrollView,
View,
Text,
StatusBar,
Button,
TouchableOpacity,
} from 'react-native';
import {Header, Colors} from 'react-native/Libraries/NewAppScreen';
import Upload from 'react-native-background-upload';
const BASE = 'http://127.0.0.1:8765';
const RAW_FILE = 'internal://cache/upload-test.bin';
const MULTIPART_FILE = 'internal://cache/sample.jpg';
const url10SecDelayPut = `${BASE}/stall`;
const url5secDelayFail = `${BASE}/reject`;
const urlMultipart = `${BASE}/echo`;
function errorMessage(error) {
if (error instanceof Error) {
return error.message;
}
return String(error);
}
const App = () => {
const [delay10Completed, set10SecDelayCompleted] = useState(false);
const [delay5Completed, set5SecDelayCompleted] = useState(false);
const [uploadId, setUploadId] = useState(null);
const [progress, setProgress] = useState(null);
const [lastResult, setLastResult] = useState('点下面的按钮开始上传');
const listenUpload = (id, onCompleted, onError) => {
Upload.addListener('progress', id, data => {
if (typeof data.progress === 'number') {
setProgress(data.progress);
}
});
Upload.addListener('completed', id, data => {
const code = data.responseCode ?? 0;
setLastResult(`completed HTTP ${code}`);
if (typeof onCompleted === 'function') {
onCompleted(data);
}
});
Upload.addListener('error', id, data => {
setLastResult(`error: ${data.error ?? 'failed'}`);
if (typeof onError === 'function') {
onError(data);
}
});
Upload.addListener('cancelled', id, () => {
setLastResult(`cancelled ${id}`);
});
};
const startRawUpload = (url, onCompleted, onError) => {
setLastResult('正在启动上传...');
set10SecDelayCompleted(false);
Upload.startUpload({
url,
path: RAW_FILE,
method: 'PUT',
type: 'raw',
notification: {enabled: true},
})
.then(id => {
setUploadId(id);
setProgress(0);
setLastResult(`已启动 ${id}`);
listenUpload(id, onCompleted, onError);
})
.catch(err => {
setUploadId(null);
setProgress(null);
setLastResult(`启动失败: ${errorMessage(err)}`);
});
};
const onPressUpload = () => {
setLastResult('正在启动 multipart...');
Upload.startUpload({
url: urlMultipart,
path: MULTIPART_FILE,
method: 'POST',
type: 'multipart',
field: 'uploaded_media',
notification: {enabled: true},
})
.then(id => {
setUploadId(id);
setProgress(0);
setLastResult(`multipart 已启动 ${id}`);
listenUpload(id, () => {
setLastResult('multipart completed');
});
})
.catch(err => {
setUploadId(null);
setProgress(null);
setLastResult(`multipart 启动失败: ${errorMessage(err)}`);
});
};
return (
<>
<StatusBar barStyle="dark-content" />
<SafeAreaView testID="main_screen" style={styles.safeArea}>
<ScrollView
contentInsetAdjustmentBehavior="automatic"
style={styles.scrollView}
>
<Header />
{global.HermesInternal == null ? null : (
<View style={styles.engine}>
<Text style={styles.footer}>Engine: Hermes</Text>
</View>
)}
<View style={styles.body}>
<View style={styles.sectionContainer}>
<TouchableOpacity
testID="10_sec_delay_button"
style={styles.actionButton}
onPress={() => {
startRawUpload(url10SecDelayPut, ({responseCode}) => {
if (responseCode <= 299) {
set10SecDelayCompleted(true);
}
});
}}
>
<Text style={styles.actionLabel}>10 Sec Delay Success</Text>
</TouchableOpacity>
{delay10Completed && (
<View testID="10_sec_delay_completed">
<Text>Finished!!!</Text>
</View>
)}
</View>
<View style={styles.sectionContainer}>
<TouchableOpacity
testID="5_sec_delay_button"
style={styles.actionButton}
onPress={() => {
startRawUpload(
url5secDelayFail,
({responseCode}) => {
if (responseCode === 502) {
set5SecDelayCompleted(true);
}
},
() => {
set5SecDelayCompleted(true);
},
);
}}
>
<Text style={styles.actionLabel}>5 Sec Delay Error</Text>
</TouchableOpacity>
{delay5Completed && (
<View testID="5_sec_delay_completed">
<Text>Finished!!!</Text>
</View>
)}
<Button
title="Tap To Upload Multipart"
onPress={onPressUpload}
/>
<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>
<Text style={styles.result}>{lastResult}</Text>
<View />
<Button
testID="cancel_button"
title="Tap to Cancel Upload"
onPress={() => {
if (!uploadId) {
setLastResult('没有可取消的任务');
return;
}
Upload.cancelUpload(uploadId)
.then(() => {
setLastResult(`已取消 ${uploadId}`);
setUploadId(null);
setProgress(null);
})
.catch(err => {
setLastResult(`取消失败: ${errorMessage(err)}`);
});
}}
/>
</View>
</View>
</ScrollView>
</SafeAreaView>
</>
);
};
const styles = StyleSheet.create({
safeArea: {
flex: 1,
backgroundColor: Colors.lighter,
},
scrollView: {
backgroundColor: Colors.lighter,
},
engine: {
position: 'absolute',
right: 0,
},
body: {
backgroundColor: Colors.white,
},
sectionContainer: {
marginTop: 32,
paddingHorizontal: 24,
},
actionButton: {
paddingVertical: 12,
},
actionLabel: {
fontSize: 16,
color: '#007AFF',
},
result: {
marginTop: 12,
textAlign: 'center',
color: '#175cd3',
fontSize: 14,
},
footer: {
color: Colors.dark,
fontSize: 12,
fontWeight: '600',
padding: 4,
paddingRight: 12,
textAlign: 'right',
},
});
export default App;