[Online Courses, Schools, and Other External Resour] LingoIO:
About this project:

This project has been created in hopes for finally making language learning 100% free. LingoIO has already created software for native-level translations for various languages, and is slowly releasing source code to broaden the audience, and get developers into creating plugins for the software. Afterall, everyone should have free education. (This project supports both Android and iOS)

With this tutorial, you will learn VARIOUS elements to building the software from the ground up. This includes, but is not limited to very wide range of functionalities as listed below​

AngularJS

Loading data from JSON (soon.....)

Parsing JSON data (soon.....)

Custom Animation / Functionality (soon.....)

Building a flash-cards system

Android AppGyver

Preparing a template

Building the backbone

PHP - Where most of the magic happens (soon.....)

Working with the database

Spanish Syntax Mapping

Spanish word-ordering detection

Handling translation responses

Progress system

For now, we will go piece-by-piece .

[Getting your project setup]:

The good thing is that we are building this from scratch, so, the only requirement is that you have Steroids JS installed, which you can grab at AppGyver . They have an EXTREMELY easy tutorial on getting setup. It's much better than we could ever make in a post, so, please follow their install wizard ^_^​

Now that we have that out the way, let's take a look at the AngularJS controllers, and how they are setup.​

The structure of an Index Card

| card_stack
--| card
----| title
----| cardID
----| answers
-------| answer
-------| description

Setting up our controllers Backbone

In your application path, we should first find the file 'app\example\scripts\LearnMoreController'. This is the file we will be using as our main controller.​

We should start by creating a reference to our controller, which is quite easy:

//example is the name of the default module created.
var LIMP = angular.module("example");

//Alternatively, you may opt to stick with the default reference which would be the following
angular.module("example").controller
angular.module("example").factory

//So on and so forth . . . .

Now that we can interact with our application, let's go ahead and setup our initial Learning controller

//Remember the Limp variable we set? It should go right above this function
var LIMP = angular.module("example");

//Notice that we have made references to $scope, $element, and supersonic
//These are required
LIMP.controller('FlashcardController', function ($scope, $element, supersonic) {

});

We can now interact with our controller ^_^ . But we still have a ways to go. . . .

We can now setup our initial deck, and let our scope know what it contains. Add the following inside the controller

$scope.card_stack = [{ "title": "Hello", "cardID": "Hello", "answers": [{ "answer": "Hola", "description": "Saying hi" }] }, { "title": "The Dog", "cardID": "the_dog", "answers": [{ "answer": "El perro", "description": "(masc) Animal" }, { "answer": "La perra", "description": "(fem) Animal" }] }, { "title": "The cat", "cardID": "the_cat", "answers": [{ "answer": "El gato", "description": "(masc) Animal" }, { "answer": "La gata", "description": "(fem) Animal" }] }];

We now have three flashcards: "hello", "the dog", and "the cat" with their respective answers.

Now, we want to be able to test on flash-cards don't we? For that, there are a few things we have to do.

We need to create another controller that will handle our study system. We will call this 'StudyController'

It should be placed under the FlashcardController.

LIMP.controller("StudyController", function ($scope, $element, supersonic) {

});

Again, define your card_stack -- but this time, let's make another reference

LIMP.controller("StudyController", function ($scope, $element, supersonic) {

//STACK OF CARDS
$scope.card_stack = [{ "title": "Hello", "cardID": "Hello", "answers": [{ "answer": "Hola", "description": "Saying hi" }] }, { "title": "The Dog", "cardID": "the_dog", "answers": [{ "answer": "El perro", "description": "(masc) Animal" }, { "answer": "La perra", "description": "(fem) Animal" }] }, { "title": "The cat", "cardID": "the_cat", "answers": [{ "answer": "El gato", "description": "(masc) Animal" }, { "answer": "La gata", "description": "(fem) Animal" }] }];

$scope.study_cards = $scope.card_stack;

});

