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