commit 1f6d1786db4edc86f4cc382084f98c0469d37042
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Mon Jul 18 23:08:29 2022 +0200

    Lots of progress with the main screen

diff --git a/distorted-sokoban/src/main/java/org/distorted/sokoban/SokobanActivity.java b/distorted-sokoban/src/main/java/org/distorted/sokoban/SokobanActivity.java
index 9611dba..0690ab9 100644
--- a/distorted-sokoban/src/main/java/org/distorted/sokoban/SokobanActivity.java
+++ b/distorted-sokoban/src/main/java/org/distorted/sokoban/SokobanActivity.java
@@ -28,18 +28,28 @@ import android.view.DisplayCutout;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.WindowManager;
+import android.widget.AdapterView;
 import android.widget.LinearLayout;
+import android.widget.SimpleAdapter;
 import android.widget.TextView;
 
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
 import helpers.TransparentImageButton;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
 public class SokobanActivity extends ListActivity
   {
-  private static final String ITEM_IMAGE    = "item_image";
-  private static final String ITEM_TITLE    = "item_title";
-  private static final String ITEM_SUBTITLE = "item_subtitle"; 
+  private static final String L_NUMBER = "lNumber";
+  private static final String L_RECORD = "lRecord";
+  private static final String L_IMAGE  = "lImage";
+  private static final String R_NUMBER = "rNumber";
+  private static final String R_RECORD = "rRecord";
+  private static final String R_IMAGE  = "rImage";
 
   private static final float RATIO_BAR    = 0.10f;
   private static final float RATIO_INSET  = 0.09f;
@@ -78,46 +88,6 @@ public class SokobanActivity extends ListActivity
 
     LinearLayout upper = findViewById(R.id.upper_layout);
     createUpperLayout(upper);
-
-/*
-    final List<Map<String, Object>> data = new ArrayList<>();
-    final SparseArray<Class<? extends Activity>> activityMapping = new SparseArray<>();
-
-    int index=0;
-
-    for( Application app : Application.values() )
-      {
-      final Map<String, Object> item = new HashMap<>();
-      item.put(ITEM_IMAGE, app.icon);
-      item.put(ITEM_TITLE, (index+1)+". "+getText(app.title));
-      item.put(ITEM_SUBTITLE, getText(app.subtitle));
-      data.add(item);
-      activityMapping.put(index++, app.activity);
-      }
-
-    final SimpleAdapter dataAdapter = new SimpleAdapter( this,
-                                                         data,
-                                                         R.layout.toc_item,
-                                                         new String[] {ITEM_IMAGE, ITEM_TITLE, ITEM_SUBTITLE},
-                                                         new int[] {R.id.Image, R.id.Title, R.id.SubTitle}  );
-    setListAdapter(dataAdapter);
-      
-    getListView().setOnItemClickListener(new OnItemClickListener()
-      {
-      @Override
-      public void onItemClick(AdapterView<?> parent, View view, int position, long id)
-        {
-        final Class<? extends Activity> activityToLaunch = activityMapping.get(position);
-            
-        if (activityToLaunch != null)
-          {
-          final Intent launchIntent = new Intent(SokobanActivity.this, activityToLaunch);
-          startActivity(launchIntent);
-          }
-        }
-      });
-
- */
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -152,6 +122,23 @@ public class SokobanActivity extends ListActivity
       }
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  @Override
+  public void onResume()
+    {
+    super.onResume();
+    createListOfLevels();
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  @Override
+  public void onPause()
+    {
+    super.onPause();
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   private void createUpperLayout(LinearLayout upper)
@@ -305,4 +292,42 @@ public class SokobanActivity extends ListActivity
       default: return huge;
       }
     }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private void createListOfLevels()
+    {
+    /*
+    final List<Map<String, Object>> data = new ArrayList<>();
+
+    int index=0;
+
+    for( Application app : Application.values() )
+      {
+      final Map<String, Object> item = new HashMap<>();
+      item.put(ITEM_IMAGE, app.icon);
+      item.put(ITEM_TITLE, (index+1)+". "+getText(app.title));
+      item.put(ITEM_SUBTITLE, getText(app.subtitle));
+      data.add(item);
+      }
+
+    final SimpleAdapter dataAdapter = new SimpleAdapter( this,
+                                                         data,
+                                                         R.layout.toc_item,
+                                                         new String[] {L_NUMBER, L_RECORD, L_IMAGE, R_NUMBER, R_RECORD, R_IMAGE},
+                                                         new int[] {R.id.leftNumber , R.id.leftRecord , R.id.leftImage ,
+                                                                    R.id.rightNumber, R.id.rightRecord, R.id.rightImage,}  );
+    setListAdapter(dataAdapter);
+
+    getListView().setOnItemClickListener(new AdapterView.OnItemClickListener()
+      {
+      @Override
+      public void onItemClick(AdapterView<?> parent, View view, int position, long id)
+        {
+        android.util.Log.e("D","id="+id+" position="+position+" clicked!!");
+        }
+      });
+
+     */
+    }
   }