We have our cards defined that we will test on. Now, there are a few variables you need to define, so that we can keep track of question progress

LIMP.controller("StudyController", function ($scope, $element, supersonic) {

//STACK OF CARDS
$scope.card_stack = [{ "title": "Hello", "cardID": "Hello", "answers": [{ "answer": "Hola", "description": "Saying hi" }] }, { "title": "The Dog", "cardID": "the_dog", "answers": [{ "answer": "El perro", "description": "(masc) Animal" }, { "answer": "La perra", "description": "(fem) Animal" }] }, { "title": "The cat", "cardID": "the_cat", "answers": [{ "answer": "El gato", "description": "(masc) Animal" }, { "answer": "La gata", "description": "(fem) Animal" }] }];

$scope.study_cards = $scope.card_stack;

//STORES VALUE FOR THE CURRENT QUESTION
$scope.currentQuestion = "";

//KEEP TRACK OF PROGRESS ( WHICH QUESTION ARE WE AT, HOW MANY DO WE HAVE )
$scope.studyIndex = 0;
$scope.studyCount = $scope.study_cards.length;

//NUMBER OF ANSWERS CORRECT / FALSE
$scope.numCorrect = 0;
$scope.numWrong = 0;

//SET FIRST QUESTION TITLE
$scope.currentQuestion = $scope.card_stack[0].title
});

We are almost done with a basic flash-cards system, but we have two functions that we need to setup.

$scope.submitAnswer() and $scope.studySessionComplete()

The two functions should be added inside the StudyController, under the $scope.currentQuestion like so

LIMP.controller("StudyController", function ($scope, $element, supersonic) {

//STACK OF CARDS
$scope.card_stack = [{ "title": "Hello", "cardID": "Hello", "answers": [{ "answer": "Hola", "description": "Saying hi" }] }, { "title": "The Dog", "cardID": "the_dog", "answers": [{ "answer": "El perro", "description": "(masc) Animal" }, { "answer": "La perra", "description": "(fem) Animal" }] }, { "title": "The cat", "cardID": "the_cat", "answers": [{ "answer": "El gato", "description": "(masc) Animal" }, { "answer": "La gata", "description": "(fem) Animal" }] }];

$scope.study_cards = $scope.card_stack;

//STORES VALUE FOR THE CURRENT QUESTION
$scope.currentQuestion = "";

//KEEP TRACK OF PROGRESS ( WHICH QUESTION ARE WE AT, HOW MANY DO WE HAVE )
$scope.studyIndex = 0;
$scope.studyCount = $scope.study_cards.length;

//NUMBER OF ANSWERS CORRECT / FALSE
$scope.numCorrect = 0;
$scope.numWrong = 0;

//SET FIRST QUESTION TITLE
$scope.currentQuestion = $scope.card_stack[0].title

//Submit the answer
$scope.submitAnswer = function () {

//alert("submit answer");
var answer = $("#submission_text").val();

//SET ANSWERS IN VARIABLE the_answers
var the_answers = $scope.study_cards[$scope.studyIndex].answers;

//VARIABLE FOR ANSWER RESPONSE
var answer_correct = false;

//CHECK IF ANSWER CORRECT

//LOOP THROUGH EACH ANSWER
for (var i = 0 ; i < the_answers.length; i++) {

if ($scope.study_cards[$scope.studyIndex].answers[i].answer == answer) {
answer_correct = true;
}
}

if (answer_correct) { //IF ANSWER IS CORRECT

$scope.numCorrect++; // +1
} else { //IF ANSWER IS WRONG

$scope.numWrong++; // +1
}

//NEW QUESTION
$scope.studyIndex ++;
if ($scope.studyIndex >= $scope.studyCount) {
$scope.studySessionComplete();
} else {
//SET NEW QUESTION TITLE
$scope.currentQuestion = $scope.study_cards[$scope.studyIndex].title;
}

$("#submission_text").val("");

};

//Study session is finished
$scope.studySessionComplete = function () {
$("#gameBoard").fadeOut(1500, function () {
$("#scoreBoard").fadeIn(function () {
alert("All done here....");
});
});
}

}

});

