Commit 320a5088 by Arturo Montejo Ráez

Merge branch 'develop' of http://gitlab.ujaen.es/yotta/pictogram into develop

parents 6b5d2786 8d1761cb
Showing with 98 additions and 581 deletions
...@@ -176,11 +176,10 @@ public class PCBDBHelper extends SQLiteOpenHelper { ...@@ -176,11 +176,10 @@ public class PCBDBHelper extends SQLiteOpenHelper {
Cursor cursor = db.rawQuery("SELECT id_stu, id_picto, id_grid, id_child_grid, id_stupicto, url, translation, attributes FROM collection_detail WHERE id_stu = "+id_stu,null); Cursor cursor = db.rawQuery("SELECT id_stu, id_picto, id_grid, id_child_grid, id_stupicto, url, translation, attributes FROM collection_detail WHERE id_stu = "+id_stu,null);
Log.i(LOG_TAG, "Local recovering " + cursor.getCount() + " pictos for student " + id_stu + " from local DB Scene:"+id_grid); Log.i(LOG_TAG, "Local recovering " + cursor.getCount() + " pictos for student " + id_stu + " from local DB Scene:"+id_grid);
cursor.moveToFirst(); cursor.moveToFirst();
vocabulary.clear();
if (cursor.getCount()>0) do{ if (cursor.getCount()>0) do{
Picto picto = new Picto(cursor.getInt(1), cursor.getString(5),cursor.getInt(4),cursor.getInt(2),cursor.getInt(3),new JSONObject(cursor.getString(7))); Picto picto = new Picto(cursor.getInt(1), cursor.getString(5),cursor.getInt(4),cursor.getInt(2),cursor.getInt(3),new JSONObject(cursor.getString(7)));
vocabulary.addPicto(picto); vocabulary.addPicto(picto);
}while (cursor.moveToNext()); }while (cursor.moveToNext());
cursor.close(); cursor.close();
//db.close(); <--no es necesario cerrar la bbdd https://groups.google.com/forum/#!msg/android-developers/NwDRpHUXt0U/jIam4Q8-cqQJ //db.close(); <--no es necesario cerrar la bbdd https://groups.google.com/forum/#!msg/android-developers/NwDRpHUXt0U/jIam4Q8-cqQJ
...@@ -263,7 +262,8 @@ public class PCBDBHelper extends SQLiteOpenHelper { ...@@ -263,7 +262,8 @@ public class PCBDBHelper extends SQLiteOpenHelper {
values.put("url", picto.get_url()); values.put("url", picto.get_url());
values.put("translation",picto.get_translation()); values.put("translation",picto.get_translation());
values.put("attributes",picto.get_json_attrs()); values.put("attributes",picto.get_json_attrs());
db.insertWithOnConflict("collection_detail", null, values,SQLiteDatabase.CONFLICT_REPLACE); db.delete("collection_detail","id_grid="+picto.get_grid()+" and id_picto="+ picto.get_ImgId(),null);
db.insertWithOnConflict("collection_detail", null, values,SQLiteDatabase.CONFLICT_ABORT);
} }
Log.i(LOG_TAG,"Storage "+n+" pictos for student "+id_stu); Log.i(LOG_TAG,"Storage "+n+" pictos for student "+id_stu);
//db.close(); <--no es necesario cerrar la bbdd https://groups.google.com/forum/#!msg/android-developers/NwDRpHUXt0U/jIam4Q8-cqQJ //db.close(); <--no es necesario cerrar la bbdd https://groups.google.com/forum/#!msg/android-developers/NwDRpHUXt0U/jIam4Q8-cqQJ
...@@ -281,7 +281,6 @@ public class PCBDBHelper extends SQLiteOpenHelper { ...@@ -281,7 +281,6 @@ public class PCBDBHelper extends SQLiteOpenHelper {
ContentValues values=new ContentValues(7); ContentValues values=new ContentValues(7);
values.put("id_stu", id_stu); values.put("id_stu", id_stu);
values.put("id_picto", picto.get_ImgId()); values.put("id_picto", picto.get_ImgId());
//TODO: Añadir aqui el id de escena activa para el estudiante
values.put("id_grid",picto.get_grid()); values.put("id_grid",picto.get_grid());
values.put("id_stupicto",picto.get_stupicto_id()); values.put("id_stupicto",picto.get_stupicto_id());
values.put("url", picto.get_url()); values.put("url", picto.get_url());
......
...@@ -300,7 +300,8 @@ public class Picto extends Img { ...@@ -300,7 +300,8 @@ public class Picto extends Img {
*/ */
public boolean is_disabled() { public boolean is_disabled() {
try { try {
return PCBcontext.getPcbdb().getCurrentUser().is_supervisor() && this.attributes.getString(JSON_ATTTRS.STATUS).equals(JSON_ATTTR_STATUS_VALUES.DISABLED); //return PCBcontext.getPcbdb().getCurrentUser().is_supervisor() && this.attributes.getString(JSON_ATTTRS.STATUS).equals(JSON_ATTTR_STATUS_VALUES.DISABLED);
return this.attributes.getString(JSON_ATTTRS.STATUS).equals(JSON_ATTTR_STATUS_VALUES.DISABLED);
} catch (JSONException e) { } catch (JSONException e) {
return false; return false;
} }
...@@ -321,13 +322,14 @@ public class Picto extends Img { ...@@ -321,13 +322,14 @@ public class Picto extends Img {
* *
* @return if the picto is visible * @return if the picto is visible
*/ */
public boolean is_invisible(LinkedList<Integer> visited) { private boolean is_invisible(LinkedList<Integer> visited) {
boolean visible=!is_invisible1(); boolean visible=!is_invisible1();
if (visible && has_child_grid() && !visited.contains(get_child_grid())) { if (visible && has_child_grid() && !visited.contains(get_child_grid())) {
visited.add(get_child_grid()); visited.add(get_child_grid());
LinkedList<Picto> childs = PCBcontext.getVocabulary().next(get_child_grid()); LinkedList<Picto> childs = PCBcontext.getVocabulary().next(get_child_grid());
if (childs==null) if (childs==null)
Log.e(LOG_TAG,"Picto "+this.get_legend()+ " with empty grid "+get_child_grid()); visible=false;
else else
for (Picto child : childs) { for (Picto child : childs) {
visible = !child.is_invisible(visited); visible = !child.is_invisible(visited);
...@@ -478,7 +480,7 @@ public class Picto extends Img { ...@@ -478,7 +480,7 @@ public class Picto extends Img {
* toString method * toString method
*/ */
public String toString(){ public String toString(){
return "(" + get_ImgId() + ") - ["+ get_row() +","+ get_column()+"]" + get_translation() + " - " + get_url() + " --- " + get_json_attrs(); return "( img:" + get_ImgId() + ", grid: "+get_grid()+ ", id:"+get_stupicto_id()+") - ["+ get_row() +","+ get_column()+"]" + get_translation() + " - " + get_url() + " --- " + get_json_attrs()+"."+super.toString();
} }
......
...@@ -63,16 +63,15 @@ public class Vocabulary implements Iterable<Picto> { ...@@ -63,16 +63,15 @@ public class Vocabulary implements Iterable<Picto> {
VocabularyTalk.iVocabularyListener vocabulary_listeners[] = {new VocabularyTalk.iVocabularyListener() { VocabularyTalk.iVocabularyListener vocabulary_listeners[] = {new VocabularyTalk.iVocabularyListener() {
@Override @Override
public void change(action action, int picto_grid, int picto_id, int id_child_grid, JSONObject args) { public void change(action action, int picto_grid, int picto_id, int id_child_grid, JSONObject args) {
switch (action) { switch (action) {
case delete: { case delete: {
Log.i(this.getClass().getCanonicalName(), "Picto delete "+picto_grid+"."+picto_id); Log.i(LOG_TAG, "Picto delete "+picto_grid+"."+picto_id);
removePicto(picto_grid,picto_id); removePicto(picto_grid,picto_id);
break; break;
} }
case update:{ case update:{
Log.i(this.getClass().getCanonicalName(), "Picto update "+args.toString()); Log.i(LOG_TAG, "Vocabulary action listened (vocabulary model): " + action);
try { try {
modifyAttsPicto(picto_grid, picto_id, args.getJSONObject("attributes"), id_child_grid); modifyAttsPicto(picto_grid, picto_id, args.getJSONObject("attributes"), id_child_grid);
} catch (JSONException e) { } catch (JSONException e) {
...@@ -121,7 +120,7 @@ public class Vocabulary implements Iterable<Picto> { ...@@ -121,7 +120,7 @@ public class Vocabulary implements Iterable<Picto> {
public void synchronize() { public void synchronize() {
VocabularyDownloader downloader = new VocabularyDownloader(this,this.pictos,this.imgListener); VocabularyDownloader downloader = new VocabularyDownloader(this,this.imgListener);
downloader.synchronize(); downloader.synchronize();
} }
//public boolean is_category(Picto p) {return this.pictos.containsKey(p.get_ImgId()); } //public boolean is_category(Picto p) {return this.pictos.containsKey(p.get_ImgId()); }
...@@ -136,11 +135,13 @@ public class Vocabulary implements Iterable<Picto> { ...@@ -136,11 +135,13 @@ public class Vocabulary implements Iterable<Picto> {
public void addPictoAndSave(Picto pic, ImgDownloader.tsource source, ImgDownloader.iImgDownloaderListener imgListener){ public void addPictoAndSave(Picto pic, ImgDownloader.tsource source, ImgDownloader.iImgDownloaderListener imgListener){
Vector<Img> imgs=new Vector<Img>(1); Vector<Img> imgs=new Vector<Img>(1);
if (pic.is_local()) addPicto(pic);
imgs.add(pic); imgs.add(pic);
ImgDownloader downloader = new ImgDownloader(PCBcontext.getContext(), imgListener,source); ImgDownloader downloader = new ImgDownloader(PCBcontext.getContext(), imgListener,source);
downloader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, imgs); downloader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, imgs);
if (!pic.local_update()) addPicto(pic);
PCBcontext.getPcbdb().savePicto(pic); PCBcontext.getPcbdb().savePicto(pic);
} }
...@@ -155,7 +156,8 @@ public class Vocabulary implements Iterable<Picto> { ...@@ -155,7 +156,8 @@ public class Vocabulary implements Iterable<Picto> {
int index=-1; int index=-1;
if (pictos_cat!=null) if (pictos_cat!=null)
for (int i=0; i<pictos_cat.size() && index==-1; i++) for (int i=0; i<pictos_cat.size() && index==-1; i++)
if (pictos_cat.get(i).get_ImgId()==pic_id) index=i; if (pictos_cat.get(i).get_ImgId()==pic_id)
index=i;
return index; return index;
} }
...@@ -248,13 +250,18 @@ public class Vocabulary implements Iterable<Picto> { ...@@ -248,13 +250,18 @@ public class Vocabulary implements Iterable<Picto> {
*/ */
public void addPicto(Picto picto) { public void addPicto(Picto picto) {
LinkedList<Picto> pictos_grid; LinkedList<Picto> pictos_grid;
if (find_picto_index(picto.get_grid(),picto.get_ImgId())>-1)
Log.e(LOG_TAG,"********ADDING PICTO DUPLICATED!!!!!!!!!!! "+picto);
else {
if (this.pictos.containsKey(picto.get_grid())) if (this.pictos.containsKey(picto.get_grid()))
pictos_grid = pictos.get(picto.get_grid()); pictos_grid = pictos.get(picto.get_grid());
else { else {
pictos_grid = new LinkedList(); pictos_grid = new LinkedList();
this.pictos.put(new Integer(picto.get_grid()),pictos_grid); this.pictos.put(new Integer(picto.get_grid()), pictos_grid);
} }
pictos_grid.add(picto); pictos_grid.add(picto);
}
} }
...@@ -368,4 +375,8 @@ public class Vocabulary implements Iterable<Picto> { ...@@ -368,4 +375,8 @@ public class Vocabulary implements Iterable<Picto> {
return vocabulary; return vocabulary;
} }
public void clear() {
this.pictos.clear();
}
} }
...@@ -37,7 +37,8 @@ import java.util.concurrent.TimeUnit; ...@@ -37,7 +37,8 @@ import java.util.concurrent.TimeUnit;
public class NetService implements Runnable, RestapiWrapper.iSilentLogin { public class NetService implements Runnable, RestapiWrapper.iSilentLogin {
private static final String LOG_TAG=NetService.class.getCanonicalName(); private static final String LOG_TAG=NetService.class.getCanonicalName();
private static final String ping_session="server/ping"; private static final String ping_session="server/ping_session";
private static final String ping="server/ping";
private boolean updated; private boolean updated;
private final Vector<iNetServiceStatus> listeners; private final Vector<iNetServiceStatus> listeners;
...@@ -46,13 +47,12 @@ public class NetService implements Runnable, RestapiWrapper.iSilentLogin { ...@@ -46,13 +47,12 @@ public class NetService implements Runnable, RestapiWrapper.iSilentLogin {
private long nextRestfullSynchro; private long nextRestfullSynchro;
private long nextServerPing; private long nextServerPing;
public NetService(iNetServiceStatus listener) { public NetService(iNetServiceStatus listener) {
this.updated=RestapiWrapper.ping(PCBcontext.getContext().getResources().getString(R.string.server), ping_session); RestapiWrapper.ping(PCBcontext.getContext().getResources().getString(R.string.server), ping);
this.updated=false;
nextServerPing=0; nextServerPing=0;
this.listeners = new Vector<>(2); this.listeners = new Vector<>(2);
this.listeners.add(listener); this.listeners.add(listener);
if (listener instanceof iNetServiceDevice) ((iNetServiceDevice)listener).build(); if (listener instanceof iNetServiceDevice) ((iNetServiceDevice)listener).build();
Log.i(LOG_TAG, "Checking Pictogram server access...");
Log.i(LOG_TAG, this.updated ? "Pictogram server access ok" : "Pictogram server access failed, Internet connection available?");
ScheduledThreadPoolExecutor exec = new ScheduledThreadPoolExecutor(1); ScheduledThreadPoolExecutor exec = new ScheduledThreadPoolExecutor(1);
exec.scheduleWithFixedDelay(this, 0, PCBcontext.getContext().getResources().getInteger(R.integer.netservice_timing), TimeUnit.SECONDS); exec.scheduleWithFixedDelay(this, 0, PCBcontext.getContext().getResources().getInteger(R.integer.netservice_timing), TimeUnit.SECONDS);
} }
...@@ -151,19 +151,17 @@ public class NetService implements Runnable, RestapiWrapper.iSilentLogin { ...@@ -151,19 +151,17 @@ public class NetService implements Runnable, RestapiWrapper.iSilentLogin {
public void run() { public void run() {
try { try {
ConnectivityManager cm = ConnectivityManager cm =
(ConnectivityManager)PCBcontext.getContext().getSystemService(Context.CONNECTIVITY_SERVICE); (ConnectivityManager) PCBcontext.getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = cm.getActiveNetworkInfo(); NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
boolean isConnected = activeNetwork != null && activeNetwork.isConnectedOrConnecting(); boolean isConnected = activeNetwork != null && activeNetwork.isConnectedOrConnecting();
if (!isConnected) { if (!isConnected)
setOffline(new NetworkErrorException("No Internet access")); setOffline(new NetworkErrorException("No Internet access"));
return; else {
} final long now = new Date().getTime();
long now = new Date().getTime(); if (now >= nextServerPing || !updated) {
if ( (now < nextServerPing)) return; nextServerPing = now + serverPingTimming;
nextServerPing=now+serverPingTimming; PCBcontext.getRestapiWrapper().ask(updated ? ping_session : ping, new RestapiWrapper.iRestapiListener() {
PCBcontext.getRestapiWrapper().ask(ping_session, new RestapiWrapper.iRestapiListener() {
@Override @Override
public void preExecute() { public void preExecute() {
...@@ -172,63 +170,63 @@ public class NetService implements Runnable, RestapiWrapper.iSilentLogin { ...@@ -172,63 +170,63 @@ public class NetService implements Runnable, RestapiWrapper.iSilentLogin {
@Override @Override
public void result(JSONArray result) { public void result(JSONArray result) {
} }
@Override @Override
public void result(final JSONObject result) { public void result(final JSONObject result) {
try { try {
final float version = ((float)(Float.valueOf(result.getString("version")).intValue()*10))/10; final float version = ((float) (Float.valueOf(result.getString("version")).intValue() * 10)) / 10;
if (PCBcontext.getActivityContext() != null && version > DeviceHelper.getAppVersion() && newVersionContext!=PCBcontext.getActivityContext()) { if (PCBcontext.getActivityContext() != null && version > DeviceHelper.getAppVersion() && newVersionContext != PCBcontext.getActivityContext()) {
newVersionContext=PCBcontext.getActivityContext(); // prevent from showing several times the alert newVersionContext = PCBcontext.getActivityContext(); // prevent from showing several times the alert
newVersionAlert(version,PCBcontext.getActivityContext(), version); newVersionAlert(version, PCBcontext.getActivityContext(), version);
} }
} catch (Exception e) { } catch (Exception e) {
Log.e(LOG_TAG, "PING JSON ERROR: " + result + " " + e.getMessage()); Log.e(LOG_TAG, "PING JSON ERROR: " + result + " " + e.getMessage());
} }
long now = new Date().getTime();
if (!updated) { if (!updated) {
nextRestfullSynchro = now; setOnline();
updated = true;
String TAG_TOKEN="token";
try {
PCBcontext.getRestapiWrapper().setToken(result.getString(TAG_TOKEN));
} catch (JSONException e) {
Log.e(LOG_TAG,"Error when getting token:"+e.getMessage()+" res:"+result.toString());
}
if (PCBcontext.is_user_logged()) //si el usuario aun no hizo login, en realidad no es necesario hacer nada if (PCBcontext.is_user_logged()) //si el usuario aun no hizo login, en realidad no es necesario hacer nada
// Comprobar si hay usuario offline, para hacer login transparente // Comprobar si hay usuario offline, para hacer login transparente
if (PCBcontext.is_user_offline()) if (PCBcontext.is_user_offline())
login(); login();
else if (PCBcontext.is_user_online()) { else if (PCBcontext.is_user_online()) {
PCBcontext.getRoom().connect(); PCBcontext.getRoom().connect();
synchronizeStuData(); synchronizeStuData();
PCBcontext.getActionLog().batch(); PCBcontext.getActionLog().batch();
}; }
} else { } else {
try {
PCBcontext.getRestapiWrapper().setToken(result.getString("token"));
Log.i(LOG_TAG, "session token updated");
} catch (JSONException e) {
Log.e(LOG_TAG, "Error when ping:" + e.getMessage() + " res:" + result.toString());
}
//cada restfullSynchroTimming aprox. se fuerza sincronización de vocabulario y configuración de usuario //cada restfullSynchroTimming aprox. se fuerza sincronización de vocabulario y configuración de usuario
if (PCBcontext.is_user_logged()) { if (PCBcontext.is_user_logged()) {
if (restfullSynchroTimming > 0 && (now >= nextRestfullSynchro)) { if (restfullSynchroTimming > 0 && (now >= nextRestfullSynchro)) {
Log.i(LOG_TAG, "Vocabulary request."); Log.i(LOG_TAG, "Vocabulary request.");
if(!PCBcontext.getRoom().inRoom()){ if (!PCBcontext.getRoom().inRoom()) {
PCBcontext.getRoom().connect(); PCBcontext.getRoom().connect();
} }
synchronizeStuData(); synchronizeStuData();
nextSynchro(now+restfullSynchroTimming); nextSynchro(now + restfullSynchroTimming);
} }
} else nextSynchro(now+restfullSynchroTimming); } else nextSynchro(now + restfullSynchroTimming);
} }
} }
@Override @Override
public void error(RestapiWrapper.HTTPException e) { public void error(RestapiWrapper.HTTPException e) {
Log.e(LOG_TAG, "Error when PING asking:" + e.getMessage()+" .Ping session?"+!updated);
setOffline(e); setOffline(e);
} }
}); });
notifyStatus(); }
}catch(Exception e) { }
Log.e(LOG_TAG,"THREAD NOT WORKING BECAUSE:"+e.getMessage()); }catch(Exception e){
Log.e(LOG_TAG, "THREAD NOT WORKING BECAUSE:" + e.getMessage());
this.restart_app(true); this.restart_app(true);
} }
} }
...@@ -272,6 +270,7 @@ public class NetService implements Runnable, RestapiWrapper.iSilentLogin { ...@@ -272,6 +270,7 @@ public class NetService implements Runnable, RestapiWrapper.iSilentLogin {
@Override @Override
public void error(RestapiWrapper.HTTPException e) { public void error(RestapiWrapper.HTTPException e) {
Log.e(LOG_TAG, "Raw error from server when getting student info:" + e.getMessage() + " (error " + e.getCode() + ")"); Log.e(LOG_TAG, "Raw error from server when getting student info:" + e.getMessage() + " (error " + e.getCode() + ")");
restart_app(false);
} }
}); });
} }
...@@ -287,10 +286,18 @@ public class NetService implements Runnable, RestapiWrapper.iSilentLogin { ...@@ -287,10 +286,18 @@ public class NetService implements Runnable, RestapiWrapper.iSilentLogin {
public void setOffline(Exception e) { public void setOffline(Exception e) {
this.updated=false; this.updated=false;
//PCBcontext.getRoom().exit();
Log.e(LOG_TAG, "PCB offline because exception happens: " + e.getMessage()); Log.e(LOG_TAG, "PCB offline because exception happens: " + e.getMessage());
notifyStatus(); notifyStatus();
} }
public void setOnline() {
this.updated=true;
Log.i(LOG_TAG, "PCB online");
notifyStatus();
}
public iNetServiceDevice getNetServiceDevice() { public iNetServiceDevice getNetServiceDevice() {
iNetServiceDevice device=null; iNetServiceDevice device=null;
for (iNetServiceStatus listener: listeners) for (iNetServiceStatus listener: listeners)
......
...@@ -356,6 +356,7 @@ public class PictoUploader { ...@@ -356,6 +356,7 @@ public class PictoUploader {
exists_local_img=false; exists_local_img=false;
PCBcontext.getPcbdb().savePicto(this.picto); PCBcontext.getPcbdb().savePicto(this.picto);
PCBcontext.getVocabulary().addPicto(this.picto);
PCBcontext.getRoom().emit(new VocabularyAction(VocabularyAction.ADD, this.picto)); PCBcontext.getRoom().emit(new VocabularyAction(VocabularyAction.ADD, this.picto));
} }
......
...@@ -17,8 +17,6 @@ import org.json.JSONException; ...@@ -17,8 +17,6 @@ import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import java.io.IOException; import java.io.IOException;
import java.util.Hashtable;
import java.util.LinkedList;
import java.util.Vector; import java.util.Vector;
/** /**
...@@ -28,21 +26,22 @@ import java.util.Vector; ...@@ -28,21 +26,22 @@ import java.util.Vector;
public class VocabularyDownloader { public class VocabularyDownloader {
private static final String LOG_TAG = VocabularyDownloader.class.getSimpleName(); private static final String LOG_TAG = VocabularyDownloader.class.getSimpleName();
Vocabulary vocabulary; Vocabulary vocabulary;
Hashtable<Integer,LinkedList<Picto>> pictos;
ImgDownloader.iImgDownloaderListener imgListener; ImgDownloader.iImgDownloaderListener imgListener;
public VocabularyDownloader(Vocabulary vocabulary, Hashtable<Integer, LinkedList<Picto>> pictos, ImgDownloader.iImgDownloaderListener imgListener) { public VocabularyDownloader(Vocabulary vocabulary, ImgDownloader.iImgDownloaderListener imgListener) {
this.vocabulary=vocabulary; this.vocabulary=vocabulary;
this.pictos=pictos;
this.imgListener=imgListener; this.imgListener=imgListener;
} }
public void synchronize() { public void synchronize() {
if (TransactionMonitor.getDBOnTransaction()!=null) {
Log.e(LOG_TAG,"Vocabulary synchronization aborted because the previous Transaction is not finished");
return;
}
synchronize_upload(new PictoUploader.iDeletedOnServer() { synchronize_upload(new PictoUploader.iDeletedOnServer() {
@Override @Override
public void ok(int npictos) { public void ok(int npictos) {
pictos.clear(); vocabulary.clear();
TransactionMonitor.startTransaction(PCBcontext.getPcbdb()); TransactionMonitor.startTransaction(PCBcontext.getPcbdb());
PCBcontext.getPcbdb().deleteVocabulary(TransactionMonitor.getDBOnTransaction());
if (npictos>0) if (npictos>0)
Toast.makeText( Toast.makeText(
PCBcontext.getActivityContext(), PCBcontext.getActivityContext(),
...@@ -96,14 +95,14 @@ public class VocabularyDownloader { ...@@ -96,14 +95,14 @@ public class VocabularyDownloader {
@Override @Override
public void result(JSONObject result) { public void result(JSONObject result) {
downloaded_scenes.add(id_grid);
if (result != null && PCBcontext.is_user_logged()) { if (result != null && PCBcontext.is_user_logged()) {
JSONObject picto, attributes; JSONObject picto, attributes;
JSONObject stupicto = null; JSONObject stupicto = null;
try { try {
JSONArray stu_pictos = result.getJSONArray("pictos"); //Obtengo el JSONArray de los stupictos JSONArray stu_pictos = result.getJSONArray("pictos"); //Obtengo el JSONArray de los stupictos
Picto[] pictos_list = new Picto[stu_pictos.length()]; Picto[] pictos_list = new Picto[stu_pictos.length()];
downloaded_scenes.add(result.getInt("id"));
for (int i = 0; i < stu_pictos.length(); i++) { for (int i = 0; i < stu_pictos.length(); i++) {
stupicto = stu_pictos.getJSONObject(i); stupicto = stu_pictos.getJSONObject(i);
picto = stupicto.getJSONObject("picto"); picto = stupicto.getJSONObject("picto");
...@@ -161,9 +160,7 @@ public class VocabularyDownloader { ...@@ -161,9 +160,7 @@ public class VocabularyDownloader {
private void synchronizeImgs(Picto updated_collection[]) throws JSONException { private void synchronizeImgs(Picto updated_collection[]) throws JSONException {
Vector<Img> imgs=new Vector<Img>(updated_collection.length); Vector<Img> imgs=new Vector<Img>(updated_collection.length);
for (Picto updated_picto: updated_collection) { for (Picto updated_picto: updated_collection) {
LinkedList<Picto> pictos_grid;
Picto picto = new Picto(updated_picto.get_ImgId(), Picto picto = new Picto(updated_picto.get_ImgId(),
updated_picto.get_url(), updated_picto.get_url(),
updated_picto.get_stupicto_id(), updated_picto.get_stupicto_id(),
...@@ -171,14 +168,7 @@ public class VocabularyDownloader { ...@@ -171,14 +168,7 @@ public class VocabularyDownloader {
updated_picto.get_child_grid(), updated_picto.get_child_grid(),
updated_picto.get_translation(), updated_picto.get_translation(),
updated_picto.get_json_attrs()); updated_picto.get_json_attrs());
if (pictos.containsKey(new Integer(picto.get_grid()))) { vocabulary.addPicto(picto);
pictos_grid = pictos.get(picto.get_grid());
}else {
pictos_grid = new LinkedList<>();
pictos.put(picto.get_grid(),pictos_grid);
}
pictos_grid.add(picto);
imgs.add(picto); imgs.add(picto);
} }
...@@ -195,13 +185,13 @@ public class VocabularyDownloader { ...@@ -195,13 +185,13 @@ public class VocabularyDownloader {
* TODO: keep record of failed uploaded images to re-include as local pictos * TODO: keep record of failed uploaded images to re-include as local pictos
*/ */
private void synchronize_upload(final PictoUploader.iDeletedOnServer deleted_pictos) { private void synchronize_upload(final PictoUploader.iDeletedOnServer deleted_pictos) {
try { try {
if (this.pictos.isEmpty()) if (vocabulary.size()==0)
PCBcontext.getPcbdb().getStudentVocabulary(vocabulary); PCBcontext.getPcbdb().getStudentVocabulary(vocabulary);
} catch (JSONException e) { } catch (JSONException e) {
Log.e(this.getClass().getName(), " Picto json error from local storage: " + e.getMessage()); Log.e(this.getClass().getName(), " Picto json error from local storage: " + e.getMessage());
} }
Vector<Picto> pictos_to_be_removed=new Vector<>(3); Vector<Picto> pictos_to_be_removed=new Vector<>(3);
for (Picto picto: vocabulary) { for (Picto picto: vocabulary) {
if (picto.is_deleted()) if (picto.is_deleted())
......
...@@ -33,13 +33,15 @@ public class Room { ...@@ -33,13 +33,15 @@ public class Room {
private SailsSocketsIO socket=null; private SailsSocketsIO socket=null;
private boolean inRoom=false; private boolean inRoom=false;
private final Hashtable<String, Emitter.Listener> listeners; private final Hashtable<String, Emitter.Listener> listeners;
public Room( ) { public Room( ) {
Log.i(this.getClass().getName(), "Entering room"); Log.i(this.getClass().getName(), "Entering room");
listeners=new Hashtable<>(); listeners=new Hashtable<>();
listeners.put("disconnect", new Emitter.Listener() { listeners.put("disconnect", new Emitter.Listener() {
@Override @Override
public void call(Object... args) { public void call(Object... args) {
Log.e(LOG_TAG,"******************Websockect disconnect"); Log.e(LOG_TAG,"Websockect disconnect");
PCBcontext.getNetService().setOffline(new SocketIOException("Websocket connection is lost")); PCBcontext.getNetService().setOffline(new SocketIOException("Websocket connection is lost"));
} }
}); });
...@@ -102,10 +104,12 @@ public class Room { ...@@ -102,10 +104,12 @@ public class Room {
this.listeners.put(msg, listener); this.listeners.put(msg, listener);
} }
private void listen_again() { private void listen_again() {
for (String msg: this.listeners.keySet()) { for (String msg: this.listeners.keySet()) {
Log.e(this.getClass().getName(), "******************************Listening to "+msg); if (this.socket!=null) {
this.socket.unregisterMessage(msg); this.socket.unregisterMessage(msg);
this.socket.registerMessage(msg, this.listeners.get(msg)); this.socket.registerMessage(msg, this.listeners.get(msg));
}else Log.e(this.getClass().getName(), "NULL socket when listening to " + msg);
} }
} }
...@@ -119,11 +123,9 @@ public class Room { ...@@ -119,11 +123,9 @@ public class Room {
} }
} }
private void unlisten() { private void unlisten() {
for (String msg: this.listeners.keySet()) { for (String msg: this.listeners.keySet())
Log.i(this.getClass().getName(), "Unlistening to "+msg);
this.socket.unregisterMessage(msg); this.socket.unregisterMessage(msg);
} }
}
private void unsubscribe() { private void unsubscribe() {
try { try {
...@@ -138,8 +140,8 @@ public class Room { ...@@ -138,8 +140,8 @@ public class Room {
Log.i(this.getClass().getName(), "Leaving room"); Log.i(this.getClass().getName(), "Leaving room");
unlisten(); unlisten();
unsubscribe(); unsubscribe();
this.socket.destroy(); //this.socket.destroy();
this.socket=null; //this.socket=null;
} }
} }
...@@ -147,7 +149,7 @@ public class Room { ...@@ -147,7 +149,7 @@ public class Room {
super.finalize(); super.finalize();
Log.i(this.getClass().getName(), "Discarding room"); Log.i(this.getClass().getName(), "Discarding room");
Log.e(LOG_TAG,"Websocket connection is lost because ojbect is finalized"); Log.e(LOG_TAG,"Websocket connection is lost because ojbect is finalized");
PCBcontext.getNetService().setOffline(new SocketIOException("Websocket connection is lost because ojbect is finalized")); PCBcontext.getNetService().setOffline(new SocketIOException("Websocket connection is lost because object is finalized"));
exit(); exit();
} }
......
...@@ -33,7 +33,7 @@ public class StudentTalk implements Emitter.Listener { ...@@ -33,7 +33,7 @@ public class StudentTalk implements Emitter.Listener {
try { try {
JSONObject msg=((JSONObject) args[0]).getJSONObject("student"); JSONObject msg=((JSONObject) args[0]).getJSONObject("student");
if (lastTalk!=null && lastTalk.equals(msg.toString())) { if (lastTalk!=null && lastTalk.equals(msg.toString())) {
Log.e(LOG_TAG, "********************************Message from server duplicated!"); Log.e(LOG_TAG, "Message from server duplicated!");
return; return;
} }
lastTalk=msg.toString(); lastTalk=msg.toString();
......
...@@ -188,5 +188,5 @@ public class Img { ...@@ -188,5 +188,5 @@ public class Img {
/** /**
* @overide * @overide
*/ */
public String toString() {return this.type+"."+this.id;} public String toString() {return this.type+"."+this.id+"."+super.toString();}
} }
...@@ -124,15 +124,17 @@ public final class PCBcontext { ...@@ -124,15 +124,17 @@ public final class PCBcontext {
} }
public static void unset_user() { public static void unset_user() {
Log.e(PCBcontext.class.getCanonicalName(), "User unset. Student " + getPcbdb().getCurrentUser().get_name_stu()); Log.i(PCBcontext.class.getCanonicalName(), "User unset. Student " + getPcbdb().getCurrentUser().get_name_stu());
if (room!=null) room.exit(); if (room!=null) room.exit();
if (TransactionMonitor.getDBOnTransaction()!=null) { if (TransactionMonitor.getDBOnTransaction()!=null) {
Log.e(LOG_TAG, "Unset when transaction is active, aborting transaction"); Log.e(LOG_TAG, "Unset when transaction is active, aborting transaction");
TransactionMonitor.endTransaction(false); TransactionMonitor.endTransaction(false);
} }
pcbdb = null; pcbdb = null;
room = null; //room = null;
vocabulary = null; vocabulary = null;
studentTalk = null;
getNetService().notifyStatus(); getNetService().notifyStatus();
} }
@Override @Override
......
...@@ -150,7 +150,7 @@ public class TTSHelper { ...@@ -150,7 +150,7 @@ public class TTSHelper {
public void play(String input) { public void play(String input) {
Bundle params = new Bundle(); Bundle params = new Bundle();
params.putString(TextToSpeech.Engine.KEY_PARAM_VOLUME, "1"); params.putFloat(TextToSpeech.Engine.KEY_PARAM_VOLUME, new Float(1));
params.putString(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, "TAPE_READ"); params.putString(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, "TAPE_READ");
ttobj.speak(input, TextToSpeech.QUEUE_FLUSH, params, "TAPE_READ"); ttobj.speak(input, TextToSpeech.QUEUE_FLUSH, params, "TAPE_READ");
} }
......
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Automatically generated file. DO NOT MODIFY -->
<!-- Values from product flavor: DevFlavor -->
<string name="apk" translatable="false">pictogram_dev.apk</string>
<string name="server" translatable="false">https://dev.pictogramweb.com</string>
<bool name="ssl_connect">false</bool>
<!-- Values from default config. -->
<bool name="NotifyAllwaysVisible">true</bool>
<string name="VersionManagerClass" translatable="false">com.yottacode.pictogram.communicator.VersionManager</string>
</resources>
[
{
"outputFile": "C:\\home\\german\\pictogram\\android\\Pictogram\\communicator\\build\\intermediates\\incremental\\mergeDevFlavorDebugResources\\merged.dir\\values-h720dp-v13\\values-h720dp-v13.xml",
"map": [
{
"to": {
"startLine": 2,
"startColumn": 4,
"startOffset": 55,
"endColumn": 66,
"endOffset": 117
},
"from": {
"file": "C:\\home\\german\\.android\\build-cache\\116ba476ffe1c97e7a1f57d6511e4139a0deeca9\\output\\res\\values-h720dp-v13\\values-h720dp-v13.xml",
"position": {
"startLine": 2,
"startColumn": 4,
"startOffset": 55,
"endColumn": 66,
"endOffset": 117
}
}
}
]
},
{
"outputFile": "C:\\Users\\Fernando\\git\\pictogram\\android\\Pictogram\\communicator\\build\\intermediates\\incremental\\mergeDevFlavorDebugResources\\merged.dir\\values-h720dp-v13\\values-h720dp-v13.xml",
"map": [
{
"to": {
"startLine": 2,
"startColumn": 4,
"startOffset": 55,
"endColumn": 66,
"endOffset": 117
},
"from": {
"file": "C:\\Users\\Fernando\\.android\\build-cache\\17fa1970374ae1714f0d4f5c4dd1f5f61d6601bf\\output\\res\\values-h720dp-v13\\values-h720dp-v13.xml",
"position": {
"startLine": 2,
"startColumn": 4,
"startOffset": 55,
"endColumn": 66,
"endOffset": 117
}
}
}
]
},
{
"outputFile": "C:\\Users\\Fernando\\Git\\pictogram\\android\\Pictogram\\communicator\\build\\intermediates\\incremental\\mergeDevFlavorDebugResources\\merged.dir\\values-h720dp-v13\\values-h720dp-v13.xml",
"map": [
{
"to": {
"startLine": 2,
"startColumn": 4,
"startOffset": 55,
"endColumn": 66,
"endOffset": 117
},
"from": {
"file": "C:\\Users\\Fernando\\.android\\build-cache\\4b93b66b05cee2131eef68820393b824c2f2a3a6\\output\\res\\values-h720dp-v13\\values-h720dp-v13.xml",
"position": {
"startLine": 2,
"startColumn": 4,
"startOffset": 55,
"endColumn": 66,
"endOffset": 117
}
}
}
]
}
]
\ No newline at end of file
[
{
"outputFile": "C:\\home\\german\\pictogram\\android\\Pictogram\\communicator\\build\\intermediates\\incremental\\mergeDevFlavorDebugResources\\merged.dir\\values-hdpi-v4\\values-hdpi-v4.xml",
"map": [
{
"to": {
"startLine": 2,
"startColumn": 4,
"startOffset": 55,
"endLine": 6,
"endColumn": 13,
"endOffset": 327
},
"from": {
"file": "C:\\home\\german\\.android\\build-cache\\116ba476ffe1c97e7a1f57d6511e4139a0deeca9\\output\\res\\values-hdpi-v4\\values-hdpi-v4.xml",
"position": {
"startLine": 2,
"startColumn": 4,
"startOffset": 55,
"endLine": 6,
"endColumn": 13,
"endOffset": 327
}
}
}
]
},
{
"outputFile": "C:\\Users\\Fernando\\Git\\pictogram\\android\\Pictogram\\communicator\\build\\intermediates\\incremental\\mergeDevFlavorDebugResources\\merged.dir\\values-hdpi-v4\\values-hdpi-v4.xml",
"map": [
{
"to": {
"startLine": 2,
"startColumn": 4,
"startOffset": 55,
"endLine": 6,
"endColumn": 13,
"endOffset": 327
},
"from": {
"file": "C:\\Users\\Fernando\\.android\\build-cache\\4b93b66b05cee2131eef68820393b824c2f2a3a6\\output\\res\\values-hdpi-v4\\values-hdpi-v4.xml",
"position": {
"startLine": 2,
"startColumn": 4,
"startOffset": 55,
"endLine": 6,
"endColumn": 13,
"endOffset": 327
}
}
}
]
},
{
"outputFile": "C:\\Users\\Fernando\\git\\pictogram\\android\\Pictogram\\communicator\\build\\intermediates\\incremental\\mergeDevFlavorDebugResources\\merged.dir\\values-hdpi-v4\\values-hdpi-v4.xml",
"map": [
{
"to": {
"startLine": 2,
"startColumn": 4,
"startOffset": 55,
"endLine": 6,
"endColumn": 13,
"endOffset": 327
},
"from": {
"file": "C:\\Users\\Fernando\\.android\\build-cache\\17fa1970374ae1714f0d4f5c4dd1f5f61d6601bf\\output\\res\\values-hdpi-v4\\values-hdpi-v4.xml",
"position": {
"startLine": 2,
"startColumn": 4,
"startOffset": 55,
"endLine": 6,
"endColumn": 13,
"endOffset": 327
}
}
}
]
}
]
\ No newline at end of file
[
{
"outputFile": "C:\\home\\german\\pictogram\\android\\Pictogram\\communicator\\build\\intermediates\\incremental\\mergeDevFlavorDebugResources\\merged.dir\\values-land\\values-land.xml",
"map": [
{
"to": {
"startLine": 2,
"startColumn": 4,
"startOffset": 55,
"endColumn": 69,
"endOffset": 120
},
"from": {
"file": "C:\\home\\german\\.android\\build-cache\\116ba476ffe1c97e7a1f57d6511e4139a0deeca9\\output\\res\\values-land\\values-land.xml",
"position": {
"startLine": 2,
"startColumn": 4,
"startOffset": 55,
"endColumn": 69,
"endOffset": 120
}
}
},
{
"to": {
"startLine": 3,
"startColumn": 4,
"startOffset": 125,
"endColumn": 63,
"endOffset": 184
},
"from": {
"file": "C:\\home\\german\\.android\\build-cache\\116ba476ffe1c97e7a1f57d6511e4139a0deeca9\\output\\res\\values-land\\values-land.xml",
"position": {
"startLine": 3,
"startColumn": 4,
"startOffset": 125,
"endColumn": 63,
"endOffset": 184
}
}
},
{
"to": {
"startLine": 4,
"startColumn": 4,
"startOffset": 189,
"endColumn": 70,
"endOffset": 255
},
"from": {
"file": "C:\\home\\german\\.android\\build-cache\\116ba476ffe1c97e7a1f57d6511e4139a0deeca9\\output\\res\\values-land\\values-land.xml",
"position": {
"startLine": 4,
"startColumn": 4,
"startOffset": 189,
"endColumn": 70,
"endOffset": 255
}
}
},
{
"to": {
"startLine": 5,
"startColumn": 4,
"startOffset": 260,
"endColumn": 67,
"endOffset": 323
},
"from": {
"file": "C:\\home\\german\\.android\\build-cache\\116ba476ffe1c97e7a1f57d6511e4139a0deeca9\\output\\res\\values-land\\values-land.xml",
"position": {
"startLine": 5,
"startColumn": 4,
"startOffset": 260,
"endColumn": 67,
"endOffset": 323
}
}
}
]
},
{
"outputFile": "C:\\Users\\Fernando\\Git\\pictogram\\android\\Pictogram\\communicator\\build\\intermediates\\incremental\\mergeDevFlavorDebugResources\\merged.dir\\values-land\\values-land.xml",
"map": [
{
"to": {
"startLine": 2,
"startColumn": 4,
"startOffset": 55,
"endColumn": 69,
"endOffset": 120
},
"from": {
"file": "C:\\Users\\Fernando\\.android\\build-cache\\4b93b66b05cee2131eef68820393b824c2f2a3a6\\output\\res\\values-land\\values-land.xml",
"position": {
"startLine": 2,
"startColumn": 4,
"startOffset": 55,
"endColumn": 69,
"endOffset": 120
}
}
},
{
"to": {
"startLine": 3,
"startColumn": 4,
"startOffset": 125,
"endColumn": 63,
"endOffset": 184
},
"from": {
"file": "C:\\Users\\Fernando\\.android\\build-cache\\4b93b66b05cee2131eef68820393b824c2f2a3a6\\output\\res\\values-land\\values-land.xml",
"position": {
"startLine": 3,
"startColumn": 4,
"startOffset": 125,
"endColumn": 63,
"endOffset": 184
}
}
},
{
"to": {
"startLine": 4,
"startColumn": 4,
"startOffset": 189,
"endColumn": 70,
"endOffset": 255
},
"from": {
"file": "C:\\Users\\Fernando\\.android\\build-cache\\4b93b66b05cee2131eef68820393b824c2f2a3a6\\output\\res\\values-land\\values-land.xml",
"position": {
"startLine": 4,
"startColumn": 4,
"startOffset": 189,
"endColumn": 70,
"endOffset": 255
}
}
},
{
"to": {
"startLine": 5,
"startColumn": 4,
"startOffset": 260,
"endColumn": 67,
"endOffset": 323
},
"from": {
"file": "C:\\Users\\Fernando\\.android\\build-cache\\4b93b66b05cee2131eef68820393b824c2f2a3a6\\output\\res\\values-land\\values-land.xml",
"position": {
"startLine": 5,
"startColumn": 4,
"startOffset": 260,
"endColumn": 67,
"endOffset": 323
}
}
}
]
},
{
"outputFile": "C:\\Users\\Fernando\\git\\pictogram\\android\\Pictogram\\communicator\\build\\intermediates\\incremental\\mergeDevFlavorDebugResources\\merged.dir\\values-land\\values-land.xml",
"map": [
{
"to": {
"startLine": 2,
"startColumn": 4,
"startOffset": 55,
"endColumn": 69,
"endOffset": 120
},
"from": {
"file": "C:\\Users\\Fernando\\.android\\build-cache\\17fa1970374ae1714f0d4f5c4dd1f5f61d6601bf\\output\\res\\values-land\\values-land.xml",
"position": {
"startLine": 2,
"startColumn": 4,
"startOffset": 55,
"endColumn": 69,
"endOffset": 120
}
}
},
{
"to": {
"startLine": 3,
"startColumn": 4,
"startOffset": 125,
"endColumn": 63,
"endOffset": 184
},
"from": {
"file": "C:\\Users\\Fernando\\.android\\build-cache\\17fa1970374ae1714f0d4f5c4dd1f5f61d6601bf\\output\\res\\values-land\\values-land.xml",
"position": {
"startLine": 3,
"startColumn": 4,
"startOffset": 125,
"endColumn": 63,
"endOffset": 184
}
}
},
{
"to": {
"startLine": 4,
"startColumn": 4,
"startOffset": 189,
"endColumn": 70,
"endOffset": 255
},
"from": {
"file": "C:\\Users\\Fernando\\.android\\build-cache\\17fa1970374ae1714f0d4f5c4dd1f5f61d6601bf\\output\\res\\values-land\\values-land.xml",
"position": {
"startLine": 4,
"startColumn": 4,
"startOffset": 189,
"endColumn": 70,
"endOffset": 255
}
}
},
{
"to": {
"startLine": 5,
"startColumn": 4,
"startOffset": 260,
"endColumn": 67,
"endOffset": 323
},
"from": {
"file": "C:\\Users\\Fernando\\.android\\build-cache\\17fa1970374ae1714f0d4f5c4dd1f5f61d6601bf\\output\\res\\values-land\\values-land.xml",
"position": {
"startLine": 5,
"startColumn": 4,
"startOffset": 260,
"endColumn": 67,
"endOffset": 323
}
}
}
]
}
]
\ No newline at end of file
[
{
"outputFile": "C:\\home\\german\\pictogram\\android\\Pictogram\\communicator\\build\\intermediates\\incremental\\mergeDevFlavorDebugResources\\merged.dir\\values-ldltr-v21\\values-ldltr-v21.xml",
"map": [
{
"to": {
"startLine": 2,
"startColumn": 4,
"startOffset": 55,
"endColumn": 112,
"endOffset": 163
},
"from": {
"file": "C:\\home\\german\\.android\\build-cache\\116ba476ffe1c97e7a1f57d6511e4139a0deeca9\\output\\res\\values-ldltr-v21\\values-ldltr-v21.xml",
"position": {
"startLine": 2,
"startColumn": 4,
"startOffset": 55,
"endColumn": 112,
"endOffset": 163
}
}
}
]
},
{
"outputFile": "C:\\Users\\Fernando\\Git\\pictogram\\android\\Pictogram\\communicator\\build\\intermediates\\incremental\\mergeDevFlavorDebugResources\\merged.dir\\values-ldltr-v21\\values-ldltr-v21.xml",
"map": [
{
"to": {
"startLine": 2,
"startColumn": 4,
"startOffset": 55,
"endColumn": 112,
"endOffset": 163
},
"from": {
"file": "C:\\Users\\Fernando\\.android\\build-cache\\4b93b66b05cee2131eef68820393b824c2f2a3a6\\output\\res\\values-ldltr-v21\\values-ldltr-v21.xml",
"position": {
"startLine": 2,
"startColumn": 4,
"startOffset": 55,
"endColumn": 112,
"endOffset": 163
}
}
}
]
},
{
"outputFile": "C:\\Users\\Fernando\\git\\pictogram\\android\\Pictogram\\communicator\\build\\intermediates\\incremental\\mergeDevFlavorDebugResources\\merged.dir\\values-ldltr-v21\\values-ldltr-v21.xml",
"map": [
{
"to": {
"startLine": 2,
"startColumn": 4,
"startOffset": 55,
"endColumn": 112,
"endOffset": 163
},
"from": {
"file": "C:\\Users\\Fernando\\.android\\build-cache\\17fa1970374ae1714f0d4f5c4dd1f5f61d6601bf\\output\\res\\values-ldltr-v21\\values-ldltr-v21.xml",
"position": {
"startLine": 2,
"startColumn": 4,
"startOffset": 55,
"endColumn": 112,
"endOffset": 163
}
}
}
]
}
]
\ No newline at end of file
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