diff --git a/distorted-sokoban/src/main/java/org/distorted/sokoban/SokobanDatabase.java b/distorted-sokoban/src/main/java/org/distorted/sokoban/SokobanDatabase.java
index 252e2f8..f1c0ac3 100644
--- a/distorted-sokoban/src/main/java/org/distorted/sokoban/SokobanDatabase.java
+++ b/distorted-sokoban/src/main/java/org/distorted/sokoban/SokobanDatabase.java
@@ -14,25 +14,21 @@ import java.util.Map;
 public class SokobanDatabase 
 { 
 	private static final String TAG_DB = "SokobanDatabase";
-	private static final String PREFS_NAME = "sokobanPrefsFile";	
-	
+	private static final String PREFS_NAME = "sokobanPrefsFile";
 	public static final int BEGIN_LEVELS = 1000;
 	public static final int INVALID = 1000000;
 
-	private static int numrunnings;
-	private static int numplayings;
-	private static int hash;
-	private static String username;
-	private static String veriname;
-	private static int uniqueid;
-	private static int scrollpos;
-	private static boolean finishedBootup = false;
-	private static String iso = null;
-	 
-	private static SokobanLevels mLevels;
-	private static SokobanDatabase mThis =null;
+  private static SokobanDatabase mThis =null;
+
+	private int mNumRunnings;
+	private int mNumPlayings;
+	private String mUsername;
+	private String mVeriname;
+	private int mUniqueid;
+	private int mScrollpos;
+	private final boolean mFinishedBootup;
+	private String mISO = null;
 	private final WeakReference<Context> mContext;
-	
 
 	private static final String[] bl = new String[]
 	  {
@@ -633,23 +629,21 @@ public class SokobanDatabase
 	{
 	    mContext = new WeakReference<>(co);
 	    
-	    mLevels = SokobanLevels.getInstance();
-	    numrunnings = 0;
-	    numplayings = 0;
-	    uniqueid    = 0;
-	    username    ="";
-	    veriname    ="";
-	    scrollpos   = 0;
+	    SokobanLevels levels = SokobanLevels.getInstance();
+	    mNumRunnings = 0;
+	    mNumPlayings = 0;
+	    mUniqueid    = 0;
+	    mUsername    ="";
+	    mVeriname    ="";
+	    mScrollpos   = 0;
 	    
 	    for(int i=0; i<BUILTIN_LEVELS; i++)
 	      {
 	      int xlen = Integer.parseInt(bl[2*i]);
 	      SokobanLevel sl = new SokobanLevel( null, null, INVALID, INVALID, null, false,xlen, bl[2*i+1]);
-	      mLevels.addLevel(sl,i);
+	      levels.addLevel(sl,i);
 	      }
 
-	    hash = computeHash();
-	    
 	    try
 		  {
 		  SharedPreferences settings = co.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
@@ -660,31 +654,14 @@ public class SokobanDatabase
 		  Log.e( TAG_DB, "Failed to retrieve preferences: "+ex.toString());
 		  }
 	    
-	    if( veriname==null ) veriname="";
-	    if( username==null ) username="";  
-	    if( uniqueid==0 ) uniqueid = getDeviceID();
-
-	    mLevels.setScroll(scrollpos);
-	    mLevels.updateMyRecords(username);
+	    if( mVeriname==null ) mVeriname="";
+	    if( mUsername==null ) mUsername="";
+	    if( mUniqueid==0 ) mUniqueid = getDeviceID();
 
-	    if( numrunnings==0 ) SokobanCanvas.setState(SokobanCanvas.STATE_HELP);
+	    levels.setScroll(mScrollpos);
+	    levels.updateMyRecords(mUsername);
 
-	    if( hash != computeHash() )  // someone has been messing with RMS !
-	      {
-	    Log.e(TAG_DB, "messing in DB");	
-	    	
-	      SokobanLevel sl;
-	      veriname = "";
-
-	      for(int i=0; ; i++)
-	        {
-	        sl = SokobanLevels.getLevel(i);
-	        if( sl==null ) break;
-	        sl.resetPrivate();
-	        }
-	      }
-
-	    finishedBootup = true;
+	    mFinishedBootup = true;
 	    SokobanCanvas.setRepaint();
 	}
 
@@ -705,305 +682,27 @@ public class SokobanDatabase
             
             	try
             	{
-            		num = Integer.valueOf(key).intValue();
+            		num = Integer.parseInt(key);
             		sett= String.valueOf(val);
             		
             		switch(num)
             		{
-            		case 1 : username    = sett; break;
-            		case 2 : veriname    = sett; break;
-            		case 3 : hash        = Integer.valueOf(sett).intValue(); break;
-            		case 4 : numrunnings = Integer.valueOf(sett).intValue(); break;
-            		case 5 : numplayings = Integer.valueOf(sett).intValue(); break;
-            		case 6 : uniqueid    = Integer.valueOf(sett).intValue(); break;
-            		case 7 : scrollpos   = Integer.valueOf(sett).intValue(); break;
-            		default: recoverLevel(num,sett); break;
+            		case 1 : mUsername    = sett; break;
+            		case 2 : mVeriname    = sett; break;
+            		case 3 : mNumRunnings = Integer.parseInt(sett); break;
+            		case 4 : mNumPlayings = Integer.parseInt(sett); break;
+            		case 5 : mUniqueid    = Integer.parseInt(sett); break;
+            		case 6 : mScrollpos   = Integer.parseInt(sett); break;
             		}
             	}
             	catch( Exception ex )
             	{
-            		Log.e(TAG_DB, "error retrieving preference "+String.valueOf(val)+" :"+ex.toString());
+            		Log.e(TAG_DB, "error retrieving preference "+val+" :"+ex.toString());
             	}                     	     
             }   
         }
 	}
 
