commit 881697b35e58282fe9c78f1dcd4648d5095bcc12
Author: leszek <leszek@koltunski.pl>
Date:   Sun Jan 21 16:10:08 2024 +0100

    progress

diff --git a/src/main/java/org/distorted/main/MainSettingsPopup.java b/src/main/java/org/distorted/main/MainSettingsPopup.java
index bc72a98b..ffb2a319 100644
--- a/src/main/java/org/distorted/main/MainSettingsPopup.java
+++ b/src/main/java/org/distorted/main/MainSettingsPopup.java
@@ -10,6 +10,7 @@
 package org.distorted.main;
 
 import android.content.Context;
+import android.content.res.Resources;
 import android.os.Build;
 import android.util.TypedValue;
 import android.view.Gravity;
@@ -30,14 +31,13 @@ import java.lang.reflect.Field;
 public class MainSettingsPopup implements AdapterView.OnItemSelectedListener
   {
   public static final int SORT_CLASSIC    = 0;
-  public static final int SORT_CATEGORY   = 1;
+  public static final int SORT_SHAPE      = 1;
   public static final int SORT_DIFFICULTY = 2;
   public static final int SORT_AUTHOR     = 3;
   public static final int SORT_YEAR       = 4;
 
   public static final int SORT_DEFAULT    = SORT_CLASSIC;
 
-  private static final String[] mSortNames = { "Classic" , "Category" , "Difficulty", "Author" , "Year" };
   private static final float MENU_TITLE_SIZE= 0.070f;
   private static final float MENU_TEXT_SIZE = 0.060f;
   private static final int[] mLocation = new int[2];
@@ -45,6 +45,7 @@ public class MainSettingsPopup implements AdapterView.OnItemSelectedListener
   private final PopupWindow mPopup;
   private final WeakReference<MainActivity> mAct;
   private int mCurrMethod;
+  private String[] mSortNames;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // this is supposed to prevent showing the navigational bar when we show the drop down list,
@@ -109,6 +110,7 @@ public class MainSettingsPopup implements AdapterView.OnItemSelectedListener
     actSpinner.setOnItemSelectedListener(this);
 
     mCurrMethod = sortMethod;
+    buildSortOptions(act);
 
     ArrayAdapter<String> actAdapter = new ArrayAdapter<>(act, android.R.layout.simple_spinner_item, mSortNames);
     actAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
@@ -117,6 +119,20 @@ public class MainSettingsPopup implements AdapterView.OnItemSelectedListener
     if( sortMethod>=0 && sortMethod<mSortNames.length ) actSpinner.setSelection(sortMethod);
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private void buildSortOptions(MainActivity act)
+    {
+    Resources res = act.getResources();
+    mSortNames = new String[5];
+
+    mSortNames[0] = res.getString(R.string.sort_classic);
+    mSortNames[1] = res.getString(R.string.sort_shape);
+    mSortNames[2] = res.getString(R.string.sort_difficulty);
+    mSortNames[3] = res.getString(R.string.sort_author);
+    mSortNames[4] = res.getString(R.string.sort_year);
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // work around lame bugs in Android's version <= 10 pop-up and split-screen modes
 
diff --git a/src/main/java/org/distorted/objects/RubikObjectCategories.java b/src/main/java/org/distorted/objects/RubikObjectCategories.java
index 839d5687..3298291c 100644
--- a/src/main/java/org/distorted/objects/RubikObjectCategories.java
+++ b/src/main/java/org/distorted/objects/RubikObjectCategories.java
@@ -69,7 +69,7 @@ public abstract class RubikObjectCategories
     {
     switch(sortMode)
       {
-      case SORT_CATEGORY  : return new RubikObjectCategoriesCat();
+      case SORT_SHAPE     : return new RubikObjectCategoriesShape();
       case SORT_DIFFICULTY: return new RubikObjectCategoriesDiff();
       case SORT_AUTHOR    : return new RubikObjectCategoriesAuthor();
       case SORT_YEAR      : return new RubikObjectCategoriesYear();
diff --git a/src/main/java/org/distorted/objects/RubikObjectCategoriesCat.java b/src/main/java/org/distorted/objects/RubikObjectCategoriesCat.java
deleted file mode 100644
index e2c7be7e..00000000
--- a/src/main/java/org/distorted/objects/RubikObjectCategoriesCat.java
+++ /dev/null
@@ -1,92 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// Copyright 2024 Leszek Koltunski                                                               //
-//                                                                                               //
-// This file is part of Magic Cube.                                                              //
-//                                                                                               //
-// Magic Cube is proprietary software licensed under an EULA which you should have received      //
-// along with the code. If not, check https://distorted.org/magic/License-Magic-Cube.html        //
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-package org.distorted.objects;
-
-import java.util.Arrays;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-public class RubikObjectCategoriesCat extends RubikObjectCategories
-{
-  private void buildSort(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;
-      }
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  void buildIndices()
-    {
-    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();
-      }
-
-    buildSort(cats);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  void buildTitle()
-    {
-    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
-      }
-    }
-}
diff --git a/src/main/java/org/distorted/objects/RubikObjectCategoriesShape.java b/src/main/java/org/distorted/objects/RubikObjectCategoriesShape.java
new file mode 100644
index 00000000..3905eedd
--- /dev/null
+++ b/src/main/java/org/distorted/objects/RubikObjectCategoriesShape.java
@@ -0,0 +1,103 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2024 Leszek Koltunski                                                               //
+//                                                                                               //
+// This file is part of Magic Cube.                                                              //
+//                                                                                               //
+// Magic Cube is proprietary software licensed under an EULA which you should have received      //
+// along with the code. If not, check https://distorted.org/magic/License-Magic-Cube.html        //
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+package org.distorted.objects;
+
+import java.util.Arrays;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+public class RubikObjectCategoriesShape extends RubikObjectCategories
+{
+  private void buildSort(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 int digestCategory(int cat)
+    {
+    int shape = (cat & 0x7);
+    int axis  = (cat & 0x1f) >> 3;
+    return (shape<<2) + axis;   // only shape and axis sorted by shape
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  void buildIndices()
+    {
+    int numObjects = RubikObjectList.getNumObjects();
+    int[] cats = new int[numObjects];
+
+    for(int o=0; o<numObjects; o++)
+      {
+      RubikObject obj = RubikObjectList.getObject(o);
+      int cat = obj==null ? 0 : obj.getCategory();
+      cats[o] = digestCategory(cat);
+      }
+
+    buildSort(cats);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  void buildTitle()
+    {
+    mIconIDs = new int[mNumCategories];
+
+    for(int t=0; t<mNumCategories; t++)
+      {
+      int obj = mObjectIndices[t][0];
+      RubikObject object = RubikObjectList.getObject(obj);
+      int cat = object==null ? 0 : object.getCategory();
+      int category = digestCategory(cat);
+      mIconIDs[t] = CATEGORY_IMAGES[category%5];  //TODO
+      }
+    }
+}
diff --git a/src/main/res/values-de/strings.xml b/src/main/res/values-de/strings.xml
index 3cae2bf1..fe62613a 100755
--- a/src/main/res/values-de/strings.xml
+++ b/src/main/res/values-de/strings.xml
@@ -85,6 +85,12 @@
     <string name="config_mesh_fast">Schelles</string>
     <string name="config_mesh_nice">Hübsches</string>
 
+    <string name="sort_classic">klassisch</string>
+    <string name="sort_shape">form</string>
+    <string name="sort_difficulty">schwierigkeit</string>
+    <string name="sort_author">autor</string>
+    <string name="sort_year">jahr</string>
+
     <string name="credits1">Open Source App, die mit der Distorted Graphics Library entwickelt wurde. Lizenziert unter <a href="https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html">GPL Version 2</a> oder wie gewünscht einer späteren Version.</string>
     <string name="credits2">Hübsche Muster von Walter Randelshofer. Sehen Sie <a href="http://www.randelshofer.ch">http://www.randelshofer.ch</a></string>
     <string name="credits3">Rubik und Rubik Cube sind eingetragene Warenzeichen. Wir sind damit nicht verbunden.</string>
diff --git a/src/main/res/values-es/strings.xml b/src/main/res/values-es/strings.xml
index fc1cdb46..3215543c 100755
--- a/src/main/res/values-es/strings.xml
+++ b/src/main/res/values-es/strings.xml
@@ -85,6 +85,12 @@
     <string name="config_mesh_fast">Rápida</string>
     <string name="config_mesh_nice">Bonita</string>
 
+    <string name="sort_classic">clásico</string>
+    <string name="sort_shape">forma</string>
+    <string name="sort_difficulty">dificultad</string>
+    <string name="sort_author">autor</string>
+    <string name="sort_year">año</string>
+
     <string name="credits1">Aplicación de código abierto desarrollada con la biblioteca de gráficos de Distorted. Con licencia <a href="https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html">GPL versión 2</a> o, a tu elección, cualquier versión posterior.</string>
     <string name="credits2">Pretty Patterns por Walter Randelshofer. Mira <a href="http://www.randelshofer.ch">http://www.randelshofer.ch</a></string>
     <string name="credits3">Rubik y Rubik Cube son marcas registradas. No estamos afiliados a ella.</string>
diff --git a/src/main/res/values-fr/strings.xml b/src/main/res/values-fr/strings.xml
index fc42328e..5997645d 100755
--- a/src/main/res/values-fr/strings.xml
+++ b/src/main/res/values-fr/strings.xml
@@ -85,6 +85,12 @@
     <string name="config_mesh_fast">Rapide</string>
     <string name="config_mesh_nice">Belle</string>
 
+    <string name="sort_classic">classique</string>
+    <string name="sort_shape">forme</string>
+    <string name="sort_difficulty">difficulté</string>
+    <string name="sort_author">auteur</string>
+    <string name="sort_year">année</string>
+
     <string name="credits1">Appli Open Source développée à l\'aide de la bibliothèque graphique Distorted. Sous licence <a href="https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html">GPL version 2</a> ou - à votre choix - toute version ultérieure.</string>
     <string name="credits2">Pretty Patterns par Walter Randelshofer. Voir <a href="http://www.randelshofer.ch">http://www.randelshofer.ch</a></string>
     <string name="credits3">Rubik et Rubik Cube sont des marques déposées. Nous n\'y sommes pas affiliés.</string>
diff --git a/src/main/res/values-ja/strings.xml b/src/main/res/values-ja/strings.xml
index 0b8685cd..bfe05c07 100755
--- a/src/main/res/values-ja/strings.xml
+++ b/src/main/res/values-ja/strings.xml
@@ -85,6 +85,12 @@
     <string name="config_mesh_fast">速い</string>
     <string name="config_mesh_nice">良い</string>
 
+    <string name="sort_classic">古典学</string>
+    <string name="sort_shape">形</string>
+    <string name="sort_difficulty">困難</string>
+    <string name="sort_author">著者</string>
+    <string name="sort_year">年</string>
+
     <string name="credits1">ディストートグラフィックのライブラリを使用して開発されたオープンソースアプリ。<a href="https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html">GPL バージョン 2</a>でライセンスされているか、または-オプション-それ以降のすべてのバージョン。</string>
     <string name="credits2">Pretty Patterns 沿って Walter Randelshofer. 見る <a href="http://www.randelshofer.ch">http://www.randelshofer.ch</a></string>
     <string name="credits3">ルービックキューブおよびルービックキューブは登録商標です。 私たちはそれと提携していません。</string>
diff --git a/src/main/res/values-ko/strings.xml b/src/main/res/values-ko/strings.xml
index 74a4b730..ce6384c5 100755
--- a/src/main/res/values-ko/strings.xml
+++ b/src/main/res/values-ko/strings.xml
@@ -85,6 +85,12 @@
     <string name="config_mesh_fast">빠른</string>
     <string name="config_mesh_nice">멋진</string>
 
+    <string name="sort_classic">전통적인</string>
+    <string name="sort_shape">모양</string>
+    <string name="sort_difficulty">어려움</string>
+    <string name="sort_author">작가</string>
+    <string name="sort_year">년도</string>
+
     <string name="credits1">왜곡된 그래픽 라이브러리를 사용하여 개발된 오픈 소스 앱. <a href="https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html">GPL 버전 2</a> 또는 귀하의 선택에 따라 최신 버전으로 라이센스가 부여됩니다.</string>
     <string name="credits2">Pretty Patterns 으로 Walter Randelshofer. 보다 <a href="http://www.randelshofer.ch">http://www.randelshofer.ch</a></string>
     <string name="credits3">Rubik 및 Rubik Cube는 등록 상표입니다. 우리는 그것과 제휴하지 않습니다.</string>
diff --git a/src/main/res/values-pl/strings.xml b/src/main/res/values-pl/strings.xml
index e44e8c4b..f6e5cc51 100644
--- a/src/main/res/values-pl/strings.xml
+++ b/src/main/res/values-pl/strings.xml
@@ -85,6 +85,12 @@
     <string name="config_mesh_fast">Szybka</string>
     <string name="config_mesh_nice">Ładna</string>
 
+    <string name="sort_classic">klasycznie</string>
+    <string name="sort_shape">kształt</string>
+    <string name="sort_difficulty">trudność</string>
+    <string name="sort_author">autor</string>
+    <string name="sort_year">rok</string>
+
     <string name="credits1">Aplikacja open-source napisana wykorzystując bibliotekę Distorted. Licencja: <a href="https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html">GPL wersja 2</a> albo jakakolwiek poźniejsza.</string>
     <string name="credits2">Piękne Wzory Waltera Randelshofera. Zobacz <a href="http://www.randelshofer.ch">http://www.randelshofer.ch</a></string>
     <string name="credits3">Rubik i RubikCube to zarejestrowane znaki towarowe. Nie jesteśmy z nimi powiązani.</string>
diff --git a/src/main/res/values-ru/strings.xml b/src/main/res/values-ru/strings.xml
index 76e552ab..f388a612 100755
--- a/src/main/res/values-ru/strings.xml
+++ b/src/main/res/values-ru/strings.xml
@@ -85,6 +85,12 @@
     <string name="config_mesh_fast">Быстрая</string>
     <string name="config_mesh_nice">Красивая</string>
 
+    <string name="sort_classic">классик</string>
+    <string name="sort_shape">форма</string>
+    <string name="sort_difficulty">сложность</string>
+    <string name="sort_author">автор</string>
+    <string name="sort_year">год</string>
+
     <string name="credits1">Приложение с открытым исходным кодом, разработанное с использованием библиотеки графики Искажений. Лицензируется согласно <a href="https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html">версии 2 GPL</a> или любой более поздней версии по вашему выбору.</string>
     <string name="credits2">Pretty Patterns по Walter Randelshofer. Смотри <a href="http://www.randelshofer.ch">http://www.randelshofer.ch</a></string>
     <string name="credits3">Рубик и Кубик Рубика являются зарегистрированными товарными знаками. Мы не связаны с этим.</string>
diff --git a/src/main/res/values-zh-rCN/strings.xml b/src/main/res/values-zh-rCN/strings.xml
index 56479de3..1d14705d 100644
--- a/src/main/res/values-zh-rCN/strings.xml
+++ b/src/main/res/values-zh-rCN/strings.xml
@@ -85,6 +85,12 @@
     <string name="config_mesh_fast">快</string>
     <string name="config_mesh_nice">好的</string>
 
+    <string name="sort_classic">經典的</string>
+    <string name="sort_shape">形狀</string>
+    <string name="sort_difficulty">困难</string>
+    <string name="sort_author">作者</string>
+    <string name="sort_year">年</string>
+
     <string name="credits1">此应用程式原始码开发使用Distorted图型库。根据<a href="https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html">通用公共许可版本2</a>或者任何更新版本（根据您的选择）进行许可。</string>
     <string name="credits2">Pretty Patterns by Werner Randelshofer. 請看 <a href="http://www.randelshofer.ch">http://www.randelshofer.ch</a></string>
     <string name="credits3">魔方和魔方是注册商标。 我们不隶属于它。</string>
diff --git a/src/main/res/values-zh-rTW/strings.xml b/src/main/res/values-zh-rTW/strings.xml
index 691f9d62..d6e2784d 100644
--- a/src/main/res/values-zh-rTW/strings.xml
+++ b/src/main/res/values-zh-rTW/strings.xml
@@ -85,6 +85,12 @@
     <string name="config_mesh_fast">快</string>
     <string name="config_mesh_nice">好的</string>
 
+    <string name="sort_classic">经典的</string>
+    <string name="sort_shape">形状</string>
+    <string name="sort_difficulty">困難</string>
+    <string name="sort_author">作者</string>
+    <string name="sort_year">年</string>
+
     <string name="credits1">此應用程式原始碼開發使用Distorted圖型庫。根據<a href="https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html">通用公共許可版本2</a>或者任何更新版本（根據您的選擇）進行許可。</string>
     <string name="credits2">Pretty Patterns by Werner Randelshofer. 請看 <a href="http://www.randelshofer.ch">http://www.randelshofer.ch</a></string>
     <string name="credits3">魔方和魔方是註冊商標。 我們不隸屬於它。</string>
diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml
index c1c29b5f..309e46c7 100644
--- a/src/main/res/values/strings.xml
+++ b/src/main/res/values/strings.xml
@@ -109,6 +109,12 @@
     <string name="config_mesh_fast">Fast</string>
     <string name="config_mesh_nice">Nice</string>
 
+    <string name="sort_classic">classic</string>
+    <string name="sort_shape">shape</string>
+    <string name="sort_difficulty">difficulty</string>
+    <string name="sort_author">author</string>
+    <string name="sort_year">year</string>
+
     <string name="webview_error" translatable="false">Error Loading WebView</string>
     <string name="opengl_error" translatable="false">Error</string>
     <string name="opengl_error_text" translatable="false">This device does not support OpenGL 3.0</string>