$scope.studySessionComplete tells our UI we are finished, and to display stats.

This simply hides the gameBoard, and displays the scoreBoard as defined in our HTML

$scope.submitAnswer handles our submission of answers. Here is how it works

We get value of the input box, and set it as the answer

Then, we get a list of possible answers for the question we are currently on.

The app then loops through those answers, and looks for a match.

Next, if a match is found, add points -- and vice versus for wrong

Finally, we check to see if we are done testing. If not, increase the index -- and set the next question. If we are, $scope.studySessionComplete() is called.

We are done with the JS portion. Your code should look like this:

LIMP.controller('FlashcardController', function ($scope, $element, supersonic) {
$scope.card_stack = [{ "title": "Hello", "cardID": "Hello", "answers": [{ "answer": "Hola", "description": "Saying hi" }] }, { "title": "The Dog", "cardID": "the_dog", "answers": [{ "answer": "El perro", "description": "(masc) Animal" }, { "answer": "La perra", "description": "(fem) Animal" }] }, { "title": "The cat", "cardID": "the_cat", "answers": [{ "answer": "El gato", "description": "(masc) Animal" }, { "answer": "La gata", "description": "(fem) Animal" }] }];

$scope.startTest = function () {
//alert("SAFDA");
var view = new supersonic.ui.View("example#learnNow");
supersonic.ui.layers.push(view);
}
});

LIMP.controller("StudyController", function ($scope, $element, supersonic) {

//STACK OF CARDS
$scope.card_stack = [{ "title": "Hello", "cardID": "Hello", "answers": [{ "answer": "Hola", "description": "Saying hi" }] }, { "title": "The Dog", "cardID": "the_dog", "answers": [{ "answer": "El perro", "description": "(masc) Animal" }, { "answer": "La perra", "description": "(fem) Animal" }] }, { "title": "The cat", "cardID": "the_cat", "answers": [{ "answer": "El gato", "description": "(masc) Animal" }, { "answer": "La gata", "description": "(fem) Animal" }] }];

$scope.study_cards = $scope.card_stack;

//STORES VALUE FOR THE CURRENT QUESTION
$scope.currentQuestion = "";

//KEEP TRACK OF PROGRESS ( WHICH QUESTION ARE WE AT, HOW MANY DO WE HAVE )
$scope.studyIndex = 0;
$scope.studyCount = $scope.study_cards.length;

//NUMBER OF ANSWERS CORRECT / FALSE
$scope.numCorrect = 0;
$scope.numWrong = 0;

//SET FIRST QUESTION TITLE
$scope.currentQuestion = $scope.card_stack[0].title

//Submit the answer
$scope.submitAnswer = function () {

//alert("submit answer");
var answer = $("#submission_text").val();

//SET ANSWERS IN VARIABLE the_answers
var the_answers = $scope.study_cards[$scope.studyIndex].answers;

//VARIABLE FOR ANSWER RESPONSE
var answer_correct = false;

//CHECK IF ANSWER CORRECT

//LOOP THROUGH EACH ANSWER
for (var i = 0 ; i < the_answers.length; i++) {

if ($scope.study_cards[$scope.studyIndex].answers[i].answer == answer) {
answer_correct = true;
}
}

if (answer_correct) { //IF ANSWER IS CORRECT

$scope.numCorrect++; // +1
} else { //IF ANSWER IS WRONG

$scope.numWrong++; // +1
}

//NEW QUESTION
$scope.studyIndex ++;
if ($scope.studyIndex >= $scope.studyCount) {
$scope.studySessionComplete();
} else {
//SET NEW QUESTION TITLE
$scope.currentQuestion = $scope.study_cards[$scope.studyIndex].title;
}

$("#submission_text").val("");

};

//Study session is finished
$scope.studySessionComplete = function () {
$("#gameBoard").fadeOut(1500, function () {
$("#scoreBoard").fadeIn(function () {
alert("All done here....");
});
});
}

});