-///////////////////////////////////////////////////////////////////
-	  
-	private void recoverLevel(int id, String value)
-	{
-		int begin=0,end=0,lvlNum;
-		String tmp;
-
-		//Log.d(TAG_DB, "recovering level "+id+" :"+value);
-		
-		end = value.indexOf(" ", begin+1);
-
-		if( end<0 )
-		{
-			Log.e(TAG_DB, "error recovering level! value: "+value);
-			return;
-		}
-
-		tmp = value.substring(begin,end);
-		lvlNum = Integer.valueOf(tmp).intValue();
-		
-		recoverLevelData(id,lvlNum,end,value);
-	}
-
-///////////////////////////////////////////////////////////////////
-
-	private void recoverLevelData(int id, int num, int begin, String value)
-	{
-		int end;
-		String tmp;
-		SokobanLevel sl;
-		int intrinsic   = INVALID;
-		int mytime      = INVALID;
-		int mymoves     = INVALID;
-		int worldtime   = INVALID;
-		int worldmoves  = INVALID;
-		String worldname   = "";
-		String worldcountry= "";
-		boolean submitted  = false;
-
-		// recover intrinsic num
-		end = value.indexOf(" ", begin+1);
-
-		if( end<0 )
-		{
-			Log.e(TAG_DB, "1 error recovering builtin level, value: "+value);
-			return;
-		}
-
-		try
-		{
-			tmp = value.substring( begin+1,end);
-			intrinsic = Integer.valueOf(tmp).intValue();
-		}
-		catch(Exception ex1 ) {Log.e(TAG_DB, "1: "+ex1.toString()); }
-
-		begin = end;
-
-		// recover mytime
-		end = value.indexOf(" ", begin+1);
-
-		if( end<0 )
-		{
-			Log.e(TAG_DB, "1 error recovering builtin level, value: "+value);
-			return;
-		}
-
-		try
-		{
-			tmp = value.substring( begin+1,end);
-			mytime = Integer.valueOf(tmp).intValue();
-		}
-		catch(Exception ex1 ) {Log.e(TAG_DB, "1: "+ex1.toString()); }
-
-		begin = end;
-
-		// recover mymoves
-		end = value.indexOf(" ", begin+1);
-
-		if( end<0 )
-		{
-			Log.e(TAG_DB, "2 error recovering builtin level, value: "+value);
-			return;
-		}
-
-		try
-		{
-			tmp = value.substring( begin+1,end);
-			mymoves = Integer.valueOf(tmp).intValue();
-		}
-		catch(Exception ex1 ) {Log.e(TAG_DB, "2: "+ex1.toString()); }
-
-		begin = end;
-
-		// recover worldtime
-		end = value.indexOf(" ", begin+1);
-
-		if( end<0 )
-		{
-			Log.e(TAG_DB, "3 error recovering builtin level, value: "+value);
-			return;
-		}
-
-		try
-		{
-			tmp = value.substring( begin+1,end);
-			worldtime = Integer.valueOf(tmp).intValue();
-		}
-		catch(Exception ex1 ) {Log.e(TAG_DB, "3: "+ex1.toString()); }
-
-		begin = end;
-
-		// recover worldmoves
-		end = value.indexOf(" ", begin+1);
-
-		if( end<0 )
-		{
-			Log.e(TAG_DB, "4 error recovering builtin level, value: "+value);
-			return;
-		}
-
-		try
-		{
-			tmp = value.substring( begin+1,end);
-			worldmoves = Integer.valueOf(tmp).intValue();
-		}
-		catch(Exception ex1 ) {Log.e(TAG_DB, "4: "+ex1.toString()); }
-
-		begin = end;
-
-		// 	recover worldname
-		end = value.indexOf(" ", begin+1);
-
-		if( end<0 )
-		{
-			Log.e(TAG_DB, "5 error recovering builtin level, value: "+value);
-			return;
-		}
-
-		try
-		{
-			worldname = value.substring( begin+1,end);
-		}
-		catch(Exception ex1 ) {Log.e(TAG_DB, "5: "+ex1.toString()); }
-
-		begin = end;
-
-		// recover worldcountry
-		end = value.indexOf(" ", begin+1);
-
-		if( end<0 )
-		{
-			Log.e(TAG_DB, "6 error recovering builtin level, value: "+value);
-			return;
-		}
-
-		try
-		{
-			worldcountry = value.substring( begin+1,end);
-		}
-		catch(Exception ex1 ) {Log.e(TAG_DB,"6: "+ex1.toString()); }
-
-		begin = end;
-
-		// recover submitted
-		end = value.indexOf(" ", begin+1);
-
-		if( end<0 )
-		{
-			Log.e(TAG_DB, "7 error recovering builtin level, value: "+value);
-			return;
-		}
-
-		try
-		{
-			tmp = value.substring( begin+1,end);
-			submitted = (Integer.valueOf(tmp).intValue()==1 ? true:false);
-		}
-		catch(Exception ex1 ) {Log.e(TAG_DB, "7: "+ex1.toString()); }
-
-		begin = end;
-
-		if( num<BUILTIN_LEVELS )
-		{
-			sl = SokobanLevels.getLevel(num);
-
-			if( sl==null ) { Log.e(TAG_DB, "Error recovering builtin level "+num); return; }
-
-		//	Log.d(TAG_DB, "setting my info: "+mymoves+" "+mytime+" "+username+" "+getCountry() );
-			
-			sl.setMyInfo(mymoves,mytime, username, getCountry() );
-			sl.addRecordInfo(worldmoves,worldtime,0,worldname,worldcountry);
-			sl.setSubmitted(submitted);
-			sl.setRecordId(id);
-		}
-		else
-		{
-			String author="", coun="", position="";
-			int cols=0;
-
-			// recover author
-			end = value.indexOf(" ", begin+1);
-
-			if( end<0 )
-			{
-				Log.e(TAG_DB, "8 error recovering builtin level, value: "+value);
-				return;
-			}
-
-			try
-			{
-				author = value.substring( begin+1,end);
-			}
-			catch(Exception ex1 ) {Log.e(TAG_DB, "8: "+ex1.toString()); }
-
-			begin = end;
-
-			// recover country
-			end = value.indexOf(" ", begin+1);
-
-			if( end<0 )
-			{
-				Log.e(TAG_DB, "9 error recovering builtin level, value: "+value);
-				return;
-			}
-
-			try
-			{
-				coun = value.substring( begin+1,end);
-			}
-			catch(Exception ex1 ) {Log.e(TAG_DB, "9: "+ex1.toString()); }
-
-			begin = end;
-
-			// recover cols
-			end = value.indexOf(" ", begin+1);
-
-			if( end<0 )
-			{
-				Log.e(TAG_DB, "10 error recovering builtin level, value: "+value);
-				return;
-			}
-
-			try
-			{
-				tmp = value.substring( begin+1,end);
-				cols = Integer.valueOf(tmp).intValue();
-			}
-			catch(Exception ex1 ) {Log.e(TAG_DB, "10: "+ex1.toString()); }
-
-			begin = end;
-
-			// recover position
-			end = value.indexOf(" ", begin+1);
-
-			if( end<0 )
-			{
-				Log.e(TAG_DB, "11 error recovering builtin level, value: "+value);
-				return;
-			}
-
-			try
-			{
-				position = value.substring( begin+1,end);
-			}
-			catch(Exception ex1 ) {Log.e(TAG_DB, "11: "+ex1.toString()); }
-
-			begin = end;
-
-	//		Log.d(TAG_DB, "loading created level: "+author+" "+coun+" "+mymoves+" "+mytime);
-			
-			SokobanRecordInfo sri = new SokobanRecordInfo(worldmoves,worldtime,worldname,worldcountry);
-			sl = new SokobanLevel(author,coun,mymoves,mytime,sri,submitted,cols,position);
-			mLevels.insertLevel(sl,num,intrinsic,id);
-		}	
-}
-
 ///////////////////////////////////////////////////////////////////
 	
 	private int getDeviceID()
