@ -0,0 +1,3 @@ |
|||||
|
module.exports = { |
||||
|
extends: "handlebarlabs" |
||||
|
} |
@ -0,0 +1,7 @@ |
|||||
|
node_modules/**/* |
||||
|
npm-debug.* |
||||
|
*.jks |
||||
|
*.p12 |
||||
|
*.key |
||||
|
*.mobileprovision |
||||
|
yarn.lock |
@ -0,0 +1 @@ |
|||||
|
{} |
After Width: | Height: | Size: 550 B |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 2.7 KiB |
After Width: | Height: | Size: 853 B |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 3.6 KiB |
@ -0,0 +1,53 @@ |
|||||
|
import React from "react"; |
||||
|
import { View, StyleSheet, Dimensions, Image } from "react-native"; |
||||
|
|
||||
|
const screen = Dimensions.get("window"); |
||||
|
|
||||
|
const styles = StyleSheet.create({ |
||||
|
container: { |
||||
|
position: "absolute", |
||||
|
top: 0, |
||||
|
bottom: 0, |
||||
|
left: 0, |
||||
|
right: 0, |
||||
|
flex: 1, |
||||
|
alignItems: "center", |
||||
|
justifyContent: "center" |
||||
|
}, |
||||
|
circle: { |
||||
|
backgroundColor: "#ff4136", |
||||
|
width: screen.width / 2, |
||||
|
height: screen.width / 2, |
||||
|
borderRadius: screen.width / 2, |
||||
|
alignItems: "center", |
||||
|
justifyContent: "center" |
||||
|
}, |
||||
|
circleCorrect: { |
||||
|
backgroundColor: "#28A125" |
||||
|
}, |
||||
|
icon: { |
||||
|
width: screen.width / 3 |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
export const Alert = ({ correct, visible }) => { |
||||
|
if (!visible) return null; |
||||
|
|
||||
|
const icon = correct |
||||
|
? require("../assets/check.png") |
||||
|
: require("../assets/close.png"); |
||||
|
|
||||
|
const circleStyles = [styles.circle]; |
||||
|
|
||||
|
if (correct) { |
||||
|
circleStyles.push(styles.circleCorrect); |
||||
|
} |
||||
|
|
||||
|
return ( |
||||
|
<View style={styles.container}> |
||||
|
<View style={circleStyles}> |
||||
|
<Image source={icon} style={styles.icon} resizeMode="contain" /> |
||||
|
</View> |
||||
|
</View> |
||||
|
); |
||||
|
}; |
@ -0,0 +1,35 @@ |
|||||
|
import React from "react"; |
||||
|
import { View, TouchableOpacity, Text, StyleSheet } from "react-native"; |
||||
|
|
||||
|
const styles = StyleSheet.create({ |
||||
|
button: { |
||||
|
backgroundColor: "rgba(255, 255, 255, 0.3)", |
||||
|
borderRadius: 10, |
||||
|
paddingVertical: 15, |
||||
|
alignItems: "center", |
||||
|
justifyContent: "center", |
||||
|
width: "100%", |
||||
|
marginTop: 20 |
||||
|
}, |
||||
|
text: { |
||||
|
color: "#fff", |
||||
|
fontSize: 20, |
||||
|
textAlign: "center" |
||||
|
}, |
||||
|
buttonContainer: { |
||||
|
flexDirection: "row", |
||||
|
flexWrap: "wrap", |
||||
|
marginTop: 20, |
||||
|
justifyContent: "space-between" |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
export const Button = ({ text, onPress = () => {} }) => ( |
||||
|
<TouchableOpacity onPress={onPress} style={styles.button}> |
||||
|
<Text style={styles.text}>{text}</Text> |
||||
|
</TouchableOpacity> |
||||
|
); |
||||
|
|
||||
|
export const ButtonContainer = ({ children }) => ( |
||||
|
<View style={styles.buttonContainer}>{children}</View> |
||||
|
); |
@ -0,0 +1,24 @@ |
|||||
|
import React from "react"; |
||||
|
import { View, Text, TouchableOpacity, StyleSheet } from "react-native"; |
||||
|
|
||||
|
const styles = StyleSheet.create({ |
||||
|
row: { |
||||
|
paddingHorizontal: 15, |
||||
|
paddingVertical: 20, |
||||
|
backgroundColor: "#36B1F0", |
||||
|
marginBottom: 1 |
||||
|
}, |
||||
|
text: { |
||||
|
fontSize: 18, |
||||
|
color: "#fff", |
||||
|
fontWeight: "600" |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
export const RowItem = ({ onPress = () => {}, name, color }) => ( |
||||
|
<TouchableOpacity onPress={onPress} activeOpacity={0.8}> |
||||
|
<View style={[styles.row, { backgroundColor: color }]}> |
||||
|
<Text style={styles.text}>{name}</Text> |
||||
|
</View> |
||||
|
</TouchableOpacity> |
||||
|
); |
@ -0,0 +1,34 @@ |
|||||
|
const questions = [ |
||||
|
{ |
||||
|
id: 1, |
||||
|
question: "Domanda 1", |
||||
|
answers: [ |
||||
|
{ id: "1", text: "Mars" }, |
||||
|
{ id: "2", text: "Jupiter", correct: true }, |
||||
|
{ id: "3", text: "Saturn" }, |
||||
|
{ id: "4", text: "Venus" } |
||||
|
] |
||||
|
}, |
||||
|
{ |
||||
|
id: 2, |
||||
|
question: "Domanda 2", |
||||
|
answers: [ |
||||
|
{ id: "1", text: "6" }, |
||||
|
{ id: "2", text: "7" }, |
||||
|
{ id: "3", text: "8", correct: true }, |
||||
|
{ id: "4", text: "9" } |
||||
|
] |
||||
|
}, |
||||
|
{ |
||||
|
id: 3, |
||||
|
question: "Domanda 3", |
||||
|
answers: [ |
||||
|
{ id: "1", text: "6" }, |
||||
|
{ id: "2", text: "7" }, |
||||
|
{ id: "3", text: "8", correct: true }, |
||||
|
{ id: "4", text: "9" } |
||||
|
] |
||||
|
} |
||||
|
]; |
||||
|
|
||||
|
export default questions; |
@ -0,0 +1,22 @@ |
|||||
|
const questions = [ |
||||
|
{ |
||||
|
question: "What is localhost's IP address?", |
||||
|
answers: [ |
||||
|
{ id: "1", text: "192.168.1.1" }, |
||||
|
{ id: "2", text: "127.0.0.1", correct: true }, |
||||
|
{ id: "3", text: "209.85.231.104" }, |
||||
|
{ id: "4", text: "66.220.149.25" } |
||||
|
] |
||||
|
}, |
||||
|
{ |
||||
|
question: "What kind of fruit was used to name a computer in 1984?", |
||||
|
answers: [ |
||||
|
{ id: "1", text: "Blackberry" }, |
||||
|
{ id: "2", text: "Blueberry" }, |
||||
|
{ id: "3", text: "Pear" }, |
||||
|
{ id: "4", text: "Apple", correct: true } |
||||
|
] |
||||
|
} |
||||
|
]; |
||||
|
|
||||
|
export default questions; |
@ -0,0 +1,22 @@ |
|||||
|
const questions = [ |
||||
|
{ |
||||
|
question: "What is the fifth planet from the sun?", |
||||
|
answers: [ |
||||
|
{ id: "1", text: "Mars" }, |
||||
|
{ id: "2", text: "Jupiter", correct: true }, |
||||
|
{ id: "3", text: "Saturn" }, |
||||
|
{ id: "4", text: "Venus" } |
||||
|
] |
||||
|
}, |
||||
|
{ |
||||
|
question: "How many planets are in the Solar System?", |
||||
|
answers: [ |
||||
|
{ id: "1", text: "6" }, |
||||
|
{ id: "2", text: "7" }, |
||||
|
{ id: "3", text: "8", correct: true }, |
||||
|
{ id: "4", text: "9" } |
||||
|
] |
||||
|
} |
||||
|
]; |
||||
|
|
||||
|
export default questions; |
@ -0,0 +1,23 @@ |
|||||
|
const questions = [ |
||||
|
{ |
||||
|
question: |
||||
|
"In the Roy Rogers -Dale Evans Museum, you will find Roy and Dales stuffed horses. Roy's horse was named Trigger, which was Dales horse?", |
||||
|
answers: [ |
||||
|
{ id: "1", text: "Buttermilk", correct: true }, |
||||
|
{ id: "2", text: "Daisy" }, |
||||
|
{ id: "3", text: "Scout" }, |
||||
|
{ id: "4", text: "Tulip" } |
||||
|
] |
||||
|
}, |
||||
|
{ |
||||
|
question: 'What weapon has become known as "the gun that won the west"?', |
||||
|
answers: [ |
||||
|
{ id: "1", text: "Smith & Wesson Revolver" }, |
||||
|
{ id: "2", text: "Colt Peacemaker", correct: true }, |
||||
|
{ id: "3", text: "Winchester Revolver" }, |
||||
|
{ id: "4", text: "Sharps Derringer" } |
||||
|
] |
||||
|
} |
||||
|
]; |
||||
|
|
||||
|
export default questions; |
@ -0,0 +1,26 @@ |
|||||
|
import { createStackNavigator, createAppContainer } from "react-navigation"; |
||||
|
|
||||
|
import QuizIndex from "./screens/QuizIndex"; |
||||
|
import Quiz from "./screens/Quiz"; |
||||
|
|
||||
|
const MainStack = createStackNavigator({ |
||||
|
QuizIndex: { |
||||
|
screen: QuizIndex, |
||||
|
navigationOptions: { |
||||
|
headerTitle: "Quizzes" |
||||
|
} |
||||
|
}, |
||||
|
Quiz: { |
||||
|
screen: Quiz, |
||||
|
navigationOptions: ({ navigation }) => ({ |
||||
|
headerTitle: navigation.getParam("title"), |
||||
|
headerTintColor: "#fff", |
||||
|
headerStyle: { |
||||
|
backgroundColor: navigation.getParam("color"), |
||||
|
borderBottomColor: navigation.getParam("color") |
||||
|
} |
||||
|
}) |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
export default createAppContainer(MainStack); |
@ -0,0 +1,122 @@ |
|||||
|
import React from "react" |
||||
|
import { View, StyleSheet, StatusBar, Text, SafeAreaView } from "react-native" |
||||
|
|
||||
|
import { Button, ButtonContainer } from "../components/Button" |
||||
|
import { Alert } from "../components/Alert" |
||||
|
|
||||
|
const styles = StyleSheet.create({ |
||||
|
container: { |
||||
|
backgroundColor: "#36B1F0", |
||||
|
flex: 1, |
||||
|
paddingHorizontal: 20 |
||||
|
}, |
||||
|
text: { |
||||
|
color: "#fff", |
||||
|
fontSize: 25, |
||||
|
textAlign: "center", |
||||
|
letterSpacing: -0.02, |
||||
|
fontWeight: "600" |
||||
|
}, |
||||
|
safearea: { |
||||
|
flex: 1, |
||||
|
marginTop: 100, |
||||
|
justifyContent: "space-between" |
||||
|
} |
||||
|
}) |
||||
|
|
||||
|
class Quiz extends React.Component { |
||||
|
|
||||
|
state = { |
||||
|
correctCount: 0, |
||||
|
totalCount: this.props.navigation.getParam("questions", []).length, |
||||
|
availableIds: this.props.navigation.getParam("questions", []).map(a => a.id), |
||||
|
activeQuestionId: this.props.navigation.getParam("questions", [])[ |
||||
|
Math.floor(Math.random() * this.props.navigation.getParam("questions", []).length) |
||||
|
].id, |
||||
|
answered: false, |
||||
|
answerCorrect: false |
||||
|
} |
||||
|
|
||||
|
answer = correct => { |
||||
|
this.setState( |
||||
|
state => { |
||||
|
const nextState = { answered: true } |
||||
|
|
||||
|
if (correct) { |
||||
|
nextState.correctCount = state.correctCount + 1 |
||||
|
nextState.answerCorrect = true |
||||
|
} else { |
||||
|
nextState.answerCorrect = false |
||||
|
} |
||||
|
|
||||
|
return nextState |
||||
|
}, |
||||
|
() => { |
||||
|
setTimeout(() => this.nextQuestion(), 750) |
||||
|
} |
||||
|
) |
||||
|
} |
||||
|
|
||||
|
nextQuestion = () => { |
||||
|
this.setState(state => { |
||||
|
const updatedIndexes = state.availableIds.filter( item => item != state.activeQuestionId) |
||||
|
const nextId = updatedIndexes[Math.floor(Math.random() * updatedIndexes.length)] |
||||
|
|
||||
|
if (!updatedIndexes.length) { |
||||
|
this.props.navigation.popToTop() |
||||
|
} |
||||
|
/* |
||||
|
if (nextIndex >= state.totalCount) { |
||||
|
this.props.navigation.popToTop() |
||||
|
}*/ |
||||
|
|
||||
|
return { |
||||
|
totalCount: updatedIndexes.length, |
||||
|
availableIds: updatedIndexes, |
||||
|
activeQuestionId: nextId, |
||||
|
answered: false |
||||
|
} |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
render() { |
||||
|
const questions = this.props.navigation.getParam("questions", []) |
||||
|
const question = questions.filter(item => item.id == this.state.activeQuestionId)[0] || questions[0] |
||||
|
|
||||
|
return ( |
||||
|
<View |
||||
|
style={[ |
||||
|
styles.container, |
||||
|
{ backgroundColor: this.props.navigation.getParam("color") } |
||||
|
]} |
||||
|
> |
||||
|
<StatusBar barStyle="light-content" /> |
||||
|
<SafeAreaView style={styles.safearea}> |
||||
|
<View> |
||||
|
<Text style={styles.text}>{question.question}</Text> |
||||
|
|
||||
|
<ButtonContainer> |
||||
|
{question.answers.map(answer => ( |
||||
|
<Button |
||||
|
key={answer.id} |
||||
|
text={answer.text} |
||||
|
onPress={() => this.answer(answer.correct)} |
||||
|
/> |
||||
|
))} |
||||
|
</ButtonContainer> |
||||
|
</View> |
||||
|
|
||||
|
<Text style={styles.text}> |
||||
|
{`${this.state.correctCount}/${this.state.totalCount} - ${this.state.availableIds.join(',')} `} |
||||
|
</Text> |
||||
|
</SafeAreaView> |
||||
|
<Alert |
||||
|
correct={this.state.answerCorrect} |
||||
|
visible={this.state.answered} |
||||
|
/> |
||||
|
</View> |
||||
|
) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export default Quiz |
@ -0,0 +1,59 @@ |
|||||
|
import React from "react"; |
||||
|
import { ScrollView, StatusBar } from "react-native"; |
||||
|
|
||||
|
import spaceQuestions from "../data/space"; |
||||
|
import westernsQuestions from "../data/westerns"; |
||||
|
import computerQuestions from "../data/computers"; |
||||
|
import aerodynamicQuestions from "../data/aerodynamic"; |
||||
|
|
||||
|
import { RowItem } from "../components/RowItem"; |
||||
|
|
||||
|
export default ({ navigation }) => ( |
||||
|
<ScrollView> |
||||
|
<StatusBar barStyle="dark-content" /> |
||||
|
<RowItem |
||||
|
name="Aerodinamica" |
||||
|
color="#36b1f0" |
||||
|
onPress={() => |
||||
|
navigation.navigate("Quiz", { |
||||
|
title: "Aerodinamica", |
||||
|
questions: aerodynamicQuestions, |
||||
|
color: "#36b1f0" |
||||
|
}) |
||||
|
} |
||||
|
/> |
||||
|
<RowItem |
||||
|
name="Space" |
||||
|
color="#36b1f0" |
||||
|
onPress={() => |
||||
|
navigation.navigate("Quiz", { |
||||
|
title: "Space", |
||||
|
questions: spaceQuestions, |
||||
|
color: "#36b1f0" |
||||
|
}) |
||||
|
} |
||||
|
/> |
||||
|
<RowItem |
||||
|
name="Westerns" |
||||
|
color="#799496" |
||||
|
onPress={() => |
||||
|
navigation.navigate("Quiz", { |
||||
|
title: "Westerns", |
||||
|
questions: westernsQuestions, |
||||
|
color: "#799496" |
||||
|
}) |
||||
|
} |
||||
|
/> |
||||
|
<RowItem |
||||
|
name="Computers" |
||||
|
color="#49475B" |
||||
|
onPress={() => |
||||
|
navigation.navigate("Quiz", { |
||||
|
title: "Computers", |
||||
|
questions: computerQuestions, |
||||
|
color: "#49475B" |
||||
|
}) |
||||
|
} |
||||
|
/> |
||||
|
</ScrollView> |
||||
|
); |
@ -0,0 +1,16 @@ |
|||||
|
## React Native Quiz App |
||||
|
|
||||
|
A simple cross platform (iOS and Android) React Native quiz app. |
||||
|
|
||||
|
 |
||||
|
 |
||||
|
|
||||
|
### Installation |
||||
|
|
||||
|
- `git clone ssh://git@2.238.194.8:2222/git/vds_quiz.git` |
||||
|
- `yarn install`/`npm install` |
||||
|
|
||||
|
### Running |
||||
|
|
||||
|
- `yarn run ios`/`npm run ios` or `yarn run android`/`npm run android` |
||||
|
|
@ -0,0 +1,24 @@ |
|||||
|
{ |
||||
|
"expo": { |
||||
|
"name": "VDS Quiz", |
||||
|
"slug": "VDS Quiz", |
||||
|
"privacy": "public", |
||||
|
"sdkVersion": "35.0.0", |
||||
|
"platforms": ["ios", "android"], |
||||
|
"version": "1.0.0", |
||||
|
"orientation": "portrait", |
||||
|
"icon": "./assets/icon.png", |
||||
|
"splash": { |
||||
|
"image": "./assets/splash.png", |
||||
|
"resizeMode": "contain", |
||||
|
"backgroundColor": "#ffffff" |
||||
|
}, |
||||
|
"updates": { |
||||
|
"fallbackToCacheTimeout": 0 |
||||
|
}, |
||||
|
"assetBundlePatterns": ["**/*"], |
||||
|
"ios": { |
||||
|
"supportsTablet": true |
||||
|
} |
||||
|
} |
||||
|
} |
After Width: | Height: | Size: 2.9 KiB |
After Width: | Height: | Size: 7.0 KiB |
@ -0,0 +1,6 @@ |
|||||
|
module.exports = function(api) { |
||||
|
api.cache(true) |
||||
|
return { |
||||
|
presets: ['babel-preset-expo'], |
||||
|
} |
||||
|
} |
@ -0,0 +1,25 @@ |
|||||
|
{ |
||||
|
"main": "node_modules/expo/AppEntry.js", |
||||
|
"scripts": { |
||||
|
"start": "expo start", |
||||
|
"android": "expo start --android", |
||||
|
"ios": "expo start --ios", |
||||
|
"eject": "expo eject", |
||||
|
"lint": "eslint ." |
||||
|
}, |
||||
|
"dependencies": { |
||||
|
"expo": "^35.0.0", |
||||
|
"react": "16.8.3", |
||||
|
"react-native": "https://github.com/expo/react-native/archive/sdk-35.0.0.tar.gz", |
||||
|
"react-native-gesture-handler": "~1.3.0", |
||||
|
"react-native-reanimated": "~1.2.0", |
||||
|
"react-navigation": "^3.6.1" |
||||
|
}, |
||||
|
"devDependencies": { |
||||
|
"babel-preset-expo": "^7.0.0", |
||||
|
"eslint": "^5.16.0", |
||||
|
"eslint-config-handlebarlabs": "^0.0.3", |
||||
|
"prettier": "^1.16.4" |
||||
|
}, |
||||
|
"private": true |
||||
|
} |