commit 329c0aeb480abe881fc8a54995d3e7a75b37c6cb
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Thu Feb 20 21:46:20 2020 +0000

    Many small improvements.

diff --git a/src/main/java/org/distorted/dialog/RubikDialogAbout.java b/src/main/java/org/distorted/dialog/RubikDialogAbout.java
index 7b228550..7bead22d 100644
--- a/src/main/java/org/distorted/dialog/RubikDialogAbout.java
+++ b/src/main/java/org/distorted/dialog/RubikDialogAbout.java
@@ -75,7 +75,9 @@ public class RubikDialogAbout extends AppCompatDialogFragment
 
     final View view = inflater.inflate(R.layout.dialog_about, null);
     TextView text = view.findViewById(R.id.about_version);
-    text.setText(R.string.app_version);
+    String appName = getString(R.string.app_name);
+    String appVers = getString(R.string.app_version);
+    text.setText(getString(R.string.ap_placeholder,appName, appVers));
     builder.setView(view);
 
     return builder.create();
diff --git a/src/main/java/org/distorted/dialog/RubikDialogScoresPagerAdapter.java b/src/main/java/org/distorted/dialog/RubikDialogScoresPagerAdapter.java
index 2ec3dbcb..aa3cc1e5 100644
--- a/src/main/java/org/distorted/dialog/RubikDialogScoresPagerAdapter.java
+++ b/src/main/java/org/distorted/dialog/RubikDialogScoresPagerAdapter.java
@@ -162,7 +162,7 @@ class RubikDialogScoresPagerAdapter extends PagerAdapter implements RubikScoresD
     if( allCreated )
       {
       RubikScoresDownloader downloader = new RubikScoresDownloader();
-      downloader.download(this, "distorted", 1);                        // TODO
+      downloader.download(this, "distorted", "1.0.0", 1);                        // TODO
       }
 
     return mViews[position];
diff --git a/src/main/java/org/distorted/network/RubikScoresDownloader.java b/src/main/java/org/distorted/network/RubikScoresDownloader.java
index b9dda581..ddfcba61 100644
--- a/src/main/java/org/distorted/network/RubikScoresDownloader.java
+++ b/src/main/java/org/distorted/network/RubikScoresDownloader.java
@@ -24,8 +24,6 @@ import java.net.HttpURLConnection;
 import java.net.URL;
 import java.net.UnknownHostException;
 
-import org.distorted.magic.R;
-
 import static org.distorted.object.RubikObject.LENGTH;
 import static org.distorted.uistate.RubikStatePlay.MAX_SCRAMBLE;
 
@@ -85,7 +83,7 @@ public class RubikScoresDownloader implements Runnable
   private static boolean mRunning = false;
   private static int mMode = IDLE;
   private static Receiver mReceiver;
-  private static String mUserName;
+  private static String mUserName, mVersion;
   private static int mNumRuns;
 
   private static String mScores = "";
@@ -93,12 +91,20 @@ public class RubikScoresDownloader implements Runnable
   private static String[][][] mName    = new String[LENGTH][MAX_SCRAMBLE][MAX_PLACES];
   private static String[][][] mTime    = new String[LENGTH][MAX_SCRAMBLE][MAX_PLACES];
 
