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