commit ff4a2a13c7bb69a6e03156a2a5d055b77519ad14
Author: leszek <leszek@koltunski.pl>
Date:   Thu Jan 18 16:47:05 2024 +0100

    progress with new sorting methods.

diff --git a/src/main/java/org/distorted/bandaged/BandagedRenderer.java b/src/main/java/org/distorted/bandaged/BandagedRenderer.java
index 8991b7f4..4989376f 100644
--- a/src/main/java/org/distorted/bandaged/BandagedRenderer.java
+++ b/src/main/java/org/distorted/bandaged/BandagedRenderer.java
@@ -304,7 +304,7 @@ public class BandagedRenderer implements GLSurfaceView.Renderer, DistortedLibrar
      try
        {
        JsonWriter writer = JsonWriter.getInstance();
-       String json = writer.createObjectString(object,24,0);
+       String json = writer.createObjectString(object);
        writer.write(filename,json);
        return true;
        }
diff --git a/src/main/java/org/distorted/config/ConfigScreenPane.java b/src/main/java/org/distorted/config/ConfigScreenPane.java
index 29f45c15..f7dbd44a 100644
--- a/src/main/java/org/distorted/config/ConfigScreenPane.java
+++ b/src/main/java/org/distorted/config/ConfigScreenPane.java
@@ -9,6 +9,9 @@
 
 package org.distorted.config;
 
+import static org.distorted.objects.RubikObjectCategories.DIFF_IDS;
+import static org.distorted.objects.RubikObjectCategories.DIFF_IMAGES;
+
 import java.io.InputStream;
 
 import android.graphics.PorterDuff;
