commit d05e7629a17a9b21317c272fe1b6927a1cfae5b8
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Tue Dec 27 01:10:04 2022 +0100

    Stars: introductory dialog explaining the concept of stars.

diff --git a/src/main/java/org/distorted/dialogs/RubikDialogExplainStars.java b/src/main/java/org/distorted/dialogs/RubikDialogExplainStars.java
new file mode 100644
index 00000000..8edac461
--- /dev/null
+++ b/src/main/java/org/distorted/dialogs/RubikDialogExplainStars.java
@@ -0,0 +1,79 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2022 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.dialogs;
+
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.util.DisplayMetrics;
+import android.util.TypedValue;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.Window;
+import android.widget.Button;
+
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AlertDialog;
+import androidx.appcompat.app.AppCompatDialogFragment;
+import androidx.fragment.app.FragmentActivity;
+
+import org.distorted.main.R;
+import org.distorted.main.RubikActivity;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+public class RubikDialogExplainStars extends AppCompatDialogFragment
+  {
+  @NonNull
+  @Override
+  public Dialog onCreateDialog(Bundle savedInstanceState)
+    {
+    FragmentActivity act = getActivity();
+    LayoutInflater inflater = act.getLayoutInflater();
+    AlertDialog.Builder builder = new AlertDialog.Builder(act);
+    DisplayMetrics displaymetrics = new DisplayMetrics();
+    act.getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
+    final float butSize = displaymetrics.widthPixels * RubikActivity.DIALOG_BUTTON_SIZE;
+    final View view = inflater.inflate(R.layout.dialog_explain_stars, null);
+
+    builder.setCancelable(true);
+
+    builder.setPositiveButton( R.string.ok, new DialogInterface.OnClickListener()
+      {
+      @Override
+      public void onClick(DialogInterface dialog, int which) { }
+      });
+
+    builder.setView(view);
+
+    final Dialog dialog = builder.create();
+    dialog.setCanceledOnTouchOutside(false);
+    Window window = dialog.getWindow();
+
+    if( window!=null )
+      {
+      window.getDecorView().setSystemUiVisibility(RubikActivity.FLAGS);
+      }
+
+    dialog.setOnShowListener(new DialogInterface.OnShowListener()
+      {
+      @Override
+      public void onShow(DialogInterface dialog)
+        {
+        Button btnPositive = ((AlertDialog)dialog).getButton(Dialog.BUTTON_POSITIVE);
+        btnPositive.setTextSize(TypedValue.COMPLEX_UNIT_PX, butSize);
+        Button btnNegative = ((AlertDialog)dialog).getButton(Dialog.BUTTON_NEGATIVE);
+        btnNegative.setTextSize(TypedValue.COMPLEX_UNIT_PX, butSize);
+        }
+      });
+
+    return dialog;
+    }
+  }
diff --git a/src/main/java/org/distorted/main/RubikActivity.java b/src/main/java/org/distorted/main/RubikActivity.java
index 68ac1d04..1f21c222 100644
--- a/src/main/java/org/distorted/main/RubikActivity.java
+++ b/src/main/java/org/distorted/main/RubikActivity.java
@@ -35,6 +35,7 @@ import com.google.firebase.inappmessaging.FirebaseInAppMessaging;
 
 import org.distorted.config.ConfigActivity;
 import org.distorted.bandaged.BandagedCreatorActivity;
+import org.distorted.dialogs.RubikDialogExplainStars;
 import org.distorted.library.main.DistortedLibrary;
 
 import org.distorted.library.main.DistortedScreen;
@@ -49,6 +50,8 @@ import org.distorted.external.RubikScores;
 import org.distorted.external.RubikNetwork;
 import org.distorted.objects.RubikObject;
 import org.distorted.objects.RubikObjectList;
+import org.distorted.overlays.DataStars;
+import org.distorted.overlays.OverlayStars;
 import org.distorted.purchase.PurchaseActivity;
 import org.distorted.screens.RubikScreenSolving;
 import org.distorted.screens.ScreenList;
@@ -108,7 +111,7 @@ public class RubikActivity extends AppCompatActivity
     private int mCurrentApiVersion;
     private int mHeightUpperBar, mHeightLowerBar;
     private int mOldVersion1, mOldVersion2, mOldVersion3;
