From 7eb9e6f954a0e210fa2ebf2054a46f5cc584f0f2 Mon Sep 17 00:00:00 2001 From: David Hebbeker Date: Sat, 17 Mar 2018 15:58:48 +0100 Subject: [PATCH 01/12] Defined simple class to hold score information. Relates to #4. --- .../info/hebbeker/david/memorex/Score.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 app/src/main/java/info/hebbeker/david/memorex/Score.java diff --git a/app/src/main/java/info/hebbeker/david/memorex/Score.java b/app/src/main/java/info/hebbeker/david/memorex/Score.java new file mode 100644 index 0000000..1ded8a4 --- /dev/null +++ b/app/src/main/java/info/hebbeker/david/memorex/Score.java @@ -0,0 +1,21 @@ +package info.hebbeker.david.memorex; + +/** + * Does contain information about a score. + * \todo Add the following attributes: username, speed, date, points + */ +public class Score +{ + /** + * Completed level. + *

+ * If the player fails at level 2, the completed level is 1. If he fails at level 1, the + * completed level is 0. + */ + private final int level; + + public Score(final int level) + { + this.level = level; + } +} From 18a85dcb5eb7f961be6227822ba00068c0787d34 Mon Sep 17 00:00:00 2001 From: David Hebbeker Date: Sat, 17 Mar 2018 18:52:40 +0100 Subject: [PATCH 02/12] Developed a class to (de-)serialize objects to strings. Usage of Base64 decoder has been avoided in order to be compatible to low API levels. --- .../david/util/StringSerialization.java | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 app/src/main/java/info/hebbeker/david/util/StringSerialization.java diff --git a/app/src/main/java/info/hebbeker/david/util/StringSerialization.java b/app/src/main/java/info/hebbeker/david/util/StringSerialization.java new file mode 100644 index 0000000..ef3b41e --- /dev/null +++ b/app/src/main/java/info/hebbeker/david/util/StringSerialization.java @@ -0,0 +1,36 @@ +package info.hebbeker.david.util; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; + +public class StringSerialization +{ + /** + * Serialize object to byte array and convert to String. + */ + public static String serialize(final Serializable objectToSerialize) throws IOException + { + final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + final ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream); + objectOutputStream.writeObject(objectToSerialize); + objectOutputStream.flush(); + objectOutputStream.close(); + return byteArrayOutputStream.toString(); + } + + /** + * Decode String to byte array and deserialize. + */ + public static Object deserialize(final String serializedObject) throws IOException, ClassNotFoundException + { + final byte serializedObjectBytes[] = serializedObject.getBytes(); + final ObjectInputStream objectInputStream = new ObjectInputStream(new ByteArrayInputStream(serializedObjectBytes)); + final Object deserializedObject = objectInputStream.readObject(); + objectInputStream.close(); + return deserializedObject; + } +} From b0eb320500fed46372c3454e62456dca5e24dfbd Mon Sep 17 00:00:00 2001 From: David Hebbeker Date: Sat, 17 Mar 2018 20:05:31 +0100 Subject: [PATCH 03/12] Defined container to store and load high scores. Relates to #4. --- .../david/memorex/HighScoreContainer.java | 63 +++++++++++++++++++ .../info/hebbeker/david/memorex/Score.java | 12 +++- 2 files changed, 73 insertions(+), 2 deletions(-) create mode 100644 app/src/main/java/info/hebbeker/david/memorex/HighScoreContainer.java diff --git a/app/src/main/java/info/hebbeker/david/memorex/HighScoreContainer.java b/app/src/main/java/info/hebbeker/david/memorex/HighScoreContainer.java new file mode 100644 index 0000000..f414dec --- /dev/null +++ b/app/src/main/java/info/hebbeker/david/memorex/HighScoreContainer.java @@ -0,0 +1,63 @@ +package info.hebbeker.david.memorex; + +import android.content.SharedPreferences; + +import java.io.IOError; +import java.io.IOException; + +import info.hebbeker.david.util.StringSerialization; + +class HighScoreContainer +{ + final private SharedPreferences sharedPref; + final private String highScorePreferenceKey = "HighScoreStorage"; + private Score currentHighScore; + + HighScoreContainer(final SharedPreferences sharedPref) + { + this.sharedPref = sharedPref; + loadHighScore(); + } + + private void loadHighScore() + { + try + { + String highScoreSerializedObject = this.sharedPref.getString(highScorePreferenceKey, ""); + currentHighScore = (Score) StringSerialization.deserialize(highScoreSerializedObject); + if (currentHighScore == null) + { + throw new Exception("Getting stored high score failed!"); + } + } catch (Exception e) + { + e.printStackTrace(); + currentHighScore = new Score(0); + saveHighScore(); + } + } + + boolean setNewHighScore(final Score newScore) + { + final boolean isNewHighScore = newScore.isGreaterThan(currentHighScore); + if (isNewHighScore) + { + currentHighScore = newScore; + saveHighScore(); + } + return isNewHighScore; + } + + private void saveHighScore() + { + try + { + SharedPreferences.Editor editor = sharedPref.edit(); + editor.putString(highScorePreferenceKey, StringSerialization.serialize(currentHighScore)); + editor.apply(); + } catch (IOException e) + { + throw new IOError(e); // nothing I can do about it... + } + } +} diff --git a/app/src/main/java/info/hebbeker/david/memorex/Score.java b/app/src/main/java/info/hebbeker/david/memorex/Score.java index 1ded8a4..59f4eed 100644 --- a/app/src/main/java/info/hebbeker/david/memorex/Score.java +++ b/app/src/main/java/info/hebbeker/david/memorex/Score.java @@ -4,7 +4,7 @@ * Does contain information about a score. * \todo Add the following attributes: username, speed, date, points */ -public class Score +class Score implements java.io.Serializable { /** * Completed level. @@ -14,8 +14,16 @@ public class Score */ private final int level; - public Score(final int level) + Score(final int level) { this.level = level; } + + /** + * @return true if this score is greater than other score + */ + boolean isGreaterThan(final Score otherScore) + { + return this.level > otherScore.level; + } } From bc79c59824bb5ab235ea086fef24b6ca2e8aaa4b Mon Sep 17 00:00:00 2001 From: David Hebbeker Date: Sun, 18 Mar 2018 08:11:07 +0100 Subject: [PATCH 04/12] Removed serialization class. The serialization class, as it, is insufficient to be used with [SharedPreferences][]. This may be an [issue with the format][1]. Thus encoding is necessary [2]! Encoding can be achieved through: * Official [Base64][] class. Downside: Requires API level 26. * [Base64Coder][] class (license: MIT). Downside: Dependency to uncertain code quality. In case an additional dependency is added, one could also consider to outsource the complete (de-)serialization. For example to: * [TinyDB][]. Downside: Dependency to uncertain license and code quality. * Apache serialization utilities [3], [Gson Library][] or ObjectSerializer class from Apache Pig project [4]. [SharedPreferences]: https://developer.android.com/reference/android/content/SharedPreferences.html [1]: https://stackoverflow.com/a/44029114/5534993 [Base64]: https://developer.android.com/reference/java/util/Base64.html [2]: https://stackoverflow.com/revisions/134918/9 [3]: https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/SerializationUtils.html [Base64Coder]: http://www.source-code.biz/base64coder/java/ [TinyDB]: https://github.com/kcochibili/TinyDB--Android-Shared-Preferences-Turbo [4]: https://github.com/apache/pig/blob/89c2e8e76c68d0d0abe6a36b4e08ddc56979796f/src/org/apache/pig/impl/util/ObjectSerializer.java [Gson Library]: https://github.com/google/gson (reverted from commit 18a85dcb5eb7f961be6227822ba00068c0787d34) --- .../david/util/StringSerialization.java | 36 ------------------- 1 file changed, 36 deletions(-) delete mode 100644 app/src/main/java/info/hebbeker/david/util/StringSerialization.java diff --git a/app/src/main/java/info/hebbeker/david/util/StringSerialization.java b/app/src/main/java/info/hebbeker/david/util/StringSerialization.java deleted file mode 100644 index ef3b41e..0000000 --- a/app/src/main/java/info/hebbeker/david/util/StringSerialization.java +++ /dev/null @@ -1,36 +0,0 @@ -package info.hebbeker.david.util; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.Serializable; - -public class StringSerialization -{ - /** - * Serialize object to byte array and convert to String. - */ - public static String serialize(final Serializable objectToSerialize) throws IOException - { - final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); - final ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream); - objectOutputStream.writeObject(objectToSerialize); - objectOutputStream.flush(); - objectOutputStream.close(); - return byteArrayOutputStream.toString(); - } - - /** - * Decode String to byte array and deserialize. - */ - public static Object deserialize(final String serializedObject) throws IOException, ClassNotFoundException - { - final byte serializedObjectBytes[] = serializedObject.getBytes(); - final ObjectInputStream objectInputStream = new ObjectInputStream(new ByteArrayInputStream(serializedObjectBytes)); - final Object deserializedObject = objectInputStream.readObject(); - objectInputStream.close(); - return deserializedObject; - } -} From 3c7bab78f4f8d525e4cd17b631bd21633cca7001 Mon Sep 17 00:00:00 2001 From: David Hebbeker Date: Sun, 18 Mar 2018 10:00:32 +0100 Subject: [PATCH 05/12] Switched form own serialization class to Gson library. Relates to #4. --- app/build.gradle | 1 + .../david/memorex/HighScoreContainer.java | 29 +++++++++---------- .../info/hebbeker/david/memorex/Score.java | 2 +- 3 files changed, 15 insertions(+), 17 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index e7f7a38..2c798c9 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -60,4 +60,5 @@ dependencies { testImplementation 'junit:junit:4.12' androidTestImplementation 'com.android.support.test:runner:1.0.1' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1' + compile "com.google.code.gson:gson:2.8.2" } diff --git a/app/src/main/java/info/hebbeker/david/memorex/HighScoreContainer.java b/app/src/main/java/info/hebbeker/david/memorex/HighScoreContainer.java index f414dec..b4c4c6a 100644 --- a/app/src/main/java/info/hebbeker/david/memorex/HighScoreContainer.java +++ b/app/src/main/java/info/hebbeker/david/memorex/HighScoreContainer.java @@ -2,15 +2,16 @@ import android.content.SharedPreferences; -import java.io.IOError; -import java.io.IOException; +import com.google.gson.Gson; +import com.google.gson.JsonSyntaxException; -import info.hebbeker.david.util.StringSerialization; +import java.io.IOException; class HighScoreContainer { final private SharedPreferences sharedPref; final private String highScorePreferenceKey = "HighScoreStorage"; + final private Gson gson = new Gson(); private Score currentHighScore; HighScoreContainer(final SharedPreferences sharedPref) @@ -24,12 +25,13 @@ private void loadHighScore() try { String highScoreSerializedObject = this.sharedPref.getString(highScorePreferenceKey, ""); - currentHighScore = (Score) StringSerialization.deserialize(highScoreSerializedObject); - if (currentHighScore == null) + currentHighScore = gson.fromJson(highScoreSerializedObject, Score.class); + if (currentHighScore == null) // this may be overcautious { - throw new Exception("Getting stored high score failed!"); + throw new IOException("Getting stored high score failed!"); } - } catch (Exception e) + } + catch (JsonSyntaxException|IOException e) { e.printStackTrace(); currentHighScore = new Score(0); @@ -50,14 +52,9 @@ boolean setNewHighScore(final Score newScore) private void saveHighScore() { - try - { - SharedPreferences.Editor editor = sharedPref.edit(); - editor.putString(highScorePreferenceKey, StringSerialization.serialize(currentHighScore)); - editor.apply(); - } catch (IOException e) - { - throw new IOError(e); // nothing I can do about it... - } + SharedPreferences.Editor editor = sharedPref.edit(); + String highScoreSerializedObject = gson.toJson(currentHighScore); + editor.putString(highScorePreferenceKey, highScoreSerializedObject); + editor.apply(); } } diff --git a/app/src/main/java/info/hebbeker/david/memorex/Score.java b/app/src/main/java/info/hebbeker/david/memorex/Score.java index 59f4eed..bcd97f8 100644 --- a/app/src/main/java/info/hebbeker/david/memorex/Score.java +++ b/app/src/main/java/info/hebbeker/david/memorex/Score.java @@ -4,7 +4,7 @@ * Does contain information about a score. * \todo Add the following attributes: username, speed, date, points */ -class Score implements java.io.Serializable +class Score { /** * Completed level. From 0c6409f9dd76394c19fce6c066de90cb6ad03db9 Mon Sep 17 00:00:00 2001 From: David Hebbeker Date: Sun, 18 Mar 2018 10:54:12 +0100 Subject: [PATCH 06/12] Integration of HighScoreContainer. High score is now recorded. Relates to #4. --- app/src/main/java/info/hebbeker/david/memorex/Game.java | 8 ++++++-- .../java/info/hebbeker/david/memorex/MainActivity.java | 7 +++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/info/hebbeker/david/memorex/Game.java b/app/src/main/java/info/hebbeker/david/memorex/Game.java index aad12f0..c645a74 100644 --- a/app/src/main/java/info/hebbeker/david/memorex/Game.java +++ b/app/src/main/java/info/hebbeker/david/memorex/Game.java @@ -68,12 +68,16 @@ private void nextLevel() gameBoardInterface.queueDisplaySymbolSequence(symbolSequence); } - void putPlayerInput(final Symbol symbol) + void putPlayerInput(final Symbol symbol, final HighScoreContainer highScoreContainer) { // if input symbol is not correct, notify user and reset board game if (symbol != currentSymbol.next()) { - gameBoardInterface.notifyUser("Game Over (" + symbolSequence.size() + ")"); + // end current game + final int completedLevel = symbolSequence.size() - 1; + final Score score = new Score(completedLevel); + highScoreContainer.setNewHighScore(score); + gameBoardInterface.notifyUser("Game Over (" + completedLevel + ")"); gameBoardInterface.clearBoard(); } // if sequence is complete, notify user and start next level diff --git a/app/src/main/java/info/hebbeker/david/memorex/MainActivity.java b/app/src/main/java/info/hebbeker/david/memorex/MainActivity.java index 8b38b66..e0ae770 100644 --- a/app/src/main/java/info/hebbeker/david/memorex/MainActivity.java +++ b/app/src/main/java/info/hebbeker/david/memorex/MainActivity.java @@ -1,5 +1,6 @@ package info.hebbeker.david.memorex; +import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.preference.PreferenceManager; @@ -18,8 +19,9 @@ public class MainActivity extends AppCompatActivity implements GameBoardInterfac { private final SymbolButton[] symbols = new SymbolButton[4]; private final Game game = new Game(this, symbols); - private View startGameButton; + private View startGameButton = null; private Toast notification = null; + private HighScoreContainer highScoreContainer = null; @Override protected void onCreate(final Bundle savedInstanceState) @@ -28,6 +30,7 @@ protected void onCreate(final Bundle savedInstanceState) setContentView(R.layout.activity_main); startGameButton = findViewById(R.id.startButton); + highScoreContainer = new HighScoreContainer(getSharedPreferences("info.hebbeker.david.memorex.PREFERENCE_SCORE_FILE_KEY", Context.MODE_PRIVATE)); symbols[0] = findViewById(R.id.button1); symbols[1] = findViewById(R.id.button2); @@ -55,7 +58,7 @@ public void signalSymbol2Game(View view) { SymbolButton pressedButton = (SymbolButton) view; pressedButton.signalSymbol(); // signal symbol to user - game.putPlayerInput(pressedButton); // signal symbol to game + game.putPlayerInput(pressedButton, highScoreContainer); // signal symbol to game } public void startGame(@SuppressWarnings("unused") final View view) From afeec314fcfcaf9213fd45f71773974ab4046f7e Mon Sep 17 00:00:00 2001 From: David Hebbeker Date: Sun, 18 Mar 2018 11:11:39 +0100 Subject: [PATCH 07/12] Added comment about the placement of the settings menu entry. --- app/src/main/res/menu/main_menu.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/src/main/res/menu/main_menu.xml b/app/src/main/res/menu/main_menu.xml index 1d0d5fc..ceec4b1 100644 --- a/app/src/main/res/menu/main_menu.xml +++ b/app/src/main/res/menu/main_menu.xml @@ -6,6 +6,10 @@ android:onClick="showAbout" android:title="@string/about_this_app" android:titleCondensed="About" /> + + Date: Sun, 18 Mar 2018 11:47:21 +0100 Subject: [PATCH 08/12] Added empty Activity DisplayHighScore. This Activity will be used in order to display the high score. The activity has been attached to the main_menu. Relates to #4. --- app/src/main/AndroidManifest.xml | 11 +++++++++++ .../hebbeker/david/memorex/DisplayHighScore.java | 15 +++++++++++++++ .../info/hebbeker/david/memorex/MainActivity.java | 6 ++++++ .../res/layout/activity_display_high_score.xml | 8 ++++++++ app/src/main/res/menu/main_menu.xml | 5 +++++ app/src/main/res/values/strings.xml | 1 + 6 files changed, 46 insertions(+) create mode 100644 app/src/main/java/info/hebbeker/david/memorex/DisplayHighScore.java create mode 100644 app/src/main/res/layout/activity_display_high_score.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 486b287..66459ff 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -36,6 +36,17 @@ android:name="android.support.PARENT_ACTIVITY" android:value="info.hebbeker.david.memorex.MainActivity" /> + + + + + \ No newline at end of file diff --git a/app/src/main/java/info/hebbeker/david/memorex/DisplayHighScore.java b/app/src/main/java/info/hebbeker/david/memorex/DisplayHighScore.java new file mode 100644 index 0000000..9e26d90 --- /dev/null +++ b/app/src/main/java/info/hebbeker/david/memorex/DisplayHighScore.java @@ -0,0 +1,15 @@ +package info.hebbeker.david.memorex; + +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; + +public class DisplayHighScore extends AppCompatActivity +{ + + @Override + protected void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_display_high_score); + } +} diff --git a/app/src/main/java/info/hebbeker/david/memorex/MainActivity.java b/app/src/main/java/info/hebbeker/david/memorex/MainActivity.java index e0ae770..3b72a64 100644 --- a/app/src/main/java/info/hebbeker/david/memorex/MainActivity.java +++ b/app/src/main/java/info/hebbeker/david/memorex/MainActivity.java @@ -157,6 +157,12 @@ public void run() }).start(); } + public void showHighScore(@SuppressWarnings("unused") final MenuItem menuItem) + { + Intent intent = new Intent(this, DisplayHighScore.class); + startActivity(intent); + } + public void showAbout(@SuppressWarnings("unused") final MenuItem menuItem) { Intent intent = new Intent(this, DisplayAboutActivity.class); diff --git a/app/src/main/res/layout/activity_display_high_score.xml b/app/src/main/res/layout/activity_display_high_score.xml new file mode 100644 index 0000000..37adc74 --- /dev/null +++ b/app/src/main/res/layout/activity_display_high_score.xml @@ -0,0 +1,8 @@ + + + + diff --git a/app/src/main/res/menu/main_menu.xml b/app/src/main/res/menu/main_menu.xml index ceec4b1..b2863db 100644 --- a/app/src/main/res/menu/main_menu.xml +++ b/app/src/main/res/menu/main_menu.xml @@ -1,6 +1,11 @@

