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        <ColorsTest colors={[this.state.colorTop, this.state.colorBottom]} />
51        <LocationsTest locations={[location, 1.0 - location]} />
52        <ControlPointTest start={[position, 0]} />
53        {Platform.OS !== 'web' && <SnapshotTest />}
54      </ScrollView>
55    );
56  }
57}
58
59const Container: React.FunctionComponent<{ title: string }> = ({ title, children }) => (
60  <View style={styles.container}>
61    <Text style={styles.containerTitle}>{title}</Text>
62    {children}
63  </View>
64);
65
66const SnapshotTest = () => (
67  <Container title="Snapshot">
68    <View style={{ flexDirection: 'row', alignSelf: 'stretch', justifyContent: 'space-evenly' }}>
69      <LinearGradient
70        colors={['white', 'red']}
71        start={[0.5, 0.5]}
72        end={[1, 1]}
73        style={{
74          width: 100,
75          maxHeight: 200,
76          minHeight: 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}> = ({ start = [0.5, 0], end = [0, 1] }) => {
95  const startInfo = `start={[${start.map(point => +point.toFixed(2)).join(', ')}]}`;
96  const endInfo = `end={[${end.map(point => +point.toFixed(2)).join(', ')}]}`;
97
98  return (
99    <Container title="Control Points">
100      <View>
101        {[startInfo, endInfo].map((pointInfo, index) => (
102          <MonoText key={'--' + index}>{pointInfo}</MonoText>
103        ))}
104      </View>
105      <LinearGradient
106        start={start}
107        end={end}
108        locations={[0.5, 0.5]}
109        colors={['blue', 'lime']}
110        style={styles.gradient}
111      />
112    </Container>
113  );
114};
115
116const ColorsTest = ({ colors }: { colors: string[] }) => {
117  const info = colors.map(value => `"${value}"`).join(', ');
118  return (
119    <Container title="Colors">
120      <MonoText>{`colors={[${info}]}`}</MonoText>
121      <LinearGradient colors={colors} style={styles.gradient} />
122    </Container>
123  );
124};
125
126const LocationsTest: React.FunctionComponent<{ locations: number[] }> = ({ locations }) => {
127  const locationsInfo = locations.map(location => +location.toFixed(2)).join(', ');
128  return (
129    <Container title="Locations">
130      <MonoText>{`locations={[${locationsInfo}]}`}</MonoText>
131      <LinearGradient colors={['red', 'blue']} locations={locations} style={styles.gradient} />
132    </Container>
133  );
134};
135
136const styles = StyleSheet.create({
137  container: {
138    padding: 8,
139    flexShrink: 0,
140  },
141  containerTitle: {
142    fontSize: 14,
143    fontWeight: '600',
144    textAlign: 'center',
145    marginBottom: 8,
146  },
147  gradient: {
148    flex: 1,
149    flexShrink: 0,
150    minHeight: 200,
151    maxHeight: 200,
152  },
153});
154