Commit 55c1e583 by Pablo Molina

Solved #428, uso del panel libre en la aplicación android

- Actualizado soporte de android para la nueva API
- Actualizado /supervisor/id/students en la API
- Actualizados atributos de StuPicto y Student
- Actualizado manejo de expresiones de un picto nuevo en la web
- Actualizada la carga de pictos en android
- Refactorizado el código de android para el uso del panel libre
- Arreglados problemas en los tests originados por los cambios en la API
- Actualizado valor devuelto por StudentController.update
parent 5f0948b6
......@@ -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(){
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() {
......
......@@ -4,7 +4,6 @@ import android.app.Activity;
import android.app.AlertDialog;
import android.database.Cursor;
import android.graphics.Color;
import android.content.ClipData;
import android.content.ClipDescription;
......@@ -27,7 +26,6 @@ import android.view.ViewGroup;
import android.view.Window;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.Interpolator;
import android.view.animation.TranslateAnimation;
import android.widget.AdapterView;
import android.widget.CheckBox;
......@@ -62,13 +60,13 @@ public class PictogramActivity extends Activity implements iVocabularyListener,
// Main layout for this activity
RelativeLayout mainLayout;
// Adapter for de grid showing the categories grid (and main pictos)
PictoGridAdapter pictoCategoriesGridAdapter;
PictoGridAdapter pictoMainGridAdapter;
// Grid showing the categories grid (and main pictos)
GridView pictoCategoriesGridView;
GridView pictoMainGridView;
// Adapter for the grid showing pictos from a category (initially hidden)
PictoGridAdapter pictoGridAdapter;
PictoGridAdapter pictoCategoryGridAdapter;
// Grid showing pictos from a category (initially hidden)
GridView pictoGridView;
GridView pictoCategoryGridView;
// Adapter for the tape view (list of pictos to send to the server)
TapeAdapter tapeAdapter;
// Tape view (list of pictos to send to the server)
......@@ -88,9 +86,9 @@ public class PictogramActivity extends Activity implements iVocabularyListener,
// Count for delete long press (hidden exit)
private int count_deletelong = 0;
// Animation for hidding the picto category view
Animation hidePictoCategoryViewAnimation;
Animation hidePictoMainViewAnimation;
// Animation for showing the picto category view
Animation showPictoCategoryViewAnimation;
Animation showPictoMainViewAnimation;
// Button used for showing the picto category view
ImageButton showPictoCategoriesViewButton;
......@@ -116,22 +114,22 @@ public class PictogramActivity extends Activity implements iVocabularyListener,
this.tapeGridView = (GridView) this.findViewById(R.id.tape_grid_view);
this.tapeGridView.setAdapter(this.tapeAdapter);
this.pictoCategoriesGridAdapter = new PictoGridAdapter(new LinkedList<Picto>());
this.pictoCategoriesGridView = (GridView) this.findViewById(R.id.picto_categories_grid_view);
this.pictoCategoriesGridView.setAdapter(this.pictoCategoriesGridAdapter);
this.pictoMainGridAdapter = new PictoGridAdapter(new LinkedList<Picto>());
this.pictoMainGridView = (GridView) this.findViewById(R.id.picto_main_grid_view);
this.pictoMainGridView.setAdapter(this.pictoMainGridAdapter);
this.pictoGridAdapter = new PictoGridAdapter(new LinkedList<Picto>());
this.pictoGridView = (GridView) this.findViewById(R.id.picto_grid_view);
this.pictoGridView.setAdapter(this.pictoGridAdapter);
this.pictoCategoryGridAdapter = new PictoGridAdapter(new LinkedList<Picto>());
this.pictoCategoryGridView = (GridView) this.findViewById(R.id.picto_category_grid_view);
this.pictoCategoryGridView.setAdapter(this.pictoCategoryGridAdapter);
// @TODO take this value from user configuration (0: normal, 1: large)
int pictogramSize = 0;
if (pictogramSize == 0) {
this.pictoCategoriesGridView.setNumColumns(10);
this.pictoGridView.setNumColumns(10);
this.pictoMainGridView.setNumColumns(10);
this.pictoCategoryGridView.setNumColumns(10);
} else if (pictogramSize == 1) {
this.pictoCategoriesGridView.setNumColumns(4);
this.pictoGridView.setNumColumns(4);
this.pictoMainGridView.setNumColumns(4);
this.pictoCategoryGridView.setNumColumns(4);
}
// tts = new TextToSpeech(this, this, "IVONA Text-to-Speech HQ");
......@@ -139,14 +137,14 @@ public class PictogramActivity extends Activity implements iVocabularyListener,
tts.setOnUtteranceProgressListener(new OnTTSEndListener());
this.tapeGridView.setOnDragListener(new OnPictoDragListener());
this.pictoCategoriesGridView.setOnDragListener(new OnPictoDragListener());
this.pictoGridView.setOnDragListener(new OnPictoDragListener());
this.pictoMainGridView.setOnDragListener(new OnPictoDragListener());
this.pictoCategoryGridView.setOnDragListener(new OnPictoDragListener());
this.pictoCategoriesGridView.setOnItemClickListener(new OnPictoClickListener());
this.pictoGridView.setOnItemClickListener(new OnPictoClickListener());
this.pictoMainGridView.setOnItemClickListener(new OnPictoClickListener());
this.pictoCategoryGridView.setOnItemClickListener(new OnPictoClickListener());
this.pictoCategoriesGridView.setOnItemLongClickListener(new OnPictoLongClickListener());
this.pictoGridView.setOnItemLongClickListener(new OnPictoLongClickListener());
this.pictoMainGridView.setOnItemLongClickListener(new OnPictoLongClickListener());
this.pictoCategoryGridView.setOnItemLongClickListener(new OnPictoLongClickListener());
final ImageButton deleteButton = (ImageButton) findViewById(R.id.button_delete);
final ImageButton ttsButton = (ImageButton) findViewById(R.id.button_tts);
......@@ -159,9 +157,9 @@ public class PictogramActivity extends Activity implements iVocabularyListener,
this.generateAnimations();
if (this.currentCategory != null) {
this.hidePictoCategoriesGridView();
this.hidePictoMainGridView();
} else {
this.showPictoCategoriesGridView();
this.showPictoMainGridView();
}
}
......@@ -189,33 +187,33 @@ public class PictogramActivity extends Activity implements iVocabularyListener,
int animationDuration = 400;
int animationWidth = displayMetrics.widthPixels;
this.hidePictoCategoryViewAnimation = new TranslateAnimation(0, -animationWidth, 0, 0);
this.hidePictoCategoryViewAnimation.setDuration(animationDuration);
this.hidePictoCategoryViewAnimation.setFillAfter(true);
this.hidePictoCategoryViewAnimation.setInterpolator(new AccelerateDecelerateInterpolator());
this.hidePictoCategoryViewAnimation.setAnimationListener(new Animation.AnimationListener() {
this.hidePictoMainViewAnimation = new TranslateAnimation(0, -animationWidth, 0, 0);
this.hidePictoMainViewAnimation.setDuration(animationDuration);
this.hidePictoMainViewAnimation.setFillAfter(true);
this.hidePictoMainViewAnimation.setInterpolator(new AccelerateDecelerateInterpolator());
this.hidePictoMainViewAnimation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {}
@Override
public void onAnimationEnd(Animation animation) {
pictoCategoriesGridView.setTranslationZ(-1000.0f);
pictoCategoriesGridView.setVisibility(View.GONE);
pictoMainGridView.setTranslationZ(-1000.0f);
pictoMainGridView.setVisibility(View.GONE);
}
@Override
public void onAnimationRepeat(Animation animation) {}
});
this.showPictoCategoryViewAnimation = new TranslateAnimation(-animationWidth, 0, 0, 0);
this.showPictoCategoryViewAnimation.setDuration(animationDuration);
this.showPictoCategoryViewAnimation.setFillAfter(true);
this.showPictoCategoryViewAnimation.setInterpolator(new AccelerateDecelerateInterpolator());
this.showPictoCategoryViewAnimation.setAnimationListener(new Animation.AnimationListener() {
this.showPictoMainViewAnimation = new TranslateAnimation(-animationWidth, 0, 0, 0);
this.showPictoMainViewAnimation.setDuration(animationDuration);
this.showPictoMainViewAnimation.setFillAfter(true);
this.showPictoMainViewAnimation.setInterpolator(new AccelerateDecelerateInterpolator());
this.showPictoMainViewAnimation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
pictoCategoriesGridView.setTranslationZ(1000.0f);
pictoCategoriesGridView.setVisibility(View.VISIBLE);
pictoMainGridView.setTranslationZ(1000.0f);
pictoMainGridView.setVisibility(View.VISIBLE);
}
@Override
......@@ -230,18 +228,18 @@ public class PictogramActivity extends Activity implements iVocabularyListener,
* Show the main category grid view and hide the pictoGrid, unloading all pictos
* if necesary.
*/
private void showPictoCategoriesGridView() {
Log.d(LOG_TAG, "Showing pictoCategoriesGridView");
private void showPictoMainGridView() {
Log.d(LOG_TAG, "Showing pictoMainGridView");
this.pictoCategoriesGridAdapter.clear();
this.pictoCategoriesGridAdapter.addAll(this.sort(this.vocabulary.startSentence()));
this.pictoCategoriesGridAdapter.notifyDataSetChanged();
this.pictoMainGridAdapter.clear();
this.pictoMainGridAdapter.addAll(this.sort(this.vocabulary.startSentence()));
this.pictoMainGridAdapter.notifyDataSetChanged();
this.pictoCategoriesGridView.setEnabled(true);
this.pictoGridView.setEnabled(false);
this.pictoMainGridView.setEnabled(true);
this.pictoCategoryGridView.setEnabled(false);
if (this.pictoCategoriesGridView.getAnimation() == this.hidePictoCategoryViewAnimation) {
this.pictoCategoriesGridView.startAnimation(this.showPictoCategoryViewAnimation);
if (this.pictoMainGridView.getAnimation() == this.hidePictoMainViewAnimation) {
this.pictoMainGridView.startAnimation(this.showPictoMainViewAnimation);
}
this.currentCategory = null;
......@@ -250,30 +248,30 @@ public class PictogramActivity extends Activity implements iVocabularyListener,
/**
* Hides the main category grid view and show a concrete category (this.currentCategory)
*/
private void hidePictoCategoriesGridView() {
Log.d(LOG_TAG, "Hiding pictoCategoriesGridView");
private void hidePictoMainGridView() {
Log.d(LOG_TAG, "Hiding pictoMainGridView");
this.pictoGridAdapter.clear();
this.pictoGridAdapter.addAll(this.sort(this.vocabulary.next(this.currentCategory)));
this.pictoGridAdapter.notifyDataSetChanged();
this.pictoCategoryGridAdapter.clear();
this.pictoCategoryGridAdapter.addAll(this.sort(this.vocabulary.next(this.currentCategory)));
this.pictoCategoryGridAdapter.notifyDataSetChanged();
if (this.currentCategory.get_color() != -1) {
this.pictoGridView.setBackgroundColor(this.currentCategory.get_color());
this.pictoCategoryGridView.setBackgroundColor(this.currentCategory.get_color());
}
this.pictoCategoriesGridView.setEnabled(false);
this.pictoGridView.setEnabled(true);
this.pictoMainGridView.setEnabled(false);
this.pictoCategoryGridView.setEnabled(true);
if (this.pictoCategoriesGridView.getAnimation() != this.hidePictoCategoryViewAnimation) {
this.pictoCategoriesGridView.startAnimation(this.hidePictoCategoryViewAnimation);
if (this.pictoMainGridView.getAnimation() != this.hidePictoMainViewAnimation) {
this.pictoMainGridView.startAnimation(this.hidePictoMainViewAnimation);
}
}
/**
* Returns pictoGridAdapter or pictoCategoriesGridAdapter depending on the current View
* Returns pictoCategoryGridAdapter or pictoMainGridAdapter depending on the current View
*/
private PictoGridAdapter getCurrentPictoGridAdapter() {
return (currentCategory == null) ? this.pictoCategoriesGridAdapter : this.pictoGridAdapter;
return (currentCategory == null) ? this.pictoMainGridAdapter : this.pictoCategoryGridAdapter;
}
/**
......@@ -282,6 +280,9 @@ public class PictogramActivity extends Activity implements iVocabularyListener,
* @return
*/
public LinkedList<Picto> sort(LinkedList<Picto> list){
if (list == null) {
list = new LinkedList<>();
}
LinkedList<Picto> ll = new LinkedList<>();
......@@ -291,8 +292,17 @@ public class PictogramActivity extends Activity implements iVocabularyListener,
int cols = getResources().getInteger(R.integer.columns);
Picto[][] mp = new Picto[rows][cols];
for(Picto p : list)
for (Picto p : list) {
if (PCBcontext.getPcbdb().getCurrentUser().has_categories()) {
if (p.get_column() != -1 && p.get_row() != -1) {
mp[p.get_column()][p.get_row()] = p;
}
} else {
if (p.getFreeColumn() != -1 && p.getFreeRow() != -1) {
mp[p.getFreeColumn()][p.getFreeRow()] = p;
}
}
}
try {
/*
......@@ -325,9 +335,9 @@ public class PictogramActivity extends Activity implements iVocabularyListener,
@Override
public void run() {
if (currentCategory != null) {
hidePictoCategoriesGridView();
hidePictoMainGridView();
} else {
showPictoCategoriesGridView();
showPictoMainGridView();
}
}
});
......@@ -502,20 +512,20 @@ public class PictogramActivity extends Activity implements iVocabularyListener,
// if the view is the tape_grid_view, we accept the drag item
// Destino tape_grid_view y origen panel_grid_view
if(v == findViewById(R.id.tape_grid_view) && viewgroup == findViewById(R.id.picto_grid_view)) {
if(v == findViewById(R.id.tape_grid_view) && viewgroup == findViewById(R.id.picto_category_grid_view)) {
Log.d("Drag:", "Posición: " + position);
Picto p = pictoGridAdapter.getItem(position);
Picto p = pictoCategoryGridAdapter.getItem(position);
if(!p.is_category()) {
currentCategory = null;
tapeAdapter.addItem(p);
tapeAdapter.notifyDataSetChanged();
showPictoCategoriesGridView();
showPictoMainGridView();
PCBcontext.getActionLog().log(new TalkAction(TalkAction.ADD, p));
}
}
// Si el destino es el panel y el origen la cinta de frase
else if(v == findViewById(R.id.picto_grid_view) && viewgroup == findViewById(R.id.tape_grid_view)){
else if(v == findViewById(R.id.picto_category_grid_view) && viewgroup == findViewById(R.id.tape_grid_view)){
Log.d("Drag:", "Posición: " + position);
Picto p = tapeAdapter.getItem(position);
tapeAdapter.deleteItem(position);
......@@ -548,7 +558,7 @@ public class PictogramActivity extends Activity implements iVocabularyListener,
Log.d(LOG_TAG, "Clic en picto: " + p.toString());
//Log.d(LOG_TAG, "STATUS: " + p.get_status());
//QUITAR PARA QUE HABLE pictoGridAdapter.ttsPicto(p, tts);
//QUITAR PARA QUE HABLE pictoCategoryGridAdapter.ttsPicto(p, tts);
// If is not the blank picto, it isn't invisible or disabled
if (p.get_id() != 0 &&
......@@ -565,14 +575,14 @@ public class PictogramActivity extends Activity implements iVocabularyListener,
if (p.is_category()) {
currentCategory = p;
PCBcontext.getActionLog().log(new TalkAction(TalkAction.SELECT, p));
hidePictoCategoriesGridView();
hidePictoMainGridView();
} else if (tapeAdapter.getCount() < maxInTape) {
currentCategory = null;
tapeAdapter.addItem(p);
tapeAdapter.notifyDataSetChanged();
PCBcontext.getActionLog().log(new TalkAction(TalkAction.ADD, p));
showPictoCategoriesGridView();
showPictoMainGridView();
}
}
}
......@@ -598,7 +608,7 @@ public class PictogramActivity extends Activity implements iVocabularyListener,
} else {
p.alter_status();
showPictoCategoriesGridView();
showPictoMainGridView();
}
} else {
ClipData.Item item = new ClipData.Item("" + position);
......@@ -667,7 +677,7 @@ public class PictogramActivity extends Activity implements iVocabularyListener,
public void run() {
tapeAdapter.deleteAll();
tapeAdapter.notifyDataSetChanged();
showPictoCategoriesGridView();
showPictoMainGridView();
}
});
}
......@@ -719,7 +729,7 @@ public class PictogramActivity extends Activity implements iVocabularyListener,
private class OnShowPictoCategoriesViewButtonClick implements View.OnClickListener {
@Override
public void onClick(View v) {
showPictoCategoriesGridView();
showPictoMainGridView();
}
}
......@@ -746,7 +756,7 @@ public class PictogramActivity extends Activity implements iVocabularyListener,
/**
* función para la edición de un texto asociado a una nueva imagen y guardar el nuevo picto
*/
public void chooseTextAndSavePicto(final String selectedImagePath, final int row, final int col) {
public void chooseTextAndSavePicto(final String selectedImagePath, final int row, final int col, final int freeRow, final int freeColumn) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(getResources().getString(R.string.enterImgLabel));
......@@ -767,7 +777,10 @@ public class PictogramActivity extends Activity implements iVocabularyListener,
input.getText().toString(),
cat,
row,
col, new iLocalPicto() {
col,
freeRow,
freeColumn,
new iLocalPicto() {
@Override
public void saved(Picto localPicto) {
PictogramActivity.this.refresh();
......@@ -800,10 +813,14 @@ public class PictogramActivity extends Activity implements iVocabularyListener,
selectedImagePath = getPath(selectedImageUri);
int row=this.getIntent().getIntExtra(Picto.JSON_ATTTRS.ROW, -1);
int col=this.getIntent().getIntExtra(Picto.JSON_ATTTRS.COLUMN, -1);
int freeRow = this.getIntent().getIntExtra(Picto.JSON_ATTTRS.FREE_ROW, -1);
int freeColumn = this.getIntent().getIntExtra(Picto.JSON_ATTTRS.FREE_COLUMN, -1);
Log.i(this.getClass().getCanonicalName(), "0 Picto x y " + " " + row + " " + col);
this.getIntent().removeExtra(Picto.JSON_ATTTRS.ROW);
this.getIntent().removeExtra(Picto.JSON_ATTTRS.COLUMN);
chooseTextAndSavePicto(selectedImagePath, row, col);
this.getIntent().removeExtra(Picto.JSON_ATTTRS.FREE_ROW);
this.getIntent().removeExtra(Picto.JSON_ATTTRS.FREE_COLUMN);
chooseTextAndSavePicto(selectedImagePath, row, col, freeRow, freeColumn);
}
}
}
......
......@@ -210,5 +210,4 @@ public final class PCBcontext {
}
return actionLog;
}
}
......@@ -64,7 +64,7 @@
android:scaleType="fitCenter" />
<GridView
android:id="@+id/picto_grid_view"
android:id="@+id/picto_category_grid_view"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:layout_below="@+id/tape_grid_view"
......@@ -83,7 +83,7 @@
</GridView>
<GridView
android:id="@+id/picto_categories_grid_view"
android:id="@+id/picto_main_grid_view"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:layout_below="@+id/tape_grid_view"
......
/* global Student, PictoCoreCat, VStuLastInstruction, StuPicto, StuSup, sailsTokenAuth, sails */
/* global Student, PictoCoreCat, VStuLastInstruction, StuPicto, StuSup, sailsTokenAuth, sails,
Picto */
/**
/* StudentController
......@@ -55,13 +56,17 @@ module.exports = {
.getTime()
});
} else {
sails.log.error(`Invalid student login: user ${student.username}, password\
"${req.body.password}"`);
res.badRequest();
}
} else {
sails.log.error(`Tried to login as non-existing student ${req.body.username}`);
res.badRequest();
}
})
.catch(function () {
sails.log.error(`Error getting student ${req.body.username} for login`);
res.serverError();
});
},
......@@ -220,7 +225,6 @@ module.exports = {
Student.findOne(req.params.id_stu)
.exec(function (err, stu) {
var k;
if (err || !stu)
return res.json(500, {
error: "No student found"
......@@ -238,9 +242,7 @@ module.exports = {
error: 'Error when saving student'
});
}
return res.json({
result: 'Deleted'
});
return res.json(stu);
});
});
},
......@@ -752,65 +754,69 @@ module.exports = {
/**
* Add an existing picto to the student's collection
* @param {request} req
* @param {request} req (with studentId and pictoId as url parameter)
* {
* attributes: { @see StuPicto.getValidAttributes() }
* }
* @param {response} res
* {
* id: stuPictoId (association betweet student and picto)
* picto: {
* id: pictoId,
* }
* student: studentId (speficied as url parameter)
* picto: { @see Picto model}
* attributes: { @see StuPicto.getValidAttributes() }
* expression: { @see Picto model }
* }
*/
add_picto: function (req, res) {
var params = req.allParams();
StuPicto.create({
student: params.id_stu,
picto: params.id_picto,
attributes: params.attributes
})
.then(function (stuPicto) {
if (!stuPicto) {
sails.log.error(`Can't create StuPicto for picto ${params.id_picto} \
and student ${params.id_stu}`);
throw new Error('stupicto not added');
var student;
var picto;
Student.findOne({ id: params.id_stu })
.then((studentData) => {
if (studentData) {
student = studentData;
} else {
sails.log.error(`Student ${params.id_stu} not found`);
throw new Error();
}
res.ok({
id: stuPicto.id,
picto: { id: stuPicto.picto },
attributes: stuPicto.attributes
});
Picto.findOne({ id: params.id_picto })
.populate('expressions', {
lang: student.lang
})
.catch(function () {
sails.log.debug(`Trying to find an existing StuPicto for picto ${params.id_picto} \
and student ${params.id_stu}`);
StuPicto.findOne({
student: params.id_stu,
picto: params.id_picto
.then((pictoData) => {
if (pictoData) {
picto = pictoData;
} else {
sails.log.error(`Picto ${params.id_picto} not found`);
throw new Error();
}
StuPicto.create({
student: student.id,
picto: picto.id,
attributes: params.attributes
})
.then((stuPicto) => {
if (!stuPicto) {
sails.log.error(`Can't create or find StuPicto for picto ${params.id_picto} \
and student ${params.id_stu}. Check if both picto and student exist and check`);
res.badRequest();
if (stuPicto) {
sails.log.debug('StuPicto created: %j', stuPicto);
res.ok(Object.assign(
{},
stuPicto.toObject(),
{ picto: picto.toObject() },
{ expression: picto.expressions.pop() }
));
} else {
res.ok({
id: stuPicto.id,
picto: { id: stuPicto.picto },
attributes: stuPicto.attributes
});
sails.log.error('StuPicto not created');
throw new Error();
}
})
.catch(() => {
sails.log.error(`Server error finding StuPicto for picto ${params.id_picto} \
and student ${params.id_stu}`);
res.serverError();
});
});
.catch(() => res.serverError());
})
.catch(() => res.badRequest());
})
.catch(() => res.badRequest());
},
/**
......
/* global sails, sailsTokenAuth, Supervisor, Office, Student, StuSup, Picto */
const fs = require('fs');
const path = require('path');
const lodash = require('lodash');
const bcrypt = require('bcrypt-nodejs');
/**
* SupervisorController
*
......@@ -50,7 +55,6 @@ module.exports = {
* }
*/
login: function (req, res) {
var bcrypt = require('bcrypt-nodejs');
var email = req.body.email;
var password = req.body.password;
......@@ -331,48 +335,34 @@ module.exports = {
},
/**
* Get the list of students linked to this supervisor
* Get the list of students linked to this supervisor.
* The extra supervision attribute indicates the existing relationship between the supervisor and
* the student:
*
* 0. There is no relationship (but the students is part of the same office)
* 1. The supervisor is his/her tutor
* 2. The supervisor is his/her teacher
*
* @param {request} req {}
* @param {response} res
* [
* {
* "student": {
* "id": 1234
* "username": "johndoe"
* "name": "John"
* "surname": "Doe"
* "birthdate": "2005-06-19T22:00:00.000Z"
* "notes": null // @TODO 357
* "supervision": 1 // @TODO 357
* "gender": "M/F"
* "country": "ES/EN..."
* "pic": "student/avatar/url.jpg"
* "notes": null
* "lang": "es-es/en-gb..."
* "office": 1234
* "supervision": 0/1/2
* "lang": "es"
* "attributes": {
* "categories": "off" // @TODO 357
* "input_feedback": {
* "vibration": false,
* "ligh_up": true,
* "beep": true,
* "tts": false
* },
* "input_selection": "double click" // @TODO 357
* "pictogram_size": "normal/large"
* "tts_engine": "IVONA Text-to-Speech HQ",
* "tts_voice": "child" // @TODO 357
* "picto_select": "enlarge" // @TODO 357
* "legend": "no" // @TODO 357
* "animation": "yes" // @TODO 357
* "tts_options": {
* "picto": true // @TODO 357
* "phrase": false // @TODO 357
* }
* "picto_background": "#00ff5a"
* "phrase_background": "#ff0000" // @TODO 357
* }
* },
* "supervisor": 10,
* "id": 31 // @TODO 357
* "attributes": { @see Student.getValidAttributes() documentation },
* },
* {
* ...
* }
* ]
*/
students: function (req, res) {
......@@ -380,13 +370,19 @@ module.exports = {
if (supervisor) {
StuSup.find({ supervisor: supervisor.id }).populate('student').then(function (stuSups) {
var students = stuSups.map(function (stuSup) {
return stuSup.student;
var student = stuSup.student;
student.supervision = req.token.office ? 2 : 1;
return student;
});
if (req.token.isSupAdmin && req.token.office.id) {
if (req.token.isSupAdmin && req.token.office && req.token.office.id) {
Student.find({ office: req.token.office.id }).then(function (officeStudents) {
students.concat(officeStudents);
res.ok(require('lodash').uniq(students, false, 'id'));
students = students.map((student) => {
student.supervision = student.supervision || 0;
return student;
});
res.ok(lodash.uniq(students, false, 'id'));
})
.catch(function () {
res.serverError();
......@@ -453,8 +449,6 @@ module.exports = {
* {} // Just returns an empty 'ok' response
*/
upload: function (req, res) {
var fs = require('fs');
var path = require('path');
var newAvatarFileName;
var newAvatarFileDescriptor;
var newAvatarDirectory = sails.config.pictogram.paths.supervisorAvatarDirectory;
......
......@@ -43,6 +43,12 @@ module.exports = {
columnName: 'attributes',
required: true,
type: 'json'
},
toJSON: function () {
var stuPicto = this.toObject();
stuPicto.attributes = StuPicto.getValidAttributes(stuPicto.attributes);
return stuPicto;
}
},
......@@ -66,7 +72,7 @@ module.exports = {
getValidAttributes(attributes) {
'use strict';
sails.log.debug('Requested attributes for StuPicto', attributes);
sails.log.verbose('Requested attributes for StuPicto', attributes);
const validAttributes = {};
const defaultAttributes = {
id_cat: null,
......@@ -114,7 +120,7 @@ module.exports = {
delete validAttributes.color;
}
}
sails.log.debug('Valid attributes for StuPicto', validAttributes);
sails.log.verbose('Valid attributes for StuPicto', validAttributes);
return Object.assign({}, defaultAttributes, validAttributes);
},
......
......@@ -104,6 +104,7 @@ module.exports = {
toJSON: function () {
var student = this.toObject();
student.pic = sails.config.pictogram.urls.getStudentAvatarUrl(student.pic);
student.attributes = Student.getValidAttributes(student.attributes);
delete student.password;
return student;
},
......@@ -211,8 +212,8 @@ module.exports = {
delete validAttributes.tape_background;
}
}
sails.log.debug('Requested attributes for Student', attributes);
sails.log.debug('Valid attributes for Student', validAttributes);
sails.log.verbose('Requested attributes for Student', attributes);
sails.log.verbose('Valid attributes for Student', validAttributes);
return Object.assign({}, defaultAttributes, validAttributes);
},
......
......@@ -76,7 +76,7 @@ dashboardControllers.controller('AddPictoCtrl', function (
//
$scope.load_own_pictos = function () {
$scope.source = 'ownpictos';
$http.get(config.backend + '/sup/' + $scope.sup.id + '/pictos')
$http.get(config.backend + '/sup/' + supervisor.id + '/pictos')
.success(function (data) {
if (data) {
$scope.pictos = data;
......@@ -159,7 +159,7 @@ dashboardControllers.controller('AddPictoCtrl', function (
$upload.upload({
url: '/picto/upload',
method: 'POST',
fields: { owner: $scope.sup.id },
fields: { owner: supervisor.id },
file: file
}).success(function (picto) {
$translate('picto_upload_success').then(function (translation) {
......@@ -314,39 +314,27 @@ dashboardControllers.controller('AddPictoCtrl', function (
//
// Delete own picto
//
$scope.remove_own_picto = function (id_picto){
console.log("delete_picto:" + id_picto);
$scope.remove_own_picto = function (pictoId) {
var deletePicto = $window.confirm('Are you absolutely sure you want to delete?');
if(deletePicto){
$http
.delete(config.backend+'/picto/'+ id_picto)
.success(function(data, status, headers, config) {
// Eliminar de la vista: Se recorre el array de objetos json para buscarlo
for(var i=0; i < $scope.pictos.length; i++) {
if(id_picto == $scope.pictos[i].id)
$scope.pictos.splice(i,1);
if (deletePicto) {
$http.delete(config.backend + '/picto/' + pictoId)
.success(function () {
var i;
for (i = 0; i < $scope.pictos.length; i++) {
if (pictoId === $scope.pictos[i].id) {
$scope.pictos.splice(i, 1);
}
}
console.log("Supervisor picto deleted");
})
.error(function(data, status, headers, config) {
console.log("Error from API: " + data.error);
});
.error(function () {});
}
};
//
//
//
$scope.close = function () {
$modalInstance.close("Ejemplo de elemento devuelto");
$modalInstance.close('Ejemplo de elemento devuelto');
};
// No usado
$scope.cancel = function () {
// Deshacer todos los pictos asignados a las categorías??
$modalInstance.dismiss('cancel');
};
......@@ -354,18 +342,17 @@ dashboardControllers.controller('AddPictoCtrl', function (
// Modal window to open picto expression
//
$scope.open_exp = function (picto) {
var modalInstance = $modal.open({
animation: true,
templateUrl: 'modules/student/views/pictoexp.html',
controller: 'PictoExpCtrl',
size: 'md',
resolve: { // Passing data to the controller of the window
picto: function(){
resolve: {
picto: function () {
return picto;
},
sup: function(){
return $scope.sup;
sup: function () {
return supervisor;
}
}
});
......@@ -373,13 +360,8 @@ dashboardControllers.controller('AddPictoCtrl', function (
// Returned data from the modal window
modalInstance.result.then(
function (exp) {
// Output from the window by clicking cancel or outside its borders
console.log(exp);
picto.expressions.push(exp);
}
);
};
// End Modal window to manage picto config
});
......@@ -298,12 +298,17 @@ describe('Student API', function () {
.expect((response) => {
assert.isObject(response.body);
assert.isNumber(response.body.id);
assert.isNumber(response.body.student);
assert.isObject(response.body.picto);
assert.isObject(response.body.expression);
assert.equal(response.body.picto.id, 1234);
assert.equal(response.body.expression.text, 'test-expression');
delete response.body.picto;
delete response.body.expression;
delete response.body.id;
delete response.body.student;
})
.expect({
picto: {
id: 1234
},
attributes: {
coord_x: 3,
coord_y: 3,
......@@ -350,7 +355,7 @@ describe('Student API', function () {
var stuPictoId;
supervisorAgent
.post(`/stu/${studentAgent.data.id}/picto/1234`)
.post(`/stu/${studentAgent.data.id}/picto/1235`)
.send({
attributes: {
coord_x: 3,
......
......@@ -22,9 +22,12 @@ describe('Supervisor API', function () {
response.body.forEach(function (student) {
assert.isObject(student);
assert.isNumber(student.id);
assert.isString(student.username);
assert.isString(student.name);
assert.isString(student.surname);
assert.isUndefined(student.password);
assert.isObject(student.attributes);
assert.oneOf(student.supervision, [0, 1, 2]);
});
})
.end(done);
......
/* eslint-disable no-console */
var DATABASE_BACKUP_FILE = '/tmp/pictogram_test_backup.sql';
var UPLOAD_FOLDER = '';
var UPLOAD_FOLDER_BACKUP = '';
var UPLOAD_FOLDER;
var UPLOAD_FOLDER_BACKUP;
var Agent = require('supertest').agent;
var AuthAgent = require('./test-auth-agent');
var chai = require('chai');
......@@ -73,10 +73,12 @@ before(function (serverLoadDone) {
after(function (done) {
// Restore the database and the upload folder
if (UPLOAD_FOLDER && UPLOAD_FOLDER_BACKUP) {
childProcess.execSync('mysql -u pictodbuser -pp1KT015 pictodb < ' + DATABASE_BACKUP_FILE);
childProcess.execSync('rm ' + DATABASE_BACKUP_FILE);
childProcess.execSync('rm -r ' + UPLOAD_FOLDER);
childProcess.execSync('mv ' + UPLOAD_FOLDER_BACKUP + ' ' + UPLOAD_FOLDER);
}
sails.lower(done);
});
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