App.js 7.5 KB

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