@@ -1029,33 +728,25 @@ public class SokobanDatabase
 	
 	public boolean saveValues()
 	    {
-		//Log.e(TAG_DB, "saveValues: "+finishedBootup);
-		
-	    if( !finishedBootup ) return false;
+	    if( !mFinishedBootup ) return false;
 
 	    boolean ret = false;
 	   
-	    numrunnings++;
-	    hash = computeHash();
-	    scrollpos = SokobanLevels.getScroll();
+	    mNumRunnings++;
+	    mScrollpos = SokobanLevels.getScroll();
 	    
 	    try
 	      {
-	        Context co = mContext.get();
-          SharedPreferences settings = co.getSharedPreferences(PREFS_NAME,Context.MODE_PRIVATE);
-          SharedPreferences.Editor editor = settings.edit();
+	      Context co = mContext.get();
+        SharedPreferences settings = co.getSharedPreferences(PREFS_NAME,Context.MODE_PRIVATE);
+        SharedPreferences.Editor editor = settings.edit();
 	      
-          editor.putString("1", username);
-          editor.putString("2", veriname);
-          editor.putInt("3", hash);
-          editor.putInt("4", numrunnings);
-          editor.putInt("5", numplayings);
-          editor.putInt("6", uniqueid);
-          editor.putInt("7", scrollpos);
-        
-         // Log.d(TAG_DB, "saving: username="+username+" veriname="+veriname+" hash="+hash+" numrunnings="+numrunnings+" numplayings="+numplayings+" uniqueid="+uniqueid+" scrollpos="+scrollpos);
-  		
-	      if( saveLevels(editor)==false ) return false;
+        editor.putString("1", mUsername);
+        editor.putString("2", mVeriname);
+        editor.putInt("3"   , mNumRunnings);
+        editor.putInt("4"   , mNumPlayings);
+        editor.putInt("5"   , mUniqueid);
+        editor.putInt("6"   , mScrollpos);
 
 	      editor.commit();
 	      ret = true;
@@ -1067,49 +758,7 @@ public class SokobanDatabase
 
 	    return ret;
 	    }
- 
-///////////////////////////////////////////////////////////////////
-
-	private static boolean saveLevels(SharedPreferences.Editor editor)
-	{
-		String tmp;
-		int sb;
-		SokobanLevel level;
-		SokobanRecordInfo wr;
-
-		for(int i=0; ; i++)
-		{
-			level = SokobanLevels.getLevel(i);
-			if( level==null ) break;
 
-			if( level.isDirty() )
-			{
-				wr = level.getRecordInfo(0);
-				sb = level.isSubmitted()==true?1:0;
-
-				if( wr!=null )
-					tmp = i+" "+level.getIntrinsicNum()+" "+level.getMyTime()+" "+
-						  level.getMyMoves()+" "+wr.getTime()+" "+wr.getMove()+" "+
-						  wr.getName()+" "+wr.getCountry()+" "+sb+" ";
-				else
-					tmp = i+" "+level.getIntrinsicNum()+" "+level.getMyTime()+" "+
-						  level.getMyMoves()+" "+INVALID+" "+INVALID+" unk unk "+sb+" ";
-
-				if( i>=BUILTIN_LEVELS )
-				{
-					tmp+=level.getAuthor()+" "+level.getCountry()+" "+level.getCols()+" "+level.encodeLevel()+" ";
-				}
-
-				editor.putString(String.valueOf(level.getRecordId()), tmp);
-				
-				//Log.d(TAG_DB, "saving level "+i+" record id:"+level.getRecordId()+": "+tmp);
-				
-			}
-		}
-
-		return true;
-	}
-	
 ///////////////////////////////////////////////////////////////////
 
 	public static void init(Activity act)
@@ -1119,84 +768,58 @@ public class SokobanDatabase
 
 ///////////////////////////////////////////////////////////////////
 
-	private static int computeHash()
-	{
-		 
-		final int MODULO = 227;
-		int ret = 0;
-		SokobanLevel sl;
-
-		for(int i=0; ; i++)
-		   {
-		   sl = SokobanLevels.getLevel(i);
-		   if( sl==null ) break;
-
-		   ret +=   sl.getMyMoves();
-		   ret += 2*sl.getMyTime();
-		   }
-
-		int length = veriname==null ? 0 : veriname.length();
-
-		for(int i=0;i<length;i++)
-		   ret += i*veriname.charAt(i);
-
-		return (ret%=MODULO);
-	}
-	
-///////////////////////////////////////////////////////////////////
-
-	public static int getNumRunnings()
+	public int getNumRunnings()
 	{
-		return numrunnings;
+		return mNumRunnings;
 	}
 
 ///////////////////////////////////////////////////////////////////
 
-	public static int getId()
+	public int getId()
 	{
-	    return uniqueid;
+	    return mUniqueid;
 	}
 
 ///////////////////////////////////////////////////////////////////
 	
-	public static int getNumPlayings()
+	public int getNumPlayings()
 	{
-		return numplayings;
+		return mNumPlayings;
 	}
 
 ///////////////////////////////////////////////////////////////////
 
-	public static void incNumPlayings()
+	public void incNumPlayings()
 	{
-		numplayings++;
+		mNumPlayings++;
 	}
 
 ///////////////////////////////////////////////////////////////////
 	
-	public static void setName(String newname)
+	public void setName(String newname)
 	{
-		username = newname;
+		mUsername = newname;
 	}
 
 ///////////////////////////////////////////////////////////////////
 	
-	public static String getName()
+	public String getName()
 	{
-		return username;
+		return mUsername;
 	}
 
 ///////////////////////////////////////////////////////////////////
 
-	public static void setVeri(String newveri)
+	public void setVeri(String newveri)
 	{
-		veriname = newveri;
+		mVeriname = newveri;
 	}
 
 ///////////////////////////////////////////////////////////////////
 
-	public static String getVeri()
+	public String getVeri()
 	{
-		return veriname;
+		return mVeriname;
 	}
 
 ///////////////////////////////////////////////////////////////////
@@ -1208,16 +831,23 @@ public class SokobanDatabase
 
 ///////////////////////////////////////////////////////////////////
 
-	public static String getCountry()
+  public int getNumLevels()
+		{
+		return BUILTIN_LEVELS;
+		}
+
+///////////////////////////////////////////////////////////////////
+
+	public String getCountry()
 	{
-		if( iso==null ) iso = SokobanCanvas.getIso();
+		if( mISO==null ) mISO = SokobanCanvas.getIso();
 	
 		char digit1, digit2;
 		
 		try
 		  {
-		  digit1 = iso.charAt(0);
-		  digit2 = iso.charAt(1);
+		  digit1 = mISO.charAt(0);
+		  digit2 = mISO.charAt(1);
 		  }
 		catch( Exception ex )
 		  {
diff --git a/distorted-sokoban/src/main/java/org/distorted/sokoban/SokobanLevel.java b/distorted-sokoban/src/main/java/org/distorted/sokoban/SokobanLevel.java
index a841bd3..f204bc8 100644
--- a/distorted-sokoban/src/main/java/org/distorted/sokoban/SokobanLevel.java
+++ b/distorted-sokoban/src/main/java/org/distorted/sokoban/SokobanLevel.java
@@ -70,7 +70,7 @@ public class SokobanLevel
       move  = (byte)m;
       }
     }
-  private static Vector<Move> moves = new Vector<Move>();
+  private static Vector<Move> moves = new Vector<>();
 
   private SokobanRecordInfo[] recordList;
   private SokobanRecordInfo recordMine;
@@ -109,13 +109,22 @@ public class SokobanLevel
 
       author = a;
       country= c;
-      
-      recordMine = new SokobanRecordInfo(mm,mt,SokobanDatabase.getName(),SokobanDatabase.getCountry());
+
+      SokobanDatabase db = SokobanDatabase.getInstance();
+
+      if( db!=null )
+        {
+        recordMine = new SokobanRecordInfo(mm,mt,db.getName(),db.getCountry());
+        }
+      else
+        {
+        recordMine = new SokobanRecordInfo(mm,mt,"","");
+        }
 
       cutAuthor();
 
       cImg = (author==null ? null:SokobanLevels.getInstance().getFlag(c));
-      
+
       recordList = new SokobanRecordInfo[mMaxRecords];
       for(int i=0; i<mMaxRecords; i++) recordList[i]=null;
 
@@ -145,7 +154,7 @@ public class SokobanLevel
     		  
       validateScratch = new byte[mRows][mCols]; 
       cells = new byte[mRows][mCols];
-      
+
       recordList = new SokobanRecordInfo[mMaxRecords];
       for(int i=0; i<mMaxRecords; i++) recordList[i]=null;
 
@@ -175,13 +184,13 @@ public class SokobanLevel
   private void cutAuthor()
   {
     if( author!=null )
-      {  
-      mPaint.setTextSize(SokobanRecordInfo.getFontSize());	
-    	
+      {
+      mPaint.setTextSize(SokobanRecordInfo.getFontSize());
+
       float len2 = mPaint.measureText(strAuthor);
       float len1 = mPaint.measureText(author);
       int len0 = SokobanLevels.levelInfoW-10-28;
-      
+
       if( len1+len2>len0 )
         {
         int l = author.length();
@@ -193,7 +202,7 @@ public class SokobanLevel
           len1 = mPaint.measureText(author);
           }
         }
-      }  
+      }
   }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -463,34 +472,35 @@ public class SokobanLevel
   {
      recordId = id;
   }
