1import AsyncStorage from '@react-native-community/async-storage'; 2import { Asset } from 'expo-asset'; 3import * as FileSystem from 'expo-file-system'; 4import * as Progress from 'expo-progress'; 5import React from 'react'; 6import { Alert, ScrollView, StyleSheet } from 'react-native'; 7 8import ListButton from '../components/ListButton'; 9 10interface State { 11 downloadProgress: number; 12} 13 14// See: https://github.com/expo/expo/pull/10229#discussion_r490961694 15// eslint-disable-next-line @typescript-eslint/ban-types 16export default class FileSystemScreen extends React.Component<{}, State> { 17 static navigationOptions = { 18 title: 'FileSystem', 19 }; 20 21 readonly state: State = { 22 downloadProgress: 0, 23 }; 24 25 download?: FileSystem.DownloadResumable; 26 27 _download = async () => { 28 const url = 'http://ipv4.download.thinkbroadband.com/256KB.zip'; 29 await FileSystem.downloadAsync(url, FileSystem.documentDirectory + '256KB.zip'); 30 alert('Download complete!'); 31 }; 32 33 _startDownloading = async () => { 34 const url = 'http://ipv4.download.thinkbroadband.com/5MB.zip'; 35 const fileUri = FileSystem.documentDirectory + '5MB.zip'; 36 const callback: FileSystem.DownloadProgressCallback = downloadProgress => { 37 const progress = 38 downloadProgress.totalBytesWritten / downloadProgress.totalBytesExpectedToWrite; 39 this.setState({ 40 downloadProgress: progress, 41 }); 42 }; 43 const options = { md5: true }; 44 this.download = FileSystem.createDownloadResumable(url, fileUri, options, callback); 45 46 try { 47 const result = await this.download.downloadAsync(); 48 if (result) { 49 this._downloadComplete(); 50 } 51 } catch (e) { 52 console.log(e); 53 } 54 }; 55 56 _pause = async () => { 57 if (!this.download) { 58 alert('Initiate a download first!'); 59 return; 60 } 61 try { 62 const downloadSnapshot = await this.download.pauseAsync(); 63 await AsyncStorage.setItem('pausedDownload', JSON.stringify(downloadSnapshot)); 64 alert('Download paused...'); 65 } catch (e) { 66 console.log(e); 67 } 68 }; 69 70 _resume = async () => { 71 try { 72 if (this.download) { 73 const result = await this.download.resumeAsync(); 74 if (result) { 75 this._downloadComplete(); 76 } 77 } else { 78 this._fetchDownload(); 79 } 80 } catch (e) { 81 console.log(e); 82 } 83 }; 84 85 _downloadComplete = () => { 86 if (this.state.downloadProgress !== 1) { 87 this.setState({ 88 downloadProgress: 1, 89 }); 90 } 91 alert('Download complete!'); 92 }; 93 94 _fetchDownload = async () => { 95 try { 96 const downloadJson = await AsyncStorage.getItem('pausedDownload'); 97 if (downloadJson !== null) { 98 const downloadFromStore = JSON.parse(downloadJson); 99 const callback: FileSystem.DownloadProgressCallback = downloadProgress => { 100 const progress = 101 downloadProgress.totalBytesWritten / downloadProgress.totalBytesExpectedToWrite; 102 this.setState({ 103 downloadProgress: progress, 104 }); 105 }; 106 this.download = new FileSystem.DownloadResumable( 107 downloadFromStore.url, 108 downloadFromStore.fileUri, 109 downloadFromStore.options, 110 callback, 111 downloadFromStore.resumeData 112 ); 113 await this.download.resumeAsync(); 114 if (this.state.downloadProgress === 1) { 115 alert('Download complete!'); 116 } 117 } else { 118 alert('Initiate a download first!'); 119 return; 120 } 121 } catch (e) { 122 console.log(e); 123 } 124 }; 125 126 _getInfo = async () => { 127 if (!this.download) { 128 alert('Initiate a download first!'); 129 return; 130 } 131 try { 132 const info = await FileSystem.getInfoAsync(this.download._fileUri); 133 Alert.alert('File Info:', JSON.stringify(info), [{ text: 'OK', onPress: () => {} }]); 134 } catch (e) { 135 console.log(e); 136 } 137 }; 138 139 _readAsset = async () => { 140 const asset = Asset.fromModule(require('../../assets/index.html')); 141 await asset.downloadAsync(); 142 try { 143 const result = await FileSystem.readAsStringAsync(asset.localUri!); 144 Alert.alert('Result', result); 145 } catch (e) { 146 Alert.alert('Error', e.message); 147 } 148 }; 149 150 _getInfoAsset = async () => { 151 const asset = Asset.fromModule(require('../../assets/index.html')); 152 await asset.downloadAsync(); 153 try { 154 const result = await FileSystem.getInfoAsync(asset.localUri!); 155 Alert.alert('Result', JSON.stringify(result, null, 2)); 156 } catch (e) { 157 Alert.alert('Error', e.message); 158 } 159 }; 160 161 _copyAndReadAsset = async () => { 162 const asset = Asset.fromModule(require('../../assets/index.html')); 163 await asset.downloadAsync(); 164 const tmpFile = FileSystem.cacheDirectory + 'test.html'; 165 try { 166 await FileSystem.copyAsync({ from: asset.localUri!, to: tmpFile }); 167 const result = await FileSystem.readAsStringAsync(tmpFile); 168 Alert.alert('Result', result); 169 } catch (e) { 170 Alert.alert('Error', e.message); 171 } 172 }; 173 174 _alertFreeSpace = async () => { 175 const freeBytes = await FileSystem.getFreeDiskStorageAsync(); 176 alert(`${Math.round(freeBytes / 1024 / 1024)} MB available`); 177 }; 178 179 render() { 180 return ( 181 <ScrollView style={{ padding: 10 }}> 182 <ListButton onPress={this._download} title="Download file (512KB)" /> 183 <ListButton onPress={this._startDownloading} title="Start Downloading file (5MB)" /> 184 <ListButton onPress={this._pause} title="Pause Download" /> 185 <ListButton onPress={this._resume} title="Resume Download" /> 186 <ListButton onPress={this._getInfo} title="Get Info" /> 187 <Progress.Bar style={styles.progress} isAnimated progress={this.state.downloadProgress} /> 188 <ListButton onPress={this._readAsset} title="Read Asset" /> 189 <ListButton onPress={this._getInfoAsset} title="Get Info Asset" /> 190 <ListButton onPress={this._copyAndReadAsset} title="Copy and Read Asset" /> 191 <ListButton onPress={this._alertFreeSpace} title="Alert free space" /> 192 </ScrollView> 193 ); 194 } 195} 196 197const styles = StyleSheet.create({ 198 progress: { 199 marginHorizontal: 10, 200 marginVertical: 32, 201 }, 202}); 203