+  private static int[][] mPlaces = new int[LENGTH][MAX_SCRAMBLE];
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   private void fillValues()
     {
     int begin=-1 ,end, len = mScores.length();
 
+    for(int i=0; i<LENGTH; i++)
+      for(int j=0; j<MAX_SCRAMBLE; j++)
+        {
+        mPlaces[i][j] = 0;
+        }
+
     while( begin<len )
       {
       end = mScores.indexOf('\n', begin+1);
@@ -134,6 +140,11 @@ public class RubikScoresDownloader implements Runnable
 
         if(level>=0 && level<MAX_SCRAMBLE && place>=0 && place<MAX_PLACES)
           {
+          int p = mPlaces[size][level];
+          mPlaces[size][level]++;
+
+          if( p!=place ) android.util.Log.e("downloader", "size="+size+" level="+level+" p="+p+" place="+place);
+
           mCountry[size][level][place] = country;
           mName   [size][level][place] = name;
           mTime   [size][level][place] = realTime;
@@ -183,8 +194,7 @@ public class RubikScoresDownloader implements Runnable
 
   private boolean doDownload()
     {
-    String version = R.string.app_version+"d";
-    String message=URL+"/download.cgi?n="+URLencode(mUserName)+"&r="+mNumRuns+"&e="+version;
+    String message=URL+"/download.cgi?n="+URLencode(mUserName)+"&r="+mNumRuns+"&e="+mVersion+"d";
 
     try
       {
@@ -230,6 +240,12 @@ public class RubikScoresDownloader implements Runnable
       return false;
       }
 
+    if( mScores.length()==0 )
+      {
+      mReceiver.exception("Failed to download scores");
+      return false;
+      }
+
     return true;
     }
 
@@ -280,11 +296,12 @@ public class RubikScoresDownloader implements Runnable
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  public void download(Receiver receiver, String userName, int numRuns)
+  public void download(Receiver receiver, String userName, String version, int numRuns)
     {
     mReceiver = receiver;
     mMode     = DOWNLOAD;
     mUserName = userName;
+    mVersion  = version;
     mNumRuns  = numRuns;
 
     Thread networkThrd = new Thread(this);
diff --git a/src/main/java/org/distorted/uistate/RubikStateAbstract.java b/src/main/java/org/distorted/uistate/RubikStateAbstract.java
index 8e943c70..7e39cbcb 100644
--- a/src/main/java/org/distorted/uistate/RubikStateAbstract.java
+++ b/src/main/java/org/distorted/uistate/RubikStateAbstract.java
@@ -28,8 +28,8 @@ public abstract class RubikStateAbstract
   {
   public static final int BUTTON_ID_BACK= 1023;
 
-  public abstract void enterState(RubikActivity act);
-  public abstract void leaveState(RubikActivity act);
+  abstract void enterState(RubikActivity act);
+  abstract void leaveState(RubikActivity act);
   public abstract void savePreferences(SharedPreferences.Editor editor);
   public abstract void restorePreferences(SharedPreferences preferences);
   }
diff --git a/src/main/java/org/distorted/uistate/RubikStateMain.java b/src/main/java/org/distorted/uistate/RubikStateMain.java
index 2266e519..6c349479 100644
--- a/src/main/java/org/distorted/uistate/RubikStateMain.java
+++ b/src/main/java/org/distorted/uistate/RubikStateMain.java
@@ -37,7 +37,7 @@ import static android.view.View.INVISIBLE;
 
 public class RubikStateMain extends RubikStateAbstract
   {
-  public void leaveState(RubikActivity act)
+  void leaveState(RubikActivity act)
     {
     FragmentManager mana = act.getSupportFragmentManager();
     RubikDialogMain diag = (RubikDialogMain) mana.findFragmentByTag(RubikDialogMain.getDialogTag());
@@ -54,7 +54,7 @@ public class RubikStateMain extends RubikStateAbstract
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  public void enterState(RubikActivity act)
+  void enterState(RubikActivity act)
     {
     FragmentManager mana = act.getSupportFragmentManager();
     RubikDialogMain diag = (RubikDialogMain) mana.findFragmentByTag(RubikDialogMain.getDialogTag());
diff --git a/src/main/java/org/distorted/uistate/RubikStatePlay.java b/src/main/java/org/distorted/uistate/RubikStatePlay.java
index a381a480..a41c77e1 100644
--- a/src/main/java/org/distorted/uistate/RubikStatePlay.java
+++ b/src/main/java/org/distorted/uistate/RubikStatePlay.java
@@ -51,14 +51,14 @@ public class RubikStatePlay extends RubikStateAbstract
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  public void leaveState(RubikActivity act)
+  void leaveState(RubikActivity act)
     {
     mPickerValue = mPicker.getValue();
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  public void enterState(RubikActivity act)
+  void enterState(RubikActivity act)
     {
     LayoutInflater inflater = act.getLayoutInflater();
 
diff --git a/src/main/java/org/distorted/uistate/RubikStateSolving.java b/src/main/java/org/distorted/uistate/RubikStateSolving.java
index cf29ec98..4fbbc213 100644
--- a/src/main/java/org/distorted/uistate/RubikStateSolving.java
+++ b/src/main/java/org/distorted/uistate/RubikStateSolving.java
@@ -33,26 +33,45 @@ import java.util.Timer;
 import java.util.TimerTask;
 
 import static android.view.View.INVISIBLE;
+import static org.distorted.object.RubikObject.LENGTH;
+import static org.distorted.uistate.RubikStatePlay.MAX_SCRAMBLE;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
 public class RubikStateSolving extends RubikStateAbstract
   {
+  private static final int NO_RECORD = Integer.MAX_VALUE;
+
   private TextView mTime;
   private Timer mTimer;
   private long mStartTime;
   private boolean mRunning;
 
+  private long[][] mRecords;
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  public void leaveState(RubikActivity act)
+  RubikStateSolving()
+    {
+    mRecords = new long[LENGTH][MAX_SCRAMBLE];
+
+    for(int i=0; i<LENGTH; i++)
+      for(int j=0; j<MAX_SCRAMBLE; j++)
+        {
+        mRecords[i][j] = NO_RECORD;
+        }
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  void leaveState(RubikActivity act)
     {
     stopCounting();
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  public void enterState(RubikActivity act)
+  void enterState(RubikActivity act)
     {
     LayoutInflater inflater = act.getLayoutInflater();
 
@@ -96,14 +115,25 @@ public class RubikStateSolving extends RubikStateAbstract
 
   public void savePreferences(SharedPreferences.Editor editor)
     {
-
+    for(int i=0; i<LENGTH; i++)
+      for(int j=0; j<MAX_SCRAMBLE; j++)
+        {
+        if( mRecords[i][j]!=NO_RECORD)
+          {
+          editor.putLong("record_"+i+"_"+j, mRecords[i][j]);
+          }
+        }
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public void restorePreferences(SharedPreferences preferences)
     {
-
+    for(int i=0; i<LENGTH; i++)
+      for(int j=0; j<MAX_SCRAMBLE; j++)
+        {
+        mRecords[i][j] = preferences.getInt("record_"+i+"_"+j, NO_RECORD );
+        }
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -148,7 +178,22 @@ public class RubikStateSolving extends RubikStateAbstract
         }
       mRunning = false;
 
-      return System.currentTimeMillis()-mStartTime;
+      long timeTaken = System.currentTimeMillis()-mStartTime;
+
+      RubikStatePlay play = (RubikStatePlay)RubikState.PLAY.getStateClass();
+      int object  = play.getButton();
+      int scramble= play.getPicker();
+
+      if( object>=0 && object<LENGTH && scramble>=0 && scramble<MAX_SCRAMBLE )
+        {
+        if( mRecords[object][scramble]> timeTaken )
+          {
+          mRecords[object][scramble] = timeTaken;
+          android.util.Log.e("solv","new record!");
+          }
+        }
+
+      return timeTaken;
       }
 
     return 0;
diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml
index bb80158c..0e668dbf 100644
--- a/src/main/res/values/strings.xml
+++ b/src/main/res/values/strings.xml
@@ -1,6 +1,6 @@
 <resources>
     <string name="app_name">Magic Cube</string>
-    <string name="app_version">Magic Cube v1.0.0</string>
+    <string name="app_version">1.0.0</string>
     <string name="distorted">DISTORTED</string>
     <string name="scramble">Scramble</string>
     <string name="solve">Solve</string>
@@ -26,4 +26,5 @@
     <string name="ms_placeholder">%1$d ms</string>
     <string name="sc_placeholder">Scramble %1$d</string>
     <string name="tm_placeholder">%1$02d:%2$02d</string>
+    <string name="ap_placeholder">%1$s %2$s</string>
 </resources>
