App.js 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. import React, { Component } from "react";
  2. import {
  3. StyleSheet,
  4. Text,
  5. View,
  6. ScrollView,
  7. Image,
  8. Switch,
  9. TextInput,
  10. Picker,
  11. Slider,
  12. WebView
  13. } from "react-native";
  14. import omit from "lodash/omit";
  15. import { captureRef } from "react-native-view-shot";
  16. import { Surface } from "gl-react-native";
  17. import GL from "gl-react";
  18. import MapView from "react-native-maps";
  19. import Video from "react-native-video";
  20. import Btn from "./Btn";
  21. const catsSource = {
  22. uri: "https://i.imgur.com/5EOyTDQ.jpg"
  23. };
  24. const shaders = GL.Shaders.create({
  25. helloGL: {
  26. frag: `
  27. precision highp float;
  28. varying vec2 uv;
  29. uniform float blue;
  30. void main () {
  31. gl_FragColor = vec4(uv.x, uv.y, blue, 1.0);
  32. }`
  33. }
  34. });
  35. const HelloGL = GL.createComponent(
  36. ({ blue }) => <GL.Node shader={shaders.helloGL} uniforms={{ blue }} />,
  37. { displayName: "HelloGL" }
  38. );
  39. export default class App extends Component {
  40. state = {
  41. previewSource: catsSource,
  42. error: null,
  43. res: null,
  44. value: {
  45. format: "png",
  46. quality: 0.9,
  47. result: "tmpfile",
  48. snapshotContentContainer: false
  49. }
  50. };
  51. snapshot = refname => () =>
  52. captureRef(this.refs[refname], this.state.value)
  53. .then(
  54. res =>
  55. this.state.value.result !== "tmpfile"
  56. ? res
  57. : new Promise((success, failure) =>
  58. // just a test to ensure res can be used in Image.getSize
  59. Image.getSize(
  60. res,
  61. (width, height) => (
  62. console.log(res, width, height), success(res)
  63. ),
  64. failure
  65. )
  66. )
  67. )
  68. .then(res =>
  69. this.setState({
  70. error: null,
  71. res,
  72. previewSource: {
  73. uri:
  74. this.state.value.result === "base64"
  75. ? "data:image/" + this.state.value.format + ";base64," + res
  76. : res
  77. }
  78. })
  79. )
  80. .catch(
  81. error => (
  82. console.warn(error),
  83. this.setState({ error, res: null, previewSource: null })
  84. )
  85. );
  86. render() {
  87. const { value, previewSource, error, res } = this.state;
  88. const {
  89. format,
  90. quality,
  91. width,
  92. height,
  93. result,
  94. snapshotContentContainer
  95. } = value;
  96. return (
  97. <ScrollView
  98. ref="full"
  99. style={styles.root}
  100. contentContainerStyle={styles.container}
  101. >
  102. <View ref="header" style={styles.header}>
  103. <Text style={styles.title}>😃 ViewShot Example 😜</Text>
  104. <View style={styles.p1}>
  105. <Text style={styles.text}>This is a </Text>
  106. <Text style={styles.code}>react-native-view-shot</Text>
  107. <Text style={styles.text}> showcase.</Text>
  108. </View>
  109. <View style={styles.preview}>
  110. {error ? (
  111. <Text style={styles.previewError}>
  112. {"" + (error.message || error)}
  113. </Text>
  114. ) : (
  115. <Image
  116. fadeDuration={0}
  117. resizeMode="contain"
  118. style={styles.previewImage}
  119. source={previewSource}
  120. />
  121. )}
  122. </View>
  123. <Text numberOfLines={1} style={styles.previewUriText}>
  124. {res ? res.slice(0, 200) : ""}
  125. </Text>
  126. </View>
  127. <View ref="form" style={styles.form}>
  128. <View style={styles.btns}>
  129. <Btn
  130. label="😻 Reset"
  131. onPress={() => this.setState({ previewSource: catsSource })}
  132. />
  133. <Btn label="📷 Head Section" onPress={this.snapshot("header")} />
  134. <Btn label="📷 Form" onPress={this.snapshot("form")} />
  135. <Btn
  136. label="📷 Experimental Section"
  137. onPress={this.snapshot("complex")}
  138. />
  139. <Btn label="📷 All (ScrollView)" onPress={this.snapshot("full")} />
  140. <Btn label="📷 GL React" onPress={this.snapshot("gl")} />
  141. <Btn label="📷 MapView" onPress={this.snapshot("mapview")} />
  142. <Btn label="📷 WebView" onPress={this.snapshot("webview")} />
  143. <Btn label="📷 Video" onPress={this.snapshot("video")} />
  144. <Btn
  145. label="📷 Empty View (should crash)"
  146. onPress={this.snapshot("empty")}
  147. />
  148. </View>
  149. <View style={styles.field}>
  150. <Text style={styles.label}>Format</Text>
  151. <Picker
  152. style={styles.input}
  153. selectedValue={format}
  154. onValueChange={format =>
  155. this.setState({ value: { ...value, format } })}
  156. >
  157. <Picker.Item label="PNG" value="png" />
  158. <Picker.Item label="JPEG" value="jpeg" />
  159. <Picker.Item label="WEBM (android only)" value="webm" />
  160. <Picker.Item label="INVALID" value="_invalid_" />
  161. </Picker>
  162. </View>
  163. <View style={styles.field}>
  164. <Text style={styles.label}>Quality</Text>
  165. <Slider
  166. style={styles.input}
  167. value={quality}
  168. onValueChange={quality =>
  169. this.setState({ value: { ...value, quality } })}
  170. />
  171. <Text>{(quality * 100).toFixed(0)}%</Text>
  172. </View>
  173. <View style={styles.field}>
  174. <Text style={styles.label}>Size</Text>
  175. <Switch
  176. style={styles.switch}
  177. value={width !== undefined}
  178. onValueChange={checked =>
  179. this.setState({
  180. value: omit(
  181. {
  182. ...value,
  183. width: 300,
  184. height: 300
  185. },
  186. checked ? [] : ["width", "height"]
  187. )
  188. })}
  189. />
  190. {width !== undefined ? (
  191. <TextInput
  192. style={styles.inputText}
  193. value={"" + width}
  194. keyboardType="number-pad"
  195. onChangeText={txt =>
  196. !isNaN(txt) &&
  197. this.setState({
  198. value: { ...value, width: parseInt(txt, 10) }
  199. })}
  200. />
  201. ) : (
  202. <Text style={styles.inputText}>(auto)</Text>
  203. )}
  204. <Text>x</Text>
  205. {height !== undefined ? (
  206. <TextInput
  207. style={styles.inputText}
  208. value={"" + height}
  209. keyboardType="number-pad"
  210. onChangeText={txt =>
  211. !isNaN(txt) &&
  212. this.setState({
  213. value: { ...value, height: parseInt(txt, 10) }
  214. })}
  215. />
  216. ) : (
  217. <Text style={styles.inputText}>(auto)</Text>
  218. )}
  219. </View>
  220. <View style={styles.field}>
  221. <Text style={styles.label}>Result</Text>
  222. <Picker
  223. style={styles.input}
  224. selectedValue={result}
  225. onValueChange={result =>
  226. this.setState({ value: { ...value, result } })}
  227. >
  228. <Picker.Item label="tmpfile" value="tmpfile" />
  229. <Picker.Item label="base64" value="base64" />
  230. <Picker.Item label="data URI" value="data-uri" />
  231. <Picker.Item label="INVALID" value="_invalid_" />
  232. </Picker>
  233. </View>
  234. <View style={styles.field}>
  235. <Text style={styles.label}>snapshotContentContainer</Text>
  236. <Switch
  237. style={styles.switch}
  238. value={snapshotContentContainer}
  239. onValueChange={snapshotContentContainer =>
  240. this.setState({
  241. value: { ...value, snapshotContentContainer }
  242. })}
  243. />
  244. </View>
  245. </View>
  246. <View ref="empty" collapsable={false} />
  247. <View style={styles.experimental} ref="complex" collapsable={false}>
  248. <Text style={styles.experimentalTitle}>Experimental Stuff</Text>
  249. <Surface ref="gl" width={300} height={300}>
  250. <HelloGL blue={0.5} />
  251. </Surface>
  252. <MapView
  253. ref="mapview"
  254. initialRegion={{
  255. latitude: 37.78825,
  256. longitude: -122.4324,
  257. latitudeDelta: 0.0922,
  258. longitudeDelta: 0.0421
  259. }}
  260. style={{ width: 300, height: 300 }}
  261. />
  262. <View
  263. ref="webview"
  264. collapsable={false}
  265. style={{ width: 300, height: 300 }}
  266. >
  267. <WebView
  268. source={{
  269. uri: "https://github.com/gre/react-native-view-shot"
  270. }}
  271. />
  272. </View>
  273. <Video
  274. ref="video"
  275. style={{ width: 300, height: 300 }}
  276. source={require("./broadchurch.mp4")}
  277. volume={0}
  278. repeat
  279. />
  280. </View>
  281. </ScrollView>
  282. );
  283. }
  284. }
  285. const styles = StyleSheet.create({
  286. root: {
  287. flex: 1,
  288. backgroundColor: "#f6f6f6"
  289. },
  290. container: {
  291. paddingVertical: 20,
  292. backgroundColor: "#f6f6f6"
  293. },
  294. title: {
  295. fontSize: 20,
  296. textAlign: "center",
  297. margin: 10
  298. },
  299. experimental: {
  300. padding: 10,
  301. flexDirection: "column",
  302. alignItems: "center"
  303. },
  304. experimentalTitle: {
  305. fontSize: 16,
  306. margin: 10
  307. },
  308. p1: {
  309. marginBottom: 10,
  310. flexDirection: "row",
  311. flexWrap: "wrap",
  312. justifyContent: "center",
  313. alignItems: "center"
  314. },
  315. text: {
  316. color: "#333"
  317. },
  318. code: {
  319. fontWeight: "bold",
  320. color: "#000"
  321. },
  322. field: {
  323. flexDirection: "row",
  324. alignItems: "center",
  325. paddingVertical: 4,
  326. paddingHorizontal: 10
  327. },
  328. label: {
  329. minWidth: 80,
  330. fontStyle: "italic",
  331. color: "#888"
  332. },
  333. switch: {
  334. marginRight: 50
  335. },
  336. input: {
  337. flex: 1,
  338. marginHorizontal: 5
  339. },
  340. inputText: {
  341. flex: 1,
  342. marginHorizontal: 5,
  343. color: "red",
  344. textAlign: "center"
  345. },
  346. preview: {
  347. flexDirection: "row",
  348. alignItems: "center",
  349. justifyContent: "space-around"
  350. },
  351. previewImage: {
  352. width: 375,
  353. height: 300
  354. },
  355. previewUriText: {
  356. fontSize: 12,
  357. fontStyle: "italic",
  358. color: "#666",
  359. textAlign: "center",
  360. padding: 10,
  361. paddingBottom: 0
  362. },
  363. previewError: {
  364. width: 375,
  365. height: 300,
  366. paddingTop: 20,
  367. textAlign: "center",
  368. fontSize: 20,
  369. fontWeight: "bold",
  370. color: "#fff",
  371. backgroundColor: "#c00"
  372. },
  373. header: {
  374. backgroundColor: "#f6f6f6",
  375. borderColor: "#000",
  376. borderWidth: 1,
  377. paddingBottom: 20
  378. },
  379. form: {
  380. backgroundColor: "#fff"
  381. },
  382. btns: {
  383. flexDirection: "row",
  384. flexWrap: "wrap",
  385. alignItems: "center",
  386. justifyContent: "center",
  387. paddingVertical: 10,
  388. margin: 4
  389. }
  390. });