commit 80f574a1c6b7ce70b0f2b03dabebc43d2c2a7a57
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Fri Aug 12 00:37:53 2022 +0200

    IAP, part 1: Introduce the concept of a 'free' and 'not free' object to
    
    - ObjectType
    - DownloadedObject
    - RubikObject
    - jsons

diff --git a/src/main/java/org/distorted/bandaged/BandagedCreatorRenderer.java b/src/main/java/org/distorted/bandaged/BandagedCreatorRenderer.java
index fa9b3994..56407916 100644
--- a/src/main/java/org/distorted/bandaged/BandagedCreatorRenderer.java
+++ b/src/main/java/org/distorted/bandaged/BandagedCreatorRenderer.java
@@ -445,7 +445,7 @@ public class BandagedCreatorRenderer implements GLSurfaceView.Renderer, Distorte
      try
        {
        JsonWriter writer = JsonWriter.getInstance();
-       String json = writer.createObjectString(object,24);
+       String json = writer.createObjectString(object,24,true);
        writer.write(filename,json);
        return true;
        }
diff --git a/src/main/java/org/distorted/bandaged/BandagedCreatorScreen.java b/src/main/java/org/distorted/bandaged/BandagedCreatorScreen.java
index dacc71d5..826ba08b 100644
--- a/src/main/java/org/distorted/bandaged/BandagedCreatorScreen.java
+++ b/src/main/java/org/distorted/bandaged/BandagedCreatorScreen.java
@@ -175,19 +175,16 @@ public class BandagedCreatorScreen implements AdapterView.OnItemSelectedListener
     mSpinnerX = act.findViewById(R.id.bandagedCreatorX);
     mSpinnerX.setOnItemSelectedListener(this);
     ArrayAdapter<String> adX = new ArrayAdapter<>(act, R.layout.spinner_item, createSizes("X") );
-    adX.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
     mSpinnerX.setAdapter(adX);
 
     mSpinnerY = act.findViewById(R.id.bandagedCreatorY);
     mSpinnerY.setOnItemSelectedListener(this);
     ArrayAdapter<String> adY = new ArrayAdapter<>(act, R.layout.spinner_item, createSizes("Y") );
-    adY.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
     mSpinnerY.setAdapter(adY);
 
     mSpinnerZ = act.findViewById(R.id.bandagedCreatorZ);
     mSpinnerZ.setOnItemSelectedListener(this);
     ArrayAdapter<String> adZ = new ArrayAdapter<>(act, R.layout.spinner_item, createSizes("Z") );
-    adZ.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
     mSpinnerZ.setAdapter(adZ);
 
     ViewGroup.MarginLayoutParams paramsX = (ViewGroup.MarginLayoutParams) mSpinnerX.getLayoutParams();