- 
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
- 
+
   public int getRecordId()
   {
      return recordId;
   }
- 
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
  
   public void setDirty()  
   {
      mDirty = true;
   }
- 
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
- 
+
   public boolean isDirty()
   {
      return mDirty;
   }
- 
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
- 
+
   public void resetPrivate()
-  {  
-      recordMine.set(SokobanDatabase.INVALID, SokobanDatabase.INVALID, SokobanDatabase.getName(),SokobanDatabase.getCountry());
-  }
+    {
+    SokobanDatabase db = SokobanDatabase.getInstance();
+    recordMine.set(SokobanDatabase.INVALID, SokobanDatabase.INVALID, db.getName(), db.getCountry());
+    }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
diff --git a/distorted-sokoban/src/main/java/org/distorted/sokoban/SokobanLevels.java b/distorted-sokoban/src/main/java/org/distorted/sokoban/SokobanLevels.java
index b061fc0..1ad8c17 100644
--- a/distorted-sokoban/src/main/java/org/distorted/sokoban/SokobanLevels.java
+++ b/distorted-sokoban/src/main/java/org/distorted/sokoban/SokobanLevels.java
@@ -917,7 +917,7 @@ public class SokobanLevels
       {
       if( state==SokobanCanvas.STATE_MAIN && clickedLevel>=0 && dx*dx+dy*dy<=MIN_CLICK_DIST*MIN_CLICK_DIST)
         {
-        SokobanDatabase.incNumPlayings();
+        SokobanDatabase.getInstance().incNumPlayings();
         currLevel = clickedLevel;
         currMoves = 0;
         SokobanCanvas.getMenu().enterPlayState(currLevel);
@@ -1135,7 +1135,8 @@ public class SokobanLevels
 
         if( currMoves < m || (currMoves==m && currTime<sl.getMyTime() ) )
           {
-          sl.setMyInfo(currMoves,currTime,SokobanDatabase.getName(), SokobanDatabase.getCountry());
+          SokobanDatabase db = SokobanDatabase.getInstance();
+          sl.setMyInfo(currMoves,currTime,db.getName(),db.getCountry());
           sl.setDirty();
           SokobanLevelBuffer.invalidateAllR();
           SokobanCanvas.setState(SokobanCanvas.STATE_NEWR);
diff --git a/distorted-sokoban/src/main/java/org/distorted/sokoban/SokobanMenu.java b/distorted-sokoban/src/main/java/org/distorted/sokoban/SokobanMenu.java
index 516eeb4..0d30ed8 100644
--- a/distorted-sokoban/src/main/java/org/distorted/sokoban/SokobanMenu.java
+++ b/distorted-sokoban/src/main/java/org/distorted/sokoban/SokobanMenu.java
@@ -482,7 +482,7 @@ public final class SokobanMenu implements TouchKeyboard.VirtualKeyboardListener
                                        SokobanCanvas.setState(SokobanCanvas.STATE_NAME);
                                        }
                                      break;
-      case SokobanCanvas.STATE_HELP: if( SokobanDatabase.getNumRunnings()==0 )
+      case SokobanCanvas.STATE_HELP: if( SokobanDatabase.getInstance().getNumRunnings()==0 )
                                        SokobanCanvas.setState(SokobanCanvas.STATE_MAIN);
                                      else
                                        SokobanCanvas.setState(SokobanCanvas.STATE_MENU);
@@ -680,10 +680,12 @@ public final class SokobanMenu implements TouchKeyboard.VirtualKeyboardListener
     mPaint.setColor(SokobanCanvas.COLOR_BLACK);
     mPaint.setTextSize(mFontH);
     mPaint.setTextAlign(Align.CENTER);
-    
-    c.drawText( "'"+SokobanDatabase.getName()+"'", scrWidth/2, scrHeight/2 -   mFontH/2, mPaint);
-    c.drawText( strIAT                           , scrWidth/2, scrHeight/2 +   mFontH/2, mPaint);
-    c.drawText( strTagain                        , scrWidth/2, scrHeight/2 + 3*mFontH/2, mPaint);
+
+    SokobanDatabase db = SokobanDatabase.getInstance();
+
+    c.drawText( "'"+db.getName()+"'", scrWidth/2, scrHeight/2 -   mFontH/2, mPaint);
+    c.drawText( strIAT              , scrWidth/2, scrHeight/2 +   mFontH/2, mPaint);
+    c.drawText( strTagain           , scrWidth/2, scrHeight/2 + 3*mFontH/2, mPaint);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -1228,7 +1230,9 @@ public final class SokobanMenu implements TouchKeyboard.VirtualKeyboardListener
 	  tkb.setMinSize(1);
 	  }
 
-	tkb.setText(SokobanDatabase.getName());
+
+
+	tkb.setText(SokobanDatabase.getInstance().getName());
 	mCanvas.getActivity().setContentView(tkb);
     }
 