Last but not least, let's tie our code to our JS ^_^

For starters, you need to open the structure file found at

{project_name}/config/structure.coffee

It should be this:

module.exports =

# See styling options for tabs and other native components in app/common/native-styles/ios.css or app/common/native-styles/android.css
tabs: [
{
title: "Vocabulary"
id: "index"
location: "example#flashcards" # URLs are supported!
}
{
title: "LingoIO"
id: "internet"
location: "lingoio.com" # URLs are supported!
}
{
title: "Twitter"
id: "internet"
location: "twitter.com/lingo_io" # URLs are supported!
}
]

# rootView:
# location: "example#getting-started"

preloads: [
{
id: "learn-now"
location: "example#learnNow"
}
{
id: "using-the-scanner"
location: "example#using-the-scanner"
}
]

# drawers:
# left:
# id: "leftDrawer"
# location: "example#drawer"
# showOnAppLoad: false
# options:
# animation: "swingingDoor"
#
# initialView:
# id: "initialView"
# location: "example#initial-view"

Finally, add the following files to folder {project_name}/app/example/views

learnNow.html

<link href="/Bootstrap3/css/bootstrap.css" rel="stylesheet" />
<link href="/Bootstrap3/css/bootstrap-theme.css" rel="stylesheet" />
<div ng-controller="StudyController">
<div id="gameBoard" class="list">
<div class="item">
Question: {{numCorrect}} / {{studyIndex}}
</div>
<div class="item">
Number Correct: {{numCorrect}} / {{studyIndex}}
</div><br /><br />
<div class="item">
How do you say <strong>'<big>{{currentQuestion}}</big>'</strong> in English ?
</div>
<div class="item item-divider"></div>
<div class="item">
<input id="submission_text" type="text" style="padding: 15px; width: 100%;" placeholder="Answer..." /><br /><br />
<input type="button" class="btn btn-primary" style="padding: 15px; width: 100%;" Value="Submit Answer" ng-click="submitAnswer()" />
</div>

</div>

<div id="scoreBoard" style="display: none;">
<h1>Congratulations on completing your study session ! ^_^</h1>
You have studied the following<br />
<div class="item" ng-repeat="card in card_stack">
<div id="{{card.cardID}}">
<div class="item item-divider">
<span style="display: inline-block">{{card.title}}</span><span style="display: inline-block; float: right"><img src="/star.png" height="25" /></span>
</div>
</div>
</div>
</div>
</div>

flashcards.html

<link href="/Bootstrap3/css/bootstrap.css" rel="stylesheet" />
<link href="/Bootstrap3/css/bootstrap-theme.css" rel="stylesheet" />
<div class="padding" ng-controller="FlashcardController">
<div class="list">
<div class="item" ng-repeat="card in card_stack">

<div id="{{card.cardID}}">
<div class="item item-divider">
<span style="display: inline-block">{{card.title}}</span><span style="display: inline-block; float: right"><img src="/star.png" height="25" /></span>
</div>

<div ng-repeat="answer in card.answers" class="padding item item-divider">
<code>{{answer.answer}}</code><br /><br />
<p style="color: darkgreen; padding: 15px;">
<code>{{answer.description}}</code>
</p>

</div>
</div>

</div>
</div>
<div ng-click="startTest();" class="btn btn-primary" style="margin: auto; padding: 15px; width: 200px;">Hello</div>
</div>

As I find time, I will add other elements of this tutorial such as the back-end, syntax/word mapping, etc! Be patient ^_^

Check out the full source-code here on Github: github.com/montraydavis/AppGyver-Flashcards/

twitter.com/lingo_io