Add the module games #338

Closed
Amab wants to merge 53 commits from feat/kahoot into develop
40 changed files with 4028 additions and 45 deletions

View File

@ -166,6 +166,70 @@
android:name="android.support.PARENT_ACTIVITY"
android:value="es.ugr.swad.swadroid.modules.tests.Tests" />
</activity>
<activity
android:name="es.ugr.swad.swadroid.modules.games.Games"
android:label="@string/gamesModuleLabel"
android:theme="@style/Theme.AppCompat.Light"
android:parentActivityName="es.ugr.swad.swadroid.modules.games.GamesList" >
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="es.ugr.swad.swadroid.modules.games.GamesList" />
</activity>
<activity
android:name="es.ugr.swad.swadroid.modules.games.GamesList"
android:label="@string/gamesModuleLabel"
android:theme="@style/Theme.AppCompat.Light"
android:parentActivityName="es.ugr.swad.swadroid.modules.games.GamesList" >
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="es.ugr.swad.swadroid.modules.games.GamesList" />
</activity>
<activity
android:name="es.ugr.swad.swadroid.modules.games.Matches"
android:label="@string/gamesModuleLabel"
android:theme="@style/Theme.AppCompat.Light"
android:parentActivityName="es.ugr.swad.swadroid.modules.games.GamesList" >
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="es.ugr.swad.swadroid.modules.games.GamesList" />
</activity>
<activity
android:name="es.ugr.swad.swadroid.modules.games.MatchesList"
android:label="@string/gamesModuleLabel"
android:theme="@style/Theme.AppCompat.Light"
android:parentActivityName="es.ugr.swad.swadroid.modules.games.GamesList" >
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="es.ugr.swad.swadroid.modules.games.GamesList" />
</activity>
<activity
android:name="es.ugr.swad.swadroid.modules.games.GamesPlay"
android:label="@string/gamesModuleLabel"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
android:theme="@style/Theme.AppCompat.Light"
android:parentActivityName="es.ugr.swad.swadroid.modules.games.GamesList" >
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="es.ugr.swad.swadroid.modules.games.GamesList" />
</activity>
<activity
android:name="es.ugr.swad.swadroid.modules.games.GamesPlayStatus"
android:label="@string/gamesModuleLabel"
android:theme="@style/Theme.AppCompat.Translucent"
android:parentActivityName="es.ugr.swad.swadroid.modules.games.GamesPlay" >
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="es.ugr.swad.swadroid.modules.games.GamesPlay" />
</activity>
<activity
android:name="es.ugr.swad.swadroid.modules.games.GamesPlayAnswer"
android:label="@string/gamesModuleLabel"
android:theme="@style/Theme.AppCompat.Translucent"
android:parentActivityName="es.ugr.swad.swadroid.modules.games.GamesPlay" >
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="es.ugr.swad.swadroid.modules.games.GamesPlay" />
</activity>
<activity
android:name="es.ugr.swad.swadroid.modules.messages.Messages"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
@ -363,27 +427,6 @@
android:name="android.content.SyncAdapter"
android:resource="@xml/sync_notifications" />
</service>
<!-- Optionally, register AnalyticsReceiver and AnalyticsService to support background
dispatching on non-Google Play devices -->
<receiver android:name="com.google.android.gms.analytics.AnalyticsReceiver"
android:enabled="true">
<intent-filter>
<action android:name="com.google.android.gms.analytics.ANALYTICS_DISPATCH" />
</intent-filter>
</receiver>
<service android:name="com.google.android.gms.analytics.AnalyticsService"
android:enabled="true"
android:exported="false"/>
<!-- Optionally, register CampaignTrackingReceiver and CampaignTrackingService to enable
installation campaign reporting -->
<receiver android:name="com.google.android.gms.analytics.CampaignTrackingReceiver"
android:exported="true">
<intent-filter>
<action android:name="com.android.vending.INSTALL_REFERRER" />
</intent-filter>
</receiver>
<service android:name="com.google.android.gms.analytics.CampaignTrackingService" />
<provider
android:name="androidx.core.content.FileProvider"

View File