@@ -26,25 +29,7 @@ import org.distorted.objects.RubikObjectList;
 
 public class ConfigScreenPane
 {
-  private static final int[] IDS =
-    {
-    R.id.configDifficulty0,
-    R.id.configDifficulty1,
-    R.id.configDifficulty2,
-    R.id.configDifficulty3,
-    R.id.configDifficulty4
-    };
-
-  private static final int[] IMAGES =
-    {
-    R.drawable.difficulty1,
-    R.drawable.difficulty2,
-    R.drawable.difficulty3,
-    R.drawable.difficulty4,
-    R.drawable.difficulty5,
-    };
-
-  private static final int NUM_IDS         = IDS.length;
+  private static final int NUM_IDS         = DIFF_IDS.length;
   private static final float PADDING_RATIO = 0.016f;
   private static final float TEXT_RATIO    = 0.025f;
 
@@ -66,9 +51,9 @@ public class ConfigScreenPane
         {
         reader.parseJsonFileMetadata(stream);
         name       = reader.getObjectName();
-        author     = reader.getInventor();
+        author     = reader.getAuthor();
         year       = reader.getYearOfInvention();
-        difficulty = (int)reader.getComplexity();
+        difficulty = (int)reader.getDifficulty();
         }
       catch(Exception ex)
         {
@@ -91,8 +76,8 @@ public class ConfigScreenPane
 
       for(int i=0; i<NUM_IDS; i++)
         {
-        ImageView image = layout.findViewById(IDS[i]);
-        image.setImageResource(IMAGES[i]);
+        ImageView image = layout.findViewById(DIFF_IDS[i]);
+        image.setImageResource(DIFF_IMAGES[i]);
         image.setColorFilter( difficulty==i ? 0xffff0000 : 0xffffffff, PorterDuff.Mode.MULTIPLY );
         }
       }
diff --git a/src/main/java/org/distorted/dialogs/RubikDialogUpdateView.java b/src/main/java/org/distorted/dialogs/RubikDialogUpdateView.java
index c8b28757..c695b732 100644
--- a/src/main/java/org/distorted/dialogs/RubikDialogUpdateView.java
+++ b/src/main/java/org/distorted/dialogs/RubikDialogUpdateView.java
@@ -197,11 +197,16 @@ public class RubikDialogUpdateView implements RubikNetwork.Downloadee
           File file = new File(act.getFilesDir(), objectName);
           InputStream stream = new FileInputStream(file);
           JsonReader reader = new JsonReader();
-          reader.readNumScramblesAndPrice(stream);
+          reader.parseJsonFileMetadata(stream);
           stream.close();
 
           mInfo.mNumScrambles = reader.getNumScrambles();
           mInfo.mPrice        = reader.getPrice();
+          float diff          = reader.getDifficulty();
+          int category        = reader.getCategory();
+          int year            = reader.getYearOfInvention();
+          String author       = reader.getAuthor();
+
           if( SHOW_DOWNLOADED_DEBUG ) android.util.Log.e("D", "Read from JSON numScrambles="+mInfo.mNumScrambles+" price="+mInfo.mPrice);
 
           if( mInfo.mExtrasStream!=null )
@@ -218,8 +223,8 @@ public class RubikDialogUpdateView implements RubikNetwork.Downloadee
 
             if( SHOW_DOWNLOADED_DEBUG ) android.util.Log.e("D", "1");
 
-            boolean success = RubikObjectList.addDownloadedObject(act, mInfo.mObjectShortName, mInfo.mNumScrambles, mInfo.mPrice,
-                                                                  mInfo.mObjectMinorVersion, mInfo.mExtrasMinorVersion, mIconSaved, oSuccess, eSuccess);
+            boolean success = RubikObjectList.addDownloadedObject(act, mInfo.mObjectShortName, mInfo.mNumScrambles, mInfo.mPrice, mInfo.mObjectMinorVersion,
+                                                                  mInfo.mExtrasMinorVersion, mIconSaved, oSuccess, eSuccess, diff, category, year, author);
             if( success )
               {
               if( SHOW_DOWNLOADED_DEBUG ) android.util.Log.e("D", "2");
diff --git a/src/main/java/org/distorted/helpers/ObjectGridCreator.java b/src/main/java/org/distorted/helpers/ObjectGridCreator.java
index 6b4433e4..85f1b24b 100644
--- a/src/main/java/org/distorted/helpers/ObjectGridCreator.java
+++ b/src/main/java/org/distorted/helpers/ObjectGridCreator.java
@@ -235,13 +235,17 @@ public class ObjectGridCreator
       }
 
     LayoutInflater layoutInflater = (LayoutInflater)act.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+    int obj = 0;
 
     for(int object : objects)
       {
       View v = createView(act,layoutInflater,object,mPadding );
-      int row = object/colCount;
+      int row = obj/colCount;
+      obj++;
+      GridLayout.Spec rs = rowSpecs[row];
+      GridLayout.Spec cs = colSpecs[nextInRow[row]];
 
-      GridLayout.LayoutParams params = new GridLayout.LayoutParams(rowSpecs[row],colSpecs[nextInRow[row]]);
+      GridLayout.LayoutParams params = new GridLayout.LayoutParams(rs,cs);
       params.bottomMargin = mMargin;
       params.topMargin    = mMargin;
       params.leftMargin   = mMargin;
diff --git a/src/main/java/org/distorted/objects/RubikObject.java b/src/main/java/org/distorted/objects/RubikObject.java
index 20631616..41cacf5e 100644
--- a/src/main/java/org/distorted/objects/RubikObject.java
+++ b/src/main/java/org/distorted/objects/RubikObject.java
@@ -42,6 +42,9 @@ public class RubikObject
   private final int mSolverOrdinal;
   private final int mObjectOrdinal;
   private final boolean mIsLocal;
+  private final int mCategory, mYear;
+  private final float mDifficulty;
+  private final String mAuthor;
 
   private boolean mIsFree;
   private int mJsonID, mMeshID, mExtrasID;
@@ -65,6 +68,10 @@ public class RubikObject
     mJsonID      = meta.objectJson();
     mMeshID      = meta.mesh();
     mExtrasID    = meta.extrasJson();
+    mDifficulty  = meta.getDifficulty();
+    mCategory    = meta.getCategory();
+    mYear        = meta.getYearOfInvention();
+    mAuthor      = meta.getAuthor();
     mIsLocal     = false;
 
     int patternOrdinal  = RubikPatternList.getOrdinal(mObjectOrdinal);
@@ -90,6 +97,10 @@ public class RubikObject
     mIsFree        = mPrice==0;
     mObjectVersion = object.objectVersion;
     mExtrasVersion = object.extrasVersion;
+    mDifficulty    = object.difficulty;
+    mCategory      = object.category;
+    mYear          = object.year;
+    mAuthor        = object.author;
 
     mPatterns      = null;
     mExtrasOrdinal = -1;
@@ -285,6 +296,34 @@ public class RubikObject
     return null;
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getCategory()
+    {
+    return mCategory;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public float getDifficulty()
+    {
+    return mDifficulty;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getYearOfInvention()
+    {
+    return mYear;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public String getAuthor()
+    {
+    return mAuthor;
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public boolean hasExtras()
diff --git a/src/main/java/org/distorted/objects/RubikObjectCategories.java b/src/main/java/org/distorted/objects/RubikObjectCategories.java
index 6bd3536d..0890a2c8 100644
--- a/src/main/java/org/distorted/objects/RubikObjectCategories.java
+++ b/src/main/java/org/distorted/objects/RubikObjectCategories.java
@@ -11,10 +11,41 @@ package org.distorted.objects;
 
 import static org.distorted.main.MainSettingsPopup.*;
 
+import org.distorted.main.R;
+
+import java.util.Arrays;
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
 public class RubikObjectCategories
 {
+  public static final int[] DIFF_IDS =
+    {
+    R.id.configDifficulty0,
+    R.id.configDifficulty1,
+    R.id.configDifficulty2,
+    R.id.configDifficulty3,
+    R.id.configDifficulty4
+    };
+
+  public static final int[] DIFF_IMAGES =
+    {
+    R.drawable.difficulty1,
+    R.drawable.difficulty2,
+    R.drawable.difficulty3,
+    R.drawable.difficulty4,
+    R.drawable.difficulty5,
+    };
+
+  public static final int[] CATEGORY_IMAGES =
+    {
+    R.drawable.difficulty1,
+    R.drawable.difficulty2,
+    R.drawable.difficulty3,
+    R.drawable.difficulty4,
+    R.drawable.difficulty5,
+    };
+
   private final int mNumCategories;
   private int[][] mObjectIndices;
   private int[] mIconIDs;
@@ -43,46 +74,236 @@ public class RubikObjectCategories
       }
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private void buildSortStr(String[] data)
+    {
+    int numObjects = data.length;
+    String[] sorted = new String[numObjects];
+    System.arraycopy(data, 0, sorted, 0, numObjects);
+
+    Arrays.sort(sorted);
+
+    String[] categories = new String[numObjects];
+    int numCategories = 0;
+
+    for(int o=0; o<numObjects; o++)
+      if( o==0 || !sorted[o-1].equals(sorted[o]) )
+        {
+        categories[numCategories] = sorted[o];
+        numCategories++;
+        }
+
+    int lastChange = -1;
+    int curr = 0;
+    int[] numInCategory = new int[numCategories];
+
+    for(int o=0; o<numObjects; o++)
+      if( o==numObjects-1 || !sorted[o].equals(sorted[o+1]) )
+        {
+        numInCategory[curr] = o-lastChange;
+        curr++;
+        lastChange = o;
+        }
+
+    mObjectIndices = new int[numCategories][];
+
+    for(int c=0; c<numCategories; c++)
+      {
+      mObjectIndices[c] = new int[numInCategory[c]];
+
+      String cat = categories[c];
+      int index = 0;
+
+      for(int o=0; o<numObjects; o++)
+        if( data[o].equals(cat) ) mObjectIndices[c][index++] = o;
+      }
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private void buildSortInt(int[] data)
+    {
+    int numObjects = data.length;
+    int[] sorted = new int[numObjects];
+    System.arraycopy(data, 0, sorted, 0, numObjects);
+
+    Arrays.sort(sorted);
+
+    int[] categories = new int[numObjects];
+    int numCategories = 0;
+
+    for(int o=0; o<numObjects; o++)
+      if( o==0 || sorted[o-1]!=sorted[o] )
+        {
+        categories[numCategories] = sorted[o];
+        numCategories++;
+        }
+
+    int lastChange = -1;
+    int curr = 0;
+    int[] numInCategory = new int[numCategories];
+
+    for(int o=0; o<numObjects; o++)
+      if( o==numObjects-1 || sorted[o]!=sorted[o+1] )
+        {
+        numInCategory[curr] = o-lastChange;
+        curr++;
+        lastChange = o;
+        }
+
+    mObjectIndices = new int[numCategories][];
+
+    for(int c=0; c<numCategories; c++)
+      {
+      mObjectIndices[c] = new int[numInCategory[c]];
+
+      int cat = categories[c];
+      int index = 0;
+
+      for(int o=0; o<numObjects; o++)
+        if( data[o]==cat ) mObjectIndices[c][index++] = o;
+      }
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private void buildSortFloat(float[] data)
+    {
+    int numObjects = data.length;
+    float[] sorted = new float[numObjects];
+    System.arraycopy(data, 0, sorted, 0, numObjects);
+
+    Arrays.sort(sorted);
+
+    float[] categories = new float[numObjects];
+    int numCategories = 0;
+
+    for(int o=0; o<numObjects; o++)
+      if( o==0 || sorted[o-1]!=sorted[o] )
+        {
+        categories[numCategories] = sorted[o];
+        numCategories++;
+        }
+
+    int lastChange = -1;
+    int curr = 0;
+    int[] numInCategory = new int[numCategories];
+
+    for(int o=0; o<numObjects; o++)
+      if( o==numObjects-1 || sorted[o]!=sorted[o+1] )
+        {
+        numInCategory[curr] = o-lastChange;
+        curr++;
+        lastChange = o;
+        }
+
+    mObjectIndices = new int[numCategories][];
+
+    for(int c=0; c<numCategories; c++)
+      {
+      mObjectIndices[c] = new int[numInCategory[c]];
+
+      float cat = categories[c];
+      int index = 0;
+
+      for(int o=0; o<numObjects; o++)
+        if( data[o]==cat ) mObjectIndices[c][index++] = o;
+      }
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   private void buildSortCategory()
     {
+    int numObjects = RubikObjectList.getNumObjects();
+    int[] cats = new int[numObjects];
 
+    for(int o=0; o<numObjects; o++)
+      {
+      RubikObject obj = RubikObjectList.getObject(o);
+      cats[o] = obj==null ? 0 : obj.getCategory();
+      }
+
+    buildSortInt(cats);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   private void buildSortDifficulty()
     {
+    int numObjects = RubikObjectList.getNumObjects();
+    float[] diffs = new float[numObjects];
+
+    for(int o=0; o<numObjects; o++)
+      {
+      RubikObject obj = RubikObjectList.getObject(o);
+      diffs[o] = obj==null ? 0 : obj.getDifficulty();
+      }
 
+    buildSortFloat(diffs);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   private void buildSortAuthor()
     {
+    int numObjects = RubikObjectList.getNumObjects();
+    String[] auths = new String[numObjects];
+
+    for(int o=0; o<numObjects; o++)
+      {
+      RubikObject obj = RubikObjectList.getObject(o);
+      auths[o] = obj==null ? "" : obj.getAuthor();
+      }
 
+    buildSortStr(auths);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   private void buildSortYear()
     {
+    int numObjects = RubikObjectList.getNumObjects();
+    int[] years = new int[numObjects];
 
+    for(int o=0; o<numObjects; o++)
+      {
+      RubikObject obj = RubikObjectList.getObject(o);
+      years[o] = obj==null ? 0 : obj.getYearOfInvention();
+      }
+
+    buildSortInt(years);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   private void buildIconsCategory()
     {
+    mIconIDs = new int[mNumCategories];
 
+    for(int t=0; t<mNumCategories; t++)
+      {
+      int obj = mObjectIndices[t][0];
+      RubikObject object = RubikObjectList.getObject(obj);
+      int category = object==null ? 0 : object.getCategory();
+      mIconIDs[t] = CATEGORY_IMAGES[category%5];  //TODO
+      }
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   private void buildIconsDifficulty()
     {
+    mIconIDs = new int[mNumCategories];
 
+    for(int t=0; t<mNumCategories; t++)
+      {
+      int obj = mObjectIndices[t][0];
+      RubikObject object = RubikObjectList.getObject(obj);
+      int difficulty = object==null ? 0 : (int)object.getDifficulty();
+      mIconIDs[t] = DIFF_IMAGES[difficulty];
+      }
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -95,7 +316,7 @@ public class RubikObjectCategories
       {
       int obj = mObjectIndices[t][0];
       RubikObject object = RubikObjectList.getObject(obj);
-
+      mTitles[t] = object==null ? "" : object.getAuthor();
       }
     }
 
@@ -103,7 +324,15 @@ public class RubikObjectCategories
 
   private void buildTitleYear()
     {
+    mTitles = new String[mNumCategories];
 
+    for(int t=0; t<mNumCategories; t++)
+      {
+      int obj = mObjectIndices[t][0];
+      RubikObject object = RubikObjectList.getObject(obj);
+      int year = object==null ? 0 : object.getYearOfInvention();
+      mTitles[t] = String.valueOf(year);
+      }
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/main/java/org/distorted/objects/RubikObjectList.java b/src/main/java/org/distorted/objects/RubikObjectList.java
index e11df0c2..39358f1a 100644
--- a/src/main/java/org/distorted/objects/RubikObjectList.java
+++ b/src/main/java/org/distorted/objects/RubikObjectList.java
@@ -39,14 +39,22 @@ public class RubikObjectList
     String shortName;
     boolean icon,object,extras;
     int numScrambles, objectVersion, extrasVersion, price;
+    int category, year;
+    float difficulty;
+    String author;
 
-    DownloadedObject(String sName, int scrambles, int pr, int oVersion, int eVersion, boolean i, boolean o, boolean e)
+    DownloadedObject(String sName, int scrambles, int pr, int oVersion, int eVersion, boolean i,
+                     boolean o, boolean e, float diff, int cat, int y, String a)
       {
       shortName     = sName;
       numScrambles  = scrambles;
       price         = pr;
       objectVersion = oVersion;
       extrasVersion = eVersion;
+      difficulty    = diff;
+      category      = cat;
+      year          = y;
+      author        = a;
 
       icon   = i;
       object = o;
@@ -186,7 +194,7 @@ public class RubikObjectList
 // PUBLIC API
 
   public static boolean addDownloadedObject(Context context, String shortName, int numScrambles, int price, int objectVersion,
-                                         int extrasVersion, boolean icon, boolean object, boolean extras)
+                                         int extrasVersion, boolean icon, boolean object, boolean extras, float diff, int category, int year, String author)
     {
     if( SHOW_DOWNLOADED_DEBUG ) android.util.Log.e("D", "New downloaded object "+shortName+" icon="+icon+" object="+object+" extras="+extras);
 
@@ -213,7 +221,7 @@ public class RubikObjectList
     if( !object ) objectVersion=-1;
     if( !extras ) extrasVersion=-1;
 
-    DownloadedObject obj = new DownloadedObject(shortName,numScrambles,price,objectVersion,extrasVersion,icon,object,extras);
+    DownloadedObject obj = new DownloadedObject(shortName,numScrambles,price,objectVersion,extrasVersion,icon,object,extras,diff,category,year,author);
     if ( internalAddDownloadedObject(obj) )
       {
       if( SHOW_DOWNLOADED_DEBUG ) android.util.Log.e("D", "Adding new downloaded object "+shortName+" icon="+obj.icon+" object="+obj.object+" extras="+obj.extras);
@@ -310,6 +318,14 @@ public class RubikObjectList
         downloadedObjects.append(' ');
         downloadedObjects.append(object.extras ? "1":"0");
         downloadedObjects.append(' ');
+        downloadedObjects.append(object.difficulty);
+        downloadedObjects.append(' ');
+        downloadedObjects.append(object.category);
+        downloadedObjects.append(' ');
+        downloadedObjects.append(object.year);
+        downloadedObjects.append(' ');
+        downloadedObjects.append(object.author);
+        downloadedObjects.append(' ');
         downloadedObjects.append(object.price);
         }
 
@@ -352,7 +368,7 @@ public class RubikObjectList
         String[] parts = dObj.split(" ");
         int length = parts.length;
 
-        if( length==7 || length==8 )
+        if( length>=7 )
           {
           String name = parts[0];
           String scra = parts[1];
@@ -362,12 +378,20 @@ public class RubikObjectList
           String obje = parts[5];
           String extr = parts[6];
 
-          int price;
+          int price=0,category=0,year=0;
+          float diff=0.0f;
+          String author="";
 
-          if( length==7 ) price=0;
-          else
+          if( length>=11 )
+            {
+            diff     = Float.parseFloat(parts[7]);
+            category = Integer.parseInt(parts[8]);
+            year     = Integer.parseInt(parts[9]);
+            author   = parts[10];
+            }
+          if( length>=12 )
             {
-            char c = parts[7].charAt(0);
+            char c = parts[11].charAt(0);
             if( c=='t' )      price = 0;
             else if( c=='f' ) price = ListObjects.DEFAULT_PRICE_OF_OLD_OBJECTS;
             else              price = Integer.parseInt(parts[7]);
@@ -381,7 +405,7 @@ public class RubikObjectList
           boolean bObje = obje.equals("1");
           boolean bExtr = extr.equals("1");
 
-          addDownloadedObject(context,name,scrambles,price,oVersion,eVersion,bIcon,bObje,bExtr);
+          addDownloadedObject(context,name,scrambles,price,oVersion,eVersion,bIcon,bObje,bExtr,diff,category,year,author);
           }
         }
       }
diff --git a/src/main/java/org/distorted/purchase/PurchaseScreenPane.java b/src/main/java/org/distorted/purchase/PurchaseScreenPane.java
index de9add85..ae5e24d6 100644
--- a/src/main/java/org/distorted/purchase/PurchaseScreenPane.java
+++ b/src/main/java/org/distorted/purchase/PurchaseScreenPane.java
@@ -189,9 +189,9 @@ public class PurchaseScreenPane implements ListenerOverlay
         {
         reader.parseJsonFileMetadata(stream);
         name       = reader.getObjectName();
-        author     = reader.getInventor();
+        author     = reader.getAuthor();
         year       = reader.getYearOfInvention();
-        difficulty = (int)reader.getComplexity();
+        difficulty = (int)reader.getDifficulty();
         }
       catch(Exception ex)
         {