@@ -1236,7 +1240,7 @@ public final class SokobanMenu implements TouchKeyboard.VirtualKeyboardListener
 
   public void okPressed(String text)
     { 
-    SokobanDatabase.setName(text);
+    SokobanDatabase.getInstance().setName(text);
     SokobanLevels.getInstance().updateMyRecords(text);
     mCanvas.getActivity().setContentView(mCanvas);
     SokobanCanvas.setRepaint();
diff --git a/distorted-sokoban/src/main/java/org/distorted/sokoban/SokobanRecordInfo.java b/distorted-sokoban/src/main/java/org/distorted/sokoban/SokobanRecordInfo.java
index ec33e03..2c05fb2 100644
--- a/distorted-sokoban/src/main/java/org/distorted/sokoban/SokobanRecordInfo.java
+++ b/distorted-sokoban/src/main/java/org/distorted/sokoban/SokobanRecordInfo.java
@@ -51,7 +51,9 @@ public void set(int m, int t, String n, String c)
   country = c;
   movetime = move<SokobanDatabase.INVALID ? move+"m "+time+"s" : null;
   img = SokobanLevels.getInstance().getFlag(c);
-  mine = SokobanDatabase.getName().equals(n);
+
+  SokobanDatabase db = SokobanDatabase.getInstance();
+  mine = (db!=null && db.getName().equals(n));
 
   setCut();
   }
