commit 264af0add99ac8bc49df80e77785e803c6d49f24
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Fri Apr 3 22:54:28 2020 +0100

    More support for the 3x3x3 Solver.

diff --git a/src/main/java/org/distorted/uistate/RubikState.java b/src/main/java/org/distorted/uistate/RubikState.java
index 4bd475bb..914d80fb 100644
--- a/src/main/java/org/distorted/uistate/RubikState.java
+++ b/src/main/java/org/distorted/uistate/RubikState.java
@@ -26,11 +26,12 @@ import org.distorted.magic.RubikActivity;
 
 public enum RubikState
   {
-  MAIN ( null , false, new RubikStateMain()    ),
-  PLAY ( MAIN , true , new RubikStatePlay()    ),
-  SOLV ( PLAY , true , new RubikStateSolving() ),
-  PATT ( MAIN , false, new RubikStatePattern() ),
-  SVER ( MAIN , false, new RubikStateSolver()  ),
+  MAIN ( null , false, new RubikStateMain()      ),
+  PLAY ( MAIN , true , new RubikStatePlay()      ),
+  SOLV ( PLAY , true , new RubikStateSolving()   ),
+  PATT ( MAIN , false, new RubikStatePattern()   ),
+  SVER ( MAIN , false, new RubikStateSolver()    ),
+  SOLU ( SVER , false, new RubikStateSolution()  ),
   ;
 
   public static final int LENGTH = values().length;
diff --git a/src/main/java/org/distorted/uistate/RubikStateSolution.java b/src/main/java/org/distorted/uistate/RubikStateSolution.java
new file mode 100644
index 00000000..6fe64718
--- /dev/null
+++ b/src/main/java/org/distorted/uistate/RubikStateSolution.java
@@ -0,0 +1,175 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2020 Leszek Koltunski                                                               //
+//                                                                                               //
+// This file is part of Magic Cube.                                                              //
+//                                                                                               //
+// Magic Cube is free software: you can redistribute it and/or modify                            //
+// it under the terms of the GNU General Public License as published by                          //
+// the Free Software Foundation, either version 2 of the License, or                             //
+// (at your option) any later version.                                                           //
+//                                                                                               //
+// Magic Cube is distributed in the hope that it will be useful,                                 //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
+// GNU General Public License for more details.                                                  //
+//                                                                                               //
+// You should have received a copy of the GNU General Public License                             //
+// along with Magic Cube.  If not, see <http://www.gnu.org/licenses/>.                           //
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+package org.distorted.uistate;
+
+import android.content.SharedPreferences;
+import android.util.DisplayMetrics;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.Button;
+import android.widget.ImageButton;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import org.distorted.magic.R;
+import org.distorted.magic.RubikActivity;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+public class RubikStateSolution extends RubikStateAbstract
+  {
+  private Button mBackButton;
+  private ImageButton mPrevButton, mNextButton;
+  private TextView mMovesText;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  void leaveState(RubikActivity act)
+    {
+
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  void enterState(final RubikActivity act)
+    {
+    DisplayMetrics metrics = act.getResources().getDisplayMetrics();
+    final float scale = metrics.density;
+    LayoutInflater inflater = act.getLayoutInflater();
+
+    // TOP ////////////////////////////
+    LinearLayout layoutTop = act.findViewById(R.id.upperBar);
+    layoutTop.removeAllViews();
+
+    final TextView text = (TextView)inflater.inflate(R.layout.upper_text, null);
+    text.setText(R.string.solution);
+    layoutTop.addView(text);
+
+    // BOT ////////////////////////////
+    if( mPrevButton==null ) setupPrevButton(act,scale);
+    if( mNextButton==null ) setupNextButton(act,scale);
+    if( mMovesText ==null ) setupTextView(act,scale);
+
+    LinearLayout layoutLeft = act.findViewById(R.id.mainBarLeft);
+    layoutLeft.removeAllViews();
+    layoutLeft.addView(mPrevButton);
+    layoutLeft.addView(mMovesText);
+    layoutLeft.addView(mNextButton);
+
+    if( mBackButton==null ) setupBackButton(act,scale);
+
+    LinearLayout layoutRight = act.findViewById(R.id.mainBarRight);
+    layoutRight.removeAllViews();
+    layoutRight.addView(mBackButton);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private void setupPrevButton(final RubikActivity act, final float scale)
+    {
+    int padding = (int)(3*scale + 0.5f);
+    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(0,LinearLayout.LayoutParams.MATCH_PARENT,1.0f);
+    mPrevButton = new ImageButton(act);
+    mPrevButton.setLayoutParams(params);
+    mPrevButton.setPadding(padding,0,padding,0);
+    mPrevButton.setImageResource(R.drawable.left);
+
+    mPrevButton.setOnClickListener( new View.OnClickListener()
+      {
+      @Override
+      public void onClick(View v)
+        {
+
+        }
+      });
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private void setupNextButton(final RubikActivity act, final float scale)
+    {
+    int padding = (int)( 3*scale + 0.5f);
+    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(0,LinearLayout.LayoutParams.MATCH_PARENT, 1.0f);
+    mNextButton = new ImageButton(act);
+    mNextButton.setLayoutParams(params);
+    mNextButton.setPadding(padding,0,padding,0);
+    mNextButton.setImageResource(R.drawable.right);
+
+    mNextButton.setOnClickListener( new View.OnClickListener()
+      {
+      @Override
+      public void onClick(View v)
+        {
+
+        }
+      });
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private void setupTextView(final RubikActivity act, final float scale)
+    {
+    int padding = (int)( 3*scale + 0.5f);
+    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(0,LinearLayout.LayoutParams.MATCH_PARENT,2.0f);
+
+    mMovesText = new TextView(act);
+    mMovesText.setTextSize(20);
+    mMovesText.setLayoutParams(params);
+    mMovesText.setPadding(padding,0,padding,0);
+    mMovesText.setGravity(Gravity.CENTER);
+    mMovesText.setText(act.getString(R.string.mo_placeholder,0,0));
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private void setupBackButton(final RubikActivity act, final float scale)
+    {
+    int padding = (int)(3*scale + 0.5f);
+    LinearLayout.LayoutParams backParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.MATCH_PARENT);
+    mBackButton = new Button(act);
+    mBackButton.setLayoutParams(backParams);
+    mBackButton.setPadding(padding,0,padding,0);
+    mBackButton.setText(R.string.back);
+
+    mBackButton.setOnClickListener( new View.OnClickListener()
+      {
+      @Override
+      public void onClick(View v)
+        {
+        RubikState.goBack(act);
+        }
+      });
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public void savePreferences(SharedPreferences.Editor editor)
+    {
+    mBackButton = null;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public void restorePreferences(SharedPreferences preferences)
+    {
+
+    }
+  }
diff --git a/src/main/java/org/distorted/uistate/RubikStateSolver.java b/src/main/java/org/distorted/uistate/RubikStateSolver.java
index 99be3a9c..33579e0f 100644
--- a/src/main/java/org/distorted/uistate/RubikStateSolver.java
+++ b/src/main/java/org/distorted/uistate/RubikStateSolver.java
@@ -49,7 +49,7 @@ public class RubikStateSolver extends RubikStateAbstract
 
   private static Bitmap[] mBitmap;
   private ImageButton[] mColorButton;
-  private Button mBackButton;
+  private Button mBackButton, mSolveButton;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
@@ -77,6 +77,12 @@ public class RubikStateSolver extends RubikStateAbstract
     for(ImageButton button: mColorButton) layoutTop.addView(button);
 
     // BOT ////////////////////////////
+    if( mSolveButton==null ) setupSolveButton(act,scale);
+
+    LinearLayout layoutLeft = act.findViewById(R.id.mainBarLeft);
+    layoutLeft.removeAllViews();
+    layoutLeft.addView(mSolveButton);
+
     if( mBackButton==null ) setupBackButton(act,scale);
 
     LinearLayout layoutRight = act.findViewById(R.id.mainBarRight);
@@ -143,6 +149,27 @@ public class RubikStateSolver extends RubikStateAbstract
       }
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private void setupSolveButton(final RubikActivity act, final float scale)
+    {
+    int padding = (int)(3*scale + 0.5f);
+    LinearLayout.LayoutParams backParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.MATCH_PARENT);
+    mSolveButton = new Button(act);
+    mSolveButton.setLayoutParams(backParams);
+    mSolveButton.setPadding(padding,0,padding,0);
+    mSolveButton.setText(R.string.solve);
+
+    mSolveButton.setOnClickListener( new View.OnClickListener()
+      {
+      @Override
+      public void onClick(View v)
+        {
+        RubikState.switchState(act,RubikState.SOLU);
+        }
+      });
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   private void setupBackButton(final RubikActivity act, final float scale)
diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml
index eb85c632..f72ed1af 100644
--- a/src/main/res/values/strings.xml
+++ b/src/main/res/values/strings.xml
@@ -21,6 +21,7 @@
     <string name="yes">YES</string>
     <string name="no">NO</string>
     <string name="you">YOU</string>
+    <string name="solution">Solution</string>
     <string name="ready">Ready?</string>
     <string name="sizechange_effect">Size Change Effect</string>
     <string name="solve_effect">Solve Effect</string>
