1import React from 'react';
2import { LinearGradient } from 'expo-linear-gradient';
3import {
4  View,
5  Text,
6  Image,
7  StyleSheet,
8  ScrollView,
9  Dimensions,
10} from 'react-native';
11import { captureScreen } from 'react-native-view-shot';
12import { captureRef as takeSnapshotAsync } from 'react-native-view-shot';
13
14import * as MediaLibrary from 'expo-media-library';
15import * as Permissions from 'expo-permissions';
16
17import { Platform } from '@unimodules/core';
18import Button from '../components/Button';
19
20// Source: https://codepen.io/zessx/pen/rDEAl <3
21const gradientColors = ['#90dffe', '#38a3d1'];
22
23interface State {
24  image?: string;
25  screenUri?: string;
26}
27
28export default class ViewShotScreen extends React.Component<{}, State> {
29  static navigationOptions = {
30    title: 'ViewShot',
31  };
32
33  readonly state: State = {};
34  view?: View;
35
36  handleRef = (ref: View) => {
37    this.view = ref;
38  }
39
40  handlePress = async () => {
41    try {
42      const image = await takeSnapshotAsync(this.view!, {
43        format: 'png',
44        quality: 0.5,
45        result: 'data-uri',
46      });
47      this.setState({ image });
48    } catch (e) {
49      console.error(e);
50    }
51  }
52
53  handleScreenCapturePress = async () => {
54    if (Platform.OS === 'web') {
55      try {
56        const screenUri = await takeSnapshotAsync(undefined as unknown as number, {
57          format: 'jpg',
58          quality: 0.8,
59          result: 'data-uri',
60        });
61        this.setState({ screenUri });
62      } catch (e) {
63        console.error(e);
64      }
65      return;
66    }
67    const uri = await captureScreen({
68      format: 'jpg',
69      quality: 0.8,
70    });
71    this.setState({ screenUri: uri });
72  }
73
74  handleAddToMediaLibraryPress = async () => {
75    const uri = this.state.screenUri;
76
77    if (uri) {
78      const { status } = await Permissions.askAsync(Permissions.CAMERA_ROLL);
79
80      if (status === 'granted') {
81        await MediaLibrary.createAssetAsync(uri);
82        alert('Successfully added captured screen to media library');
83      } else {
84        alert('Camera roll permissions not granted');
85      }
86    }
87  }
88
89  render() {
90    const imageSource = { uri: this.state.image };
91    return (
92      <ScrollView contentContainerStyle={{ alignItems: 'center' }}>
93        <View
94          style={styles.snapshotContainer}
95          ref={this.handleRef}
96          collapsable={false}
97        >
98          <LinearGradient
99            colors={gradientColors}
100            style={styles.gradient}
101            start={[0, 0]}
102            end={[0, 1]}
103          >
104            <Image style={styles.snapshot} source={imageSource} />
105            <Text style={styles.text}>Snapshot will show above</Text>
106          </LinearGradient>
107        </View>
108        <Button
109          style={styles.button}
110          onPress={this.handlePress}
111          title="TAKE THE (SNAP)SHOT!"
112        />
113        <Button
114          style={styles.button}
115          onPress={this.handleScreenCapturePress}
116          title="Capture whole screen"
117        />
118        <Image
119          style={{
120            width: Dimensions.get('window').width,
121            height: Dimensions.get('window').height,
122            borderColor: '#f00',
123            borderWidth: 10,
124          }}
125          source={{ uri: this.state.screenUri }}
126        />
127        <Button
128          style={styles.button}
129          disabled={!this.state.screenUri}
130          onPress={this.handleAddToMediaLibraryPress}
131          title="Add to media library"
132        />
133      </ScrollView>
134    );
135  }
136}
137
138const styles = StyleSheet.create({
139  snapshotContainer: {
140    height: 200,
141    alignSelf: 'stretch',
142    alignItems: 'stretch',
143    justifyContent: 'space-around',
144  },
145  gradient: {
146    flex: 1,
147    alignItems: 'center',
148  },
149  snapshot: {
150    width: 150,
151    height: 150,
152  },
153  text: {
154    margin: 10,
155    color: '#fff',
156    fontWeight: '700',
157  },
158  button: {
159    margin: 15,
160  },
161});
162