├── Constants.js
├── _resources
├── babelRelayPlugin.js
└── schema.json
├── .babelrc
├── Utils
└── Relay
│ ├── AppRelay.js
│ ├── AsRelayContainer.js
│ ├── AppRelayNetworkLayer.js
│ └── AsRelayRenderer.js
├── RelayQueries
└── ViewerQuery.js
├── Components
├── WithFreightSansFont.js
├── WithFreightSansBoldFont.js
├── FadeIn.android.js
└── FadeIn.ios.js
├── Style
├── Colors.js
└── Layout.js
├── Navigation
├── ExTabScene.js
├── ExNavigationReducer.js
├── ExTabItem.js
├── ExBadge.js
├── ExTab.js
├── ExTabNavigator.js
├── ExTabBar.js
├── ExNavigationHeader.js
├── ExNavigationStackReducer.js
├── ExNavigationCard.js
└── ExNavigationAnimatedView.js
├── .gitignore
├── AppComponents
├── ExText.js
├── ExIcon.js
└── Schedule.js
├── LICENSE
├── package.json
├── README.md
├── .flowconfig
├── ReactConfApp.js
└── .eslintrc
/Constants.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @providesModule Constants
3 | */
4 | 'use strict';
5 |
6 | export default {
7 | cdnHost: 'https://s3-us-west-1.amazonaws.com/reactconf2016/',
8 | };
9 |
--------------------------------------------------------------------------------
/_resources/babelRelayPlugin.js:
--------------------------------------------------------------------------------
1 | const getBabelRelayPlugin = require('babel-relay-plugin');
2 | const schema = require('./schema.json');
3 |
4 | module.exports = getBabelRelayPlugin(schema.data);
5 |
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "passPerPreset": true,
3 | "presets": [
4 | { "plugins": "../_resources/babelRelayPlugin.js" },
5 | "react-native",
6 | ],
7 | "plugins": [
8 | "transform-export-extensions",
9 | "transform-decorators-legacy",
10 | "transform-react-constant-elements"
11 | ]
12 | }
13 |
--------------------------------------------------------------------------------
/Utils/Relay/AppRelay.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @providesModule AppRelay
3 | */
4 |
5 | import Relay from 'react-relay';
6 |
7 | export AppRelayNetworkLayer from 'AppRelayNetworkLayer';
8 | export AsRelayContainer from 'AsRelayContainer';
9 | export AsRelayRenderer from 'AsRelayRenderer';
10 |
11 | export { Relay };
12 |
--------------------------------------------------------------------------------
/RelayQueries/ViewerQuery.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @providesModule ViewerQuery
3 | */
4 |
5 | import Relay from 'react-relay';
6 |
7 | export default {
8 | queries: {
9 | viewer: Component => Relay.QL`
10 | query ViewerQuery {
11 | viewer {
12 | ${Component.getFragment('viewer')}
13 | }
14 | }`,
15 | },
16 | };
17 |
--------------------------------------------------------------------------------
/Components/WithFreightSansFont.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @providesModule WithFreightSansFont
3 | */
4 | 'use strict';
5 |
6 | import { createCustomFontComponent } from '@exponent/with-custom-font';
7 |
8 | import Constants from 'Constants';
9 |
10 | export default createCustomFontComponent({
11 | fontFamily: 'FreightSansLFPro',
12 | fontWeight: 'normal',
13 | fontFamilyAndroid: 'FreightSansLFPro',
14 | fontStyleAndroid: 'regular',
15 | uri: `${Constants.cdnHost}FreigSanLFProBoo.otf`,
16 | });
17 |
--------------------------------------------------------------------------------
/Components/WithFreightSansBoldFont.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @providesModule WithFreightSansBoldFont
3 | */
4 | 'use strict';
5 |
6 | import { createCustomFontComponent } from '@exponent/with-custom-font';
7 |
8 | import Constants from 'Constants';
9 |
10 | export default createCustomFontComponent({
11 | fontFamily: 'FreightSansLFPro',
12 | fontWeight: 'bold',
13 | fontFamilyAndroid: 'FreightSansLFPro',
14 | fontStyleAndroid: 'bold',
15 | uri: `${Constants.cdnHost}FreigSanLFProBol.otf`,
16 | });
17 |
--------------------------------------------------------------------------------
/Style/Colors.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2015-present 650 Industries. All rights reserved.
3 | *
4 | * @providesModule Colors
5 | * @flow
6 | */
7 | 'use strict';
8 |
9 | export default {
10 | transparent: 'rgba(0, 0, 0, 0)',
11 | tint: 'rgb(88, 136, 219)',
12 |
13 | backgroundWhite: '#fff',
14 | backgroundGray: '#f3f5f5',
15 | lighterSeparator: '#f5f5f5',
16 | separator: '#eaeaea',
17 | darkerSeparator: '#E5E5E5',
18 |
19 | slightlyFaded: '#3C4243',
20 |
21 | text: '#484e5c',
22 | timestampText: '#c1c3c7',
23 | link: '#1F76F7',
24 | };
25 |
--------------------------------------------------------------------------------
/Navigation/ExTabScene.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @providesModule ExTabScene
3 | */
4 | 'use strict';
5 |
6 | import React, {
7 | NavigationExperimental,
8 | StyleSheet,
9 | Text,
10 | View,
11 | } from 'react-native';
12 |
13 | const {
14 | AnimatedView: NavigationAnimatedView,
15 | Card: NavigationCard,
16 | Container: NavigationContainer,
17 | Header: NavigationHeader,
18 | Reducer: NavigationReducer,
19 | } = NavigationExperimental;
20 |
21 | class ExTabScene extends React.Component {
22 |
23 | render() {
24 | return (
25 |
26 | );
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Utils/Relay/AsRelayContainer.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @providesModule AsRelayContainer
3 | */
4 |
5 | import invariant from 'invariant';
6 | import Relay from 'react-relay';
7 |
8 | export default function AsRelayContainer(Component) {
9 | invariant(
10 | Component.relay,
11 | 'Relay components must specify Relay container properties in `relay` static property.',
12 | Component.displayName || Component.name
13 | );
14 |
15 | const RelayComponent = Relay.createContainer(Component, {
16 | initialVariables: Component.relay.initialVariables,
17 | fragments: Component.relay.fragments,
18 | prepareVariables: Component.relay.prepareVariables,
19 | });
20 |
21 | RelayComponent.__proto__ = Component;
22 |
23 | return RelayComponent;
24 | }
25 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 |
6 | # Runtime data
7 | pids
8 | *.pid
9 | *.seed
10 |
11 | # Directory for instrumented libs generated by jscoverage/JSCover
12 | lib-cov
13 |
14 | # Coverage directory used by tools like istanbul
15 | coverage
16 |
17 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
18 | .grunt
19 |
20 | # node-waf configuration
21 | .lock-wscript
22 |
23 | # Compiled binary addons (http://nodejs.org/api/addons.html)
24 | build/Release
25 |
26 | # Dependency directory
27 | # https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git
28 | node_modules
29 |
30 | # Optional npm cache directory
31 | .npm
32 |
33 | # Optional REPL history
34 | .node_repl_history
35 |
--------------------------------------------------------------------------------
/Utils/Relay/AppRelayNetworkLayer.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @providesModule AppRelayNetworkLayer
3 | */
4 |
5 | import Relay from 'react-relay';
6 |
7 | export default class AppRelayNetworkLayer extends Relay.DefaultNetworkLayer {
8 | sendMutation(mutation) {
9 | console.log('Mutation: ---');
10 | console.log(mutation.getQueryString(), mutation.getVariables(), mutation.getDebugName());
11 | console.log('/Mutation: ---');
12 | return super.sendMutation(...arguments);
13 | }
14 |
15 | sendQueries(queries) {
16 | console.log('Queries: ---');
17 | for (let q of queries) {
18 | console.log(q.getQueryString(), q.getVariables(), q.getID(), q.getDebugName());
19 | }
20 | console.log('/Queries: ---');
21 | return super.sendQueries(...arguments);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Navigation/ExNavigationReducer.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @providesModule ExNavigationReducer
3 | */
4 |
5 | import { NavigationExperimental } from 'react-native';
6 | const { Reducer: NavigationReducer } = NavigationExperimental;
7 | const ExNavigationStackReducer = require('ExNavigationStackReducer');
8 |
9 | function makeSimpleStackReducer(tabName) {
10 | return (
11 | ExNavigationStackReducer({
12 | initialStates: [
13 | {type: `${tabName}Page`, key: 'base', title: tabName},
14 | ],
15 | key: tabName,
16 | matchAction: () => false,
17 | })
18 | );
19 | }
20 |
21 | export default NavigationReducer.TabsReducer({
22 | tabReducers: [
23 | makeSimpleStackReducer('Schedule'),
24 | makeSimpleStackReducer('People'),
25 | makeSimpleStackReducer('Event Info'),
26 | makeSimpleStackReducer('Me'),
27 | ],
28 | });
29 |
--------------------------------------------------------------------------------
/AppComponents/ExText.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @providesModule ExText
3 | */
4 | 'use strict';
5 |
6 | import React, {
7 | Platform,
8 | StyleSheet,
9 | Text,
10 | } from 'react-native';
11 |
12 | export default class ExText extends React.Component {
13 | render() {
14 | return (
15 |
19 | {this.props.children}
20 |
21 | );
22 | }
23 |
24 | setNativeProps(nativeProps) {
25 | this._textRef.setNativeProps(nativeProps);
26 | }
27 |
28 | _setTextRef(component) {
29 | this._textRef = component;
30 |
31 | if (typeof this.props.textRef === 'function') {
32 | this.props.textRef(component);
33 | }
34 | }
35 | }
36 |
37 | const styles = StyleSheet.create({
38 | base: {
39 | fontFamily: 'FreightSansLFPro',
40 | },
41 | });
42 |
--------------------------------------------------------------------------------
/Components/FadeIn.android.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2015-present 650 Industries. All rights reserved.
3 | *
4 | * @providesModule FadeIn
5 | */
6 | 'use strict';
7 |
8 | import React, {
9 | StyleSheet,
10 | View,
11 | } from 'react-native';
12 |
13 | export default class FadeIn extends React.Component {
14 |
15 | render() {
16 | let image = React.Children.only(this.props.children);
17 |
18 | return (
19 |
20 |
21 |
22 |
23 |
24 | {image}
25 |
26 | );
27 | }
28 | }
29 |
30 | let styles = StyleSheet.create({
31 | placeholderContainer: {
32 | position: 'absolute',
33 | top: 0,
34 | left: 0,
35 | bottom: 0,
36 | right: 0,
37 | },
38 | placeholder: {
39 | backgroundColor: '#F1F1F1',
40 | },
41 | });
42 |
--------------------------------------------------------------------------------
/Navigation/ExTabItem.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @providesModule ExTabItem
3 | */
4 | 'use strict';
5 |
6 | import React, {
7 | Text,
8 | PropTypes,
9 | View,
10 | } from 'react-native';
11 |
12 | export default class ExTabItem extends React.Component {
13 | static propTypes = {
14 | renderIcon: PropTypes.func.isRequired,
15 | renderSelectedIcon: PropTypes.func,
16 | badgeText: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
17 | renderBadge: PropTypes.func,
18 | title: PropTypes.string,
19 | titleStyle: Text.propTypes.style,
20 | selectedTitleStyle: Text.propTypes.style,
21 | selected: PropTypes.bool,
22 | onPress: PropTypes.func,
23 | allowFontScaling: PropTypes.bool
24 | };
25 |
26 | static defaultProps = {
27 | renderIcon: () => ,
28 | };
29 |
30 | render() {
31 | let child = React.Children.only(this.props.children);
32 | return React.cloneElement(child, {
33 | style: [child.props.style, this.props.style],
34 | });
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/AppComponents/ExIcon.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @providesModule ExIcon
3 | */
4 | 'use strict';
5 |
6 | import React, {
7 | PropTypes,
8 | } from 'react-native';
9 | import ResponsiveImage from '@exponent/react-native-responsive-image';
10 |
11 | import Constants from 'Constants';
12 |
13 | export default class ExIcon extends React.Component {
14 |
15 | static propTypes = {
16 | ...ResponsiveImage.propTypes,
17 | imageName: PropTypes.string,
18 | };
19 |
20 | static sources(imageName, options = {}) {
21 | let baseUrl = `${Constants.cdnHost}${imageName}`;
22 |
23 | return {
24 | 2: {uri: `${baseUrl}@2x.png`},
25 | // 3: {uri: `${baseUrl}@3x.png`},
26 | };
27 | }
28 |
29 | setNativeProps(nativeProps) {
30 | this._image.setNativeProps(nativeProps);
31 | }
32 |
33 | render() {
34 | return (
35 | { this._image = image; }}
37 | sources={ExIcon.sources(this.props.imageName, this.props)}
38 | fadeDuration={0}
39 | {...this.props}
40 | />
41 | );
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Exponent JS
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Style/Layout.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2015-present 650 Industries. All rights reserved.
3 | *
4 | * @providesModule Layout
5 | */
6 | 'use strict';
7 |
8 | import {
9 | Dimensions,
10 | PixelRatio,
11 | Platform,
12 | NativeModules,
13 | } from 'react-native';
14 |
15 | const { ExponentConstants } = NativeModules;
16 |
17 | let windowDimensions = Dimensions.get('window');
18 | let isSmallDevice = (windowDimensions.width <= 320);
19 |
20 | let Layout = {
21 | isSmallDevice,
22 | pixel: 1 / PixelRatio.get(),
23 | tabBarHeight: 49,
24 | navigationBarDisplacement: 0,
25 | marginHorizontal: isSmallDevice ? 10 : 15,
26 | statusBarHeight: 20, //ExponentConstants.statusBarHeight,
27 | window: windowDimensions,
28 | };
29 |
30 | let platformDependentLayout = {};
31 |
32 | if (Platform.OS === 'ios') {
33 | platformDependentLayout = {
34 | navigationBarHeight: 44,
35 | };
36 | } else {
37 | platformDependentLayout = {
38 | navigationBarHeight: 56,
39 | navigationBarDisplacement: Layout.statusBarHeight,
40 | };
41 | }
42 |
43 | platformDependentLayout.headerHeight = Layout.statusBarHeight + platformDependentLayout.navigationBarHeight;
44 |
45 | Object.assign(Layout, platformDependentLayout);
46 |
47 | export default Layout;
48 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-conf-experience",
3 | "version": "0.0.0",
4 | "license": "MIT",
5 | "description": "React Conf 2016 Official App",
6 | "private": true,
7 | "main": "ReactConfApp.js",
8 | "author": "Adam Miskiewicz ",
9 | "exp": {
10 | "abiVersion": "UNVERSIONED",
11 | "name": "React Conf 2016",
12 | "orientation": "portrait",
13 | "primaryColor": "#f6f6f7"
14 | },
15 | "config": {
16 | "graphqlEndpoint": "http://14a5e704.ngrok.com"
17 | },
18 | "scripts": {
19 | "fetch-graphql": "curl $npm_package_config_graphqlEndpoint/schema.json > _resources/schema.json"
20 | },
21 | "dependencies": {
22 | "@exponent/react-native-responsive-image": "^0.1.0",
23 | "@exponent/with-custom-font": "^2.0.0",
24 | "immutable": "^3.7.6",
25 | "react": "^0.14.7",
26 | "react-mixin": "^3.0.3",
27 | "react-native": "github:exponentjs/react-native#2016-02-09",
28 | "react-native-clone-referenced-element": "^1.0.0",
29 | "react-relay": "github:exponentjs/relay#exp-latest",
30 | "react-timer-mixin": "^0.13.3"
31 | },
32 | "devDependencies": {
33 | "babel-eslint": "^4.1.8",
34 | "babel-plugin-transform-decorators-legacy": "^1.3.4",
35 | "babel-plugin-transform-export-extensions": "^6.5.0",
36 | "babel-plugin-transform-react-constant-elements": "^6.5.0",
37 | "babel-preset-react-native": "^1.4.0",
38 | "babel-relay-plugin": "^0.7.0",
39 | "eslint": "^2.1.0",
40 | "eslint-plugin-react": "^3.16.1"
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # The React Conf Experience
2 | A mobile app for React Conf 2016.
3 |
4 | In this repo we experiment with NavigationExperimental and use Relay for
5 | all data fetching and such. We hope it will serve as an interesting
6 | example for people who are interested in either.
7 |
8 | ## Project
9 |
10 | Mockups from Thinkmill here: https://www.dropbox.com/sh/7spugbj4usjkmsy/AAC-iKIG2B0n8wGJSd57ngqUa?dl=0. There are quite a few complex features to implement so this is the Trello board that lists priorities and who's working on what: https://trello.com/b/1aQe7XX3/react-conf-experience.
11 |
12 | Items noted as **Necessary** are needed for the conference app to be usable. Items under **Features** are nice to have. If you'd like to help and can commit to building a feature, add yourself as a member to its card and move the card under **In Progress** so we know who's working on what. When you're done with the feature, move the card to **Done**.
13 |
14 | ## How to run it (OS X)
15 |
16 | 1. Check out this repository somewhere on your computer.
17 | 2. Get set up with Exponent by downloading the Exponent app from the Play Store (Android 4.4+) or App Store (iOS 8+).
18 | 3. Then download XDE from here: https://github.com/exponentjs/xde/releases/latest
19 | 4. Launch XDE and click Open Project; select your copy of the repository you checked out. XDE will launch the packager.
20 | 5. Use XDE to send a development link to your phone that you can open with Exponent. You can also run the iOS simulator from XDE, install Exponent on it, and open the project in the simulator.
21 | 6. Make changes in your copy of the repository and refresh Exponent; on iOS, double-tap the Exponent button, and on Android, swipe from the top and tap the refresh button in the notification center.
22 |
--------------------------------------------------------------------------------
/Navigation/ExBadge.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @providesModule ExBadge
3 | */
4 | 'use strict';
5 |
6 | import React, {
7 | StyleSheet,
8 | Text,
9 | } from 'react-native';
10 |
11 | import Layout from 'Layout';
12 |
13 | export default class ExBadge extends React.Component {
14 | static propTypes = Text.propTypes;
15 |
16 | constructor(props, context) {
17 | super(props, context);
18 |
19 | this._handleLayout = this._handleLayout.bind(this);
20 | }
21 |
22 | state = {
23 | computedSize: null,
24 | };
25 |
26 | render() {
27 | let { computedSize } = this.state;
28 | let style = {};
29 | if (!computedSize) {
30 | style.opacity = 0;
31 | } else {
32 | style.width = Math.max(computedSize.height, computedSize.width);
33 | }
34 |
35 | return (
36 |
41 | {this.props.children}
42 |
43 | );
44 | }
45 |
46 | _handleLayout(event) {
47 | let { width, height } = event.nativeEvent.layout;
48 | let { computedSize } = this.state;
49 | if (computedSize && computedSize.height === height &&
50 | computedSize.width === width) {
51 | return;
52 | }
53 |
54 | this.setState({
55 | computedSize: { width, height },
56 | });
57 |
58 | if (this.props.onLayout) {
59 | this.props.onLayout(event);
60 | }
61 | }
62 | }
63 |
64 | let styles = StyleSheet.create({
65 | container: {
66 | fontSize: 12,
67 | color: '#fff',
68 | backgroundColor: 'rgb(0, 122, 255)',
69 | lineHeight: 15,
70 | textAlign: 'center',
71 | borderWidth: 1 + Layout.pixel,
72 | borderColor: '#fefefe',
73 | borderRadius: 17 / 2,
74 | overflow: 'hidden',
75 | },
76 | });
77 |
--------------------------------------------------------------------------------
/.flowconfig:
--------------------------------------------------------------------------------
1 | [ignore]
2 |
3 | # We fork some components by platform.
4 | .*/*.web.js
5 | .*/*.android.js
6 |
7 | # Some modules have their own node_modules with overlap
8 | .*/node_modules/node-haste/.*
9 |
10 | # Ugh
11 | .*/node_modules/babel.*
12 | .*/node_modules/babylon.*
13 | .*/node_modules/invariant.*
14 |
15 | # Ignore react and fbjs where there are overlaps, but don't ignore
16 | # anything that react-native relies on
17 | .*/node_modules/fbjs/lib/fetch.js
18 | .*/node_modules/fbjs/lib/ExecutionEnvironment.js
19 | .*/node_modules/fbjs/lib/ErrorUtils.js
20 |
21 | # Flow has a built-in definition for the 'react' module which we prefer to use
22 | # over the currently-untyped source
23 | .*/node_modules/react/react.js
24 | .*/node_modules/react/lib/React.js
25 | .*/node_modules/react/lib/ReactDOM.js
26 |
27 | # Ignore commoner tests
28 | .*/node_modules/commoner/test/.*
29 |
30 | # See https://github.com/facebook/flow/issues/442
31 | .*/react-tools/node_modules/commoner/lib/reader.js
32 |
33 | # Ignore jest
34 | .*/node_modules/jest-cli/.*
35 |
36 | [include]
37 |
38 | [libs]
39 | node_modules/react-native/Libraries/react-native/react-native-interface.js
40 |
41 | [options]
42 | module.system=haste
43 |
44 | esproposal.decorators=ignore
45 | esproposal.class_static_fields=enable
46 | esproposal.class_instance_fields=enable
47 |
48 | module.name_mapper='^image![a-zA-Z0-9$_-]+$' -> 'GlobalImageStub'
49 | module.name_mapper='^[./a-zA-Z0-9$_-]+\.png$' -> 'RelativeImageStub'
50 |
51 | munge_underscores=true
52 |
53 | suppress_type=$FlowIssue
54 | suppress_type=$FlowFixMe
55 | suppress_type=$FixMe
56 |
57 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(1[0-4]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
58 | suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(1[0-4]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)? #[0-9]+
59 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
60 |
--------------------------------------------------------------------------------
/Navigation/ExTab.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @providesModule ExTab
3 | */
4 | 'use strict';
5 |
6 | import React, {
7 | PropTypes,
8 | StyleSheet,
9 | Text,
10 | TouchableOpacity,
11 | View,
12 | } from 'react-native';
13 |
14 | import Layout from 'Layout';
15 |
16 | export default class ExTab extends React.Component {
17 | static propTypes = {
18 | title: PropTypes.string,
19 | titleStyle: Text.propTypes.style,
20 | badge: PropTypes.element,
21 | onPress: PropTypes.func,
22 | hidesTabTouch: PropTypes.bool,
23 | allowFontScaling: PropTypes.bool
24 | };
25 |
26 | constructor(props, context) {
27 | super(props, context);
28 |
29 | this._handlePress = this._handlePress.bind(this);
30 | }
31 |
32 | render() {
33 | let { title, badge } = this.props;
34 | let icon = React.Children.only(this.props.children);
35 |
36 | if (title) {
37 | title =
38 |
42 | {title}
43 | ;
44 | }
45 |
46 | if (badge) {
47 | badge = React.cloneElement(badge, {
48 | style: [styles.badge, badge.props.style],
49 | });
50 | }
51 |
52 | let tabStyle = [styles.container, title ? null : styles.untitledContainer];
53 | return (
54 |
58 |
59 | {icon}
60 | {badge}
61 |
62 | {title}
63 |
64 | );
65 | }
66 |
67 | _handlePress(event) {
68 | if (this.props.onPress) {
69 | this.props.onPress(event);
70 | }
71 | }
72 | }
73 |
74 | let styles = StyleSheet.create({
75 | badge: {
76 | position: 'absolute',
77 | top: -6,
78 | right: -10,
79 | },
80 | container: {
81 | flex: 1,
82 | flexDirection: 'column',
83 | justifyContent: 'flex-end',
84 | alignItems: 'center',
85 | },
86 | untitledContainer: {
87 | paddingBottom: 13,
88 | },
89 | title: {
90 | color: '#929292',
91 | fontSize: 10,
92 | textAlign: 'center',
93 | alignSelf: 'stretch',
94 | marginTop: 4,
95 | marginBottom: 1 + Layout.pixel,
96 | },
97 | });
98 |
--------------------------------------------------------------------------------
/Components/FadeIn.ios.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2015-present 650 Industries. All rights reserved.
3 | *
4 | * @providesModule FadeIn
5 | */
6 | 'use strict';
7 |
8 | import React, {
9 | Animated,
10 | StyleSheet,
11 | View,
12 | } from 'react-native';
13 | import TimerMixin from 'react-timer-mixin';
14 |
15 | import reactMixin from 'react-mixin';
16 | import cloneReferencedElement from 'react-native-clone-referenced-element';
17 |
18 | export default class FadeIn extends React.Component {
19 |
20 | constructor(props, context) {
21 | super(props, context);
22 |
23 | this.state = {
24 | placeholderContainerOpacity: new Animated.Value(1),
25 | };
26 | }
27 |
28 | render() {
29 | let image = cloneReferencedElement(React.Children.only(this.props.children), {
30 | ref: component => { this._image = component; },
31 | onLoadEnd: this._onLoadEnd.bind(this),
32 | });
33 |
34 | return (
35 |
36 | {image}
37 |
38 |
42 |
43 |
44 |
45 | );
46 | }
47 |
48 | _onLoadEnd() {
49 |
50 | /* NOTE(brentvatne): If we animate in immediately when the onLoadEvent event
51 | fires, there are two unwanted consequences:
52 | 1. Animation feels janky - not entirely sure why that is
53 | (handled with minimumWait)
54 | 2. Many images finish loading in the same frame for some reason, and in my
55 | opinion it looks better when the images fade in separately
56 | (handled with staggerNonce) */
57 |
58 | const minimumWait = 100;
59 | const staggerNonce = 200 * Math.random();
60 |
61 | this.setTimeout(() => {
62 | Animated.timing(this.state.placeholderContainerOpacity, {
63 | toValue: 0,
64 | duration: 350,
65 | }).start();
66 | }, minimumWait + staggerNonce);
67 | }
68 | }
69 |
70 | reactMixin(FadeIn.prototype, TimerMixin);
71 |
72 | let styles = StyleSheet.create({
73 | placeholderContainer: {
74 | position: 'absolute',
75 | top: 0,
76 | left: 0,
77 | bottom: 0,
78 | right: 0,
79 | },
80 | placeholder: {
81 | backgroundColor: '#F1F1F1',
82 | },
83 | });
84 |
--------------------------------------------------------------------------------
/Navigation/ExTabNavigator.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @providesModule ExTabNavigator
3 | */
4 | 'use strict';
5 |
6 | import React, {
7 | NavigationExperimental,
8 | StyleSheet,
9 | View,
10 | } from 'react-native';
11 |
12 | const {
13 | Container: NavigationContainer,
14 | View: NavigationView,
15 | } = NavigationExperimental;
16 |
17 | import ExNavigationAnimatedView from 'ExNavigationAnimatedView';
18 | import ExNavigationCard from 'ExNavigationCard';
19 | import ExNavigationHeader from 'ExNavigationHeader';
20 | import ExTabItem from 'ExTabItem';
21 | import ExTabBar from 'ExTabBar';
22 |
23 | class ExTabNavigator extends React.Component {
24 |
25 | static Item = ExTabItem;
26 |
27 | render() {
28 | return (
29 |
30 | {/* Takes the current navigationState and renders a scene for each tab.
31 | * It also hides and shows these tabs depending on which index is selected
32 | * in the navigationState. */}
33 |
38 |
39 | {/* This actually renders the tab bar view (buttons etc) */ }
40 |
46 |
47 | );
48 | }
49 |
50 | _renderTabScene(tabState, tabIndex) {
51 | { /* Each tab scene has its own stack, and we want transitions between
52 | * scenes in this substack to be animated, so we use AnimatedView
53 | * along with NavigationHeader and NavigationCard */ }
54 | return (
55 | {
60 | return (
61 | state.title}
66 | />
67 | );
68 | }}
69 | renderScene={(child, index, position, layout) => {
70 | return (
71 |
78 | {this.props.renderScene(child, index)}
79 |
80 | );
81 | }}
82 | />
83 | );
84 | }
85 | }
86 |
87 | export default NavigationContainer.create(ExTabNavigator);
88 |
89 | const styles = StyleSheet.create({
90 | container: {
91 | flex: 1,
92 | },
93 | tabNavigator: {
94 | flex: 1,
95 | },
96 | });
97 |
--------------------------------------------------------------------------------
/Navigation/ExTabBar.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @providesModule ExTabBar
3 | */
4 | 'use strict';
5 |
6 | import React, {
7 | NavigationExperimental,
8 | Platform,
9 | StyleSheet,
10 | Text,
11 | TouchableOpacity,
12 | View,
13 | } from 'react-native';
14 |
15 | const {
16 | Container: NavigationContainer,
17 | Reducer: NavigationReducer,
18 | } = NavigationExperimental;
19 |
20 | const {
21 | JumpToAction,
22 | } = NavigationReducer.TabsReducer;
23 |
24 | import ExBadge from 'ExBadge';
25 | import ExTab from 'ExTab';
26 | import Layout from 'Layout';
27 |
28 | class ExTabBar extends React.Component {
29 |
30 | static propTypes = {
31 | ...View.propTypes,
32 | shadowStyle: View.propTypes.style,
33 | };
34 |
35 | render() {
36 | return (
37 |
38 | {this.props.tabs.map(this._renderTab.bind(this))}
39 |
40 |
41 | );
42 | }
43 |
44 | _navigateToTab(index) {
45 | this.props.onNavigate(JumpToAction(index));
46 | }
47 |
48 | _renderTab(tabState, i) {
49 | let isSelected = i === this.props.index;
50 | let focusTab = () => this._navigateToTab(i);
51 | let item = this.props.renderTabItem(
52 | tabState.key,
53 | isSelected,
54 | focusTab,
55 | );
56 |
57 |
58 | let icon;
59 | if (isSelected) {
60 | if (item.props.renderSelectedIcon) {
61 | icon = item.props.renderSelectedIcon();
62 | } else if (item.props.renderIcon) {
63 | let defaultIcon = item.props.renderIcon();
64 | icon = React.cloneElement(defaultIcon, {
65 | style: [defaultIcon.props.style, styles.defaultSelectedIcon],
66 | });
67 | }
68 | } else if (!isSelected && item.props.renderIcon) {
69 | icon = item.props.renderIcon();
70 | }
71 |
72 | let badge;
73 | if (item.props.renderBadge) {
74 | badge = item.props.renderBadge();
75 | } else if (item.props.badgeText) {
76 | badge = {item.props.badgeText};
77 | }
78 |
79 | return (
80 |
93 | {icon}
94 |
95 | );
96 | }
97 | };
98 |
99 | export default NavigationContainer.create(ExTabBar);
100 |
101 | const styles = StyleSheet.create({
102 | tabBar: {
103 | height: 60,
104 | flexDirection: 'row',
105 | justifyContent: 'space-around',
106 | position: 'absolute',
107 | bottom: 0,
108 | left: 0,
109 | right: 0,
110 | },
111 | tabButton: {
112 | flex: 1,
113 | },
114 | tabButtonText: {
115 | paddingTop: 20,
116 | textAlign: 'center',
117 | fontSize: 17,
118 | fontWeight: '500',
119 | },
120 | shadow: {
121 | backgroundColor: 'rgba(0, 0, 0, 0.25)',
122 | height: Layout.pixel,
123 | position: 'absolute',
124 | left: 0,
125 | right: 0,
126 | top: Platform.OS === 'android' ? 0 : -Layout.pixel,
127 | },
128 | });
129 |
--------------------------------------------------------------------------------
/Navigation/ExNavigationHeader.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @providesModule ExNavigationHeader
3 | */
4 | 'use strict';
5 |
6 | import React, {
7 | Animated,
8 | Image,
9 | NavigationExperimental,
10 | StyleSheet,
11 | Text,
12 | TouchableOpacity,
13 | View,
14 | } from 'react-native';
15 |
16 | const {
17 | Container: NavigationContainer,
18 | Reducer: NavigationReducer,
19 | } = NavigationExperimental;
20 |
21 | import ExIcon from 'ExIcon';
22 | import ExText from 'ExText';
23 | import WithFreightSansFont from 'WithFreightSansFont';
24 |
25 | const AnimatedExText = Animated.createAnimatedComponent(ExText);
26 | const AnimatedExIcon = Animated.createAnimatedComponent(ExIcon);
27 |
28 | class ExNavigationHeader extends React.Component {
29 |
30 | componentWillMount() {
31 | this._handleBackPress = this._handleBackPress.bind(this);
32 | }
33 |
34 | render() {
35 | var state = this.props.navigationState;
36 | return (
37 |
42 | {state.children.map(this._renderTitle, this)}
43 | {state.children.map(this._renderBackButton, this)}
44 |
45 | );
46 | }
47 |
48 | _renderBackButton(childState, index) {
49 | if (index === 0) {
50 | return null;
51 | }
52 |
53 | return (
54 |
64 |
67 |
68 |
69 |
70 | );
71 | }
72 |
73 | _renderTitle(childState, index) {
74 | return (
75 |
87 | {this.props.getTitle(childState)}
88 |
89 | );
90 | }
91 |
92 | _handleBackPress() {
93 | this.props.onNavigate(NavigationReducer.StackReducer.PopAction());
94 | }
95 | }
96 |
97 | ExNavigationHeader = NavigationContainer.create(ExNavigationHeader);
98 |
99 | const styles = StyleSheet.create({
100 | title: {
101 | textAlign: 'center',
102 | marginTop: 10,
103 | fontSize: 21,
104 | color: '#0A0A0A',
105 | position: 'absolute',
106 | backgroundColor: 'transparent',
107 | top: 12,
108 | left: 0,
109 | right: 0,
110 | },
111 | header: {
112 | backgroundColor: '#F3F5F5',
113 | paddingTop: 20,
114 | top: 0,
115 | height: 64,
116 | right: 0,
117 | left: 0,
118 | borderBottomWidth: 0.5,
119 | borderBottomColor: '#D2D2D2',
120 | position: 'absolute',
121 | },
122 | backButtonWrapper: {
123 | width: 29,
124 | height: 37,
125 | bottom: 10,
126 | left: 2,
127 | padding: 8,
128 | position: 'absolute',
129 | },
130 | backButtonImage: {
131 | tintColor: '#000',
132 | width: 13,
133 | height: 21,
134 | transform: [{rotate: '180deg'}],
135 | },
136 | });
137 |
138 | module.exports = ExNavigationHeader;
139 |
--------------------------------------------------------------------------------
/Utils/Relay/AsRelayRenderer.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @providesModule AsRelayRenderer
3 | */
4 |
5 | import _ from 'lodash';
6 |
7 | import React, {
8 | Alert,
9 | PropTypes,
10 | } from 'react-native';
11 |
12 | import RelayRenderer from 'react-relay/lib/RelayRenderer';
13 |
14 | import AsRelayContainer from 'AsRelayContainer';
15 |
16 | /**
17 | * Builds a Relay root container from static properties defined on the wrapped component.
18 | * The return component will accept a special prop, "routeParams", that will pass the appropriate
19 | * parameters to the Relay root.
20 | */
21 | export default function AsRelayRenderer(Component) {
22 |
23 | if (Component.relay && !Component.relay.queries) {
24 | throw new Error('Relay component must define queries for Relay Root Container.');
25 | }
26 |
27 | const RelayComponent = AsRelayContainer(Component);
28 |
29 | // Global failure component
30 |
31 | class FailedComponent extends React.Component {
32 | componentDidMount() {
33 | if (__DEV__) {
34 | console.error(this.props.error);
35 | }
36 |
37 | Alert.alert('Network Request Failed', null, [
38 | { text: 'Retry', onPress: () => {
39 | this.props.retry();
40 | }},
41 | { text: 'Cancel' },
42 | ]);
43 | return;
44 | }
45 |
46 | render() {
47 | return ;
48 | }
49 | }
50 |
51 | class RelayRendererWrapper extends React.Component {
52 | static propTypes = {
53 | routeParams: PropTypes.object,
54 | };
55 |
56 | static defaultProps = {
57 | routeParams: {},
58 | };
59 |
60 | constructor(props, ...args) {
61 | super(props, ...args);
62 | this.state = {
63 | queryConfig: this._computeQueryConfig(props),
64 | };
65 | }
66 |
67 | render() {
68 | const emptyFragments = _.zipObject(RelayComponent.getFragmentNames().map(name => ([name, null])));
69 |
70 | return (
71 | {
76 | if (error) { // error
77 | return ;
78 | } else if (props) { // fetched
79 | return ;
80 | } else { // loading
81 | return ;
82 | }
83 | }}
84 | />
85 | );
86 | }
87 |
88 | componentWillReceiveProps(nextProps) {
89 | if (this.props.routeParams !== nextProps.routeParams) {
90 | this.setState({
91 | queryConfig: this._computeQueryConfig(nextProps),
92 | });
93 | }
94 | }
95 |
96 | _computeQueryConfig(props) {
97 | let queryConfig = {
98 | name: `relay-route-${RelayComponent.displayName}`,
99 | queries: { ...RelayComponent.relay.queries },
100 | params: {},
101 | };
102 |
103 | /*
104 | Allows us to define:
105 |
106 | static relay = {
107 | ...
108 | paramDefinitions: ...
109 | }
110 |
111 | on the component being wrapped and we ensure these allow
112 | our given route params.
113 | */
114 |
115 | const { relay: { paramDefinitions } } = RelayComponent;
116 |
117 | if (paramDefinitions) {
118 | queryConfig.params = _.reduce(paramDefinitions, (final, val, key) => {
119 | if (props.routeParams[key]) {
120 | final[key] = props.routeParams[key];
121 | }
122 | return final;
123 | }, {});
124 | }
125 |
126 | return queryConfig;
127 | }
128 | }
129 |
130 | return RelayRendererWrapper;
131 | }
132 |
--------------------------------------------------------------------------------
/ReactConfApp.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @providesModule ReactConfApp
3 | */
4 |
5 | import React, {
6 | AppRegistry,
7 | InteractionManager,
8 | NavigationExperimental,
9 | StyleSheet,
10 | Text,
11 | View,
12 | } from 'react-native';
13 |
14 | const {
15 | Container: NavigationContainer,
16 | RootContainer: NavigationRootContainer,
17 | } = NavigationExperimental;
18 |
19 | import {
20 | Relay,
21 | AppRelayNetworkLayer,
22 | } from 'AppRelay';
23 |
24 | import Colors from 'Colors';
25 | import ExNavigationReducer from 'ExNavigationReducer';
26 | import ExIcon from 'ExIcon';
27 | import ExText from 'ExText';
28 | import Layout from 'Layout';
29 | import Schedule from 'Schedule';
30 | import ExTabNavigator from 'ExTabNavigator';
31 |
32 | class App extends React.Component {
33 | constructor(...args) {
34 | super(...args);
35 | process.env.ENDPOINT = 'http://14a5e704.ngrok.com';
36 |
37 | Relay.injectTaskScheduler(InteractionManager.runAfterInteractions);
38 |
39 | // Default network layer
40 | Relay.injectNetworkLayer(
41 | new AppRelayNetworkLayer(`${process.env.ENDPOINT}/graphql`, {
42 | fetchTimeout: 10000,
43 | })
44 | );
45 | }
46 |
47 | render() {
48 | return (
49 |
53 | );
54 | }
55 |
56 | _renderApp(navigationState) {
57 | if (!navigationState) {
58 | return null;
59 | }
60 |
61 | return (
62 |
67 |
68 | );
69 | }
70 |
71 | _renderTabItem(key, isSelected) {
72 | return (
73 | }
77 | renderSelectedIcon={() => }
78 | selectedTitleStyle={{color: Colors.tint}}
79 | selected={isSelected}
80 | />
81 | );
82 | }
83 |
84 | _renderTabScene(route, index) {
85 | if (route.type === 'SchedulePage') {
86 | return ;
87 | } else if (route.type === 'ActivityInfo') {
88 | return (
89 |
90 | Info goes here!!!!!
91 |
92 | );
93 | } else {
94 | return (
95 |
96 | {route.title || route.type}
97 |
98 | );
99 | }
100 | }
101 | }
102 |
103 | class TabIcon extends React.Component {
104 | render() {
105 | let imageName, style;
106 | let { tab, selected } = this.props;
107 |
108 | if (tab === 'Schedule') {
109 | imageName = 'ScheduleIcon';
110 | style = { width: 25, height: 28, marginBottom: -1 }
111 | } else if (tab === 'People') {
112 | imageName = 'PeopleIcon';
113 | style = { width: 45, height: 24, marginTop: -1 }
114 | } else if (tab === 'Event Info') {
115 | imageName = 'EventInfoIcon';
116 | style = { width: 20, height: 28, marginBottom: -1 }
117 | } else {
118 | imageName = 'MeIcon';
119 | style = { width: 35, height: 25 }
120 | }
121 |
122 | style.tintColor = selected ? Colors.tint : '#fff';
123 |
124 | return (
125 |
129 | );
130 | }
131 | }
132 |
133 |
134 | const styles = StyleSheet.create({
135 | headerContainer: {
136 | backgroundColor: Colors.backgroundGray,
137 | height: 84,
138 | alignItems: 'center',
139 | justifyContent: 'center',
140 | paddingTop: 28,
141 | borderBottomWidth: Layout.pixel,
142 | borderBottomColor: Colors.separator,
143 | },
144 | tabBar: {
145 | backgroundColor: '#1B1D24',
146 | },
147 | });
148 |
149 | AppRegistry.registerComponent('main', () => App);
150 | console.disableYellowBox = true;
151 |
--------------------------------------------------------------------------------
/Navigation/ExNavigationStackReducer.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @providesModule ExNavigationStackReducer
3 | * @flow
4 | */
5 | 'use strict';
6 |
7 | var NavigationStateUtils = require('NavigationState');
8 |
9 | import type {
10 | NavigationState,
11 | NavigationReducer,
12 | } from 'NavigationState';
13 |
14 | import type {
15 | BackAction,
16 | } from 'NavigationRootContainer';
17 |
18 | export type NavigationStackReducerAction = BackAction | {
19 | type: string,
20 | };
21 |
22 | export type NavigationStackVelocityParams = {
23 | vx: number;
24 | vy: number;
25 | };
26 |
27 | const ActionTypes = {
28 | GESTURE_POP: 'react-native/NavigationExperimental/stack-gesture-pop',
29 | PUSH: 'react-native/NavigationExperimental/stack-push',
30 | POP: 'react-native/NavigationExperimental/stack-pop',
31 | JUMP_TO: 'react-native/NavigationExperimental/stack-jumpTo',
32 | JUMP_TO_INDEX: 'react-native/NavigationExperimental/stack-jumpToIndex',
33 | RESET: 'react-native/NavigationExperimental/stack-reset',
34 | };
35 |
36 | const DEFAULT_KEY = 'NAV_STACK_DEFAULT_KEY';
37 |
38 | function NavigationStackPushAction(state: NavigationState): NavigationStackReducerAction {
39 | return {
40 | type: ActionTypes.PUSH,
41 | state,
42 | };
43 | }
44 |
45 | function NavigationStackGesturePopAction(velocity: NavigationStackVelocityParams): NavigationStackReducerAction {
46 | return {
47 | type: ActionTypes.GESTURE_POP,
48 | velocity,
49 | };
50 | }
51 |
52 | function NavigationStackPopAction(): NavigationStackReducerAction {
53 | return {
54 | type: ActionTypes.POP,
55 | };
56 | }
57 |
58 | function NavigationStackJumpToAction(key: string): NavigationStackReducerAction {
59 | return {
60 | type: ActionTypes.JUMP_TO,
61 | key,
62 | };
63 | }
64 |
65 | function NavigationStackJumpToIndexAction(index: number): NavigationStackReducerAction {
66 | return {
67 | type: ActionTypes.JUMP_TO_INDEX,
68 | index,
69 | };
70 | }
71 |
72 | function NavigationStackResetAction(children: Array, index: number): NavigationStackReducerAction {
73 | return {
74 | type: ActionTypes.RESET,
75 | index,
76 | children,
77 | };
78 | }
79 |
80 | type StackReducerConfig = {
81 | initialStates: Array;
82 | initialIndex: ?number;
83 | key: ?string;
84 | matchAction: (action: any) => boolean;
85 | actionStateMap: (action: any) => NavigationState;
86 | };
87 |
88 | function NavigationStackReducer({initialStates, initialIndex, key, matchAction, actionStateMap}: StackReducerConfig): NavigationReducer {
89 | return function (lastState: ?NavigationState, action: any): NavigationState {
90 | if (key == null) {
91 | key = DEFAULT_KEY;
92 | }
93 | if (initialIndex == null) {
94 | initialIndex = initialStates.length - 1;
95 | }
96 | if (!lastState) {
97 | lastState = {
98 | index: initialIndex,
99 | children: initialStates,
100 | key,
101 | };
102 | }
103 | const lastParentState = NavigationStateUtils.getParent(lastState);
104 | if (!action || !lastParentState) {
105 | return lastState;
106 | }
107 | switch (action.type) {
108 | case ActionTypes.PUSH:
109 | return NavigationStateUtils.push(
110 | lastParentState,
111 | action.state
112 | );
113 | case ActionTypes.POP:
114 | case ActionTypes.GESTURE_POP:
115 | case 'BackAction':
116 | if (lastParentState.index === 0 || lastParentState.children.length === 1) {
117 | return lastParentState;
118 | }
119 | return NavigationStateUtils.pop(lastParentState);
120 | case ActionTypes.JUMP_TO:
121 | return NavigationStateUtils.jumpTo(
122 | lastParentState,
123 | action.key
124 | );
125 | case ActionTypes.JUMP_TO_INDEX:
126 | return NavigationStateUtils.jumpToIndex(
127 | lastParentState,
128 | action.index
129 | );
130 | case ActionTypes.RESET:
131 | return {
132 | ...lastParentState,
133 | index: action.index,
134 | children: action.children,
135 | };
136 | }
137 | if (matchAction(action)) {
138 | return NavigationStateUtils.push(
139 | lastParentState,
140 | actionStateMap(action)
141 | );
142 | }
143 | return lastParentState;
144 | };
145 | }
146 |
147 | NavigationStackReducer.PushAction = NavigationStackPushAction;
148 | NavigationStackReducer.PopAction = NavigationStackPopAction;
149 | NavigationStackReducer.GesturePopAction = NavigationStackGesturePopAction;
150 | NavigationStackReducer.JumpToAction = NavigationStackJumpToAction;
151 | NavigationStackReducer.JumpToIndexAction = NavigationStackJumpToIndexAction;
152 | NavigationStackReducer.ResetAction = NavigationStackResetAction;
153 |
154 | module.exports = NavigationStackReducer;
155 |
--------------------------------------------------------------------------------
/Navigation/ExNavigationCard.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @providesModule ExNavigationCard
3 | */
4 | 'use strict';
5 |
6 | const Animated = require('Animated');
7 | const NavigationReducer = require('NavigationReducer');
8 | const NavigationContainer = require('NavigationContainer');
9 | const PanResponder = require('PanResponder');
10 | const Platform = require('Platform');
11 | const React = require('React');
12 | const StyleSheet = require('StyleSheet');
13 | const View = require('View');
14 |
15 | // note(brentvatne): yuck
16 | const Dimensions = require('Dimensions');
17 | const WINDOW_WIDTH = Dimensions.get('window').width;
18 |
19 | const ENABLE_GESTURES = true;
20 | const ExNavigationStackReducer = require('ExNavigationStackReducer');
21 |
22 | import type {
23 | NavigationParentState
24 | } from 'NavigationState';
25 |
26 | type Layout = {
27 | initWidth: number,
28 | initHeight: number,
29 | width: Animated.Value;
30 | height: Animated.Value;
31 | };
32 |
33 | type Props = {
34 | navigationState: NavigationParentState;
35 | index: number;
36 | position: Animated.Value;
37 | layout: Layout;
38 | onNavigate: Function;
39 | children: Object;
40 | };
41 |
42 | class NavigationCard extends React.Component {
43 | _responder: ?Object;
44 | _lastHeight: number;
45 | _lastWidth: number;
46 | _widthListener: string;
47 | _heightListener: string;
48 | props: Props;
49 | componentWillMount() {
50 | if (ENABLE_GESTURES) {
51 | this._enableGestures();
52 | }
53 | }
54 | _enableGestures() {
55 | this._responder = PanResponder.create({
56 | onMoveShouldSetPanResponder: (e, {dx, dy, moveX, moveY, x0, y0}) => {
57 | if (this.props.navigationState.index === 0) {
58 | return false;
59 | }
60 | if (moveX > 30) {
61 | return false;
62 | }
63 | if (dx > 5 && Math.abs(dy) < 4) {
64 | return true;
65 | }
66 | return false;
67 | },
68 | onPanResponderGrant: (e, {dx, dy, moveX, moveY, x0, y0}) => {
69 | },
70 | onPanResponderMove: (e, {dx}) => {
71 | const a = (-dx / this._lastWidth) + this.props.navigationState.index;
72 | this.props.position.setValue(a);
73 | },
74 | onPanResponderRelease: (e, {vx, dx}) => {
75 | const xRatio = dx / this._lastWidth;
76 | const doesPop = (xRatio + vx) > 0.45;
77 | if (doesPop) {
78 | // todo: add an action which accepts velocity of the pop action/gesture, which is caught and used by NavigationAnimatedView
79 | this.props.onNavigate(ExNavigationStackReducer.GesturePopAction({
80 | vx: vx,
81 | vy: 0,
82 | }));
83 | return;
84 | }
85 | Animated.spring(this.props.position, {
86 | toValue: this.props.navigationState.index,
87 | }).start();
88 | },
89 | onPanResponderTerminate: (e, {vx, dx}) => {
90 | Animated.spring(this.props.position, {
91 | toValue: this.props.navigationState.index,
92 | }).start();
93 | },
94 | });
95 | }
96 | componentDidMount() {
97 | this._lastHeight = this.props.layout.initHeight;
98 | this._lastWidth = this.props.layout.initWidth;
99 | this._widthListener = this.props.layout.width.addListener(({value}) => {
100 | this._lastWidth = value;
101 | });
102 | this._heightListener = this.props.layout.height.addListener(({value}) => {
103 | this._lastHeight = value;
104 | });
105 | // todo: fix listener and last layout dimensions when props change. potential bugs here
106 | }
107 | componentWillUnmount() {
108 | this.props.layout.width.removeListener(this._widthListener);
109 | this.props.layout.height.removeListener(this._heightListener);
110 | }
111 | render() {
112 | const cardPosition = Animated.add(this.props.position, new Animated.Value(-this.props.index));
113 |
114 | let { index } = this.props;
115 | const gestureValue = this.props.position.interpolate({
116 | inputRange: [index - 1, index, index + 1],
117 | outputRange: [-WINDOW_WIDTH, 0, WINDOW_WIDTH / 2.5],
118 | extrapolate: 'clamp',
119 | });
120 |
121 | const touchResponderHandlers = this._responder ? this._responder.panHandlers : null;
122 | return (
123 |
135 | {this.props.children}
136 |
137 |
148 |
149 | );
150 | }
151 | }
152 |
153 | NavigationCard = NavigationContainer.create(NavigationCard);
154 |
155 | const styles = StyleSheet.create({
156 | card: {
157 | backgroundColor: '#E9E9EF',
158 | shadowColor: 'black',
159 | shadowOpacity: 0.4,
160 | shadowOffset: {width: 0, height: 0},
161 | shadowRadius: 10,
162 | top: 0,
163 | bottom: 0,
164 | position: 'absolute',
165 | },
166 | overlay: {
167 | backgroundColor: 'black',
168 | position: 'absolute',
169 | top: 0,
170 | left: 0,
171 | bottom: 0,
172 | right: 0,
173 | },
174 | });
175 |
176 | module.exports = NavigationCard;
177 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "babel-eslint",
3 |
4 | "ecmaFeatures": {
5 | "modules": true,
6 | "jsx": true
7 | },
8 |
9 | "env": {
10 | "es6": true,
11 | "jasmine": true,
12 | "node": true
13 | },
14 |
15 | // Map from global var to bool specifying if it can be redefined
16 | "globals": {
17 | "__DEV__": false,
18 | "Promise": false,
19 | "XMLHttpRequest": false,
20 | "fetch": false,
21 | "requestAnimationFrame": false,
22 | },
23 |
24 | "plugins": [
25 | "react"
26 | ],
27 |
28 | "rules": {
29 | "no-alert": 1,
30 | "no-array-constructor": 1,
31 | "no-bitwise": 0,
32 | "no-caller": 1,
33 | "no-catch-shadow": 0,
34 | "no-class-assign": 0,
35 | "no-cond-assign": 1,
36 | "no-console": 0,
37 | "no-const-assign": 2,
38 | "no-constant-condition": 1,
39 | "no-continue": 0,
40 | "no-control-regex": 1,
41 | "no-debugger": 1,
42 | "no-delete-var": 2,
43 | "no-div-regex": 1,
44 | "no-dupe-keys": 2,
45 | "no-dupe-args": 2,
46 | "no-duplicate-case": 2,
47 | "no-else-return": 0,
48 | "no-empty": 0,
49 | "no-empty-character-class": 1,
50 | "no-eq-null": 0,
51 | "no-eval": 1,
52 | "no-ex-assign": 1,
53 | "no-extend-native": 1,
54 | "no-extra-bind": 1,
55 | "no-extra-boolean-cast": 1,
56 | "no-extra-parens": 0,
57 | "no-extra-semi": 1,
58 | "no-fallthrough": 1,
59 | "no-floating-decimal": 1,
60 | "no-func-assign": 2,
61 | "no-implied-eval": 1,
62 | "no-inline-comments": 0,
63 | "no-inner-declarations": [0, "functions"],
64 | "no-invalid-regexp": 2,
65 | "no-irregular-whitespace": 1,
66 | "no-iterator": 1,
67 | "no-label-var": 1,
68 | "no-labels": 1,
69 | "no-lone-blocks": 1,
70 | "no-lonely-if": 0,
71 | "no-loop-func": 0,
72 | "no-mixed-requires": [0, false],
73 | "no-mixed-spaces-and-tabs": [1, false],
74 | "no-multi-spaces": 0,
75 | "no-multi-str": 0,
76 | "no-multiple-empty-lines": [0, {"max": 2}],
77 | "no-native-reassign": 0,
78 | "no-negated-in-lhs": 1,
79 | "no-nested-ternary": 0,
80 | "no-new": 1,
81 | "no-new-func": 1,
82 | "no-new-object": 1,
83 | "no-new-require": 1,
84 | "no-new-wrappers": 1,
85 | "no-obj-calls": 1,
86 | "no-octal": 1,
87 | "no-octal-escape": 1,
88 | "no-param-reassign": 0,
89 | "no-path-concat": 1,
90 | "no-plusplus": 0,
91 | "no-process-env": 0,
92 | "no-process-exit": 0,
93 | "no-proto": 1,
94 | "no-redeclare": 1,
95 | "no-regex-spaces": 0,
96 | "no-reserved-keys": 0,
97 | "no-restricted-modules": 0,
98 | "no-return-assign": 1,
99 | "no-script-url": 1,
100 | "no-self-compare": 1,
101 | "no-sequences": 1,
102 | "no-shadow": 0,
103 | "no-shadow-restricted-names": 1,
104 | "no-spaced-func": 1,
105 | "no-sparse-arrays": 1,
106 | "no-sync": 0,
107 | "no-ternary": 0,
108 | "no-trailing-spaces": 1,
109 | "no-this-before-super": 0,
110 | "no-throw-literal": 1,
111 | "no-undef": 2,
112 | "no-undef-init": 0,
113 | "no-undefined": 0,
114 | "no-unexpected-multiline": 1,
115 | "no-underscore-dangle": 0,
116 | "no-unneeded-ternary": 1,
117 | "no-unreachable": 1,
118 | "no-unused-expressions": 1,
119 | "no-unused-vars": [1, {"vars": "all", "args": "none"}],
120 | "no-use-before-define": 0,
121 | "no-useless-call": 0,
122 | "no-void": 1,
123 | "no-var": 0,
124 | "no-warning-comments": [0, { "terms": ["todo", "fixme", "xxx"], "location": "start" }],
125 | "no-with": 1,
126 |
127 | "array-bracket-spacing": [1, "never"],
128 | "arrow-parens": 0,
129 | "arrow-spacing": [1, { "before": true, "after": true }],
130 | "accessor-pairs": 0,
131 | "block-scoped-var": 0,
132 | "brace-style": [0, "1tbs"],
133 | "callback-return": 0,
134 | "camelcase": 0,
135 | "comma-dangle": [1, "always-multiline"],
136 | "comma-spacing": [1, {"before": false, "after": true}],
137 | "comma-style": [1, "last"],
138 | "complexity": [0, 11],
139 | "computed-property-spacing": [0, "never"],
140 | "consistent-return": 0,
141 | "consistent-this": [0, "self"],
142 | "constructor-super": 1,
143 | "curly": [1, "all"],
144 | "default-case": 0,
145 | "dot-location": [1, "property"],
146 | "dot-notation": [0, { "allowKeywords": true }],
147 | "eol-last": 1,
148 | "eqeqeq": [1, "smart"],
149 | "func-names": 0,
150 | "func-style": [0, "declaration"],
151 | "generator-star-spacing": [0, "after"],
152 | "guard-for-in": 0,
153 | "handle-callback-err": [1, "^(err|error)$"],
154 | "indent": [0, 2],
155 | "init-declarations": 0,
156 | "key-spacing": [0, { "beforeColon": false, "afterColon": true }],
157 | "linebreak-style": [0, "unix"],
158 | "lines-around-comment": 0,
159 | "max-depth": [0, 4],
160 | "max-len": [0, 80, 4],
161 | "max-nested-callbacks": [0, 2],
162 | "max-params": [0, 3],
163 | "max-statements": [0, 10],
164 | "new-cap": 0,
165 | "new-parens": 1,
166 | "newline-after-var": 0,
167 | "object-curly-spacing": [0, "always", { "objectsInObjects": false }],
168 | "object-shorthand": [1, "always"],
169 | "one-var": [0, "never"],
170 | "operator-assignment": [0, "always"],
171 | "operator-linebreak": [1, "after"],
172 | "padded-blocks": 0,
173 | "prefer-const": 0,
174 | "prefer-spread": 1,
175 | "quote-props": 0,
176 | "quotes": [1, "single", "avoid-escape"],
177 | "radix": 1,
178 | "require-yield": 0,
179 | "semi": 1,
180 | "semi-spacing": [1, { "before": false, "after": true }],
181 | "sort-vars": 0,
182 | "keyword-spacing": 1,
183 | "space-before-blocks": [1, "always"],
184 | "space-before-function-paren": [1, { "anonymous": "never", "named": "never" }],
185 | "space-in-parens": [1, "never"],
186 | "space-infix-ops": 1,
187 | "space-unary-ops": [0, { "words": true, "nonwords": false }],
188 | "spaced-comment": 0,
189 | "strict": [1, "global"],
190 | "use-isnan": 2,
191 | "valid-jsdoc": 0,
192 | "valid-typeof": 2,
193 | "vars-on-top": 0,
194 | "wrap-iife": 0,
195 | "wrap-regex": 0,
196 | "yoda": [1, "never", { "exceptRange": false }],
197 |
198 | // React
199 | "react/display-name": [1, { "acceptTranspilerName": true }],
200 | "react/jsx-boolean-value": [1, "never"],
201 | "react/jsx-no-undef": 2,
202 | "react/jsx-quotes": [1, "double", "avoid-escape"],
203 | "react/jsx-sort-prop-types": 0,
204 | "react/jsx-sort-props": 0,
205 | "react/jsx-uses-react": 1,
206 | "react/jsx-uses-vars": 1,
207 | "react/no-danger": 0,
208 | "react/no-did-mount-set-state": [1, "allow-in-func"],
209 | "react/no-did-update-set-state": [1, "allow-in-func"],
210 | "react/no-multi-comp": 0,
211 | "react/no-unknown-property": 1,
212 | "react/prop-types": 0,
213 | "react/react-in-jsx-scope": 2,
214 | "react/require-extension": 1,
215 | "react/self-closing-comp": 1,
216 | "react/sort-comp": 0,
217 | "react/wrap-multilines": [1, { "declaration": false, "assignment": false, "return": true}]
218 | }
219 | }
220 |
--------------------------------------------------------------------------------
/Navigation/ExNavigationAnimatedView.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @providesModule ExNavigationAnimatedView
3 | */
4 | 'use strict';
5 |
6 | var Animated = require('Animated');
7 | var Map = require('Map');
8 | var NavigationStateUtils = require('NavigationState');
9 | var NavigationContainer = require('NavigationContainer');
10 | var React = require('react-native');
11 | var View = require('View');
12 |
13 | const USE_NATIVE_ANIMATIONS = true;
14 |
15 | import type {
16 | NavigationState,
17 | NavigationParentState,
18 | } from 'NavigationState';
19 |
20 | type NavigationScene = {
21 | index: number,
22 | state: NavigationState,
23 | isStale: boolean,
24 | };
25 |
26 | /**
27 | * Helper function to compare route keys (e.g. "9", "11").
28 | */
29 | function compareKey(one: string, two: string): number {
30 | var delta = one.length - two.length;
31 | if (delta > 0) {
32 | return 1;
33 | }
34 | if (delta < 0) {
35 | return -1;
36 | }
37 | return one > two ? 1 : -1;
38 | }
39 |
40 | /**
41 | * Helper function to sort scenes based on their index and view key.
42 | */
43 | function compareScenes(
44 | one: NavigationScene,
45 | two: NavigationScene
46 | ): number {
47 | if (one.index > two.index) {
48 | return 1;
49 | }
50 | if (one.index < two.index) {
51 | return -1;
52 | }
53 |
54 | return compareKey(
55 | one.state.key,
56 | two.state.key
57 | );
58 | }
59 |
60 | type Layout = {
61 | initWidth: number,
62 | initHeight: number,
63 | width: Animated.Value;
64 | height: Animated.Value;
65 | };
66 |
67 | type OverlayRenderer = (
68 | position: Animated.Value,
69 | layout: Layout
70 | ) => ReactElement;
71 |
72 | type SceneRenderer = (
73 | state: NavigationState,
74 | index: number,
75 | position: Animated.Value,
76 | layout: Layout
77 | ) => ReactElement
78 |
79 | type Props = {
80 | navigationState: NavigationParentState;
81 | renderScene: SceneRenderer;
82 | renderOverlay: ?OverlayRenderer;
83 | style: any;
84 | };
85 |
86 | class NavigationAnimatedView extends React.Component {
87 | _animatedHeight: Animated.Value;
88 | _animatedWidth: Animated.Value;
89 | _lastHeight: number;
90 | _lastWidth: number;
91 | props: Props;
92 | constructor(props) {
93 | super(props);
94 | this._animatedHeight = new Animated.Value(0);
95 | this._animatedWidth = new Animated.Value(0);
96 | this.state = {
97 | position: new Animated.Value(this.props.navigationState.index, USE_NATIVE_ANIMATIONS),
98 | scenes: new Map(),
99 | };
100 | }
101 | componentWillMount() {
102 | this.setState({
103 | scenes: this._reduceScenes(this.state.scenes, this.props.navigationState),
104 | });
105 | }
106 | componentDidMount() {
107 | this.postionListener = this.state.position.addListener(this._onProgressChange.bind(this));
108 | }
109 | componentWillReceiveProps(nextProps) {
110 | if (nextProps.navigationState !== this.props.navigationState) {
111 | this.setState({
112 | scenes: this._reduceScenes(this.state.scenes, nextProps.navigationState, this.props.navigationState),
113 | });
114 | }
115 | }
116 | componentDidUpdate(lastProps) {
117 | if (lastProps.navigationState.index !== this.props.navigationState.index) {
118 | this._isTransitioning = true;
119 |
120 | Animated.spring(this.state.position, {
121 | toValue: this.props.navigationState.index,
122 | bounciness: 0,
123 | speed: 15,
124 | restDisplacementThreshold: 0.1,
125 | restSpeedThreshold: 0.1,
126 | overshootClamping: true,
127 | }).start(({finished}) => {
128 | if (finished) {
129 | this._isTransitioning = false;
130 | }
131 | });
132 | }
133 | }
134 |
135 | componentWillUnmount() {
136 | if (this.postionListener) {
137 | this.state.position.removeListener(this.postionListener);
138 | this.postionListener = null;
139 | }
140 | }
141 |
142 | onNavigate(action) {
143 | if (action.velocity) {
144 | this._isTransitioning = true;
145 |
146 | Animated.spring(this.state.position, {
147 | toValue: this.props.navigationState.index - 1,
148 | bounciness: 0,
149 | speed: 15,
150 | velocity: -action.velocity.cx,
151 | restDisplacementThreshold: 0.05,
152 | restSpeedThreshold: 0.05,
153 | overshootClamping: true,
154 | }).start(() => {
155 | this._isTransitioning = false;
156 | this.props.onNavigate(action);
157 | });
158 | } else {
159 | if (!this._isTransitioning) {
160 | this.props.onNavigate(action);
161 | }
162 | }
163 |
164 | }
165 |
166 | getNavigationHandler() {
167 | return this.onNavigate.bind(this);
168 | }
169 |
170 | getChildContext() {
171 | return {
172 | onNavigate: this.getNavigationHandler(),
173 | };
174 | }
175 |
176 | _onProgressChange(data: Object): void {
177 | console.log(data);
178 | if (Math.abs(data.value - this.props.navigationState.index) > Number.EPSILON) {
179 | return;
180 | }
181 | this.state.scenes.forEach((scene, index) => {
182 | if (scene.isStale) {
183 | const scenes = this.state.scenes.slice();
184 | scenes.splice(index, 1);
185 | this.setState({ scenes, });
186 | }
187 | });
188 | }
189 | _reduceScenes(
190 | scenes: Array,
191 | nextState: NavigationParentState,
192 | lastState: ?NavigationParentState
193 | ): Array {
194 | let nextScenes = nextState.children.map((child, index) => {
195 | return {
196 | index,
197 | state: child,
198 | isStale: false,
199 | };
200 | });
201 |
202 | if (lastState) {
203 | lastState.children.forEach((child, index) => {
204 | if (!NavigationStateUtils.get(nextState, child.key)) {
205 | nextScenes.push({
206 | index,
207 | state: child,
208 | isStale: true,
209 | });
210 | }
211 | });
212 | }
213 |
214 | nextScenes = nextScenes.sort(compareScenes);
215 |
216 | return nextScenes;
217 | }
218 | render() {
219 | return (
220 | {
222 | const {height, width} = e.nativeEvent.layout;
223 | this._animatedHeight &&
224 | this._animatedHeight.setValue(height);
225 | this._animatedWidth &&
226 | this._animatedWidth.setValue(width);
227 | this._lastHeight = height;
228 | this._lastWidth = width;
229 | }}
230 | style={this.props.style}>
231 | {this.state.scenes.map(this._renderScene, this)}
232 | {this._renderOverlay(this._renderOverlay, this)}
233 |
234 | );
235 | }
236 | _getLayout() {
237 | return {
238 | height: this._animatedHeight,
239 | width: this._animatedWidth,
240 | initWidth: this._lastWidth,
241 | initHeight: this._lastHeight,
242 | };
243 | }
244 | _renderScene(scene: NavigationScene) {
245 | return this.props.renderScene(
246 | scene.state,
247 | scene.index,
248 | this.state.position,
249 | this._getLayout()
250 | );
251 | }
252 | _renderOverlay() {
253 | const {renderOverlay} = this.props;
254 | if (renderOverlay) {
255 | return renderOverlay(
256 | this.state.position,
257 | this._getLayout()
258 | );
259 | }
260 | return null;
261 | }
262 | }
263 |
264 | NavigationAnimatedView.contextTypes = {
265 | onNavigate: React.PropTypes.func,
266 | };
267 |
268 | NavigationAnimatedView.childContextTypes = {
269 | onNavigate: React.PropTypes.func,
270 | };
271 |
272 | NavigationAnimatedView = NavigationContainer.create(NavigationAnimatedView);
273 |
274 | module.exports = NavigationAnimatedView;
275 |
--------------------------------------------------------------------------------
/AppComponents/Schedule.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @providesModule Schedule
3 | */
4 |
5 | import React, {
6 | Image,
7 | ListView,
8 | NavigationExperimental,
9 | ScrollView,
10 | StyleSheet,
11 | Text,
12 | TouchableHighlight,
13 | View,
14 | } from 'react-native';
15 | import Immutable from 'immutable';
16 |
17 | const {
18 | Container: NavigationContainer,
19 | Reducer: NavigationReducer,
20 | } = NavigationExperimental;
21 |
22 | const {
23 | PushAction,
24 | } = NavigationReducer.StackReducer;
25 |
26 | import {
27 | AsRelayContainer,
28 | AsRelayRenderer,
29 | Relay,
30 | } from 'AppRelay';
31 | import Colors from 'Colors';
32 | import ExIcon from 'ExIcon';
33 | import ExText from 'ExText';
34 | import Layout from 'Layout';
35 | import ViewerQuery from 'ViewerQuery';
36 | import WithFreightSansFont from 'WithFreightSansFont';
37 |
38 | const Events = Immutable.fromJS([
39 | {
40 | time: new Date('Mon Feb 22 2016 09:30:00 GMT-0800 (PST)'),
41 | title: 'How To Use React In A Wedding Gift Without Being A Bad Friend',
42 | speaker: 'Keith Poplawski',
43 | speakerPhotoUri: 'http://conf.reactjs.com/img/keith-poplawski.jpg',
44 | description: 'As a belated gift, I’ve created a physical, standalone version of Jeopardy. Featuring React as the project’s interface, an Arduino and a node app running on a Raspberry Pi create an engaging and unique user experience. The presentation highlights React’s potential to respond to input beyond the mouse, including touch, physical buttons, and speech recognition.',
45 | },
46 | {
47 | time: new Date('Mon Feb 22 2016 10:00:00 GMT-0800 (PST)'),
48 | title: 'Team × Technology',
49 | speaker: 'James Ide',
50 | speakerPhotoUri: 'http://conf.reactjs.com/img/james-ide.jpg',
51 | description: `With React Native, mobile developers are able to increase both their productivity and scope of work. The cross-platform technology is fantastic for teams building for Android and iOS, and developers can take ownership of products & features instead of single-platform implementations. At Exponent we've extended this idea to include both products and infrastructure. I'll talk a bit about how we apply this to our software development and the benefits and challenges of growing full-stack developers into cross-stack mobile developers who are responsible for Android and iOS.`,
52 | },
53 | {
54 | time: new Date('Tue Feb 23 2016 09:30:00 GMT-0800 (PST)'),
55 | title: 'Redux, Re-frame, Relay, Om/next, oh my!',
56 | speaker: 'Jared Forsyth',
57 | speakerPhotoUri: 'http://conf.reactjs.com/img/jared-forsyth.jpg',
58 | description: 'Managing client-side state is pretty easy for TodoMVC, but soon after you move beyond that, your app can quickly get brittle, discouraging re-use and significantly complicating maintenance. I will give an overview of a few of the libraries/frameworks that have appeared recently that try to address this problem, show how each of them looks when used in the React context, and then discuss advantages, disadvantages, common patterns, and what we can learn.',
59 | },
60 | {
61 | time: new Date('Mon Feb 22 2016 09:00:00 GMT-0800 (PST)'),
62 | title: 'Breakfast',
63 | },
64 | {
65 | time: new Date('Tue Feb 23 2016 09:00:00 GMT-0800 (PST)'),
66 | title: 'Breakfast',
67 | },
68 | ]);
69 |
70 | function dayOfWeekAsString(dayNumber) {
71 | return ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'][dayNumber - 1];
72 | }
73 |
74 | class Schedule extends React.Component {
75 |
76 | static relay = {
77 | queries: { ...ViewerQuery.queries },
78 | fragments: {
79 | viewer: () => Relay.QL`
80 | fragment on Viewer {
81 | id
82 | days: schedule {
83 | date
84 | slots(first: 1000) {
85 | edges {
86 | node {
87 | ${SlotPreview.getFragment('slot')}
88 | }
89 | }
90 | }
91 | }
92 | }
93 | `,
94 | },
95 | };
96 |
97 | constructor(props) {
98 | super(props);
99 |
100 | let dataSource = new ListView.DataSource({
101 | rowHasChanged: (r1, r2) => r1 !== r2,
102 | sectionHeaderHasChanged: (s1, s2) => s1 !== s2,
103 | });
104 |
105 | this.state = {
106 | dataSource,
107 | };
108 | }
109 |
110 | _computeSlotsByDay() {
111 | const { days } = this.props.viewer;
112 |
113 | return days.reduce((result, day) => {
114 | let dayOfWeek = dayOfWeekAsString(new Date(day.date).getDay());
115 | result[dayOfWeek] = result[dayOfWeek] || [];
116 | result[dayOfWeek].push(...day.slots.edges.map(e => e.node));
117 | return result;
118 | }, {});
119 | }
120 |
121 | render() {
122 | if (this.props.relayLoading || !this.props.viewer) {
123 | return ;
124 | }
125 |
126 | let slotsByDay = this._computeSlotsByDay();
127 |
128 | let dataSource = this.state.dataSource
129 | .cloneWithRowsAndSections(slotsByDay, Object.keys(slotsByDay));
130 |
131 | return (
132 |
139 | );
140 | }
141 |
142 | _renderRow(slot) {
143 | return (
144 |
145 | );
146 | }
147 |
148 | _renderSeparator(sectionId, rowId) {
149 | return (
150 |
151 | );
152 | }
153 |
154 | _renderSectionHeader(sectionData, day) {
155 | return (
156 |
157 |
158 |
159 | {day.toUpperCase()}
160 |
161 |
162 |
163 | );
164 | }
165 |
166 | getNavigationHandler() {
167 | return this.props.onNavigate || this.context.onNavigate;
168 | }
169 |
170 | getChildContext() {
171 | return {
172 | onNavigate: this.getNavigationHandler(),
173 | };
174 | }
175 | }
176 |
177 | Schedule.contextTypes = {
178 | onNavigate: React.PropTypes.func,
179 | };
180 |
181 | Schedule.childContextTypes = {
182 | onNavigate: React.PropTypes.func,
183 | };
184 |
185 | export default AsRelayRenderer(Schedule);
186 |
187 | const startTimeEndTimeFragment = Relay.QL`
188 | fragment on ScheduleSlotInterface {
189 | startTime
190 | endTime
191 | }
192 | `;
193 |
194 | class SlotPreview extends React.Component {
195 |
196 | static relay = {
197 | fragments: {
198 | slot: () => Relay.QL`
199 | fragment on ScheduleSlot {
200 | __typename
201 | ${startTimeEndTimeFragment}
202 | ...on ActivitySlot {
203 | title
204 | }
205 | ...on TalkSlot {
206 | talk {
207 | title
208 | speaker {
209 | name
210 | avatarUrl
211 | }
212 | }
213 | }
214 | ...on LightningTalksSlot {
215 | id
216 | talks {
217 | title
218 | speaker {
219 | name
220 | avatarUrl
221 | }
222 | }
223 | }
224 | }
225 | `,
226 | },
227 | };
228 |
229 | render() {
230 | let { slot } = this.props;
231 | let isSpecial = slot.__typename !== 'TalkSlot';
232 |
233 | if (slot.__typename === 'TalkSlot') {
234 | return this._renderFullTalk();
235 | } else if (slot.__typename === 'LightningTalksSlot') {
236 | return this._renderLightningTalk();
237 | } else {
238 | return this._renderSpecial();
239 | }
240 | }
241 |
242 | _renderFullTalk() {
243 | let { slot } = this.props;
244 |
245 | return (
246 | {
249 | this.props.onNavigate(PushAction({
250 | type: 'ActivityInfo', slot, title: 'Activity Info!'
251 | }))
252 | }}>
253 |
254 |
255 |
258 |
259 |
260 |
261 |
262 | {get12HourTime(new Date(slot.startTime))}
263 |
264 |
265 |
266 | {slot.talk.title}
267 |
268 |
269 |
270 | {slot.talk.speaker.name}
271 |
272 |
273 |
274 |
275 |
278 |
279 |
280 |
281 | );
282 | }
283 |
284 | _renderLightningTalk() {
285 | let { slot } = this.props;
286 |
287 | return (
288 | {
291 | this.props.onNavigate(PushAction({
292 | type: 'ActivityInfo', slot, title: 'Activity Info!'
293 | }))
294 | }}>
295 |
296 |
297 |
298 |
301 |
302 |
303 |
304 |
305 | {get12HourTime(new Date(slot.startTime))}
306 |
307 |
308 |
309 | Lightning talks
310 |
311 |
312 |
313 |
314 |
317 |
318 |
319 |
320 | {slot.talks.map(talk => {
321 | return (
322 |
323 |
324 |
327 |
328 |
329 |
330 |
331 | {talk.title} by {talk.speaker.name}
332 |
333 |
334 |
335 | );
336 | })}
337 |
338 |
339 | );
340 | }
341 |
342 | _renderSpecial() {
343 | let { slot } = this.props;
344 |
345 | return (
346 |
347 |
348 |
349 | {get12HourTime(new Date(slot.startTime))} - {slot.title}
350 |
351 |
352 |
353 | );
354 | }
355 | }
356 |
357 | SlotPreview = AsRelayContainer(SlotPreview);
358 |
359 | function get12HourTime(date) {
360 | let hours = date.getHours() > 12 ? date.getHours() - 12 : date.getHours();
361 | let amPm = date.getHours() >= 12 ? "PM" : "AM";
362 | let minutes = date.getMinutes() < 10 ? "0" + date.getMinutes() : date.getMinutes();
363 | return hours + ":" + minutes + amPm;
364 | }
365 |
366 | const styles = StyleSheet.create({
367 | sectionHeaderContainer: {
368 | backgroundColor: Colors.backgroundGray,
369 | borderBottomWidth: Layout.pixel,
370 | borderBottomColor: Colors.separator,
371 | paddingTop: 15,
372 | paddingBottom: 5,
373 | paddingLeft: 12,
374 | },
375 | sectionHeaderText: {
376 | fontSize: 14,
377 | },
378 | slotPreviewMultipleImagesColumn: {
379 | flexDirection: 'row',
380 | flex: 1,
381 | paddingBottom: 10,
382 | paddingRight: 30,
383 | },
384 | speakerPhoto: {
385 | width: 40,
386 | height: 40,
387 | borderRadius: 20,
388 | marginBottom: 3,
389 | },
390 | titleDetailsText: {
391 | color: Colors.slightlyFaded,
392 | },
393 | titleText: {
394 | fontSize: 18,
395 | },
396 | subtitleText: {
397 | fontSize: 16,
398 | color: '#888',
399 | paddingTop: 5,
400 | },
401 | rowSeparator: {
402 | height: Layout.pixel,
403 | backgroundColor: Colors.separator,
404 | flex: 1,
405 | },
406 | slotPreviewContainer: {
407 | flexDirection: 'row',
408 | backgroundColor: Colors.backgroundWhite,
409 | padding: 15,
410 | },
411 | slotPreviewLightningContainer: {
412 | flexDirection: 'column',
413 | backgroundColor: Colors.backgroundWhite,
414 | padding: 15,
415 | },
416 | slotPreviewLightningInnerContainer: {
417 | flexDirection: 'row',
418 | },
419 | slotPreviewDescriptionColumn: {
420 | flex: 1,
421 | paddingRight: 40,
422 | },
423 | slotPreviewImageColumn: {
424 | width: 50,
425 | justifyContent: 'center',
426 | paddingTop: 2,
427 | },
428 | slotPreviewMultipleImagesColumn: {
429 | flex: 1,
430 | },
431 | slotPreviewCaratColumn: {
432 | width: 20,
433 | paddingTop: 15,
434 | justifyContent: 'center',
435 | },
436 | slotPreviewCarat: {
437 | alignSelf: 'center',
438 | width: 8,
439 | height: 13,
440 | },
441 | });
442 |
--------------------------------------------------------------------------------
/_resources/schema.json:
--------------------------------------------------------------------------------
1 | {
2 | "data": {
3 | "__schema": {
4 | "queryType": {
5 | "name": "RootQuery"
6 | },
7 | "mutationType": null,
8 | "subscriptionType": null,
9 | "types": [
10 | {
11 | "kind": "OBJECT",
12 | "name": "RootQuery",
13 | "description": null,
14 | "fields": [
15 | {
16 | "name": "viewer",
17 | "description": null,
18 | "args": [],
19 | "type": {
20 | "kind": "OBJECT",
21 | "name": "Viewer",
22 | "ofType": null
23 | },
24 | "isDeprecated": false,
25 | "deprecationReason": null
26 | },
27 | {
28 | "name": "node",
29 | "description": "Fetches an object given its ID",
30 | "args": [
31 | {
32 | "name": "id",
33 | "description": "The ID of an object",
34 | "type": {
35 | "kind": "NON_NULL",
36 | "name": null,
37 | "ofType": {
38 | "kind": "SCALAR",
39 | "name": "ID",
40 | "ofType": null
41 | }
42 | },
43 | "defaultValue": null
44 | }
45 | ],
46 | "type": {
47 | "kind": "INTERFACE",
48 | "name": "Node",
49 | "ofType": null
50 | },
51 | "isDeprecated": false,
52 | "deprecationReason": null
53 | }
54 | ],
55 | "inputFields": null,
56 | "interfaces": [],
57 | "enumValues": null,
58 | "possibleTypes": null
59 | },
60 | {
61 | "kind": "OBJECT",
62 | "name": "Viewer",
63 | "description": "Viewer of the application",
64 | "fields": [
65 | {
66 | "name": "id",
67 | "description": "The ID of an object",
68 | "args": [],
69 | "type": {
70 | "kind": "NON_NULL",
71 | "name": null,
72 | "ofType": {
73 | "kind": "SCALAR",
74 | "name": "ID",
75 | "ofType": null
76 | }
77 | },
78 | "isDeprecated": false,
79 | "deprecationReason": null
80 | },
81 | {
82 | "name": "me",
83 | "description": "The current logged-in user.",
84 | "args": [],
85 | "type": {
86 | "kind": "OBJECT",
87 | "name": "User",
88 | "ofType": null
89 | },
90 | "isDeprecated": false,
91 | "deprecationReason": null
92 | },
93 | {
94 | "name": "schedule",
95 | "description": "Schedule of the current event",
96 | "args": [],
97 | "type": {
98 | "kind": "LIST",
99 | "name": null,
100 | "ofType": {
101 | "kind": "OBJECT",
102 | "name": "Schedule",
103 | "ofType": null
104 | }
105 | },
106 | "isDeprecated": false,
107 | "deprecationReason": null
108 | },
109 | {
110 | "name": "allSpeakers",
111 | "description": null,
112 | "args": [
113 | {
114 | "name": "after",
115 | "description": null,
116 | "type": {
117 | "kind": "SCALAR",
118 | "name": "String",
119 | "ofType": null
120 | },
121 | "defaultValue": null
122 | },
123 | {
124 | "name": "first",
125 | "description": null,
126 | "type": {
127 | "kind": "SCALAR",
128 | "name": "Int",
129 | "ofType": null
130 | },
131 | "defaultValue": null
132 | },
133 | {
134 | "name": "before",
135 | "description": null,
136 | "type": {
137 | "kind": "SCALAR",
138 | "name": "String",
139 | "ofType": null
140 | },
141 | "defaultValue": null
142 | },
143 | {
144 | "name": "last",
145 | "description": null,
146 | "type": {
147 | "kind": "SCALAR",
148 | "name": "Int",
149 | "ofType": null
150 | },
151 | "defaultValue": null
152 | }
153 | ],
154 | "type": {
155 | "kind": "OBJECT",
156 | "name": "SpeakerConnection",
157 | "ofType": null
158 | },
159 | "isDeprecated": false,
160 | "deprecationReason": null
161 | },
162 | {
163 | "name": "speakersByName",
164 | "description": "A connection providing a list of conference speakers that can be filtered by name.",
165 | "args": [],
166 | "type": {
167 | "kind": "LIST",
168 | "name": null,
169 | "ofType": {
170 | "kind": "OBJECT",
171 | "name": "Speaker",
172 | "ofType": null
173 | }
174 | },
175 | "isDeprecated": false,
176 | "deprecationReason": null
177 | },
178 | {
179 | "name": "eventInfo",
180 | "description": "Information about the current event.",
181 | "args": [],
182 | "type": {
183 | "kind": "OBJECT",
184 | "name": "Event",
185 | "ofType": null
186 | },
187 | "isDeprecated": false,
188 | "deprecationReason": null
189 | }
190 | ],
191 | "inputFields": null,
192 | "interfaces": [
193 | {
194 | "kind": "INTERFACE",
195 | "name": "Node",
196 | "ofType": null
197 | }
198 | ],
199 | "enumValues": null,
200 | "possibleTypes": null
201 | },
202 | {
203 | "kind": "INTERFACE",
204 | "name": "Node",
205 | "description": "An object with an ID",
206 | "fields": [
207 | {
208 | "name": "id",
209 | "description": "The id of the object.",
210 | "args": [],
211 | "type": {
212 | "kind": "NON_NULL",
213 | "name": null,
214 | "ofType": {
215 | "kind": "SCALAR",
216 | "name": "ID",
217 | "ofType": null
218 | }
219 | },
220 | "isDeprecated": false,
221 | "deprecationReason": null
222 | }
223 | ],
224 | "inputFields": null,
225 | "interfaces": null,
226 | "enumValues": null,
227 | "possibleTypes": [
228 | {
229 | "kind": "OBJECT",
230 | "name": "Event",
231 | "ofType": null
232 | },
233 | {
234 | "kind": "OBJECT",
235 | "name": "FullLengthTalk",
236 | "ofType": null
237 | },
238 | {
239 | "kind": "OBJECT",
240 | "name": "LightningTalk",
241 | "ofType": null
242 | },
243 | {
244 | "kind": "OBJECT",
245 | "name": "Speaker",
246 | "ofType": null
247 | },
248 | {
249 | "kind": "OBJECT",
250 | "name": "ActivitySlot",
251 | "ofType": null
252 | },
253 | {
254 | "kind": "OBJECT",
255 | "name": "LightningTalksSlot",
256 | "ofType": null
257 | },
258 | {
259 | "kind": "OBJECT",
260 | "name": "TalkSlot",
261 | "ofType": null
262 | },
263 | {
264 | "kind": "OBJECT",
265 | "name": "Schedule",
266 | "ofType": null
267 | },
268 | {
269 | "kind": "OBJECT",
270 | "name": "User",
271 | "ofType": null
272 | },
273 | {
274 | "kind": "OBJECT",
275 | "name": "Viewer",
276 | "ofType": null
277 | }
278 | ]
279 | },
280 | {
281 | "kind": "OBJECT",
282 | "name": "Event",
283 | "description": "Information about an event",
284 | "fields": [
285 | {
286 | "name": "id",
287 | "description": "The ID of an object",
288 | "args": [],
289 | "type": {
290 | "kind": "NON_NULL",
291 | "name": null,
292 | "ofType": {
293 | "kind": "SCALAR",
294 | "name": "ID",
295 | "ofType": null
296 | }
297 | },
298 | "isDeprecated": false,
299 | "deprecationReason": null
300 | },
301 | {
302 | "name": "name",
303 | "description": null,
304 | "args": [],
305 | "type": {
306 | "kind": "SCALAR",
307 | "name": "String",
308 | "ofType": null
309 | },
310 | "isDeprecated": false,
311 | "deprecationReason": null
312 | },
313 | {
314 | "name": "location",
315 | "description": null,
316 | "args": [],
317 | "type": {
318 | "kind": "OBJECT",
319 | "name": "Point",
320 | "ofType": null
321 | },
322 | "isDeprecated": false,
323 | "deprecationReason": null
324 | },
325 | {
326 | "name": "codeOfConduct",
327 | "description": null,
328 | "args": [],
329 | "type": {
330 | "kind": "SCALAR",
331 | "name": "String",
332 | "ofType": null
333 | },
334 | "isDeprecated": false,
335 | "deprecationReason": null
336 | }
337 | ],
338 | "inputFields": null,
339 | "interfaces": [
340 | {
341 | "kind": "INTERFACE",
342 | "name": "Node",
343 | "ofType": null
344 | }
345 | ],
346 | "enumValues": null,
347 | "possibleTypes": null
348 | },
349 | {
350 | "kind": "SCALAR",
351 | "name": "ID",
352 | "description": "The `ID` scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `\"4\"`) or integer (such as `4`) input value will be accepted as an ID.",
353 | "fields": null,
354 | "inputFields": null,
355 | "interfaces": null,
356 | "enumValues": null,
357 | "possibleTypes": null
358 | },
359 | {
360 | "kind": "SCALAR",
361 | "name": "String",
362 | "description": "The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.",
363 | "fields": null,
364 | "inputFields": null,
365 | "interfaces": null,
366 | "enumValues": null,
367 | "possibleTypes": null
368 | },
369 | {
370 | "kind": "OBJECT",
371 | "name": "Point",
372 | "description": null,
373 | "fields": [
374 | {
375 | "name": "latitude",
376 | "description": null,
377 | "args": [],
378 | "type": {
379 | "kind": "SCALAR",
380 | "name": "Float",
381 | "ofType": null
382 | },
383 | "isDeprecated": false,
384 | "deprecationReason": null
385 | },
386 | {
387 | "name": "longitude",
388 | "description": null,
389 | "args": [],
390 | "type": {
391 | "kind": "SCALAR",
392 | "name": "Float",
393 | "ofType": null
394 | },
395 | "isDeprecated": false,
396 | "deprecationReason": null
397 | }
398 | ],
399 | "inputFields": null,
400 | "interfaces": [],
401 | "enumValues": null,
402 | "possibleTypes": null
403 | },
404 | {
405 | "kind": "SCALAR",
406 | "name": "Float",
407 | "description": "The `Float` scalar type represents signed double-precision fractional values as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point). ",
408 | "fields": null,
409 | "inputFields": null,
410 | "interfaces": null,
411 | "enumValues": null,
412 | "possibleTypes": null
413 | },
414 | {
415 | "kind": "OBJECT",
416 | "name": "FullLengthTalk",
417 | "description": "A talk",
418 | "fields": [
419 | {
420 | "name": "id",
421 | "description": "The ID of an object",
422 | "args": [],
423 | "type": {
424 | "kind": "NON_NULL",
425 | "name": null,
426 | "ofType": {
427 | "kind": "SCALAR",
428 | "name": "ID",
429 | "ofType": null
430 | }
431 | },
432 | "isDeprecated": false,
433 | "deprecationReason": null
434 | },
435 | {
436 | "name": "title",
437 | "description": null,
438 | "args": [],
439 | "type": {
440 | "kind": "SCALAR",
441 | "name": "String",
442 | "ofType": null
443 | },
444 | "isDeprecated": false,
445 | "deprecationReason": null
446 | },
447 | {
448 | "name": "description",
449 | "description": null,
450 | "args": [],
451 | "type": {
452 | "kind": "SCALAR",
453 | "name": "String",
454 | "ofType": null
455 | },
456 | "isDeprecated": false,
457 | "deprecationReason": null
458 | },
459 | {
460 | "name": "speaker",
461 | "description": null,
462 | "args": [],
463 | "type": {
464 | "kind": "OBJECT",
465 | "name": "Speaker",
466 | "ofType": null
467 | },
468 | "isDeprecated": false,
469 | "deprecationReason": null
470 | }
471 | ],
472 | "inputFields": null,
473 | "interfaces": [
474 | {
475 | "kind": "INTERFACE",
476 | "name": "Node",
477 | "ofType": null
478 | }
479 | ],
480 | "enumValues": null,
481 | "possibleTypes": null
482 | },
483 | {
484 | "kind": "OBJECT",
485 | "name": "Speaker",
486 | "description": "A speaker at a conference",
487 | "fields": [
488 | {
489 | "name": "id",
490 | "description": "The ID of an object",
491 | "args": [],
492 | "type": {
493 | "kind": "NON_NULL",
494 | "name": null,
495 | "ofType": {
496 | "kind": "SCALAR",
497 | "name": "ID",
498 | "ofType": null
499 | }
500 | },
501 | "isDeprecated": false,
502 | "deprecationReason": null
503 | },
504 | {
505 | "name": "name",
506 | "description": null,
507 | "args": [],
508 | "type": {
509 | "kind": "SCALAR",
510 | "name": "String",
511 | "ofType": null
512 | },
513 | "isDeprecated": false,
514 | "deprecationReason": null
515 | },
516 | {
517 | "name": "email",
518 | "description": null,
519 | "args": [],
520 | "type": {
521 | "kind": "SCALAR",
522 | "name": "String",
523 | "ofType": null
524 | },
525 | "isDeprecated": false,
526 | "deprecationReason": null
527 | },
528 | {
529 | "name": "company",
530 | "description": null,
531 | "args": [],
532 | "type": {
533 | "kind": "SCALAR",
534 | "name": "String",
535 | "ofType": null
536 | },
537 | "isDeprecated": false,
538 | "deprecationReason": null
539 | },
540 | {
541 | "name": "avatarUrl",
542 | "description": null,
543 | "args": [],
544 | "type": {
545 | "kind": "SCALAR",
546 | "name": "String",
547 | "ofType": null
548 | },
549 | "isDeprecated": false,
550 | "deprecationReason": null
551 | },
552 | {
553 | "name": "talks",
554 | "description": null,
555 | "args": [],
556 | "type": {
557 | "kind": "LIST",
558 | "name": null,
559 | "ofType": {
560 | "kind": "UNION",
561 | "name": "Talk",
562 | "ofType": null
563 | }
564 | },
565 | "isDeprecated": false,
566 | "deprecationReason": null
567 | }
568 | ],
569 | "inputFields": null,
570 | "interfaces": [
571 | {
572 | "kind": "INTERFACE",
573 | "name": "Node",
574 | "ofType": null
575 | }
576 | ],
577 | "enumValues": null,
578 | "possibleTypes": null
579 | },
580 | {
581 | "kind": "UNION",
582 | "name": "Talk",
583 | "description": "A talk",
584 | "fields": null,
585 | "inputFields": null,
586 | "interfaces": null,
587 | "enumValues": null,
588 | "possibleTypes": [
589 | {
590 | "kind": "OBJECT",
591 | "name": "FullLengthTalk",
592 | "ofType": null
593 | },
594 | {
595 | "kind": "OBJECT",
596 | "name": "LightningTalk",
597 | "ofType": null
598 | }
599 | ]
600 | },
601 | {
602 | "kind": "OBJECT",
603 | "name": "LightningTalk",
604 | "description": "A lightning talk",
605 | "fields": [
606 | {
607 | "name": "id",
608 | "description": "The ID of an object",
609 | "args": [],
610 | "type": {
611 | "kind": "NON_NULL",
612 | "name": null,
613 | "ofType": {
614 | "kind": "SCALAR",
615 | "name": "ID",
616 | "ofType": null
617 | }
618 | },
619 | "isDeprecated": false,
620 | "deprecationReason": null
621 | },
622 | {
623 | "name": "title",
624 | "description": null,
625 | "args": [],
626 | "type": {
627 | "kind": "SCALAR",
628 | "name": "String",
629 | "ofType": null
630 | },
631 | "isDeprecated": false,
632 | "deprecationReason": null
633 | },
634 | {
635 | "name": "speaker",
636 | "description": null,
637 | "args": [],
638 | "type": {
639 | "kind": "OBJECT",
640 | "name": "Speaker",
641 | "ofType": null
642 | },
643 | "isDeprecated": false,
644 | "deprecationReason": null
645 | }
646 | ],
647 | "inputFields": null,
648 | "interfaces": [
649 | {
650 | "kind": "INTERFACE",
651 | "name": "Node",
652 | "ofType": null
653 | }
654 | ],
655 | "enumValues": null,
656 | "possibleTypes": null
657 | },
658 | {
659 | "kind": "OBJECT",
660 | "name": "ActivitySlot",
661 | "description": "An activity (break/lunch/etc.)",
662 | "fields": [
663 | {
664 | "name": "id",
665 | "description": "The ID of an object",
666 | "args": [],
667 | "type": {
668 | "kind": "NON_NULL",
669 | "name": null,
670 | "ofType": {
671 | "kind": "SCALAR",
672 | "name": "ID",
673 | "ofType": null
674 | }
675 | },
676 | "isDeprecated": false,
677 | "deprecationReason": null
678 | },
679 | {
680 | "name": "title",
681 | "description": null,
682 | "args": [],
683 | "type": {
684 | "kind": "SCALAR",
685 | "name": "String",
686 | "ofType": null
687 | },
688 | "isDeprecated": false,
689 | "deprecationReason": null
690 | },
691 | {
692 | "name": "startTime",
693 | "description": null,
694 | "args": [],
695 | "type": {
696 | "kind": "SCALAR",
697 | "name": "DateTime",
698 | "ofType": null
699 | },
700 | "isDeprecated": false,
701 | "deprecationReason": null
702 | },
703 | {
704 | "name": "endTime",
705 | "description": null,
706 | "args": [],
707 | "type": {
708 | "kind": "SCALAR",
709 | "name": "DateTime",
710 | "ofType": null
711 | },
712 | "isDeprecated": false,
713 | "deprecationReason": null
714 | }
715 | ],
716 | "inputFields": null,
717 | "interfaces": [
718 | {
719 | "kind": "INTERFACE",
720 | "name": "ScheduleSlotInterface",
721 | "ofType": null
722 | },
723 | {
724 | "kind": "INTERFACE",
725 | "name": "Node",
726 | "ofType": null
727 | }
728 | ],
729 | "enumValues": null,
730 | "possibleTypes": null
731 | },
732 | {
733 | "kind": "INTERFACE",
734 | "name": "ScheduleSlotInterface",
735 | "description": null,
736 | "fields": [
737 | {
738 | "name": "startTime",
739 | "description": null,
740 | "args": [],
741 | "type": {
742 | "kind": "SCALAR",
743 | "name": "DateTime",
744 | "ofType": null
745 | },
746 | "isDeprecated": false,
747 | "deprecationReason": null
748 | },
749 | {
750 | "name": "endTime",
751 | "description": null,
752 | "args": [],
753 | "type": {
754 | "kind": "SCALAR",
755 | "name": "DateTime",
756 | "ofType": null
757 | },
758 | "isDeprecated": false,
759 | "deprecationReason": null
760 | }
761 | ],
762 | "inputFields": null,
763 | "interfaces": null,
764 | "enumValues": null,
765 | "possibleTypes": [
766 | {
767 | "kind": "OBJECT",
768 | "name": "ActivitySlot",
769 | "ofType": null
770 | },
771 | {
772 | "kind": "OBJECT",
773 | "name": "LightningTalksSlot",
774 | "ofType": null
775 | },
776 | {
777 | "kind": "OBJECT",
778 | "name": "TalkSlot",
779 | "ofType": null
780 | }
781 | ]
782 | },
783 | {
784 | "kind": "OBJECT",
785 | "name": "LightningTalksSlot",
786 | "description": null,
787 | "fields": [
788 | {
789 | "name": "id",
790 | "description": "The ID of an object",
791 | "args": [],
792 | "type": {
793 | "kind": "NON_NULL",
794 | "name": null,
795 | "ofType": {
796 | "kind": "SCALAR",
797 | "name": "ID",
798 | "ofType": null
799 | }
800 | },
801 | "isDeprecated": false,
802 | "deprecationReason": null
803 | },
804 | {
805 | "name": "talks",
806 | "description": null,
807 | "args": [],
808 | "type": {
809 | "kind": "LIST",
810 | "name": null,
811 | "ofType": {
812 | "kind": "OBJECT",
813 | "name": "LightningTalk",
814 | "ofType": null
815 | }
816 | },
817 | "isDeprecated": false,
818 | "deprecationReason": null
819 | },
820 | {
821 | "name": "startTime",
822 | "description": null,
823 | "args": [],
824 | "type": {
825 | "kind": "SCALAR",
826 | "name": "DateTime",
827 | "ofType": null
828 | },
829 | "isDeprecated": false,
830 | "deprecationReason": null
831 | },
832 | {
833 | "name": "endTime",
834 | "description": null,
835 | "args": [],
836 | "type": {
837 | "kind": "SCALAR",
838 | "name": "DateTime",
839 | "ofType": null
840 | },
841 | "isDeprecated": false,
842 | "deprecationReason": null
843 | }
844 | ],
845 | "inputFields": null,
846 | "interfaces": [
847 | {
848 | "kind": "INTERFACE",
849 | "name": "ScheduleSlotInterface",
850 | "ofType": null
851 | },
852 | {
853 | "kind": "INTERFACE",
854 | "name": "Node",
855 | "ofType": null
856 | }
857 | ],
858 | "enumValues": null,
859 | "possibleTypes": null
860 | },
861 | {
862 | "kind": "SCALAR",
863 | "name": "DateTime",
864 | "description": null,
865 | "fields": null,
866 | "inputFields": null,
867 | "interfaces": null,
868 | "enumValues": null,
869 | "possibleTypes": null
870 | },
871 | {
872 | "kind": "OBJECT",
873 | "name": "TalkSlot",
874 | "description": null,
875 | "fields": [
876 | {
877 | "name": "id",
878 | "description": "The ID of an object",
879 | "args": [],
880 | "type": {
881 | "kind": "NON_NULL",
882 | "name": null,
883 | "ofType": {
884 | "kind": "SCALAR",
885 | "name": "ID",
886 | "ofType": null
887 | }
888 | },
889 | "isDeprecated": false,
890 | "deprecationReason": null
891 | },
892 | {
893 | "name": "talk",
894 | "description": null,
895 | "args": [],
896 | "type": {
897 | "kind": "OBJECT",
898 | "name": "FullLengthTalk",
899 | "ofType": null
900 | },
901 | "isDeprecated": false,
902 | "deprecationReason": null
903 | },
904 | {
905 | "name": "startTime",
906 | "description": null,
907 | "args": [],
908 | "type": {
909 | "kind": "SCALAR",
910 | "name": "DateTime",
911 | "ofType": null
912 | },
913 | "isDeprecated": false,
914 | "deprecationReason": null
915 | },
916 | {
917 | "name": "endTime",
918 | "description": null,
919 | "args": [],
920 | "type": {
921 | "kind": "SCALAR",
922 | "name": "DateTime",
923 | "ofType": null
924 | },
925 | "isDeprecated": false,
926 | "deprecationReason": null
927 | }
928 | ],
929 | "inputFields": null,
930 | "interfaces": [
931 | {
932 | "kind": "INTERFACE",
933 | "name": "ScheduleSlotInterface",
934 | "ofType": null
935 | },
936 | {
937 | "kind": "INTERFACE",
938 | "name": "Node",
939 | "ofType": null
940 | }
941 | ],
942 | "enumValues": null,
943 | "possibleTypes": null
944 | },
945 | {
946 | "kind": "OBJECT",
947 | "name": "Schedule",
948 | "description": null,
949 | "fields": [
950 | {
951 | "name": "id",
952 | "description": "The ID of an object",
953 | "args": [],
954 | "type": {
955 | "kind": "NON_NULL",
956 | "name": null,
957 | "ofType": {
958 | "kind": "SCALAR",
959 | "name": "ID",
960 | "ofType": null
961 | }
962 | },
963 | "isDeprecated": false,
964 | "deprecationReason": null
965 | },
966 | {
967 | "name": "date",
968 | "description": null,
969 | "args": [],
970 | "type": {
971 | "kind": "SCALAR",
972 | "name": "DateTime",
973 | "ofType": null
974 | },
975 | "isDeprecated": false,
976 | "deprecationReason": null
977 | },
978 | {
979 | "name": "slots",
980 | "description": null,
981 | "args": [
982 | {
983 | "name": "after",
984 | "description": null,
985 | "type": {
986 | "kind": "SCALAR",
987 | "name": "String",
988 | "ofType": null
989 | },
990 | "defaultValue": null
991 | },
992 | {
993 | "name": "first",
994 | "description": null,
995 | "type": {
996 | "kind": "SCALAR",
997 | "name": "Int",
998 | "ofType": null
999 | },
1000 | "defaultValue": null
1001 | },
1002 | {
1003 | "name": "before",
1004 | "description": null,
1005 | "type": {
1006 | "kind": "SCALAR",
1007 | "name": "String",
1008 | "ofType": null
1009 | },
1010 | "defaultValue": null
1011 | },
1012 | {
1013 | "name": "last",
1014 | "description": null,
1015 | "type": {
1016 | "kind": "SCALAR",
1017 | "name": "Int",
1018 | "ofType": null
1019 | },
1020 | "defaultValue": null
1021 | }
1022 | ],
1023 | "type": {
1024 | "kind": "OBJECT",
1025 | "name": "ScheduleSlotConnection",
1026 | "ofType": null
1027 | },
1028 | "isDeprecated": false,
1029 | "deprecationReason": null
1030 | }
1031 | ],
1032 | "inputFields": null,
1033 | "interfaces": [
1034 | {
1035 | "kind": "INTERFACE",
1036 | "name": "Node",
1037 | "ofType": null
1038 | }
1039 | ],
1040 | "enumValues": null,
1041 | "possibleTypes": null
1042 | },
1043 | {
1044 | "kind": "SCALAR",
1045 | "name": "Int",
1046 | "description": "The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1. ",
1047 | "fields": null,
1048 | "inputFields": null,
1049 | "interfaces": null,
1050 | "enumValues": null,
1051 | "possibleTypes": null
1052 | },
1053 | {
1054 | "kind": "OBJECT",
1055 | "name": "ScheduleSlotConnection",
1056 | "description": "A connection to a list of items.",
1057 | "fields": [
1058 | {
1059 | "name": "pageInfo",
1060 | "description": "Information to aid in pagination.",
1061 | "args": [],
1062 | "type": {
1063 | "kind": "NON_NULL",
1064 | "name": null,
1065 | "ofType": {
1066 | "kind": "OBJECT",
1067 | "name": "PageInfo",
1068 | "ofType": null
1069 | }
1070 | },
1071 | "isDeprecated": false,
1072 | "deprecationReason": null
1073 | },
1074 | {
1075 | "name": "edges",
1076 | "description": "Information to aid in pagination.",
1077 | "args": [],
1078 | "type": {
1079 | "kind": "LIST",
1080 | "name": null,
1081 | "ofType": {
1082 | "kind": "OBJECT",
1083 | "name": "ScheduleSlotEdge",
1084 | "ofType": null
1085 | }
1086 | },
1087 | "isDeprecated": false,
1088 | "deprecationReason": null
1089 | }
1090 | ],
1091 | "inputFields": null,
1092 | "interfaces": [],
1093 | "enumValues": null,
1094 | "possibleTypes": null
1095 | },
1096 | {
1097 | "kind": "OBJECT",
1098 | "name": "PageInfo",
1099 | "description": "Information about pagination in a connection.",
1100 | "fields": [
1101 | {
1102 | "name": "hasNextPage",
1103 | "description": "When paginating forwards, are there more items?",
1104 | "args": [],
1105 | "type": {
1106 | "kind": "NON_NULL",
1107 | "name": null,
1108 | "ofType": {
1109 | "kind": "SCALAR",
1110 | "name": "Boolean",
1111 | "ofType": null
1112 | }
1113 | },
1114 | "isDeprecated": false,
1115 | "deprecationReason": null
1116 | },
1117 | {
1118 | "name": "hasPreviousPage",
1119 | "description": "When paginating backwards, are there more items?",
1120 | "args": [],
1121 | "type": {
1122 | "kind": "NON_NULL",
1123 | "name": null,
1124 | "ofType": {
1125 | "kind": "SCALAR",
1126 | "name": "Boolean",
1127 | "ofType": null
1128 | }
1129 | },
1130 | "isDeprecated": false,
1131 | "deprecationReason": null
1132 | },
1133 | {
1134 | "name": "startCursor",
1135 | "description": "When paginating backwards, the cursor to continue.",
1136 | "args": [],
1137 | "type": {
1138 | "kind": "SCALAR",
1139 | "name": "String",
1140 | "ofType": null
1141 | },
1142 | "isDeprecated": false,
1143 | "deprecationReason": null
1144 | },
1145 | {
1146 | "name": "endCursor",
1147 | "description": "When paginating forwards, the cursor to continue.",
1148 | "args": [],
1149 | "type": {
1150 | "kind": "SCALAR",
1151 | "name": "String",
1152 | "ofType": null
1153 | },
1154 | "isDeprecated": false,
1155 | "deprecationReason": null
1156 | }
1157 | ],
1158 | "inputFields": null,
1159 | "interfaces": [],
1160 | "enumValues": null,
1161 | "possibleTypes": null
1162 | },
1163 | {
1164 | "kind": "SCALAR",
1165 | "name": "Boolean",
1166 | "description": "The `Boolean` scalar type represents `true` or `false`.",
1167 | "fields": null,
1168 | "inputFields": null,
1169 | "interfaces": null,
1170 | "enumValues": null,
1171 | "possibleTypes": null
1172 | },
1173 | {
1174 | "kind": "OBJECT",
1175 | "name": "ScheduleSlotEdge",
1176 | "description": "An edge in a connection.",
1177 | "fields": [
1178 | {
1179 | "name": "node",
1180 | "description": "The item at the end of the edge",
1181 | "args": [],
1182 | "type": {
1183 | "kind": "UNION",
1184 | "name": "ScheduleSlot",
1185 | "ofType": null
1186 | },
1187 | "isDeprecated": false,
1188 | "deprecationReason": null
1189 | },
1190 | {
1191 | "name": "cursor",
1192 | "description": "A cursor for use in pagination",
1193 | "args": [],
1194 | "type": {
1195 | "kind": "NON_NULL",
1196 | "name": null,
1197 | "ofType": {
1198 | "kind": "SCALAR",
1199 | "name": "String",
1200 | "ofType": null
1201 | }
1202 | },
1203 | "isDeprecated": false,
1204 | "deprecationReason": null
1205 | }
1206 | ],
1207 | "inputFields": null,
1208 | "interfaces": [],
1209 | "enumValues": null,
1210 | "possibleTypes": null
1211 | },
1212 | {
1213 | "kind": "UNION",
1214 | "name": "ScheduleSlot",
1215 | "description": null,
1216 | "fields": null,
1217 | "inputFields": null,
1218 | "interfaces": null,
1219 | "enumValues": null,
1220 | "possibleTypes": [
1221 | {
1222 | "kind": "OBJECT",
1223 | "name": "TalkSlot",
1224 | "ofType": null
1225 | },
1226 | {
1227 | "kind": "OBJECT",
1228 | "name": "LightningTalksSlot",
1229 | "ofType": null
1230 | },
1231 | {
1232 | "kind": "OBJECT",
1233 | "name": "ActivitySlot",
1234 | "ofType": null
1235 | }
1236 | ]
1237 | },
1238 | {
1239 | "kind": "OBJECT",
1240 | "name": "User",
1241 | "description": "An authenticated user of the application.",
1242 | "fields": [
1243 | {
1244 | "name": "id",
1245 | "description": "The ID of an object",
1246 | "args": [],
1247 | "type": {
1248 | "kind": "NON_NULL",
1249 | "name": null,
1250 | "ofType": {
1251 | "kind": "SCALAR",
1252 | "name": "ID",
1253 | "ofType": null
1254 | }
1255 | },
1256 | "isDeprecated": false,
1257 | "deprecationReason": null
1258 | }
1259 | ],
1260 | "inputFields": null,
1261 | "interfaces": [
1262 | {
1263 | "kind": "INTERFACE",
1264 | "name": "Node",
1265 | "ofType": null
1266 | }
1267 | ],
1268 | "enumValues": null,
1269 | "possibleTypes": null
1270 | },
1271 | {
1272 | "kind": "OBJECT",
1273 | "name": "SpeakerConnection",
1274 | "description": "A connection to a list of items.",
1275 | "fields": [
1276 | {
1277 | "name": "pageInfo",
1278 | "description": "Information to aid in pagination.",
1279 | "args": [],
1280 | "type": {
1281 | "kind": "NON_NULL",
1282 | "name": null,
1283 | "ofType": {
1284 | "kind": "OBJECT",
1285 | "name": "PageInfo",
1286 | "ofType": null
1287 | }
1288 | },
1289 | "isDeprecated": false,
1290 | "deprecationReason": null
1291 | },
1292 | {
1293 | "name": "edges",
1294 | "description": "Information to aid in pagination.",
1295 | "args": [],
1296 | "type": {
1297 | "kind": "LIST",
1298 | "name": null,
1299 | "ofType": {
1300 | "kind": "OBJECT",
1301 | "name": "SpeakerEdge",
1302 | "ofType": null
1303 | }
1304 | },
1305 | "isDeprecated": false,
1306 | "deprecationReason": null
1307 | }
1308 | ],
1309 | "inputFields": null,
1310 | "interfaces": [],
1311 | "enumValues": null,
1312 | "possibleTypes": null
1313 | },
1314 | {
1315 | "kind": "OBJECT",
1316 | "name": "SpeakerEdge",
1317 | "description": "An edge in a connection.",
1318 | "fields": [
1319 | {
1320 | "name": "node",
1321 | "description": "The item at the end of the edge",
1322 | "args": [],
1323 | "type": {
1324 | "kind": "OBJECT",
1325 | "name": "Speaker",
1326 | "ofType": null
1327 | },
1328 | "isDeprecated": false,
1329 | "deprecationReason": null
1330 | },
1331 | {
1332 | "name": "cursor",
1333 | "description": "A cursor for use in pagination",
1334 | "args": [],
1335 | "type": {
1336 | "kind": "NON_NULL",
1337 | "name": null,
1338 | "ofType": {
1339 | "kind": "SCALAR",
1340 | "name": "String",
1341 | "ofType": null
1342 | }
1343 | },
1344 | "isDeprecated": false,
1345 | "deprecationReason": null
1346 | }
1347 | ],
1348 | "inputFields": null,
1349 | "interfaces": [],
1350 | "enumValues": null,
1351 | "possibleTypes": null
1352 | },
1353 | {
1354 | "kind": "OBJECT",
1355 | "name": "__Schema",
1356 | "description": "A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all available types and directives on the server, as well as the entry points for query, mutation, and subscription operations.",
1357 | "fields": [
1358 | {
1359 | "name": "types",
1360 | "description": "A list of all types supported by this server.",
1361 | "args": [],
1362 | "type": {
1363 | "kind": "NON_NULL",
1364 | "name": null,
1365 | "ofType": {
1366 | "kind": "LIST",
1367 | "name": null,
1368 | "ofType": {
1369 | "kind": "NON_NULL",
1370 | "name": null,
1371 | "ofType": {
1372 | "kind": "OBJECT",
1373 | "name": "__Type"
1374 | }
1375 | }
1376 | }
1377 | },
1378 | "isDeprecated": false,
1379 | "deprecationReason": null
1380 | },
1381 | {
1382 | "name": "queryType",
1383 | "description": "The type that query operations will be rooted at.",
1384 | "args": [],
1385 | "type": {
1386 | "kind": "NON_NULL",
1387 | "name": null,
1388 | "ofType": {
1389 | "kind": "OBJECT",
1390 | "name": "__Type",
1391 | "ofType": null
1392 | }
1393 | },
1394 | "isDeprecated": false,
1395 | "deprecationReason": null
1396 | },
1397 | {
1398 | "name": "mutationType",
1399 | "description": "If this server supports mutation, the type that mutation operations will be rooted at.",
1400 | "args": [],
1401 | "type": {
1402 | "kind": "OBJECT",
1403 | "name": "__Type",
1404 | "ofType": null
1405 | },
1406 | "isDeprecated": false,
1407 | "deprecationReason": null
1408 | },
1409 | {
1410 | "name": "subscriptionType",
1411 | "description": "If this server support subscription, the type that subscription operations will be rooted at.",
1412 | "args": [],
1413 | "type": {
1414 | "kind": "OBJECT",
1415 | "name": "__Type",
1416 | "ofType": null
1417 | },
1418 | "isDeprecated": false,
1419 | "deprecationReason": null
1420 | },
1421 | {
1422 | "name": "directives",
1423 | "description": "A list of all directives supported by this server.",
1424 | "args": [],
1425 | "type": {
1426 | "kind": "NON_NULL",
1427 | "name": null,
1428 | "ofType": {
1429 | "kind": "LIST",
1430 | "name": null,
1431 | "ofType": {
1432 | "kind": "NON_NULL",
1433 | "name": null,
1434 | "ofType": {
1435 | "kind": "OBJECT",
1436 | "name": "__Directive"
1437 | }
1438 | }
1439 | }
1440 | },
1441 | "isDeprecated": false,
1442 | "deprecationReason": null
1443 | }
1444 | ],
1445 | "inputFields": null,
1446 | "interfaces": [],
1447 | "enumValues": null,
1448 | "possibleTypes": null
1449 | },
1450 | {
1451 | "kind": "OBJECT",
1452 | "name": "__Type",
1453 | "description": "The fundamental unit of any GraphQL Schema is the type. There are many kinds of types in GraphQL as represented by the `__TypeKind` enum.\n\nDepending on the kind of a type, certain fields describe information about that type. Scalar types provide no information beyond a name and description, while Enum types provide their values. Object and Interface types provide the fields they describe. Abstract types, Union and Interface, provide the Object types possible at runtime. List and NonNull types compose other types.",
1454 | "fields": [
1455 | {
1456 | "name": "kind",
1457 | "description": null,
1458 | "args": [],
1459 | "type": {
1460 | "kind": "NON_NULL",
1461 | "name": null,
1462 | "ofType": {
1463 | "kind": "ENUM",
1464 | "name": "__TypeKind",
1465 | "ofType": null
1466 | }
1467 | },
1468 | "isDeprecated": false,
1469 | "deprecationReason": null
1470 | },
1471 | {
1472 | "name": "name",
1473 | "description": null,
1474 | "args": [],
1475 | "type": {
1476 | "kind": "SCALAR",
1477 | "name": "String",
1478 | "ofType": null
1479 | },
1480 | "isDeprecated": false,
1481 | "deprecationReason": null
1482 | },
1483 | {
1484 | "name": "description",
1485 | "description": null,
1486 | "args": [],
1487 | "type": {
1488 | "kind": "SCALAR",
1489 | "name": "String",
1490 | "ofType": null
1491 | },
1492 | "isDeprecated": false,
1493 | "deprecationReason": null
1494 | },
1495 | {
1496 | "name": "fields",
1497 | "description": null,
1498 | "args": [
1499 | {
1500 | "name": "includeDeprecated",
1501 | "description": null,
1502 | "type": {
1503 | "kind": "SCALAR",
1504 | "name": "Boolean",
1505 | "ofType": null
1506 | },
1507 | "defaultValue": "false"
1508 | }
1509 | ],
1510 | "type": {
1511 | "kind": "LIST",
1512 | "name": null,
1513 | "ofType": {
1514 | "kind": "NON_NULL",
1515 | "name": null,
1516 | "ofType": {
1517 | "kind": "OBJECT",
1518 | "name": "__Field",
1519 | "ofType": null
1520 | }
1521 | }
1522 | },
1523 | "isDeprecated": false,
1524 | "deprecationReason": null
1525 | },
1526 | {
1527 | "name": "interfaces",
1528 | "description": null,
1529 | "args": [],
1530 | "type": {
1531 | "kind": "LIST",
1532 | "name": null,
1533 | "ofType": {
1534 | "kind": "NON_NULL",
1535 | "name": null,
1536 | "ofType": {
1537 | "kind": "OBJECT",
1538 | "name": "__Type",
1539 | "ofType": null
1540 | }
1541 | }
1542 | },
1543 | "isDeprecated": false,
1544 | "deprecationReason": null
1545 | },
1546 | {
1547 | "name": "possibleTypes",
1548 | "description": null,
1549 | "args": [],
1550 | "type": {
1551 | "kind": "LIST",
1552 | "name": null,
1553 | "ofType": {
1554 | "kind": "NON_NULL",
1555 | "name": null,
1556 | "ofType": {
1557 | "kind": "OBJECT",
1558 | "name": "__Type",
1559 | "ofType": null
1560 | }
1561 | }
1562 | },
1563 | "isDeprecated": false,
1564 | "deprecationReason": null
1565 | },
1566 | {
1567 | "name": "enumValues",
1568 | "description": null,
1569 | "args": [
1570 | {
1571 | "name": "includeDeprecated",
1572 | "description": null,
1573 | "type": {
1574 | "kind": "SCALAR",
1575 | "name": "Boolean",
1576 | "ofType": null
1577 | },
1578 | "defaultValue": "false"
1579 | }
1580 | ],
1581 | "type": {
1582 | "kind": "LIST",
1583 | "name": null,
1584 | "ofType": {
1585 | "kind": "NON_NULL",
1586 | "name": null,
1587 | "ofType": {
1588 | "kind": "OBJECT",
1589 | "name": "__EnumValue",
1590 | "ofType": null
1591 | }
1592 | }
1593 | },
1594 | "isDeprecated": false,
1595 | "deprecationReason": null
1596 | },
1597 | {
1598 | "name": "inputFields",
1599 | "description": null,
1600 | "args": [],
1601 | "type": {
1602 | "kind": "LIST",
1603 | "name": null,
1604 | "ofType": {
1605 | "kind": "NON_NULL",
1606 | "name": null,
1607 | "ofType": {
1608 | "kind": "OBJECT",
1609 | "name": "__InputValue",
1610 | "ofType": null
1611 | }
1612 | }
1613 | },
1614 | "isDeprecated": false,
1615 | "deprecationReason": null
1616 | },
1617 | {
1618 | "name": "ofType",
1619 | "description": null,
1620 | "args": [],
1621 | "type": {
1622 | "kind": "OBJECT",
1623 | "name": "__Type",
1624 | "ofType": null
1625 | },
1626 | "isDeprecated": false,
1627 | "deprecationReason": null
1628 | }
1629 | ],
1630 | "inputFields": null,
1631 | "interfaces": [],
1632 | "enumValues": null,
1633 | "possibleTypes": null
1634 | },
1635 | {
1636 | "kind": "ENUM",
1637 | "name": "__TypeKind",
1638 | "description": "An enum describing what kind of type a given `__Type` is.",
1639 | "fields": null,
1640 | "inputFields": null,
1641 | "interfaces": null,
1642 | "enumValues": [
1643 | {
1644 | "name": "SCALAR",
1645 | "description": "Indicates this type is a scalar.",
1646 | "isDeprecated": false,
1647 | "deprecationReason": null
1648 | },
1649 | {
1650 | "name": "OBJECT",
1651 | "description": "Indicates this type is an object. `fields` and `interfaces` are valid fields.",
1652 | "isDeprecated": false,
1653 | "deprecationReason": null
1654 | },
1655 | {
1656 | "name": "INTERFACE",
1657 | "description": "Indicates this type is an interface. `fields` and `possibleTypes` are valid fields.",
1658 | "isDeprecated": false,
1659 | "deprecationReason": null
1660 | },
1661 | {
1662 | "name": "UNION",
1663 | "description": "Indicates this type is a union. `possibleTypes` is a valid field.",
1664 | "isDeprecated": false,
1665 | "deprecationReason": null
1666 | },
1667 | {
1668 | "name": "ENUM",
1669 | "description": "Indicates this type is an enum. `enumValues` is a valid field.",
1670 | "isDeprecated": false,
1671 | "deprecationReason": null
1672 | },
1673 | {
1674 | "name": "INPUT_OBJECT",
1675 | "description": "Indicates this type is an input object. `inputFields` is a valid field.",
1676 | "isDeprecated": false,
1677 | "deprecationReason": null
1678 | },
1679 | {
1680 | "name": "LIST",
1681 | "description": "Indicates this type is a list. `ofType` is a valid field.",
1682 | "isDeprecated": false,
1683 | "deprecationReason": null
1684 | },
1685 | {
1686 | "name": "NON_NULL",
1687 | "description": "Indicates this type is a non-null. `ofType` is a valid field.",
1688 | "isDeprecated": false,
1689 | "deprecationReason": null
1690 | }
1691 | ],
1692 | "possibleTypes": null
1693 | },
1694 | {
1695 | "kind": "OBJECT",
1696 | "name": "__Field",
1697 | "description": "Object and Interface types are described by a list of Fields, each of which has a name, potentially a list of arguments, and a return type.",
1698 | "fields": [
1699 | {
1700 | "name": "name",
1701 | "description": null,
1702 | "args": [],
1703 | "type": {
1704 | "kind": "NON_NULL",
1705 | "name": null,
1706 | "ofType": {
1707 | "kind": "SCALAR",
1708 | "name": "String",
1709 | "ofType": null
1710 | }
1711 | },
1712 | "isDeprecated": false,
1713 | "deprecationReason": null
1714 | },
1715 | {
1716 | "name": "description",
1717 | "description": null,
1718 | "args": [],
1719 | "type": {
1720 | "kind": "SCALAR",
1721 | "name": "String",
1722 | "ofType": null
1723 | },
1724 | "isDeprecated": false,
1725 | "deprecationReason": null
1726 | },
1727 | {
1728 | "name": "args",
1729 | "description": null,
1730 | "args": [],
1731 | "type": {
1732 | "kind": "NON_NULL",
1733 | "name": null,
1734 | "ofType": {
1735 | "kind": "LIST",
1736 | "name": null,
1737 | "ofType": {
1738 | "kind": "NON_NULL",
1739 | "name": null,
1740 | "ofType": {
1741 | "kind": "OBJECT",
1742 | "name": "__InputValue"
1743 | }
1744 | }
1745 | }
1746 | },
1747 | "isDeprecated": false,
1748 | "deprecationReason": null
1749 | },
1750 | {
1751 | "name": "type",
1752 | "description": null,
1753 | "args": [],
1754 | "type": {
1755 | "kind": "NON_NULL",
1756 | "name": null,
1757 | "ofType": {
1758 | "kind": "OBJECT",
1759 | "name": "__Type",
1760 | "ofType": null
1761 | }
1762 | },
1763 | "isDeprecated": false,
1764 | "deprecationReason": null
1765 | },
1766 | {
1767 | "name": "isDeprecated",
1768 | "description": null,
1769 | "args": [],
1770 | "type": {
1771 | "kind": "NON_NULL",
1772 | "name": null,
1773 | "ofType": {
1774 | "kind": "SCALAR",
1775 | "name": "Boolean",
1776 | "ofType": null
1777 | }
1778 | },
1779 | "isDeprecated": false,
1780 | "deprecationReason": null
1781 | },
1782 | {
1783 | "name": "deprecationReason",
1784 | "description": null,
1785 | "args": [],
1786 | "type": {
1787 | "kind": "SCALAR",
1788 | "name": "String",
1789 | "ofType": null
1790 | },
1791 | "isDeprecated": false,
1792 | "deprecationReason": null
1793 | }
1794 | ],
1795 | "inputFields": null,
1796 | "interfaces": [],
1797 | "enumValues": null,
1798 | "possibleTypes": null
1799 | },
1800 | {
1801 | "kind": "OBJECT",
1802 | "name": "__InputValue",
1803 | "description": "Arguments provided to Fields or Directives and the input fields of an InputObject are represented as Input Values which describe their type and optionally a default value.",
1804 | "fields": [
1805 | {
1806 | "name": "name",
1807 | "description": null,
1808 | "args": [],
1809 | "type": {
1810 | "kind": "NON_NULL",
1811 | "name": null,
1812 | "ofType": {
1813 | "kind": "SCALAR",
1814 | "name": "String",
1815 | "ofType": null
1816 | }
1817 | },
1818 | "isDeprecated": false,
1819 | "deprecationReason": null
1820 | },
1821 | {
1822 | "name": "description",
1823 | "description": null,
1824 | "args": [],
1825 | "type": {
1826 | "kind": "SCALAR",
1827 | "name": "String",
1828 | "ofType": null
1829 | },
1830 | "isDeprecated": false,
1831 | "deprecationReason": null
1832 | },
1833 | {
1834 | "name": "type",
1835 | "description": null,
1836 | "args": [],
1837 | "type": {
1838 | "kind": "NON_NULL",
1839 | "name": null,
1840 | "ofType": {
1841 | "kind": "OBJECT",
1842 | "name": "__Type",
1843 | "ofType": null
1844 | }
1845 | },
1846 | "isDeprecated": false,
1847 | "deprecationReason": null
1848 | },
1849 | {
1850 | "name": "defaultValue",
1851 | "description": "A GraphQL-formatted string representing the default value for this input value.",
1852 | "args": [],
1853 | "type": {
1854 | "kind": "SCALAR",
1855 | "name": "String",
1856 | "ofType": null
1857 | },
1858 | "isDeprecated": false,
1859 | "deprecationReason": null
1860 | }
1861 | ],
1862 | "inputFields": null,
1863 | "interfaces": [],
1864 | "enumValues": null,
1865 | "possibleTypes": null
1866 | },
1867 | {
1868 | "kind": "OBJECT",
1869 | "name": "__EnumValue",
1870 | "description": "One possible value for a given Enum. Enum values are unique values, not a placeholder for a string or numeric value. However an Enum value is returned in a JSON response as a string.",
1871 | "fields": [
1872 | {
1873 | "name": "name",
1874 | "description": null,
1875 | "args": [],
1876 | "type": {
1877 | "kind": "NON_NULL",
1878 | "name": null,
1879 | "ofType": {
1880 | "kind": "SCALAR",
1881 | "name": "String",
1882 | "ofType": null
1883 | }
1884 | },
1885 | "isDeprecated": false,
1886 | "deprecationReason": null
1887 | },
1888 | {
1889 | "name": "description",
1890 | "description": null,
1891 | "args": [],
1892 | "type": {
1893 | "kind": "SCALAR",
1894 | "name": "String",
1895 | "ofType": null
1896 | },
1897 | "isDeprecated": false,
1898 | "deprecationReason": null
1899 | },
1900 | {
1901 | "name": "isDeprecated",
1902 | "description": null,
1903 | "args": [],
1904 | "type": {
1905 | "kind": "NON_NULL",
1906 | "name": null,
1907 | "ofType": {
1908 | "kind": "SCALAR",
1909 | "name": "Boolean",
1910 | "ofType": null
1911 | }
1912 | },
1913 | "isDeprecated": false,
1914 | "deprecationReason": null
1915 | },
1916 | {
1917 | "name": "deprecationReason",
1918 | "description": null,
1919 | "args": [],
1920 | "type": {
1921 | "kind": "SCALAR",
1922 | "name": "String",
1923 | "ofType": null
1924 | },
1925 | "isDeprecated": false,
1926 | "deprecationReason": null
1927 | }
1928 | ],
1929 | "inputFields": null,
1930 | "interfaces": [],
1931 | "enumValues": null,
1932 | "possibleTypes": null
1933 | },
1934 | {
1935 | "kind": "OBJECT",
1936 | "name": "__Directive",
1937 | "description": "A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document.\n\nIn some cases, you need to provide options to alter GraphQL’s execution behavior in ways field arguments will not suffice, such as conditionally including or skipping a field. Directives provide this by describing additional information to the executor.",
1938 | "fields": [
1939 | {
1940 | "name": "name",
1941 | "description": null,
1942 | "args": [],
1943 | "type": {
1944 | "kind": "NON_NULL",
1945 | "name": null,
1946 | "ofType": {
1947 | "kind": "SCALAR",
1948 | "name": "String",
1949 | "ofType": null
1950 | }
1951 | },
1952 | "isDeprecated": false,
1953 | "deprecationReason": null
1954 | },
1955 | {
1956 | "name": "description",
1957 | "description": null,
1958 | "args": [],
1959 | "type": {
1960 | "kind": "SCALAR",
1961 | "name": "String",
1962 | "ofType": null
1963 | },
1964 | "isDeprecated": false,
1965 | "deprecationReason": null
1966 | },
1967 | {
1968 | "name": "args",
1969 | "description": null,
1970 | "args": [],
1971 | "type": {
1972 | "kind": "NON_NULL",
1973 | "name": null,
1974 | "ofType": {
1975 | "kind": "LIST",
1976 | "name": null,
1977 | "ofType": {
1978 | "kind": "NON_NULL",
1979 | "name": null,
1980 | "ofType": {
1981 | "kind": "OBJECT",
1982 | "name": "__InputValue"
1983 | }
1984 | }
1985 | }
1986 | },
1987 | "isDeprecated": false,
1988 | "deprecationReason": null
1989 | },
1990 | {
1991 | "name": "onOperation",
1992 | "description": null,
1993 | "args": [],
1994 | "type": {
1995 | "kind": "NON_NULL",
1996 | "name": null,
1997 | "ofType": {
1998 | "kind": "SCALAR",
1999 | "name": "Boolean",
2000 | "ofType": null
2001 | }
2002 | },
2003 | "isDeprecated": false,
2004 | "deprecationReason": null
2005 | },
2006 | {
2007 | "name": "onFragment",
2008 | "description": null,
2009 | "args": [],
2010 | "type": {
2011 | "kind": "NON_NULL",
2012 | "name": null,
2013 | "ofType": {
2014 | "kind": "SCALAR",
2015 | "name": "Boolean",
2016 | "ofType": null
2017 | }
2018 | },
2019 | "isDeprecated": false,
2020 | "deprecationReason": null
2021 | },
2022 | {
2023 | "name": "onField",
2024 | "description": null,
2025 | "args": [],
2026 | "type": {
2027 | "kind": "NON_NULL",
2028 | "name": null,
2029 | "ofType": {
2030 | "kind": "SCALAR",
2031 | "name": "Boolean",
2032 | "ofType": null
2033 | }
2034 | },
2035 | "isDeprecated": false,
2036 | "deprecationReason": null
2037 | }
2038 | ],
2039 | "inputFields": null,
2040 | "interfaces": [],
2041 | "enumValues": null,
2042 | "possibleTypes": null
2043 | }
2044 | ],
2045 | "directives": [
2046 | {
2047 | "name": "include",
2048 | "description": "Directs the executor to include this field or fragment only when the `if` argument is true.",
2049 | "args": [
2050 | {
2051 | "name": "if",
2052 | "description": "Included when true.",
2053 | "type": {
2054 | "kind": "NON_NULL",
2055 | "name": null,
2056 | "ofType": {
2057 | "kind": "SCALAR",
2058 | "name": "Boolean",
2059 | "ofType": null
2060 | }
2061 | },
2062 | "defaultValue": null
2063 | }
2064 | ],
2065 | "onOperation": false,
2066 | "onFragment": true,
2067 | "onField": true
2068 | },
2069 | {
2070 | "name": "skip",
2071 | "description": "Directs the executor to skip this field or fragment when the `if` argument is true.",
2072 | "args": [
2073 | {
2074 | "name": "if",
2075 | "description": "Skipped when true.",
2076 | "type": {
2077 | "kind": "NON_NULL",
2078 | "name": null,
2079 | "ofType": {
2080 | "kind": "SCALAR",
2081 | "name": "Boolean",
2082 | "ofType": null
2083 | }
2084 | },
2085 | "defaultValue": null
2086 | }
2087 | ],
2088 | "onOperation": false,
2089 | "onFragment": true,
2090 | "onField": true
2091 | }
2092 | ]
2093 | }
2094 | }
2095 | }
--------------------------------------------------------------------------------