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