-    private String mCurrVersion;
+    private String mOldVersion, mCurrVersion;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
@@ -279,9 +282,39 @@ public class RubikActivity extends AppCompatActivity
       int object = RubikObjectList.getCurrObject();
       changeIfDifferent(object,view.getObjectControl());
 
-      if( mIsChinese && !mPolicyAccepted ) PrivacyPolicy();
+      if( mIsChinese && !mPolicyAccepted ) privacyPolicy();
+
+      if( USE_IAP && mOldVersion!=null && oldVersionLessThan(1,11,5) && !mCurrVersion.equals("1.11.4") )
+        {
+        explainStars();
+        }
+      else
+        {
+        RubikScores scores = RubikScores.getInstance();
+        int totStars = scores.getNumStars();
+        DistortedScreen screen = getScreen();
+        OverlayStars stars = new OverlayStars();
+        DataStars data = new DataStars(totStars,0,getResources());
+        stars.startOverlay(screen,null,data);
+        }
       }
-    
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    private void privacyPolicy()
+      {
+      RubikDialogPrivacy priDiag = new RubikDialogPrivacy();
+      priDiag.show(getSupportFragmentManager(), null);
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    private void explainStars()
+      {
+      RubikDialogExplainStars staDiag = new RubikDialogExplainStars();
+      staDiag.show(getSupportFragmentManager(), null);
+      }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
     
     @Override
@@ -354,8 +387,8 @@ public class RubikActivity extends AppCompatActivity
     private void restorePreferences(SharedPreferences preferences, boolean justStarted)
       {
       mPolicyAccepted = preferences.getBoolean("policyAccepted", false);
-      String oldVersion = preferences.getString("appVersion","");
-      parseVersion(oldVersion);
+      mOldVersion = preferences.getString("appVersion","");
+      parseOldVersion(mOldVersion);
 
       RubikObjectList.restorePreferences(this,preferences,justStarted);
 
@@ -407,7 +440,7 @@ public class RubikActivity extends AppCompatActivity
       // So in such case, i.e. on fresh upgrade from version<=1.8.6 to version>=1.9.0, do not
       // restore the object scrambling.
 
-      if( !oldVersion.equals("") )
+      if( !mOldVersion.equals("") )
         {
         RubikSurfaceView view = findViewById(R.id.rubikSurfaceView);
         view.getObjectControl().restorePreferences(preferences);
@@ -416,7 +449,7 @@ public class RubikActivity extends AppCompatActivity
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-    private void parseVersion(String version)
+    private void parseOldVersion(String version)
       {
       if( version==null ) return;
 
@@ -468,14 +501,6 @@ public class RubikActivity extends AppCompatActivity
         }
       }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-    private void PrivacyPolicy()
-      {
-      RubikDialogPrivacy priDiag = new RubikDialogPrivacy();
-      priDiag.show(getSupportFragmentManager(), null);
-      }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
     void OpenGLError()
diff --git a/src/main/java/org/distorted/overlays/OverlayStars.java b/src/main/java/org/distorted/overlays/OverlayStars.java
index 36069237..12c4809a 100644
--- a/src/main/java/org/distorted/overlays/OverlayStars.java
+++ b/src/main/java/org/distorted/overlays/OverlayStars.java
@@ -374,7 +374,7 @@ public class OverlayStars extends OverlayGeneric implements EffectListener
             mNodeFalling=null;
             }
 
-         mListener.overlayFinished(id);
+         if( mListener!=null ) mListener.overlayFinished(id);
          }
       }
 
diff --git a/src/main/res/layout/dialog_explain_stars.xml b/src/main/res/layout/dialog_explain_stars.xml
new file mode 100644
index 00000000..0a9431dd
--- /dev/null
+++ b/src/main/res/layout/dialog_explain_stars.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:gravity="center|fill_horizontal"
+    android:layout_marginLeft="10dp"
+    android:layout_marginRight="10dp"
+    android:layout_marginTop="0dp"
+    android:background="@color/grey"
+    android:orientation="vertical">
+
+    <TextView
+        android:id="@+id/privacy_string"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:gravity="center"
+        android:textSize="24sp"
+        android:text="@string/explain_stars_text"
+        android:layout_marginTop="10dp"
+        android:layout_marginLeft="10dp"
+        android:layout_marginRight="10dp"
+        android:layout_marginBottom="10dp"/>
+</LinearLayout>
diff --git a/src/main/res/values-de/strings.xml b/src/main/res/values-de/strings.xml
index 0b4d32ca..430fd7d0 100755
--- a/src/main/res/values-de/strings.xml
+++ b/src/main/res/values-de/strings.xml
@@ -71,6 +71,7 @@
     <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>
 
