Brak opisu

App.js 11KB

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