diff --git a/vds-app/.eslintrc.js b/vds-app/.eslintrc.js
new file mode 100644
index 0000000..d39a471
--- /dev/null
+++ b/vds-app/.eslintrc.js
@@ -0,0 +1,3 @@
+module.exports = {
+ extends: "handlebarlabs"
+}
diff --git a/vds-app/.gitignore b/vds-app/.gitignore
new file mode 100644
index 0000000..c84de93
--- /dev/null
+++ b/vds-app/.gitignore
@@ -0,0 +1,7 @@
+node_modules/**/*
+npm-debug.*
+*.jks
+*.p12
+*.key
+*.mobileprovision
+yarn.lock
diff --git a/vds-app/.watchmanconfig b/vds-app/.watchmanconfig
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/vds-app/.watchmanconfig
@@ -0,0 +1 @@
+{}
diff --git a/vds-app/App/assets/check.png b/vds-app/App/assets/check.png
new file mode 100644
index 0000000..3821204
Binary files /dev/null and b/vds-app/App/assets/check.png differ
diff --git a/vds-app/App/assets/check@2x.png b/vds-app/App/assets/check@2x.png
new file mode 100644
index 0000000..4a4cc7e
Binary files /dev/null and b/vds-app/App/assets/check@2x.png differ
diff --git a/vds-app/App/assets/check@3x.png b/vds-app/App/assets/check@3x.png
new file mode 100644
index 0000000..777df21
Binary files /dev/null and b/vds-app/App/assets/check@3x.png differ
diff --git a/vds-app/App/assets/close.png b/vds-app/App/assets/close.png
new file mode 100644
index 0000000..28f62c6
Binary files /dev/null and b/vds-app/App/assets/close.png differ
diff --git a/vds-app/App/assets/close@2x.png b/vds-app/App/assets/close@2x.png
new file mode 100644
index 0000000..5289b00
Binary files /dev/null and b/vds-app/App/assets/close@2x.png differ
diff --git a/vds-app/App/assets/close@3x.png b/vds-app/App/assets/close@3x.png
new file mode 100644
index 0000000..c6d6748
Binary files /dev/null and b/vds-app/App/assets/close@3x.png differ
diff --git a/vds-app/App/components/Alert.js b/vds-app/App/components/Alert.js
new file mode 100644
index 0000000..94e270c
--- /dev/null
+++ b/vds-app/App/components/Alert.js
@@ -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 (
+
+
+
+
+
+ );
+};
diff --git a/vds-app/App/components/Button.js b/vds-app/App/components/Button.js
new file mode 100644
index 0000000..805d0d3
--- /dev/null
+++ b/vds-app/App/components/Button.js
@@ -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 = () => {} }) => (
+
+ {text}
+
+);
+
+export const ButtonContainer = ({ children }) => (
+ {children}
+);
diff --git a/vds-app/App/components/RowItem.js b/vds-app/App/components/RowItem.js
new file mode 100644
index 0000000..4954bda
--- /dev/null
+++ b/vds-app/App/components/RowItem.js
@@ -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 }) => (
+
+
+ {name}
+
+
+);
diff --git a/vds-app/App/data/aerodynamic.js b/vds-app/App/data/aerodynamic.js
new file mode 100644
index 0000000..7c0d4a4
--- /dev/null
+++ b/vds-app/App/data/aerodynamic.js
@@ -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;
diff --git a/vds-app/App/data/computers.js b/vds-app/App/data/computers.js
new file mode 100644
index 0000000..6ff5667
--- /dev/null
+++ b/vds-app/App/data/computers.js
@@ -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;
diff --git a/vds-app/App/data/space.js b/vds-app/App/data/space.js
new file mode 100644
index 0000000..e30b543
--- /dev/null
+++ b/vds-app/App/data/space.js
@@ -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;
diff --git a/vds-app/App/data/westerns.js b/vds-app/App/data/westerns.js
new file mode 100644
index 0000000..50a8705
--- /dev/null
+++ b/vds-app/App/data/westerns.js
@@ -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;
diff --git a/vds-app/App/index.js b/vds-app/App/index.js
new file mode 100644
index 0000000..8d2c498
--- /dev/null
+++ b/vds-app/App/index.js
@@ -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);
diff --git a/vds-app/App/screens/Quiz.js b/vds-app/App/screens/Quiz.js
new file mode 100644
index 0000000..44a5cc0
--- /dev/null
+++ b/vds-app/App/screens/Quiz.js
@@ -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 (
+
+
+
+
+ {question.question}
+
+
+ {question.answers.map(answer => (
+
+
+
+
+ {`${this.state.correctCount}/${this.state.totalCount} - ${this.state.availableIds.join(',')} `}
+
+
+
+
+ )
+ }
+}
+
+export default Quiz
diff --git a/vds-app/App/screens/QuizIndex.js b/vds-app/App/screens/QuizIndex.js
new file mode 100644
index 0000000..a4f13cc
--- /dev/null
+++ b/vds-app/App/screens/QuizIndex.js
@@ -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 }) => (
+
+
+
+ navigation.navigate("Quiz", {
+ title: "Aerodinamica",
+ questions: aerodynamicQuestions,
+ color: "#36b1f0"
+ })
+ }
+ />
+
+ navigation.navigate("Quiz", {
+ title: "Space",
+ questions: spaceQuestions,
+ color: "#36b1f0"
+ })
+ }
+ />
+
+ navigation.navigate("Quiz", {
+ title: "Westerns",
+ questions: westernsQuestions,
+ color: "#799496"
+ })
+ }
+ />
+
+ navigation.navigate("Quiz", {
+ title: "Computers",
+ questions: computerQuestions,
+ color: "#49475B"
+ })
+ }
+ />
+
+);
diff --git a/vds-app/README.md b/vds-app/README.md
new file mode 100644
index 0000000..313b2a4
--- /dev/null
+++ b/vds-app/README.md
@@ -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`
+
diff --git a/vds-app/app.json b/vds-app/app.json
new file mode 100644
index 0000000..e8e0ffc
--- /dev/null
+++ b/vds-app/app.json
@@ -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
+ }
+ }
+}
diff --git a/vds-app/assets/icon.png b/vds-app/assets/icon.png
new file mode 100644
index 0000000..3f5bbc0
Binary files /dev/null and b/vds-app/assets/icon.png differ
diff --git a/vds-app/assets/splash.png b/vds-app/assets/splash.png
new file mode 100644
index 0000000..4f9ade6
Binary files /dev/null and b/vds-app/assets/splash.png differ
diff --git a/vds-app/babel.config.js b/vds-app/babel.config.js
new file mode 100644
index 0000000..f755472
--- /dev/null
+++ b/vds-app/babel.config.js
@@ -0,0 +1,6 @@
+module.exports = function(api) {
+ api.cache(true)
+ return {
+ presets: ['babel-preset-expo'],
+ }
+}
diff --git a/vds-app/package.json b/vds-app/package.json
new file mode 100644
index 0000000..bf50f1c
--- /dev/null
+++ b/vds-app/package.json
@@ -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
+}