+    <string name="explain_stars_text">In dieser Version wird das Konzept der Sterne eingeführt. Verdiene Sterne durch das Lösen von Rätseln. Sie können auch Sterne kaufen. Geben Sie Sterne aus, um Rätsel und andere Funktionen in der App freizuschalten.</string>
     <string name="solver_generic_error1">Löser für dieses Objekt und diese Größe noch nicht implementiert!</string>
 
     <string name="solver_cube3_error1">Es gibt nur %1$d %2$s Facelets.</string>
diff --git a/src/main/res/values-es/strings.xml b/src/main/res/values-es/strings.xml
index ccae3bd6..e9e760c3 100755
--- a/src/main/res/values-es/strings.xml
+++ b/src/main/res/values-es/strings.xml
@@ -71,6 +71,7 @@
     <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>
 
+    <string name="explain_stars_text">Esta versión introduce el concepto de estrellas. Gana estrellas resolviendo puzles. También puedes comprar estrellas. Gasta estrellas para desbloquear puzles y otras funciones de la aplicación.</string>
     <string name="solver_generic_error1">¡Aún no se implementado el solucionador para este objeto y tamaño!</string>
 
     <string name="solver_cube3_error1">Solo hay %1$d facetas %2$s.</string>
diff --git a/src/main/res/values-fr/strings.xml b/src/main/res/values-fr/strings.xml
index 8bfa97c2..d302087d 100755
--- a/src/main/res/values-fr/strings.xml
+++ b/src/main/res/values-fr/strings.xml
@@ -71,6 +71,7 @@
     <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>
 
+    <string name="explain_stars_text">Cette version introduit le concept d\'étoiles. Gagnez des étoiles en résolvant des puzzles. Vous pouvez également acheter des étoiles. Dépensez des étoiles pour débloquer des puzzles et d\'autres fonctionnalités de l\'application.</string>
     <string name="solver_generic_error1">Solutionneur pour cet objet et cette taille non encore mis en place !</string>
 
     <string name="solver_cube3_error1">Il n\'y a que %1$d facettes %2$s.</string>
diff --git a/src/main/res/values-ja/strings.xml b/src/main/res/values-ja/strings.xml
index 1a505b1a..f44deba0 100755
--- a/src/main/res/values-ja/strings.xml
+++ b/src/main/res/values-ja/strings.xml
@@ -71,6 +71,7 @@
     <string name="credits2">Pretty Patterns 沿って Walter Randelshofer. 見る <a href="http://www.randelshofer.ch">http://www.randelshofer.ch</a></string>
     <string name="credits3">ルービックキューブおよびルービックキューブは登録商標です。 私たちはそれと提携していません。</string>
 
+    <string name="explain_stars_text">このバージョンでは、星の概念が導入されています。パズルを解くとスターがもらえます。また、スターを購入することもできます。スターを消費して、アプリ内のパズルやその他の機能をアンロックします。</string>
     <string name="solver_generic_error1">このオブジェクトとサイズのソルバーはまだ実装されていません！</string>
 
     <string name="solver_cube3_error1">%2$s小顔は%1$dつだけ</string>
diff --git a/src/main/res/values-ko/strings.xml b/src/main/res/values-ko/strings.xml
index 32b5ac43..4281cab5 100755
--- a/src/main/res/values-ko/strings.xml
+++ b/src/main/res/values-ko/strings.xml
@@ -71,6 +71,7 @@
     <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>
 
+    <string name="explain_stars_text">이 버전은 별의 개념을 소개합니다. 퍼즐을 풀어 별을 획득하세요. 별을 살 수도 있습니다. 앱에서 퍼즐 및 기타 기능을 잠금 해제하려면 별을 사용하세요.</string>
     <string name="solver_generic_error1">아직 구현되지 않은 이 개체 및 크기에 대한 해결사!</string>
 
     <string name="solver_cube3_error1">%2$s작은 얼굴은  %1$d개뿐입니다.</string>
diff --git a/src/main/res/values-pl/strings.xml b/src/main/res/values-pl/strings.xml
index d174d4cc..81b5c78b 100644
--- a/src/main/res/values-pl/strings.xml
+++ b/src/main/res/values-pl/strings.xml
@@ -71,6 +71,7 @@
     <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>
 
