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