App.js 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. // import * as Expo from 'expo'
  2. import React from 'react'
  3. import {
  4. Text,
  5. View,
  6. AsyncStorage,
  7. // TouchableOpacity,
  8. TouchableHighlight
  9. // Image,
  10. // Linking
  11. } from 'react-native'
  12. import Uppy from '@uppy/core'
  13. import Tus from '@uppy/tus'
  14. import UppyFilePicker from './react-native/file-picker'
  15. function hashCode (str) {
  16. var hash = 0
  17. if (str.length === 0) {
  18. return hash
  19. }
  20. for (var i = 0; i < str.length; i++) {
  21. var char = str.charCodeAt(i)
  22. hash = ((hash << 5) - hash) + char
  23. hash = hash & hash // Convert to 32bit integer
  24. }
  25. return hash
  26. }
  27. function customFingerprint (file, options) {
  28. console.log('_____________________')
  29. console.log('FILE:')
  30. console.log(file)
  31. console.log('_____________________')
  32. let exifHash = 'noexif'
  33. if (file.exif) {
  34. exifHash = hashCode(JSON.stringify(file.exif))
  35. }
  36. console.log(exifHash)
  37. const fingerprint = ['tus', file.name || 'noname', file.size || 'nosize', exifHash].join('/')
  38. console.log(fingerprint)
  39. return fingerprint
  40. }
  41. export default class App extends React.Component {
  42. constructor () {
  43. super()
  44. this.state = {
  45. progress: 0,
  46. total: 0,
  47. file: null,
  48. uploadURL: null,
  49. isFilePickerVisible: false,
  50. isPaused: false,
  51. uploadStarted: false,
  52. uploadComplete: false
  53. }
  54. this.isReactNative = (typeof navigator !== 'undefined' &&
  55. typeof navigator.product === 'string' &&
  56. navigator.product.toLowerCase() === 'reactnative')
  57. this.startUpload = this.startUpload.bind(this)
  58. // this.selectPhotoTapped = this.selectPhotoTapped.bind(this)
  59. this.showFilePicker = this.showFilePicker.bind(this)
  60. this.hideFilePicker = this.hideFilePicker.bind(this)
  61. this.togglePauseResume = this.togglePauseResume.bind(this)
  62. console.log('Is this React Native?', this.isReactNative)
  63. this.uppy = Uppy({ autoProceed: true, debug: true })
  64. this.uppy.use(Tus, {
  65. endpoint: 'https://master.tus.io/files/',
  66. urlStorage: AsyncStorage,
  67. fingerprint: customFingerprint
  68. })
  69. this.uppy.on('upload-progress', (file, progress) => {
  70. this.setState({
  71. progress: progress.bytesUploaded,
  72. total: progress.bytesTotal,
  73. uploadStarted: true
  74. })
  75. })
  76. this.uppy.on('upload-success', (file, response) => {
  77. console.log(file.name, response)
  78. })
  79. this.uppy.on('complete', (result) => {
  80. this.setState({
  81. status: 'Upload complete ✅',
  82. uploadURL: result.successful[0].uploadURL,
  83. uploadComplete: true,
  84. uploadStarted: false
  85. })
  86. // console.log('Upload complete:')
  87. // console.log(result)
  88. })
  89. }
  90. // selectPhotoTapped () {
  91. // console.log('Selecting photo...')
  92. // Expo.Permissions.askAsync(Expo.Permissions.CAMERA_ROLL).then((isAllowed) => {
  93. // if (!isAllowed) return
  94. // Expo.ImagePicker.launchImageLibraryAsync({
  95. // mediaTypes: 'All'
  96. // })
  97. // .then((result) => {
  98. // console.log(result)
  99. // if (!result.cancelled) {
  100. // this.setState({ file: result })
  101. // this.uppy.addFile({
  102. // source: 'React Native',
  103. // name: 'photo.jpg',
  104. // type: result.type,
  105. // data: result
  106. // })
  107. // }
  108. // })
  109. // })
  110. // }
  111. startUpload () {
  112. this.setState({
  113. status: 'Uploading...'
  114. })
  115. }
  116. showFilePicker () {
  117. this.setState({
  118. isFilePickerVisible: true,
  119. uploadStarted: false,
  120. uploadComplete: false
  121. })
  122. }
  123. hideFilePicker () {
  124. this.setState({
  125. isFilePickerVisible: false
  126. })
  127. }
  128. togglePauseResume () {
  129. if (this.state.isPaused) {
  130. this.uppy.resumeAll()
  131. this.setState({
  132. isPaused: false
  133. })
  134. } else {
  135. this.uppy.pauseAll()
  136. this.setState({
  137. isPaused: true
  138. })
  139. }
  140. }
  141. resumeAll () {
  142. this.uppy.resumeAll()
  143. this.setState({
  144. isPaused: false
  145. })
  146. }
  147. render () {
  148. return (
  149. <View style={{
  150. flex: 1,
  151. backgroundColor: '#fff',
  152. alignItems: 'center',
  153. justifyContent: 'center'
  154. }}>
  155. <SelectAndUploadFileWithUppy
  156. state={this.state}
  157. selectPhotoTapped={this.selectPhotoTapped}
  158. showFilePicker={this.showFilePicker}
  159. togglePauseResume={this.togglePauseResume} />
  160. <UppyFilePicker
  161. show={this.state.isFilePickerVisible}
  162. uppy={this.uppy}
  163. onRequestClose={this.hideFilePicker}
  164. serverUrl="http://localhost:3020" />
  165. </View>
  166. )
  167. }
  168. }
  169. function ProgressBar (props) {
  170. const progress = props.progress || 0
  171. const total = props.total || 0
  172. const percentage = Math.round(progress / total * 100)
  173. const colorGreen = '#0b8600'
  174. const colorBlue = '#006bb7'
  175. return (
  176. <View style={{
  177. marginTop: 15,
  178. marginBottom: 15
  179. }}>
  180. <View
  181. style={{
  182. height: 5,
  183. overflow: 'hidden',
  184. backgroundColor: '#dee1e3'
  185. }}>
  186. <View style={{
  187. height: 5,
  188. backgroundColor: percentage === 100 ? colorGreen : colorBlue,
  189. width: percentage + '%'
  190. }} />
  191. </View>
  192. <Text>{percentage ? percentage + '%' : null}</Text>
  193. </View>
  194. )
  195. }
  196. function PauseResumeButton (props) {
  197. if (!props.uploadStarted || props.uploadComplete) {
  198. return null
  199. }
  200. // return (
  201. // <Button
  202. // onPress={props.onPress}
  203. // color="#bb00cc"
  204. // title={props.isPaused ? 'Resume' : 'Pause'}
  205. // accessibilityLabel={props.isPaused ? 'Resume' : 'Pause'}
  206. // />
  207. // )
  208. return (
  209. <TouchableHighlight
  210. onPress={props.onPress}
  211. style={{
  212. backgroundColor: '#006bb7',
  213. padding: 10
  214. }}>
  215. <Text
  216. style={{
  217. color: '#fff',
  218. textAlign: 'center',
  219. fontSize: 17
  220. }}>{props.isPaused ? 'Resume' : 'Pause'}</Text>
  221. </TouchableHighlight>
  222. )
  223. }
  224. function SelectFiles (props) {
  225. return (
  226. <TouchableHighlight
  227. onPress={props.showFilePicker}
  228. style={{
  229. backgroundColor: '#006bb7',
  230. padding: 15
  231. }}>
  232. <Text
  233. style={{
  234. color: '#fff',
  235. textAlign: 'center',
  236. fontSize: 17
  237. }}>Select files</Text>
  238. </TouchableHighlight>
  239. )
  240. }
  241. function SelectAndUploadFileWithUppy (props) {
  242. return (
  243. <View>
  244. <Text style={{
  245. fontSize: 25,
  246. marginBottom: 20
  247. }}>Uppy in React Native</Text>
  248. {/* <TouchableOpacity onPress={props.selectPhotoTapped}>
  249. { props.state.file === null
  250. ? <Text>Select a Photo</Text>
  251. : <Image
  252. style={{ width: 200, height: 200 }}
  253. source={{ uri: props.state.file.uri }} />
  254. }
  255. { props.state.uploadURL !== null &&
  256. <Button
  257. onPress={(ev) => {
  258. Linking.openURL(props.state.uploadURL)
  259. }}
  260. title="Show Uploaded File"
  261. accessibilityLabel="Open uploaded file"
  262. />
  263. }
  264. </TouchableOpacity> */}
  265. <SelectFiles showFilePicker={props.showFilePicker} />
  266. <ProgressBar
  267. progress={props.state.progress}
  268. total={props.state.total}
  269. />
  270. <PauseResumeButton
  271. isPaused={props.state.isPaused}
  272. onPress={props.togglePauseResume}
  273. uploadStarted={props.state.uploadStarted}
  274. uploadComplete={props.state.uploadComplete} />
  275. <Text>{props.state.status ? 'Status: ' + props.state.status : null}</Text>
  276. <Text>{props.state.progress} of {props.state.total}</Text>
  277. </View>
  278. )
  279. }