+    <string name="explain_stars_text">Ta wersja wprowadza koncepcję gwiazdek. Zdobywaj gwiazdki, rozwiązując poziomy. Możesz także kupić gwiazdki. Wydawaj gwiazdki, aby odblokować obiekty i inne funkcje w aplikacji.</string>
     <string name="solver_generic_error1">Rozwiązywacz takiego obiektu jest jeszcze nie zaimplementowany!</string>
 
     <string name="solver_cube3_error1">Jest tylko %1$d %2$s ścian.</string>
diff --git a/src/main/res/values-ru/strings.xml b/src/main/res/values-ru/strings.xml
index 72579911..a5eabcc8 100755
--- a/src/main/res/values-ru/strings.xml
+++ b/src/main/res/values-ru/strings.xml
@@ -71,6 +71,7 @@
     <string name="credits2">Pretty Patterns по Walter Randelshofer. Смотри <a href="http://www.randelshofer.ch">http://www.randelshofer.ch</a></string>
     <string name="credits3">Рубик и Кубик Рубика являются зарегистрированными товарными знаками. Мы не связаны с этим.</string>
 
+    <string name="explain_stars_text">В этой версии введена концепция звезд. Зарабатывайте звезды, решая головоломки. Вы также можете покупать звезды. Тратьте звезды, чтобы разблокировать головоломки и другие возможности приложения.</string>
     <string name="solver_generic_error1">Решебника для этого объекта и размера еще нет!</string>
 
     <string name="solver_cube3_error1">Всего %1$d %2$s граней!</string>
diff --git a/src/main/res/values-zh-rCN/strings.xml b/src/main/res/values-zh-rCN/strings.xml
index 8e21806b..c48b4238 100644
--- a/src/main/res/values-zh-rCN/strings.xml
+++ b/src/main/res/values-zh-rCN/strings.xml
@@ -77,6 +77,7 @@
     <string name="accept">接受</string>
     <string name="decline">拒绝</string>
 
+    <string name="explain_stars_text">这个版本引入了星星的概念。通过解开谜题获得星星。你也可以购买星星。花费星星来解锁谜题和应用程序中的其他功能。</string>
     <string name="solver_generic_error1">此对象和尺寸的求解器尚未实现！</string>
 
     <string name="solver_cube3_error1">只有%1$d个%2$s小面</string>
diff --git a/src/main/res/values-zh-rTW/strings.xml b/src/main/res/values-zh-rTW/strings.xml
index 2681355a..705517f3 100644
--- a/src/main/res/values-zh-rTW/strings.xml
+++ b/src/main/res/values-zh-rTW/strings.xml
@@ -71,6 +71,7 @@
     <string name="credits2">Pretty Patterns by Werner Randelshofer. 請看 <a href="http://www.randelshofer.ch">http://www.randelshofer.ch</a></string>
     <string name="credits3">魔方和魔方是註冊商標。 我們不隸屬於它。</string>
 
+    <string name="explain_stars_text">这个版本引入了星星的概念。通过解开谜题获得星星。你也可以购买星星。花费星星来解锁谜题和应用程序中的其他功能。</string>
     <string name="solver_generic_error1">此對象和尺寸的求解器尚未實現！</string>
 
     <string name="solver_cube3_error1">只有%1$d個%2$s小臉</string>
diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml
index 12020696..22c4dac7 100644
--- a/src/main/res/values/strings.xml
+++ b/src/main/res/values/strings.xml
@@ -75,6 +75,7 @@
     <string name="credits3">Rubik and Rubik Cube are registered trademarks. We are not affiliated with it.</string>
     <string name="credits4" translatable="false">Please see our <a href="https://distorted.org/redmine/projects/magic-cube/wiki/Privacy_policy">Privacy Policy</a></string>
 
+    <string name="explain_stars_text">This version introduces the concept of stars. Earn stars by solving puzzles. You can also buy stars. Spend stars to unlock puzzles and other features in the app.</string>
     <string name="privacy_policy" translatable="false">Privacy Policy</string>
     <string name="privacy_policy_text" translatable="false">Please see and accept our <a href="https://distorted.org/redmine/projects/magic-cube/wiki/Privacy_policy">Privacy Policy</a></string>
     <string name="accept" translatable="false">Accept</string>
