Commit 17a24f5a by Fernando Martínez Santiago

Merge branch 'develop' of http://scm.ujaen.es/softuno/pictogram

parents bc33a78c 709ba63f
Showing with 918 additions and 630 deletions
# EditorConfig is awesome: http://EditorConfig.org
root = true
[*]
end_of_line = lf
charset = utf-8
indent_style = space
indent_size = 2
trim_trailing_whitespace = true
insert_final_newline = true
[android/**]
indent_size = 4
# Compiled source #
###################
*.com
*.class
*.dll
*.exe
*.o
*.so
# Temporal files
################
\#.*\#
# BCrypt build #
################
sails/src/node_modules/bcrypt/build/
# Reports #
###########
eslint-report.xml
mocha-report.xml
# Images #
##########
......@@ -22,41 +14,31 @@ sails/symbolstx
sails/src/assets/symbolstx
sails/src/assets/upload
# Webapp #
##########
sails/src/logs
sails/src/assets/app/bower_components
sails/src/assets/app/modules
sails/src/assets/app/css
sails/src/assets/app/js
sails/src/assets/scripts/config.js
# Other #
#########
sails/src/assets/app/js/lib/sails.io.js
sails/src/config/ssl/**/*.key
sails/src/config/ssl/**/*.crt
sails/src/config/ssl/**/*.csr
sails/src/config/local.js
sails/src/assets/app/js/config.js
sails/src/assets/app/js/local.js
sails/src/config/ssl
sails/src/config/logs
sails/src/node_modules
sails/src/assets/app/bower_components
sails/src/.tmp
sails/config/tmp.sql
android/Pictogram/.idea
sails/.vagrant
# Android #
###########
.idea
android/Pictogram/.idea
android/Pictogram/app/app.iml
android/Pictogram/Pictogrammar.iml
# Packages #
############
# it's better to unpack these files and commit the raw source
# git has its own built in compression methods
*.7z
*.dmg
*.gz
*.iso
*.jar
*.rar
*.tar
*.zip
# Logs and databases #
######################
*.log
*.sqlite
# OS generated files #
######################
.DS_Store
......@@ -66,4 +48,3 @@ android/Pictogram/Pictogrammar.iml
.Trashes
ehthumbs.db
Thumbs.db
# Estructura del repositorio
- `master`: versión estable, servida en [pre.yottacode.com][1]
- `develop`: versión con los últimos issues completados, servida
en [dev.yottacode.com][2], se irá añadiendo periódicamente a `master`
- `issue/xxx`: versión con los cambios que resuelven el issue xxx, se unirá
a `develop` cuando se complete
## Antes de unir un issue
Se deben unir todos sus commmits con el comando `git squash` dejando una
descripción del tipo:
```
Fixed/solved #xxx, breve descripción opcional.
- Cambio A
- Cambio B
- ...
```
## Contribuciones menores
Si se quiere añadir un pequeño cambio al repositorio, puede enviarse
directamente a la rama `develop` siempre que pueda describirse brevemente
los cambios que se han realizado.
## Etiquetas
Para organizar los issues estas son las etiquetas que se van a utilizar en
todo el repositorio, organizadas en 3 categorías:
- Tipo:
- `bug`: fallos que deben resolverse
- `improvement`: mejoras y/o sugerencias a implementar
- `refactor`: cambios en la nomenglatura y la documentación
- Campo:
- `android`: cliente android
- `webapp`: aplicación web (sólo el cliente)
- `server`: servidor y base de datos
- `company`: issues relacionados con la empresa (por ejemplo congresos)
- Estado:
- `in-progress`: incidencias en proceso de desarrollo
- `critical`: elementos importantes que deben tener prioridad
# Aspecto del código
- En el fichero [.editorconfig][3] se encuentra el estilo utilizado en el código (en cuento a
espacios, codificación y demás). Existen numerosos plugins que pueden encontrarse en
[editorconfig.org][4].
- En el fichero [/sails/src/.eslintrc][5] se encuentran los estilos referentes a los ficheros de
javascript. Tanto `eslint` como las configuraciones necesarias se encuentran en el fichero
[/sails/src/package.json][6], y se instalarán como dependencias de desarrollo.
> Puede configurarse eslint en el editor usado o ejecutando `eslint [ficheros]` desde
> el directorio [/sails/src][7].
[1]: https://pre.yottacode.com/
[2]: https://dev.yottacode.com/
[3]: /softuno/pictogram/blob/develop/.editorconfig
[4]: http://editorconfig.org
[5]: /softuno/pictogram/blob/develop/sails/src/.eslintrc
[6]: /softuno/pictogram/blob/develop/sails/src/package.json
[7]: /softuno/pictogram/tree/develop/sails/src
# Pictogram
Este proyecto contiene el código de Pictogram, que se divide en tres:
- [Servidor](sails): API REST del servidor
- [Cliente web](sails/src/assets/app): aplicación web con el dashboard para supervisores
- [Cliente android](android/Pictogram): aplicación android para tablet para estudiantes
- [Servidor][2]: API REST del servidor
- [Cliente web][3]: aplicación web con el dashboard para supervisores
- [Cliente android][4]: aplicación android para tablet para estudiantes
En cada directorio puede leerse la descripción de dicha parte, incluyendo configuración y demás
utilidades. La estructura del repositorio en sí y forma de contribución se describe en
[el fichero de contribuciones][1].
## Integración continua
Para comprobar que todo funciona correctamente se ha habilitado un servidor con jenkins que
comprueba que el código está bien escrito y funciona correctamente (actualmente sólo para el
código JavaScript). Datos del servidor:
- Dirección: [ararat.ujaen.es:9537][5]
- Usuario: `uruk`
- Contraseña: `saruman es et`
> Sólo se aplica la integración a las ramas **develop** e **issue/\***. Queda pendiente el añadido
> de **master** cuando incluya la siguiente versión estable de **develop**
[1]: /softuno/pictogram/blob/develop/CONTRIBUTING.md
[2]: /softuno/pictogram/tree/develop/sails
[3]: /softuno/pictogram/tree/develop/sails/src/assets/app
[4]: /softuno/pictogram/tree/develop/android/Pictogram
[5]: http://ararat.ujaen.es:9537/job/pictogram-dev/
......@@ -9,7 +9,7 @@ android {
buildToolsVersion "21.1.2"
defaultConfig {
applicationId "com.yottacode.pictogram"
minSdkVersion 19
minSdkVersion 21
targetSdkVersion 21
versionCode 1
versionName "1.0"
......
......@@ -153,6 +153,12 @@ public class RestapiWrapper {
// convert inputstream to string
if (inputStream!=null) result = convertInputStreamToString(inputStream);
if (result.equals("") && urlConnection.getResponseCode() == 200) {
result = "{ result: \"OK\" }";
} else if (result.equals("")) {
result = "{ error: " + urlConnection.getResponseCode() + " }";
}
return result;
}
......@@ -209,6 +215,9 @@ public class RestapiWrapper {
while ((line=br.readLine()) != null) {
response+=line;
}
if (response.equals("") && responseCode != HttpsURLConnection.HTTP_OK) {
response = "{ error: " + responseCode + " }";
}
return response;
}
......
......@@ -28,6 +28,8 @@ public class Picto extends Img {
public static String CATEGORY = "id_cat";
public static String COLUMN = "coord_x";
public static String ROW = "coord_y";
public static String FREE_COLUMN = "free_category_coord_x";
public static String FREE_ROW = "free_category_coord_y";
public static String MAGNIFY = "magnify";
public static String HIGHLIGHT = "highlight";
public static String STATUS = "status";
......@@ -48,12 +50,14 @@ public class Picto extends Img {
private JSONObject attributes;
private String translation;
public Picto(int id, String url, String translation, int cat, int row, int column) throws JSONException {
public Picto(int id, String url, String translation, int cat, int row, int column, int freeRow, int freeColumn) throws JSONException {
this(id, url, translation, new JSONObject()
.put(JSON_ATTTRS.CATEGORY,cat)
.put(JSON_ATTTRS.COLUMN,column)
.put(JSON_ATTTRS.ROW,row)
.put(JSON_ATTTRS.STATUS,JSON_ATTTR_STATUS_VALUES.ENABLED));
.put(JSON_ATTTRS.CATEGORY, cat)
.put(JSON_ATTTRS.COLUMN, column)
.put(JSON_ATTTRS.ROW, row)
.put(JSON_ATTTRS.FREE_ROW, freeRow)
.put(JSON_ATTTRS.FREE_COLUMN, freeColumn)
.put(JSON_ATTTRS.STATUS, JSON_ATTTR_STATUS_VALUES.ENABLED));
}
public Picto(int id, String url,String translation, String attributes) throws JSONException {
this(id, url, translation, new JSONObject(attributes));
......@@ -216,11 +220,7 @@ public class Picto extends Img {
* @return the row of the picto
*/
public int get_row() {
try {
return Integer.parseInt(this.attributes.getString(JSON_ATTTRS.ROW));
} catch (JSONException e) {
return -1;
}
return this.attributes.optInt(JSON_ATTTRS.ROW, -1);
}
/**
......@@ -228,11 +228,23 @@ public class Picto extends Img {
* @return the column of the picto
*/
public int get_column() {
try {
return Integer.parseInt(this.attributes.getString(JSON_ATTTRS.COLUMN));
} catch (JSONException e) {
return -1;
}
return this.attributes.optInt(JSON_ATTTRS.COLUMN, -1);
}
/**
*
* @return the free row of the picto
*/
public int getFreeRow() {
return this.attributes.optInt(JSON_ATTTRS.FREE_ROW, -1);
}
/**
*
* @return the free column of the picto
*/
public int getFreeColumn() {
return this.attributes.optInt(JSON_ATTTRS.FREE_COLUMN, -1);
}
/**
......@@ -303,7 +315,10 @@ public class Picto extends Img {
* @return
*/
public boolean is_category() {
return this.get_category()==Picto.NO_CATEGORY && this.get_column()!=Picto.ROW_UNCATEGORIZED_CONCEPTS;
return this.get_category()==Picto.NO_CATEGORY &&
this.get_column() != Picto.ROW_UNCATEGORIZED_CONCEPTS &&
this.getFreeColumn() == -1 &&
this.getFreeRow() == -1;
}
/**
*
......
......@@ -26,7 +26,7 @@ public class User {
}
public final static class JSON_STUDENT_ATTTRS{
static String CATEGORIES = "category";
static String CATEGORIES = "categories";
static String INPUT_FEEDBACK = "input feedback";
static String INPUT_SELECTION = "input selection";
static String PICTOGRAM_SIZE = "pictogram size";
......@@ -232,11 +232,7 @@ public class User {
* @return true if the collection is organized by categories (default: True)
*/
public boolean has_categories() {
try {
return this.attributes_stu.getString(JSON_STUDENT_ATTTRS.CATEGORIES).equalsIgnoreCase("on");
} catch (JSONException e) {
return true;
}
return this.attributes_stu.optBoolean(JSON_STUDENT_ATTTRS.CATEGORIES, true);
}
/**
......
......@@ -4,6 +4,7 @@ import android.os.AsyncTask;
import android.util.Log;
import com.yottacode.pictogram.action.VocabularyAction;
import com.yottacode.pictogram.dao.PCBDBHelper;
import com.yottacode.pictogram.dao.Picto;
import com.yottacode.pictogram.net.ImgDownloader;
import com.yottacode.pictogram.net.PictoUploader;
......@@ -311,7 +312,19 @@ public class Vocabulary implements Iterable<Picto> {
* @return list of pictos which should be selectable at the beginning of a sentence. Empty categories are removed
*/
public LinkedList<Picto> startSentence(){
return this.pictos.get(new Integer(Picto.NO_CATEGORY));
if (PCBcontext.getPcbdb().getCurrentUser().has_categories()) {
return this.pictos.get(new Integer(Picto.NO_CATEGORY));
} else {
LinkedList<Picto> freePictos = new LinkedList<>();
for (LinkedList<Picto> category : pictos.values()) {
for (Picto picto : category) {
if (picto.getFreeRow() != -1 && picto.getFreeColumn() != -1) {
freePictos.add(picto);
}
}
}
return freePictos;
}
}
/**
......@@ -334,11 +347,11 @@ public class Vocabulary implements Iterable<Picto> {
/*
* It saves locally a new picto obtained from the PCB
*/
public Picto saveLocalPicto(String url, String exp, int cat, int coord_x, int coord_y, final iLocalPicto listener) {
public Picto saveLocalPicto(String url, String exp, int cat, int coord_x, int coord_y, int free_category_coord_x, int free_category_coord_y, final iLocalPicto listener) {
int id= PCBcontext.getDevice().getNextLocalPictoID();
final Picto picto[]=new Picto[1];
try {
picto[0] = new Picto(id, url, exp, cat, coord_x, coord_y);
picto[0] = new Picto(id, url, exp, cat, coord_x, coord_y, free_category_coord_x, free_category_coord_y);
addPicto(picto[0], ImgDownloader.tsource.local, new iImgDownloaderListener() {
@Override
public void loadComplete() {
......
......@@ -2,7 +2,6 @@ package com.yottacode.pictogram.gui;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
......@@ -11,17 +10,24 @@ import android.widget.ImageView;
import android.widget.TextView;
import com.yottacode.pictogram.R;
import com.yottacode.pictogram.tools.Img;
import java.io.IOException;
import java.util.Vector;
/**
* Creates a View for each student on the list with a photo and his/her name.
* It uses list_single.xml for the layout creation.
*/
public class CustomList extends ArrayAdapter<String>{
private final Activity context;
private final String[] name_surname;
private final Vector<Bitmap> images;
/**
* @param context Context used for rendering the view
* @param name_surname List of students' names
* @param images List of students' photos
*/
public CustomList(Activity context,
String[] name_surname, Vector<Bitmap> images) {
super(context, R.layout.list_single, name_surname);
......@@ -30,13 +36,19 @@ public class CustomList extends ArrayAdapter<String>{
this.images = images;
}
/**
* @param position Student position in the name_surname/images arrays
* @param view @TODO not being used
* @param parent @TODO not being used
* @return The rendered student view
*/
@Override
public View getView(int position, View view, ViewGroup parent) {
LayoutInflater inflater = context.getLayoutInflater();
View rowView= inflater.inflate(R.layout.list_single, null, true);
TextView txtTitle = (TextView) rowView.findViewById(R.id.txt);
TextView txtTitle = (TextView) rowView.findViewById(R.id.loginStudentName);
ImageView imageView = (ImageView) rowView.findViewById(R.id.img);
ImageView imageView = (ImageView) rowView.findViewById(R.id.loginStudentPhoto);
txtTitle.setText(name_surname[position]);
//imageView.setImageResource(R.drawable.user);
......
package com.yottacode.pictogram.gui;
import android.annotation.TargetApi;
import android.content.Intent;
import android.os.AsyncTask;
import android.support.v4.app.FragmentActivity;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.widget.Toast;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import com.yottacode.pictogram.R;
import com.yottacode.pictogram.net.ImgDownloader;
import com.yottacode.pictogram.net.iImgDownloaderListener;
import com.yottacode.pictogram.tools.Img;
import com.yottacode.pictogram.tools.PCBcontext;
import java.io.IOException;
import java.util.Vector;
/**
* LoginActivity show the login window to select the student and supervisor
* It uses device to read the token value
* @author Miguel Ángel García Cumbreras
* @author Fernando Martínez santiago
* @version 1.0
*/
public class LoginActivity extends FragmentActivity {
private int sup_id;
// String constant for logs
private final String LOG_TAG = this.getClass().getSimpleName(); // Or .getCanonicalName()
/**
* If there is Internet connection it calls the WS to recover the pairs student-supervisor
* @param savedInstanceState
......@@ -39,10 +41,58 @@ public class LoginActivity extends FragmentActivity {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_login);
// Enable logout button
final Button logoutButton = (Button) findViewById(R.id.loginTopbarLogout);
logoutButton.setEnabled(true);
logoutButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent serialActivity = new Intent(getBaseContext(), SerialActivity.class);
serialActivity.putExtra("resetPrevUser", true);
startActivity(serialActivity);
}
});
// Set supervisor information on topbar
final TextView supervisorFullNameView = (TextView) findViewById(R.id.loginTopbarSupervisorFullName);
final TextView supervisorUserNameView = (TextView) findViewById(R.id.loginTopbarSupervisorUserName);
final ImageView supervisorPhotoView = (ImageView) findViewById(R.id.loginTopbarSupervisorPhoto);
supervisorFullNameView.setText(
this.getIntent().getStringExtra("name") + " " +
this.getIntent().getStringExtra("surname"));
supervisorUserNameView.setText(this.getIntent().getStringExtra("email"));
final Vector<Img> imgs = new Vector<>(1);
imgs.add(new Img(
this.getIntent().getIntExtra("id", -1),
this.getIntent().getStringExtra("pic"),
Img.SUPERVISOR
));
ImgDownloader downloader = new ImgDownloader(this, new iImgDownloaderListener() {
@Override
public void loadComplete() {
try {
supervisorPhotoView.setImageBitmap(
imgs.get(0).get_bitmap(PCBcontext.getContext())
);
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void loadImg(Img image) {}
}, ImgDownloader.tsource.remote);
downloader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, imgs);
}
@Override
protected void onResume() {
super.onResume();
Toast.makeText(this, "onResume", Toast.LENGTH_SHORT).show();
}
}
\ No newline at end of file
package com.yottacode.pictogram.gui;
import android.annotation.TargetApi;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Build;
import android.os.Bundle;
import android.speech.tts.TextToSpeech;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.FrameLayout;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import com.yottacode.pictogram.R;
import com.yottacode.pictogram.dao.Picto;
import com.yottacode.pictogram.tools.PCBcontext;
import java.io.IOException;
import java.util.LinkedList;
public class PictoGridAdapter extends ArrayAdapter {
private LinkedList<Picto> pictoLinkedList;
private final String LOG_TAG = this.getClass().getSimpleName();
public PictoGridAdapter(LinkedList<Picto> pictoLinkedList){
super(PCBcontext.getContext(), PictoItemViewGenerator.LAYOUT, pictoLinkedList);
this.pictoLinkedList = pictoLinkedList;
}
@Override
public int getCount() {
return this.pictoLinkedList.size();
}
@Override
public Picto getItem(int position) {
return this.pictoLinkedList.get(position);
}
@Override
public long getItemId(int position) {
return 0;
}
public void deleteAll() {
this.pictoLinkedList.clear();
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
return PictoItemViewGenerator.getPictoView(
this.pictoLinkedList.get(position),
convertView,
parent
);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public void ttsPicto(Picto p, TextToSpeech tts) {
if (p.is_enabled()) {
String input = p.get_translation();
Bundle params = new Bundle();
params.putString(TextToSpeech.Engine.KEY_PARAM_VOLUME, "1");
tts.speak(input, TextToSpeech.QUEUE_FLUSH, params, null);
}
}
}
\ No newline at end of file
package com.yottacode.pictogram.gui;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import com.yottacode.pictogram.R;
import com.yottacode.pictogram.dao.Picto;
import com.yottacode.pictogram.tools.PCBcontext;
import java.io.IOException;
/**
* This class is used for generating PictoViews which will be inserted inside a picto grid
* or a picto tape.
*/
public class PictoItemViewGenerator {
public static final int LAYOUT = R.layout.picto_grid_item;
public static View getPictoView(Picto picto, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = LayoutInflater.from(parent.getContext()).inflate(LAYOUT, parent, false);
}
RelativeLayout layoutWrapper = (RelativeLayout) convertView.findViewById(R.id.picto_grid_item_layout_wrapper);
FrameLayout layout = (FrameLayout) convertView.findViewById(R.id.picto_grid_item_layout);
ImageView pictoImage = (ImageView) convertView.findViewById(R.id.picto_grid_item_image);
ImageView redCrossImage = (ImageView) convertView.findViewById(R.id.picto_grid_item_redcross);
layoutWrapper.setVisibility(View.GONE);
layoutWrapper.setBackground(null);
layoutWrapper.setAlpha(0.25f);
layout.setBackgroundColor(convertView.getResources()
.getColor(R.color.picto_default_background));
redCrossImage.setVisibility(View.GONE);
pictoImage.setScaleX(1.0f);
pictoImage.setScaleY(1.0f);
pictoImage.setVisibility(View.GONE);
if (picto != null) {
if (!picto.is_invisible() && !picto.is_disabled()) {
layoutWrapper.setAlpha(1.00f);
}
try {
pictoImage.setImageBitmap(picto.get_bitmap(PCBcontext.getContext()));
if (!picto.is_invisible() || PCBcontext.getPcbdb().getCurrentUser().is_supervisor()) {
layoutWrapper.setVisibility(View.VISIBLE);
pictoImage.setVisibility(View.VISIBLE);
layoutWrapper.setBackground(convertView.getResources()
.getDrawable(R.drawable.picto_grid_item_border));
if (picto.is_magnify()) {
pictoImage.setScaleX(1.2f);
pictoImage.setScaleY(1.2f);
}
if (picto.is_disabled()) {
redCrossImage.setVisibility(View.VISIBLE);
}
if (picto.is_category()) {
layout.setBackgroundColor(picto.get_color());
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
return convertView;
}
}
......@@ -285,7 +285,7 @@ public class StudentFragmentGrid extends Fragment{
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_new_student, container, false);
gridView = (GridView)view.findViewById(R.id.gridview);
gridView = (GridView)view.findViewById(R.id.loginStudentGridView);
Boolean offline = getActivity().getIntent().getBooleanExtra("offline", false);
if (offline || onlineStudentsOK) showStudentsGrid();
return view;
......
package com.yottacode.pictogram.gui;
import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.speech.tts.TextToSpeech;
import android.speech.tts.UtteranceProgressListener;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.BaseAdapter;
import android.widget.GridView;
import android.widget.FrameLayout;
import android.widget.ImageView;
import com.yottacode.pictogram.R;
import com.yottacode.pictogram.dao.Picto;
import com.yottacode.pictogram.tools.PCBcontext;
import com.yottacode.pictogram.tts.TTSHelper;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Locale;
/**
* Created by emblanco on 9/10/14.
* @version 2.2
* @author Miguel Ángel García
*/
public class TapeAdapter extends BaseAdapter {
//private Context mContext;
private LinkedList<Picto> lPictos;
private LinkedList<Picto> pictoLinkedList;
public TapeAdapter(){
//mContext = c;
lPictos = new LinkedList<Picto>(); // the list begins empty
pictoLinkedList = new LinkedList<Picto>(); // the list begins empty
}
@Override
public int getCount(){
return lPictos.size();
return pictoLinkedList.size();
}
public Picto getItem(int position) {
// este método debería devolver el objeto que esta en esa posición del
// adapter.
return lPictos.get(position);
return pictoLinkedList.get(position);
}
public long getItemId(int position) {
......@@ -59,19 +48,19 @@ public class TapeAdapter extends BaseAdapter {
// AÑADIR ITEM AL ADAPTADOR
public void addItem(Picto p){
lPictos.add(p);
pictoLinkedList.add(p);
}
// ELIMINAR ITEM DEL ADAPTADOR
public void deleteItem(int position){
lPictos.remove(position);
pictoLinkedList.remove(position);
}
// ELIMINAR el último ITEM DEL ADAPTADOR
public void deleteLastView(){
// Controlar excepcion al intentar eliminar el último cuando no hay elementos
try{
lPictos.removeLast();
pictoLinkedList.removeLast();
}catch(ArrayIndexOutOfBoundsException exception){
Log.e("Excepción", "ArrayIndexOutOfBounds: " + exception.getMessage());
}
......@@ -79,16 +68,16 @@ public class TapeAdapter extends BaseAdapter {
// ELIMINAR TODOS LOS ITEMS DEL ADAPTADOR
public void deleteAll(){
lPictos.clear();
pictoLinkedList.clear();
}
// DEVUELVE TODOS LOS ELEMENTOS
public LinkedList<Picto> getAll(){ return lPictos; }
public LinkedList<Picto> getAll(){ return pictoLinkedList; }
// Devuelvo la cadena actual como un String
public String getAllAsString(){
String complete = "";
Iterator<Picto> iterator = lPictos.iterator();
Iterator<Picto> iterator = pictoLinkedList.iterator();
while (iterator.hasNext()) {
Picto current = iterator.next();
complete += " " + current.get_translation();
......@@ -97,56 +86,30 @@ public class TapeAdapter extends BaseAdapter {
}
// DEVUELVE último elemento
public Picto getLastItem(){ return lPictos.getLast(); }
public Picto getLastItem(){
return pictoLinkedList.getLast();
}
// Devuelve true o false si tiene o no elementos la lista de pictos
public boolean hasElements(){
return (lPictos.size() > 0);
return (pictoLinkedList.size() > 0);
}
@Override
public View getView(int position, View convertView, ViewGroup parent){
ImageView view;
if(convertView == null){
view = new ImageView(PCBcontext.getContext());
// Ancho y alto de la imagen en la vista donde se va a colocar (en pixels)
view.setLayoutParams(new GridView.LayoutParams(80, 60));
view.setScaleType(ImageView.ScaleType.CENTER_CROP);
view.setPadding(5,5,5,5);
//view.setPadding(10,15,10,10);
}else{
view = (ImageView) convertView;
}
try{
view.setImageBitmap(lPictos.get(position).get_bitmap(PCBcontext.getContext()));
} catch (IOException e) {
e.printStackTrace();
}
return view;
}
// Función que devuelve los píxeles equivalentes a los dps pasados
public int getPx(int dimensionDp) {
float density = PCBcontext.getContext().getResources().getDisplayMetrics().density;
return (int) (dimensionDp * density + 0.5f);
return PictoItemViewGenerator.getPictoView(
this.pictoLinkedList.get(position),
convertView,
parent
);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public void ttsAllNew(TextToSpeech tts){
// DE PRUEBA
//String input = lPictos.getFirst().get_translation();
public void ttsAllNew(TextToSpeech tts) {
String input = getAllAsString();
//String input = "Geni, vaya fin de semana en el bater vas a pasar !!!";
Bundle params = new Bundle();
params.putString(TextToSpeech.Engine.KEY_PARAM_VOLUME, "1");
//tts.setPitch((float) 0.6);
//tts.setSpeechRate((float) 1);
tts.speak(input, TextToSpeech.QUEUE_FLUSH, params, null);
params.putString(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, "TAPE_READ");
tts.speak(input, TextToSpeech.QUEUE_FLUSH, params, "TAPE_READ");
}
}
......@@ -13,13 +13,11 @@ import com.yottacode.pictogram.R;
import com.yottacode.pictogram.dao.LoginException;
import com.yottacode.pictogram.dao.User;
import com.yottacode.pictogram.gui.PictogramActivity;
import com.yottacode.pictogram.gui.SerialActivity;
import com.yottacode.pictogram.tools.PCBcontext;
import org.json.JSONArray;
import org.json.JSONObject;
import java.util.Hashtable;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
......@@ -157,11 +155,11 @@ public class NetService implements Runnable {
stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
builder.setContentIntent(resultPendingIntent);
if (updated)
builder.setSmallIcon(R.drawable.picton)
builder.setSmallIcon(R.drawable.application_online)
.setContentTitle("Pictogram online")
.setContentText(PCBcontext.getContext().getResources().getString(R.string.pictogram_online));
else
builder.setSmallIcon(R.drawable.pictoff)
builder.setSmallIcon(R.drawable.application_offline)
.setContentTitle("Pictogram offline")
.setContentText(PCBcontext.getContext().getResources().getString(R.string.pictogram_offline));
......
......@@ -132,8 +132,9 @@ public class Img {
try {
this.bitmap=BitmapFactory.decodeStream(is);
if (this.bitmap.getWidth()>MAX_WIDTH) {
this.bitmap = new BitmapTools(this.bitmap).rescale(MAX_WIDTH / (float) this.bitmap.getWidth()).paintSquare(3, Color.DKGRAY).get();
this.bitmap = new BitmapTools(this.bitmap)
.rescale(MAX_WIDTH / (float) this.bitmap.getWidth())
.get();
}
}catch(java.lang.OutOfMemoryError err) {
Log.e(Img.class.getCanonicalName(), "Out of memory when decoding "+this.get_url());
......
......@@ -17,12 +17,7 @@ import com.yottacode.pictogram.net.NetService;
import com.yottacode.pictogram.action.Room;
import com.yottacode.pictogram.net.iImgDownloaderListener;
/**
* Created by emblanco on 15/10/15.
* Modified by Fernando on 09/11/15: NetService, Room, Vocabulary, RestapiWrapper, Context, Action support
*/
public final class PCBcontext {
private static Context context;
private static PCBDBHelper pcbdb;
private static Device device=null;
......@@ -47,34 +42,40 @@ public final class PCBcontext {
return Holder.INSTANCE;
}
//
// ---------------------------------------------------------------------------------------------
// Rest of class methods
//
// Init method for passing params to the singleton
/**
* Init method for passing params to the singleton
* @param c @TODO application or activity context?
*/
public static void init(Context c){
if (!init) {
init=true;
init = true;
context = c;
device = new Device(c, null, 1);
SSLDummyContext.init(context.getResources().getBoolean(R.bool.ssl_connect));
wrapper = new RestapiWrapper(context.getResources().getString(R.string.server), null);
service = new NetService(context.getResources().getInteger(R.integer.netservice_timing));
device.deleteDeprecatedImgs();
Log.i(PCBcontext.class.getCanonicalName(), "PCB context started. It's required set_user method call");
Log.i(PCBcontext.class.getCanonicalName(), "PCB context started. It's required" +
"set_user method call");
} else {
Log.e(PCBcontext.class.getClass().getCanonicalName(), "Init method was previously" +
"invoked! Please, check your code");
}
else Log.e(PCBcontext.class.getClass().getCanonicalName(), "Init method was previously invoked! Please, revise your code");
}
/**
*
* Init method for passing the rest of params to the singleton.
* It is required to set the device token before calling set_user
* @param student
* @param student @TODO user is not student
* @param listener
*/
public static void set_user(User student, String token, iImgDownloaderListener listener) {
if (!init) throw new java.lang.AssertionError("init must be called once previously ");
if (!init) {
throw new java.lang.AssertionError("init must be called once previously ");
}
Log.i(PCBcontext.class.getCanonicalName(), "User set at student " + student.get_name_stu());
wrapper.setToken(token);
pcbdb = new PCBDBHelper(null, 1, student);
......@@ -83,59 +84,130 @@ public final class PCBcontext {
actionLog = new ActionLog();
vocabulary = new Vocabulary(listener);
}
/**
* if the user becomes from offline to online and the login is failed, then the user relogin in the app
* The most frequent reason is a password change while the user have been logged offline
* if the user becomes from offline to online and the login is failed, then the user relogin in
* the app. The most frequent reason is a password change while the user have been logged
* offline
*/
public static void restart_app() {
SerialActivity.resetDefaultUser();
public static void restart_app() {
SerialActivity.resetDefaultUser();
Intent serialActivity = new Intent(PCBcontext.getContext(), SerialActivity.class);
serialActivity.putExtra("resetPrevUser", true);
PCBcontext.getContext().startActivity(serialActivity);
}
Intent serialActivity = new Intent(PCBcontext.getContext(), SerialActivity.class);
serialActivity.putExtra("resetPrevUser", true);
PCBcontext.getContext().startActivity(serialActivity);
}
/**
*
* @return true if the user is logged offline and it has not been online previously. False in other case (user not logged, user logged online, user offline but it was previously online logged
* @return true if the user is logged offline and it has not been online previously. False in
* other case (user not logged, user logged online, user offline but it was previously online
* logged
*/
public static boolean is_user_offline() {
return pcbdb == null ? false //no hay usuario aun
: !getPcbdb().isUser_online();
if (pcbdb == null) {
return false;
} else {
return !getPcbdb().isUser_online();
}
}
public static boolean is_user_online() {
return pcbdb != null && getPcbdb().isUser_online();
}
// Return the context
// modified by Fernando
public static Context getContext(){ if (context==null) throw new java.lang.NullPointerException("Context is null. PCBcontext.init must be invoked previously"); return context; }
// Return the device
// modified by Fernando
public static Device getDevice(){ if (device==null) throw new java.lang.NullPointerException("Device is null. PCBcontext.init must be invoked previously");return device; }
// Return the PCBDB
// modified by Fernando
public static PCBDBHelper getPcbdb(){ if (context==null) throw new java.lang.NullPointerException("PCBDB is null. PCBcontext.set_user must be invoked previously");return pcbdb; }
/**
* @return context
* @TODO complete documentation
*/
public static Context getContext() {
if (context == null) {
throw new java.lang.NullPointerException("Context is null. PCBcontext.init must be" +
"invoked previously");
}
return context;
}
// Return the NetService
// modified by Fernando
public static NetService getNetService(){ if (service==null) throw new java.lang.NullPointerException("NetService is null. PCBcontext.set_user must be invoked previously"); return service; }
/**
* @return device
* @TODO complete documentation
*/
public static Device getDevice() {
if (device == null) {
throw new java.lang.NullPointerException("Device is null. PCBcontext.init must be" +
"invoked previously");
}
return device;
}
// Return the RestapiWrapper
// modified by Fernando
public static RestapiWrapper getRestapiWrapper(){ if (wrapper==null) throw new java.lang.NullPointerException("RestapiWrapper is null. PCBcontext.init must be invoked previously"); return wrapper; }
/**
* @return PCBDB
* @TODO complete documentation
*/
public static PCBDBHelper getPcbdb() {
if (context == null) {
throw new java.lang.NullPointerException("PCBDB is null. PCBcontext.set_user must be" +
"invoked previously");
}
return pcbdb;
}
// Return the Room
// modified by Fernando
public static Room getRoom(){ if (room==null) throw new java.lang.NullPointerException("Room is null. PCBcontext.set_user must be invoked previously"); return room; }
/**
* @return NetService
* @TODO complete documentation
*/
public static NetService getNetService(){
if (service == null) {
throw new java.lang.NullPointerException("NetService is null. PCBcontext.set_user" +
"must be invoked previously");
}
return service;
}
/**
* @return RestapiWrapper
* @TODO complete documentation
*/
public static RestapiWrapper getRestapiWrapper(){
if (wrapper == null) {
throw new java.lang.NullPointerException("RestapiWrapper is null. PCBcontext.init" +
"must be invoked previously");
}
return wrapper;
}
// Return the Vocabulary
// modified by Fernando
public static Vocabulary getVocabulary(){ if (vocabulary==null) throw new java.lang.NullPointerException("Vocabulary is null. PCBcontext.set_user must be invoked previously"); return vocabulary; }
/**
* @return Room
* @TODO complete documentation
*/
public static Room getRoom(){
if (room == null) {
throw new java.lang.NullPointerException("Room is null. PCBcontext.set_user must" +
"be invoked previously");
}
return room;
}
// Return the ActionLog
// modified by Fernando
public static ActionLog getActionLog(){ if (actionLog==null) throw new java.lang.NullPointerException("ActionLog is null. PCBcontext.set_user must be invoked previously"); return actionLog; }
/**
* @return Vocabulary
* @TODO complete documentation
*/
public static Vocabulary getVocabulary(){
if (vocabulary == null) {
throw new java.lang.NullPointerException("Vocabulary is null. PCBcontext.set_user" +
"must be invoked previously");
}
return vocabulary;
}
/**
* @return ActionLog
* @TODO complete documentation
*/
public static ActionLog getActionLog(){
if (actionLog == null) {
throw new java.lang.NullPointerException("ActionLog is null. PCBcontext.set_user" +
"must be invoked previously");
}
return actionLog;
}
}
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<stroke
android:width="7dp"
android:color="#de0707" />
<stroke android:width="@dimen/picto_border_width" android:color="@color/picto_border" />
<corners android:radius="2dp" />
</shape>
\ No newline at end of file
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal"
tools:context="com.yottacode.pictogram.gui.LoginActivity">
<TextView
android:layout_width="fill_parent"
android:layout_height="100px"
android:gravity="center"
android:id="@+id/logintitle"
android:text="@string/loginTitle"
android:textStyle="bold"
android:textColor="@color/material_blue_grey_800"
android:textSize="20px"
android:layout_alignParentTop="true"/>
<fragment
android:layout_width="fill_parent"
android:layout_height="400px"
class="com.yottacode.pictogram.gui.StudentFragmentGrid"
android:id="@+id/alumnos"
android:layout_below="@+id/logintitle"/>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_margin="8dp"
android:layout_marginLeft="16dp"
android:layout_marginTop="8dp"
android:layout_marginRight="16dp"
android:layout_marginBottom="0dp"
android:id="@+id/loginTopbarLayout">
<ImageView
android:layout_width="48dp"
android:layout_height="48dp"
android:id="@+id/loginTopbarSupervisorPhoto"
android:layout_gravity="left"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true"
android:background="@color/accent_material_dark"
android:scaleType="centerCrop" />
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:id="@+id/loginTopbarSupervisorNameLayout"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_centerVertical="true"
android:layout_toEndOf="@+id/loginTopbarSupervisorPhoto"
android:gravity="center_vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text=""
android:id="@+id/loginTopbarSupervisorFullName" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:text=""
android:id="@+id/loginTopbarSupervisorUserName"
android:textColor="@color/abc_secondary_text_material_light" />
</LinearLayout>
<Button
style="?android:attr/buttonStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/logout"
android:id="@+id/loginTopbarLogout"
android:layout_alignParentEnd="true"
android:layout_alignParentBottom="true"
android:layout_alignParentTop="true"
android:enabled="false" />
</RelativeLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@android:color/darker_gray"
android:layout_marginBottom="16dp"
android:id="@+id/view"
android:layout_below="@+id/loginTopbarLayout"
android:layout_marginTop="0dp" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="fill_parent"
android:layout_below="@+id/loginTopbarLayout">
<fragment
android:layout_width="wrap_content"
android:layout_height="wrap_content"
class="com.yottacode.pictogram.gui.StudentFragmentGrid"
android:id="@+id/loginStudentGrid"
android:layout_gravity="center"
tools:layout="@layout/fragment_new_student" />
</FrameLayout>
</RelativeLayout>
\ No newline at end of file
......@@ -2,61 +2,101 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:paddingTop="10dp"
android:orientation="horizontal"
android:background="#BDBDBD"
android:keepScreenOn="true"
android:id="@+id/pictogramLayout"
tools:context=".PictogramActivity">
tools:context=".PictogramActivity"
android:padding="@dimen/small_padding">
<!-- android:keepScreenOn - To keep the screen bright as long as the app is visible (also forever) -->
<GridView
android:id="@+id/tape_grid_view"
android:layout_width="850dp"
android:layout_height="85dp"
android:layout_width="wrap_content"
android:layout_height="@dimen/tape_normal_height"
android:padding="@dimen/small_padding"
android:gravity="center"
android:numColumns="@integer/columns"
android:numColumns="10"
android:accessibilityLiveRegion="none"
android:background="@android:color/holo_red_light"
android:clickable="false"
android:layout_alignParentTop="true">
android:layout_alignParentTop="true"
android:layout_alignParentStart="true"
android:layout_alignParentEnd="true"
android:paddingRight="192dp"
android:horizontalSpacing="@dimen/picto_grid_spacing">
</GridView>
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="850dp"
android:paddingTop="20dp"
android:src="@drawable/back64"
android:background="@null"
android:layout_width="@dimen/picto_normal_width"
android:layout_height="@dimen/tape_normal_height"
android:src="@drawable/remove_picto_from_tape"
android:id="@+id/button_delete"
android:layout_alignParentTop="true"/>
android:layout_alignParentTop="true"
android:layout_toLeftOf="@+id/button_tts"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:clickable="true"
android:background="@null" />
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="20dp"
android:paddingTop="20dp"
android:src="@drawable/play64"
android:layout_width="@dimen/picto_normal_width"
android:layout_height="@dimen/tape_normal_height"
android:src="@drawable/send_tape"
android:background="@null"
android:id="@+id/button_tts"
android:layout_toRightOf="@+id/tape_grid_view"
android:adjustViewBounds="true"
android:layout_alignParentTop="true"
android:adjustViewBounds="true"/>
android:layout_alignParentEnd="true"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:clickable="true" />
<ImageButton
android:layout_width="96dp"
android:layout_height="match_parent"
android:id="@+id/showPictoCategoriesViewButton"
android:layout_alignParentStart="true"
android:src="@drawable/show_categories_grid"
android:background="#EEEEEE"
android:layout_below="@+id/tape_grid_view"
android:scaleType="fitCenter" />
<GridView
android:id="@+id/picto_category_grid_view"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:layout_below="@+id/tape_grid_view"
android:layout_alignParentBottom="true"
android:numColumns="10"
android:gravity="center_vertical|center|center_horizontal"
android:background="#DDDDDD"
android:layout_alignParentEnd="true"
android:layout_toEndOf="@+id/showPictoCategoriesViewButton"
android:paddingLeft="@dimen/small_padding"
android:paddingTop="@dimen/small_padding"
android:paddingRight="@dimen/small_padding"
android:paddingBottom="@dimen/small_padding"
android:verticalSpacing="@dimen/picto_grid_spacing"
android:horizontalSpacing="@dimen/picto_grid_spacing">
</GridView>
<GridView
android:id="@+id/panel_grid_view"
android:id="@+id/picto_main_grid_view"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:paddingTop="20dp"
android:columnWidth="100dp"
android:verticalSpacing="1dp"
android:horizontalSpacing="15dp"
android:stretchMode="columnWidth"
android:layout_below="@+id/tape_grid_view">
android:layout_below="@+id/tape_grid_view"
android:layout_alignParentStart="true"
android:numColumns="10"
android:gravity="center_vertical|center|center_horizontal"
android:background="#DDDDDD"
android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true"
android:paddingLeft="@dimen/small_padding"
android:paddingTop="@dimen/small_padding"
android:horizontalSpacing="@dimen/picto_grid_spacing"
android:verticalSpacing="@dimen/picto_grid_spacing">
</GridView>
</RelativeLayout>
\ No newline at end of file
......@@ -49,7 +49,7 @@
android:layout_height="120px"
android:layout_marginLeft="30px"
android:orientation="horizontal"
android:src="@drawable/logo_pictogram"
android:src="@drawable/pictogram_logo"
android:layout_centerHorizontal="true"
android:id="@+id/imageView"
android:layout_toRightOf="@+id/serialmail"
......
......@@ -12,7 +12,7 @@
android:layout_height="120px"
android:contentDescription="@string/app_name"
android:orientation="vertical"
android:src="@drawable/logo"
android:src="@drawable/yottacode_logo"
android:scaleX="0.5"
android:scaleY="0.5"
android:id="@+id/imageView2"
......@@ -25,7 +25,7 @@
android:layout_height="120px"
android:contentDescription="@string/app_name"
android:orientation="vertical"
android:src="@drawable/logo_pictogram"
android:src="@drawable/pictogram_logo"
android:id="@+id/imageView"
android:scaleX="1.5"
android:scaleY="1.5"
......
<?xml version="1.0" encoding="utf-8"?>
<GridView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/gridview"
android:id="@+id/loginStudentGridView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="2dp"
android:numColumns="5"
android:verticalSpacing="1dp"
android:horizontalSpacing="5dp"
android:gravity="center"
android:layout_alignParentTop="true"
/>
android:layout_height="wrap_content"
android:numColumns="auto_fit"
android:gravity="center_vertical|center|center_horizontal"
android:stackFromBottom="false"
android:padding="32dp"
android:horizontalSpacing="16dp"
android:verticalSpacing="16dp" />
<?xml version="1.0" encoding="utf-8"?>
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/image_border"/>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center_vertical|center_horizontal">
<ImageView
android:id="@+id/img"
android:layout_width="140dp"
android:layout_height="140dp"
android:layout_alignParentTop="true"/>
android:id="@+id/loginStudentPhoto"
android:layout_width="128dp"
android:layout_height="128dp"
android:layout_centerHorizontal="true" />
<TextView
android:id="@+id/txt"
android:layout_width="140dp"
android:layout_height="140dp"
android:id="@+id/loginStudentName"
android:layout_width="128dp"
android:layout_height="wrap_content"
android:layout_below="@+id/loginStudentPhoto"
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_centerHorizontal="true"
android:layout_below="@+id/img"/>
android:paddingTop="8dp"
android:paddingBottom="8dp"
android:gravity="center" />
</RelativeLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical|center|center_horizontal"
android:id="@+id/picto_grid_item_layout_wrapper"
android:background="@drawable/picto_grid_item_border"
android:padding="@dimen/picto_border_width">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="@dimen/picto_normal_height"
android:id="@+id/picto_grid_item_layout"
android:background="@color/picto_default_background"
android:padding="@dimen/picto_padding">
<ImageView
android:id="@+id/picto_grid_item_image"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/picto_grid_item_redcross"
android:src="@drawable/disabled_picto" />
</FrameLayout>
</RelativeLayout>
\ No newline at end of file
......@@ -15,6 +15,7 @@
<string name="title_activity_login_activity_fragments">Users login</string>
<string name="title_activity_pictogram">PictogramActivity</string>
<string name="title_activity_splash_screen">SplashScreenActivity</string>
<string name="logout">Logout</string>
<string name="loginTitle">Who are you?</string>
<string name="LoginError">Login</string>
<string name="passErrorMsg">This password is not correct. Try again.</string>
......
......@@ -16,6 +16,7 @@
<string name="prompt_serial_mail">Usuario</string>
<string name="prompt_serial_pass">Contraseña</string>
<string name="action_entrar">Entrar</string>
<string name="logout">Cerrar sesión</string>
<string name="loginTitle">¿Quién eres?</string>
<string name="LoginError">Login</string>
<string name="passErrorMsg">La contraseña indicada no es correcta. Inténtelo de nuevo.</string>
......
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item name="picto_default_background" type="color">#CCFFFFFF</item>
<item name="picto_border" type="color">#AA000000</item>
<item name="blue" type="color">#FF33B5E5</item>
<item name="purple" type="color">#FFAA66CC</item>
<item name="green" type="color">#FF99CC00</item>
......
......@@ -2,4 +2,12 @@
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
<dimen name="small_padding">8dp</dimen>
<dimen name="picto_grid_spacing">4dp</dimen>
<dimen name="picto_border_width">1dp</dimen>
<dimen name="picto_padding">4dp</dimen>
<dimen name="picto_normal_height">80dp</dimen>
<dimen name="picto_normal_width">80dp</dimen>
<dimen name="tape_normal_height">100dp</dimen>
</resources>
......@@ -16,6 +16,7 @@
<string name="prompt_serial_mail">Usuario</string>
<string name="prompt_serial_pass">Contraseña</string>
<string name="action_entrar">Entrar</string>
<string name="logout">Cerrar sesión</string>
<string name="loginTitle">¿Quién eres?</string>
<string name="LoginError">Login</string>
<string name="passErrorMsg">La contraseña indicada no es correcta. Inténtelo de nuevo.</string>
......
{
"hooks": {
"grunt": false
}
}
# Servidor de Pictogram e instalación del cliente web
En este directorio se encuentra el servidor web ([src](./src)) y la aplicación
web ([src/assets/app](./src/assets/app)). Los distintos ficheros de configuración
utilizados para la inicialización y el testeo de la aplicación se encuentran
en el directorio [conf](./conf).
## Instalación del servidor y el cliente web
## Dependencias
Las distintas configuraciones aplicadas a la instalación pueden leerse en los `roles`
de [ansible][9] creados para ello, pero **no es necesario ejecutarlas a mano**, las opciones
mostradas más adelante hacen todo el trabajo.
- Ubuntu >= 14.04
- Nodejs >= 0.10.37
- Npm >= 3.8.5
- Bower >= 1.4.1
- [Instalación de NodeJS][4]
- [Instalación de MYSQL][5]
- [Importación de la base de datos][6]
- [Dependencias del cliente web][7]
- [Dependencias y ejecución del servidor][8]
## Instalación del servidor y el cliente web
### Opción A (producción): ejecución en la máquina local
1. Descargar upload.zip y symbolstx.zip desde el servidor de Yottacode:
- Ejecutar el script [install.sh](./install.sh) para instalar todas las
dependencias del servidor y el cliente web.
- Acceder al directorio [conf](./conf) para la instalación de la base de datos.
```
scp ec2-user@pre.yottacode.com:~/upload.zip .
scp ec2-user@pre.yottacode.com:~/symbolstx.zip .
unzip upload.zip
unzip symbolstx.zip
rm upload.zip
rm symbolstx.zip
```
2. Cambiar la contraseña de root de mysql a root: `mysqladmin -u root password root`. Este paso
es necesario para la creación de la base de datos `pictodb` y el usuario `pictodbuser`.
3. Ejecutar [./install.sh][3].
4. Restaurar la contraseña de root de mysql: `mysqladmin -u root password [OLD_PASSWORD]`
5. Ejecutar [./bootstrap.sh][19] para lanzar el servidor.
6. Configurar los ficheros `/sails/src/config/local.js` y `/sails/src/assets/scripts/config.js`
generados si fuera necesario (estos ficheros no se encuentran en el repositorio, son generados
por ansible a partir de una plantilla).
7. Generar los [certificados ssl][21] si fuera necesario.
> **Importante**: el script utilizado creará un entorno para el servidor desde
> cero, por lo que **pueden perderse los datos** almacenados por usuarios.
### Opción B (desarrollo): ejecución en una máquina virtual generada automáticamente
## Desarrollo y pruebas
1. Descargar upload.zip y symbolstx.zip desde el servidor de Yottacode:
```
scp ec2-user@pre.yottacode.com:~/upload.zip .
scp ec2-user@pre.yottacode.com:~/symbolstx.zip .
unzip upload.zip
unzip symbolstx.zip
rm upload.zip
rm symbolstx.zip
```
2. Instalar [virtualbox][1] y [vagrant][2] (version >1.5 para este último).
3. Ejecutar `vagrant up` desde este directorio.
4. Configurar los ficheros `/sails/src/config/local.js` y `/sails/src/assets/scripts/config.js`
generados si fuera necesario (estos ficheros no se encuentran en el repositorio, son generados
por ansible a partir de una plantilla).
5. Generar los [certificados ssl][21] si fuera necesario.
Para ejecutar el servidor como desarrollo se debe acceder al directorio
[conf](./conf) e instalar los datos de la base de datos necesarios.
> **Importante**: el script utilizado creará un entorno para el servidor desde cero, por lo que
> **pueden perderse los datos** almacenados por usuarios.
## Ejecución
Para lanzar el servidor hay que acceder al directorio [src](./src) y ejecutar
uno de esos comandos:
Una vez lanzado sails con el servidor comienza con la compilación de la aplicación web mediante
tareas de Grunt, para esta configuración existe, por un lado, un fichero [Gruntfile.js][11] que
se encarga de cargar las tareas establecidas y ejecutar la especificada (`default` si no se
especifica nada). Por otro lado están las tareas establecidas dentro del directorio [tasks][12],
que a su vez se divide en [config][13] y [register][14]. La primera de ellas contiene parámetros
de configuración, la segunda la propia ejecución de las tareas.
- `sails lift`: para un servidor corriente
- `sails console`: para un servidor con un intérprete de nodejs con las
variables de sails expuestas
**Este proceso se realiza automáticamente, sólo hay que lanzar el el servidor con uno de los
siguientes comandos**:
- `sails lift`: tarea [default][15]
- `sails lift --prod`: tarea [prod][16]
- `sails www`: tarea [build][17]
- `sails www --prod`: tarea [buildProd][18]
> La opción `--prod` indica que sails se ejecutará en modo producción
>
> El servidor se ejecutará en [localhost:1337/app](http://localhost:1337/app)
[1]: https://www.virtualbox.org/
[2]: https://www.vagrantup.com/
[3]: /softuno/pictogram/blob/develop/sails/install.sh
[4]: /softuno/pictogram/blob/develop/sails/roles/nodejs/README.md
[5]: /softuno/pictogram/blob/develop/sails/roles/mysql/README.md
[6]: /softuno/pictogram/blob/develop/sails/roles/database/README.md
[7]: /softuno/pictogram/blob/develop/sails/roles/webapp/README.md
[8]: /softuno/pictogram/blob/develop/sails/roles/server/README.md
[9]: https://www.ansible.com/
[10]: /softuno/pictogram/blob/develop/sails/src/README.md
[11]: /softuno/pictogram/blob/develop/sails/src/Gruntfile.js
[12]: /softuno/pictogram/tree/develop/sails/src/tasks
[13]: /softuno/pictogram/tree/develop/sails/src/tasks/config
[14]: /softuno/pictogram/tree/develop/sails/src/tasks/register
[15]: /softuno/pictogram/blob/develop/sails/src/tasks/register/default.js
[16]: /softuno/pictogram/blob/develop/sails/src/tasks/register/prod.js
[17]: /softuno/pictogram/blob/develop/sails/src/tasks/register/build.js
[18]: /softuno/pictogram/blob/develop/sails/src/tasks/register/buildProd.js
[19]: /softuno/pictogram/blob/develop/sails/bootstrap.sh
[20]: https://localhost:1337/app
[21]: /softuno/pictogram/tree/develop/sails/src/config/ssl
\ No newline at end of file
# -*- mode: ruby -*-
# vi: set ft=ruby :
Vagrant.configure(2) do |config|
# "ubuntu/trusty64" for ubuntu environment
# "boxcutter/centos71" for AWS similar environment
config.vm.box = "boxcutter/centos71"
config.vm.network "forwarded_port", guest: 1337, host: 1337
config.vm.network "forwarded_port", guest: 80, host: 8080
config.vm.provider "virtualbox" do |vb|
vb.memory = 1024
end
config.vm.provision "shell", path: "install.sh"
config.vm.provision "shell", path: "bootstrap.sh", run: "always"
end
#!/bin/bash
echo "-- Running pictogram server"
if [ -e "src/app.js" ]; then
cd src && npm start
elif [ -e "/vagrant/src/app.js" ]; then
cd /vagrant/src && npm start
elif [ -e "/home/vagrant/sync/src/app.js" ]; then
cd /home/vagrant/sync/src && npm start
else
echo "-- app.js not found, cannot run pictogram server"
exit
fi
# Configuración de la base de datos
## Scripts
- [installdb.sh](./installdb.sh) elimina la base de datos existente y realiza
una instalación limpia para producción.
- [installdb-tests.sh](./installdb-test.sh) realiza el mismo proceso
que [installdb.sh](./installdb.sh) pero añadiendo los datos de tests.
- [installdb-autismojaen.sh](./installdb-autismojaen.sh) realiza el mismo
proceso que [installdb.sh](./installdb.sh), pero añadiendo los datos de
autismojaen.
> **Importante**: para no añadir la biblioteca de symbolstix de nuevo
> y conservarla en el caso de que ya esté en la base de datos se puede
> añadir la opción `--ignore-symbolstix` a todos los scripts (por ejemplo
> `installdb.sh --ignore-symbolstix` no importará estos datos).
## Orden de la importación
### Datos necesarios
- [init.sql](./pictodb-init.sql) inicializa el usuario y permisos de la base de
datos.
- _[init-ignoresymbolstix.sql](./sql/init-ignoresymbolstix.sql) realiza el mismo
proceso que [init.sql](./sql/init.sql), pero ignorando a symbolstix._
- [pictodb-schema.sql](./sql/pictodb-schema.sql) contiene el esquema de la base de
datos.
- _[symbolstix-categories.sql](./sql/symbolstix-categories.sql) añade las
categorías de symbolstix._
- _[symbolstix-metadata.sql](./sql/symbolstix-metadata.sql) añade los
metadatos de symbolstix._
- [pictodb-data.sql](./sql/pictodb-data.sql) contiene la información básica que
la aplicación necesita para funcionar.
- [triggers-enrolments-integrity-constraints.sql](./pictodb-triggers-enrolments-integrity-constraints.sql)
añade disparadores para el control de integridad de inscripciones.
- [triggers-sessions-integrity-constraints.sql](./pictodb-triggers-enrolments-integrity-constraints.sql)
añade disparadores para el control de integridad de sesiones.
### Añadido de datos de desarrollo y pruebas
- [test.sql](./sql/test-autismojaen.sql) contiene datos para el desarrollo y
pruebas de la aplicación.
- [test-autismojaen.sql](./sql/test-autismojaen.sql) añade los datos de
autismojaen.
## Notes
### Importación de datos
To import `pictodb-data.sql` into MySQL without foreign key constraints, ensure
that the imported file starts with `SET foreign_key_checks=0;` and then you turn
on it again with `SET foreign_key_checks=1;`
### Eliminando la base de datos completa
```sql
SET foreign_key_checks=0;
DROP TABLE `action`, `device`, `enrolment`, `instruction`, `license`,
`license_activation`, `meta_picto`, `meta_stu`, `method`, `office`,
`official_dev`, `picto`, `picto_acl`, `picto_core`, `picto_core_cat`,
`picto_exp`, `picto_tag`, `picto_tag_sup`, `source`, `student`, `stu_picto`,
`stu_sup`, `stu_sup_dev`, `supervisor`, `try`, `working_session`;
SET foreign_key_checks=1;
```
#!/bin/bash
ROOT_PASSWD=passwd
IGNORE_SYMBOLSTIX=false
USAGE="Usage: ${0##*/} <mysql root pwd> [--ignore-symbolstix]"
DBUSER=pictodbuser
DBNAME=pictodb
function do_exit {
echo $USAGE
exit 1
}
function execute_db {
echo $1
mysql -u $DBUSER -pp1KT015 $DBNAME < $1
}
function main {
if [ $# -eq 0 ]; then do_exit; fi
if [ $# -gt 2 ]; then do_exit; fi
if [ $# -eq 1 ]; then ROOT_PASSWD=$1; fi
if [ $# -eq 2 ]; then
if [ $2 != '--ignore-symbolstix' ]; then do_exit; fi
ROOT_PASSWD=$1
IGNORE_SYMBOLSTIX=true
fi
if [ $IGNORE_SYMBOLSTIX == true ]; then
echo Init ignoring symbolstix
mysql -u root -p$ROOT_PASSWD < ./sql/init-ignoresymbolstix.sql
else
echo Init with symbolstix
mysql -u root -p$ROOT_PASSWD < ./sql/init.sql
fi
execute_db ./sql/pictodb-schema.sql
if [ $IGNORE_SYMBOLSTIX == false ]; then
execute_db ./sql/symbolstix-categories.sql
execute_db ./sql/symbolstix-metadata.sql
fi
execute_db ./sql/pictodb-data.sql
execute_db ./sql/test-autismojaen.sql
execute_db ./sql/triggers-enrolments-integrity-constraints.sql
execute_db ./sql/triggers-sessions-integrity-constraints.sql
}
main "$@"
#!/bin/bash
ROOT_PASSWD=passwdd
IGNORE_SYMBOLSTIX=false
USAGE="Usage: ${0##*/} <mysql root pwd> [--ignore-symbolstix]"
DBUSER=pictodbuser
DBNAME=pictodb
function do_exit {
echo $USAGE
exit 1
}
function execute_db {
echo $1
mysql -u $DBUSER -pp1KT015 $DBNAME < $1
}
function main {
if [ $# -eq 0 ]; then do_exit; fi
if [ $# -gt 2 ]; then do_exit; fi
if [ $# -eq 1 ]; then ROOT_PASSWD=$1; fi
if [ $# -eq 2 ]; then
if [ $2 != '--ignore-symbolstix' ]; then do_exit; fi
ROOT_PASSWD=$1
IGNORE_SYMBOLSTIX=true
fi
if [ $IGNORE_SYMBOLSTIX == true ]; then
echo Init ignoring symbolstix
mysql -u root -p$ROOT_PASSWD < ./sql/init-ignoresymbolstix.sql
else
echo Init with symbolstix
mysql -u root -p$ROOT_PASSWD < ./sql/init.sql
fi
execute_db ./sql/pictodb-schema.sql
if [ $IGNORE_SYMBOLSTIX == false ]; then
execute_db ./sql/symbolstix-categories.sql
execute_db ./sql/symbolstix-metadata.sql
fi
execute_db ./sql/pictodb-data.sql
execute_db ./sql/test.sql
execute_db ./sql/triggers-enrolments-integrity-constraints.sql
execute_db ./sql/triggers-sessions-integrity-constraints.sql
}
main "$@"
#!/bin/bash
ROOT_PASSWD=passwd
IGNORE_SYMBOLSTIX=false
USAGE="Usage: ${0##*/} <mysql root pwd> [--ignore-symbolstix]"
DBUSER=pictodbuser
DBNAME=pictodb
function do_exit {
echo $USAGE
exit 1
}
function execute_db {
echo $1
mysql -u $DBUSER -pp1KT015 $DBNAME < $1
}
function main {
if [ $# -eq 0 ]; then do_exit; fi
if [ $# -gt 2 ]; then do_exit; fi
if [ $# -eq 1 ]; then ROOT_PASSWD=$1; fi
if [ $# -eq 2 ]; then
if [ $2 != '--ignore-symbolstix' ]; then do_exit; fi
ROOT_PASSWD=$1
IGNORE_SYMBOLSTIX=true
fi
if [ $IGNORE_SYMBOLSTIX == true ]; then
echo Init ignoring symbolstix
mysql -u root -p$ROOT_PASSWD < ./sql/init-ignoresymbolstix.sql
else
echo Init with symbolstix
mysql -u root -p$ROOT_PASSWD < ./sql/init.sql
fi
execute_db ./sql/pictodb-schema.sql
if [ $IGNORE_SYMBOLSTIX == false ]; then
execute_db ./sql/symbolstix-categories.sql
execute_db ./sql/symbolstix-metadata.sql
fi
execute_db ./sql/pictodb-data.sql
execute_db ./sql/triggers-enrolments-integrity-constraints.sql
execute_db ./sql/triggers-sessions-integrity-constraints.sql
}
main "$@"
/// template file for sails/src/assets/app/js/config.js
'use strict';
/* Configuration constants */
angular.module('dashboardConfig', [])
.constant('config', {
'backend': 'https://sinai-fernando.ujaen.es:9944'
// 'backend': 'http://localhost:1337',
// 'backend': 'https://dev.yottacode.com',
// // 'backend': 'https://test.yottacode.com',
// // 'backend_ws': 'ws://localhost:1337',
// 'version': 0.1
});
//// template file for sails/src/config/local.js
/**
* Local environment settings
*
* Use this file to specify configuration settings for use while developing
* the app on your personal system: for example, this would be a good place
* to store database or email passwords that apply only to you, and shouldn't
* be shared with others in your organization.
*
* These settings take precedence over all other config files, including those
* in the env/ subfolder.
*
* PLEASE NOTE:
* local.js is included in your .gitignore, so if you're using git
* as a version control solution for your Sails app, keep in mind that
* this file won't be committed to your repository!
*
* Good news is, that means you can specify configuration for your local
* machine in this file without inadvertently committing personal information
* (like database passwords) to the repo. Plus, this prevents other members
* of your team from commiting their local configuration changes on top of yours.
*
* In a production environment, you probably want to leave this file out
* entirely and leave all your settings in env/production.js
*
*
* For more information, check out:
* http://sailsjs.org/#!/documentation/anatomy/myApp/config/local.js.html
*/
module.exports = {
/***************************************************************************
* Your SSL certificate and key, if you want to be able to serve HTTP *
* responses over https:// and/or use websockets over the wss:// protocol *
* (recommended for HTTP, strongly encouraged for WebSockets) *
* *
* In this example, we'll assume you created a folder in your project, *
* `config/ssl` and dumped your certificate/key files there: *
***************************************************************************/
ssl: {
ca: require('fs').readFileSync(__dirname + '/ssl/goddady/gd.yottacode.com.bundle.crt'),
key: require('fs').readFileSync(__dirname + '/ssl/goddady/gd.yottacode.com.key'),
cert: require('fs').readFileSync(__dirname + '/ssl/goddady/gd.yottacode.com.crt')
},
/***************************************************************************
* The `port` setting determines which TCP port your app will be *
* deployed on. *
* *
* Ports are a transport-layer concept designed to allow many different *
* networking applications run at the same time on a single computer. *
* More about ports: *
* http://en.wikipedia.org/wiki/Port_(computer_networking) *
* *
* By default, if it's set, Sails uses the `PORT` environment variable. *
* Otherwise it falls back to port 1337. *
* *
* In env/production.js, you'll probably want to change this setting *
* to 80 (http://) or 443 (https://) if you have an SSL certificate *
***************************************************************************/
port: process.env.PORT || 1337,
/***************************************************************************
* The runtime "environment" of your Sails app is either typically *
* 'development' or 'production'. *
* *
* In development, your Sails app will go out of its way to help you *
* (for instance you will receive more descriptive error and *
* debugging output) *
* *
* In production, Sails configures itself (and its dependencies) to *
* optimize performance. You should always put your app in production mode *
* before you deploy it to a server. This helps ensure that your Sails *
* app remains stable, performant, and scalable. *
* *
* By default, Sails sets its environment using the `NODE_ENV` environment *
* variable. If NODE_ENV is not set, Sails will run in the *
* 'development' environment. *
***************************************************************************/
// environment: process.env.NODE_ENV || 'development'
};

87.8 KB | W: | H:

87.8 KB | W: | H:

sails/doc/EC.png
sails/doc/assets/database-er-diagram.png
sails/doc/EC.png
sails/doc/assets/database-er-diagram.png
  • 2-up
  • Swipe
  • Onion skin
This diff could not be displayed because it is too large.

9.04 KB | W: | H:

4.5 KB | W: | H:

sails/src/assets/app/img/logo_pictogram.png
sails/src/assets/app/img/logo_pictogram.png
sails/src/assets/app/img/logo_pictogram.png
sails/src/assets/app/img/logo_pictogram.png
  • 2-up
  • Swipe
  • Onion skin
This diff could not be displayed because it is too large.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment