No Description

App.js 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436
  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, captureScreen } 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. captureScreenshot = () =>
  52. captureScreen(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. snapshot = refname => () =>
  87. captureRef(this.refs[refname], this.state.value)
  88. .then(
  89. res =>
  90. this.state.value.result !== "tmpfile"
  91. ? res
  92. : new Promise((success, failure) =>
  93. // just a test to ensure res can be used in Image.getSize
  94. Image.getSize(
  95. res,
  96. (width, height) => (
  97. console.log(res, width, height), success(res)
  98. ),
  99. failure
  100. )
  101. )
  102. )
  103. .then(res =>
  104. this.setState({
  105. error: null,
  106. res,
  107. previewSource: {
  108. uri:
  109. this.state.value.result === "base64"
  110. ? "data:image/" + this.state.value.format + ";base64," + res
  111. : res
  112. }
  113. })
  114. )
  115. .catch(
  116. error => (
  117. console.warn(error),
  118. this.setState({ error, res: null, previewSource: null })
  119. )
  120. );
  121. render() {
  122. const { value, previewSource, error, res } = this.state;
  123. const {
  124. format,
  125. quality,
  126. width,
  127. height,
  128. result,
  129. snapshotContentContainer
  130. } = value;
  131. return (
  132. <ScrollView
  133. ref="full"
  134. style={styles.root}
  135. contentContainerStyle={styles.container}
  136. >
  137. <View ref="header" style={styles.header}>
  138. <Text style={styles.title}>😃 ViewShot Example 😜</Text>
  139. <View style={styles.p1}>
  140. <Text style={styles.text}>This is a </Text>
  141. <Text style={styles.code}>react-native-view-shot</Text>
  142. <Text style={styles.text}> showcase.</Text>
  143. </View>
  144. <View style={styles.preview}>
  145. {error ? (
  146. <Text style={styles.previewError}>
  147. {"" + (error.message || error)}
  148. </Text>
  149. ) : (
  150. <Image
  151. fadeDuration={0}
  152. resizeMode="contain"
  153. style={styles.previewImage}
  154. source={previewSource}
  155. />
  156. )}
  157. </View>
  158. <Text numberOfLines={1} style={styles.previewUriText}>
  159. {res ? res.slice(0, 200) : ""}
  160. </Text>
  161. </View>
  162. <View ref="form" style={styles.form}>
  163. <View style={styles.btns}>
  164. <Btn
  165. label="😻 Reset"
  166. onPress={() => this.setState({ previewSource: catsSource })}
  167. />
  168. <Btn label="📷 Head Section" onPress={this.snapshot("header")} />
  169. <Btn label="📷 Form" onPress={this.snapshot("form")} />
  170. <Btn
  171. label="📷 Experimental Section"
  172. onPress={this.snapshot("complex")}
  173. />
  174. <Btn label="📷 All (ScrollView)" onPress={this.snapshot("full")} />
  175. <Btn label="📷 GL React" onPress={this.snapshot("gl")} />
  176. <Btn label="📷 MapView" onPress={this.snapshot("mapview")} />
  177. <Btn label="📷 WebView" onPress={this.snapshot("webview")} />
  178. <Btn label="📷 Video" onPress={this.snapshot("video")} />
  179. <Btn label="📷 Native Screenshot" onPress={this.captureScreenshot}/>
  180. <Btn
  181. label="📷 Empty View (should crash)"
  182. onPress={this.snapshot("empty")}
  183. />
  184. </View>
  185. <View style={styles.field}>
  186. <Text style={styles.label}>Format</Text>
  187. <Picker
  188. style={styles.input}
  189. selectedValue={format}
  190. onValueChange={format =>
  191. this.setState({ value: { ...value, format } })}
  192. >
  193. <Picker.Item label="PNG" value="png" />
  194. <Picker.Item label="JPEG" value="jpeg" />
  195. <Picker.Item label="WEBM (android only)" value="webm" />
  196. <Picker.Item label="INVALID" value="_invalid_" />
  197. </Picker>
  198. </View>
  199. <View style={styles.field}>
  200. <Text style={styles.label}>Quality</Text>
  201. <Slider
  202. style={styles.input}
  203. value={quality}
  204. onValueChange={quality =>
  205. this.setState({ value: { ...value, quality } })}
  206. />
  207. <Text>{(quality * 100).toFixed(0)}%</Text>
  208. </View>
  209. <View style={styles.field}>
  210. <Text style={styles.label}>Size</Text>
  211. <Switch
  212. style={styles.switch}
  213. value={width !== undefined}
  214. onValueChange={checked =>
  215. this.setState({
  216. value: omit(
  217. {
  218. ...value,
  219. width: 300,
  220. height: 300
  221. },
  222. checked ? [] : ["width", "height"]
  223. )
  224. })}
  225. />
  226. {width !== undefined ? (
  227. <TextInput
  228. style={styles.inputText}
  229. value={"" + width}
  230. keyboardType="number-pad"
  231. onChangeText={txt =>
  232. !isNaN(txt) &&
  233. this.setState({
  234. value: { ...value, width: parseInt(txt, 10) }
  235. })}
  236. />
  237. ) : (
  238. <Text style={styles.inputText}>(auto)</Text>
  239. )}
  240. <Text>x</Text>
  241. {height !== undefined ? (
  242. <TextInput
  243. style={styles.inputText}
  244. value={"" + height}
  245. keyboardType="number-pad"
  246. onChangeText={txt =>
  247. !isNaN(txt) &&
  248. this.setState({
  249. value: { ...value, height: parseInt(txt, 10) }
  250. })}
  251. />
  252. ) : (
  253. <Text style={styles.inputText}>(auto)</Text>
  254. )}
  255. </View>
  256. <View style={styles.field}>
  257. <Text style={styles.label}>Result</Text>
  258. <Picker
  259. style={styles.input}
  260. selectedValue={result}
  261. onValueChange={result =>
  262. this.setState({ value: { ...value, result } })}
  263. >
  264. <Picker.Item label="tmpfile" value="tmpfile" />
  265. <Picker.Item label="base64" value="base64" />
  266. <Picker.Item label="data URI" value="data-uri" />
  267. <Picker.Item label="INVALID" value="_invalid_" />
  268. </Picker>
  269. </View>
  270. <View style={styles.field}>
  271. <Text style={styles.label}>snapshotContentContainer</Text>
  272. <Switch
  273. style={styles.switch}
  274. value={snapshotContentContainer}
  275. onValueChange={snapshotContentContainer =>
  276. this.setState({
  277. value: { ...value, snapshotContentContainer }
  278. })}
  279. />
  280. </View>
  281. </View>
  282. <View ref="empty" collapsable={false} />
  283. <View style={styles.experimental} ref="complex" collapsable={false}>
  284. <Text style={styles.experimentalTitle}>Experimental Stuff</Text>
  285. <Surface ref="gl" width={300} height={300}>
  286. <HelloGL blue={0.5} />
  287. </Surface>
  288. <MapView
  289. ref="mapview"
  290. initialRegion={{
  291. latitude: 37.78825,
  292. longitude: -122.4324,
  293. latitudeDelta: 0.0922,
  294. longitudeDelta: 0.0421
  295. }}
  296. style={{ width: 300, height: 300 }}
  297. />
  298. <View
  299. ref="webview"
  300. collapsable={false}
  301. style={{ width: 300, height: 300 }}
  302. >
  303. <WebView
  304. source={{
  305. uri: "https://github.com/gre/react-native-view-shot"
  306. }}
  307. />
  308. </View>
  309. <Video
  310. ref="video"
  311. style={{ width: 300, height: 300 }}
  312. source={require("./broadchurch.mp4")}
  313. volume={0}
  314. repeat
  315. />
  316. </View>
  317. </ScrollView>
  318. );
  319. }
  320. }
  321. const styles = StyleSheet.create({
  322. root: {
  323. flex: 1,
  324. backgroundColor: "#f6f6f6"
  325. },
  326. container: {
  327. paddingVertical: 20,
  328. backgroundColor: "#f6f6f6"
  329. },
  330. title: {
  331. fontSize: 20,
  332. textAlign: "center",
  333. margin: 10
  334. },
  335. experimental: {
  336. padding: 10,
  337. flexDirection: "column",
  338. alignItems: "center"
  339. },
  340. experimentalTitle: {
  341. fontSize: 16,
  342. margin: 10
  343. },
  344. p1: {
  345. marginBottom: 10,
  346. flexDirection: "row",
  347. flexWrap: "wrap",
  348. justifyContent: "center",
  349. alignItems: "center"
  350. },
  351. text: {
  352. color: "#333"
  353. },
  354. code: {
  355. fontWeight: "bold",
  356. color: "#000"
  357. },
  358. field: {
  359. flexDirection: "row",
  360. alignItems: "center",
  361. paddingVertical: 4,
  362. paddingHorizontal: 10
  363. },
  364. label: {
  365. minWidth: 80,
  366. fontStyle: "italic",
  367. color: "#888"
  368. },
  369. switch: {
  370. marginRight: 50
  371. },
  372. input: {
  373. flex: 1,
  374. marginHorizontal: 5
  375. },
  376. inputText: {
  377. flex: 1,
  378. marginHorizontal: 5,
  379. color: "red",
  380. textAlign: "center"
  381. },
  382. preview: {
  383. flexDirection: "row",
  384. alignItems: "center",
  385. justifyContent: "space-around"
  386. },
  387. previewImage: {
  388. width: 375,
  389. height: 300
  390. },
  391. previewUriText: {
  392. fontSize: 12,
  393. fontStyle: "italic",
  394. color: "#666",
  395. textAlign: "center",
  396. padding: 10,
  397. paddingBottom: 0
  398. },
  399. previewError: {
  400. width: 375,
  401. height: 300,
  402. paddingTop: 20,
  403. textAlign: "center",
  404. fontSize: 20,
  405. fontWeight: "bold",
  406. color: "#fff",
  407. backgroundColor: "#c00"
  408. },
  409. header: {
  410. backgroundColor: "#f6f6f6",
  411. borderColor: "#000",
  412. borderWidth: 1,
  413. paddingBottom: 20
  414. },
  415. form: {
  416. backgroundColor: "#fff"
  417. },
  418. btns: {
  419. flexDirection: "row",
  420. flexWrap: "wrap",
  421. alignItems: "center",
  422. justifyContent: "center",
  423. paddingVertical: 10,
  424. margin: 4
  425. }
  426. });