@ -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 |
|||
} |