commit 8e3898c894dbe25e818fcc029ee7fd41f586c47a
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Thu Apr 9 23:09:09 2020 +0100

    Each object size now has its own number of levels (not always 18!)

diff --git a/src/main/java/org/distorted/dialogs/RubikDialogScoresPagerAdapter.java b/src/main/java/org/distorted/dialogs/RubikDialogScoresPagerAdapter.java
index 8fd42f56..b4fe6be6 100644
--- a/src/main/java/org/distorted/dialogs/RubikDialogScoresPagerAdapter.java
+++ b/src/main/java/org/distorted/dialogs/RubikDialogScoresPagerAdapter.java
@@ -32,8 +32,6 @@ import org.distorted.scores.RubikScores;
 import org.distorted.scores.RubikScoresDownloader;
 import org.distorted.objects.RubikObjectList;
 
-import static org.distorted.states.RubikStatePlay.MAX_LEVEL;
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
 class RubikDialogScoresPagerAdapter extends PagerAdapter implements RubikScoresDownloader.Receiver
@@ -136,7 +134,11 @@ class RubikDialogScoresPagerAdapter extends PagerAdapter implements RubikScoresD
 
   private void addPage(int tab, final RubikDialogScoresView view, final String[][] country, final String[][] name, final float[][] time)
     {
-    for(int i=0; i<MAX_LEVEL; i++)
+    int object   = RubikObjectList.unpackObject(tab);
+    int sizeIndex= RubikObjectList.unpackSizeIndex(tab);
+    int maxLevel  = RubikObjectList.getMaxLevel(object, sizeIndex);
+
+    for(int i=0; i<maxLevel; i++)
       {
       final LinearLayout section = view.createSection(mAct, tab, i, country[i], name[i], time[i]);
 
diff --git a/src/main/java/org/distorted/dialogs/RubikDialogScoresView.java b/src/main/java/org/distorted/dialogs/RubikDialogScoresView.java
index a1e7840a..5bd1069a 100644
--- a/src/main/java/org/distorted/dialogs/RubikDialogScoresView.java
+++ b/src/main/java/org/distorted/dialogs/RubikDialogScoresView.java
@@ -78,14 +78,14 @@ public class RubikDialogScoresView extends FrameLayout
     Resources res = act.getResources();
     String packageName = act.getPackageName();
 
-    int object = RubikObjectList.unpackObject(tab);
-    int size   = RubikObjectList.unpackSize(tab);
+    int object   = RubikObjectList.unpackObject(tab);
+    int sizeIndex= RubikObjectList.unpackSizeIndex(tab);
     RubikScores scores = RubikScores.getInstance();
 
     boolean inserted = false;
-    long myRecordInMillis = scores.getRecord(object, size, level);
+    long myRecordInMillis = scores.getRecord(object, sizeIndex, level);
     float myRecordInSeconds = (myRecordInMillis/100)/10.0f;
-    boolean mySubmitted = scores.isSubmitted(object, size, level);
+    boolean mySubmitted = scores.isSubmitted(object, sizeIndex, level);
     String myName = scores.getName();
     if( myName.length()==0 ) myName = act.getString(R.string.you);
     int myCountryID = res.getIdentifier( scores.getCountry(), "drawable", packageName);
diff --git a/src/main/java/org/distorted/objects/RubikObjectList.java b/src/main/java/org/distorted/objects/RubikObjectList.java
index 8d98e12f..bfaad1bf 100644
--- a/src/main/java/org/distorted/objects/RubikObjectList.java
+++ b/src/main/java/org/distorted/objects/RubikObjectList.java
@@ -33,10 +33,10 @@ public enum RubikObjectList
   {
   CUBE (
          new int[][] {
-                       {2 , R.drawable.cube2} ,
-                       {3 , R.drawable.cube3} ,
-                       {4 , R.drawable.cube4} ,
-                       {5 , R.drawable.cube5}
+                       {2 , 12, R.drawable.cube2} ,
+                       {3 , 16, R.drawable.cube3} ,
+                       {4 , 20, R.drawable.cube4} ,
+                       {5 , 24, R.drawable.cube5}
                      },
          RubikCube.class,
          new RubikCubeMovement()
@@ -44,9 +44,9 @@ public enum RubikObjectList
 
   PYRA (
          new int[][] {
-                       {3 , R.drawable.pyra3} ,
-                       {4 , R.drawable.pyra4} ,
-                       {5 , R.drawable.pyra5}
+                       {3 , 10, R.drawable.pyra3} ,
+                       {4 , 15, R.drawable.pyra4} ,
+                       {5 , 20, R.drawable.pyra5}
                      },
          RubikPyraminx.class,
          new RubikPyraminxMovement()
@@ -55,8 +55,9 @@ public enum RubikObjectList
 
   public static final int NUM_OBJECTS = values().length;
   public static final int MAX_SIZE;
+  public static final int MAX_LEVEL;
 
-  private final int[] mObjectSizes, mIconIDs;
+  private final int[] mObjectSizes, mMaxLevels, mIconIDs;
   private final Class<? extends RubikObject> mObjectClass;
   private final RubikObjectMovement mObjectMovementClass;
   private static final RubikObjectList[] objects;
@@ -67,7 +68,8 @@ public enum RubikObjectList
     mNumAll = 0;
     int size, i = 0;
     objects = new RubikObjectList[NUM_OBJECTS];
-    int maxsize = Integer.MIN_VALUE;
+    int maxSize  = Integer.MIN_VALUE;
+    int maxLevel = Integer.MIN_VALUE;
 
     for(RubikObjectList object: RubikObjectList.values())
       {
@@ -75,10 +77,16 @@ public enum RubikObjectList
       i++;
       size = object.mObjectSizes.length;
       mNumAll += size;
-      if( size> maxsize ) maxsize = size;
+      if( size> maxSize ) maxSize = size;
+
+      for(int j=0; j<size; j++)
+        {
+        if( object.mMaxLevels[j] > maxLevel ) maxLevel = object.mMaxLevels[j];
+        }
       }
 
-    MAX_SIZE = maxsize;
+    MAX_SIZE = maxSize;
+    MAX_LEVEL= maxLevel;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -100,7 +108,7 @@ public enum RubikObjectList
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  public static int unpackSize(int number)
+  public static int unpackSizeIndex(int number)
     {
     int num;
 
@@ -189,6 +197,19 @@ public enum RubikObjectList
     return mNumAll;
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public static int getMaxLevel(int ordinal, int sizeIndex)
+    {
+    if( ordinal>=0 && ordinal<NUM_OBJECTS )
+      {
+      int num = objects[ordinal].mObjectSizes.length;
+      return sizeIndex>=0 && sizeIndex<num ? objects[ordinal].mMaxLevels[sizeIndex] : 0;
+      }
+
+    return 0;
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public static int getOrdinal(String name)
@@ -249,12 +270,14 @@ public enum RubikObjectList
     int length = info.length;
 
     mObjectSizes= new int[length];
+    mMaxLevels  = new int[length];
     mIconIDs    = new int[length];
 
     for(int i=0; i<length; i++)
       {
       mObjectSizes[i] = info[i][0];
-      mIconIDs[i]     = info[i][1];
+      mMaxLevels[i]   = info[i][1];
+      mIconIDs[i]     = info[i][2];
       }
 
     mObjectClass         = object;
@@ -263,16 +286,23 @@ public enum RubikObjectList
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  public int[] getIconIDs()
+  public int[] getSizes()
     {
-    return mIconIDs;
+    return mObjectSizes;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  public int[] getSizes()
+  public int[] getMaxLevels()
     {
-    return mObjectSizes;
+    return mMaxLevels;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int[] getIconIDs()
+    {
+    return mIconIDs;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/main/java/org/distorted/scores/RubikScores.java b/src/main/java/org/distorted/scores/RubikScores.java
index 4a4663e2..6d334222 100644
--- a/src/main/java/org/distorted/scores/RubikScores.java
+++ b/src/main/java/org/distorted/scores/RubikScores.java
@@ -29,7 +29,7 @@ import java.util.UUID;
 
 import static org.distorted.objects.RubikObjectList.MAX_SIZE;
 import static org.distorted.objects.RubikObjectList.NUM_OBJECTS;
-import static org.distorted.states.RubikStatePlay.MAX_LEVEL;
+import static org.distorted.objects.RubikObjectList.MAX_LEVEL;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // hold my own scores, and some other statistics.
@@ -111,9 +111,9 @@ public class RubikScores
 
       for(int size=0; size<length; size++)
         {
-        for(int scramble=0; scramble<MAX_LEVEL; scramble++)
+        for(int level=0; level<MAX_LEVEL; level++)
           {
-          if( mSubmitted[object][size][scramble]==0 && mRecords[object][size][scramble]<NO_RECORD )
+          if( mSubmitted[object][size][level]==0 && mRecords[object][size][level]<NO_RECORD )
             {
             if( !first ) builder.append(',');
             else         first=false;
@@ -124,9 +124,9 @@ public class RubikScores
                       builder.append("_");
                       builder.append(sizes[size]);
                       break;
-              case 1: builder.append(scramble);
+              case 1: builder.append(level);
                       break;
-              case 2: builder.append(mRecords[object][size][scramble]);
+              case 2: builder.append(mRecords[object][size][level]);
                       break;
               }
             }
@@ -160,7 +160,7 @@ public class RubikScores
     int[] sizes;
     int length;
 
-    for(int scramble=0; scramble<MAX_LEVEL; scramble++)
+    for(int level=0; level<MAX_LEVEL; level++)
       {
       builder.setLength(0);
 
@@ -176,14 +176,14 @@ public class RubikScores
           builder.append("_");
           builder.append(sizes[size]);
           builder.append("=");
-          builder.append(mRecords[object][size][scramble]);
+          builder.append(mRecords[object][size][level]);
           builder.append(",");
-          builder.append(mSubmitted[object][size][scramble]);
+          builder.append(mSubmitted[object][size][level]);
           builder.append(" ");
           }
         }
 
-      editor.putString("scores_record"+scramble, builder.toString());
+      editor.putString("scores_record"+level, builder.toString());
       }
 
     editor.putString("scores_name"  , mName  );
@@ -202,10 +202,10 @@ public class RubikScores
     int object, sizeIndex, subm;
     long time;
 
-    for(int scramble=0; scramble<MAX_LEVEL; scramble++)
+    for(int level=0; level<MAX_LEVEL; level++)
       {
       start = end = 0;
-      recordStr = preferences.getString("scores_record"+scramble, "");
+      recordStr = preferences.getString("scores_record"+level, "");
 
       while( end!=-1 )
         {
@@ -237,8 +237,8 @@ public class RubikScores
 
             if( sizeIndex>=0 && sizeIndex<MAX_SIZE && subm>=0 && subm<=1 )
               {
-              mRecords  [object][sizeIndex][scramble] = time;
-              mSubmitted[object][sizeIndex][scramble] = subm;
+              mRecords  [object][sizeIndex][level] = time;
+              mSubmitted[object][sizeIndex][level] = subm;
               }
             else
               {
@@ -264,16 +264,16 @@ public class RubikScores
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  public boolean setRecord(int object, int size, int scramble, long timeTaken)
+  public boolean setRecord(int object, int size, int level, long timeTaken)
     {
     int maxsize = RubikObjectList.getObject(object).getSizes().length;
 
-    if( object>=0 && object<NUM_OBJECTS && size>=0 && size<maxsize && scramble>=1 && scramble<=MAX_LEVEL )
+    if( object>=0 && object<NUM_OBJECTS && size>=0 && size<maxsize && level>=1 && level<=MAX_LEVEL )
       {
-      if( mRecords[object][size][scramble-1]> timeTaken )
+      if( mRecords[object][size][level-1]> timeTaken )
         {
-        mRecords  [object][size][scramble-1] = timeTaken;
-        mSubmitted[object][size][scramble-1] = 0;
+        mRecords  [object][size][level-1] = timeTaken;
+        mSubmitted[object][size][level-1] = 0;
         return true;
         }
       }
@@ -341,13 +341,13 @@ public class RubikScores
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  public long getRecord(int object, int size, int scramble)
+  public long getRecord(int object, int size, int level)
     {
     int maxsize = RubikObjectList.getObject(object).getSizes().length;
 
-    if( object>=0 && object<NUM_OBJECTS && size>=0 && size<maxsize && scramble>=0 && scramble<MAX_LEVEL )
+    if( object>=0 && object<NUM_OBJECTS && size>=0 && size<maxsize && level>=0 && level<MAX_LEVEL )
       {
-      return mRecords[object][size][scramble];
+      return mRecords[object][size][level];
       }
 
     return -1;
@@ -355,13 +355,13 @@ public class RubikScores
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  public boolean isSubmitted(int object, int size, int scramble)
+  public boolean isSubmitted(int object, int size, int level)
     {
     int maxsize = RubikObjectList.getObject(object).getSizes().length;
 
-    if( object>=0 && object<NUM_OBJECTS && size>=0 && size<maxsize && scramble>=0 && scramble<MAX_LEVEL )
+    if( object>=0 && object<NUM_OBJECTS && size>=0 && size<maxsize && level>=0 && level<MAX_LEVEL )
       {
-      return mSubmitted[object][size][scramble]==1;
+      return mSubmitted[object][size][level]==1;
       }
 
     return false;
@@ -422,9 +422,9 @@ public class RubikScores
       length = list.getSizes().length;
 
       for(int size=0; size<length; size++)
-        for(int scramble=0; scramble<MAX_LEVEL; scramble++)
+        for(int level=0; level<MAX_LEVEL; level++)
           {
-          if( mSubmitted[object][size][scramble]==0 && mRecords[object][size][scramble]<NO_RECORD )
+          if( mSubmitted[object][size][level]==0 && mRecords[object][size][level]<NO_RECORD )
             {
             return true;
             }
diff --git a/src/main/java/org/distorted/scores/RubikScoresDownloader.java b/src/main/java/org/distorted/scores/RubikScoresDownloader.java
index 0982c5a0..83785125 100644
--- a/src/main/java/org/distorted/scores/RubikScoresDownloader.java
+++ b/src/main/java/org/distorted/scores/RubikScoresDownloader.java
@@ -29,7 +29,7 @@ import java.net.HttpURLConnection;
 import java.net.URL;
 import java.net.UnknownHostException;
 
-import static org.distorted.states.RubikStatePlay.MAX_LEVEL;
+import static org.distorted.objects.RubikObjectList.MAX_LEVEL;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
@@ -185,19 +185,19 @@ public class RubikScoresDownloader implements Runnable
 
       if( object>=0 && object<mTotal )
         {
-        int scramble   = Integer.parseInt( row.substring(s1+1,s2) );
+        int level      = Integer.parseInt( row.substring(s1+1,s2) );
         String name    = row.substring(s2+1, s3);
         int time       = Integer.parseInt( row.substring(s3+1,s4) );
         String country = row.substring(s4+1, s5);
 
-        if(scramble>=0 && scramble<MAX_LEVEL)
+        if(level>=0 && level<MAX_LEVEL)
           {
-          int p = mPlaces[object][scramble];
-          mPlaces[object][scramble]++;
+          int p = mPlaces[object][level];
+          mPlaces[object][level]++;
 
-          mCountry[object][scramble][p] = country;
-          mName   [object][scramble][p] = name;
-          mTime   [object][scramble][p] = ((float)(time/100))/10.0f;
+          mCountry[object][level][p] = country;
+          mName   [object][level][p] = name;
+          mTime   [object][level][p] = ((float)(time/100))/10.0f;
           }
         }
       }
diff --git a/src/main/java/org/distorted/states/RubikStatePlay.java b/src/main/java/org/distorted/states/RubikStatePlay.java
index b1b214e2..0725b331 100644
--- a/src/main/java/org/distorted/states/RubikStatePlay.java
+++ b/src/main/java/org/distorted/states/RubikStatePlay.java
@@ -32,7 +32,7 @@ import android.widget.Button;
 import android.widget.ImageButton;
 import android.widget.LinearLayout;
 import android.widget.PopupWindow;
-import android.widget.Spinner;
+import android.support.v7.widget.AppCompatSpinner;
 
 import org.distorted.main.R;
 import org.distorted.main.RubikActivity;
@@ -43,7 +43,6 @@ import org.distorted.objects.RubikObjectList;
 public class RubikStatePlay extends RubikStateAbstract implements AdapterView.OnItemSelectedListener
   {
   private static final int DEF_LEVEL =  1;
-  public  static final int MAX_LEVEL = 18;
   public  static final int DEF_OBJECT= RubikObjectList.CUBE.ordinal();
   public  static final int DEF_SIZE  =  3;
 
@@ -54,7 +53,8 @@ public class RubikStatePlay extends RubikStateAbstract implements AdapterView.On
   private int mSize   = DEF_SIZE;
   private int mLayoutWidth;
   private LinearLayout mLayout;
-  private Spinner mLevelSpinner;
+  private AppCompatSpinner mLevelSpinner;
+  private ArrayAdapter<String> mSpinnerAdapter;
   private int mLevelValue;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -143,23 +143,25 @@ public class RubikStatePlay extends RubikStateAbstract implements AdapterView.On
     spinnerLayoutParams.leftMargin   =   spinnerMargin;
     spinnerLayoutParams.rightMargin  = 2*spinnerMargin;
 
-    mLevelSpinner = new Spinner(act);
+    mLevelSpinner = new AppCompatSpinner(act);
     mLevelSpinner.setLayoutParams(spinnerLayoutParams);
     mLevelSpinner.setPadding(spinnerPadding,0,spinnerPadding,0);
     mLevelSpinner.setBackgroundResource(R.drawable.spinner);
     mLevelSpinner.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
 
     mLevelSpinner.setOnItemSelectedListener(this);
-    String[] levels = new String[MAX_LEVEL];
+    int sizeIndex = RubikObjectList.getSizeIndex(mObject,mSize);
+    int maxLevel = RubikObjectList.getMaxLevel(mObject, sizeIndex);
+    String[] levels = new String[maxLevel];
 
-    for(int i=0; i<MAX_LEVEL; i++)
+    for(int i=0; i<maxLevel; i++)
       {
       levels[i] = act.getString(R.string.lv_placeholder,i+1);
       }
 
-    ArrayAdapter<String> adapterType = new ArrayAdapter<>(act,android.R.layout.simple_spinner_item, levels);
-    adapterType.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
-    mLevelSpinner.setAdapter(adapterType);
+    mSpinnerAdapter = new ArrayAdapter<>(act,android.R.layout.simple_spinner_item, levels);
+    mSpinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+    mLevelSpinner.setAdapter(mSpinnerAdapter);
     mLevelSpinner.setSelection(mLevelValue-1);
     }
 
@@ -272,7 +274,21 @@ public class RubikStatePlay extends RubikStateAbstract implements AdapterView.On
               mObject = obj;
               mSize   = sizes[size];
               act.changeObject(list,sizes[size],null);
+
+              int sizeIndex = RubikObjectList.getSizeIndex(mObject,mSize);
+              int maxLevel  = RubikObjectList.getMaxLevel(mObject, sizeIndex);
+              String[] levels = new String[maxLevel];
+
+              for(int i=0; i<maxLevel; i++)
+                {
+                levels[i] = act.getString(R.string.lv_placeholder,i+1);
+                }
+
+              mSpinnerAdapter = new ArrayAdapter<>(act,android.R.layout.simple_spinner_item, levels);
+              mSpinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+              mLevelSpinner.setAdapter(mSpinnerAdapter);
               }
+
             mPopup.dismiss();
             }
           });