@@ -71,7 +73,7 @@ public void set(int m, int t)
 public void set(String n)
   {
   name = n;
-  mine = SokobanDatabase.getName().equals(n);
+  mine = SokobanDatabase.getInstance().getName().equals(n);
   setCut();
   }
 
diff --git a/distorted-sokoban/src/main/java/org/distorted/sokoban/SokobanRecords.java b/distorted-sokoban/src/main/java/org/distorted/sokoban/SokobanRecords.java
index 46fddbe..2d0b780 100644
--- a/distorted-sokoban/src/main/java/org/distorted/sokoban/SokobanRecords.java
+++ b/distorted-sokoban/src/main/java/org/distorted/sokoban/SokobanRecords.java
@@ -111,7 +111,8 @@ public class SokobanRecords implements Runnable
 		try
 		  {
 		  String message="";
-		  int run = SokobanDatabase.getNumRunnings();
+		  SokobanDatabase db = SokobanDatabase.getInstance();
+		  int run = db.getNumRunnings();
 
 		  if(mode==SUBMITR)
 		    {
@@ -125,8 +126,8 @@ public class SokobanRecords implements Runnable
 		    message+=("&s="+URLencode(getSMSC()));
 		    message+=("&h="+hash);
 		    message+=("&r="+run);
-		    message+=("&p="+SokobanDatabase.getNumPlayings());
-		    message+=("&i="+SokobanDatabase.getId());
+		    message+=("&p="+db.getNumPlayings());
+		    message+=("&i="+db.getId());
 		    message+=("&e="+SokobanCanvas.mVersionStr+"a");
 		    }
 		  else if(mode==DOWNLOADR)
@@ -243,7 +244,8 @@ public class SokobanRecords implements Runnable
         switch(responseNum)
           {
           case  0: SokobanCanvas.setState(SokobanCanvas.STATE_RECO);// success
-                   SokobanDatabase.setVeri(name);
+                   SokobanDatabase db = SokobanDatabase.getInstance();
+                   db.setVeri(name);
                    submitLevelsList(lv);
                    break;
           case -2: SokobanMenu.setAction(SokobanMenu.ACTION_SUBR);
@@ -413,7 +415,8 @@ public class SokobanRecords implements Runnable
 	  public void downloadLevels()
         {   
         mode = DOWNLOADL;
-        name = SokobanDatabase.getName();
+        SokobanDatabase db = SokobanDatabase.getInstance();
+        name = db.getName();
         start();
         }
 
@@ -424,8 +427,9 @@ public class SokobanRecords implements Runnable
         if( mDirtyRecords )
           {
           mode = DOWNLOADR;
-          name = SokobanDatabase.getName();
-          veri = SokobanDatabase.getVeri();
+          SokobanDatabase db = SokobanDatabase.getInstance();
+          name = db.getName();
+          veri = db.getVeri();
           start();
           }
         }
@@ -434,9 +438,10 @@ public class SokobanRecords implements Runnable
 
 	  public boolean submitRecord(int lvl)
 	    {
-        name = SokobanDatabase.getName();
+	      SokobanDatabase db = SokobanDatabase.getInstance();
+        name = db.getName();
         if( name==null || name.length()==0 ) return false;
-        veri = SokobanDatabase.getVeri();
+        veri = db.getVeri();
         mode = SUBMITR;
         lv = lvl;
 
@@ -448,9 +453,10 @@ public class SokobanRecords implements Runnable
 
 	  public boolean submitLevel(int cols, String level)
         {
-        name = SokobanDatabase.getName();
+        SokobanDatabase db = SokobanDatabase.getInstance();
+        name = db.getName();
         if( name==null || name.length()==0 ) return false;
-        veri = SokobanDatabase.getVeri();
+        veri = db.getVeri();
         mode = SUBMITL;
         mCols = cols;
         mLevel= level;
diff --git a/distorted-sokoban/src/main/res/layout/toc_item.xml b/distorted-sokoban/src/main/res/layout/toc_item.xml
index 9e7efcd..74e8a25 100644
--- a/distorted-sokoban/src/main/res/layout/toc_item.xml
+++ b/distorted-sokoban/src/main/res/layout/toc_item.xml
@@ -3,31 +3,75 @@
 	xmlns:android="http://schemas.android.com/apk/res/android"
 	android:layout_width="match_parent"	
 	android:layout_height="wrap_content"
+	android:baselineAligned="false"
 	android:orientation="horizontal"
 	android:paddingTop="4dp"
 	android:paddingBottom="4dp">
 
-   	<ImageView
-   		android:id="@+id/Image"
-   		android:layout_width="wrap_content"
-   		android:layout_height="wrap_content"
-   		android:layout_margin="8dp"
-   		android:background="@drawable/icon_border"/>
-
    	<LinearLayout
    		android:layout_width="0dp"
  		android:layout_height="wrap_content"
  		android:layout_weight="1"
  		android:orientation="vertical"
  		android:layout_gravity="center_vertical">
-		<TextView 
-    		android:id="@+id/Title" 
-    		android:layout_width="match_parent" 
-    		android:layout_height="wrap_content"
-    		android:textStyle="bold"/>
-   		<TextView 
-    		android:id="@+id/SubTitle" 
-    		android:layout_width="wrap_content" 
-    		android:layout_height="wrap_content"/>	       
+
+ 		<LinearLayout
+	        android:layout_width="match_parent"
+	        android:layout_height="wrap_content"
+	        android:orientation="horizontal"
+	        android:paddingTop="4dp"
+	        android:paddingBottom="4dp">
+
+		    <TextView
+    		    android:id="@+id/leftNumber"
+    		    android:layout_width="match_parent"
+    		    android:layout_height="wrap_content"
+    		    android:textStyle="bold"/>
+   		    <TextView
+    		    android:id="@+id/leftRecord"
+    		    android:layout_width="wrap_content"
+    		    android:layout_height="wrap_content"/>
+    	</LinearLayout>
+
+   	    <ImageView
+   		    android:id="@+id/leftImage"
+   		    android:layout_width="wrap_content"
+   		    android:layout_height="wrap_content"
+   		    android:contentDescription="@string/level_image"
+   		    android:layout_margin="8dp"
+   		    android:background="@drawable/icon_border"/>
+	</LinearLayout>
+	<LinearLayout
+   		android:layout_width="0dp"
+ 		android:layout_height="wrap_content"
+ 		android:layout_weight="1"
+ 		android:orientation="vertical"
+ 		android:layout_gravity="center_vertical">
+
+ 		<LinearLayout
+	        android:layout_width="match_parent"
+	        android:layout_height="wrap_content"
+	        android:orientation="horizontal"
+	        android:paddingTop="4dp"
+	        android:paddingBottom="4dp">
+
+		    <TextView
+    		    android:id="@+id/rightNumber"
+    		    android:layout_width="match_parent"
+    		    android:layout_height="wrap_content"
+    		    android:textStyle="bold"/>
+   		    <TextView
+    		    android:id="@+id/rightRecord"
+    		    android:layout_width="wrap_content"
+    		    android:layout_height="wrap_content"/>
+    	</LinearLayout>
+
+   	    <ImageView
+   		    android:id="@+id/rightImage"
+   		    android:layout_width="wrap_content"
+   		    android:layout_height="wrap_content"
+   		    android:contentDescription="@string/level_image"
+   		    android:layout_margin="8dp"
+   		    android:background="@drawable/icon_border"/>
  	</LinearLayout>    
 </LinearLayout>
diff --git a/distorted-sokoban/src/main/res/values/strings.xml b/distorted-sokoban/src/main/res/values/strings.xml
index 87fb29f..eacaad1 100644
--- a/distorted-sokoban/src/main/res/values/strings.xml
+++ b/distorted-sokoban/src/main/res/values/strings.xml
@@ -66,4 +66,6 @@
     <string name="nocd">Number of crates does</string>     
     <string name="netn">not equal the number</string>     
     <string name="ods">of destination squares</string>
+
+    <string name="level_image">Level Image</string>
 </resources>