diff --git a/src/main/java/org/distorted/dialogs/RubikDialogUpdateView.java b/src/main/java/org/distorted/dialogs/RubikDialogUpdateView.java
index 441bd65a..f6050c6c 100644
--- a/src/main/java/org/distorted/dialogs/RubikDialogUpdateView.java
+++ b/src/main/java/org/distorted/dialogs/RubikDialogUpdateView.java
@@ -194,8 +194,10 @@ public class RubikDialogUpdateView implements RubikNetwork.Downloadee
         try
           {
           JsonReader reader = JsonReader.getInstance();
-          mInfo.mNumScrambles = reader.readNumScrambles(act,objectName);
-          if( SHOW_DOWNLOADED_DEBUG ) android.util.Log.e("D", "Read from JSON numScrambles="+mInfo.mNumScrambles);
+          reader.readNumScramblesAndIsFree(act,objectName);
+          mInfo.mNumScrambles = reader.getNumScrambles();
+          mInfo.mIsFree       = reader.isFree();
+          if( SHOW_DOWNLOADED_DEBUG ) android.util.Log.e("D", "Read from JSON numScrambles="+mInfo.mNumScrambles+" isFree="+mInfo.mIsFree);
 
           if( mInfo.mExtrasStream!=null )
             {
@@ -211,8 +213,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.mObjectMinorVersion,
-                                                                  mInfo.mExtrasMinorVersion, mIconSaved, oSuccess, eSuccess);
+            boolean success = RubikObjectList.addDownloadedObject(act, mInfo.mObjectShortName, mInfo.mNumScrambles, mInfo.mIsFree,
+                                                                  mInfo.mObjectMinorVersion, mInfo.mExtrasMinorVersion, mIconSaved, oSuccess, eSuccess);
             if( success )
               {
               if( SHOW_DOWNLOADED_DEBUG ) android.util.Log.e("D", "2");
diff --git a/src/main/java/org/distorted/external/RubikUpdates.java b/src/main/java/org/distorted/external/RubikUpdates.java
index 7ede9f02..f18a29cb 100644
--- a/src/main/java/org/distorted/external/RubikUpdates.java
+++ b/src/main/java/org/distorted/external/RubikUpdates.java
@@ -36,6 +36,7 @@ public class RubikUpdates
     public final boolean mUpdateExtras;
 
     public int mNumScrambles;
+    public boolean mIsFree;
     public Bitmap mIcon;
     public InputStream mObjectStream;
     public InputStream mExtrasStream;
diff --git a/src/main/java/org/distorted/objects/RubikObject.java b/src/main/java/org/distorted/objects/RubikObject.java
index e0c2a2f7..b1307b1b 100644
--- a/src/main/java/org/distorted/objects/RubikObject.java
+++ b/src/main/java/org/distorted/objects/RubikObject.java
@@ -40,6 +40,7 @@ public class RubikObject
   private final String mLowerName, mUpperName;
   private final int mIconID;
   private final String[][] mPatterns;
+  private final boolean mIsFree;
 
   private int mJsonID, mMeshID, mExtrasID;
   private int mObjectMinor, mExtrasMinor;
@@ -57,6 +58,7 @@ public class RubikObject
     mUpperName   = type.name();
     mLowerName   = type.name().toLowerCase(Locale.ENGLISH);
     mNumScramble = type.getNumScramble();
+    mIsFree      = type.isFree();
 
     mIconID      = type.getIconID();
     mJsonID      = ObjectJson.getObjectJsonID(ordinal);
@@ -85,6 +87,7 @@ public class RubikObject
     mLowerName     = object.shortName;
     mUpperName     = object.shortName.toUpperCase(Locale.ENGLISH);
     mNumScramble   = object.numScrambles;
+    mIsFree        = object.free;
     mObjectMinor   = object.objectMinor;
     mExtrasMinor   = object.extrasMinor;
 
@@ -211,6 +214,13 @@ public class RubikObject
     return mNumScramble;
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public boolean isFree()
+    {
+    return mIsFree;
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public int getObjectMinor()
diff --git a/src/main/java/org/distorted/objects/RubikObjectList.java b/src/main/java/org/distorted/objects/RubikObjectList.java
index 4c4ff9ab..9c009702 100644
--- a/src/main/java/org/distorted/objects/RubikObjectList.java
+++ b/src/main/java/org/distorted/objects/RubikObjectList.java
@@ -38,14 +38,15 @@ public class RubikObjectList
   public static class DownloadedObject
     {
     String shortName;
-    boolean icon,object,extras;
+    boolean icon,object,extras,free;
     int numScrambles, objectMinor, extrasMinor;
 
-    DownloadedObject(String sName, int scrambles, int oMinor, int eMinor, boolean i, boolean o, boolean e)
+    DownloadedObject(String sName, int scrambles, boolean isFree, int oMinor, int eMinor, boolean i, boolean o, boolean e)
       {
       shortName = sName;
 
       numScrambles= scrambles;
+      free        = isFree;
       objectMinor = oMinor;
       extrasMinor = eMinor;
 
@@ -133,7 +134,7 @@ public class RubikObjectList
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // PUBLIC API
 
-  public static boolean addDownloadedObject(Context context, String shortName, int numScrambles, int objectMinor,
+  public static boolean addDownloadedObject(Context context, String shortName, int numScrambles, boolean isFree, int objectMinor,
                                          int extrasMinor, boolean icon, boolean object, boolean extras)
     {
     if( SHOW_DOWNLOADED_DEBUG ) android.util.Log.e("D", "New downloaded object "+shortName+" icon="+icon+" object="+object+" extras="+extras);
@@ -171,7 +172,7 @@ public class RubikObjectList
     if( !object ) objectMinor=-1;
     if( !extras ) extrasMinor=-1;
 
-    DownloadedObject obj = new DownloadedObject(shortName,numScrambles,objectMinor,extrasMinor,icon,object,extras);
+    DownloadedObject obj = new DownloadedObject(shortName,numScrambles,isFree,objectMinor,extrasMinor,icon,object,extras);
     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);
@@ -234,6 +235,8 @@ public class RubikObjectList
         downloadedObjects.append(object.object ? "1":"0");
         downloadedObjects.append(' ');
         downloadedObjects.append(object.extras ? "1":"0");
+        downloadedObjects.append(' ');
+        downloadedObjects.append(object.free ? "true":"false");
         }
 
       String objects = downloadedObjects.toString();
@@ -279,8 +282,9 @@ public class RubikObjectList
       for(String dObj : dObjects)
         {
         String[] parts = dObj.split(" ");
+        int length = parts.length;
 
-        if( parts.length==7 )
+        if( length==7 || length==8 )
           {
           String name = parts[0];
           String scra = parts[1];
@@ -289,6 +293,7 @@ public class RubikObjectList
           String icon = parts[4];
           String obje = parts[5];
           String extr = parts[6];
+          boolean isFree = (length==7 || Boolean.parseBoolean(parts[7]));
 
           int scrambles = Integer.parseInt(scra);
           int oMinor    = Integer.parseInt(objM);
@@ -298,7 +303,7 @@ public class RubikObjectList
           boolean bObje = obje.equals("1");
           boolean bExtr = extr.equals("1");
 
-          addDownloadedObject(context,name,scrambles,oMinor,eMinor,bIcon,bObje,bExtr);
+          addDownloadedObject(context,name,scrambles,isFree,oMinor,eMinor,bIcon,bObje,bExtr);
           }
         }
       }
