Expanded Example application
This commit is contained in:
parent
e85b0170cf
commit
b607834e31
|
@ -61,13 +61,6 @@
|
|||
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/jni" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/jni" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/res" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/assets" type="java-test-resource" />
|
||||
|
@ -75,6 +68,13 @@
|
|||
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/jni" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/rs" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/jni" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/assets" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/classes" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/debug" />
|
||||
|
|
|
@ -1,61 +1,4 @@
|
|||
/**
|
||||
* Sample React Native App
|
||||
* https://github.com/facebook/react-native
|
||||
*/
|
||||
|
||||
import React, {
|
||||
AppRegistry,
|
||||
Component,
|
||||
StyleSheet,
|
||||
Text,
|
||||
View
|
||||
} from 'react-native';
|
||||
|
||||
const TestFairyBridge = require('react-native-testfairy');
|
||||
|
||||
class TestFairy extends Component {
|
||||
componentWillMount() {
|
||||
TestFairyBridge.begin('5b3af35e59a1e074e2d50675b1b629306cf0cfbd');
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
TestFairyBridge.hideView(this.refs.instructions);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Text style={styles.welcome}>
|
||||
Welcome to React Native!
|
||||
</Text>
|
||||
<Text style={styles.instructions} ref="instructions">
|
||||
To get started, edit index.android.js
|
||||
</Text>
|
||||
<Text style={styles.instructions}>
|
||||
Shake or press menu button for dev menu
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
backgroundColor: '#F5FCFF',
|
||||
},
|
||||
welcome: {
|
||||
fontSize: 20,
|
||||
textAlign: 'center',
|
||||
margin: 10,
|
||||
},
|
||||
instructions: {
|
||||
textAlign: 'center',
|
||||
color: '#333333',
|
||||
marginBottom: 5,
|
||||
},
|
||||
});
|
||||
const {AppRegistry} = require('react-native');
|
||||
const TestFairy = require('./js/app');
|
||||
|
||||
AppRegistry.registerComponent('TestFairy', () => TestFairy);
|
||||
|
|
|
@ -1,62 +1,4 @@
|
|||
/**
|
||||
* Sample React Native App
|
||||
* https://github.com/facebook/react-native
|
||||
*/
|
||||
|
||||
import React, {
|
||||
AppRegistry,
|
||||
Component,
|
||||
StyleSheet,
|
||||
Text,
|
||||
View
|
||||
} from 'react-native';
|
||||
|
||||
const TestFairyBridge = require('react-native-testfairy');
|
||||
|
||||
class TestFairy extends Component {
|
||||
componentWillMount() {
|
||||
TestFairyBridge.begin('5b3af35e59a1e074e2d50675b1b629306cf0cfbd');
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
TestFairyBridge.hideView(this.refs.instructions);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Text style={styles.welcome}>
|
||||
Welcome to React Native!
|
||||
</Text>
|
||||
<Text style={styles.instructions}>
|
||||
To get started, edit index.ios.js
|
||||
</Text>
|
||||
<Text style={styles.instructions} ref="instructions">
|
||||
Press Cmd+R to reload,{'\n'}
|
||||
Cmd+D or shake for dev menu
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
backgroundColor: '#F5FCFF',
|
||||
},
|
||||
welcome: {
|
||||
fontSize: 20,
|
||||
textAlign: 'center',
|
||||
margin: 10,
|
||||
},
|
||||
instructions: {
|
||||
textAlign: 'center',
|
||||
color: '#333333',
|
||||
marginBottom: 5,
|
||||
},
|
||||
});
|
||||
const {AppRegistry} = require('react-native');
|
||||
const TestFairy = require('./js/app');
|
||||
|
||||
AppRegistry.registerComponent('TestFairy', () => TestFairy);
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
const base64 = require('base-64');
|
||||
const endpoint = "https://app.testfairy.com/api/1";
|
||||
|
||||
module.exports = {
|
||||
projects: function(login) {
|
||||
var authentication = base64.encode(`${login.email}:${login.token}`);
|
||||
var url = endpoint + "/projects"
|
||||
return fetch(url, {
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Basic ${authentication}`
|
||||
}
|
||||
})
|
||||
.then(res => res.json());
|
||||
},
|
||||
builds: function(project, login) {
|
||||
var authentication = base64.encode(`${login.email}:${login.token}`);
|
||||
var url = endpoint + `/projects/${project.id}/builds`
|
||||
return fetch(url, {
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Basic ${authentication}`
|
||||
}
|
||||
})
|
||||
.then(res => res.json());
|
||||
},
|
||||
sessions: function(project, build, login) {
|
||||
var authentication = base64.encode(`${login.email}:${login.token}`);
|
||||
var url = endpoint + `/projects/${project.id}/builds/${build.id}/sessions`
|
||||
return fetch(url, {
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Basic ${authentication}`
|
||||
}
|
||||
})
|
||||
.then(res => res.json());
|
||||
},
|
||||
session: function(project, build, session, login) {
|
||||
var authentication = base64.encode(`${login.email}:${login.token}`);
|
||||
var url = endpoint + `/projects/${project.id}/builds/${build.id}/sessions/${session.id}`
|
||||
return fetch(url, {
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Basic ${authentication}`
|
||||
}
|
||||
})
|
||||
.then(res => res.json());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
'use strict';
|
||||
|
||||
import React from 'react-native'
|
||||
import { createStore, applyMiddleware } from 'redux'
|
||||
import { Provider } from 'react-redux'
|
||||
import thunk from 'redux-thunk'
|
||||
|
||||
import reducers from './reducers'
|
||||
import Main from './main'
|
||||
|
||||
const createStoreWithMW = applyMiddleware(thunk)(createStore)
|
||||
const store = createStoreWithMW(reducers)
|
||||
|
||||
module.exports = React.createClass({
|
||||
render: function () {
|
||||
return (
|
||||
<Provider store={store}>
|
||||
<Main />
|
||||
</Provider>
|
||||
);
|
||||
}
|
||||
});
|
|
@ -0,0 +1,118 @@
|
|||
'use strict';
|
||||
|
||||
var React = require('react-native');
|
||||
var {
|
||||
View,
|
||||
Text,
|
||||
StyleSheet,
|
||||
ListView,
|
||||
RefreshControl
|
||||
} = React;
|
||||
|
||||
import NavBar, { NavButton, NavButtonText, NavTitle } from 'react-native-nav'
|
||||
|
||||
module.exports = React.createClass({
|
||||
getInitialState: function() {
|
||||
return {
|
||||
refreshing: false,
|
||||
dataSource: new ListView.DataSource({
|
||||
rowHasChanged: (row1, row2) => row1 !== row2
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
this.onRefresh();
|
||||
},
|
||||
|
||||
componentWillReceiveProps: function(props) {
|
||||
const {dataSource} = this.state;
|
||||
this.setState({
|
||||
dataSource: dataSource.cloneWithRows(props.items)
|
||||
});
|
||||
},
|
||||
|
||||
render: function () {
|
||||
const {dataSource} = this.state;
|
||||
var navigation;
|
||||
if (this.props.hasBack) {
|
||||
navigation = (
|
||||
<NavBar style={styles} statusBar={{ barStyle: 'light-content' }}>
|
||||
<NavButton onPress={() => this.props.navigator.pop()}><NavButtonText>{"Back"}</NavButtonText></NavButton>
|
||||
<NavTitle style={styles.title}>{this.props.title}</NavTitle>
|
||||
<NavButton onPress={() => this.props.onLogout()}><NavButtonText>{'Logout'}</NavButtonText></NavButton>
|
||||
</NavBar>
|
||||
);
|
||||
} else {
|
||||
navigation = (
|
||||
<NavBar style={styles} statusBar={{ barStyle: 'light-content' }}>
|
||||
<NavButton><NavButtonText>{' '}</NavButtonText></NavButton>
|
||||
<NavTitle style={styles.title}>{this.props.title}</NavTitle>
|
||||
<NavButton onPress={() => this.props.onLogout()}><NavButtonText>{'Logout'}</NavButtonText></NavButton>
|
||||
</NavBar>
|
||||
);
|
||||
}
|
||||
|
||||
if (dataSource.getRowCount() == 0 && this.state.refreshing == false) {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
{navigation}
|
||||
<View style={styles.emptyView}>
|
||||
<Text>No {this.props.title} found!</Text>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
{navigation}
|
||||
<ListView
|
||||
dataSource={dataSource}
|
||||
renderRow={this.renderRow}
|
||||
style={styles.listView}>
|
||||
<RefreshControl
|
||||
refreshing={this.state.refreshing}
|
||||
onRefresh={this.onRefresh}/>
|
||||
</ListView>
|
||||
</View>
|
||||
);
|
||||
},
|
||||
|
||||
renderRow: function(item) {
|
||||
return this.props.renderRow(item, this.props);
|
||||
},
|
||||
|
||||
onRefresh: function() {
|
||||
const {fetch} = this.props;
|
||||
this.setState({refreshing: true});
|
||||
fetch(this.props)
|
||||
.then(() => {
|
||||
this.setState({refreshing: false});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
var styles = StyleSheet.create({
|
||||
emptyView: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center'
|
||||
},
|
||||
container: {
|
||||
flex: 1
|
||||
},
|
||||
statusBar: {
|
||||
backgroundColor: '#000',
|
||||
},
|
||||
navBar: {
|
||||
backgroundColor: '#212121',
|
||||
},
|
||||
title: {
|
||||
color: '#fff',
|
||||
flex: 1
|
||||
},
|
||||
listView: {
|
||||
|
||||
}
|
||||
});
|
|
@ -0,0 +1,243 @@
|
|||
'use strict';
|
||||
|
||||
const React = require('react-native');
|
||||
const {Platform, StyleSheet, Navigator} = React;
|
||||
const {View, Text, TouchableHighlight} = React;
|
||||
const {connect} = require('react-redux');
|
||||
const TestFairyBridge = require('react-native-testfairy');
|
||||
|
||||
const SignIn = require('./signin');
|
||||
const Projects = require('./projects');
|
||||
const List = require('./list');
|
||||
const Session = require('./session');
|
||||
const actions = require('./actions');
|
||||
|
||||
var Main = React.createClass({
|
||||
componentWillMount() {
|
||||
TestFairyBridge.begin('5b3af35e59a1e074e2d50675b1b629306cf0cfbd');
|
||||
},
|
||||
|
||||
render: function () {
|
||||
return (
|
||||
<Navigator
|
||||
ref='navigator'
|
||||
style={styles.container}
|
||||
initialRoute={{}}
|
||||
configureScene={(route) => {
|
||||
if (Platform.OS === 'android') {
|
||||
return Navigator.SceneConfigs.FloatFromBottomAndroid;
|
||||
} else {
|
||||
return Navigator.SceneConfigs.FloatFromRight;
|
||||
}
|
||||
}}
|
||||
renderScene={this.renderScene}
|
||||
/>
|
||||
);
|
||||
},
|
||||
|
||||
isLoggedIn: function() {
|
||||
var {login} = this.props;
|
||||
return login.email && login.token;
|
||||
},
|
||||
|
||||
renderScene: function(route, navigator) {
|
||||
var {
|
||||
login,
|
||||
fetchProjects, projects,
|
||||
fetchBuilds, builds,
|
||||
fetchSessions, sessions,
|
||||
fetchSession, session
|
||||
} = this.props;
|
||||
|
||||
if (route.session) {
|
||||
return (<Session
|
||||
login={login}
|
||||
project={route.project}
|
||||
build={route.build}
|
||||
session={route.session}
|
||||
fetch={fetchSession}
|
||||
current={session}
|
||||
navigator={navigator}
|
||||
hasBack={true}
|
||||
onLogout={this.props.doLogout}
|
||||
/>)
|
||||
}
|
||||
|
||||
if (route.sessions) {
|
||||
return (<List
|
||||
title={`${route.project.name} Sessions`}
|
||||
login={login}
|
||||
fetch={fetchSessions}
|
||||
items={sessions}
|
||||
navigator={navigator}
|
||||
renderRow={this.renderSessionItem}
|
||||
build={route.build}
|
||||
project={route.project}
|
||||
hasBack={true}
|
||||
onLogout={this.props.doLogout}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (route.builds) {
|
||||
return (<List
|
||||
title={`${route.project.name} Builds`}
|
||||
login={login}
|
||||
fetch={fetchBuilds}
|
||||
items={builds}
|
||||
navigator={navigator}
|
||||
renderRow={this.renderBuildItem}
|
||||
project={route.project}
|
||||
hasBack={true}
|
||||
onLogout={this.props.doLogout}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
// if (route.projects) {
|
||||
if (this.isLoggedIn()) {
|
||||
return (
|
||||
<List
|
||||
title={'Projects'}
|
||||
login={login}
|
||||
fetch={fetchProjects}
|
||||
items={projects}
|
||||
navigator={navigator}
|
||||
renderRow={this.renderProjectItem}
|
||||
hasBack={false}
|
||||
onLogout={this.props.doLogout}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<SignIn
|
||||
login={login}
|
||||
onLogin={this.props.doLogin}/>
|
||||
);
|
||||
},
|
||||
|
||||
renderProjectItem: function(project, props) {
|
||||
return (
|
||||
<TouchableHighlight onPress={() => {
|
||||
this.refs.navigator.push({builds: true, project: project})
|
||||
}} underlayColor='#CCC'>
|
||||
<View style={styles.projectRow}>
|
||||
<Text style={styles.projectRowTitle}>{project.name}</Text>
|
||||
<Text style={styles.projectRowSubTitle}>{project.packageName}</Text>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
);
|
||||
},
|
||||
|
||||
renderBuildItem: function(build, props) {
|
||||
return (
|
||||
<TouchableHighlight onPress={() => {
|
||||
this.refs.navigator.push({sessions: true, build: build, project: props.project})
|
||||
}} underlayColor='#CCC'>
|
||||
<View style={styles.projectRow}>
|
||||
<Text style={styles.projectRowTitle}>{build.appName}</Text>
|
||||
<Text style={styles.projectRowSubTitle}>{build.version}</Text>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
);
|
||||
},
|
||||
|
||||
renderSessionItem: function(session, props) {
|
||||
return (
|
||||
<TouchableHighlight onPress={() => {
|
||||
this.refs.navigator.push({session: true, build: props.build, project: props.project, session: session})
|
||||
}} underlayColor='#CCC'>
|
||||
<View style={styles.projectRow}>
|
||||
<Text style={styles.projectRowTitle}>{session.testerEmail}</Text>
|
||||
<Text style={styles.projectRowSubTitle}>Session #{session.id} - {session.duration}</Text>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = connect(state => {
|
||||
return {...state}
|
||||
}, (dispatch) => {
|
||||
return {
|
||||
doLogin: function(email, token) {
|
||||
dispatch({
|
||||
type: 'LOGIN',
|
||||
item: {email, token}
|
||||
});
|
||||
},
|
||||
doLogout: function() {
|
||||
dispatch({
|
||||
type: 'LOGOUT'
|
||||
});
|
||||
},
|
||||
fetchProjects: function(props) {
|
||||
var login = props.login;
|
||||
return actions.projects(login)
|
||||
.then(res => {
|
||||
dispatch({
|
||||
type: 'NEW_PROJECTS',
|
||||
items: res.projects
|
||||
})
|
||||
}, err => {
|
||||
console.log(err);
|
||||
})
|
||||
},
|
||||
fetchBuilds: function(props) {
|
||||
var {project, login} = props;
|
||||
return actions.builds(project, login)
|
||||
.then(res => {
|
||||
dispatch({
|
||||
type: 'NEW_BUILDS',
|
||||
items: res.builds
|
||||
});
|
||||
}, err => {
|
||||
console.log(err);
|
||||
})
|
||||
},
|
||||
fetchSessions: function(props) {
|
||||
var {project, build, login} = props;
|
||||
return actions.sessions(project, build, login)
|
||||
.then(res => {
|
||||
dispatch({
|
||||
type: 'NEW_SESSIONS',
|
||||
items: res.sessions
|
||||
});
|
||||
}, err => {
|
||||
console.log(err);
|
||||
})
|
||||
},
|
||||
fetchSession: function(props) {
|
||||
var {project, build, login, session} = props;
|
||||
return actions.session(project, build, session, login)
|
||||
.then(res => {
|
||||
console.log(res);
|
||||
return res;
|
||||
})
|
||||
.then(res => {
|
||||
dispatch({
|
||||
type: 'SET_SELECTED_SESSION',
|
||||
item: res.session
|
||||
});
|
||||
}, err => {
|
||||
console.log(err);
|
||||
})
|
||||
}
|
||||
}
|
||||
})(Main);
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
},
|
||||
projectRow: {
|
||||
padding: 16
|
||||
},
|
||||
projectRowTitle: {
|
||||
fontSize: 18
|
||||
},
|
||||
projectRowSubTitle: {
|
||||
color: '#666'
|
||||
}
|
||||
});
|
|
@ -0,0 +1,74 @@
|
|||
'use strict';
|
||||
|
||||
var React = require('react-native');
|
||||
var {
|
||||
View,
|
||||
Text,
|
||||
StyleSheet,
|
||||
ListView
|
||||
} = React;
|
||||
|
||||
import NavBar, { NavButton, NavButtonText, NavTitle } from 'react-native-nav'
|
||||
|
||||
module.exports = React.createClass({
|
||||
getInitialState: function() {
|
||||
return {
|
||||
dataSource: new ListView.DataSource({
|
||||
rowHasChanged: (row1, row2) => row1 !== row2
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
const {login, fetchProjects} = this.props;
|
||||
fetchProjects(login);
|
||||
},
|
||||
|
||||
componentWillReceiveProps: function(props) {
|
||||
const {dataSource} = this.state;
|
||||
this.setState({
|
||||
dataSource: dataSource.cloneWithRows(props.projects)
|
||||
});
|
||||
},
|
||||
|
||||
render: function () {
|
||||
const {dataSource} = this.state;
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<NavBar style={styles} statusBar={{ barStyle: 'light-content' }}>
|
||||
<NavTitle style={styles.title}>TestFairy</NavTitle>
|
||||
</NavBar>
|
||||
<ListView
|
||||
dataSource={dataSource}
|
||||
renderRow={this.renderRow}
|
||||
style={styles.listView}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
},
|
||||
|
||||
renderRow: function(project) {
|
||||
return (
|
||||
<Text>{project.name}</Text>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1
|
||||
},
|
||||
statusBar: {
|
||||
backgroundColor: '#000',
|
||||
},
|
||||
navBar: {
|
||||
backgroundColor: '#212121',
|
||||
},
|
||||
title: {
|
||||
color: '#fff',
|
||||
flex: 1
|
||||
},
|
||||
listView: {
|
||||
|
||||
}
|
||||
});
|
|
@ -0,0 +1,47 @@
|
|||
'use strict';
|
||||
|
||||
var { combineReducers } = require('redux');
|
||||
|
||||
var initial = {
|
||||
email: undefined,
|
||||
token: undefined
|
||||
};
|
||||
|
||||
module.exports = combineReducers({
|
||||
login: function(state = initial, action) {
|
||||
if (action.type == 'LOGIN') {
|
||||
return action.item;
|
||||
} else if (action.type == 'LOGOUT') {
|
||||
return {};
|
||||
}
|
||||
|
||||
return state;
|
||||
},
|
||||
projects: function(state = [], action) {
|
||||
if (action.type === 'NEW_PROJECTS') {
|
||||
return action.items;
|
||||
}
|
||||
return state;
|
||||
},
|
||||
builds: function(state = [], action) {
|
||||
if (action.type === 'NEW_BUILDS') {
|
||||
return action.items;
|
||||
}
|
||||
return state;
|
||||
},
|
||||
sessions: function(state = [], action) {
|
||||
if (action.type === 'NEW_SESSIONS') {
|
||||
return action.items;
|
||||
}
|
||||
return state;
|
||||
},
|
||||
session: function(state = {}, action) {
|
||||
if (action.type === 'SET_SELECTED_SESSION') {
|
||||
return action.item;
|
||||
} else if (action.type === 'CLEAR_SELECTED_SESSION') {
|
||||
return {};
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
});
|
|
@ -0,0 +1,79 @@
|
|||
'use strict';
|
||||
|
||||
var React = require('react-native');
|
||||
var {
|
||||
View,
|
||||
Text,
|
||||
StyleSheet,
|
||||
ScrollView
|
||||
} = React;
|
||||
|
||||
import NavBar, { NavButton, NavButtonText, NavTitle } from 'react-native-nav'
|
||||
|
||||
module.exports = React.createClass({
|
||||
getInitialState: function() {
|
||||
return {
|
||||
session: this.props.session
|
||||
};
|
||||
},
|
||||
componentWillReceiveProps: function(props) {
|
||||
var session = Object.assign({}, this.state.session, props.session);
|
||||
this.setState({
|
||||
session: session
|
||||
});
|
||||
},
|
||||
componentDidMount: function() {
|
||||
this.onRefresh();
|
||||
},
|
||||
onRefresh: function() {
|
||||
const {fetch} = this.props;
|
||||
fetch(this.props);
|
||||
},
|
||||
render: function () {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<NavBar style={styles} statusBar={{ barStyle: 'light-content' }}>
|
||||
<NavButton onPress={() => this.props.navigator.pop()}><NavButtonText>{"Back"}</NavButtonText></NavButton>
|
||||
<NavTitle style={styles.title}>{this.props.project.name} (#{this.props.session.id})</NavTitle>
|
||||
<NavButton onPress={() => this.props.onLogout()}><NavButtonText>{'Logout'}</NavButtonText></NavButton>
|
||||
</NavBar>
|
||||
<ScrollView style={styles.container}>
|
||||
<View>
|
||||
{this.sessionItem('Package: ', this.props.project.packageName)}
|
||||
{this.sessionItem('Version: ', this.props.build.version)}
|
||||
{this.sessionItem('Tester: ', this.props.session.testerEmail)}
|
||||
{this.sessionItem('Duration: ', this.props.session.duration)}
|
||||
{this.sessionItem('Device: ', this.props.session.device)}
|
||||
</View>
|
||||
</ScrollView>
|
||||
</View>
|
||||
);
|
||||
},
|
||||
sessionItem: function(key, value) {
|
||||
return <View style={{flexDirection: 'row'}}>
|
||||
<Text style={styles.key}>{key}</Text><Text style={styles.value}>{value}</Text>
|
||||
</View>
|
||||
}
|
||||
});
|
||||
|
||||
var styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1
|
||||
},
|
||||
statusBar: {
|
||||
backgroundColor: '#000',
|
||||
},
|
||||
navBar: {
|
||||
backgroundColor: '#212121',
|
||||
},
|
||||
title: {
|
||||
color: '#fff'
|
||||
},
|
||||
key: {
|
||||
color: '#CCC',
|
||||
fontSize: 20
|
||||
},
|
||||
value: {
|
||||
fontSize: 20
|
||||
}
|
||||
});
|
|
@ -0,0 +1,118 @@
|
|||
'use strict';
|
||||
|
||||
var React = require('react-native');
|
||||
var {
|
||||
View,
|
||||
Text,
|
||||
StatusBar,
|
||||
StyleSheet,
|
||||
TextInput,
|
||||
TouchableHighlight
|
||||
} = React;
|
||||
|
||||
const TestFairyBridge = require('react-native-testfairy');
|
||||
|
||||
module.exports = React.createClass({
|
||||
getInitialState: function() {
|
||||
return {
|
||||
email: this.props.login.email,
|
||||
token: this.props.login.token
|
||||
};
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
TestFairyBridge.hideView(this.refs.emailInput);
|
||||
TestFairyBridge.hideView(this.refs.apiTokenInput);
|
||||
},
|
||||
|
||||
render: function () {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<StatusBar
|
||||
translucent={true}
|
||||
/>
|
||||
<View style={styles.top}>
|
||||
<Text style={styles.header}>TestFairy</Text>
|
||||
<View style={styles.inputWrapper}>
|
||||
<TextInput
|
||||
ref='emailInput'
|
||||
style={styles.input}
|
||||
onChangeText={(text) => this.setState({email: text})}
|
||||
value={this.state.email}
|
||||
placeholder={'Email'}
|
||||
autoCapitalize={'none'}
|
||||
keyboardType={'email-address'}
|
||||
autoCorrect={false}
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.inputWrapper}>
|
||||
<TextInput
|
||||
ref='apiTokenInput'
|
||||
style={[styles.input]}
|
||||
onChangeText={(text) => this.setState({token: text})}
|
||||
value={this.state.token}
|
||||
placeholder={'API Token'}
|
||||
/>
|
||||
</View>
|
||||
<TouchableHighlight style={styles.buttonWrapper} onPress={this.doLogin} underlayColor='#CCC'>
|
||||
<Text style={styles.button}>Sign In</Text>
|
||||
</TouchableHighlight>
|
||||
</View>
|
||||
<View style={styles.bottom}>
|
||||
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
},
|
||||
|
||||
doLogin: function() {
|
||||
this.props.onLogin(this.state.email, this.state.token);
|
||||
}
|
||||
});
|
||||
|
||||
var styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1
|
||||
},
|
||||
top: {
|
||||
flex: 5,
|
||||
marginTop: 100,
|
||||
},
|
||||
bottom: {
|
||||
flex: 4
|
||||
},
|
||||
header: {
|
||||
fontSize: 25,
|
||||
padding: 4,
|
||||
textAlign: 'center',
|
||||
marginBottom: 12
|
||||
},
|
||||
inputWrapper: {
|
||||
|
||||
},
|
||||
input: {
|
||||
padding: 4,
|
||||
height: 40,
|
||||
width: 350,
|
||||
borderColor: 'gray',
|
||||
borderWidth: 1,
|
||||
borderRadius: 5,
|
||||
margin: 5,
|
||||
alignSelf: 'center',
|
||||
flex: 1,
|
||||
textAlign: 'center'
|
||||
},
|
||||
buttonWrapper: {
|
||||
margin: 12,
|
||||
alignItems: 'center'
|
||||
},
|
||||
button: {
|
||||
padding: 8,
|
||||
textAlign: 'center',
|
||||
fontSize: 20,
|
||||
backgroundColor: '#000000',
|
||||
color: '#FFFFFF',
|
||||
borderRadius: 5,
|
||||
width: 350
|
||||
}
|
||||
});
|
|
@ -6,8 +6,13 @@
|
|||
"start": "node node_modules/react-native/local-cli/cli.js start"
|
||||
},
|
||||
"dependencies": {
|
||||
"base-64": "^0.1.0",
|
||||
"react": "^0.14.8",
|
||||
"react-native": "^0.23.1",
|
||||
"react-native-testfairy": "file:../"
|
||||
"react-native-nav": "^1.1.2",
|
||||
"react-native-testfairy": "file:../",
|
||||
"react-redux": "~4.3.0",
|
||||
"redux": "~3.2.1",
|
||||
"redux-thunk": "~1.0.3"
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue