commit 96e6700051db9b053f5263125abe25b628b8e269
Author: leszek <leszek@koltunski.pl>
Date:   Thu Nov 16 17:25:02 2023 +0100

    minor improvement for the Updates Dialog

diff --git a/src/main/java/org/distorted/dialogs/RubikDialogPattern.java b/src/main/java/org/distorted/dialogs/RubikDialogPattern.java
new file mode 100644
index 00000000..4eb5242d
--- /dev/null
+++ b/src/main/java/org/distorted/dialogs/RubikDialogPattern.java
@@ -0,0 +1,150 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2023 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.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.ExpandableListView;
+
+import androidx.fragment.app.FragmentActivity;
+
+import org.distorted.main.R;
+import org.distorted.objectlib.main.ObjectControl;
+import org.distorted.objectlib.patterns.RubikPattern;
+import org.distorted.objectlib.patterns.RubikPatternList;
+import org.distorted.patternui.PatternActivity;
+import org.distorted.patternui.ScreenList;
+import org.distorted.patternui.ScreenPattern;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+public class RubikDialogPattern extends RubikDialogAbstract
+  {
+  private ExpandableListView mListView;
+  private int mPatternOrdinal, mPos;
+  private int mExpandedGroup;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  @Override
+  public void onResume()
+    {
+    super.onResume();
+
+    Window window = getDialog().getWindow();
+
+    if( window!=null )
+      {
+      WindowManager.LayoutParams params = window.getAttributes();
+      params.width  = (int)Math.min( mHeight*0.65f,mWidth*0.98f );
+      //params.height = (int)Math.min( mHeight*0.80f,mWidth*1.30f );
+      window.setAttributes(params);
+      }
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getResource()      { return R.layout.dialog_pattern_single; }
+  public int getTitleResource() { return R.string.choose_pattern; }
+  public boolean hasArgument()  { return true; }
+  public int getPositive()      { return -1; }
+  public int getNegative()      { return -1; }
+  public void positiveAction()  { }
+  public void negativeAction()  { }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public void prepareBody(Dialog dialog, View view, FragmentActivity act, float size)
+    {
+    int objectOrdinal = Integer.parseInt(mArgument);
+
+    if( objectOrdinal<0 )
+      {
+      android.util.Log.e("D", "object "+mArgument+" not found");
+      return;
+      }
+
+    mPatternOrdinal = RubikPatternList.getOrdinal(objectOrdinal);
+
+    if( mPatternOrdinal<0 )
+      {
+      android.util.Log.e("D", "patterns for object "+mArgument+" not found");
+      return;
+      }
+
+    android.util.Log.e("D", "prepareBody: object "+mArgument);
+
+    final PatternActivity pact = (PatternActivity)getContext();
+    int width = pact!=null ? pact.getScreenWidthInPixels() : 100;
+    final ObjectControl control = pact!=null ? pact.getControl() : null;
+
+    RubikPattern pattern = RubikPattern.getInstance();
+    mExpandedGroup = pattern.recallExpanded(mPatternOrdinal);
+
+    mListView = view.findViewById(R.id.patternListView);
+    RubikDialogPatternListAdapter listAdapter = new RubikDialogPatternListAdapter(act,mPatternOrdinal,width);
+    mListView.setAdapter(listAdapter);
+
+    if( mExpandedGroup>=0 ) mListView.expandGroup(mExpandedGroup);
+
+    int visible = pattern.recallVisiblePos(mPatternOrdinal);
+    mListView.setSelectionFromTop(visible,0);
+
+    mListView.setOnChildClickListener(new ExpandableListView.OnChildClickListener()
+      {
+      @Override
+      public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id)
+        {
+        RubikPattern pattern = RubikPattern.getInstance();
+        int[][] moves = pattern.reInitialize(mPatternOrdinal, groupPosition, childPosition);
+        if( control!=null ) control.initializeObject(moves);
+
+        ScreenPattern state = (ScreenPattern) ScreenList.PATT.getScreenClass();
+        state.setPattern(pact, mPatternOrdinal, groupPosition, childPosition);
+
+        rememberState();
+        dismiss();
+
+        return false;
+        }
+      });
+
+    mListView.setOnGroupExpandListener(new ExpandableListView.OnGroupExpandListener()
+      {
+      @Override
+      public void onGroupExpand(int groupPosition)
+        {
+        if(mExpandedGroup!=-1 && groupPosition!=mExpandedGroup)
+          {
+          mListView.collapseGroup(mExpandedGroup);
+          }
+
+        mExpandedGroup = groupPosition;
+        }
+      });
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private void rememberState()
+    {
+    RubikPattern pattern = RubikPattern.getInstance();
+    pattern.rememberState(mPatternOrdinal,mPos,mListView.getFirstVisiblePosition(),mExpandedGroup);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public static String getDialogTag()
+    {
+    return "DialogPatternSingle";
+    }
+  }
diff --git a/src/main/java/org/distorted/dialogs/RubikDialogPatternSingle.java b/src/main/java/org/distorted/dialogs/RubikDialogPatternSingle.java
deleted file mode 100644
index e42b16c7..00000000
--- a/src/main/java/org/distorted/dialogs/RubikDialogPatternSingle.java
+++ /dev/null
@@ -1,151 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// Copyright 2023 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.view.View;
-import android.view.Window;
-import android.view.WindowManager;
-import android.widget.ExpandableListView;
-
-import androidx.fragment.app.FragmentActivity;
-
-import org.distorted.main.R;
-import org.distorted.objectlib.main.ObjectControl;
-import org.distorted.objectlib.patterns.RubikPattern;
-import org.distorted.objectlib.patterns.RubikPatternList;
-import org.distorted.objects.RubikObjectList;
-import org.distorted.patternui.PatternActivity;
-import org.distorted.patternui.ScreenList;
-import org.distorted.patternui.ScreenPattern;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-public class RubikDialogPatternSingle extends RubikDialogAbstract
-  {
-  private ExpandableListView mListView;
-  private int mPatternOrdinal, mPos;
-  private int mExpandedGroup;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  @Override
-  public void onResume()
-    {
-    super.onResume();
-
-    Window window = getDialog().getWindow();
-
-    if( window!=null )
-      {
-      WindowManager.LayoutParams params = window.getAttributes();
-      params.width  = (int)Math.min( mHeight*0.65f,mWidth*0.98f );
-      //params.height = (int)Math.min( mHeight*0.80f,mWidth*1.30f );
-      window.setAttributes(params);
-      }
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public int getResource()      { return R.layout.dialog_pattern_single; }
-  public int getTitleResource() { return R.string.choose_pattern; }
-  public boolean hasArgument()  { return true; }
-  public int getPositive()      { return -1; }
-  public int getNegative()      { return -1; }
-  public void positiveAction()  { }
-  public void negativeAction()  { }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public void prepareBody(Dialog dialog, View view, FragmentActivity act, float size)
-    {
-    int objectOrdinal = Integer.parseInt(mArgument);
-
-    if( objectOrdinal<0 )
-      {
-      android.util.Log.e("D", "object "+mArgument+" not found");
-      return;
-      }
-
-    mPatternOrdinal = RubikPatternList.getOrdinal(objectOrdinal);
-
-    if( mPatternOrdinal<0 )
-      {
-      android.util.Log.e("D", "patterns for object "+mArgument+" not found");
-      return;
-      }
-
-    android.util.Log.e("D", "prepareBody: object "+mArgument);
-
-    final PatternActivity pact = (PatternActivity)getContext();
-    int width = pact!=null ? pact.getScreenWidthInPixels() : 100;
-    final ObjectControl control = pact!=null ? pact.getControl() : null;
-
-    RubikPattern pattern = RubikPattern.getInstance();
-    mExpandedGroup = pattern.recallExpanded(mPatternOrdinal);
-
-    mListView = view.findViewById(R.id.patternListView);
-    RubikDialogPatternListAdapter listAdapter = new RubikDialogPatternListAdapter(act,mPatternOrdinal,width);
-    mListView.setAdapter(listAdapter);
-
-    if( mExpandedGroup>=0 ) mListView.expandGroup(mExpandedGroup);
-
-    int visible = pattern.recallVisiblePos(mPatternOrdinal);
-    mListView.setSelectionFromTop(visible,0);
-
-    mListView.setOnChildClickListener(new ExpandableListView.OnChildClickListener()
-      {
-      @Override
-      public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id)
-        {
-        RubikPattern pattern = RubikPattern.getInstance();
-        int[][] moves = pattern.reInitialize(mPatternOrdinal, groupPosition, childPosition);
-        if( control!=null ) control.initializeObject(moves);
-
-        ScreenPattern state = (ScreenPattern) ScreenList.PATT.getScreenClass();
-        state.setPattern(pact, mPatternOrdinal, groupPosition, childPosition);
-
-        rememberState();
-        dismiss();
-
-        return false;
-        }
-      });
-
-    mListView.setOnGroupExpandListener(new ExpandableListView.OnGroupExpandListener()
-      {
-      @Override
-      public void onGroupExpand(int groupPosition)
-        {
-        if(mExpandedGroup!=-1 && groupPosition!=mExpandedGroup)
-          {
-          mListView.collapseGroup(mExpandedGroup);
-          }
-
-        mExpandedGroup = groupPosition;
-        }
-      });
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  private void rememberState()
-    {
-    RubikPattern pattern = RubikPattern.getInstance();
-    pattern.rememberState(mPatternOrdinal,mPos,mListView.getFirstVisiblePosition(),mExpandedGroup);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public static String getDialogTag()
-    {
-    return "DialogPatternSingle";
-    }
-  }
diff --git a/src/main/java/org/distorted/dialogs/RubikDialogTutorial.java b/src/main/java/org/distorted/dialogs/RubikDialogTutorial.java
new file mode 100644
index 00000000..a681d441
--- /dev/null
+++ b/src/main/java/org/distorted/dialogs/RubikDialogTutorial.java
@@ -0,0 +1,201 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2023 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 static android.view.View.inflate;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.content.res.Resources;
+import android.util.DisplayMetrics;
+import android.util.TypedValue;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import androidx.fragment.app.FragmentActivity;
+
+import org.distorted.main.R;
+import org.distorted.objectlib.json.JsonReader;
+import org.distorted.objects.RubikObject;
+import org.distorted.objects.RubikObjectList;
+import org.distorted.tutorials.TutorialActivity;
+
+import java.io.InputStream;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+public class RubikDialogTutorial extends RubikDialogAbstract
+  {
+  public static final float PANE_HEIGHT= 0.06f;
+  public static final float TEXT_SIZE  = 0.41f;
+
+  private Dialog mDialog;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  @Override
+  public void onResume()
+    {
+    super.onResume();
+
+    Window window = getDialog().getWindow();
+
+    if( window!=null )
+      {
+      WindowManager.LayoutParams params = window.getAttributes();
+      params.width  = (int)Math.min( mHeight*0.67f,mWidth*0.98f );
+      //params.height = (int)Math.min( mHeight*0.85f,mWidth*1.30f );
+      window.setAttributes(params);
+      }
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getResource()      { return R.layout.dialog_tutorial_single; }
+  public int getTitleResource() { return R.string.tutorials; }
+  public boolean hasArgument()  { return true; }
+  public int getPositive()      { return -1; }
+  public int getNegative()      { return -1; }
+  public void positiveAction()  { }
+  public void negativeAction()  { }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public void prepareBody(Dialog dialog, View view, FragmentActivity act, float size)
+    {
+    mDialog = dialog;
+
+    int objectOrdinal = Integer.parseInt(mArgument);
+
+    if( objectOrdinal<0 )
+      {
+      android.util.Log.e("D", "object "+mArgument+" not found");
+      return;
+      }
+
+    RubikObject robject = RubikObjectList.getObject(objectOrdinal);
+    InputStream jsonStream = robject==null ? null : robject.getExtrasStream(act);
+    String[][] tutorials=null;
+
+    if( jsonStream!=null )
+      {
+      try
+        {
+        JsonReader reader = new JsonReader();
+        reader.parseJsonTutorial(jsonStream);
+        tutorials = reader.getTutorials();
+        }
+      catch(Exception ignored) { }
+      }
+
+    if( tutorials!=null )
+      {
+      int paneSize = (int)(mHeight*PANE_HEIGHT);
+      Resources res = act.getResources();
+      String packageName = act.getPackageName();
+
+      LinearLayout layout = view.findViewById(R.id.tutLayout);
+
+      int colorB = getResources().getColor(R.color.light_grey);
+      int colorT = getResources().getColor(R.color.white);
+
+      int numTuts = tutorials.length;
+
+      for( int t=0; t<numTuts; t++)
+        {
+        String[] tutorial = tutorials[t];
+
+        String coun = tutorial[0];
+        String url  = tutorial[1];
+        String desc = tutorial[2];
+        String auth = tutorial[3];
+
+        int countryID = res.getIdentifier(coun, "drawable", packageName);
+
+        View row = createRow(act, countryID, desc, url, auth, paneSize, colorB, colorT, t==(numTuts-1) );
+        layout.addView(row);
+        }
+      }
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private View createRow(final FragmentActivity act, int countryID, final String desc, final String url,
+                         final String auth, int size, int colorB, int colorT, boolean last)
+    {
+    float textSize = size*TEXT_SIZE;
+    View row = inflate( act, R.layout.dialog_tutorial_row, null);
+
+    LinearLayout layout = row.findViewById(R.id.tutorialLayout);
+    layout.setMinimumHeight(size);
+
+    Button butt = row.findViewById(R.id.tutorialButton);
+    butt.setText(R.string.view);
+    butt.setTextColor(colorT);
+    butt.setBackgroundColor(colorB);
+    butt.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
+    butt.setHeight(size);
+
+    final TutorialActivity tact = (TutorialActivity)getContext();
+
+    butt.setOnClickListener( new View.OnClickListener()
+      {
+      @Override
+      public void onClick(View v)
+        {
+        mDialog.dismiss();
+        if( tact!=null ) tact.loadTutorial(url);
+        }
+      });
+
+    ImageView image = row.findViewById(R.id.tutorialCountry);
+    int id = countryID!=0 ? countryID : org.distorted.flags.R.drawable.unknown;
+    image.setImageResource(id);
+
+    TextView author = row.findViewById(R.id.tutorialAuthor);
+    author.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
+    author.setText(auth);
+
+    TextView title  = row.findViewById(R.id.tutorialTitle);
+    title.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
+    title.setText(desc);
+
+    if( last )
+      {
+      int m = (int)convertDpToPixel(10,act);
+      LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.WRAP_CONTENT);
+      params.bottomMargin = m;
+      params.leftMargin   = m;
+      params.rightMargin  = m;
+      layout.setLayoutParams(params);
+      }
+
+    return row;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private static float convertDpToPixel(float dp, Context context)
+    {
+    return dp*((float) context.getResources().getDisplayMetrics().densityDpi/DisplayMetrics.DENSITY_DEFAULT);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public static String getDialogTag()
+    {
+    return "DialogTutorialSingle";
+    }
+  }
diff --git a/src/main/java/org/distorted/dialogs/RubikDialogTutorialSingle.java b/src/main/java/org/distorted/dialogs/RubikDialogTutorialSingle.java
deleted file mode 100644
index 069eab38..00000000
--- a/src/main/java/org/distorted/dialogs/RubikDialogTutorialSingle.java
+++ /dev/null
@@ -1,201 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// Copyright 2023 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 static android.view.View.inflate;
-
-import android.app.Dialog;
-import android.content.Context;
-import android.content.res.Resources;
-import android.util.DisplayMetrics;
-import android.util.TypedValue;
-import android.view.View;
-import android.view.Window;
-import android.view.WindowManager;
-import android.widget.Button;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import androidx.fragment.app.FragmentActivity;
-
-import org.distorted.main.R;
-import org.distorted.objectlib.json.JsonReader;
-import org.distorted.objects.RubikObject;
-import org.distorted.objects.RubikObjectList;
-import org.distorted.tutorials.TutorialActivity;
-
-import java.io.InputStream;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-public class RubikDialogTutorialSingle extends RubikDialogAbstract
-  {
-  public static final float PANE_HEIGHT= 0.06f;
-  public static final float TEXT_SIZE  = 0.41f;
-
-  private Dialog mDialog;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  @Override
-  public void onResume()
-    {
-    super.onResume();
-
-    Window window = getDialog().getWindow();
-
-    if( window!=null )
-      {
-      WindowManager.LayoutParams params = window.getAttributes();
-      params.width  = (int)Math.min( mHeight*0.67f,mWidth*0.98f );
-      //params.height = (int)Math.min( mHeight*0.85f,mWidth*1.30f );
-      window.setAttributes(params);
-      }
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public int getResource()      { return R.layout.dialog_tutorial_single; }
-  public int getTitleResource() { return R.string.tutorials; }
-  public boolean hasArgument()  { return true; }
-  public int getPositive()      { return -1; }
-  public int getNegative()      { return -1; }
-  public void positiveAction()  { }
-  public void negativeAction()  { }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public void prepareBody(Dialog dialog, View view, FragmentActivity act, float size)
-    {
-    mDialog = dialog;
-
-    int objectOrdinal = Integer.parseInt(mArgument);
-
-    if( objectOrdinal<0 )
-      {
-      android.util.Log.e("D", "object "+mArgument+" not found");
-      return;
-      }
-
-    RubikObject robject = RubikObjectList.getObject(objectOrdinal);
-    InputStream jsonStream = robject==null ? null : robject.getExtrasStream(act);
-    String[][] tutorials=null;
-
-    if( jsonStream!=null )
-      {
-      try
-        {
-        JsonReader reader = new JsonReader();
-        reader.parseJsonTutorial(jsonStream);
-        tutorials = reader.getTutorials();
-        }
-      catch(Exception ignored) { }
-      }
-
-    if( tutorials!=null )
-      {
-      int paneSize = (int)(mHeight*PANE_HEIGHT);
-      Resources res = act.getResources();
-      String packageName = act.getPackageName();
-
-      LinearLayout layout = view.findViewById(R.id.tutLayout);
-
-      int colorB = getResources().getColor(R.color.light_grey);
-      int colorT = getResources().getColor(R.color.white);
-
-      int numTuts = tutorials.length;
-
-      for( int t=0; t<numTuts; t++)
-        {
-        String[] tutorial = tutorials[t];
-
-        String coun = tutorial[0];
-        String url  = tutorial[1];
-        String desc = tutorial[2];
-        String auth = tutorial[3];
-
-        int countryID = res.getIdentifier(coun, "drawable", packageName);
-
-        View row = createRow(act, countryID, desc, url, auth, paneSize, colorB, colorT, t==(numTuts-1) );
-        layout.addView(row);
-        }
-      }
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  private View createRow(final FragmentActivity act, int countryID, final String desc, final String url,
-                         final String auth, int size, int colorB, int colorT, boolean last)
-    {
-    float textSize = size*TEXT_SIZE;
-    View row = inflate( act, R.layout.dialog_tutorial_row, null);
-
-    LinearLayout layout = row.findViewById(R.id.tutorialLayout);
-    layout.setMinimumHeight(size);
-
-    Button butt = row.findViewById(R.id.tutorialButton);
-    butt.setText(R.string.view);
-    butt.setTextColor(colorT);
-    butt.setBackgroundColor(colorB);
-    butt.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
-    butt.setHeight(size);
-
-    final TutorialActivity tact = (TutorialActivity)getContext();
-
-    butt.setOnClickListener( new View.OnClickListener()
-      {
-      @Override
-      public void onClick(View v)
-        {
-        mDialog.dismiss();
-        if( tact!=null ) tact.loadTutorial(url);
-        }
-      });
-
-    ImageView image = row.findViewById(R.id.tutorialCountry);
-    int id = countryID!=0 ? countryID : org.distorted.flags.R.drawable.unknown;
-    image.setImageResource(id);
-
-    TextView author = row.findViewById(R.id.tutorialAuthor);
-    author.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
-    author.setText(auth);
-
-    TextView title  = row.findViewById(R.id.tutorialTitle);
-    title.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
-    title.setText(desc);
-
-    if( last )
-      {
-      int m = (int)convertDpToPixel(10,act);
-      LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.WRAP_CONTENT);
-      params.bottomMargin = m;
-      params.leftMargin   = m;
-      params.rightMargin  = m;
-      layout.setLayoutParams(params);
-      }
-
-    return row;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  private static float convertDpToPixel(float dp, Context context)
-    {
-    return dp*((float) context.getResources().getDisplayMetrics().densityDpi/DisplayMetrics.DENSITY_DEFAULT);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public static String getDialogTag()
-    {
-    return "DialogTutorialSingle";
-    }
-  }
diff --git a/src/main/java/org/distorted/dialogs/RubikDialogUpdates.java b/src/main/java/org/distorted/dialogs/RubikDialogUpdates.java
index 5705d220..eb56604e 100644
--- a/src/main/java/org/distorted/dialogs/RubikDialogUpdates.java
+++ b/src/main/java/org/distorted/dialogs/RubikDialogUpdates.java
@@ -119,7 +119,7 @@ public class RubikDialogUpdates extends RubikDialogAbstract implements RubikNetw
           {
           RubikUpdates.UpdateInfo info = updates.getCompletedUpdate(i);
           RubikDialogUpdateView rubikView = new RubikDialogUpdateView();
-          View pane = rubikView.createView(act,info,mFontSize,mPadding,pV,pT,pB);
+          View pane = rubikView.createView(act,info,mFontSize,mPadding,( (numS==0 && i==numC-1)?pL:pV),pT,pB);
           mLayout.addView(pane);
           mPanes.add(rubikView);
           }
diff --git a/src/main/java/org/distorted/patternui/ScreenPattern.java b/src/main/java/org/distorted/patternui/ScreenPattern.java
index 682902e3..4d47e6c2 100644
--- a/src/main/java/org/distorted/patternui/ScreenPattern.java
+++ b/src/main/java/org/distorted/patternui/ScreenPattern.java
@@ -17,13 +17,12 @@ import android.view.View;
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
-import org.distorted.dialogs.RubikDialogPatternSingle;
+import org.distorted.dialogs.RubikDialogPattern;
 import org.distorted.helpers.TransparentButton;
 import org.distorted.helpers.TransparentImageButton;
 import org.distorted.main.R;
 import org.distorted.objectlib.main.ObjectControl;
 import org.distorted.objectlib.patterns.RubikPattern;
-import org.distorted.objects.RubikObjectList;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
@@ -128,9 +127,9 @@ public class ScreenPattern extends ScreenAbstract
     int ordinal = act.getObjectOrdinal();
     Bundle bundle = new Bundle();
     bundle.putString("argument", String.valueOf(ordinal) );
-    RubikDialogPatternSingle diag = new RubikDialogPatternSingle();
+    RubikDialogPattern diag = new RubikDialogPattern();
     diag.setArguments(bundle);
-    diag.show( act.getSupportFragmentManager(), RubikDialogPatternSingle.getDialogTag() );
+    diag.show( act.getSupportFragmentManager(), RubikDialogPattern.getDialogTag() );
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/main/java/org/distorted/tutorials/TutorialActivity.java b/src/main/java/org/distorted/tutorials/TutorialActivity.java
index f3c21a2a..ba71ffa4 100644
--- a/src/main/java/org/distorted/tutorials/TutorialActivity.java
+++ b/src/main/java/org/distorted/tutorials/TutorialActivity.java
@@ -22,7 +22,7 @@ import android.widget.LinearLayout;
 
 import androidx.appcompat.app.AppCompatActivity;
 
-import org.distorted.dialogs.RubikDialogTutorialSingle;
+import org.distorted.dialogs.RubikDialogTutorial;
 import org.distorted.library.main.DistortedLibrary;
 
 import org.distorted.main.MainActivity;
@@ -89,9 +89,9 @@ public class TutorialActivity extends AppCompatActivity
       {
       Bundle bundle = new Bundle();
       bundle.putString("argument", String.valueOf(mObjectOrdinal) );
-      RubikDialogTutorialSingle diag = new RubikDialogTutorialSingle();
+      RubikDialogTutorial diag = new RubikDialogTutorial();
       diag.setArguments(bundle);
-      diag.show( getSupportFragmentManager(), RubikDialogTutorialSingle.getDialogTag() );
+      diag.show( getSupportFragmentManager(), RubikDialogTutorial.getDialogTag() );
       }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
