diff --git a/app/build.gradle b/app/build.gradle index d26925c..1cbc78d 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -30,5 +30,6 @@ dependencies { compile 'com.google.code.gson:gson:2.4' compile 'com.android.support:design:23.4.0' compile 'com.loopj.android:android-async-http:1.4.9' + compile 'org.ocpsoft.prettytime:prettytime:4.0.1.Final' testCompile 'junit:junit:4.12' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index c878098..a13252b 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -20,10 +20,10 @@ android:label="@string/app_name" android:theme="@style/FullscreenTheme"> - - - - + + + + - + + + \ No newline at end of file diff --git a/app/src/main/assets/unifont-9.0.02.ttf b/app/src/main/assets/unifont-9.0.02.ttf new file mode 100644 index 0000000..4e5018e Binary files /dev/null and b/app/src/main/assets/unifont-9.0.02.ttf differ diff --git a/app/src/main/java/com/rubenvandeven/emotionhero/ApiRestClient.java b/app/src/main/java/com/rubenvandeven/emotionhero/ApiRestClient.java index 9e68d55..935fa0a 100644 --- a/app/src/main/java/com/rubenvandeven/emotionhero/ApiRestClient.java +++ b/app/src/main/java/com/rubenvandeven/emotionhero/ApiRestClient.java @@ -17,6 +17,10 @@ import org.json.JSONException; import org.json.JSONObject; import java.io.UnsupportedEncodingException; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Locale; +import java.util.TimeZone; import cz.msebera.android.httpclient.Header; import cz.msebera.android.httpclient.HeaderElement; @@ -165,13 +169,17 @@ public class ApiRestClient { try { j.put("lvl_id", game.scenario.id); j.put("score", game.score); - j.put("time", game.time); + TimeZone tz = TimeZone.getTimeZone("UTC"); + DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); + df.setTimeZone(tz); + j.put("time", df.format(game.time)); JSONArray jHits = new JSONArray(); j.put("hits", jHits); for(Hit hit: game.hits.values()) { JSONObject jHit = new JSONObject(); + jHit.put("id", hit.id); jHit.put("target_index", hit.target.index); jHit.put("score", hit.score); jHit.put("glasses", hit.glasses); @@ -241,6 +249,11 @@ public class ApiRestClient { handleOnFailure(statusCode, headers, responseString, throwable); } + @Override + public void onFailure(int statusCode, Header[] headers, Throwable throwable, JSONObject response) { + onFailure(statusCode, headers, response.toString(), throwable); + } + }); } @@ -253,6 +266,12 @@ public class ApiRestClient { Log.e("API", "\t" + header.getName() + ": " + header.getValue()); } Log.e("API", "Response:"); - Log.e("API", responseString); + int maxLogSize = 1000; + for(int i = 0; i <= responseString.length() / maxLogSize; i++) { + int start = i * maxLogSize; + int end = (i+1) * maxLogSize; + end = end > responseString.length() ? responseString.length() : end; + Log.e("API", responseString.substring(start, end)); + } } } diff --git a/app/src/main/java/com/rubenvandeven/emotionhero/GameOpenHelper.java b/app/src/main/java/com/rubenvandeven/emotionhero/GameOpenHelper.java index 02215f7..bc7b420 100644 --- a/app/src/main/java/com/rubenvandeven/emotionhero/GameOpenHelper.java +++ b/app/src/main/java/com/rubenvandeven/emotionhero/GameOpenHelper.java @@ -201,24 +201,8 @@ public class GameOpenHelper extends SQLiteOpenHelper { } public Game[] getGamesForLevel(int lvl_id) { - SQLiteDatabase db = getReadableDatabase(); - - String selection = "lvl_id = ?"; - String[] selectionArgs = { Integer.toString(lvl_id) }; - - String sortOrder = "score DESC"; - - Cursor c = db.query( - GAME_TABLE_NAME, // The table to query - GAME_PROJECTION, // The columns to return - selection, // The columns for the WHERE clause - selectionArgs, // The values for the WHERE clause - null, // don't group the rows - null, // don't filter by row groups - sortOrder, // The sort order - null // no limit! - ); - return cursorToGames(c, null); + Scenario scenario = new Scenario(lvl_id, null); + return getGamesForScenario(scenario); } public Game[] getGamesForScenario(Scenario s) { @@ -249,7 +233,7 @@ public class GameOpenHelper extends SQLiteOpenHelper { c.moveToFirst(); while (!c.isAfterLast()) { Scenario scenario = s == null ? new Scenario(c.getInt(1), null) : s; - Game game = new Game(c.getLong(0), scenario, c.getFloat(2), new Date(c.getInt(3)), c.getString(4)); + Game game = new Game(c.getLong(0), scenario, c.getFloat(2), new Date(c.getLong(3)), c.getString(4)); games[i] = game; this.getHitsForGame(game); // hits are appended to game object i++; diff --git a/app/src/main/java/com/rubenvandeven/emotionhero/GamingActivity.java b/app/src/main/java/com/rubenvandeven/emotionhero/GamingActivity.java index f460bfc..9abbb3b 100644 --- a/app/src/main/java/com/rubenvandeven/emotionhero/GamingActivity.java +++ b/app/src/main/java/com/rubenvandeven/emotionhero/GamingActivity.java @@ -396,9 +396,15 @@ public class GamingActivity extends AppCompatActivity implements Detector.ImageL GameOpenHelper gameHelper = new GameOpenHelper(getApplicationContext()); gameHelper.insertGame(currentScenario.game); - Intent intent = new Intent(this, HighscoreActivity.class); - intent.putExtra(HighscoreActivity.INTENT_EXTRA_SCORE_ID, score.id.toString()); - intent.putExtra(HighscoreActivity.INTENT_EXTRA_GAME_ID, currentScenario.game.id.toString()); + + Intent intent = new Intent(this, ReviewActivity.class); + intent.putExtra(ReviewActivity.INTENT_EXTRA_GAME_ID, currentScenario.game.id); + intent.putExtra(ReviewActivity.INTENT_EXTRA_FROM_GAME, true); startActivity(intent); + +// Intent intent = new Intent(this, HighscoreActivity.class); +// intent.putExtra(HighscoreActivity.INTENT_EXTRA_SCORE_ID, score.id.toString()); +// intent.putExtra(HighscoreActivity.INTENT_EXTRA_GAME_ID, currentScenario.game.id.toString()); +// startActivity(intent); } } diff --git a/app/src/main/java/com/rubenvandeven/emotionhero/HighscoreActivity.java b/app/src/main/java/com/rubenvandeven/emotionhero/HighscoreActivity.java index 56b91f8..93500b8 100644 --- a/app/src/main/java/com/rubenvandeven/emotionhero/HighscoreActivity.java +++ b/app/src/main/java/com/rubenvandeven/emotionhero/HighscoreActivity.java @@ -27,6 +27,8 @@ import android.widget.Button; import android.widget.LinearLayout; import android.widget.TextView; +import org.ocpsoft.prettytime.PrettyTime; + import java.util.UUID; public class HighscoreActivity extends AppCompatActivity { @@ -58,6 +60,7 @@ public class HighscoreActivity extends AppCompatActivity { * with the given score highligted */ Score score; + Game game; @Override protected void onCreate(Bundle savedInstanceState) { @@ -67,15 +70,17 @@ public class HighscoreActivity extends AppCompatActivity { player = Player.getInstance(getApplicationContext()); - String scoreIdString = getIntent().getStringExtra(INTENT_EXTRA_SCORE_ID); +// // get score from Intent +// String scoreIdString = getIntent().getStringExtra(INTENT_EXTRA_SCORE_ID); +// if(scoreIdString != null) { +// UUID score_id = UUID.fromString(scoreIdString); +// score = player.getPlayerInfo().getScore(score_id); +// if(score == null) { +// Log.e("Highscore", "CANNOT FIND SCORE!! " + scoreIdString); +// } +// } + // get game from Intent String gameIdString = getIntent().getStringExtra(INTENT_EXTRA_GAME_ID); - if(scoreIdString != null) { - UUID score_id = UUID.fromString(scoreIdString); - score = player.getPlayerInfo().getScore(score_id); - if(score == null) { - Log.e("Highscore", "CANNOT FIND SCORE!! " + scoreIdString); - } - } if(gameIdString != null) { long gameId = Long.valueOf(gameIdString); Game game = player.getGameOpenHelper().getGameByid(gameId); @@ -102,9 +107,9 @@ public class HighscoreActivity extends AppCompatActivity { mViewPager = (ViewPager) findViewById(R.id.container); mViewPager.setAdapter(mSectionsPagerAdapter); - // if score is set, set current page. - if(score != null) { - int levelpage = Scenario.SCENARIOS.indexOf(score.lvl_id); + // if game is set, set current page. + if(game != null) { + int levelpage = Scenario.SCENARIOS.indexOf(game.scenario.id); mViewPager.setCurrentItem(levelpage); } @@ -140,7 +145,7 @@ public class HighscoreActivity extends AppCompatActivity { * fragment. */ private static final String ARG_LVL_ID = "LVL_ID"; - private static final String ARG_SCORE_ID = "SCORE_ID"; + private static final String ARG_GAME_ID = "GAME_ID"; public HighscoreFragment() { } @@ -149,11 +154,13 @@ public class HighscoreActivity extends AppCompatActivity { * Returns a new instance of this fragment for the given section * number. */ - public static HighscoreFragment newInstance(int lvl_id, String scoreIdString) { + public static HighscoreFragment newInstance(int lvl_id, Long gameId) { HighscoreFragment fragment = new HighscoreFragment(); Bundle args = new Bundle(); args.putInt(ARG_LVL_ID, lvl_id); - args.putString(ARG_SCORE_ID, scoreIdString); + if(gameId != null) { + args.putLong(ARG_GAME_ID, gameId); + } fragment.setArguments(args); return fragment; } @@ -170,28 +177,28 @@ public class HighscoreActivity extends AppCompatActivity { int lvl_id = getArguments().getInt(ARG_LVL_ID); - Score score = null; - String scoreIdString = getArguments().getString(ARG_SCORE_ID); + Game currentGame = null; + long gameId= getArguments().getLong(ARG_GAME_ID); final Scenario scenario = new Scenario(lvl_id, null); Player player = Player.getInstance(getContext()); - ScoreList scores = player.getPlayerInfo().getScoresForLevel(lvl_id); + GameOpenHelper gameOpenHelper = player.getGameOpenHelper(); - if(scoreIdString != null) { - UUID scoreId = UUID.fromString(scoreIdString); - score = player.getPlayerInfo().getScore(scoreId); + Game[] games = gameOpenHelper.getGamesForScenario(scenario); + + if(gameId != 0) { + Log.d("Highscore", "Request game: " + gameId); + currentGame = gameOpenHelper.getGameByid(gameId); } TextView levelName = (TextView) rootView.findViewById(R.id.levelName); - levelName.setText(scenario.toString()); - - ScoreList topscores = scores.getTopN(5); + levelName.setText("\""+scenario.toString()+"\""); LinearLayout topscoreList = (LinearLayout) rootView.findViewById(R.id.topscoreList); - if(topscores.size() == 0) { + if(games.length == 0) { // TextView noScoreItemText = new TextView(getContext(), null, R.style.AppTheme); TextView noScoreItemText = new TextView(getContext()); noScoreItemText.setText("No Scores"); @@ -201,40 +208,65 @@ public class HighscoreActivity extends AppCompatActivity { topscoreList.addView(noScoreItemText); } + + PrettyTime prettyTime = new PrettyTime(); + boolean foundScore = false; int i = 0; - for(Score topscore: topscores) { + for(Game game: games) { + final long itemGameId = game.id; i++; - String highscoreText = String.format("%1$d. %2$.2f", i, topscore.score); //make line by line elements + String highscoreText = String.format("%1$d. %2$.3f", i, game.score); //make line by line elements TextView scoreItem = new TextView(getContext()); scoreItem.setText(highscoreText); scoreItem.setTextColor(ContextCompat.getColor(getContext(), R.color.highscore)); - float multiplier = 1 + (5-i)/5f; + scoreItem.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent intent = new Intent(getContext(), ReviewActivity.class); + intent.putExtra(ReviewActivity.INTENT_EXTRA_GAME_ID, itemGameId); + startActivity(intent); + // don't finish.. keep previous button :-) + } + }); + + float multiplier = i <= 5 ? 1 + (5-i)/5f : 1f; scoreItem.setTextSize(getResources().getDimension(R.dimen.highscore_textsize) * multiplier); scoreItem.setTypeface(Typeface.DEFAULT_BOLD); topscoreList.addView(scoreItem); - if(score != null && topscore.id == score.id) { + TextView dateItem = new TextView(getContext()); + dateItem.setText(prettyTime.format(game.time)); + dateItem.setTextColor(ContextCompat.getColor(getContext(), R.color.textSecondary)); + LinearLayout.LayoutParams llp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT); + llp.setMargins(0, -20, 0, 0); // llp.setMargins(left, top, right, bottom); + dateItem.setLayoutParams(llp); + dateItem.setTypeface(Typeface.DEFAULT); + topscoreList.addView(dateItem); + + if(currentGame != null && currentGame.id == game.id) { foundScore = true; setBlinking(scoreItem); + topscoreList.requestChildFocus(scoreItem, scoreItem); // scroll to item?? } } - // if score is set.. but not a highscore... - if(score != null && foundScore == false) { - String highscoreText = String.format("\n... %1$.2f", score.score); //make line by line elements - TextView scoreItem = new TextView(getContext()); - scoreItem.setText(highscoreText); - scoreItem.setTextColor(ContextCompat.getColor(getContext(), R.color.highscore)); - scoreItem.setTextSize(getResources().getDimension(R.dimen.highscore_textsize)); - scoreItem.setTypeface(Typeface.DEFAULT_BOLD); - topscoreList.addView(scoreItem); - setBlinking(scoreItem); - } + // we now display all scores :-) +// // if score is set.. but not a highscore... +// if(score != null && foundScore == false) { +// String highscoreText = String.format("\n... %1$.2f", score.score); //make line by line elements +// TextView scoreItem = new TextView(getContext()); +// scoreItem.setText(highscoreText); +// scoreItem.setTextColor(ContextCompat.getColor(getContext(), R.color.highscore)); +// scoreItem.setTextSize(getResources().getDimension(R.dimen.highscore_textsize)); +// scoreItem.setTypeface(Typeface.DEFAULT_BOLD); +// topscoreList.addView(scoreItem); +// setBlinking(scoreItem); +// } if(player.getPlayerInfo().hasAccessToLevel(lvl_id)) { - if(score != null) { // if we come from the level itself.. show retry! + if(currentGame != null) { // if we come from the level itself.. show retry! startLvlButton.setText("Retry"); } startLvlButton.setOnClickListener(new View.OnClickListener() { @@ -294,11 +326,11 @@ public class HighscoreActivity extends AppCompatActivity { // Return a HighscoreFragment (defined as a static inner class below). // position is the used to get lvl_id. int lvl_id = getLevelIdForPosition(position); - String scoreString = null; - if(score != null && lvl_id == score.lvl_id) { - scoreString = score.id.toString(); + Long gameId = null; + if(game != null && lvl_id == game.scenario.id) { + gameId = game.id; } - return HighscoreFragment.newInstance(lvl_id, scoreString); + return HighscoreFragment.newInstance(lvl_id, gameId); } public int getLevelIdForPosition(int position) { diff --git a/app/src/main/java/com/rubenvandeven/emotionhero/ReviewActivity.java b/app/src/main/java/com/rubenvandeven/emotionhero/ReviewActivity.java new file mode 100644 index 0000000..df939a1 --- /dev/null +++ b/app/src/main/java/com/rubenvandeven/emotionhero/ReviewActivity.java @@ -0,0 +1,105 @@ +package com.rubenvandeven.emotionhero; + +import android.content.Intent; +import android.graphics.Typeface; +import android.support.v7.app.AppCompatActivity; +import android.os.Bundle; +import android.support.v7.widget.Toolbar; +import android.util.Log; +import android.view.MenuItem; +import android.view.WindowManager; +import android.widget.TextView; + +import org.ocpsoft.prettytime.PrettyTime; + +public class ReviewActivity extends AppCompatActivity { + + + public final static String INTENT_EXTRA_GAME_ID = "com.rubenvandeven.emotionhero.GAME_ID"; + public final static String INTENT_EXTRA_FROM_GAME = "com.rubenvandeven.emotionhero.FROM_GAME"; + + + protected Player player; + + protected Game game; + /** + * Whether this activity is loaded from the game (else from highscores) + */ + protected boolean fromGame; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); + setContentView(R.layout.activity_review); + + Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); + setSupportActionBar(toolbar); + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + getSupportActionBar().setTitle("Score"); + + + player = Player.getInstance(getApplicationContext()); + + // get game from Intent + long gameId = getIntent().getLongExtra(INTENT_EXTRA_GAME_ID, 0); + fromGame = getIntent().getBooleanExtra(INTENT_EXTRA_FROM_GAME, false); + Log.d("Review", "gameid:" + gameId); + if(gameId != 0) { + game = player.getGameOpenHelper().getGameByid(gameId); + if(game == null) { + Log.e("Highscore", "CANNOT FIND GAME!! " + gameId); + throw new RuntimeException("Cannot find specified game"); + } else { + Log.i("Highscore", "FOUND GAME" + game.id + " " + game.score); + Log.i("Highscore", "RANK " + player.getGameOpenHelper().getLocalRankOfGame(game)); + player.api.syncGame(game); // sync game if that is not already done + } + } else { + // no game specified??? SHould not be possible so finish + finish(); + } + + TextView lvlNameText = (TextView) findViewById(R.id.lvlNameText); + TextView dateText = (TextView) findViewById(R.id.dateText); + TextView scoreText= (TextView) findViewById(R.id.scoreText); + TextView overallScorePercText= (TextView) findViewById(R.id.overallScorePercText); + TextView improveArrow = (TextView) findViewById(R.id.improveArrow); + TextView retryArrow = (TextView) findViewById(R.id.retryArrow); + + + + Typeface font = Typeface.createFromAsset(getAssets(), "unifont-9.0.02.ttf"); + lvlNameText.setTypeface(font); + overallScorePercText.setTypeface(font); + retryArrow.setTypeface(font); + improveArrow.setTypeface(font); + + lvlNameText.setText("\""+game.scenario.toString()+"\""); + PrettyTime p = new PrettyTime(); + dateText.setText(p.format(game.time)); + scoreText.setText(String.format("%1$.3f", game.score)); + overallScorePercText.setText(String.format("%1$.0f%%", 30f)); + + + } + + @Override + public boolean onOptionsItemSelected(MenuItem menuItem) + { + switch (menuItem.getItemId()) { + case android.R.id.home: + if(fromGame) { + Intent intent = new Intent(getApplicationContext(), HighscoreActivity.class); + intent.putExtra(HighscoreActivity.INTENT_EXTRA_GAME_ID, game.id); + finish(); + startActivity(intent); + } else { + onBackPressed(); + } + return true; + default: + return super.onOptionsItemSelected(menuItem); + } + } +} diff --git a/app/src/main/java/com/rubenvandeven/emotionhero/Scenario.java b/app/src/main/java/com/rubenvandeven/emotionhero/Scenario.java index b1772ce..285ae70 100644 --- a/app/src/main/java/com/rubenvandeven/emotionhero/Scenario.java +++ b/app/src/main/java/com/rubenvandeven/emotionhero/Scenario.java @@ -136,7 +136,7 @@ public class Scenario { if(target.timestamp <= runningTime) { float scored_value = target.emotion.getValueFromFace(currentFace); float required_value = target.value; - float score = Math.round(100 - Math.abs(scored_value-required_value)); + float score = 100 - Math.abs(scored_value-required_value); Hit hit = new Hit(target, game, currentFace, score); // diff --git a/app/src/main/java/com/rubenvandeven/emotionhero/ScenarioView.java b/app/src/main/java/com/rubenvandeven/emotionhero/ScenarioView.java index 377f68e..57b1a3c 100644 --- a/app/src/main/java/com/rubenvandeven/emotionhero/ScenarioView.java +++ b/app/src/main/java/com/rubenvandeven/emotionhero/ScenarioView.java @@ -198,7 +198,7 @@ public class ScenarioView extends SurfaceView implements SurfaceHolder.Callback if(target.isHit) { Hit hit = _scenario.getHitForTarget(target); - canvas.drawText(Float.toString(hit.score), cx, cy, emoPaints.get(target.emotion)); + canvas.drawText(Integer.toString(Math.round(hit.score)), cx, cy, emoPaints.get(target.emotion)); canvas.drawCircle(cx, cy, max_ball_radius * hit.score/100, emoScoredPaints.get(target.emotion)); // TODO: Use target.hit.face to set Rect src. diff --git a/app/src/main/java/com/rubenvandeven/emotionhero/Score.java b/app/src/main/java/com/rubenvandeven/emotionhero/Score.java index d816371..07cded2 100644 --- a/app/src/main/java/com/rubenvandeven/emotionhero/Score.java +++ b/app/src/main/java/com/rubenvandeven/emotionhero/Score.java @@ -6,6 +6,8 @@ import java.util.UUID; /** * Created by ruben on 19/08/16. + * + * @deprecated */ public class Score { diff --git a/app/src/main/res/drawable/winner.png b/app/src/main/res/drawable/winner.png new file mode 100644 index 0000000..dc4683e Binary files /dev/null and b/app/src/main/res/drawable/winner.png differ diff --git a/app/src/main/res/layout/activity_credits.xml b/app/src/main/res/layout/activity_credits.xml index 72e16a8..ba7b422 100644 --- a/app/src/main/res/layout/activity_credits.xml +++ b/app/src/main/res/layout/activity_credits.xml @@ -41,7 +41,9 @@ \n\nThis project is produced as part of the Summer Sessions Network for Talent Development in a co-production of Arquivo 237 and V2_ Institute for the Unstable Media.\n -\n\nEmotional intelligence powered by Affectiva." +\n\nEmotional intelligence powered by Affectiva. + +\n\n Font used:\n - Unifont CSUR - GPL" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/textView" /> diff --git a/app/src/main/res/layout/activity_review.xml b/app/src/main/res/layout/activity_review.xml new file mode 100644 index 0000000..c8f28f5 --- /dev/null +++ b/app/src/main/res/layout/activity_review.xml @@ -0,0 +1,236 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_highscore.xml b/app/src/main/res/layout/fragment_highscore.xml index 87ac5ee..21c50b1 100644 --- a/app/src/main/res/layout/fragment_highscore.xml +++ b/app/src/main/res/layout/fragment_highscore.xml @@ -13,27 +13,33 @@ - - - + android:layout_alignParentTop="true" + android:layout_alignParentLeft="true" + android:layout_alignParentStart="true"> + + + + + + #ff00ff #ff8c00 #00aaff + #ffffff + #999999 + #ffff00 diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 12671f8..1608819 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -44,4 +44,8 @@ @color/highscore + +