├── .eslintrc.js
├── App.js
├── app.json
├── assets
├── fonts
│ └── SpaceMono-Regular.ttf
└── images
│ ├── doggo.jpeg
│ ├── icon.png
│ ├── robot-dev.png
│ ├── robot-prod.png
│ └── splash.png
├── babel.config.js
├── components
├── StyledText.js
└── TabBarIcon.js
├── constants
├── Colors.js
└── Layout.js
├── navigation
├── AppNavigator.js
└── MainTabNavigator.js
├── package.json
├── screens
├── ClientSays.js
├── LinksScreen.js
├── SettingsScreen.js
├── Task0.js
├── Task0b.js
├── Task1.js
├── Task2.js
├── Task3.js
├── Task4.js
├── Task5.js
├── Task6.js
└── react-hexagon.png
└── yarn.lock
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | "env": {
3 | "browser": true,
4 | "es6": true
5 | },
6 | "parser": "babel-eslint",
7 | 'extends': [
8 | 'plugin:react/recommended'
9 | ],
10 | "parserOptions": {
11 | "ecmaFeatures": {
12 | "jsx": true
13 | },
14 | "ecmaVersion": 2018,
15 | "sourceType": "module"
16 | },
17 | "plugins": [
18 | "react"
19 | ],
20 | "rules": {
21 | "indent": [
22 | "error",
23 | 2
24 | ],
25 | "max-len": [
26 | 0,
27 | 80,
28 | ],
29 | "no-undef": [
30 | 0
31 | ],
32 | "linebreak-style": [
33 | "error",
34 | "unix"
35 | ],
36 | "quotes": [
37 | "error",
38 | "single"
39 | ],
40 | "semi": [
41 | "error",
42 | "never"
43 | ],
44 | "react/prop-types": [
45 | 0
46 | ]
47 | }
48 | };
49 |
--------------------------------------------------------------------------------
/App.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Platform, StatusBar, StyleSheet, View } from 'react-native'
3 | import { AppLoading, Asset, Font, Icon } from 'expo'
4 | import AppNavigator from './navigation/AppNavigator'
5 |
6 | export default class App extends React.Component {
7 | state = {
8 | isLoadingComplete: false,
9 | };
10 |
11 | render() {
12 | if (!this.state.isLoadingComplete && !this.props.skipLoadingScreen) {
13 | return (
14 |
19 | )
20 | } else {
21 | return (
22 |
23 | {Platform.OS === 'ios' && }
24 |
25 |
26 | )
27 | }
28 | }
29 |
30 | _loadResourcesAsync = async () => {
31 | return Promise.all([
32 | Asset.loadAsync([
33 | require('./assets/images/robot-dev.png'),
34 | require('./assets/images/robot-prod.png'),
35 | ]),
36 | Font.loadAsync({
37 | // This is the font that we are using for our tab bar
38 | ...Icon.Ionicons.font,
39 | // We include SpaceMono because we use it in HomeScreen.js. Feel free
40 | // to remove this if you are not using it in your app
41 | 'space-mono': require('./assets/fonts/SpaceMono-Regular.ttf'),
42 | }),
43 | ])
44 | };
45 |
46 | _handleLoadingError = error => {
47 | // In this case, you might want to report the error to your error
48 | // reporting service, for example Sentry
49 | console.warn(error)
50 | };
51 |
52 | _handleFinishLoading = () => {
53 | this.setState({ isLoadingComplete: true })
54 | };
55 | }
56 |
57 | const styles = StyleSheet.create({
58 | container: {
59 | flex: 1,
60 | backgroundColor: '#fff',
61 | },
62 | })
63 |
--------------------------------------------------------------------------------
/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "expo": {
3 | "name": "workshop",
4 | "slug": "workshop",
5 | "privacy": "public",
6 | "sdkVersion": "32.0.0",
7 | "platforms": [
8 | "ios",
9 | "android"
10 | ],
11 | "version": "1.0.0",
12 | "orientation": "portrait",
13 | "icon": "./assets/images/icon.png",
14 | "splash": {
15 | "image": "./assets/images/splash.png",
16 | "resizeMode": "contain",
17 | "backgroundColor": "#ffffff"
18 | },
19 | "updates": {
20 | "fallbackToCacheTimeout": 0
21 | },
22 | "assetBundlePatterns": [
23 | "**/*"
24 | ],
25 | "ios": {
26 | "supportsTablet": true
27 | }
28 | }
29 | }
--------------------------------------------------------------------------------
/assets/fonts/SpaceMono-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/osdnk/appjs-workshop/478cb3dadb2504b9a6b0bfe25b90a1ae75b2d0f0/assets/fonts/SpaceMono-Regular.ttf
--------------------------------------------------------------------------------
/assets/images/doggo.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/osdnk/appjs-workshop/478cb3dadb2504b9a6b0bfe25b90a1ae75b2d0f0/assets/images/doggo.jpeg
--------------------------------------------------------------------------------
/assets/images/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/osdnk/appjs-workshop/478cb3dadb2504b9a6b0bfe25b90a1ae75b2d0f0/assets/images/icon.png
--------------------------------------------------------------------------------
/assets/images/robot-dev.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/osdnk/appjs-workshop/478cb3dadb2504b9a6b0bfe25b90a1ae75b2d0f0/assets/images/robot-dev.png
--------------------------------------------------------------------------------
/assets/images/robot-prod.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/osdnk/appjs-workshop/478cb3dadb2504b9a6b0bfe25b90a1ae75b2d0f0/assets/images/robot-prod.png
--------------------------------------------------------------------------------
/assets/images/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/osdnk/appjs-workshop/478cb3dadb2504b9a6b0bfe25b90a1ae75b2d0f0/assets/images/splash.png
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = function(api) {
2 | api.cache(true)
3 | return {
4 | presets: ['babel-preset-expo'],
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/components/StyledText.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Text } from 'react-native'
3 |
4 | export class MonoText extends React.Component {
5 | render() {
6 | return
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/components/TabBarIcon.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Icon } from 'expo'
3 |
4 | import Colors from '../constants/Colors'
5 |
6 | export default class TabBarIcon extends React.Component {
7 | render() {
8 | return (
9 |
15 | )
16 | }
17 | }
--------------------------------------------------------------------------------
/constants/Colors.js:
--------------------------------------------------------------------------------
1 | const tintColor = '#2f95dc'
2 |
3 | export default {
4 | tintColor,
5 | tabIconDefault: '#ccc',
6 | tabIconSelected: tintColor,
7 | tabBar: '#fefefe',
8 | errorBackground: 'red',
9 | errorText: '#fff',
10 | warningBackground: '#EAEB5E',
11 | warningText: '#666804',
12 | noticeBackground: tintColor,
13 | noticeText: '#fff',
14 | }
15 |
--------------------------------------------------------------------------------
/constants/Layout.js:
--------------------------------------------------------------------------------
1 | import { Dimensions } from 'react-native'
2 |
3 | const width = Dimensions.get('window').width
4 | const height = Dimensions.get('window').height
5 |
6 | export default {
7 | window: {
8 | width,
9 | height,
10 | },
11 | isSmallDevice: width < 375,
12 | }
13 |
--------------------------------------------------------------------------------
/navigation/AppNavigator.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { createAppContainer, createSwitchNavigator } from 'react-navigation'
3 |
4 | import MainTabNavigator from './MainTabNavigator'
5 |
6 | export default createAppContainer(createSwitchNavigator({
7 | // You could add another route here for authentication.
8 | // Read more at https://reactnavigation.org/docs/en/auth-flow.html
9 | Main: MainTabNavigator,
10 | }))
--------------------------------------------------------------------------------
/navigation/MainTabNavigator.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable react/display-name */
2 | import React from 'react'
3 | import { Platform } from 'react-native'
4 | import { createBottomTabNavigator } from 'react-navigation'
5 |
6 | import TabBarIcon from '../components/TabBarIcon'
7 | import Task0 from '../screens/Task0'
8 | import Task0b from '../screens/Task0b'
9 | import Task1 from '../screens/Task1'
10 | import Task2 from '../screens/Task2'
11 | import Task3 from '../screens/Task3'
12 | import Task4 from '../screens/Task4'
13 | import Task5 from '../screens/Task5'
14 | import Task6 from '../screens/Task6'
15 |
16 | // setInterval(() => {
17 | // let iters = 1e8, sum = 0;
18 | // while (iters-- > 0) sum += iters;
19 | // }, 300);
20 |
21 | const enhance = (Component, name) => {
22 | Component.navigationOptions = {
23 | tabBarLabel: name,
24 | header: null,
25 | tabBarIcon: ({ focused }) => (
26 |
34 | ),
35 | }
36 |
37 | return Component
38 | }
39 |
40 | export default createBottomTabNavigator({
41 | Task0: enhance(Task0, 'Task 0'),
42 | Task0b: enhance(Task0b, 'Task 0b'),
43 | Task1: enhance(Task1, 'Task 1'),
44 | Task2: enhance(Task2, 'Task 2'),
45 | Task3: enhance(Task3, 'Task 3'),
46 | Task4: enhance(Task4, 'Task 4'),
47 | Task5: enhance(Task5, 'Task 5'),
48 | Task6: enhance(Task6, 'Task 6'),
49 | }, {
50 | initialRouteName: 'Task0',
51 | })
52 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "main": "node_modules/expo/AppEntry.js",
3 | "scripts": {
4 | "start": "expo start",
5 | "android": "expo start --android",
6 | "ios": "expo start --ios",
7 | "eject": "expo eject",
8 | "test": "node ./node_modules/jest/bin/jest.js --watchAll"
9 | },
10 | "jest": {
11 | "preset": "jest-expo"
12 | },
13 | "dependencies": {
14 | "@expo/samples": "2.1.1",
15 | "expo": "^32.0.0",
16 | "react": "16.5.0",
17 | "react-native": "https://github.com/expo/react-native/archive/sdk-32.0.0.tar.gz",
18 | "react-navigation": "^3.0.9"
19 | },
20 | "devDependencies": {
21 | "babel-eslint": "^10.0.1",
22 | "babel-preset-expo": "^5.0.0",
23 | "eslint": "^5.15.1",
24 | "eslint-plugin-react": "^7.12.4",
25 | "jest-expo": "^32.0.0"
26 | },
27 | "private": true
28 | }
29 |
--------------------------------------------------------------------------------
/screens/ClientSays.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable react/prop-types */
2 | import React from 'react'
3 | import { TouchableOpacity, View } from 'react-native'
4 | import { Icon } from 'expo'
5 | import { MonoText } from '../components/StyledText'
6 |
7 | export class CliectSays extends React.Component {
8 | state = {
9 | text: ''
10 | };
11 |
12 | onPress = () => {
13 | if (this.props.text.length === this.state.text.length) {
14 | this.setState({
15 | text: ''
16 | })
17 | return
18 | }
19 | this.timer = setInterval(() => {
20 | if (this.props.text.length === this.state.text.length) {
21 | clearInterval(this.timer)
22 | return
23 | }
24 | this.setState(prev => ({
25 | text: this.props.text.substring(0, prev.text.length + 1)
26 | }))
27 | }, 30)
28 | };
29 |
30 | componentWillUnmount() {
31 | clearInterval(this.timer)
32 | }
33 |
34 | render() {
35 | return (
36 |
48 |
49 | {!!this.state.text.length &&
56 |
57 | {this.state.text}
58 |
59 |
60 | }
61 |
62 | )
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/screens/LinksScreen.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { ScrollView, StyleSheet } from 'react-native'
3 | import { ExpoLinksView } from '@expo/samples'
4 |
5 | export default class LinksScreen extends React.Component {
6 | static navigationOptions = {
7 | title: 'Links',
8 | };
9 |
10 | render() {
11 | return (
12 |
13 | {/* Go ahead and delete ExpoLinksView and replace it with your
14 | * content, we just wanted to provide you with some helpful links */}
15 |
16 |
17 | )
18 | }
19 | }
20 |
21 | const styles = StyleSheet.create({
22 | container: {
23 | flex: 1,
24 | paddingTop: 15,
25 | backgroundColor: '#fff',
26 | },
27 | })
28 |
--------------------------------------------------------------------------------
/screens/SettingsScreen.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { ExpoConfigView } from '@expo/samples'
3 |
4 | export default class SettingsScreen extends React.Component {
5 | static navigationOptions = {
6 | title: 'app.json',
7 | };
8 |
9 | render() {
10 | /* Go ahead and delete ExpoConfigView and replace it with your
11 | * content, we just wanted to give you a quick view of your config */
12 | return
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/screens/Task0.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Animated, StyleSheet, View, ScrollView } from 'react-native'
3 | import { GestureHandler } from 'expo'
4 | import { CliectSays } from './ClientSays'
5 | import { MonoText } from '../components/StyledText'
6 |
7 | const { PanGestureHandler, State } = GestureHandler
8 | export default class Task0 extends React.Component {
9 | render() {
10 | return (
11 |
12 |
13 |
14 | At vero eos et accusamus et iusto odio dignissimos
15 | ducimus qui blanditiis praesentium voluptatum deleniti
16 | atque corrupti quos dolores et quas molestias excepturi
17 | sint occaecati cupiditate non provident, similique
18 | sunt in culpa qui officia deserunt mollitia animi,
19 | id est laborum et dolorum fuga. Et harum quidem
20 | rerum facilis est et expedita distinctio. Nam libero
21 | tempore, cum soluta nobis est eligendi optio cumque
22 | nihil impedit quo minus id quod maxime placeat facere
23 | possimus, omnis voluptas assumenda est, omnis dolor
24 | repellendus. Temporibus autem quibusdam et aut officiis
25 | debitis aut rerum necessitatibus saepe eveniet ut et
26 | voluptates repudiandae sint et molestiae non recusandae.
27 | Itaque earum rerum hic tenetur a sapiente delectus, ut aut
28 | reiciendis voluptatibus maiores alias consequatur aut
29 | perferendis doloribus asperiores repellat.
30 | At vero eos et accusamus et iusto odio dignissimos
31 | ducimus qui blanditiis praesentium voluptatum deleniti
32 | atque corrupti quos dolores et quas molestias excepturi
33 | sint occaecati cupiditate non provident, similique
34 | sunt in culpa qui officia deserunt mollitia animi,
35 | id est laborum et dolorum fuga. Et harum quidem
36 | rerum facilis est et expedita distinctio. Nam libero
37 | tempore, cum soluta nobis est eligendi optio cumque
38 | nihil impedit quo minus id quod maxime placeat facere
39 | possimus, omnis voluptas assumenda est, omnis dolor
40 | repellendus. Temporibus autem quibusdam et aut officiis
41 | debitis aut rerum necessitatibus saepe eveniet ut et
42 | voluptates repudiandae sint et molestiae non recusandae.
43 | Itaque earum rerum hic tenetur a sapiente delectus, ut aut
44 | reiciendis voluptatibus maiores alias consequatur aut
45 | perferendis doloribus asperiores repellat.
46 |
47 |
48 |
49 |
50 | )
51 | }
52 | }
53 |
54 | const styles = StyleSheet.create({
55 | container: {
56 | flex: 1,
57 | backgroundColor: '#fff',
58 | justifyContent: 'center',
59 | },
60 | box: {
61 | width: 100,
62 | backgroundColor: 'yellow',
63 | height: 100,
64 | }
65 | })
66 |
--------------------------------------------------------------------------------
/screens/Task0b.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Animated, StyleSheet, View, ScrollView, Image } from 'react-native'
3 | import { GestureHandler } from 'expo'
4 | import { CliectSays } from './ClientSays'
5 | import { MonoText } from '../components/StyledText'
6 |
7 | const AniamtedImage = props => (
8 |
21 | )
22 |
23 | const Lorem = () => (
24 |
29 |
30 | At vero eos et accusamus et iusto odio dignissimos
31 | ducimus qui blanditiis praesentium voluptatum deleniti
32 | atque corrupti quos dolores et quas molestias excepturi
33 | sint occaecati cupiditate non provident, similique
34 | sunt in culpa qui officia deserunt mollitia animi,
35 | id est laborum et dolorum fuga. Et harum quidem
36 | rerum facilis est et expedita distinctio. Nam libero
37 | tempore, cum soluta nobis est eligendi optio cumque
38 | nihil impedit quo minus id quod maxime placeat facere
39 | possimus, omnis voluptas assumenda est, omnis dolor
40 | repellendus. Temporibus autem quibusdam et aut officiis
41 | debitis aut rerum necessitatibus saepe eveniet ut et
42 | voluptates repudiandae sint et molestiae non recusandae.
43 | Itaque earum rerum hic tenetur a sapiente delectus, ut aut
44 | reiciendis voluptatibus maiores alias consequatur aut
45 | perferendis doloribus asperiores repellat.
46 | At vero eos et accusamus et iusto odio dignissimos
47 | ducimus qui blanditiis praesentium voluptatum deleniti
48 | atque corrupti quos dolores et quas molestias excepturi
49 | sint occaecati cupiditate non provident, similique
50 | sunt in culpa qui officia deserunt mollitia animi,
51 | id est laborum et dolorum fuga. Et harum quidem
52 | rerum facilis est et expedita distinctio. Nam libero
53 | tempore, cum soluta nobis est eligendi optio cumque
54 | nihil impedit quo minus id quod maxime placeat facere
55 | possimus, omnis voluptas assumenda est, omnis dolor
56 | repellendus. Temporibus autem quibusdam et aut officiis
57 | debitis aut rerum necessitatibus saepe eveniet ut et
58 | voluptates repudiandae sint et molestiae non recusandae.
59 | Itaque earum rerum hic tenetur a sapiente delectus, ut aut
60 | reiciendis voluptatibus maiores alias consequatur aut
61 | perferendis doloribus asperiores repellat.
62 |
63 |
64 | )
65 |
66 | const Header = () => (
67 |
74 |
75 | Header
76 |
77 |
78 | )
79 |
80 | const { PanGestureHandler, State } = GestureHandler
81 | export default class Task0 extends React.Component {
82 | trans = new Animated.Value(0)
83 | int = this.trans.interpolate({
84 | inputRange: [0, 100, 110],
85 | outputRange: [0, 50, 50],
86 | })
87 | render() {
88 | return (
89 |
90 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 | )
103 | }
104 | }
105 |
106 | const styles = StyleSheet.create({
107 | container: {
108 | flex: 1,
109 | backgroundColor: '#fff',
110 | justifyContent: 'center',
111 | marginTop: 16
112 | },
113 | box: {
114 | width: 100,
115 | backgroundColor: 'yellow',
116 | height: 100,
117 | }
118 | })
119 |
--------------------------------------------------------------------------------
/screens/Task1.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Animated, StyleSheet, View, } from 'react-native'
3 | import { GestureHandler } from 'expo'
4 | import { CliectSays } from './ClientSays'
5 |
6 | const { PanGestureHandler, State } = GestureHandler
7 | export default class Task1 extends React.Component {
8 | render() {
9 | return (
10 |
11 |
16 |
17 |
18 | )
19 | }
20 | }
21 |
22 | const styles = StyleSheet.create({
23 | container: {
24 | flex: 1,
25 | backgroundColor: '#fff',
26 | justifyContent: 'center',
27 | alignItems: 'center'
28 | },
29 | box: {
30 | width: 100,
31 | backgroundColor: 'yellow',
32 | height: 100,
33 | }
34 | })
35 |
--------------------------------------------------------------------------------
/screens/Task2.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Animated, StyleSheet, View, } from 'react-native'
3 | import { GestureHandler } from 'expo'
4 | import { CliectSays } from './ClientSays'
5 |
6 | const { PanGestureHandler, State, PinchGestureHandler, RotationGestureHandler } = GestureHandler
7 |
8 |
9 | export default class Task1 extends React.Component {
10 | translateX = new Animated.Value(0);
11 | translateY = new Animated.Value(0);
12 | prevX = 0;
13 | prevY = 0;
14 |
15 | onPanGestureEvent = Animated.event(
16 | [
17 | {
18 | nativeEvent: {
19 | translationX: this.translateX,
20 | translationY: this.translateY,
21 | },
22 | },
23 | ],
24 | { useNativeDriver: true }
25 | );
26 |
27 | onPanHandlerStateChange = ({ nativeEvent: { oldState, translationX, translationY } }) => {
28 | if (oldState === State.ACTIVE) {
29 | this.prevX += translationX
30 | this.prevY += translationY
31 | this.translateX.setValue(0)
32 | this.translateY.setValue(0)
33 | this.translateX.setOffset(this.prevX)
34 | this.translateY.setOffset(this.prevY)
35 | }
36 | };
37 |
38 | render() {
39 | return (
40 |
41 |
46 |
51 |
52 |
55 |
56 |
59 |
60 |
63 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 | )
82 | }
83 | }
84 |
85 | const styles = StyleSheet.create({
86 | container: {
87 | flex: 1,
88 | backgroundColor: '#fff',
89 | justifyContent: 'center',
90 | alignItems: 'center'
91 | },
92 | box: {
93 | width: 100,
94 | backgroundColor: 'yellow',
95 | height: 100,
96 | },
97 | })
98 |
--------------------------------------------------------------------------------
/screens/Task3.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Animated, StyleSheet, View, } from 'react-native'
3 | import { GestureHandler } from 'expo'
4 | import { CliectSays } from './ClientSays'
5 |
6 | const { PanGestureHandler, State, PinchGestureHandler, RotationGestureHandler } = GestureHandler
7 |
8 |
9 | export default class Task1 extends React.Component {
10 | translateX = new Animated.Value(0);
11 | translateY = new Animated.Value(0);
12 | prevX = 0;
13 | prevY = 0;
14 |
15 | onPanGestureEvent = Animated.event(
16 | [
17 | {
18 | nativeEvent: {
19 | translationX: this.translateX,
20 | translationY: this.translateY,
21 | },
22 | },
23 | ],
24 | { useNativeDriver: true }
25 | );
26 |
27 | onPanHandlerStateChange = ({ nativeEvent: { oldState, translationX, translationY } }) => {
28 | if (oldState === State.ACTIVE) {
29 | this.prevX += translationX
30 | this.prevY += translationY
31 | this.translateX.setValue(0)
32 | this.translateY.setValue(0)
33 | this.translateX.setOffset(this.prevX)
34 | this.translateY.setOffset(this.prevY)
35 | }
36 | };
37 |
38 | baseScale = new Animated.Value(1);
39 | pinchScale = new Animated.Value(1);
40 | scale = Animated.multiply(this.baseScale, this.pinchScale);
41 | lastScale = 1;
42 | onPinchGestureEvent = Animated.event(
43 | [{ nativeEvent: { scale: this.pinchScale } }],
44 | { useNativeDriver: true }
45 | );
46 |
47 | onPinchHandlerStateChange = event => {
48 | if (event.nativeEvent.oldState === State.ACTIVE) {
49 | this.lastScale *= event.nativeEvent.scale
50 | this.baseScale.setValue(this.lastScale)
51 | this.pinchScale.setValue(1)
52 | }
53 | };
54 |
55 | baseRotation = new Animated.Value(0);
56 | zoomRotation = new Animated.Value(0);
57 | rotation = Animated.add(this.baseRotation, this.zoomRotation);
58 | lastRotation = 0;
59 | onRotationGestureEvent = Animated.event(
60 | [{ nativeEvent: { rotation: this.zoomRotation } }],
61 | { useNativeDriver: true }
62 | );
63 |
64 | rotationString = this.rotation.interpolate({
65 | inputRange: [-100, 100],
66 | outputRange: ['-100rad', '100rad'],
67 | });
68 |
69 | onRotationHandlerStateChange = event => {
70 | if (event.nativeEvent.oldState === State.ACTIVE) {
71 | this.lastRotation += event.nativeEvent.rotation
72 | this.baseRotation.setValue(this.lastRotation)
73 | this.zoomRotation.setValue(0)
74 | }
75 | };
76 |
77 | pinch = React.createRef();
78 | pan = React.createRef();
79 | rotate = React.createRef();
80 |
81 | render() {
82 | return (
83 |
84 |
89 |
96 |
97 |
100 |
105 |
108 |
113 |
116 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 | )
137 | }
138 | }
139 |
140 | const styles = StyleSheet.create({
141 | container: {
142 | flex: 1,
143 | backgroundColor: '#fff',
144 | justifyContent: 'center',
145 | alignItems: 'center'
146 | },
147 | box: {
148 | width: 100,
149 | backgroundColor: 'yellow',
150 | height: 100,
151 | },
152 | })
153 |
--------------------------------------------------------------------------------
/screens/Task4.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { StyleSheet, View } from 'react-native'
3 | import { DangerZone, GestureHandler } from 'expo'
4 | import { CliectSays } from './ClientSays'
5 |
6 | const { Animated } = DangerZone
7 | const {
8 | PanGestureHandler,
9 | PinchGestureHandler,
10 | State,
11 | } = GestureHandler
12 |
13 | const { set, Easing, timing, cond, block, eq, add, Value, sub,event, diff, multiply, clockRunning, startClock, stopClock, decay, Clock } = Animated
14 |
15 | function runTiming(clock, value, dest) {
16 | const state = {
17 | finished: new Value(0),
18 | position: new Value(0),
19 | frameTime: new Value(0),
20 | time: new Value(0),
21 | };
22 |
23 | const config = {
24 | toValue: new Value(0),
25 | duration: 300,
26 | easing: Easing.inOut(Easing.cubic),
27 | };
28 |
29 | return [
30 | cond(clockRunning(clock), 0, [
31 | set(state.finished, 0),
32 | set(state.frameTime, 0),
33 | set(state.time, 0),
34 | set(state.position, value),
35 | set(config.toValue, dest),
36 | startClock(clock),
37 | ]),
38 | timing(clock, state, config),
39 | cond(state.finished, stopClock(clock)),
40 | state.position,
41 | ];
42 | }
43 |
44 | function withPreservingOffset(drag, state) {
45 | const prev = new Animated.Value(0)
46 | const valWithPreservedOffset = new Animated.Value(0)
47 | return block([
48 | cond(eq(state, State.BEGAN), [
49 | set(prev, 0)
50 | ], [
51 | set(valWithPreservedOffset, add(valWithPreservedOffset, sub(drag, prev))),
52 | set(prev, drag),
53 | ]),
54 | valWithPreservedOffset
55 | ])
56 | }
57 |
58 | function runDecay(clock, value, velocity) {
59 | const state = {
60 | finished: new Value(0),
61 | velocity: new Value(0),
62 | position: new Value(0),
63 | time: new Value(0),
64 | }
65 | const config = { deceleration: 0.99 }
66 | return [
67 | cond(clockRunning(clock), 0, [
68 | set(state.finished, 0),
69 | set(state.velocity, velocity),
70 | set(state.position, value),
71 | set(state.time, 0),
72 | startClock(clock),
73 | ]),
74 | decay(clock, state, config),
75 | cond(state.finished, stopClock(clock)),
76 | state.position,
77 | ]
78 | }
79 |
80 | export default class Example extends Component {
81 | constructor(props) {
82 | super(props)
83 | this.Y = new Value(0)
84 | this.R = new Value(0)
85 | this.Z = new Value(1)
86 | const prevZ = new Value(1)
87 | const dragX = new Value(0)
88 | const dragY = new Value(0)
89 | const panState = new Value(0)
90 |
91 |
92 | this.handlePan = event([
93 | {
94 | nativeEvent: ({
95 | translationX: dragX,
96 | translationY: dragY,
97 | state: panState
98 | })
99 | },
100 | ])
101 |
102 | this.handleZoom = event([
103 | {
104 | nativeEvent: ({ scale: z, state }) =>
105 | block([
106 | cond(eq(state, State.ACTIVE), set(this.Z, multiply(z, prevZ))),
107 | cond(eq(state, State.END), [set(prevZ, this.Z)]),
108 | ]),
109 | },
110 | ])
111 |
112 | this.X = withPreservingOffset(dragX, panState)
113 | this.Y = withPreservingOffset(dragY, panState)
114 | }
115 |
116 | panRef = React.createRef();
117 | pinchRef = React.createRef();
118 |
119 | render() {
120 | return (
121 |
122 |
129 |
135 |
138 |
143 |
146 |
147 |
161 |
162 |
163 |
164 |
165 |
166 | )
167 | }
168 | }
169 |
170 | const IMAGE_SIZE = 200
171 |
172 | const styles = StyleSheet.create({
173 | container: {
174 | flex: 1,
175 | backgroundColor: '#F5FCFF',
176 | justifyContent: 'center',
177 | alignItems: 'center',
178 | },
179 | box: {
180 | width: IMAGE_SIZE,
181 | height: IMAGE_SIZE,
182 | },
183 | })
184 |
185 |
--------------------------------------------------------------------------------
/screens/Task5.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { StyleSheet, View } from 'react-native'
3 | import { DangerZone, GestureHandler } from 'expo'
4 | import { CliectSays } from './ClientSays'
5 |
6 | const { Animated } = DangerZone
7 | const {
8 | PanGestureHandler,
9 | PinchGestureHandler,
10 | State,
11 | } = GestureHandler
12 |
13 | const { set, cond, block, eq, add, Value, divide, greaterThan, sub,event, diff, multiply, clockRunning, startClock, stopClock, decay, Clock, lessThan } = Animated
14 |
15 | function runDecay(clock, value, velocity, wasStartedFromBegin) {
16 | const state = {
17 | finished: new Value(0),
18 | velocity: new Value(0),
19 | position: new Value(0),
20 | time: new Value(0),
21 | }
22 |
23 | const config = { deceleration: 0.99 }
24 |
25 | return [
26 | cond(clockRunning(clock), 0, [
27 | cond(wasStartedFromBegin, 0, [
28 | set(wasStartedFromBegin, 1),
29 | set(state.finished, 0),
30 | set(state.velocity, velocity),
31 | set(state.position, value),
32 | set(state.time, 0),
33 | startClock(clock),
34 | ]),
35 | ]),
36 | // set(state.position, value),
37 | decay(clock, state, config),
38 | cond(state.finished, stopClock(clock)),
39 | state.position,
40 | ]
41 | }
42 |
43 | function withPreservingMultiplicativeOffset (val, state) {
44 | const prev = new Animated.Value(1)
45 | const valWithPreservedOffset = new Animated.Value(1)
46 | return block([
47 | cond(eq(state, State.BEGAN), [
48 | set(prev, 1)
49 | ], [
50 | set(valWithPreservedOffset, multiply(valWithPreservedOffset, divide(val, prev))),
51 | set(prev, val),
52 | ]),
53 | valWithPreservedOffset
54 | ])
55 | }
56 |
57 | function withPreservingAdditiveOffset(drag, state) {
58 | const prev = new Animated.Value(0)
59 | const valWithPreservedOffset = new Animated.Value(0)
60 | return block([
61 | cond(eq(state, State.BEGAN), [
62 | set(prev, 0)
63 | ], [
64 | set(valWithPreservedOffset, add(valWithPreservedOffset, sub(drag, prev))),
65 | set(prev, drag),
66 | ]),
67 | valWithPreservedOffset
68 | ])
69 | }
70 |
71 | function withDecaying(drag, state, velocity) {
72 | const valDecayed = new Animated.Value(0)
73 | const offset = new Animated.Value(0)
74 | const decayClock = new Clock()
75 | // since there might be moar than one clock
76 | const wasStartedFromBegin = new Animated.Value(0)
77 | return block([
78 | cond(eq(state, State.END),
79 | [
80 | set(valDecayed, runDecay(decayClock, add(drag, offset), velocity, wasStartedFromBegin))
81 | ],
82 | [
83 | stopClock(decayClock),
84 | cond(eq(state, State.BEGAN), [
85 | set(wasStartedFromBegin, 0),
86 | set(offset, add(sub(valDecayed, drag)))
87 | ]),
88 | set(valDecayed, add(drag, offset))
89 |
90 | ],
91 | ),
92 | valDecayed,
93 | ])
94 | }
95 |
96 |
97 | export default class Example extends Component {
98 | constructor(props) {
99 | super(props)
100 | const dragX = new Value(0)
101 | const dragY = new Value(0)
102 | const scale = new Value(1)
103 | const panState = new Value(0)
104 | const scaleState = new Value(0)
105 | const velocityX = new Value(0)
106 | const velocityY = new Value(0)
107 |
108 |
109 | this.handlePan = event([
110 | {
111 | nativeEvent: ({
112 | translationX: dragX,
113 | translationY: dragY,
114 | state: panState,
115 | velocityY,
116 | velocityX
117 | })
118 | },
119 | ])
120 |
121 | this.handleZoom = event([
122 | {
123 | nativeEvent: {
124 | scale,
125 | state: scaleState
126 | }
127 | },
128 | ])
129 |
130 | this.X = withDecaying(withPreservingAdditiveOffset(dragX, panState), panState, velocityX)
131 | this.Y = withDecaying(withPreservingAdditiveOffset(dragY, panState), panState, velocityY)
132 | this.scale = withPreservingMultiplicativeOffset(scale, scaleState)
133 | }
134 |
135 | panRef = React.createRef();
136 | pinchRef = React.createRef();
137 |
138 | render() {
139 | return (
140 |
141 |
148 |
153 |
156 |
161 |
164 |
178 |
179 |
180 |
181 |
182 |
183 | )
184 | }
185 | }
186 |
187 | const IMAGE_SIZE = 200
188 |
189 | const styles = StyleSheet.create({
190 | container: {
191 | flex: 1,
192 | backgroundColor: '#F5FCFF',
193 | justifyContent: 'center',
194 | alignItems: 'center',
195 | },
196 | box: {
197 | width: IMAGE_SIZE,
198 | height: IMAGE_SIZE,
199 | },
200 | })
201 |
202 |
--------------------------------------------------------------------------------
/screens/Task6.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { StyleSheet, View } from 'react-native'
3 | import { DangerZone, GestureHandler } from 'expo'
4 | import { CliectSays } from './ClientSays'
5 |
6 | const { Animated } = DangerZone
7 | const {
8 | PanGestureHandler,
9 | PinchGestureHandler,
10 | State,
11 | } = GestureHandler
12 |
13 | const { set, cond, block, eq, add, and, sqrt, Value, spring, or, divide, greaterThan, sub,event, diff, multiply, clockRunning, startClock, stopClock, decay, Clock, lessThan } = Animated
14 |
15 |
16 | function runDecay(clock, value, velocity, wasStartedFromBegin) {
17 | const state = {
18 | finished: new Value(0),
19 | velocity: new Value(0),
20 | position: new Value(0),
21 | time: new Value(0),
22 | }
23 |
24 | const config = { deceleration: 0.99 }
25 |
26 | return [
27 | cond(clockRunning(clock), 0, [
28 | cond(wasStartedFromBegin, 0, [
29 | set(wasStartedFromBegin, 1),
30 | set(state.finished, 0),
31 | set(state.velocity, velocity),
32 | set(state.position, value),
33 | set(state.time, 0),
34 | startClock(clock),
35 | ]),
36 | ]),
37 | // set(state.position, value),
38 | decay(clock, state, config),
39 | cond(state.finished, stopClock(clock)),
40 | state.position,
41 | ]
42 | }
43 |
44 | function withPreservingMultiplicativeOffset (val, state) {
45 | const prev = new Animated.Value(1)
46 | const valWithPreservedOffset = new Animated.Value(1)
47 | return block([
48 | cond(eq(state, State.BEGAN), [
49 | set(prev, 1)
50 | ], [
51 | set(valWithPreservedOffset, multiply(valWithPreservedOffset, divide(val, prev))),
52 | set(prev, val),
53 | ]),
54 | valWithPreservedOffset
55 | ])
56 | }
57 |
58 | function withPreservingAdditiveOffset(drag, state) {
59 | const prev = new Animated.Value(0)
60 | const valWithPreservedOffset = new Animated.Value(0)
61 | return block([
62 | cond(eq(state, State.BEGAN), [
63 | set(prev, 0)
64 | ], [
65 | set(valWithPreservedOffset, add(valWithPreservedOffset, sub(drag, prev))),
66 | set(prev, drag),
67 | ]),
68 | valWithPreservedOffset
69 | ])
70 | }
71 |
72 | function withDecaying(drag, state, velocity) {
73 | const valDecayed = new Animated.Value(0)
74 | const offset = new Animated.Value(0)
75 | const decayClock = new Clock()
76 | // since there might be moar than one clock
77 | const wasStartedFromBegin = new Animated.Value(0)
78 | return block([
79 | cond(eq(state, State.END),
80 | [
81 | set(valDecayed, runDecay(decayClock, add(drag, offset), velocity, wasStartedFromBegin))
82 | ],
83 | [
84 | stopClock(decayClock),
85 | cond(eq(state, State.BEGAN), [
86 | set(wasStartedFromBegin, 0),
87 | set(offset, add(sub(valDecayed, drag)))
88 | ]),
89 | set(valDecayed, add(drag, offset))
90 |
91 | ],
92 | ),
93 | valDecayed,
94 | ])
95 | }
96 |
97 |
98 | function runSpring(clock, value, velocity, dest) {
99 | const state = {
100 | finished: new Value(0),
101 | velocity: new Value(0),
102 | position: new Value(0),
103 | time: new Value(0),
104 | }
105 |
106 | const config = {
107 | damping: 7,
108 | mass: 1,
109 | stiffness: 121.6,
110 | overshootClamping: false,
111 | restSpeedThreshold: 0.001,
112 | restDisplacementThreshold: 0.001,
113 | toValue: new Value(0),
114 | }
115 |
116 | return [
117 | cond(clockRunning(clock), 0, [
118 | set(state.finished, 0),
119 | set(state.velocity, velocity),
120 | set(state.position, value),
121 | set(config.toValue, dest),
122 | startClock(clock),
123 | ]),
124 | spring(clock, state, config),
125 | cond(state.finished, stopClock(clock)),
126 | state.position,
127 | ]
128 | }
129 |
130 |
131 | function withLimits(val, min, max, state) {
132 | const offset = new Animated.Value(0)
133 | const offsetedVal = add(offset, val)
134 | return block([
135 | cond(eq(state, State.BEGAN),[
136 | cond(lessThan(offsetedVal, min),
137 | set(offset, sub(min, val))),
138 | cond(greaterThan(offsetedVal, max),
139 | set(offset, sub(max, val)))
140 | ]),
141 | cond(lessThan(offsetedVal, min), min, cond(greaterThan(offsetedVal, max), max, offsetedVal))
142 | ])
143 | }
144 |
145 | export default class Example extends Component {
146 | constructor(props) {
147 | super(props)
148 | const dragX = new Value(0)
149 | const dragY = new Value(0)
150 | const scale = new Value(1)
151 | const panState = new Value(0)
152 | const scaleState = new Value(0)
153 | const velocityX = new Value(0)
154 | const velocityY = new Value(0)
155 |
156 |
157 |
158 | this.handlePan = event([
159 | {
160 | nativeEvent: ({
161 | translationX: dragX,
162 | translationY: dragY,
163 | state: panState,
164 | velocityY,
165 | velocityX
166 | })
167 | },
168 | ])
169 |
170 | this.handleZoom = event([
171 | {
172 | nativeEvent: {
173 | scale,
174 | state: scaleState
175 | }
176 | },
177 | ])
178 |
179 | this.X = withLimits(withDecaying(withPreservingAdditiveOffset(dragX, panState), panState, velocityX), -100, 100, panState)
180 | this.Y = withLimits(withDecaying(withPreservingAdditiveOffset(dragY, panState), panState, velocityY), -100, 100, panState)
181 | this.scale = withLimits(withPreservingMultiplicativeOffset(scale, scaleState), 0.1, 2, scaleState)
182 | }
183 |
184 | panRef = React.createRef();
185 | pinchRef = React.createRef();
186 |
187 | render() {
188 | return (
189 |
190 |
197 |
202 |
205 |
210 |
213 |
227 |
228 |
229 |
230 |
231 |
232 | )
233 | }
234 | }
235 |
236 | const IMAGE_SIZE = 200
237 |
238 | const styles = StyleSheet.create({
239 | container: {
240 | flex: 1,
241 | backgroundColor: '#F5FCFF',
242 | justifyContent: 'center',
243 | alignItems: 'center',
244 | },
245 | box: {
246 | width: IMAGE_SIZE,
247 | height: IMAGE_SIZE,
248 | },
249 | })
250 |
251 |
--------------------------------------------------------------------------------
/screens/react-hexagon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/osdnk/appjs-workshop/478cb3dadb2504b9a6b0bfe25b90a1ae75b2d0f0/screens/react-hexagon.png
--------------------------------------------------------------------------------