+ Settings speed_list switch_preference_sound + Show high score Slow Medium From 517369bc02cb411fb40f7a2f5acdcef5a2355dd1 Mon Sep 17 00:00:00 2001 From: David Hebbeker Date: Sun, 18 Mar 2018 13:04:36 +0100 Subject: [PATCH 09/12] Integration of HighScoreContainer with DisplayHighScore. * DisplayHighScore will print the string of the current high score * HighScoreContainer returns current high score * MainActivity passes high score as intent (through serialization) * Score is serializable (again) * Score can be written as a String Fixes #4. --- .../hebbeker/david/memorex/DisplayHighScore.java | 8 ++++++++ .../david/memorex/HighScoreContainer.java | 5 +++++ .../info/hebbeker/david/memorex/MainActivity.java | 2 ++ .../java/info/hebbeker/david/memorex/Score.java | 10 +++++++++- .../res/layout/activity_display_high_score.xml | 15 +++++++++++++++ app/src/main/res/values/strings.xml | 1 + 6 files changed, 40 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/info/hebbeker/david/memorex/DisplayHighScore.java b/app/src/main/java/info/hebbeker/david/memorex/DisplayHighScore.java index 9e26d90..795182e 100644 --- a/app/src/main/java/info/hebbeker/david/memorex/DisplayHighScore.java +++ b/app/src/main/java/info/hebbeker/david/memorex/DisplayHighScore.java @@ -2,6 +2,10 @@ import android.os.Bundle; import android.support.v7.app.AppCompatActivity; +import android.text.Html; +import android.widget.TextView; + +import java.io.Serializable; public class DisplayHighScore extends AppCompatActivity { @@ -11,5 +15,9 @@ protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_display_high_score); + final Serializable currentHighScore = getIntent().getSerializableExtra(MainActivity.HIGH_SCORE_DATA); + final String aboutText = getResources().getString(R.string.high_score_display, currentHighScore.toString()); + final TextView textView = findViewById(R.id.textViewHighScore); + textView.setText(Html.fromHtml(aboutText)); } } diff --git a/app/src/main/java/info/hebbeker/david/memorex/HighScoreContainer.java b/app/src/main/java/info/hebbeker/david/memorex/HighScoreContainer.java index b4c4c6a..1600f89 100644 --- a/app/src/main/java/info/hebbeker/david/memorex/HighScoreContainer.java +++ b/app/src/main/java/info/hebbeker/david/memorex/HighScoreContainer.java @@ -57,4 +57,9 @@ private void saveHighScore() editor.putString(highScorePreferenceKey, highScoreSerializedObject); editor.apply(); } + + public Score getCurrentHighScore() + { + return currentHighScore; + } } diff --git a/app/src/main/java/info/hebbeker/david/memorex/MainActivity.java b/app/src/main/java/info/hebbeker/david/memorex/MainActivity.java index 3b72a64..4ce8aa0 100644 --- a/app/src/main/java/info/hebbeker/david/memorex/MainActivity.java +++ b/app/src/main/java/info/hebbeker/david/memorex/MainActivity.java @@ -17,6 +17,7 @@ public class MainActivity extends AppCompatActivity implements GameBoardInterface, View.OnClickListener { + static final String HIGH_SCORE_DATA = MainActivity.class.getPackage().getName() + "HIGH_SCORE_DATA"; private final SymbolButton[] symbols = new SymbolButton[4]; private final Game game = new Game(this, symbols); private View startGameButton = null; @@ -160,6 +161,7 @@ public void run() public void showHighScore(@SuppressWarnings("unused") final MenuItem menuItem) { Intent intent = new Intent(this, DisplayHighScore.class); + intent.putExtra(HIGH_SCORE_DATA, highScoreContainer.getCurrentHighScore()); startActivity(intent); } diff --git a/app/src/main/java/info/hebbeker/david/memorex/Score.java b/app/src/main/java/info/hebbeker/david/memorex/Score.java index bcd97f8..ceea82d 100644 --- a/app/src/main/java/info/hebbeker/david/memorex/Score.java +++ b/app/src/main/java/info/hebbeker/david/memorex/Score.java @@ -1,10 +1,12 @@ package info.hebbeker.david.memorex; +import java.io.Serializable; + /** * Does contain information about a score. * \todo Add the following attributes: username, speed, date, points */ -class Score +class Score implements Serializable { /** * Completed level. @@ -26,4 +28,10 @@ boolean isGreaterThan(final Score otherScore) { return this.level > otherScore.level; } + + @Override + public String toString() + { + return "Level=" + level; + } } diff --git a/app/src/main/res/layout/activity_display_high_score.xml b/app/src/main/res/layout/activity_display_high_score.xml index 37adc74..401ceb2 100644 --- a/app/src/main/res/layout/activity_display_high_score.xml +++ b/app/src/main/res/layout/activity_display_high_score.xml @@ -1,8 +1,23 @@ + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 9a4a899..33243f4 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -12,6 +12,7 @@ speed_list switch_preference_sound Show high score + Current high score is: %1$s Slow Medium From f934dc7f568f202b25242debdbc1bd3c8ef933fa Mon Sep 17 00:00:00 2001 From: David Hebbeker Date: Sun, 18 Mar 2018 14:07:58 +0100 Subject: [PATCH 10/12] Added quick link to download the newest `apk` asset. Especially in the mobile view the download instructions are quite hidden. --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 1131549..b186dca 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,7 @@ +**Download latest release of Memorex App:** Got to [latest release][] page and download the *`app-release-vX-Y-Z.apk` asset*. + +[latest release]: https://github.com/dhebbeker/memorex-android/releases/latest "latest release on GitHub" + # Memorex Memorex is a simple game for short time diversion. The challenge is to memorize a sequence of symbols. The sequence is displayed by the game and the player has to repeat it directly afterwards. On success the game increments the sequence by another symbol and repeats. There are four different symbols with a color and tone each. @@ -47,6 +51,7 @@ Please refer to the [releases page][1] to download the Android application packa This app certainly has potential to grow. In case you played it, you may already have some features in mind to enhance the game. Contributors are welcome! Please read our [Code of Conduct][6]. These are some of the possibilities to contribute to the project: + * Create an issue on the [issue page][3] in order to ask questions related to the project or app, report a problem, or request a new feature. * Create or edit pages in the [project wiki][4] in order to document the app or the project itself. * Please feel free to contribute source code! These [guidelines][5] may help you doing so. From c600b9e388fb1ec69c4100f21642ba22301d1a2c Mon Sep 17 00:00:00 2001 From: David Hebbeker Date: Wed, 28 Mar 2018 14:34:00 +0200 Subject: [PATCH 11/12] Added rule on how to name development versions. This rule has been written after studying this discussion [1] about post-release version naming. Documented example for version tag name. [1]: https://github.com/semver/semver/issues/200 --- CONTRIBUTING.md | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c304d2f..6ec0eb0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -9,8 +9,37 @@ This document shall give you some guidelines in order to help you to contribute # Coding Rules Before committing to this repository, please: + * Use automatic code formatting with the [project specific format](.idea/codeStyleSettings.xml). * Make sure your code does not introduce warnings or errors. * Test your contribution on the target device. * We use [SemVer](http://semver.org/) for versioning. For the versions available, see the [tags on this repository](https://github.com/dhebbeker/memorex-android/tags). -* Project build configuration is setup for [Android Studio](https://developer.android.com/studio/index.html) \ No newline at end of file +* Project build configuration is setup for [Android Studio](https://developer.android.com/studio/index.html) + +# Versioning +Versions in this project shall be specified according to the [Semantic Versioning](https://semver.org/) 2 specification (SemVer2). Additional rules specify details of the usage. + +Tags which point to defined versions shall use the version name prefixed with a `v` as this is [common practice](https://github.com/semver/semver/issues/235#issuecomment-346477428) on GitHub. + +## Development releases +A development release is defined as a release, which is only on a branch, which is not the normal release branch. A development release aims to be included within the normal release branch after development is completed. +The normal release branch is `master`. +The following rule does specify how to name versions in development releases using Backus–Naur form: + + ::= "."".""-0.develop+" + ::= | +1 + ::= mayjor version of the normal release this development is based on + ::= | +1 + ::= minor version of the normal release this development is based on + ::= | +1 + ::= patch version of the normal release this development is based on + ::= ".""." + ::= branch name + ::= number of additional commits on top of the normal release this development is based on + ::= abbreviated object name of the most recent commit + +The major, minor or patch number are incremented according to SemVer2. Exactly one of major, minor or patch number must be incremented. +The branch name must satisfy the requirements for pre-release version identifiers of SemVer2. Slashes (`/`) in branch names must be replaced with hyphens (`-`). +The abbreviated object name of the most recent commit may be a tag, a revision number or a hash. + +The following is a valid example of a version *tag*: `v6.6.5-0.develop+feature-update-notification.1.gf934dc7` \ No newline at end of file From 6f2ff2c1f8885a871ae848fbca86b7a51db0f132 Mon Sep 17 00:00:00 2001 From: David Hebbeker Date: Wed, 28 Mar 2018 14:35:40 +0200 Subject: [PATCH 12/12] Scripted algorithm to generate version tag names. This can be used in order to render names according to a pattern. --- generate-version-tag-name.sh | 52 ++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100755 generate-version-tag-name.sh diff --git a/generate-version-tag-name.sh b/generate-version-tag-name.sh new file mode 100755 index 0000000..75216e9 --- /dev/null +++ b/generate-version-tag-name.sh @@ -0,0 +1,52 @@ +#!/bin/bash +# This script shall print a string to stdout that can directly be used as a tag name for versioning. + +echo "INFO: Call this script like this: $0 4 3 2 alpha" + +# read arguments +majorOffset=$1 +minorOffset=$2 +patchOffset=$3 +masterPostfix=$4 + +gitInfo=`git describe --tags --always --match "v[[:digit:]]*"` +rawBranchName=`git symbolic-ref --short HEAD` +branchName="${rawBranchName/\//-}" + +# truncate leading `v` +oldVersionString=${gitInfo:1} + +# separate version information +IFS=- # delimit on _ +set -f # disable the glob part +oldVersionInfo=(${oldVersionString}) # invoke the split+glob operator +IFS= + +commits=${oldVersionInfo[1]} +object=${oldVersionInfo[2]} + +# separate version numbers +IFS=. # delimit on _ +set -f # disable the glob part +oldVersionNumbers=(${oldVersionInfo[0]}) # invoke the split+glob operator +IFS= + +major=$((${oldVersionNumbers[0]}+$majorOffset)) +minor=$((${oldVersionNumbers[1]}+$minorOffset)) +patch=$((${oldVersionNumbers[2]}+$patchOffset)) + +if [ "$branchName" == "master" ]; then + if [ "$masterPostfix" == "" ]; then + postfix="" + else + postfix="-$masterPostfix" + fi +else + postfix="-0.develop+$branchName.$commits.$object" +fi + +version="$major.$minor.$patch$postfix" + +# Tags which point to defined versions shall use the version name prefixed with a `v` as this is [common practice](https://github.com/semver/semver/issues/235#issuecomment-346477428) on GitHub. +tag="v$version" +echo ${tag}