@ -30,6 +30,7 @@ import java.io.File;
* @author Antonio Aguilera Malagon <aguilerin@gmail.com>
* @author Helena Rodriguez Gijon <hrgijon@gmail.com>
* @author Jose Antonio Guerrero Aviles <cany20@gmail.com>
* @author Sergio Díaz Rueda <sergiodiazrueda8@gmail.com>
*/
public class Constants {
/**
@ -255,6 +256,38 @@ public class Constants {
* Request code for Get Available Roles
*/
public static final int GET_AVAILABLE_ROLES = 46;
/**
* Request code for Games module.
*/
public static final int GAMES_REQUEST_CODE = 47;
/**
* Request code for Games module.
*/
public static final int GAMES_PLAY_REQUEST_CODE = 48;
/**
* Request code for Games module.
*/
public static final int GAMES_ACTIVE_DOWNLOAD_CODE = 49;
/**
* Request code for Games module.
*/
public static final int GAMES_ACTIVE_LIST_CODE = 50;
/**
* Request code for Games module.
*/
public static final int MATCHES_ACTIVE_DOWNLOAD_CODE = 51;
/**
* Request code for Games module.
*/
public static final int MATCHES_ACTIVE_LIST_CODE = 52;
/**
* Request code for Games module.
*/
public static final int MATCHES_STATUS_CODE = 53;
/**
* Request code for Games module.
*/
public static final int MATCHES_ANSWER_CODE = 54;
/**
* Request code for CAMERA permission
*/
@ -353,9 +386,12 @@ public class Constants {
public static final String DIRECTORY_SWADROID = "SWADroid";
public static final String DOWNLOADS_PATH =
Environment.DIRECTORY_DOWNLOADS + File.separator + DIRECTORY_SWADROID;
/**
* Username template for messages
*/
public static final String USERNAME_TEMPLATE = "{userName}";
/**
* Maximum number of questions for games
*/
public static final int MAX_NUM_QUESTIONS_GAMES = 100000;
}

View File

@ -58,9 +58,10 @@ import es.ugr.swad.swadroid.model.Course;
import es.ugr.swad.swadroid.model.Model;
import es.ugr.swad.swadroid.modules.courses.Courses;
import es.ugr.swad.swadroid.modules.downloads.DownloadsManager;
import es.ugr.swad.swadroid.modules.games.GamesList;
import es.ugr.swad.swadroid.modules.groups.MyGroupsManager;
import es.ugr.swad.swadroid.modules.information.Information;
import es.ugr.swad.swadroid.modules.indoorlocation.IndoorLocation;
import es.ugr.swad.swadroid.modules.information.Information;
import es.ugr.swad.swadroid.modules.login.Login;
import es.ugr.swad.swadroid.modules.login.LoginActivity;
import es.ugr.swad.swadroid.modules.messages.Messages;
@ -82,16 +83,17 @@ import es.ugr.swad.swadroid.utils.Utils;
* @author Antonio Aguilera Malagon <aguilerin@gmail.com>
* @author Helena Rodriguez Gijon <hrgijon@gmail.com>
* @author Jose Antonio Guerrero Aviles <cany20@gmail.com>
* @author Sergio Díaz Rueda <sergiodiazrueda8@gmail.com>
*/
public class SWADMain extends MenuExpandableListActivity {
/**
* Function name field
*/
private final String NAME = "listText";
private static final String NAME = "listText";
/**
* Function text field
*/
private final String IMAGE = "listIcon";
private static final String IMAGE = "listIcon";
/**
* Code of selected course
*/
@ -157,7 +159,8 @@ public class SWADMain extends MenuExpandableListActivity {
*/
@Override
public void onCreate(Bundle icicle) {
int lastVersion, currentVersion;
int lastVersion;
int currentVersion;
//Initialize screen
super.onCreate(icicle);
@ -282,7 +285,7 @@ public class SWADMain extends MenuExpandableListActivity {
SyncUtils.removePeriodicSync(Constants.AUTHORITY, Bundle.EMPTY, this);
if(!Preferences.getSyncTime().equals("0") && Preferences.isSyncEnabled()) {
SyncUtils.addPeriodicSync(Constants.AUTHORITY, Bundle.EMPTY,
Long.valueOf(Preferences.getSyncTime()), this);
Long.parseLong(Preferences.getSyncTime()), this);
}
}
@ -355,7 +358,7 @@ public class SWADMain extends MenuExpandableListActivity {
else
mCoursesSpinner.setSelection(0);
mCoursesSpinner.setOnTouchListener(Spinner_OnTouch);
mCoursesSpinner.setOnTouchListener(spinnerOnTouch);
mCoursesSpinner.setVisibility(View.VISIBLE);
Log.i(TAG, "Created Spinner adapter");
@ -370,7 +373,7 @@ public class SWADMain extends MenuExpandableListActivity {
private void cleanSpinner() {
ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, new String[]{getString(R.string.clickToGetCourses)});
mCoursesSpinner.setAdapter(adapter);
mCoursesSpinner.setOnTouchListener(Spinner_OnTouch);
mCoursesSpinner.setOnTouchListener(spinnerOnTouch);
Log.i(TAG, "Cleaned Spinner adapter");
}
@ -402,20 +405,17 @@ public class SWADMain extends MenuExpandableListActivity {
}
}
private final View.OnTouchListener Spinner_OnTouch = new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP) {
private final View.OnTouchListener spinnerOnTouch = (v, event) -> {
if (event.getAction() == MotionEvent.ACTION_UP) {
if (dbHelper.getAllRows(DataBaseHelper.DB_TABLE_COURSES).isEmpty()) {
if (Utils.connectionAvailable(getApplicationContext()))
getCurrentCourses();
} else {
v.performClick();
}
if (dbHelper.getAllRows(DataBaseHelper.DB_TABLE_COURSES).isEmpty()) {
if (Utils.connectionAvailable(getApplicationContext()))
getCurrentCourses();
} else {
v.performClick();
}
return true;
}
return true;
};
private void getCurrentCourses() {
@ -567,6 +567,8 @@ public class SWADMain extends MenuExpandableListActivity {
evaluationData.add(getMenuItem(R.string.assessmentModuleLabel, R.string.fa_info));
//Test
evaluationData.add(getMenuItem(R.string.testsModuleLabel, R.string.fa_check_square_o));
//Games
evaluationData.add(getMenuItem(R.string.gamesModuleLabel, R.string.fa_trophy));
//Files category
//Documents
@ -671,6 +673,11 @@ public class SWADMain extends MenuExpandableListActivity {
} else if (keyword.equals(getString(R.string.testsModuleLabel))) {
activity = new Intent(ctx, Tests.class);
startActivityForResult(activity, Constants.TESTS_REQUEST_CODE);
} else if (keyword.equals(getString(R.string.gamesModuleLabel))) {
activity = new Intent(ctx, GamesList.class);
startActivityForResult(activity, Constants.GAMES_REQUEST_CODE);
} else if (keyword.equals(getString(R.string.messagesModuleLabel))) {
activity = new Intent(ctx, Messages.class);
activity.putExtra("eventCode", Long.valueOf(0));

View File

@ -53,6 +53,8 @@ import es.ugr.swad.swadroid.model.TestQuestion;
import es.ugr.swad.swadroid.model.TestTag;
import es.ugr.swad.swadroid.model.User;
import es.ugr.swad.swadroid.model.UserAttendance;
import es.ugr.swad.swadroid.model.Game;
import es.ugr.swad.swadroid.model.Match;
import es.ugr.swad.swadroid.preferences.Preferences;
import es.ugr.swad.swadroid.utils.Crypto;
import es.ugr.swad.swadroid.utils.OldCrypto;
@ -64,6 +66,7 @@ import es.ugr.swad.swadroid.utils.Utils;
* @author Juan Miguel Boyero Corral <juanmi1982@gmail.com>
* @author Antonio Aguilera Malagon <aguilerin@gmail.com>
* @author Helena Rodriguez Gijon <hrgijon@gmail.com>
* @author Sergio Díaz Rueda <sergiodiazrueda8@gmail.com>
*/
public class DataBaseHelper {
/**
@ -146,6 +149,22 @@ public class DataBaseHelper {
* Table name for relationship between events and courses
*/
public static final String DB_TABLE_EVENTS_COURSES = "events_courses";
/**
* Table name for games
*/
public static final String DB_TABLE_GAMES = "games";
/**
* Table name for relationship between games and courses
*/
public static final String DB_TABLE_GAMES_COURSES = "games_courses";
/**
* Table name for matches
*/
public static final String DB_TABLE_MATCHES = "matches";
/**
* Table name for relationship between matches and games
*/
public static final String DB_TABLE_MATCHES_GAMES = "matches_games";
/**
* Table name for groups
*/
@ -271,6 +290,14 @@ public class DataBaseHelper {
firstParam = "eventCode";
secondParam = "crsCod";
break;
case DataBaseHelper.DB_TABLE_GAMES_COURSES:
firstParam = "gameCode";
secondParam = "crsCod";
break;
case DataBaseHelper.DB_TABLE_MATCHES_GAMES:
firstParam = "matchCode";
secondParam = "gamecode";
break;
default:
Log.e("selectParamsPairTable", "Table " + table + " not exists");
break;
@ -319,6 +346,22 @@ public class DataBaseHelper {
params = selectParamsPairTable(table);
o = new PairTable<>(table,
ent.getInt(params.getFirst()),
ent.getInt(params.getSecond()));
break;
case DataBaseHelper.DB_TABLE_GAMES_COURSES:
params = selectParamsPairTable(table);
o = new PairTable<>(table,
ent.getInt(params.getFirst()),
ent.getInt(params.getSecond()));
break;
case DataBaseHelper.DB_TABLE_MATCHES_GAMES:
params = selectParamsPairTable(table);
o = new PairTable<>(table,
ent.getInt(params.getFirst()),
ent.getInt(params.getSecond()));
@ -469,6 +512,32 @@ public class DataBaseHelper {
false,
ent.getDouble("score"));
break;
case DataBaseHelper.DB_TABLE_GAMES:
o = new Game(ent.getLong("id"),
crypto.decrypt(ent.getString("userSurname1")),
crypto.decrypt(ent.getString("userSurname2")),
crypto.decrypt(ent.getString("userFirstName")),
crypto.decrypt(ent.getString("userPhoto")),
ent.getLong("startTime"),
ent.getLong("endTime"),
crypto.decrypt(ent.getString("title")),
crypto.decrypt(ent.getString("text")),
ent.getInt("numQuestions"),
ent.getFloat("maxGrade"),
ent.getInt("visibility"));
break;
case DataBaseHelper.DB_TABLE_MATCHES:
o = new Match(ent.getLong("id"),
crypto.decrypt(ent.getString("userSurname1")),
crypto.decrypt(ent.getString("userSurname2")),
crypto.decrypt(ent.getString("userFirstName")),
crypto.decrypt(ent.getString("userPhoto")),
ent.getLong("startTime"),
ent.getLong("endTime"),
crypto.decrypt(ent.getString("title")),
ent.getInt("questionIndex"),
crypto.decrypt(ent.getString("groups")));
break;
}
return (T) o;
@ -737,6 +806,72 @@ public class DataBaseHelper {
+ " ORDER BY E.startTime DESC,E.endTime DESC,E.title DESC", null);
}
/**
* Gets the list of games related to the selected course
*
* @param crsCod Course code to be referenced
* @return A Cursor with a list of games related to the selected course
*/
public Cursor getGamesCourseCursor(long crsCod) {
return db.rawQuery("SELECT * FROM " + DB_TABLE_GAMES + " AS E"
+ " INNER JOIN " + DB_TABLE_GAMES_COURSES + " AS C"
+ " ON E.id = C.gameCode WHERE C.crsCod ='" + crsCod +"'"
+ " ORDER BY E.startTime DESC,E.endTime DESC,E.title DESC", null);
}
/**
* Gets the list of matches related to the selected game
*
* @param gameCode game code to be referenced
* @return A Cursor with a list of matches related to the selected game
*/
public Cursor getMatchesGameCursor(long gameCode) {
return db.rawQuery("SELECT * FROM " + DB_TABLE_MATCHES + " AS E"
+ " INNER JOIN " + DB_TABLE_MATCHES_GAMES + " AS C"
+ " ON E.id = C.matchCode WHERE C.gamecode ='" + gameCode +"'"
+ " ORDER BY E.startTime DESC,E.endTime DESC,E.title DESC", null);
}
/**
* Gets the list of games related to the selected course
*
* @param crsCod Course code to be referenced
* @return A list of Game
*/
public List<Game> getGamesCourse(long crsCod) {
List<Game> result = new ArrayList<>();
List<Entity> rows = db.getEntityList(DataBaseHelper.DB_TABLE_GAMES_COURSES,
"crsCod = '" + crsCod + "'");
if (rows != null) {
for (Entity ent : rows) {
result.add((Game) getRow(DataBaseHelper.DB_TABLE_GAMES,
"id", ent.getValue("gameCode")));
}
}
return result;
}
/**
* Gets the list of matches related to the selected game
*
* @param gameCode Course code to be referenced
* @return A list of Match
*/
public List<Match> getMatchesGame(long gameCode) {
List<Match> result = new ArrayList<>();
List<Entity> rows = db.getEntityList(DataBaseHelper.DB_TABLE_MATCHES_GAMES,
"gameCode = '" + gameCode + "'");
if (rows != null) {
for (Entity ent : rows) {
result.add((Match) getRow(DataBaseHelper.DB_TABLE_MATCHES,
"id", ent.getValue("matchCode")));
}
}
return result;
}
/**
* Gets the number of users related to the selected event
*
@ -1461,6 +1596,116 @@ public class DataBaseHelper {
return numElements;
}
/**
* Inserts a new record in database for a game,
* or updates it if already exists
*
* @param game Game to be inserted
*/
public void insertGame(Game game) {
Entity ent;
String where = "id = " + game.getId();
List<Entity> rows = db.getEntityList(DataBaseHelper.DB_TABLE_GAMES, where);
if (rows.isEmpty()) {
ent = new Entity(DataBaseHelper.DB_TABLE_GAMES);
} else {
ent = rows.get(0);
}
ent.setValue("id", game.getId());
ent.setValue("userSurname1", crypto.encrypt(game.getUserSurname1()));
ent.setValue("userSurname2", crypto.encrypt(game.getUserSurname2()));
ent.setValue("userFirstName", crypto.encrypt(game.getUserFirstName()));
ent.setValue("userPhoto", crypto.encrypt(game.getUserPhoto()));
ent.setValue("startTime", game.getStartTime());
ent.setValue("endTime", game.getEndTime());
ent.setValue("title", crypto.encrypt(game.getTitle()));
ent.setValue("text", crypto.encrypt(game.getText()));
ent.setValue("numQuestions", game.getNumQuestions());
ent.setValue("maxGrade", game.getMaxGrade());
ent.setValue("visibility", game.getVisibility());
ent.save();
}
/**
* Inserts a new record in database for a match,
* or updates it if already exists
*
* @param match Match to be inserted
*/
public void insertMatch(Match match) {
Entity ent;
String where = "id = " + match.getId();
List<Entity> rows = db.getEntityList(DataBaseHelper.DB_TABLE_MATCHES, where);
if (rows.isEmpty()) {
ent = new Entity(DataBaseHelper.DB_TABLE_MATCHES);
} else {
ent = rows.get(0);
}
ent.setValue("id", match.getId());
ent.setValue("userSurname1", crypto.encrypt(match.getUserSurname1()));
ent.setValue("userSurname2", crypto.encrypt(match.getUserSurname2()));
ent.setValue("userFirstName", crypto.encrypt(match.getUserFirstName()));
ent.setValue("userPhoto", crypto.encrypt(match.getUserPhoto()));
ent.setValue("startTime", match.getStartTime());
ent.setValue("endTime", match.getEndTime());
ent.setValue("title", crypto.encrypt(match.getTitle()));
ent.setValue("questionIndex", match.getQuestionIndex());
ent.setValue("groups", crypto.encrypt(match.getGroups()));
ent.save();
}
/**
* Inserts a new record in database for the relationship between an games and a course,
* or updates it if already exists
*
* @param gameCode Game code
* @param crsCod Course code
*/
public void insertGameCourse(long gameCode, long crsCod) {
Entity ent;
String where = "gameCode = " + gameCode + " AND crsCod = " + crsCod;
List<Entity> rows = db.getEntityList(DataBaseHelper.DB_TABLE_GAMES_COURSES, where);
if (rows.isEmpty()) {
ent = new Entity(DataBaseHelper.DB_TABLE_GAMES_COURSES);
} else {
ent = rows.get(0);
}
ent.setValue("gameCode", gameCode);
ent.setValue("crsCod", crsCod);
ent.save();
}
/**
* Inserts a new record in database for the relationship between an matches and a game,
* or updates it if already exists
*
* @param matchCode Match code
* @param gameCode Game code
*/
public void insertMatchGame(long matchCode, long gameCode) {
Entity ent;
String where = "matchCode = " + matchCode + " AND gameCode = " + gameCode;
List<Entity> rows = db.getEntityList(DataBaseHelper.DB_TABLE_MATCHES_GAMES, where);
if (rows.isEmpty()) {
ent = new Entity(DataBaseHelper.DB_TABLE_MATCHES_GAMES);
} else {
ent = rows.get(0);
}
ent.setValue("matchCode", matchCode);
ent.setValue("gameCode", gameCode);
ent.save();
}
/**
* Updates a course in database
*
@ -1835,6 +2080,32 @@ public class DataBaseHelper {
ent.save();
}
/**
* Updates a game in database
*
* @param gameCode Code of event to be updated
* @param status Event status to be updated
*/
public void updateGameStatus(int gameCode, String status) {
Entity ent = db.getTopEntity(DataBaseHelper.DB_TABLE_GAMES,
"id = " + gameCode, "1");
ent.setValue("status", crypto.encrypt(status));
ent.save();
}
/**
* Updates a match in database
*
* @param matchCode Code of event to be updated
* @param status Event status to be updated
*/
public void updateMatchStatus(int matchCode, String status) {
Entity ent = db.getTopEntity(DataBaseHelper.DB_TABLE_MATCHES,
"id = " + matchCode, "1");
ent.setValue("status", crypto.encrypt(status));
ent.save();
}
/**
* Updates a Group and the relationship between Groups and Courses
*

View File

@ -0,0 +1,348 @@
package es.ugr.swad.swadroid.model;
import org.ksoap2.serialization.PropertyInfo;
import java.util.Calendar;
import java.util.Hashtable;
/**
* Class for store a game
*
* @author Juan Miguel Boyero Corral <juanmi1982@gmail.com>
* @author Sergio Díaz Rueda <sergiodiazrueda8@gmail.com>
*/
public class Game extends Model {
private String userSurname1;
private String userSurname2;
private String userFirstName;
private String userPhoto;
private long startTime;
private long endTime;
private String title;
private String text;
private int numQuestions;
private float maxGrade;
private int visibility;
private static final PropertyInfo PI_id = new PropertyInfo();
private static final PropertyInfo PI_userSurname1 = new PropertyInfo();
private static final PropertyInfo PI_userSurname2 = new PropertyInfo();
private static final PropertyInfo PI_userFirstName = new PropertyInfo();
private static final PropertyInfo PI_userPhoto = new PropertyInfo();
private static final PropertyInfo PI_startTime = new PropertyInfo();
private static final PropertyInfo PI_endTime = new PropertyInfo();
private static final PropertyInfo PI_title = new PropertyInfo();
private static final PropertyInfo PI_text = new PropertyInfo();
private static final PropertyInfo PI_numQuestions = new PropertyInfo();
private static final PropertyInfo PI_maxGrade = new PropertyInfo();
private static final PropertyInfo PI_visibility = new PropertyInfo();
private static final PropertyInfo[] PI_PROP_ARRAY =
{
PI_id,
PI_userSurname1,
PI_userSurname2,
PI_userFirstName,
PI_userPhoto,
PI_startTime,
PI_endTime,
PI_title,
PI_text,
PI_numQuestions,
PI_maxGrade,
PI_visibility
};
/**
* Constructor
*/
public Game(long gameCode, String userSurname1, String userSurname2,
String userFirstName, String userPhoto, long startTime, long endTime,
String title, String text, int numQuestions, float maxGrade, int visibility) {
super(gameCode);
this.userSurname1 = userSurname1;
this.userSurname2 = userSurname2;
this.userFirstName = userFirstName;
this.userPhoto = userPhoto;
this.startTime = startTime;
this.endTime = endTime;
this.title = title;
this.text = text;
this.numQuestions = numQuestions;
this.maxGrade = maxGrade;
this.visibility = visibility;
}
public String getUserSurname1() {
return userSurname1;
}
public void setUserSurname1(String userSurname1) {
this.userSurname1 = userSurname1;
}
public String getUserSurname2() {
return userSurname2;
}
public void setUserSurname2(String userSurname2) {
this.userSurname2 = userSurname2;
}
public String getUserFirstName() {
return userFirstName;
}
public void setUserFirstName(String userFirstName) {
this.userFirstName = userFirstName;
}
public String getUserPhoto() {
return userPhoto;
}
public void setUserPhoto(String userPhoto) {
this.userPhoto = userPhoto;
}
public long getStartTime() {
return startTime;
}
public void setStartTime(long startTime) {
this.startTime = startTime;
}
public long getEndTime() {
return endTime;
}
public void setEndTime(long endTime) {
this.endTime = endTime;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public int getNumQuestions() {
return numQuestions;
}
public void setNumQuestions(int numQuestions) {
this.numQuestions = numQuestions;
}
public float getMaxGrade() {
return maxGrade;
}
public void setMaxGrade(float maxGrade) {
this.maxGrade = maxGrade;
}
public float getVisibility() {
return visibility;
}
public void setVisibility(int visibility) {
this.visibility = visibility;
}
public Calendar getStartTimeCalendar() {
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(startTime * 1000L);
return calendar;
}
public Calendar getEndTimeCalendar() {
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(endTime * 1000L);
return calendar;
}
/* (non-Javadoc)
* @see org.ksoap2.serialization.KvmSerializable#getProperty(int)
*/
public Object getProperty(int param) {
Object object = null;
switch (param) {
case 0:
object = this.getId();
break;
case 1:
object = userSurname1;
break;
case 2:
object = userSurname2;
break;
case 3:
object = userFirstName;
break;
case 4:
object = userPhoto;
break;
case 5:
object = startTime;
break;
case 6:
object = endTime;
break;
case 7:
object = title;
break;
case 8:
object = text;
break;
case 9:
object = numQuestions;
break;
case 10:
object = maxGrade;
break;
case 11:
object = visibility;
break;
}
return object;
}
/* (non-Javadoc)
* @see org.ksoap2.serialization.KvmSerializable#getPropertyCount()
*/
public int getPropertyCount() {
return PI_PROP_ARRAY.length;
}
/* (non-Javadoc)
* @see org.ksoap2.serialization.KvmSerializable#getPropertyInfo(int, java.util.Hashtable, org.ksoap2.serialization.PropertyInfo)
*/
public void getPropertyInfo(int param, @SuppressWarnings("rawtypes")
Hashtable arg1, PropertyInfo propertyInfo) {
switch (param) {
case 0:
propertyInfo.type = PropertyInfo.LONG_CLASS;
propertyInfo.name = "gameCode";
break;
case 1:
propertyInfo.type = PropertyInfo.STRING_CLASS;
propertyInfo.name = "userSurname1";
break;
case 2:
propertyInfo.type = PropertyInfo.STRING_CLASS;
propertyInfo.name = "userSurname2";
break;
case 3:
propertyInfo.type = PropertyInfo.STRING_CLASS;
propertyInfo.name = "userFirstName";
break;
case 4:
propertyInfo.type = PropertyInfo.STRING_CLASS;
propertyInfo.name = "userPhoto";
break;
case 5:
propertyInfo.type = PropertyInfo.LONG_CLASS;
propertyInfo.name = "startTime";
break;
case 6:
propertyInfo.type = PropertyInfo.LONG_CLASS;
propertyInfo.name = "endTime";
break;
case 7:
propertyInfo.type = PropertyInfo.STRING_CLASS;
propertyInfo.name = "title";
break;
case 8:
propertyInfo.type = PropertyInfo.STRING_CLASS;
propertyInfo.name = "text";
break;
case 9:
propertyInfo.type = PropertyInfo.INTEGER_CLASS;
propertyInfo.name = "numQuestions";
break;
case 10:
propertyInfo.type = PropertyInfo.LONG_CLASS;
propertyInfo.name = "maxGrade";
break;
case 11:
propertyInfo.type = PropertyInfo.INTEGER_CLASS;
propertyInfo.name = "visibility";
break;
}
}
/* (non-Javadoc)
* @see org.ksoap2.serialization.KvmSerializable#setProperty(int, java.lang.Object)
*/
public void setProperty(int param, Object obj) {
switch (param) {
case 0:
this.setId((Long) obj);
break;
case 1:
userSurname1 = (String) obj;
break;
case 2:
userSurname2 = (String) obj;
break;
case 3:
userFirstName = (String) obj;
break;
case 4:
userPhoto = (String) obj;
break;
case 5:
startTime = (Long) obj;
break;
case 6:
endTime = (Long) obj;
break;
case 7:
title = (String) obj;
break;
case 8:
text = (String) obj;
break;
case 9:
numQuestions = (int) obj;
break;
case 10:
maxGrade = (Float) obj;
break;
case 11:
visibility = (int) obj;
break;
}
}
@Override
public String toString() {
return "Game{" +
", userSurname1='" + userSurname1 + '\'' +
", userSurname2='" + userSurname2 + '\'' +
", userFirstName='" + userFirstName + '\'' +
", userPhoto='" + userPhoto + '\'' +
", startTime=" + startTime +
", endTime=" + endTime +
", title='" + title + '\'' +
", text='" + text + '\'' +
", numQuestions='" + numQuestions + '\'' +
", maxGrade='" + maxGrade + '\'' +
", visibility='" + visibility + '\'' +
"} " + super.toString();
}
}

View File

@ -0,0 +1,304 @@
package es.ugr.swad.swadroid.model;
import org.ksoap2.serialization.PropertyInfo;
import java.util.Calendar;
import java.util.Hashtable;
/**
* Class for store a match
*
* @author Juan Miguel Boyero Corral <juanmi1982@gmail.com>
* @author Sergio Díaz Rueda <sergiodiazrueda8@gmail.com>
*/
public class Match extends Model {
private String userSurname1;
private String userSurname2;
private String userFirstName;
private String userPhoto;
private long startTime;
private long endTime;
private String title;
private int questionIndex;
private String groups;
private static final PropertyInfo PI_id = new PropertyInfo();
private static final PropertyInfo PI_userSurname1 = new PropertyInfo();
private static final PropertyInfo PI_userSurname2 = new PropertyInfo();
private static final PropertyInfo PI_userFirstName = new PropertyInfo();
private static final PropertyInfo PI_userPhoto = new PropertyInfo();
private static final PropertyInfo PI_startTime = new PropertyInfo();
private static final PropertyInfo PI_endTime = new PropertyInfo();
private static final PropertyInfo PI_title = new PropertyInfo();
private static final PropertyInfo PI_questionIndex = new PropertyInfo();
private static final PropertyInfo PI_groups = new PropertyInfo();
private static final PropertyInfo[] PI_PROP_ARRAY =
{
PI_id,
PI_userSurname1,
PI_userSurname2,
PI_userFirstName,
PI_userPhoto,
PI_startTime,
PI_endTime,
PI_title,
PI_questionIndex,
PI_groups
};
/**
* Constructor
*/
public Match(long matchCode, String userSurname1, String userSurname2,
String userFirstName, String userPhoto, long startTime, long endTime,
String title, int questionIndex, String groups) {
super(matchCode);
this.userSurname1 = userSurname1;
this.userSurname2 = userSurname2;
this.userFirstName = userFirstName;
this.userPhoto = userPhoto;
this.startTime = startTime;
this.endTime = endTime;
this.title = title;
this.questionIndex = questionIndex;
this.groups = groups;
}
public String getUserSurname1() {
return userSurname1;
}
public void setUserSurname1(String userSurname1) {
this.userSurname1 = userSurname1;
}
public String getUserSurname2() {
return userSurname2;
}
public void setUserSurname2(String userSurname2) {
this.userSurname2 = userSurname2;
}
public String getUserFirstName() {
return userFirstName;
}
public void setUserFirstName(String userFirstName) {
this.userFirstName = userFirstName;
}
public String getUserPhoto() {
return userPhoto;
}
public void setUserPhoto(String userPhoto) {
this.userPhoto = userPhoto;
}
public long getStartTime() {
return startTime;
}
public void setStartTime(long startTime) {
this.startTime = startTime;
}
public long getEndTime() {
return endTime;
}
public void setEndTime(long endTime) {
this.endTime = endTime;
}
public Calendar getStartTimeCalendar() {
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(startTime * 1000L);
return calendar;
}
public Calendar getEndTimeCalendar() {
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(endTime * 1000L);
return calendar;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public int getQuestionIndex() {
return questionIndex;
}
public void setQuestionIndex(int questionIndex) {
this.questionIndex = questionIndex;
}
public String getGroups() {
return groups;
}
public void setGroups(String groups) {
this.groups = groups;
}
/* (non-Javadoc)
* @see org.ksoap2.serialization.KvmSerializable#getProperty(int)
*/
public Object getProperty(int param) {
Object object = null;
switch (param) {
case 0:
object = this.getId();
break;
case 1:
object = userSurname1;
break;
case 2:
object = userSurname2;
break;
case 3:
object = userFirstName;
break;
case 4:
object = userPhoto;
break;
case 5:
object = startTime;
break;
case 6:
object = endTime;
break;
case 7:
object = title;
break;
case 8:
object = questionIndex;
break;
case 9:
object = groups;
break;
}
return object;
}
/* (non-Javadoc)
* @see org.ksoap2.serialization.KvmSerializable#getPropertyCount()
*/
public int getPropertyCount() {
return PI_PROP_ARRAY.length;
}
/* (non-Javadoc)
* @see org.ksoap2.serialization.KvmSerializable#getPropertyInfo(int, java.util.Hashtable, org.ksoap2.serialization.PropertyInfo)
*/
public void getPropertyInfo(int param, @SuppressWarnings("rawtypes")
Hashtable arg1, PropertyInfo propertyInfo) {
switch (param) {
case 0:
propertyInfo.type = PropertyInfo.LONG_CLASS;
propertyInfo.name = "matchCode";
break;
case 1:
propertyInfo.type = PropertyInfo.STRING_CLASS;
propertyInfo.name = "userSurname1";
break;
case 2:
propertyInfo.type = PropertyInfo.STRING_CLASS;
propertyInfo.name = "userSurname2";
break;
case 3:
propertyInfo.type = PropertyInfo.STRING_CLASS;
propertyInfo.name = "userFirstName";
break;
case 4:
propertyInfo.type = PropertyInfo.STRING_CLASS;
propertyInfo.name = "userPhoto";
break;
case 5:
propertyInfo.type = PropertyInfo.LONG_CLASS;
propertyInfo.name = "startTime";
break;
case 6:
propertyInfo.type = PropertyInfo.LONG_CLASS;
propertyInfo.name = "endTime";
break;
case 7:
propertyInfo.type = PropertyInfo.STRING_CLASS;
propertyInfo.name = "title";
break;
case 8:
propertyInfo.type = PropertyInfo.INTEGER_CLASS;
propertyInfo.name = "questionsIndex";
break;
case 9:
propertyInfo.type = PropertyInfo.STRING_CLASS;
propertyInfo.name = "groups";
break;
}
}
/* (non-Javadoc)
* @see org.ksoap2.serialization.KvmSerializable#setProperty(int, java.lang.Object)
*/
public void setProperty(int param, Object obj) {
switch (param) {
case 0:
this.setId((Long) obj);
break;
case 1:
userSurname1 = (String) obj;
break;
case 2:
userSurname2 = (String) obj;
break;
case 3:
userFirstName = (String) obj;
break;
case 4:
userPhoto = (String) obj;
break;
case 5:
startTime = (Long) obj;
break;
case 6:
endTime = (Long) obj;
break;
case 7:
title = (String) obj;
break;
case 8:
questionIndex = (int) obj;
break;
case 9:
groups = (String) obj;
break;
}
}
@Override
public String toString() {
return "Match{" +
", userSurname1='" + userSurname1 + '\'' +
", userSurname2='" + userSurname2 + '\'' +
", userFirstName='" + userFirstName + '\'' +
", userPhoto='" + userPhoto + '\'' +
", startTime=" + startTime +
", endTime=" + endTime +
", title='" + title + '\'' +
", questionsIndex='" + questionIndex + '\'' +
", groups='" + groups + '\'' +
"} " + super.toString();
}
}

View File

@ -0,0 +1,80 @@
package es.ugr.swad.swadroid.model;
import org.ksoap2.serialization.PropertyInfo;
import java.util.Hashtable;
/**
* Class for store a matchAnswer
*
* @author Juan Miguel Boyero Corral <juanmi1982@gmail.com>
* @author Sergio Díaz Rueda <sergiodiazrueda8@gmail.com>
*/
public class MatchAnswer extends Model{
private static final PropertyInfo PI_id = new PropertyInfo();
private static final PropertyInfo[] PI_PROP_ARRAY =
{
PI_id
};
/**
* Constructor
*/
public MatchAnswer(long matchCode) {
super(matchCode);
}
/* (non-Javadoc)
* @see org.ksoap2.serialization.KvmSerializable#getProperty(int)
*/
public Object getProperty(int param) {
Object object = null;
switch (param) {
case 0:
object = this.getId();
break;
}
return object;
}
/* (non-Javadoc)
* @see org.ksoap2.serialization.KvmSerializable#getPropertyCount()
*/
public int getPropertyCount() {
return PI_PROP_ARRAY.length;
}
/* (non-Javadoc)
* @see org.ksoap2.serialization.KvmSerializable#getPropertyInfo(int, java.util.Hashtable, org.ksoap2.serialization.PropertyInfo)
*/
public void getPropertyInfo(int param, @SuppressWarnings("rawtypes")
Hashtable arg1, PropertyInfo propertyInfo) {
switch (param) {
case 0:
propertyInfo.type = PropertyInfo.LONG_CLASS;
propertyInfo.name = "matchCode";
break;
}
}
/* (non-Javadoc)
* @see org.ksoap2.serialization.KvmSerializable#setProperty(int, java.lang.Object)
*/
public void setProperty(int param, Object obj) {
switch (param) {
case 0:
this.setId((Long) obj);
break;
}
}
@Override
public String toString() {
return "MatchAnswer{" +
"} " + super.toString();
}
}

View File

@ -0,0 +1,147 @@
package es.ugr.swad.swadroid.model;
import org.ksoap2.serialization.PropertyInfo;
import java.util.Hashtable;
/**
* Class for store a matchStatus
*
* @author Juan Miguel Boyero Corral <juanmi1982@gmail.com>
* @author Sergio Díaz Rueda <sergiodiazrueda8@gmail.com>
*/
public class MatchStatus extends Model{
private int questionIndex;
private int numQuestions;
private int answerIndex;
private static final PropertyInfo PI_id = new PropertyInfo();
private static final PropertyInfo PI_questionIndex = new PropertyInfo();
private static final PropertyInfo PI_numQuestions = new PropertyInfo();
private static final PropertyInfo PI_answerIndex = new PropertyInfo();
private static final PropertyInfo[] PI_PROP_ARRAY =
{
PI_id,
PI_questionIndex,
PI_numQuestions,
PI_answerIndex
};
/**
* Constructor
*/
public MatchStatus(long matchCode, int questionIndex, int numQuestions,
int answerIndex) {
super(matchCode);
this.questionIndex = questionIndex;
this.numQuestions = numQuestions;
this.answerIndex = answerIndex;
}
public int getQuestionIndex() {
return questionIndex;
}
public void setQuestionIndex(int questionIndex) {
this.questionIndex = questionIndex;
}
public int getNumQuestion() {
return numQuestions;
}
public void setNumQuestions(int numQuestions) {
this.numQuestions = numQuestions;
}
public int getAnswerIndex() {
return answerIndex;
}
public void setAnswerIndex(int selected) {
this.answerIndex = answerIndex;
}
/* (non-Javadoc)
* @see org.ksoap2.serialization.KvmSerializable#getProperty(int)
*/
public Object getProperty(int param) {
Object object = null;
switch (param) {
case 0:
object = this.getId();
break;
case 1:
object = questionIndex;
break;
case 2:
object = numQuestions;
break;
case 3:
object = answerIndex;
break;
}
return object;
}
/* (non-Javadoc)
* @see org.ksoap2.serialization.KvmSerializable#getPropertyCount()
*/
public int getPropertyCount() {
return PI_PROP_ARRAY.length;
}
/* (non-Javadoc)
* @see org.ksoap2.serialization.KvmSerializable#getPropertyInfo(int, java.util.Hashtable, org.ksoap2.serialization.PropertyInfo)
*/
public void getPropertyInfo(int param, @SuppressWarnings("rawtypes")
Hashtable arg1, PropertyInfo propertyInfo) {
switch (param) {
case 0:
propertyInfo.type = PropertyInfo.LONG_CLASS;
propertyInfo.name = "matchCode";
break;
case 1:
propertyInfo.type = PropertyInfo.INTEGER_CLASS;
propertyInfo.name = "questionIndex";
break;
case 2:
propertyInfo.type = PropertyInfo.INTEGER_CLASS;
propertyInfo.name = "numQuestions";
break;
case 3:
propertyInfo.type = PropertyInfo.INTEGER_CLASS;
propertyInfo.name = "answerIndex";
break;
}
}
/* (non-Javadoc)
* @see org.ksoap2.serialization.KvmSerializable#setProperty(int, java.lang.Object)
*/
public void setProperty(int param, Object obj) {
switch (param) {
case 0:
this.setId((Long) obj);
break;
case 1:
questionIndex = (int) obj;
break;
case 2:
numQuestions = (int) obj;
break;
case 3:
answerIndex = (int) obj;
break;
}
}
@Override
public String toString() {
return "MatchStatus{" +
", questionIndex='" + questionIndex + '\'' +
", numQuestions='" + numQuestions + '\'' +
", selected='" + answerIndex + '\'' +
"} " + super.toString();
}
}

View File

@ -0,0 +1,157 @@
package es.ugr.swad.swadroid.modules.games;
import android.content.Context;
import android.database.Cursor;
import android.graphics.Typeface;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CursorAdapter;
import android.widget.TextView;
import androidx.core.content.ContextCompat;
import java.text.DateFormat;
import java.util.Calendar;
import es.ugr.swad.swadroid.R;
import es.ugr.swad.swadroid.database.DataBaseHelper;
import es.ugr.swad.swadroid.gui.FontManager;
import es.ugr.swad.swadroid.utils.Crypto;
/**
* Abstract CursorAdapter for display games
*
* @author Juan Miguel Boyero Corral <juanmi1982@gmail.com>
* @author Sergio Díaz Rueda <sergiodiazrueda8@gmail.com>
*/
public abstract class AbstractGamesCursorAdapter extends CursorAdapter {
private final Crypto crypto;
private final Cursor cursor;
private final DateFormat df;
private final LayoutInflater inflater;
protected final DataBaseHelper dbHelper;
private final Typeface iconFont;
private static class ViewHolder {
TextView iconTextView;
TextView titleTextView;
TextView startTimeTextView;
TextView endTimeTextView;
}
/**
* Checks if a game is finished
*
* @param gameCode id of the game
* @return true if the game is finished, false otherwise
*/
protected abstract boolean isFinished(long gameCode);
/**
* Constructor
*
* @param context Application context
* @param c Database cursor
* @param dbHelper Database helper
*/
public AbstractGamesCursorAdapter(Context context, Cursor c, DataBaseHelper dbHelper) {
super(context, c, true);
this.cursor = c;
this.crypto = new Crypto(context, dbHelper.getDBKey());
this.df = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.SHORT);
this.inflater = LayoutInflater.from(context);
this.dbHelper = dbHelper;
//Get Font Awesome typeface
iconFont = FontManager.getTypeface(context, FontManager.FONTAWESOME);
}
/**
* Constructor
*
* @param context Application context
* @param c Database cursor
* @param autoRequery Flag to set autoRequery function
* @param dbHelper Database helper
*/
public AbstractGamesCursorAdapter(Context context, Cursor c,
boolean autoRequery, DataBaseHelper dbHelper) {
super(context, c, autoRequery);
this.cursor = c;
this.crypto = new Crypto(context, dbHelper.getDBKey());
this.df = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.SHORT);
this.inflater = LayoutInflater.from(context);
this.dbHelper = dbHelper;
//Get Font Awesome typeface
iconFont = FontManager.getTypeface(context, FontManager.FONTAWESOME);
}
@Override
public void bindView(View view, final Context context, Cursor cursor) {
long id = cursor.getLong(cursor.getColumnIndex("id"));
long startTime = cursor.getLong(cursor.getColumnIndex("startTime"));
long endTime = cursor.getLong(cursor.getColumnIndex("endTime"));
String title = crypto.decrypt(cursor.getString(cursor.getColumnIndex("title")));
Calendar startTimeCalendar = Calendar.getInstance();
Calendar endTimeCalendar = Calendar.getInstance();
startTimeCalendar.setTimeInMillis(startTime * 1000L);
endTimeCalendar.setTimeInMillis(endTime * 1000L);
ViewHolder holder = (ViewHolder) view.getTag();
view.setTag(holder);
holder.iconTextView = (TextView) view.findViewById(R.id.icon);
holder.iconTextView.setText(R.string.fa_check_square_o);
//Set Font Awesome typeface
holder.iconTextView.setTypeface(iconFont);
holder.titleTextView = (TextView) view.findViewById(R.id.toptext);
holder.startTimeTextView = (TextView) view.findViewById(R.id.startTimeTextView);
holder.endTimeTextView = (TextView) view.findViewById(R.id.endTimeTextView);
holder.titleTextView.setText(title);
holder.startTimeTextView.setText(df.format(startTimeCalendar.getTime()));
holder.endTimeTextView.setText(df.format(endTimeCalendar.getTime()));
//If the game is not finished yet, show dates in green, else show in red
if (isFinished(id)) {
holder.startTimeTextView.setTextColor(ContextCompat.getColor(context, R.color.red));
holder.endTimeTextView.setTextColor(ContextCompat.getColor(context, R.color.red));
} else {
holder.startTimeTextView.setTextColor(ContextCompat.getColor(context, R.color.green));
holder.endTimeTextView.setTextColor(ContextCompat.getColor(context, R.color.green));
}
}
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
View view = inflater.inflate(R.layout.game_list_item, parent, false);
ViewHolder holder = new ViewHolder();
holder.titleTextView = (TextView) view.findViewById(R.id.toptext);
holder.startTimeTextView = (TextView) view.findViewById(R.id.startTimeTextView);
holder.endTimeTextView = (TextView) view.findViewById(R.id.endTimeTextView);
view.setTag(holder);
return view;
}
@Override
public long getItemId(int position) {
if (cursor != null && cursor.moveToPosition(position)) {
return cursor.getLong(cursor.getColumnIndex("id"));
} else {
return 0;
}
}
}

View File

@ -0,0 +1,176 @@
package es.ugr.swad.swadroid.modules.games;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;
import org.ksoap2.serialization.SoapObject;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
import es.ugr.swad.swadroid.Constants;
import es.ugr.swad.swadroid.R;
import es.ugr.swad.swadroid.database.DataBaseHelper;
import es.ugr.swad.swadroid.model.Game;
import es.ugr.swad.swadroid.modules.Module;
import es.ugr.swad.swadroid.modules.courses.Courses;
import es.ugr.swad.swadroid.modules.login.Login;
import es.ugr.swad.swadroid.webservices.SOAPClient;
/**
* Games download module.
*
* @author Juan Miguel Boyero Corral <juanmi1982@gmail.com>
* @author Sergio Díaz Rueda <sergiodiazrueda8@gmail.com>
* @see <a href="https://openswad.org/ws/#getGames">getGames</a>
*/
public class Games extends Module {
/**
* Games tag name for Logcat
*/
private static final String TAG = Constants.APP_TAG + " Games";
/**
* Number of games associated to the selected course
*/
private int numGames;
/**
* List of downloaded game codes
*/
private List<Long> gameCodes;
/* (non-Javadoc)
* @see es.ugr.swad.swadroid.modules.Module#onCreate(android.os.Bundle)
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setMETHOD_NAME("getGames");
getSupportActionBar().hide();
}
/* (non-Javadoc)
* @see es.ugr.swad.swadroid.modules.Module#onStart()
*/
@Override
protected void onStart() {
super.onStart();
try {
if (isDebuggable) {
Log.d(TAG, "selectedCourseCode = " +
Courses.getSelectedCourseCode());
}
runConnection();
} catch (Exception e) {
String errorMsg = getString(R.string.errorServerResponseMsg);
error(errorMsg, e);
}
}
/* (non-Javadoc)
* @see es.ugr.swad.swadroid.modules.Module#requestService()
*/
@Override
protected void requestService() throws Exception {
long courseCode = Courses.getSelectedCourseCode();
//Creates webservice request, adds required params and sends request to webservice
createRequest(SOAPClient.CLIENT_TYPE);
addParam("wsKey", Login.getLoggedUser().getWsKey());
addParam("courseCode", (int) courseCode);
sendRequest(Game.class, false);
gameCodes = new ArrayList<>();
if (result != null) {
//Stores tests data returned by webservice response
List<Object> res = new ArrayList<>((Vector<?>) result);
SoapObject soap = (SoapObject) res.get(1);
numGames = soap.getPropertyCount();
for (int i = 0; i < numGames; i++) {
SoapObject pii = (SoapObject) soap.getProperty(i);
long gameCode = Long.parseLong(pii.getProperty("gameCode").toString());
String userSurname1 = pii.getProperty("userSurname1").toString();
String userSurname2 = pii.getProperty("userSurname2").toString();
String userFirstName = pii.getProperty("userFirstname").toString();
String userPhoto = pii.getProperty("userPhoto").toString();
long startTime = Long.parseLong(pii.getProperty("startTime").toString());
long endTime = Long.parseLong(pii.getProperty("endTime").toString());
String title = pii.getProperty("title").toString();
String text = pii.getProperty("text").toString();
int numQuestions = Integer.parseInt(pii.getProperty("numQuestions").toString());
float maxGrade = Float.parseFloat(pii.getProperty("maxGrade").toString());
int visibility = Integer.parseInt(pii.getPrimitiveProperty("visibility").toString());
if (userSurname1.equalsIgnoreCase(Constants.NULL_VALUE)) userSurname1 = "";
if (userSurname2.equalsIgnoreCase(Constants.NULL_VALUE)) userSurname2 = "";
if (userFirstName.equalsIgnoreCase(Constants.NULL_VALUE)) userFirstName = "";
if (userPhoto.equalsIgnoreCase(Constants.NULL_VALUE)) userPhoto = "";
if (title.equalsIgnoreCase(Constants.NULL_VALUE)) title = "";
if (text.equalsIgnoreCase(Constants.NULL_VALUE)) text = "";
//Inserts or updates games into database
dbHelper.insertGame(new Game(gameCode, userSurname1, userSurname2,
userFirstName, userPhoto, startTime, endTime,
title, text, numQuestions, maxGrade, visibility));
dbHelper.insertGameCourse(gameCode, courseCode);
gameCodes.add(gameCode);
}
removeOldGames();
Log.i(TAG, "Retrieved " + numGames + " games");
}
// Request finalized without errors
setResult(RESULT_OK);
}
@Override
protected void connect() {
startConnection();
}
@Override
protected void postConnect() {
if (numGames == 0) {
Toast.makeText(this, R.string.noGamesAvailableMsg,
Toast.LENGTH_LONG).show();
} else {
String msg = numGames + " " +
getResources().getString(R.string.gamesUpdated);
Toast.makeText(this, msg, Toast.LENGTH_LONG).show();
}
finish();
}
@Override
protected void onError() {
}
private void removeOldGames() {
List<Game> dbGames = dbHelper.getGamesCourse(Courses.getSelectedCourseCode());
int nGamesRemoved = 0;
if ((dbGames != null) && (!dbGames.isEmpty())) {
for (Game g : dbGames) {
if (!gameCodes.contains(g.getId())) {
dbHelper.removeAllRows(DataBaseHelper.DB_TABLE_GAMES_COURSES,
"gameCode", g.getId());
dbHelper.removeAllRows(DataBaseHelper.DB_TABLE_GAMES,
"id", g.getId());
nGamesRemoved++;
}
}
}
Log.i(TAG, "Removed " + nGamesRemoved + " games");
}
}

View File

@ -0,0 +1,35 @@
package es.ugr.swad.swadroid.modules.games;
import android.content.Context;
import android.database.Cursor;
import java.util.List;
import es.ugr.swad.swadroid.Constants;
import es.ugr.swad.swadroid.database.DataBaseHelper;
import es.ugr.swad.swadroid.model.Match;
/**
* Custom CursorAdapter for display games
*
* @author Juan Miguel Boyero Corral <juanmi1982@gmail.com>
*/
public class GamesCursorAdapter extends AbstractGamesCursorAdapter {
public GamesCursorAdapter(Context context, Cursor c, DataBaseHelper dbHelper) {
super(context, c, dbHelper);
}
public GamesCursorAdapter(Context context, Cursor c, boolean autoRequery, DataBaseHelper dbHelper) {
super(context, c, autoRequery, dbHelper);
}
@Override
protected boolean isFinished(long gameCode) {
List<Match> matchesList = dbHelper.getMatchesGame(gameCode);
return matchesList.stream().allMatch(m -> m.getQuestionIndex() > Constants.MAX_NUM_QUESTIONS_GAMES);
}
}

View File

@ -0,0 +1,284 @@
package es.ugr.swad.swadroid.modules.games;
import android.annotation.TargetApi;
import android.app.AlertDialog;
import android.content.Intent;
import android.database.Cursor;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.TextView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import java.lang.ref.WeakReference;
import es.ugr.swad.swadroid.Constants;
import es.ugr.swad.swadroid.R;
import es.ugr.swad.swadroid.gui.DialogFactory;
import es.ugr.swad.swadroid.gui.MenuExpandableListActivity;
import es.ugr.swad.swadroid.gui.ProgressScreen;
import es.ugr.swad.swadroid.modules.courses.Courses;
/**
* Games List module.
*
* @author Juan Miguel Boyero Corral <juanmi1982@gmail.com>
* @author Sergio Díaz Rueda <sergiodiazrueda8@gmail.com>
*/
public class GamesList extends MenuExpandableListActivity
implements SwipeRefreshLayout.OnRefreshListener {
/**
* GamesActiveList tag name for Logcat
*/
private static final String TAG = Constants.APP_TAG + " GamesActiveList";
/**
* ListView of games
*/
private ListView lvGames;
/**
* Adapter for ListView of games
*/
private GamesCursorAdapter adapter;
/**
* Handler for games
*/
private final GamesList.RefreshAdapterHandler mHandler =
new GamesList.RefreshAdapterHandler(this);
private final Runnable mRunnable = new Runnable() {
@Override
public void run() {
/*
Database cursor for Adapter of games
*/
Cursor dbCursor = dbHelper.getGamesCourseCursor(Courses.getSelectedCourseCode());
startManagingCursor(dbCursor);
/*
* If there aren't games to show, hide the games lvGames
* and show the empty games message
*/
if ((dbCursor == null) || (dbCursor.getCount() == 0)) {
Log.d(TAG, "Games list is empty");
emptyGamesTextView.setText(R.string.gamesEmptyListMsg);
emptyGamesTextView.setVisibility(View.VISIBLE);
lvGames.setVisibility(View.GONE);
} else {
Log.d(TAG, "Games list is not empty");
emptyGamesTextView.setVisibility(View.GONE);
lvGames.setVisibility(View.VISIBLE);
}
adapter = new GamesCursorAdapter(getBaseContext(), dbCursor, dbHelper);
lvGames.setAdapter(adapter);
mProgressScreen.hide();
}
};
/**
* TextView for the empty games message
*/
private TextView emptyGamesTextView;
/**
* Layout with "Pull to refresh" function
*/
private SwipeRefreshLayout refreshLayout;
/**
* Progress screen
*/
private ProgressScreen mProgressScreen;
/**
* ListView click listener
*/
private final ListView.OnItemClickListener clickListener = new ListView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
mProgressScreen.show();
Intent activity = new Intent(getApplicationContext(),
Matches.class);
activity.putExtra("gameCode", adapter.getItemId(position));
startActivityForResult(activity, Constants.MATCHES_ACTIVE_DOWNLOAD_CODE);
}
};
/* (non-Javadoc)
* @see es.ugr.swad.swadroid.MenuExpandableListActivity#onCreate(android.os.Bundle)
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.list_items_pulltorefresh);
refreshLayout = findViewById(R.id.swipe_container_list);
emptyGamesTextView = findViewById(R.id.list_item_title);
View mProgressScreenView = findViewById(R.id.progress_screen);
mProgressScreen = new ProgressScreen(mProgressScreenView, refreshLayout,
getString(R.string.loadingMsg), this);
lvGames = findViewById(R.id.list_pulltorefresh);
lvGames.setOnItemClickListener(clickListener);
lvGames.setOnScrollListener(new AbsListView.OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView absListView, int scrollState) {
}
@Override
public void onScroll(AbsListView absListView, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
boolean enable = true;
if ((lvGames != null) && (lvGames.getChildCount() > 0)) {
// check if the first item of the list is visible
boolean firstItemVisible = lvGames.getFirstVisiblePosition() == 0;
// check if the top of the first item is visible
boolean topOfFirstItemVisible = lvGames.getChildAt(0).getTop() == 0;
// enabling or disabling the refresh layout
enable = firstItemVisible && topOfFirstItemVisible;
}
refreshLayout.setEnabled(enable);
}
});
refreshLayout.setOnRefreshListener(this);
setAppearance();
getSupportActionBar().setSubtitle(Courses.getSelectedCourseShortName());
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
/* (non-Javadoc)
* @see es.ugr.swad.swadroid.MenuExpandableListActivity#Override(android.os.Bundle)
*/
@Override
protected void onStart() {
super.onStart();
refreshAdapter();
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
switch (requestCode) {
case Constants.MATCHES_ACTIVE_DOWNLOAD_CODE:
mProgressScreen.hide();
Intent activity;
activity = new Intent(getApplicationContext(), MatchesList.class);
activity.putExtra("gameCode", Long.parseLong(intent.getDataString()));
startActivityForResult(activity, Constants.MATCHES_ACTIVE_LIST_CODE);
refreshAdapter();
break;
}
}
private void refreshAdapter() {
mHandler.post(mRunnable);
}
private void refreshGames() {
mProgressScreen.show();
Intent activity = new Intent(this, Games.class);
startActivityForResult(activity, Constants.GAMES_ACTIVE_LIST_CODE);
}
/**
* It shows the SwipeRefreshLayout progress
*/
private void showSwipeProgress() {
refreshLayout.setRefreshing(true);
}
/**
* It shows the SwipeRefreshLayout progress
*/
private void hideSwipeProgress() {
refreshLayout.setRefreshing(false);
}
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
private void setAppearance() {
refreshLayout.setColorSchemeResources(android.R.color.holo_blue_bright,
android.R.color.holo_green_light,
android.R.color.holo_orange_light,
android.R.color.holo_red_light);
}
private boolean hasPendingGames() {
boolean hasPendingGames = false;
TextView sendingStateTextView;
int i = 0;
if ((lvGames != null) && (lvGames.getChildCount() > 0)) {
while (!hasPendingGames && (i < lvGames.getChildCount())) {
sendingStateTextView = (TextView) lvGames.getChildAt(i).findViewById
(R.id.sendingStateTextView);
hasPendingGames = sendingStateTextView.getText().equals(
getString(R.string.sendingStatePending));
i++;
}
}
return hasPendingGames;
}
private void updateGames() {
showSwipeProgress();
refreshGames();
hideSwipeProgress();
}
/**
* It must be overriden by parent classes if manual swipe is enabled.
*/
@Override
public void onRefresh() {
if (!hasPendingGames()) {
updateGames();
} else {
AlertDialog cleanGamesDialog = DialogFactory.createWarningDialog(this,
-1,
R.string.areYouSure,
R.string.updatePendingGamesMsg,
R.string.yesMsg,
R.string.noMsg,
true,
(dialog, id) -> {
dialog.cancel();
updateGames();
},
(dialog, id) -> dialog.cancel(),
null);
cleanGamesDialog.show();
}
hideSwipeProgress();
}
private static class RefreshAdapterHandler extends Handler {
private final WeakReference<GamesList> mActivity;
public RefreshAdapterHandler(GamesList activity) {
mActivity = new WeakReference<>(activity);
}
}
}

View File

@ -0,0 +1,352 @@
package es.ugr.swad.swadroid.modules.games;
import android.content.Intent;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import android.widget.ToggleButton;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import es.ugr.swad.swadroid.Constants;
import es.ugr.swad.swadroid.R;
import es.ugr.swad.swadroid.database.DataBaseHelper;
import es.ugr.swad.swadroid.gui.MenuActivity;
import es.ugr.swad.swadroid.gui.ProgressScreen;
import es.ugr.swad.swadroid.model.Game;
import es.ugr.swad.swadroid.model.Match;
import es.ugr.swad.swadroid.modules.courses.Courses;
/**
* Games Play module.
*
* @author Juan Miguel Boyero Corral <juanmi1982@gmail.com>
* @author Sergio Díaz Rueda <sergiodiazrueda8@gmail.com>
*/
public class GamesPlay extends MenuActivity implements View.OnClickListener {
/**
* Tests tag name for Logcat
*/
private static final String TAG = Constants.APP_TAG + " GamesPlay";
/**
* Progress screen
*/
private ProgressScreen mProgressScreen;
/**
* ActionBar menu
*/
private Menu menu;
/**
* Game code
*/
private long gameCode;
/**
* Match code
*/
private long matchCode;
/**
* CountDown to initiate or finish a process
*/
private CountDownTimer countDownMatchStatus;
private CountDownTimer countDownRemoveAnswerMatch;
/**
* Answer's buttons
*/
private List<ToggleButton> buttonList;
/**
* Number of answers of the current question
*/
private int numAnswers = 0;
/**
* Number of questions of the game
*/
private int numQuestions;
/**
* Index of que current question
*/
private int currentQuestion = 0;
/**
* Variable that indicates if the button should be turned on
*/
private boolean answered = false;
/* (non-Javadoc)
* @see es.ugr.swad.swadroid.modules.Module#onCreate(android.os.Bundle)
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
gameCode = getIntent().getLongExtra("gameCode", 0);
matchCode = getIntent().getLongExtra("matchCode", 0);
setContentView(R.layout.button_list);
View mProgressScreenView = findViewById(R.id.progress_screen);
View mGamesMenuLayoutView = findViewById(R.id.buttonsLayout);
mProgressScreen = new ProgressScreen(mProgressScreenView, mGamesMenuLayoutView,
getString(R.string.loadingMsg), this);
List<Match> matchesList = dbHelper.getMatchesGame(gameCode);
Optional<Match> matchOptional = matchesList
.stream()
.filter(m -> m.getId() == matchCode)
.findFirst();
if (matchOptional.isPresent()) {
Game game = dbHelper.getRow(DataBaseHelper.DB_TABLE_GAMES, "id", gameCode);
numQuestions = game.getNumQuestions();
} else {
Toast.makeText(this, R.string.errorMatchStatusMsg, Toast.LENGTH_LONG).show();
finish();
}
initializeButtons();
countDownMatchStatus = new CountDownTimer(3000, 1000) {
public void onTick(long millisUntilFinished) {
// No-op
}
public void onFinish() {
getMatchStatus();
}
};
countDownRemoveAnswerMatch = new CountDownTimer(1000, 500) {
public void onTick(long millisUntilFinished) {
// No-op
}
public void onFinish() {
setCheckAllButtons(false);
}
};
getSupportActionBar().setSubtitle(Courses.getSelectedCourseShortName());
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
@Override
protected void onStart() {
super.onStart();
mProgressScreen.show();
showQuestionButtons();
getMatchStatus();
}
@Override
protected void onPause() {
countDownMatchStatus.cancel();
countDownRemoveAnswerMatch.cancel();
super.onPause();
}
private void setFinish() {
setContentView(R.layout.games_finish);
Button finish = (Button) findViewById(R.id.buttonFinish);
finish.setOnClickListener(this);
}
private void getMatchStatus() {
countDownMatchStatus.cancel();
Intent activity = new Intent(getApplicationContext(),
GamesPlayStatus.class);
activity.putExtra("gameCode", gameCode);
activity.putExtra("matchCode", matchCode);
startActivityForResult(activity, Constants.MATCHES_STATUS_CODE);
}
private void sendMatchAnswer(int newAnswer) {
countDownMatchStatus.cancel();
Intent activity = new Intent(getApplicationContext(),
GamesPlayAnswer.class);
activity.putExtra("gameCode", gameCode);
activity.putExtra("matchCode", matchCode);
activity.putExtra("questionIndex", currentQuestion);
activity.putExtra("answerIndex", newAnswer);
startActivityForResult(activity, Constants.MATCHES_ANSWER_CODE);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
long mc;
switch (requestCode) {
case Constants.MATCHES_STATUS_CODE:
mc = data.getLongExtra("matchCode", 0);
int questionIndex = data.getIntExtra("questionIndex", 0);
int answerIndex = data.getIntExtra("answerIndex", 0);
numAnswers = data.getIntExtra("numAnswers", 0);
if (mc < 0) {
Toast.makeText(this, R.string.errorMatchStatusMsg, Toast.LENGTH_LONG).show();
finish();
} else {
if (mc != 0) {
currentQuestion = questionIndex;
if (answerIndex < 0) {
menu.findItem(R.id.action_answered).setVisible(false);
menu.findItem(R.id.action_no_answered).setVisible(true);
} else {
menu.findItem(R.id.action_answered).setVisible(true);
menu.findItem(R.id.action_no_answered).setVisible(false);
}
menu.findItem(R.id.action_remove).setVisible(true);
mProgressScreen.hide();
onConfigurationChanged(getResources().getConfiguration());
if (answered) {
if (answerIndex != -1) {
countDownRemoveAnswerMatch.start();
} else {
Toast.makeText(this, R.string.answerRemovedMsg, Toast.LENGTH_LONG).show();
}
answered = false;
}
} else {
hideButtons();
menu.findItem(R.id.action_question_index).setVisible(false);
menu.findItem(R.id.action_answered).setVisible(false);
menu.findItem(R.id.action_no_answered).setVisible(false);
menu.findItem(R.id.action_remove).setVisible(false);
if (questionIndex == 0) {
Toast.makeText(this, R.string.matchNotStartedMsg, Toast.LENGTH_LONG).show();
} else if (questionIndex > Constants.MAX_NUM_QUESTIONS_GAMES) {
Toast.makeText(this, R.string.matchFinishedMsg, Toast.LENGTH_LONG).show();
} else {
Toast.makeText(this, R.string.matchPausedMsg, Toast.LENGTH_LONG).show();
}
}
menu.findItem(R.id.action_question_index).setVisible(true);
if (questionIndex == 0) {
menu.findItem(R.id.action_question_index).setTitle(R.string.gameStart);
} else if (questionIndex > Constants.MAX_NUM_QUESTIONS_GAMES) {
menu.findItem(R.id.action_question_index).setTitle(R.string.gameFinish);
setFinish();
} else {
menu.findItem(R.id.action_question_index).setTitle
(currentQuestion + "/" + numQuestions);
}
countDownMatchStatus.start();
}
break;
case Constants.MATCHES_ANSWER_CODE:
mc = data.getLongExtra("matchCode", 0);
if (mc <= 0) {
Toast.makeText(this, R.string.errorAnswerMatchMsg, Toast.LENGTH_LONG).show();
} else {
answered = true;
getMatchStatus();
}
break;
}
}
private void hideButtons() {
for (ToggleButton button : buttonList) {
button.setVisibility(View.GONE);
}
}
private void showQuestionButtons() {
int i = 0;
for (ToggleButton button : buttonList) {
if (i < numAnswers) {
button.setVisibility(View.VISIBLE);
} else {
button.setVisibility(View.GONE);
}
i++;
}
}
private void setCheckAllButtons(boolean isChecked) {
for (ToggleButton button : buttonList) {
button.setChecked(isChecked);
}
}
private void initializeButtons() {
buttonList = Arrays.asList(
findViewById(R.id.button1),
findViewById(R.id.button2),
findViewById(R.id.button3),
findViewById(R.id.button4),
findViewById(R.id.button5),
findViewById(R.id.button6),
findViewById(R.id.button7),
findViewById(R.id.button8),
findViewById(R.id.button9),
findViewById(R.id.button10)
);
for (ToggleButton button : buttonList) {
button.setOnClickListener(this);
}
}
@Override
public void onClick(View v) {
if (v.getId() == R.id.buttonFinish) {
finish();
} else {
ToggleButton button = buttonList
.stream()
.filter(b -> b.getId() == (v.getId()))
.findFirst()
.get();
int buttonIndex = buttonList.indexOf(button);
button.setChecked(false);
sendMatchAnswer(buttonIndex);
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.game_activity_actions, menu);
this.menu = menu;
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_answered:
answered = true;
getMatchStatus();
return true;
case R.id.action_no_answered:
Toast.makeText(this, R.string.matchNoAnsweredMsg,
Toast.LENGTH_LONG).show();
return true;
case R.id.action_remove:
answered = true;
sendMatchAnswer(-1);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
}

View File

@ -0,0 +1,142 @@
package es.ugr.swad.swadroid.modules.games;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;
import org.ksoap2.serialization.SoapPrimitive;
import es.ugr.swad.swadroid.Constants;
import es.ugr.swad.swadroid.R;
import es.ugr.swad.swadroid.model.MatchAnswer;
import es.ugr.swad.swadroid.modules.Module;
import es.ugr.swad.swadroid.modules.courses.Courses;
import es.ugr.swad.swadroid.modules.login.Login;
import es.ugr.swad.swadroid.webservices.SOAPClient;
/**
* Match answer upload module.
*
* @author Juan Miguel Boyero Corral <juanmi1982@gmail.com>
* @author Sergio Díaz Rueda <sergiodiazrueda8@gmail.com>
* @see <a href="https://openswad.org/ws/#answerMatchQuestion">answerMatchQuestion</a>
*/
public class GamesPlayAnswer extends Module {
/**
* Games tag name for Logcat
*/
private static final String TAG = Constants.APP_TAG + " GamesPlayAnswer";
/**
* Game code
*/
private long gameCode;
/**
* Match code
*/
private long matchCode;
/**
* Number of question associated to the selected match
*/
private int questionIndex;
/**
* Index of answers selected by the user to the selected question
*/
private int answerIndex;
/* (non-Javadoc)
* @see es.ugr.swad.swadroid.modules.Module#onCreate(android.os.Bundle)
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
gameCode = getIntent().getLongExtra("gameCode", 0);
matchCode = getIntent().getLongExtra("matchCode", 0);
questionIndex = getIntent().getIntExtra("questionIndex", 0);
answerIndex = getIntent().getIntExtra("answerIndex", 0);
setMETHOD_NAME("answerMatchQuestion");
getSupportActionBar().hide();
}
/* (non-Javadoc)
* @see es.ugr.swad.swadroid.modules.Module#onStart()
*/
@Override
protected void onStart() {
super.onStart();
try {
if (isDebuggable) {
Log.d(TAG, "selectedCourseCode = " +
Long.toString(Courses.getSelectedCourseCode()));
}
runConnection();
} catch (Exception e) {
String errorMsg = getString(R.string.errorServerResponseMsg);
error(errorMsg, e);
}
}
/* (non-Javadoc)
* @see es.ugr.swad.swadroid.modules.Module#requestService()
*/
@Override
protected void requestService() throws Exception {
long courseCode = Courses.getSelectedCourseCode();
//Creates webservice request, adds required params and sends request to webservice
createRequest(SOAPClient.CLIENT_TYPE);
addParam("wsKey", Login.getLoggedUser().getWsKey());
addParam("courseCode", (int) courseCode);
addParam("gameCode", gameCode);
addParam("matchCode", matchCode);
addParam("questionIndex", questionIndex);
addParam("answerIndex", answerIndex);
sendRequest(MatchAnswer.class, false);
long mc = 0L;
if (result != null) {
//Stores tests data returned by webservice response
SoapPrimitive soap = (SoapPrimitive) result;
//Stores data returned by webservice response
mc = Long.parseLong(soap.getValue().toString());
}
Intent data = new Intent();
data.putExtra("matchCode", mc);
// Request finalized without errors
setResult(RESULT_OK, data);
}
@Override
protected void connect() {
String progressDescription = getString(R.string.matchesDownloadProgressDescription);
startConnection();
}
@Override
protected void postConnect() {
if (matchCode < 0) {
Toast.makeText(this, R.string.errorMatchStatusMsg, Toast.LENGTH_LONG).show();
}
finish();
}
@Override
protected void onError() {
}
}

View File

@ -0,0 +1,146 @@
package es.ugr.swad.swadroid.modules.games;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
import es.ugr.swad.swadroid.Constants;
import es.ugr.swad.swadroid.R;
import es.ugr.swad.swadroid.model.MatchStatus;
import es.ugr.swad.swadroid.modules.Module;
import es.ugr.swad.swadroid.modules.courses.Courses;
import es.ugr.swad.swadroid.modules.login.Login;
import es.ugr.swad.swadroid.webservices.SOAPClient;
/**
* Match status download module.
*
* @author Juan Miguel Boyero Corral <juanmi1982@gmail.com>
* @author Sergio Díaz Rueda <sergiodiazrueda8@gmail.com>
* @see <a href="https://openswad.org/ws/#getMatchStatus">getMatchStatus</a>
*/
public class GamesPlayStatus extends Module {
/**
* Games tag name for Logcat
*/
private static final String TAG = Constants.APP_TAG + " GamesPlayStatus";
/**
* Game code
*/
private long gameCode = -1;
/**
* Match code
*/
private long matchCode = -1;
/* (non-Javadoc)
* @see es.ugr.swad.swadroid.modules.Module#onCreate(android.os.Bundle)
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
gameCode = getIntent().getLongExtra("gameCode", 0);
matchCode = getIntent().getLongExtra("matchCode", 0);
setMETHOD_NAME("getMatchStatus");
getSupportActionBar().hide();
}
/* (non-Javadoc)
* @see es.ugr.swad.swadroid.modules.Module#onStart()
*/
@Override
protected void onStart() {
super.onStart();
try {
if (isDebuggable) {
Log.d(TAG, "selectedCourseCode = " +
Long.toString(Courses.getSelectedCourseCode()));
}
runConnection();
} catch (Exception e) {
String errorMsg = getString(R.string.errorServerResponseMsg);
error(errorMsg, e);
}
}
/* (non-Javadoc)
* @see es.ugr.swad.swadroid.modules.Module#requestService()
*/
@Override
protected void requestService() throws Exception {
long courseCode = Courses.getSelectedCourseCode();
int questionIndex = -1;
int numAnswers = -1;
int answerIndex = -1;
//Creates webservice request, adds required params and sends request to webservice
createRequest(SOAPClient.CLIENT_TYPE);
addParam("wsKey", Login.getLoggedUser().getWsKey());
addParam("courseCode", (int) courseCode);
addParam("gameCode", gameCode);
addParam("matchCode", matchCode);
sendRequest(MatchStatus.class, false);
if (result != null) {
//Stores tests data returned by webservice response
List<Object> res = new ArrayList<>((Vector<?>) result);
matchCode = Long.parseLong(res.get(0).toString());
questionIndex = Integer.parseInt(res.get(1).toString());
numAnswers = Integer.parseInt(res.get(2).toString());
answerIndex = Integer.parseInt(res.get(3).toString());
if (isDebuggable) {
Log.d("matchCode", Long.toString(matchCode));
Log.d("questionIndex", Long.toString(questionIndex));
Log.d("numAnswers", Long.toString(numAnswers));
Log.d("answerIndex", Long.toString(answerIndex));
}
Log.i(TAG, "Recovered status for match " + matchCode);
}
Intent data = new Intent();
data.putExtra("matchCode", matchCode);
data.putExtra("questionIndex", questionIndex);
data.putExtra("numAnswers", numAnswers);
data.putExtra("answerIndex", answerIndex);
// Request finalized without errors
setResult(RESULT_OK, data);
}
@Override
protected void connect() {
String progressDescription = getString(R.string.matchesDownloadProgressDescription);
startConnection();
}
@Override
protected void postConnect() {
if (matchCode < 0) {
Toast.makeText(this, R.string.errorMatchStatusMsg, Toast.LENGTH_LONG).show();
}
finish();
}
@Override
protected void onError() {
}
}

View File

@ -0,0 +1,193 @@
package es.ugr.swad.swadroid.modules.games;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;
import org.ksoap2.serialization.SoapObject;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
import es.ugr.swad.swadroid.Constants;
import es.ugr.swad.swadroid.R;
import es.ugr.swad.swadroid.database.DataBaseHelper;
import es.ugr.swad.swadroid.model.Match;
import es.ugr.swad.swadroid.modules.Module;
import es.ugr.swad.swadroid.modules.courses.Courses;
import es.ugr.swad.swadroid.modules.login.Login;
import es.ugr.swad.swadroid.webservices.SOAPClient;
/**
* Match download module.
*
* @author Juan Miguel Boyero Corral <juanmi1982@gmail.com>
* @author Sergio Díaz Rueda <sergiodiazrueda8@gmail.com>
* @see <a href="https://openswad.org/ws/#getGames">getGames</a>
*/
public class Matches extends Module {
/**
* Games tag name for Logcat
*/
private static final String TAG = Constants.APP_TAG + " MatchesActive";
/**
* Number of matches associated to the selected game
*/
private int numMatches;
/**
* List of downloaded match codes
*/
private List<Long> matchCodes;
/**
* Game code
*/
private long gameCode;
/* (non-Javadoc)
* @see es.ugr.swad.swadroid.modules.Module#onCreate(android.os.Bundle)
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
gameCode = getIntent().getLongExtra("gameCode", 0);
Log.d("gameCode", Long.toString(gameCode));
setMETHOD_NAME("getMatches");
getSupportActionBar().hide();
}
/* (non-Javadoc)
* @see es.ugr.swad.swadroid.modules.Module#onStart()
*/
@Override
protected void onStart() {
super.onStart();
try {
if (isDebuggable) {
Log.d(TAG, "selectedCourseCode = " +
Long.toString(Courses.getSelectedCourseCode()));
}
runConnection();
} catch (Exception e) {
String errorMsg = getString(R.string.errorServerResponseMsg);
error(errorMsg, e);
}
}
/* (non-Javadoc)
* @see es.ugr.swad.swadroid.modules.Module#requestService()
*/
@Override
protected void requestService() throws Exception {
long courseCode = Courses.getSelectedCourseCode();
//Creates webservice request, adds required params and sends request to webservice
createRequest(SOAPClient.CLIENT_TYPE);
addParam("wsKey", Login.getLoggedUser().getWsKey());
addParam("courseCode", (int) courseCode);
addParam("gameCode", gameCode);
sendRequest(Match.class, false);
matchCodes = new ArrayList<>();
if (result != null) {
//Stores tests data returned by webservice response
List<Object> res = new ArrayList<>((Vector<?>) result);
SoapObject soap = (SoapObject) res.get(1);
numMatches = soap.getPropertyCount();
for (int i = 0; i < numMatches; i++) {
SoapObject pii = (SoapObject) soap.getProperty(i);
long matchCode = Long.parseLong(pii.getProperty("matchCode").toString());
String userSurname1 = pii.getProperty("userSurname1").toString();
String userSurname2 = pii.getProperty("userSurname2").toString();
String userFirstName = pii.getProperty("userFirstname").toString();
String userPhoto = pii.getProperty("userPhoto").toString();
long startTime = Long.parseLong(pii.getProperty("startTime").toString());
long endTime = Long.parseLong(pii.getProperty("endTime").toString());
String title = pii.getProperty("title").toString();
int questionIndex = Integer.parseInt(pii.getProperty("questionIndex").toString());
String groups = (pii.hasProperty("groups") ? pii.getProperty("groups").toString() : "");
if (userSurname1.equalsIgnoreCase(Constants.NULL_VALUE)) userSurname1 = "";
if (userSurname2.equalsIgnoreCase(Constants.NULL_VALUE)) userSurname2 = "";
if (userFirstName.equalsIgnoreCase(Constants.NULL_VALUE)) userFirstName = "";
if (userPhoto.equalsIgnoreCase(Constants.NULL_VALUE)) userPhoto = "";
if (title.equalsIgnoreCase(Constants.NULL_VALUE)) title = "";
if (groups.equalsIgnoreCase(Constants.NULL_VALUE)) groups = "";
//Inserts or updates event into database
dbHelper.insertMatch(new Match(matchCode, userSurname1, userSurname2,
userFirstName, userPhoto, startTime, endTime,
title, questionIndex, groups));
dbHelper.insertMatchGame(matchCode, gameCode);
//Add a match Code to the new match list
matchCodes.add(matchCode);
}
//Removes old matches not listed in eventCodes
removeOldMatches();
Log.i(TAG, "Retrieved " + numMatches + " matches");
}
Intent data = new Intent();
data.setData(Uri.parse(Long.toString(gameCode)));
// Request finalized without errors
setResult(RESULT_OK, data);
}
@Override
protected void connect() {
String progressDescription = getString(R.string.matchesDownloadProgressDescription);
startConnection();
}
@Override
protected void postConnect() {
if (numMatches == 0) {
Toast.makeText(this, R.string.noMatchesAvailableMsg, Toast.LENGTH_LONG).show();
} else {
String msg = String.valueOf(numMatches) + " "
+ getResources().getString(R.string.matchesUpdated);
Toast.makeText(this, msg, Toast.LENGTH_LONG).show();
}
finish();
}
@Override
protected void onError() {
}
private void removeOldMatches() {
List<Match> dbMatches = dbHelper.getMatchesGame(gameCode);
int nMatchesRemoved = 0;
if ((dbMatches != null) && (!dbMatches.isEmpty())) {
for (Match m : dbMatches) {
if (!matchCodes.contains(m.getId())) {
dbHelper.removeAllRows(DataBaseHelper.DB_TABLE_MATCHES_GAMES,
"matchcode", m.getId());
dbHelper.removeAllRows(DataBaseHelper.DB_TABLE_MATCHES,
"id", m.getId());
nMatchesRemoved++;
}
}
}
Log.i(TAG, "Removed " + nMatchesRemoved + " matches");
}
}

View File

@ -0,0 +1,33 @@
package es.ugr.swad.swadroid.modules.games;
import android.content.Context;
import android.database.Cursor;
import es.ugr.swad.swadroid.Constants;
import es.ugr.swad.swadroid.database.DataBaseHelper;
import es.ugr.swad.swadroid.model.Match;
/**
* Custom CursorAdapter for display matches
*
* @author Juan Miguel Boyero Corral <juanmi1982@gmail.com>
*/
public class MatchesCursorAdapter extends AbstractGamesCursorAdapter {
public MatchesCursorAdapter(Context context, Cursor c, DataBaseHelper dbHelper) {
super(context, c, dbHelper);
}
public MatchesCursorAdapter(Context context, Cursor c, boolean autoRequery, DataBaseHelper dbHelper) {
super(context, c, autoRequery, dbHelper);
}
@Override
protected boolean isFinished(long matchCode) {
Match match = dbHelper.getRow(DataBaseHelper.DB_TABLE_MATCHES, "id", matchCode);
return match.getQuestionIndex() > Constants.MAX_NUM_QUESTIONS_GAMES;
}
}

View File

@ -0,0 +1,289 @@
package es.ugr.swad.swadroid.modules.games;
import android.annotation.TargetApi;
import android.app.AlertDialog;
import android.content.Intent;
import android.database.Cursor;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.TextView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import java.lang.ref.WeakReference;
import es.ugr.swad.swadroid.Constants;
import es.ugr.swad.swadroid.R;
import es.ugr.swad.swadroid.gui.DialogFactory;
import es.ugr.swad.swadroid.gui.MenuExpandableListActivity;
import es.ugr.swad.swadroid.gui.ProgressScreen;
import es.ugr.swad.swadroid.modules.courses.Courses;
/**
* Matches List module.
*
* @author Juan Miguel Boyero Corral <juanmi1982@gmail.com>
* @author Sergio Díaz Rueda <sergiodiazrueda8@gmail.com>
*/
public class MatchesList extends MenuExpandableListActivity
implements SwipeRefreshLayout.OnRefreshListener {
/**
* MatchesActiveList tag name for Logcat
*/
private static final String TAG = Constants.APP_TAG + " MatchesActiveList";
/**
* ListView of matches
*/
private ListView lvMatches;
/**
* Adapter for ListView of matches
*/
private MatchesCursorAdapter adapter;
/**
* Handler of matches
*/
private final MatchesList.RefreshAdapterHandler mHandler =
new MatchesList.RefreshAdapterHandler(this);
private final Runnable mRunnable = new Runnable() {
@Override
public void run() {
/*
* Database cursor for Adapter of matches
*/
Cursor dbCursor = dbHelper.getMatchesGameCursor(gameCode);
startManagingCursor(dbCursor);
/*
* If there aren't matches to show, hide the matches lvMatches
* and show the empty matches message
*/
if ((dbCursor == null) || (dbCursor.getCount() == 0)) {
Log.d(TAG, "Matches list is empty");
emptyMatchesTextView.setText(R.string.matchesEmptyListMsg);
emptyMatchesTextView.setVisibility(View.VISIBLE);
lvMatches.setVisibility(View.GONE);
} else {
Log.d(TAG, "Matches list is not empty");
emptyMatchesTextView.setVisibility(View.GONE);
lvMatches.setVisibility(View.VISIBLE);
}
adapter = new MatchesCursorAdapter(getBaseContext(), dbCursor, dbHelper);
lvMatches.setAdapter(adapter);
mProgressScreen.hide();
}
};
/**
* TextView for the empty matches message
*/
private TextView emptyMatchesTextView;
/**
* Layout with "Pull to refresh" function
*/
private SwipeRefreshLayout refreshLayout;
/**
* Progress screen
*/
private ProgressScreen mProgressScreen;
/**
* ListView click listener
*/
private final ListView.OnItemClickListener clickListener = new ListView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
mProgressScreen.show();
Intent activity = new Intent(getApplicationContext(),
GamesPlay.class);
activity.putExtra("gameCode", gameCode);
activity.putExtra("matchCode", adapter.getItemId(position));
startActivity(activity);
}
};
/**
* Game code
*/
private long gameCode;
/* (non-Javadoc)
* @see es.ugr.swad.swadroid.MenuExpandableListActivity#onCreate(android.os.Bundle)
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
gameCode = getIntent().getLongExtra("gameCode", 0);
setContentView(R.layout.list_items_pulltorefresh);
refreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipe_container_list);
emptyMatchesTextView = (TextView) findViewById(R.id.list_item_title);
View mProgressScreenView = findViewById(R.id.progress_screen);
mProgressScreen = new ProgressScreen(mProgressScreenView, refreshLayout,
getString(R.string.loadingMsg), this);
lvMatches = (ListView) findViewById(R.id.list_pulltorefresh);
lvMatches.setOnItemClickListener(clickListener);
lvMatches.setOnScrollListener(new AbsListView.OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView absListView, int scrollState) {
// No-op
}
@Override
public void onScroll(AbsListView absListView, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
boolean enable = true;
if ((lvMatches != null) && (lvMatches.getChildCount() > 0)) {
// check if the first item of the list is visible
boolean firstItemVisible = lvMatches.getFirstVisiblePosition() == 0;
// check if the top of the first item is visible
boolean topOfFirstItemVisible = lvMatches.getChildAt(0).getTop() == 0;
// enabling or disabling the refresh layout
enable = firstItemVisible && topOfFirstItemVisible;
}
refreshLayout.setEnabled(enable);
}
});
refreshLayout.setOnRefreshListener(this);
setAppearance();
getSupportActionBar().setSubtitle(Courses.getSelectedCourseShortName());
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
/* (non-Javadoc)
* @see es.ugr.swad.swadroid.MenuExpandableListActivity#Override(android.os.Bundle)
*/
@Override
protected void onStart() {
super.onStart();
refreshAdapter();
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
switch (requestCode) {
case Constants.MATCHES_ACTIVE_DOWNLOAD_CODE:
mProgressScreen.hide();
refreshAdapter();
break;
}
}
private void refreshAdapter() {
mHandler.post(mRunnable);
}
private void refreshMatches() {
mProgressScreen.show();
Intent activity = new Intent(this, Matches.class);
activity.putExtra("gameCode", gameCode);
startActivityForResult(activity, Constants.MATCHES_ACTIVE_DOWNLOAD_CODE);
}
/**
* It shows the SwipeRefreshLayout progress
*/
private void showSwipeProgress() {
refreshLayout.setRefreshing(true);
}
/**
* It shows the SwipeRefreshLayout progress
*/
private void hideSwipeProgress() {
refreshLayout.setRefreshing(false);
}
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
private void setAppearance() {
refreshLayout.setColorSchemeResources(android.R.color.holo_blue_bright,
android.R.color.holo_green_light,
android.R.color.holo_orange_light,
android.R.color.holo_red_light);
}
private boolean hasPendingMatches() {
boolean hasPendingMatches = false;
TextView sendingStateTextView;
int i = 0;
if ((lvMatches != null) && (lvMatches.getChildCount() > 0)) {
while (!hasPendingMatches && (i < lvMatches.getChildCount())) {
sendingStateTextView = (TextView) lvMatches.getChildAt(i).findViewById
(R.id.sendingStateTextView);
hasPendingMatches = sendingStateTextView.getText().equals
(getString(R.string.sendingStatePending));
i++;
}
}
return hasPendingMatches;
}
private void updateMatches() {
showSwipeProgress();
refreshMatches();
hideSwipeProgress();
}
/**
* It must be overriden by parent classes if manual swipe is enabled.
*/
@Override
public void onRefresh() {
if (!hasPendingMatches()) {
updateMatches();
} else {
AlertDialog cleanMatchesDialog = DialogFactory.createWarningDialog(this,
-1,
R.string.areYouSure,
R.string.updatePendingMatchesMsg,
R.string.yesMsg,
R.string.noMsg,
true,
(dialog, id) -> {
dialog.cancel();
updateMatches();
},
(dialog, id) -> dialog.cancel(),
null);
cleanMatchesDialog.show();
}
hideSwipeProgress();
}
private static class RefreshAdapterHandler extends Handler {
private final WeakReference<MatchesList> mActivity;
public RefreshAdapterHandler(MatchesList activity) {
mActivity = new WeakReference<>(activity);
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 854 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 568 B

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:state_checked="false">
<layer-list>
<item android:drawable="@color/button_red" />
<item>
<shape android:shape="rectangle">
<stroke android:width="2dp" android:color="@color/button_red_border"/>
</shape>
</item>
</layer-list>
</item>
<item android:state_checked="true">
<layer-list>
<item android:drawable="@color/button_red" />
<item xmlns:android="http://schemas.android.com/apk/res/android" >
<shape>
<stroke
android:width="8dp"
android:color="@color/button_checked"/>
</shape>
</item>
</layer-list>
</item>
</selector>

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:state_checked="false">
<layer-list>
<item android:drawable="@color/button_blue" />
<item>
<shape android:shape="rectangle">
<stroke android:width="2dp" android:color="@color/button_blue_border"/>
</shape>
</item>
</layer-list>
</item>
<item android:state_checked="true">
<layer-list>
<item android:drawable="@color/button_blue" />
<item xmlns:android="http://schemas.android.com/apk/res/android" >
<shape>
<stroke
android:width="8dp"
android:color="@color/button_checked" />
</shape>
</item>
</layer-list>
</item>
</selector>

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:state_checked="false">
<layer-list>
<item android:drawable="@color/button_yellow" />
<item>
<shape android:shape="rectangle">
<stroke android:width="2dp" android:color="@color/button_yellow_border"/>
</shape>
</item>
</layer-list>
</item>
<item android:state_checked="true">
<layer-list>
<item android:drawable="@color/button_yellow" />
<item xmlns:android="http://schemas.android.com/apk/res/android" >
<shape>
<stroke
android:width="8dp"
android:color="@color/button_checked" />
</shape>
</item>
</layer-list>
</item>
</selector>

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:state_checked="false">
<layer-list>
<item android:drawable="@color/button_green" />
<item>
<shape android:shape="rectangle">
<stroke android:width="2dp" android:color="@color/button_green_border"/>
</shape>
</item>
</layer-list>
</item>
<item android:state_checked="true">
<layer-list>
<item android:drawable="@color/button_green" />
<item xmlns:android="http://schemas.android.com/apk/res/android" >
<shape>
<stroke
android:width="8dp"
android:color="@color/button_checked" />
</shape>
</item>
</layer-list>
</item>
</selector>

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:state_checked="false">
<layer-list>
<item android:drawable="@color/button_pink" />
<item>
<shape android:shape="rectangle">
<stroke android:width="2dp" android:color="@color/button_pink_border"/>
</shape>
</item>
</layer-list>
</item>
<item android:state_checked="true">
<layer-list>
<item android:drawable="@color/button_pink" />
<item xmlns:android="http://schemas.android.com/apk/res/android" >
<shape>
<stroke
android:width="8dp"
android:color="@color/button_checked" />
</shape>
</item>
</layer-list>
</item>
</selector>

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:state_checked="false">
<layer-list>
<item android:drawable="@color/button_light_blue" />
<item>
<shape android:shape="rectangle">
<stroke android:width="2dp" android:color="@color/button_light_blue_border"/>
</shape>
</item>
</layer-list>
</item><item android:state_checked="true">
<layer-list>
<item android:drawable="@color/button_light_blue" />
<item xmlns:android="http://schemas.android.com/apk/res/android" >
<shape>
<stroke
android:width="8dp"
android:color="@color/button_checked" />
</shape>
</item>
</layer-list>
</item>
</selector>

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:state_checked="false">
<layer-list>
<item android:drawable="@color/button_orange" />
<item>
<shape android:shape="rectangle">
<stroke android:width="2dp" android:color="@color/button_orange_border"/>
</shape>
</item>
</layer-list>
</item>
<item android:state_checked="true">
<layer-list>
<item android:drawable="@color/button_orange" />
<item xmlns:android="http://schemas.android.com/apk/res/android" >
<shape>
<stroke
android:width="8dp"
android:color="@color/button_checked" />
</shape>
</item>
</layer-list>
</item>
</selector>

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:state_checked="false">
<layer-list>
<item android:drawable="@color/button_light_green" />
<item>
<shape android:shape="rectangle">
<stroke android:width="2dp" android:color="@color/button_light_green_border"/>
</shape>
</item>
</layer-list>
</item>
<item android:state_checked="true">
<layer-list>
<item android:drawable="@color/button_light_green" />
<item xmlns:android="http://schemas.android.com/apk/res/android" >
<shape>
<stroke
android:width="8dp"
android:color="@color/button_checked" />
</shape>
</item>
</layer-list>
</item>
</selector>

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:state_checked="false">
<layer-list>
<item android:drawable="@color/button_purple" />
<item>
<shape android:shape="rectangle">
<stroke android:width="2dp" android:color="@color/button_purple_border"/>
</shape>
</item>
</layer-list>
</item>
<item android:state_checked="true">
<layer-list>
<item android:drawable="@color/button_purple" />
<item xmlns:android="http://schemas.android.com/apk/res/android" >
<shape>
<stroke
android:width="8dp"
android:color="@color/button_checked" />
</shape>
</item>
</layer-list>
</item>
</selector>

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:state_checked="false">
<layer-list>
<item android:drawable="@color/button_light_yellow" />
<item>
<shape android:shape="rectangle">
<stroke android:width="2dp" android:color="@color/button_light_yellow_border"/>
</shape>
</item>
</layer-list>
</item><item android:state_checked="true">
<layer-list>
<item android:drawable="@color/button_light_yellow" />
<item xmlns:android="http://schemas.android.com/apk/res/android" >
<shape>
<stroke
android:width="8dp"
android:color="@color/button_checked" />
</shape>
</item>
</layer-list>
</item>
</selector>

View File

@ -0,0 +1,185 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="@layout/progress_screen" />
<GridLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:id="@+id/buttonsLayout">
<ToggleButton
android:id="@+id/button1"
android:background="@drawable/togglebuttona"
android:layout_row="0"
android:layout_column="0"
android:gravity="fill"
android:checked="false"
android:text="@string/buttonTitleA"
android:textAllCaps="false"
android:textColor="@color/white"
android:textOff="@string/buttonTitleA"
android:textOn="@string/buttonTitleA"
android:textSize="30sp"
android:visibility="gone" />
<ToggleButton
android:id="@+id/button2"
android:layout_width="match_parent"
android:layout_row="0"
android:layout_column="1"
android:gravity="fill"
android:layout_height="0dp"
android:layout_margin="5dp"
android:background="@drawable/togglebuttonb"
android:checked="false"
android:text="@string/buttonTitleB"
android:textAllCaps="false"
android:textColor="@color/white"
android:textOff="@string/buttonTitleB"
android:textOn="@string/buttonTitleB"
android:textSize="30sp"
android:visibility="gone" />
<ToggleButton
android:id="@+id/button3"
android:layout_width="match_parent"
android:layout_row="1"
android:layout_column="0"
android:gravity="fill"
android:layout_height="0dp"
android:layout_margin="5dp"
android:background="@drawable/togglebuttonc"
android:textAllCaps="false"
android:text="@string/buttonTitleC"
android:textOn="@string/buttonTitleC"
android:textOff="@string/buttonTitleC"
android:textSize="30sp"
android:textColor="@color/white"
android:visibility="gone" />
<ToggleButton
android:id="@+id/button4"
android:layout_width="match_parent"
android:layout_row="1"
android:layout_column="1"
android:gravity="fill"
android:layout_height="0dp"
android:layout_margin="5dp"
android:background="@drawable/togglebuttond"
android:textAllCaps="false"
android:text="@string/buttonTitleD"
android:textOn="@string/buttonTitleD"
android:textOff="@string/buttonTitleD"
android:textSize="30sp"
android:textColor="@color/white"
android:visibility="gone" />
<ToggleButton
android:id="@+id/button5"
android:layout_width="match_parent"
android:layout_row="2"
android:layout_column="0"
android:gravity="fill"
android:layout_height="0dp"
android:layout_margin="5dp"
android:background="@drawable/togglebuttone"
android:textAllCaps="false"
android:text="@string/buttonTitleE"
android:textOn="@string/buttonTitleE"
android:textOff="@string/buttonTitleE"
android:textSize="30sp"
android:textColor="@color/white"
android:visibility="gone" />
<ToggleButton
android:id="@+id/button6"
android:layout_width="match_parent"
android:layout_row="2"
android:layout_column="1"
android:gravity="fill"
android:layout_height="0dp"
android:layout_margin="5dp"
android:background="@drawable/togglebuttonf"
android:textAllCaps="false"
android:text="@string/buttonTitleF"
android:textOn="@string/buttonTitleF"
android:textOff="@string/buttonTitleF"
android:textSize="30sp"
android:textColor="@color/white"
android:visibility="gone" />
<ToggleButton
android:id="@+id/button7"
android:layout_width="match_parent"
android:layout_row="3"
android:layout_column="0"
android:gravity="fill"
android:layout_height="0dp"
android:layout_margin="5dp"
android:background="@drawable/togglebuttong"
android:textAllCaps="false"
android:text="@string/buttonTitleG"
android:textOn="@string/buttonTitleG"
android:textOff="@string/buttonTitleG"
android:textSize="30sp"
android:textColor="@color/white"
android:visibility="gone" />
<ToggleButton
android:id="@+id/button8"
android:layout_width="match_parent"
android:layout_row="3"
android:layout_column="1"
android:gravity="fill"
android:layout_height="0dp"
android:layout_margin="5dp"
android:background="@drawable/togglebuttonh"
android:textAllCaps="false"
android:text="@string/buttonTitleH"
android:textOn="@string/buttonTitleH"
android:textOff="@string/buttonTitleH"
android:textSize="30sp"
android:textColor="@color/white"
android:visibility="gone" />
<ToggleButton
android:id="@+id/button9"
android:layout_width="match_parent"
android:layout_row="4"
android:layout_column="0"
android:gravity="fill"
android:layout_height="0dp"
android:layout_margin="5dp"
android:background="@drawable/togglebuttoni"
android:textAllCaps="false"
android:text="@string/buttonTitleI"
android:textOn="@string/buttonTitleI"
android:textOff="@string/buttonTitleI"
android:textSize="30sp"
android:textColor="@color/white"
android:visibility="gone" />
<ToggleButton
android:id="@+id/button10"
android:layout_width="match_parent"
android:layout_row="4"
android:layout_column="1"
android:gravity="fill"
android:layout_height="0dp"
android:layout_margin="5dp"
android:background="@drawable/togglebuttonj"
android:textAllCaps="false"
android:text="@string/buttonTitleJ"
android:textOn="@string/buttonTitleJ"
android:textOff="@string/buttonTitleJ"
android:textSize="30sp"
android:textColor="@color/white"
android:visibility="gone" />
</GridLayout>
</LinearLayout>

View File

@ -0,0 +1,168 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="@layout/progress_screen" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:id="@+id/buttonsLayout">
<ToggleButton
android:id="@+id/button1"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_margin="5dp"
android:layout_weight="2"
android:background="@drawable/togglebuttona"
android:checked="false"
android:text="@string/buttonTitleA"
android:textAllCaps="false"
android:textColor="@color/white"
android:textOff="@string/buttonTitleA"
android:textOn="@string/buttonTitleA"
android:textSize="30sp"
android:visibility="gone" />
<ToggleButton
android:id="@+id/button2"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_margin="5dp"
android:layout_weight="2"
android:background="@drawable/togglebuttonb"
android:checked="false"
android:text="@string/buttonTitleB"
android:textAllCaps="false"
android:textColor="@color/white"
android:textOff="@string/buttonTitleB"
android:textOn="@string/buttonTitleB"
android:textSize="30sp"
android:visibility="gone" />
<ToggleButton
android:id="@+id/button3"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_margin="5dp"
android:layout_weight="2"
android:background="@drawable/togglebuttonc"
android:textAllCaps="false"
android:text="@string/buttonTitleC"
android:textOn="@string/buttonTitleC"
android:textOff="@string/buttonTitleC"
android:textSize="30sp"
android:textColor="@color/white"
android:visibility="gone" />
<ToggleButton
android:id="@+id/button4"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_margin="5dp"
android:layout_weight="2"
android:background="@drawable/togglebuttond"
android:textAllCaps="false"
android:text="@string/buttonTitleD"
android:textOn="@string/buttonTitleD"
android:textOff="@string/buttonTitleD"
android:textSize="30sp"
android:textColor="@color/white"
android:visibility="gone" />
<ToggleButton
android:id="@+id/button5"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_margin="5dp"
android:layout_weight="2"
android:background="@drawable/togglebuttone"
android:textAllCaps="false"
android:text="@string/buttonTitleE"
android:textOn="@string/buttonTitleE"
android:textOff="@string/buttonTitleE"
android:textSize="30sp"
android:textColor="@color/white"
android:visibility="gone" />
<ToggleButton
android:id="@+id/button6"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_margin="5dp"
android:layout_weight="2"
android:background="@drawable/togglebuttonf"
android:textAllCaps="false"
android:text="@string/buttonTitleF"
android:textOn="@string/buttonTitleF"
android:textOff="@string/buttonTitleF"
android:textSize="30sp"
android:textColor="@color/white"
android:visibility="gone" />
<ToggleButton
android:id="@+id/button7"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_margin="5dp"
android:layout_weight="2"
android:background="@drawable/togglebuttong"
android:textAllCaps="false"
android:text="@string/buttonTitleG"
android:textOn="@string/buttonTitleG"
android:textOff="@string/buttonTitleG"
android:textSize="30sp"
android:textColor="@color/white"
android:visibility="gone" />
<ToggleButton
android:id="@+id/button8"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_margin="5dp"
android:layout_weight="2"
android:background="@drawable/togglebuttonh"
android:textAllCaps="false"
android:text="@string/buttonTitleH"
android:textOn="@string/buttonTitleH"
android:textOff="@string/buttonTitleH"
android:textSize="30sp"
android:textColor="@color/white"
android:visibility="gone" />
<ToggleButton
android:id="@+id/button9"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_margin="5dp"
android:layout_weight="2"
android:background="@drawable/togglebuttoni"
android:textAllCaps="false"
android:text="@string/buttonTitleI"
android:textOn="@string/buttonTitleI"
android:textOff="@string/buttonTitleI"
android:textSize="30sp"
android:textColor="@color/white"
android:visibility="gone" />
<ToggleButton
android:id="@+id/button10"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_margin="5dp"
android:layout_weight="2"
android:background="@drawable/togglebuttonj"
android:textAllCaps="false"
android:text="@string/buttonTitleJ"
android:textOn="@string/buttonTitleJ"
android:textOff="@string/buttonTitleJ"
android:textSize="30sp"
android:textColor="@color/white"
android:visibility="gone" />
</LinearLayout>
</LinearLayout>

View File

@ -0,0 +1,57 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@color/background"
android:orientation="horizontal"
android:padding="6dip" >
<TextView
android:id="@+id/icon"
android:layout_width="30dp"
android:layout_height="match_parent"
android:layout_marginStart="5dp"
android:textColor="@color/foreground1"
android:textSize="28sp" >
</TextView>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:id="@+id/toptext"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textColor="@color/foreground1"
android:textSize="20sp"
android:textStyle="bold" />
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/startTimeTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="3dip" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="3dip"
android:text=" - "
android:textColor="@color/foreground1" />
<TextView
android:id="@+id/endTimeTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>
</LinearLayout>

View File

@ -0,0 +1,27 @@
<?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:background="@color/background"
android:orientation="vertical" >
<TextView
android:id="@+id/gamesMessage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="20dip"
android:textSize="20sp"
android:text="@string/gameFinishMessage"/>
<Button
android:id="@+id/buttonFinish"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_below="@+id/gamesMessage"
android:layout_centerInParent="true"
android:layout_marginTop="10dp"
android:gravity="center"
android:padding="20dip"
android:text="@string/gameFinish" />
</RelativeLayout>

View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:swadroid="http://schemas.android.com/apk/res-auto" >
<item
android:id="@+id/action_question_index"
android:visible="false"
swadroid:showAsAction="always|withText" />
<item
android:id="@+id/action_no_answered"
android:icon="@drawable/ic_action_check_box_outline_blank"
android:title="@string/gameNoAnswered"
android:visible="false"
swadroid:showAsAction="always|withText" />
<item
android:id="@+id/action_answered"
android:icon="@drawable/ic_action_check_box"
android:title="@string/gameAnswered"
android:visible="false"
swadroid:showAsAction="always|withText"/>
<item
android:id="@+id/action_remove"
android:icon="@drawable/ic_menu_delete"
android:title="@string/gameAnswerRemove"
android:visible="false"
swadroid:showAsAction="always|withText" />
</menu>

View File

@ -11,6 +11,7 @@
<string name="notificationsModuleLabel">Notificaciones</string>
<string name="coursesModuleLabel">Asignaturas</string>
<string name="testsModuleLabel">Tests</string>
<string name="gamesModuleLabel">Juegos</string>
<string name="messagesModuleLabel">Enviar mensaje</string>
<string name="noticesModuleLabel">Publicar aviso</string>
<string name="generateQRModuleLabel">Generar código QR</string>
@ -124,7 +125,6 @@
plataforma de teleformación SWAD.\nObtenlo gratis aquí:
https://play.google.com/store/apps/details?id=es.ugr.swad.swadroid</string>
<string name="blogTitle">Blog</string>
<string name="prefCatSyncTitle">Sincronización</string>
<string name="prefSyncTimeTitle">Frecuencia de sincronización</string>
<string name="prefSyncTimeSummary">Frecuencia de sincronización de las notificaciones</string>
<string name="prefSyncEnableTitle">Sincronización automática</string>
@ -271,9 +271,35 @@
<string name="eventsDownloadProgressTitle">Eventos</string>
<string name="eventsUpdated">eventos actualizados</string>
<string name="eventsDownloadProgressDescription">Sincronización de eventos.\n\nDependiendo del número de eventos a sincronizar, el procesamiento de los datos puede tardar varios minutos.\n\nPor favor, espere…</string>
<string name="gamesDownloadProgressDescription">Sincronización de juegos.\n\nDependiendo del número de juegos a sincronizar, el procesamiento de los datos puede tardar varios minutos.\n\nPor favor, espere…</string>
<string name="noGamesAvailableMsg">No hay juegos en esta asignatura</string>
<string name="gamesUpdated">Juegos actualizados</string>
<string name="gamesEmptyListMsg">No se ha descargado ningún juego.\n\nPara descargar los
juegos más recientes deslice este mensaje hacia abajo.</string>
<string name="updatePendingGamesMsg">Hay juegos con cambios pendientes de enviar al servidor. Si actualiza el listado de juegos puede perder los cambios que no haya enviado.\n\n¿Está seguro de que quiere actualizar el listado de juegos?</string>
<string name="matchesDownloadProgressDescription">Sincronización de partidas.\n\nDependiendo del número de partidas a sincronizar, el procesamiento de los datos puede tardar varios minutos.\n\nPor favor, espere…</string>
<string name="noMatchesAvailableMsg">No hay partidas en este juego</string>
<string name="matchesUpdated">partidas actualizadas</string>
<string name="matchesEmptyListMsg">No se ha descargado ninguna partida.\n\nPara descargar las
partidas más recientes deslice este mensaje hacia abajo.</string>
<string name="updatePendingMatchesMsg">Hay partidas con cambios pendientes de enviar al servidor. Si actualiza el listado de partidas puede perder los cambios que no haya enviado.\n\n¿Está seguro de que quiere actualizar el listado de partidas?</string>
<string name="errorMatchStatusMsg">Ha ocurrido un error, el solicitante no puede unirse a la partida</string>
<string name="errorAnswerMatchMsg">Ha ocurrido un error, la respuesta no ha sido guardada</string>
<string name="matchPause">La partida está pausada</string>
<string name="gameAnswered">Respondida</string>
<string name="gameNoAnswered">No respondida</string>
<string name='gameAnswerRemove'>Borrar respuesta</string>
<string name='gameStart'>Inicio</string>
<string name='gameFinish'>Finalizado</string>
<string name='gameFinishMessage'>La partida ha finalizado</string>
<string name='answerRemovedMsg'>La respuesta ha sido borrada</string>
<string name='matchNotStartedMsg'>La partida no ha empezado</string>
<string name='matchFinishedMsg'>La partida ha finalizado</string>
<string name='matchPausedMsg'>La partida está pausada o está mostrando resultados</string>
<string name='matchNoAnsweredMsg'>No ha respondido a la pregunta</string>
<string name="noEventsAvailableMsg">No hay eventos en esta asignatura</string>
<string name="event">Evento</string>
<string name="usersUpdated">usuarios actualizados</string>
<string name="usersUpdated">Usuarios actualizados</string>
<string name="noUsersAvailableMsg">No hay usuarios en este evento</string>
<string name="noUsersCheckedMsg">Debe marcar al menos un usuario</string>
<string name="usersEmptyListMsg">No se ha descargado ningún usuario.\n\nPara descargar los

View File

@ -47,5 +47,26 @@
<color name="button_background_green">#55B637</color>
<color name="gray_text">#878787</color>
<color name="background_receiver">#DFDEDD</color>
<color name="button_red">#e21c3d</color>
<color name="button_blue">#1369ce</color>
<color name="button_yellow">#d89e00</color>
<color name="button_green">#2b9010</color>
<color name="button_pink">#e30087</color>
<color name="button_light_blue">#00b5e9</color>
<color name="button_orange">#f58700</color>
<color name="button_light_green">#b3d00a</color>
<color name="button_purple">#642075</color>
<color name="button_light_yellow">#f5e800</color>
<color name="button_red_border">#a9152d</color>
<color name="button_blue_border">#0e519c</color>
<color name="button_yellow_border">#a27600</color>
<color name="button_green_border">#206c0c</color>
<color name="button_pink_border">#aa0064</color>
<color name="button_light_blue_border">#0089b0</color>
<color name="button_orange_border">#b86400</color>
<color name="button_light_green_border">#869d07</color>
<color name="button_purple_border">#4b1858</color>
<color name="button_light_yellow_border">#b8ad00</color>
<color name="button_checked">#ccff00</color>
</resources>
</resources>

View File

@ -33,4 +33,5 @@
<string name="fa_home" translatable="false">&#xf015;</string>
<string name="fa_arrow_up" translatable="false">&#xf062;</string>
<string name="fa_map_marker" translatable="false">&#xf041;</string>
</resources>
<string name="fa_trophy" translatable="false">&#xf091;</string>
</resources>

View File

@ -12,6 +12,7 @@
<string name="notificationsMarkAllAsReadModuleLabel" translatable="false">NotificationsMarkAsRead</string>
<string name="coursesModuleLabel">Courses</string>
<string name="testsModuleLabel">Tests</string>
<string name="gamesModuleLabel">Games</string>
<string name="messagesModuleLabel">Send message</string>
<string name="noticesModuleLabel">Publish notice</string>
<string name="generateQRModuleLabel">Generate QR code</string>
@ -209,6 +210,36 @@
<string name="eventsDownloadProgressDescription">Synchronizing events.\n\nDepending on the number of
events to synchronize, the data processing can take several minutes.\n\nPlease wait…</string>
<string name="eventsDownloadProgressTitle">Events</string>
<string name="gamesDownloadProgressDescription">Synchronizing games.\n\nDepending on the number of
games to synchronize, the data processing can take several minutes.\n\nPlease wait…</string>
<string name="noGamesAvailableMsg">There are no games in this course</string>
<string name="gamesUpdated">Games updated</string>
<string name="gamesEmptyListMsg">Did not download any game.\n\nTo download most recent
games slide down this message.</string>
<string name="updatePendingGamesMsg">There are pending changes waiting to be sent to the server. If you
update the list of games can lose the changes.\n\nAre you sure you want to update the list of games?</string>
<string name="matchesDownloadProgressDescription">Synchronizing matches.\n\nDepending on the number of
mathes to synchronize, the data processing can take several minutes.\n\nPlease wait…</string>
<string name="noMatchesAvailableMsg">There are no matches in this game</string>
<string name="matchesUpdated">Matches updated</string>
<string name="matchesEmptyListMsg">Did not download any match.\n\nTo download most recent
matches slide down this message.</string>
<string name="updatePendingMatchesMsg">There are pending changes waiting to be sent to the server. If you
update the list of matches can lose the changes.\n\nAre you sure you want to update the list of matches?</string>
<string name="errorMatchStatusMsg">An error has occurred, the requester can not join the match</string>
<string name="errorAnswerMatchMsg">An error has occurred, the answer has not been saved</string>
<string name="matchPause">The match is paused</string>
<string name="gameAnswered">Answered</string>
<string name="gameNoAnswered">No answered</string>
<string name='gameAnswerRemove'>Remove answer</string>
<string name='gameStart'>Start</string>
<string name='gameFinish'>Finished</string>
<string name='gameFinishMessage'>The match has finished</string>
<string name='answerRemovedMsg'>The answer has been removed</string>
<string name='matchNotStartedMsg'>The match has not started</string>
<string name='matchFinishedMsg'>The match has finished</string>
<string name='matchPausedMsg'>The match is in pause or is showing result</string>
<string name='matchNoAnsweredMsg'>You have not answered the question</string>
<string name="usersUpdate">Update</string>
<string name="newTitle">New</string>
<string name="rollcallScanQR">Scan QR</string>
@ -372,4 +403,14 @@
<string name="checkIn">Time</string>
<string name="lostLocation">Location not found</string>
<string name="nearestLocation">Nearest wireless access point</string>
<string name="buttonTitleA">a</string>
<string name="buttonTitleB">b</string>
<string name="buttonTitleC">c</string>
<string name="buttonTitleD">d</string>
<string name="buttonTitleE">e</string>
<string name="buttonTitleF">f</string>
<string name="buttonTitleG">g</string>
<string name="buttonTitleH">h</string>
<string name="buttonTitleI">i</string>
<string name="buttonTitleJ">j</string>
</resources>

View File

@ -385,6 +385,134 @@
obligatory="true"
type="foreign-key" />
</table>
<table
name="games"
new-in-version="22"
to-string="%name%" >
<field
name="id"
obligatory="true"
type="long" />
<field
name="userSurname1"
obligatory="true"
type="text" />
<field
name="userSurname2"
obligatory="true"
type="text" />
<field
name="userFirstName"
obligatory="true"
type="text" />
<field
name="userPhoto"
obligatory="true"
type="text" />
<field
name="startTime"
obligatory="true"
type="integer" />
<field
name="endTime"
obligatory="true"
type="integer" />
<field
name="title"
obligatory="true"
type="string" />
<field
name="text"
obligatory="true"
type="string" />
<field
name="numQuestions"
obligatory="true"
type="integer" />
<field
name="maxGrade"
obligatory="true"
type="float" />
<field
name="visibility"
obligatory="true"
type="integer" />
</table>
<table
name="matches"
new-in-version="22"
to-string="%name%" >
<field
name="id"
obligatory="true"
type="long" />
<field
name="userSurname1"
obligatory="true"
type="text" />
<field
name="userSurname2"
obligatory="true"
type="text" />
<field
name="userFirstName"
obligatory="true"
type="text" />
<field
name="userPhoto"
obligatory="true"
type="text" />
<field
name="startTime"
obligatory="true"
type="integer" />
<field
name="endTime"
obligatory="true"
type="integer" />
<field
name="title"
obligatory="true"
type="string" />
<field
name="questionIndex"
obligatory="true"
type="integer" />
<field
name="groups"
obligatory="true"
type="text" />
</table>
<table
name="games_courses"
new-in-version="22"
to-string="%name%" >
<field
name="gameCode"
foreign-table="games"
obligatory="true"
type="foreign-key" />
<field
name="crsCod"
foreign-table="courses"
obligatory="true"
type="foreign-key" />
</table>
<table
name="matches_games"
new-in-version="22"
to-string="%name%" >
<field
name="matchCode"
foreign-table="matches"
obligatory="true"
type="foreign-key" />
<field
name="gameCode"
foreign-table="games"
obligatory="true"
type="foreign-key" />
</table>
<table
name="groups"
new-in-version="11"
@ -516,4 +644,4 @@
type="double" />
</table>
</database>
</database>