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