1import { LinearGradient } from 'expo-linear-gradient';
2import React from 'react';
3import { Image, Platform, ScrollView, StyleSheet, Text, View } from 'react-native';
4
5import MonoText from '../components/MonoText';
6
7function incrementColor(color: string, step: number) {
8  const intColor = parseInt(color.substr(1), 16);
9  const newIntColor = (intColor + step).toString(16);
10  return `#${'0'.repeat(6 - newIntColor.length)}${newIntColor}`;
11}
12
13export default class LinearGradientScreen extends React.Component {
14  static navigationOptions = {
15    title: 'LinearGradient',
16  };
17
18  state = {
19    count: 0,
20    colorTop: '#000000',
21    colorBottom: '#cccccc',
22  };
23
24  _interval?: number;
25
26  componentDidMount() {
27    this._interval = setInterval(() => {
28      this.setState({
29        count: this.state.count + 1,
30        colorTop: incrementColor(this.state.colorTop, 1),
31        colorBottom: incrementColor(this.state.colorBottom, -1),
32      });
33    }, 100);
34  }
35
36  componentWillUnmount() {
37    clearInterval(this._interval);
38  }
39
40  render() {
41    const location = Math.sin(this.state.count / 100) * 0.5;
42    const position = Math.sin(this.state.count / 100);
43    return (
44      <ScrollView
45        style={{ flex: 1 }}
46        contentContainerStyle={{
47          alignItems: 'stretch',
48          paddingVertical: 10,
49        }}
50      >
51        <ColorsTest colors={[this.state.colorTop, this.state.colorBottom]} />
52        <LocationsTest locations={[location, 1.0 - location]} />
53        <ControlPointTest start={[position, 0]} />
54        {Platform.OS !== 'web' && <SnapshotTest />}
55      </ScrollView>
56    );
57  }
58}
59
60const Container: React.FunctionComponent<{ title: string }> = ({ title, children }) => (
61  <View style={styles.container}>
62    <Text style={styles.containerTitle}>{title}</Text>
63    {children}
64  </View>
65);
66
67const SnapshotTest = () => (
68  <Container title="Snapshot">
69    <View style={{ flexDirection: 'row', alignSelf: 'stretch', justifyContent: 'space-evenly' }}>
70      <LinearGradient
71        colors={['white', 'red']}
72        start={[0.5, 0.5]}
73        end={[1, 1]}
74        style={{
75          width: 100,
76          height: 200,
77          borderWidth: 1,
78          marginVertical: 20,
79          borderColor: 'black',
80        }}
81      />
82      <Image
83        source={require('../../assets/images/confusing_gradient.png')}
84        style={{ width: 100, height: 200, marginVertical: 20 }}
85      />
86    </View>
87    <Text style={{ marginHorizontal: 20 }}>The gradients above should look the same.</Text>
88  </Container>
89);
90
91const ControlPointTest: React.FunctionComponent<{
92  start?: [number, number];
93  end?: [number, number];
94}> = ({
95  start = [0.5, 0],
96  end = [0, 1],
97}) => {
98  const startInfo = `start={[${start.map(point => +point.toFixed(2)).join(', ')}]}`;
99  const endInfo = `end={[${end.map(point => +point.toFixed(2)).join(', ')}]}`;
100
101  return (
102    <Container title="Control Points">
103      <View>
104        {[startInfo, endInfo].map((pointInfo, index) => (
105          <MonoText key={'--' + index}>
106            {pointInfo}
107          </MonoText>
108        ))}
109      </View>
110      <LinearGradient
111        start={start}
112        end={end}
113        locations={[0.5, 0.5]}
114        colors={['blue', 'lime']}
115        style={{ flex: 1, height: 200 }}
116      />
117    </Container>
118  );
119};
120
121const ColorsTest = ({ colors }: { colors: string[] }) => {
122  const info = colors.map(value => `"${value}"`).join(', ');
123  return (
124    <Container title="Colors">
125      <MonoText>{`colors={[${info}]}`}</MonoText>
126      <LinearGradient colors={colors} style={{ flex: 1, height: 200 }} />
127    </Container>
128  );
129};
130
131const LocationsTest: React.FunctionComponent<{ locations: number[] }> = ({ locations }) => {
132  const locationsInfo = locations.map(location => +location.toFixed(2)).join(', ');
133  return (
134    <Container title="Locations">
135      <MonoText>{`locations={[${locationsInfo}]}`}</MonoText>
136      <LinearGradient
137        colors={['red', 'blue']}
138        locations={locations}
139        style={{ flex: 1, height: 200 }}
140      />
141    </Container>
142  );
143};
144
145const styles = StyleSheet.create({
146  container: {
147    padding: 8,
148  },
149  containerTitle: {
150    fontSize: 14,
151    fontWeight: '600',
152    textAlign: 'center',
153    marginBottom: 8,
154  },
155});
156