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      const result = await this.download.downloadAsync();
51      if (result) {
52        this._downloadComplete();
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        const result = await this.download.resumeAsync();
77        if (result) {
78          this._downloadComplete();
79        }
80      } else {
81        this._fetchDownload();
82      }
83    } catch (e) {
84      console.log(e);
85    }
86  };
87
88  _downloadComplete = () => {
89    if (this.state.downloadProgress !== 1) {
90      this.setState({
91        downloadProgress: 1,
92      });
93    }
94    alert('Download complete!');
95  };
96
97  _fetchDownload = async () => {
98    try {
99      const downloadJson = await AsyncStorage.getItem('pausedDownload');
100      if (downloadJson !== null) {
101        const downloadFromStore = JSON.parse(downloadJson);
102        const callback: FileSystem.DownloadProgressCallback = downloadProgress => {
103          const progress =
104            downloadProgress.totalBytesWritten / downloadProgress.totalBytesExpectedToWrite;
105          this.setState({
106            downloadProgress: progress,
107          });
108        };
109        this.download = new FileSystem.DownloadResumable(
110          downloadFromStore.url,
111          downloadFromStore.fileUri,
112          downloadFromStore.options,
113          callback,
114          downloadFromStore.resumeData
115        );
116        await this.download.resumeAsync();
117        if (this.state.downloadProgress === 1) {
118          alert('Download complete!');
119        }
120      } else {
121        alert('Initiate a download first!');
122        return;
123      }
124    } catch (e) {
125      console.log(e);
126    }
127  };
128
129  _getInfo = async () => {
130    if (!this.download) {
131      alert('Initiate a download first!');
132      return;
133    }
134    try {
135      const info = await FileSystem.getInfoAsync(this.download._fileUri);
136      Alert.alert('File Info:', JSON.stringify(info), [{ text: 'OK', onPress: () => {} }]);
137    } catch (e) {
138      console.log(e);
139    }
140  };
141
142  _readAsset = async () => {
143    const asset = Asset.fromModule(require('../../assets/index.html'));
144    await asset.downloadAsync();
145    try {
146      const result = await FileSystem.readAsStringAsync(asset.localUri!);
147      Alert.alert('Result', result);
148    } catch (e) {
149      Alert.alert('Error', e.message);
150    }
151  };
152
153  _getInfoAsset = async () => {
154    const asset = Asset.fromModule(require('../../assets/index.html'));
155    await asset.downloadAsync();
156    try {
157      const result = await FileSystem.getInfoAsync(asset.localUri!);
158      Alert.alert('Result', JSON.stringify(result, null, 2));
159    } catch (e) {
160      Alert.alert('Error', e.message);
161    }
162  };
163
164  _copyAndReadAsset = async () => {
165    const asset = Asset.fromModule(require('../../assets/index.html'));
166    await asset.downloadAsync();
167    const tmpFile = FileSystem.cacheDirectory + 'test.html';
168    try {
169      await FileSystem.copyAsync({ from: asset.localUri!, to: tmpFile });
170      const result = await FileSystem.readAsStringAsync(tmpFile);
171      Alert.alert('Result', result);
172    } catch (e) {
173      Alert.alert('Error', e.message);
174    }
175  };
176
177  _alertFreeSpace = async () => {
178    const freeBytes = await FileSystem.getFreeDiskStorageAsync();
179    alert(`${Math.round(freeBytes / 1024 / 1024)} MB available`);
180  };
181
182  render() {
183    let progress = null;
184    if (Platform.OS === 'ios') {
185      progress = <ProgressViewIOS style={styles.progress} progress={this.state.downloadProgress} />;
186    } else {
187      progress = (
188        <ProgressBarAndroid
189          style={styles.progress}
190          styleAttr="Horizontal"
191          indeterminate={false}
192          progress={this.state.downloadProgress}
193        />
194      );
195    }
196    return (
197      <ScrollView style={{ padding: 10 }}>
198        <ListButton onPress={this._download} title="Download file (512KB)" />
199        <ListButton onPress={this._startDownloading} title="Start Downloading file (5MB)" />
200        <ListButton onPress={this._pause} title="Pause Download" />
201        <ListButton onPress={this._resume} title="Resume Download" />
202        <ListButton onPress={this._getInfo} title="Get Info" />
203        {progress}
204        <ListButton onPress={this._readAsset} title="Read Asset" />
205        <ListButton onPress={this._getInfoAsset} title="Get Info Asset" />
206        <ListButton onPress={this._copyAndReadAsset} title="Copy and Read Asset" />
207        <ListButton onPress={this._alertFreeSpace} title="Alert free space" />
208      </ScrollView>
209    );
210  }
211}
212
213const styles = StyleSheet.create({
214  progress: {
215    marginHorizontal: 10,
216    marginVertical: 32,
217  },
218});
219