diff --git a/.gitignore b/.gitignore
index a7109a5..092c281 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
.settings
+.DS_store
.gradle
.idea
bin
@@ -8,6 +9,7 @@ nbandroid
private
build
app/src/main/res/values/version.xml
+app/release
compiler/compiler.obj
compiler/compiler.exe
compiler/test/compiler.exe
diff --git a/app/build.gradle b/app/build.gradle
index f78daa0..da0f27e 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -2,12 +2,14 @@ plugins {
id 'com.android.application'
}
+apply plugin: "androidx.navigation.safeargs"
+
//
// Creates version.xml
//
task createVersionXML {
doLast {
- def versionP = 'git describe --tags --long --dirty=-x --abbrev=8'
+ def versionP = 'git describe --tags --long --dirty=-x --always --abbrev=8'
.execute()
versionP.waitFor()
def version = versionP.text.trim()
@@ -72,13 +74,29 @@ android {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
+ buildFeatures {
+ viewBinding true
+ }
}
dependencies {
+ def nav_version = "2.3.5"
implementation 'androidx.appcompat:appcompat:1.3.1'
implementation 'com.google.android.material:material:1.4.0'
+ implementation 'androidx.constraintlayout:constraintlayout:2.1.0'
testImplementation 'junit:junit:4.+'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
+
+ // Java language implementation
+ implementation "androidx.navigation:navigation-fragment:$nav_version"
+ implementation "androidx.navigation:navigation-ui:$nav_version"
+ // Feature module Support
+ implementation "androidx.navigation:navigation-dynamic-features-fragment:$nav_version"
+ // Testing Navigation
+ androidTestImplementation "androidx.navigation:navigation-testing:$nav_version"
+ // Jetpack Compose Integration
+ implementation "androidx.navigation:navigation-compose:2.4.0-alpha10"
}
+
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 7c97d1d..f1b1398 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1,31 +1,24 @@
-
-
-
+ package="org.vostan.banvor"
+ android:versionName="@string/git_version">
+
+
+
-
-
-
-
+
+
\ No newline at end of file
diff --git a/app/src/main/java/org/vostan/banvor/App.java b/app/src/main/java/org/vostan/banvor/App.java
index bc7c3b8..326e21e 100644
--- a/app/src/main/java/org/vostan/banvor/App.java
+++ b/app/src/main/java/org/vostan/banvor/App.java
@@ -4,20 +4,20 @@ import android.app.Application;
import android.content.SharedPreferences;
import android.util.Log;
+import org.vostan.banvor.game.State;
+import org.vostan.banvor.model.PuzzleContainer;
+import org.vostan.banvor.model.IPuzzleSource;
+
public class App extends Application
{
public static final String TAG = "Sokoban";
public static final String PREFS = "org.dyndns.vahagn.sokoban.prefs";
public static final int MIN_LEVEL = 1;
-
+
private static App mApp = null;
- protected PuzzleContainer pc;
- protected int current_level;
- protected int achieved_level;
- protected int max_level;
+ protected State gameState;
protected SharedPreferences prefs;
- protected SharedPreferences.Editor prefsEdit;
-
+
/*
*
*/
@@ -26,98 +26,26 @@ public class App extends Application
{
super.onCreate();
mApp = this;
- pc = new PuzzleContainer();
+
+ PuzzleContainer pc = new PuzzleContainer();
+ gameState = new State(pc);
prefs = getSharedPreferences(PREFS, MODE_PRIVATE);
- prefsEdit = prefs.edit();
- max_level = pc.getCount();
- current_level = prefs.getInt("current_level", MIN_LEVEL);
- achieved_level = prefs.getInt("achieved_level", MIN_LEVEL+10);
+
+ gameState.loadState(prefs);
}
+
+ public void storeGameState(){
+ gameState.storeState(prefs.edit());
+ }
+
//
// This is a singleton object.
//
- public static App theApp()
- {
+ public static App theApp() {
return mApp;
}
- //
- // Puzzles.
- //
- public Puzzle getPuzzle( int level )
- {
- return pc.getPuzzle( level-1 );
- }
- public Puzzle getCurrentPuzzle()
- {
- return getPuzzle( getCurrentLevel() );
- }
- public Puzzle getPrevPuzzle()
- {
- if ( current_level != MIN_LEVEL )
- return getPuzzle( getCurrentLevel()-1 );
- else
- return null;
- }
- public Puzzle getNextPuzzle()
- {
- if ( current_level != achieved_level )
- return getPuzzle( getCurrentLevel()+1 );
- else
- return null;
- }
- //
- // Provide amount of puzzles.
- //
- public final int getPuzzleCount()
- {
- return max_level;
- }
- //
- // Provide highest solved puzzle.
- //
- public final int getAchivedLevel()
- {
- return achieved_level;
- }
- //
- // Provide last played puzzle.
- //
- public final int getCurrentLevel()
- {
- return current_level;
- }
- //
- // Set the current puzzle level.
- //
- public void setCurrentLevel( int l )
- {
- if ( l > achieved_level )
- l = MIN_LEVEL;
- if ( l < MIN_LEVEL )
- l = achieved_level;
- if ( l != current_level )
- {
- current_level = l;
- prefsEdit.putInt("current_level", current_level);
- prefsEdit.apply();
- if ( !prefs.edit().commit() )
- Log.d(TAG, "prefs.edit().commit() failed.");
- }
- }
- //
- // Set achieved level.
- //
- public void advanceAchivedLevel( int l )
- {
- if ( l > max_level )
- l = max_level;
- if ( l > achieved_level )
- {
- achieved_level = l;
- prefsEdit.putInt("achieved_level", achieved_level);
- prefsEdit.apply();
- if ( !prefs.edit().commit() )
- Log.d(TAG, "prefs.edit().commit() failed.");
- }
+
+ public State state(){
+ return gameState;
}
}
diff --git a/app/src/main/java/org/vostan/banvor/PuzzleBoardFragment.java b/app/src/main/java/org/vostan/banvor/PuzzleBoardFragment.java
new file mode 100644
index 0000000..b480fd9
--- /dev/null
+++ b/app/src/main/java/org/vostan/banvor/PuzzleBoardFragment.java
@@ -0,0 +1,147 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.vostan.banvor;
+
+import static org.vostan.banvor.App.theApp;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+import androidx.fragment.app.DialogFragment;
+import androidx.fragment.app.Fragment;
+
+import org.vostan.banvor.board.PuzzleControl;
+import org.vostan.banvor.databinding.FragmentPuzzleBoardBinding;
+import org.vostan.banvor.game.State;
+
+/**
+ *
+ */
+public class PuzzleBoardFragment extends Fragment
+{
+ private FragmentPuzzleBoardBinding binding;
+ private State gameState;
+ private PuzzleControl mPuzzleView;
+
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
+ {
+ gameState = theApp().state();
+ binding = FragmentPuzzleBoardBinding.inflate(inflater, container, false);
+ return binding.getRoot();
+ }
+
+ public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+
+ int gameLevel = PuzzleBoardFragmentArgs.fromBundle(getArguments()).getLevel();
+ gameState.setCurrentLevel(gameLevel);
+
+ initAndShowCurrentPuzzle();
+
+ binding.gameBoard.setPuzzleControlLister(new PuzzleControl.PuzzleControlLister() {
+ @Override
+ public void onSolved() {
+ PuzzleBoardFragment.this.onSolved();
+ }
+
+ @Override
+ public void onLongPress() {
+ }
+
+ @Override
+ public void onTouch() {
+ }
+ });
+ binding.btnPrev.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ gameState.setCurrentLevel(gameState.getCurrentLevel()-1);
+ PuzzleBoardFragment.this.initAndShowCurrentPuzzle();
+ }
+ });
+ binding.btnNext.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ gameState.setCurrentLevel(gameState.getCurrentLevel()+1);
+ PuzzleBoardFragment.this.initAndShowCurrentPuzzle();
+ }
+ });
+ binding.btnReset.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ PuzzleBoardFragment.this.initAndShowCurrentPuzzle();
+ }
+ });
+ binding.btnUndo.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ createNextLevelDialog(new DialogInterface.OnClickListener(){
+ public void onClick(DialogInterface d, int w){
+ gameState.advanceCurrentLevel();
+ initAndShowCurrentPuzzle();
+ }
+ }).show();
+ }
+ });
+ }
+
+ private void initAndShowCurrentPuzzle() {
+ int gameLevel = gameState.getCurrentLevel();
+ binding.levelNumber.setText(Integer.toString(gameLevel));
+ binding.gameBoard.setPuzzle(gameState.getCurrentPuzzle());
+ }
+
+ private void onSolved(){
+ //
+ // Since the puzzle is solved, we need to unlock next level if still locked.
+ //
+ gameState.levelSolved(gameState.getCurrentLevel());
+ //
+ // Bring a dialog for user to choose to continue or stop.
+ //
+// DialogFragment df = new DialogFragment() {
+// public Dialog onCreateDialog(Bundle savedInstanceState) {
+// return createNextLevelDialog(new DialogInterface.OnClickListener(){
+// public void onClick(DialogInterface d, int w){
+// gameState.advanceCurrentLevel();
+// initAndShowCurrentPuzzle();
+// }
+// });
+// }
+// };
+// df.show(getChildFragmentManager(), null);
+ createNextLevelDialog(new DialogInterface.OnClickListener(){
+ public void onClick(DialogInterface d, int w){
+ gameState.advanceCurrentLevel();
+ initAndShowCurrentPuzzle();
+ }
+ }).show();
+ }
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ binding = null;
+ }
+
+ private Dialog createNextLevelDialog(DialogInterface.OnClickListener listener){
+ AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+ builder.setTitle("Congratulations! You Won!");
+ builder.setMessage( "Would you like to try the next puzzle?" );
+ builder.setPositiveButton("Yes, please.", listener);
+ // Create the AlertDialog object and return it
+ Dialog dlg = builder.create();
+ dlg.setCancelable(true);
+ return dlg;
+ }
+}
diff --git a/app/src/main/java/org/vostan/banvor/PuzzleListFragment.java b/app/src/main/java/org/vostan/banvor/PuzzleListFragment.java
new file mode 100644
index 0000000..c4b02cc
--- /dev/null
+++ b/app/src/main/java/org/vostan/banvor/PuzzleListFragment.java
@@ -0,0 +1,197 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.vostan.banvor;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.os.Bundle;
+
+import androidx.annotation.NonNull;
+import androidx.fragment.app.Fragment;
+import androidx.navigation.fragment.NavHostFragment;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import android.widget.AdapterView;
+import android.widget.BaseAdapter;
+import android.widget.GridView;
+import android.widget.ImageView;
+
+import static org.vostan.banvor.App.theApp;
+
+import org.vostan.banvor.databinding.FragmentPuzzleListBinding;
+import org.vostan.banvor.game.State;
+
+/**
+ *
+ */
+class PuzzlesAdapter extends BaseAdapter
+{
+ private State gameState;
+ private Context context;
+ private int icon_size;
+ private int text_size;
+ private int text_x;
+ private int text_y;
+ private Bitmap lock_icon;
+ private Bitmap unlock_icon;
+ private Paint paint;
+
+ public PuzzlesAdapter(Context c)
+ {
+ super();
+
+ gameState = theApp().state();
+ context = c;
+ icon_size = (int)c.getResources().getDimension(R.dimen.puzzle_list_icon_size);
+ text_size = (int)c.getResources().getDimension(R.dimen.puzzle_list_number_size);
+ text_x = (int)c.getResources().getDimension(R.dimen.puzzle_list_number_x_coord);
+ text_y = (int)c.getResources().getDimension(R.dimen.puzzle_list_number_y_coord);
+
+ //
+ // Load locked icon
+ //
+ Bitmap lock_icon_tmp = BitmapFactory.decodeResource( c.getResources(), R.drawable.lock );
+ lock_icon = Bitmap.createBitmap(icon_size,icon_size,Bitmap.Config.ARGB_8888);
+ Canvas lock_canvas = new Canvas(lock_icon);
+ lock_canvas.drawBitmap(lock_icon_tmp,
+ new Rect(0,0,lock_icon_tmp.getWidth()-1,lock_icon_tmp.getHeight()-1),
+ new Rect(0,0, icon_size, icon_size),
+ null);
+
+ //
+ // Load unlock icon
+ //
+ Bitmap unlock_icon_tmp = BitmapFactory.decodeResource( c.getResources(), R.drawable.unlock );
+ unlock_icon = Bitmap.createBitmap(icon_size,icon_size,Bitmap.Config.ARGB_8888);
+ Canvas unlock_canvas = new Canvas(unlock_icon);
+ unlock_canvas.drawBitmap(unlock_icon_tmp,
+ new Rect(0,0,unlock_icon_tmp.getWidth()-1,unlock_icon_tmp.getHeight()-1),
+ new Rect(0,0,icon_size, icon_size),
+ null);
+
+ paint = new Paint();
+ }
+
+ @Override
+ public int getCount()
+ {
+ return gameState.getPuzzleCount();
+ }
+
+ @Override
+ public Object getItem(int position)
+ {
+ return null;
+ }
+
+ public int getPositionLevel(int position)
+ {
+ return position+1;
+ }
+
+ @Override
+ public long getItemId(int position)
+ {
+ return getPositionLevel(position);
+ }
+
+ // create a new ImageView for each item referenced by the Adapter
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent)
+ {
+ ImageView imageView;
+ if (convertView == null)
+ { // if it's not recycled, initialize some attributes
+ imageView = new ImageView(context);
+ imageView.setLayoutParams(new GridView.LayoutParams(icon_size, icon_size));
+ imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
+ }
+ else
+ imageView = (ImageView) convertView;
+
+ imageView.setImageBitmap(getIcon(position));
+ return imageView;
+ }
+
+ private Bitmap getIcon(int position)
+ {
+ paint.setColor( Color.WHITE );
+ paint.setTextSize( text_size );
+ paint.setTextAlign(Paint.Align.RIGHT);
+
+ int level = getPositionLevel(position);
+ Bitmap icon = ( gameState.isLocked(level) )
+ ? lock_icon.copy(Bitmap.Config.ARGB_8888,true)
+ : unlock_icon.copy(Bitmap.Config.ARGB_8888,true);
+
+ Canvas canvas = new Canvas(icon);
+ canvas.drawText( Integer.toString(level), text_x, text_y, paint);
+ return icon;
+ }
+}
+
+
+/**
+ *
+ */
+public class PuzzleListFragment extends Fragment
+{
+ private FragmentPuzzleListBinding binding;
+ private PuzzlesAdapter puzzleGridAdapter;
+ private State gameState;
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
+ {
+ gameState = theApp().state();
+ binding = FragmentPuzzleListBinding.inflate(inflater, container, false);
+ return binding.getRoot();
+ }
+
+ @Override
+ public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+
+ puzzleGridAdapter = new PuzzlesAdapter(getActivity());
+ binding.puzzleGrid.setAdapter(puzzleGridAdapter);
+
+ binding.puzzleGrid.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView> parent, View v, int position, long id) {
+ int level = puzzleGridAdapter.getPositionLevel(position);
+ if (!gameState.isLocked(level)){
+ PuzzleListFragmentDirections.ActionPuzzleListFragmentToPuzzleBoardFragment action =
+ PuzzleListFragmentDirections.actionPuzzleListFragmentToPuzzleBoardFragment();
+ action.setLevel(level);
+ NavHostFragment.findNavController(PuzzleListFragment.this)
+ .navigate(action);
+ }
+ }
+ });
+ }
+
+ @Override
+ public void onResume()
+ {
+ super.onResume();
+ if ( binding != null && binding.puzzleGrid != null ) {
+ puzzleGridAdapter.notifyDataSetChanged();
+ }
+ }
+
+ @Override
+ public void onDestroyView () {
+ super.onDestroyView();
+ binding = null;
+ }
+}
diff --git a/app/src/main/java/org/vostan/banvor/WelcomeActivity.java b/app/src/main/java/org/vostan/banvor/WelcomeActivity.java
new file mode 100644
index 0000000..10031d7
--- /dev/null
+++ b/app/src/main/java/org/vostan/banvor/WelcomeActivity.java
@@ -0,0 +1,77 @@
+package org.vostan.banvor;
+
+import android.os.Bundle;
+
+import com.google.android.material.snackbar.Snackbar;
+
+import androidx.appcompat.app.AppCompatActivity;
+
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+
+import androidx.navigation.NavController;
+import androidx.navigation.Navigation;
+import androidx.navigation.ui.AppBarConfiguration;
+import androidx.navigation.ui.NavigationUI;
+
+import org.vostan.banvor.databinding.ActivityWelcomeBinding;
+
+public class WelcomeActivity extends AppCompatActivity {
+
+ private AppBarConfiguration appBarConfiguration;
+ private ActivityWelcomeBinding binding;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ binding = ActivityWelcomeBinding.inflate(getLayoutInflater());
+ setContentView(binding.getRoot());
+
+// setSupportActionBar(binding.toolbar);
+
+ NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_content_welcome);
+
+// appBarConfiguration = new AppBarConfiguration.Builder(navController.getGraph()).build();
+// NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
+
+// binding.fab.setOnClickListener(new View.OnClickListener() {
+// @Override
+// public void onClick(View view) {
+// Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
+// .setAction("Action", null).show();
+// }
+// });
+ }
+
+// @Override
+// public boolean onCreateOptionsMenu(Menu menu) {
+// // Inflate the menu; this adds items to the action bar if it is present.
+//// getMenuInflater().inflate(R.menu.menu_main, menu);
+// return true;
+// }
+//
+// @Override
+// public boolean onOptionsItemSelected(MenuItem item) {
+// // Handle action bar item clicks here. The action bar will
+// // automatically handle clicks on the Home/Up button, so long
+// // as you specify a parent activity in AndroidManifest.xml.
+// int id = item.getItemId();
+//
+// //noinspection SimplifiableIfStatement
+// if (id == R.id.puzzle_grid) {
+// return true;
+// }
+//
+// return super.onOptionsItemSelected(item);
+// }
+
+
+ @Override
+ public boolean onSupportNavigateUp() {
+ NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_content_welcome);
+ return NavigationUI.navigateUp(navController, appBarConfiguration)
+ || super.onSupportNavigateUp();
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/vostan/banvor/WelcomeFragment.java b/app/src/main/java/org/vostan/banvor/WelcomeFragment.java
new file mode 100644
index 0000000..53b4b67
--- /dev/null
+++ b/app/src/main/java/org/vostan/banvor/WelcomeFragment.java
@@ -0,0 +1,68 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.vostan.banvor;
+
+import static org.vostan.banvor.App.theApp;
+
+import android.os.Bundle;
+
+import androidx.annotation.NonNull;
+import androidx.fragment.app.Fragment;
+import androidx.navigation.fragment.NavHostFragment;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+//import android.widget.Button;
+//import android.widget.TextView;
+//import static org.vostan.banvor.App.theApp;
+
+import org.vostan.banvor.databinding.FragmentWelcomeBinding;
+import org.vostan.banvor.game.State;
+
+/**
+ *
+ */
+public class WelcomeFragment extends Fragment
+{
+ private FragmentWelcomeBinding binding;
+ private State gameState;
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
+ {
+ gameState = theApp().state();
+ binding = FragmentWelcomeBinding.inflate(inflater, container, false);
+ return binding.getRoot();
+ }
+
+ public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+
+ binding.btnContinue.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ WelcomeFragmentDirections.ActionWelcomeFragmentToPuzzleBoardFragment action =
+ WelcomeFragmentDirections.actionWelcomeFragmentToPuzzleBoardFragment();
+ action.setLevel(gameState.getCurrentLevel());
+ NavHostFragment.findNavController(WelcomeFragment.this)
+ .navigate(action);
+ }
+ });
+ binding.btnPuzzles.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ NavHostFragment.findNavController(WelcomeFragment.this)
+ .navigate(R.id.action_WelcomeFragment_to_PuzzleListFragment);
+ }
+ });
+ }
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ binding = null;
+ }
+}
diff --git a/app/src/main/java/org/vostan/banvor/play/Animator.java b/app/src/main/java/org/vostan/banvor/board/Animator.java
similarity index 97%
rename from app/src/main/java/org/vostan/banvor/play/Animator.java
rename to app/src/main/java/org/vostan/banvor/board/Animator.java
index ef6cc71..f751e8a 100644
--- a/app/src/main/java/org/vostan/banvor/play/Animator.java
+++ b/app/src/main/java/org/vostan/banvor/board/Animator.java
@@ -2,7 +2,7 @@
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
-package org.vostan.banvor.play;
+package org.vostan.banvor.board;
import androidx.core.view.ViewCompat;
import java.util.LinkedList;
@@ -13,6 +13,113 @@ import java.util.LinkedList;
*/
public class Animator implements Runnable
{
+ public static abstract class Action
+ {
+ public int steps;
+
+ public Action()
+ {
+ steps = 0;
+ }
+
+ public abstract void intermediate( Animator ap, int step );
+ public abstract void last( Animator ap );
+ }
+
+ protected static abstract class XYAction extends Action
+ {
+ int x;
+ int y;
+
+ public XYAction( int _x, int _y )
+ {
+ x = _x;
+ y = _y;
+ }
+ }
+
+ public static class Move extends XYAction
+ {
+ public Move( int x, int y )
+ {
+ super(x,y);
+ }
+
+ public void intermediate( Animator ap, int step )
+ {}
+
+ public void last( Animator ap )
+ {
+ ap.view.getPuzzle().walk(x,y);
+ ap.view.invalidate();
+ }
+ }
+
+ public static class Push extends XYAction
+ {
+ public Push( int x, int y )
+ {
+ super(x,y);
+ }
+
+ public void intermediate( Animator ap, int step )
+ {
+ }
+
+ public void last( Animator ap )
+ {
+ ap.view.getPuzzle().push(x,y);
+ ap.view.invalidate();
+ }
+ }
+
+ public static class Select extends XYAction
+ {
+ public Select(int x, int y )
+ {
+ super(x,y);
+ }
+
+ public void intermediate( Animator ap, int step )
+ {
+ }
+
+ public void last( Animator ap )
+ {
+ ap.view.getPuzzle().select(x,y);
+ ap.view.invalidate();
+ }
+ }
+
+ public static class Unselect extends Action
+ {
+ public Unselect()
+ {}
+
+ public void intermediate( Animator ap, int step )
+ {}
+
+ public void last( Animator ap )
+ {
+ ap.view.getPuzzle().unselect();
+ ap.view.invalidate();
+ }
+ }
+
+ public static class NoMove extends XYAction
+ {
+ public NoMove( int x, int y )
+ {
+ super(x,y);
+ }
+
+ public void intermediate( Animator ap, int step )
+ {}
+
+ public void last( Animator ap )
+ {}
+ }
+
protected PuzzleView view;
protected LinkedList actions = new LinkedList();
protected boolean stop;
@@ -98,111 +205,4 @@ public class Animator implements Runnable
}
}
}
-
- public static abstract class Action
- {
- public int steps;
-
- public Action()
- {
- steps = 0;
- }
-
- public abstract void intermediate( Animator ap, int step );
- public abstract void last( Animator ap );
- }
-
- protected static abstract class XYAction extends Action
- {
- int x;
- int y;
-
- public XYAction( int _x, int _y )
- {
- x = _x;
- y = _y;
- }
- }
-
- public static class Move extends XYAction
- {
- public Move( int x, int y )
- {
- super(x,y);
- }
-
- public void intermediate( Animator ap, int step )
- {}
-
- public void last( Animator ap )
- {
- ap.view.getPuzzle().walk(x,y);
- ap.view.invalidate();
- }
- }
-
- public static class Push extends XYAction
- {
- public Push( int x, int y )
- {
- super(x,y);
- }
-
- public void intermediate( Animator ap, int step )
- {
- }
-
- public void last( Animator ap )
- {
- ap.view.getPuzzle().push(x,y);
- ap.view.invalidate();
- }
- }
-
- public static class Select extends XYAction
- {
- public Select(int x, int y )
- {
- super(x,y);
- }
-
- public void intermediate( Animator ap, int step )
- {
- }
-
- public void last( Animator ap )
- {
- ap.view.getPuzzle().select(x,y);
- ap.view.invalidate();
- }
- }
-
- public static class Unselect extends Action
- {
- public Unselect()
- {}
-
- public void intermediate( Animator ap, int step )
- {}
-
- public void last( Animator ap )
- {
- ap.view.getPuzzle().unselect();
- ap.view.invalidate();
- }
- }
-
- public static class NoMove extends XYAction
- {
- public NoMove( int x, int y )
- {
- super(x,y);
- }
-
- public void intermediate( Animator ap, int step )
- {}
-
- public void last( Animator ap )
- {}
- }
}
diff --git a/app/src/main/java/org/vostan/banvor/play/PlayActivity.java b/app/src/main/java/org/vostan/banvor/board/PlayActivity.java
similarity index 81%
rename from app/src/main/java/org/vostan/banvor/play/PlayActivity.java
rename to app/src/main/java/org/vostan/banvor/board/PlayActivity.java
index 4ae14ec..d1180a9 100644
--- a/app/src/main/java/org/vostan/banvor/play/PlayActivity.java
+++ b/app/src/main/java/org/vostan/banvor/board/PlayActivity.java
@@ -1,4 +1,4 @@
-package org.vostan.banvor.play;
+package org.vostan.banvor.board;
import android.app.AlertDialog;
import android.app.Dialog;
@@ -6,6 +6,8 @@ import android.content.DialogInterface;
import android.os.Bundle;
import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.FragmentActivity;
+
+import android.util.AttributeSet;
import android.view.View;
import android.view.Window;
import android.view.animation.Animation;
@@ -17,7 +19,7 @@ import org.vostan.banvor.App;
import static org.vostan.banvor.App.theApp;
import org.vostan.banvor.R;
-import org.vostan.banvor.Puzzle;
+import org.vostan.banvor.model.Puzzle;
public class PlayActivity extends FragmentActivity
implements PuzzleControl.PuzzleControlLister
@@ -41,16 +43,17 @@ public class PlayActivity extends FragmentActivity
//
// Create and set up the puzzle_view.
//
- puzzle_view = new PuzzleControl( this );
+// puzzle_view = new PuzzleControl(this, new AttributeSet() {
+// });
setContentView( puzzle_view );
puzzle_view.setPuzzleControlLister( this );
//
// Create action bar.
//
FrameLayout rootLayout = (FrameLayout)findViewById(android.R.id.content);
- View.inflate(this, R.layout.puzzle_view_title, rootLayout);
- title_text = (TextView)findViewById(R.id.title_text);
- title_view = findViewById(R.id.puzzle_view_title_layout);
+ View.inflate(this, R.layout.fragment_puzzle_board, rootLayout);
+ title_text = (TextView)findViewById(R.id.level_text);
+// title_view = findViewById(R.id.puzzle_view_title_layout);
//
// Load the puzzle.
//
@@ -62,9 +65,9 @@ public class PlayActivity extends FragmentActivity
//
// Advance current level and achieved level.
//
- final int nextl = theApp().getCurrentLevel()+1;
- theApp().advanceAchivedLevel(nextl);
- theApp().setCurrentLevel(nextl);
+ final int nextl = theApp().state().getCurrentLevel()+1;
+// theApp().state().(nextl);
+ theApp().state().setCurrentLevel(nextl);
//
// Bring a dialog for user to choose to continue or stop.
//
@@ -146,9 +149,9 @@ public class PlayActivity extends FragmentActivity
// If current level is less than achived level the move to next
// puzzle.
//
- if ( theApp().getCurrentLevel() > App.MIN_LEVEL )
+ if ( theApp().state().getCurrentLevel() > App.MIN_LEVEL )
{
- theApp().setCurrentLevel( theApp().getCurrentLevel()-1 );
+ theApp().state().setCurrentLevel( theApp().state().getCurrentLevel()-1 );
loadCurrentPuzzle();
puzzle_view.invalidate();
}
@@ -163,9 +166,9 @@ public class PlayActivity extends FragmentActivity
// If current level is less than achived level the move to next
// puzzle.
//
- if ( theApp().getCurrentLevel() < theApp().getAchivedLevel() )
+ if ( theApp().state().getCurrentLevel() < theApp().state().getHighestSolvedLevel() )
{
- theApp().setCurrentLevel( theApp().getCurrentLevel()+1 );
+ theApp().state().setCurrentLevel( theApp().state().getCurrentLevel()+1 );
loadCurrentPuzzle();
puzzle_view.invalidate();
@@ -189,13 +192,13 @@ public class PlayActivity extends FragmentActivity
private void loadCurrentPuzzle()
{
- puzzle = theApp().getCurrentPuzzle();
+ puzzle = theApp().state().getCurrentPuzzle();
puzzle_view.setPuzzle(puzzle);
updateTitle();
}
public void updateTitle()
{
- String title = "Level " + new Integer(theApp().getCurrentLevel()).toString();
+ String title = "Level " + new Integer(theApp().state().getCurrentLevel()).toString();
setTitle(title);
}
public void setTitle(CharSequence title)
diff --git a/app/src/main/java/org/vostan/banvor/play/PuzzleControl.java b/app/src/main/java/org/vostan/banvor/board/PuzzleControl.java
similarity index 93%
rename from app/src/main/java/org/vostan/banvor/play/PuzzleControl.java
rename to app/src/main/java/org/vostan/banvor/board/PuzzleControl.java
index 137499c..889c262 100644
--- a/app/src/main/java/org/vostan/banvor/play/PuzzleControl.java
+++ b/app/src/main/java/org/vostan/banvor/board/PuzzleControl.java
@@ -2,14 +2,17 @@
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
-package org.vostan.banvor.play;
+package org.vostan.banvor.board;
import android.content.Context;
import android.graphics.Point;
+import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
-import org.vostan.banvor.Puzzle;
+
+import org.vostan.banvor.game.PuzzleLogic;
+import org.vostan.banvor.model.Puzzle;
//import android.support.v4.view.GestureDetectorCompat;
@@ -39,9 +42,9 @@ public class PuzzleControl extends PuzzleView
public void onTouch();
}
- public PuzzleControl(Context c)
+ public PuzzleControl(Context c, AttributeSet attributeSet)
{
- super(c);
+ super(c,attributeSet);
logic = new PuzzleLogic();
animator = new Animator( this );
animator.setAnimationLister(this);
diff --git a/app/src/main/java/org/vostan/banvor/play/PuzzleView.java b/app/src/main/java/org/vostan/banvor/board/PuzzleView.java
similarity index 96%
rename from app/src/main/java/org/vostan/banvor/play/PuzzleView.java
rename to app/src/main/java/org/vostan/banvor/board/PuzzleView.java
index 6a96e51..5e8ba3e 100644
--- a/app/src/main/java/org/vostan/banvor/play/PuzzleView.java
+++ b/app/src/main/java/org/vostan/banvor/board/PuzzleView.java
@@ -1,4 +1,4 @@
-package org.vostan.banvor.play;
+package org.vostan.banvor.board;
import android.content.Context;
import android.graphics.Bitmap;
@@ -10,11 +10,13 @@ import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.RectF;
import androidx.core.view.ViewCompat;
+
+import android.util.AttributeSet;
import android.view.View;
import static java.lang.Math.*;
-import org.vostan.banvor.Puzzle;
-import static org.vostan.banvor.Puzzle.*;
+import org.vostan.banvor.model.Puzzle;
+import static org.vostan.banvor.model.Puzzle.*;
import org.vostan.banvor.R;
/**
@@ -38,9 +40,9 @@ public class PuzzleView extends View
private Rect tile_src = new Rect();
private RectF tile_dest = new RectF();
- public PuzzleView(Context context)
+ public PuzzleView(Context context, AttributeSet attributeSet)
{
- super(context);
+ super(context, attributeSet);
setFocusable(true);
//
@@ -53,24 +55,22 @@ public class PuzzleView extends View
// a.recycle();
}
- public void setPuzzle( Puzzle p )
- {
+ public void setPuzzle( Puzzle p ){
puzzle = p;
board.set(0,0,puzzle.getColumnCount(),puzzle.getRowCount());
viewport.set(board);
tile_size.set(0,0);
calcTransforms();
initTiles();
+ invalidate();
}
- public Puzzle getPuzzle()
- {
+ public Puzzle getPuzzle(){
return puzzle;
}
@Override
- protected void onSizeChanged(int w, int h, int oldw, int oldh)
- {
+ protected void onSizeChanged(int w, int h, int oldw, int oldh){
screen.set(0, 0, w, h);
tile_size.set(0,0);
calcTransforms();
@@ -78,8 +78,7 @@ public class PuzzleView extends View
}
- public void scaleViewport( float focusX, float focusY, float scale )
- {
+ public void scaleViewport( float focusX, float focusY, float scale ){
float left = scale*(focusX - screen.left);
float right = scale*(screen.right - focusX);
float top = scale*(focusY - screen.top);
@@ -91,14 +90,12 @@ public class PuzzleView extends View
ViewCompat.postInvalidateOnAnimation(this);
}
- public void scaleViewportDone()
- {
+ public void scaleViewportDone(){
//initTiles();
ViewCompat.postInvalidateOnAnimation(this);
}
- public void scrollViewport( float distanceX, float distanceY )
- {
+ public void scrollViewport( float distanceX, float distanceY ){
viewport.set( screen.left+distanceX,
screen.top+distanceY,
screen.right+distanceX,
@@ -338,7 +335,7 @@ public class PuzzleView extends View
}
private Bitmap createWorkerTile()
{
- Bitmap tmp = BitmapFactory.decodeResource( getResources(), R.drawable.worker );
+ Bitmap tmp = BitmapFactory.decodeResource( getResources(), R.drawable.worker);
Bitmap bitmap = Bitmap.createBitmap(tile_size.x, tile_size.y, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
canvas.drawBitmap(tmp,
diff --git a/app/src/main/java/org/vostan/banvor/play/PuzzleLogic.java b/app/src/main/java/org/vostan/banvor/game/PuzzleLogic.java
similarity index 99%
rename from app/src/main/java/org/vostan/banvor/play/PuzzleLogic.java
rename to app/src/main/java/org/vostan/banvor/game/PuzzleLogic.java
index 29661d0..474d6dc 100644
--- a/app/src/main/java/org/vostan/banvor/play/PuzzleLogic.java
+++ b/app/src/main/java/org/vostan/banvor/game/PuzzleLogic.java
@@ -2,15 +2,16 @@
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
-package org.vostan.banvor.play;
+package org.vostan.banvor.game;
import static java.lang.Math.*;
import java.util.Arrays;
-import org.vostan.banvor.Puzzle;
+
+import org.vostan.banvor.board.Animator;
+import org.vostan.banvor.model.Puzzle;
/**
*
- * @author vahagnk
*/
public class PuzzleLogic
{
diff --git a/app/src/main/java/org/vostan/banvor/game/State.java b/app/src/main/java/org/vostan/banvor/game/State.java
new file mode 100644
index 0000000..3bd3802
--- /dev/null
+++ b/app/src/main/java/org/vostan/banvor/game/State.java
@@ -0,0 +1,134 @@
+package org.vostan.banvor.game;
+
+import static org.vostan.banvor.App.theApp;
+
+import android.content.SharedPreferences;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import org.vostan.banvor.model.IPuzzleSource;
+import org.vostan.banvor.model.Puzzle;
+
+public class State {
+ public static final String TAG = "Sokoban.Sate";
+ public static final String CUR_LEVEL = "current_level";
+ public static final String HIGH_LEVEL = "highest_unlocked_level";
+
+ protected IPuzzleSource mPuzzleSource;
+ protected int mCurrentLevel;
+ protected int mHighestUnlockedLevel;
+ public static final int MIN_LEVEL = 1;
+ protected int mMaxLevel;
+
+ public State(@NonNull IPuzzleSource ps){
+ mPuzzleSource = ps;
+ mCurrentLevel = 0;
+ mHighestUnlockedLevel = 0;
+ mMaxLevel = mPuzzleSource.getCount();
+ }
+
+ //
+ // These are to save the game state and restore it.
+ //
+ public void storeState(@NonNull SharedPreferences.Editor prefs){
+ prefs.putInt(CUR_LEVEL, mCurrentLevel);
+ prefs.putInt(HIGH_LEVEL, mHighestUnlockedLevel);
+ prefs.apply();
+ if ( !prefs.commit() ) {
+ Log.d(TAG, "prefs.edit().commit() failed.");
+ }
+ }
+
+ public void loadState(@NonNull SharedPreferences prefs){
+ mCurrentLevel = prefs.getInt(CUR_LEVEL, MIN_LEVEL);
+ mHighestUnlockedLevel = prefs.getInt(HIGH_LEVEL, MIN_LEVEL);
+ }
+
+ //
+ // Provide amount of puzzles.
+ //
+ public final int getPuzzleCount()
+ {
+ return mPuzzleSource.getCount();
+ }
+
+ //
+ // Puzzles.
+ //
+ public Puzzle getPuzzle(int level )
+ {
+ return mPuzzleSource.getPuzzle( level-1 );
+ }
+ public Puzzle getCurrentPuzzle()
+ {
+ return getPuzzle( getCurrentLevel() );
+ }
+ public Puzzle getPrevPuzzle()
+ {
+ if ( mCurrentLevel != MIN_LEVEL ) {
+ return getPuzzle(getCurrentLevel() - 1);
+ }
+ else {
+ return null;
+ }
+ }
+ public Puzzle getNextPuzzle()
+ {
+ if ( mCurrentLevel != mHighestUnlockedLevel) {
+ return getPuzzle(getCurrentLevel() + 1);
+ }
+ else {
+ return null;
+ }
+ }
+
+ //
+ // Level Unlock logic
+ //
+ public Boolean isLocked(int level){
+ return level > mHighestUnlockedLevel;
+ }
+ private void unlockLevel( int l )
+ {
+ if ( l > mMaxLevel){
+ l = mMaxLevel;
+ }
+ if ( l > mHighestUnlockedLevel) {
+ mHighestUnlockedLevel = l;
+ }
+ theApp().storeGameState();
+ }
+ public void levelSolved(int l){
+ unlockLevel(l+1);
+ }
+
+ //
+ // Provide highest solved puzzle.
+ //
+ public final int getHighestSolvedLevel(){
+ return mHighestUnlockedLevel;
+ }
+ //
+ // Provide last played puzzle.
+ //
+ public final int getCurrentLevel(){
+ return mCurrentLevel;
+ }
+ //
+ // Set the current puzzle level.
+ //
+ public void setCurrentLevel( int l ) {
+ if ( l > mHighestUnlockedLevel){
+ l = MIN_LEVEL;
+ }
+ else if ( l < MIN_LEVEL ) {
+ l = mHighestUnlockedLevel;
+ }
+ mCurrentLevel = l;
+ theApp().storeGameState();
+ }
+ public void advanceCurrentLevel(){
+ setCurrentLevel(mCurrentLevel+1);
+ }
+}
diff --git a/app/src/main/java/org/vostan/banvor/menu/MainActivity.java b/app/src/main/java/org/vostan/banvor/menu/MainActivity.java
deleted file mode 100644
index 17e606c..0000000
--- a/app/src/main/java/org/vostan/banvor/menu/MainActivity.java
+++ /dev/null
@@ -1,122 +0,0 @@
-package org.vostan.banvor.menu;
-
-import org.vostan.banvor.play.PlayActivity;
-
-import android.content.Intent;
-import android.view.View;
-import android.os.Bundle;
-//import androidx.fragment.app.Fragment;
-//support.v4.app.FragmentActivity;
-import androidx.fragment.app.FragmentManager;
-import androidx.fragment.app.FragmentTransaction;
-import android.view.Window;
-
-import androidx.appcompat.app.AppCompatActivity;
-
-import org.vostan.banvor.R;
-import static org.vostan.banvor.App.theApp;
-
-public class MainActivity extends AppCompatActivity
-{
- protected final String TAG = "SokobanMenu";
- protected final String LEVEL= "org.dyndns.vahagn.sokoban.LEVEL";
- protected MainFragment mainFragment;
- protected PuzzleListFragment puzzleListFragment;
- protected float puzzleListXScroll;
- protected float puzzleListXScrollMax;
-
- /** Called when the activity is first created. */
- @Override
- public void onCreate(Bundle savedInstanceState)
- {
- requestWindowFeature(Window.FEATURE_NO_TITLE);
-
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main_activity);
-
- mainFragment = new MainFragment();
- puzzleListFragment = new PuzzleListFragment();
- puzzleListFragment.setOnPuzzleListAction(new PuzzleListFragment.OnPuzzleListAction() {
- public boolean onPuzzleGridDown() {
- return onPuzzleGridDown1();
- }
- public boolean onPuzzleGridXScroll(float x) {
- return onPuzzleGridXScroll1(x);
- }
- public void onPuzzleLevelClicked(int level) {
- onPuzzleClicked1(level);
- }
- });
- puzzleListXScrollMax = getWindowManager().getDefaultDisplay().getWidth();
-
- //
- // Set initila fragment.
- //
- FragmentManager fragmentManager = getSupportFragmentManager();
- FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
- fragmentTransaction.add(R.id.fragment_container, mainFragment);
-// fragmentTransaction.add(R.id.fragment_container, puzzleListFragment);
- fragmentTransaction.commit();
- }
-
- //@Override
- public void onConfigurationChanged()
- {
- // super.onConfigurationChanged();
- // setContentView(R.layout-l.menu);
- }
-
- public void onStartCurrentPuzzle(View v)
- {
- Intent intent = new Intent(this, PlayActivity.class);
- startActivity( intent );
- }
-
- public void onPuzzleListShow(View v)
- {
- getSupportFragmentManager()
- .beginTransaction()
- .setCustomAnimations(R.animator.fragment_slide_left_enter,
- R.animator.fragment_slide_left_exit)
- .replace(R.id.fragment_container, puzzleListFragment)
- .commit();
- }
-
- public boolean onPuzzleGridDown1()
- {
- puzzleListXScroll = 0;
- return true;
- }
-
- public boolean onPuzzleGridXScroll1( float x )
- {
- puzzleListXScroll += x;
- /*
- getSupportFragmentManager()
- .beginTransaction()
- .setCustomAnimations(R.animator.fragment_slide_right_enter,
- R.animator.fragment_slide_right_exit)
- .commit();
- */
- if ( -puzzleListXScroll/puzzleListXScrollMax > 0.5 )
- {
- getSupportFragmentManager()
- .beginTransaction()
- .setCustomAnimations(R.animator.fragment_slide_right_enter,
- R.animator.fragment_slide_right_exit)
- .replace(R.id.fragment_container, mainFragment)
- .commit();
- }
- return true;
- }
-
- public void onPuzzleClicked1( int level )
- {
- if ( level <= theApp().getAchivedLevel() )
- {
- theApp().setCurrentLevel(level);
- Intent intent = new Intent(this, PlayActivity.class);
- startActivity( intent );
- }
- }
-}
diff --git a/app/src/main/java/org/vostan/banvor/menu/MainFragment.java b/app/src/main/java/org/vostan/banvor/menu/MainFragment.java
deleted file mode 100644
index ee821ce..0000000
--- a/app/src/main/java/org/vostan/banvor/menu/MainFragment.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * To change this template, choose Tools | Templates
- * and open the template in the editor.
- */
-package org.vostan.banvor.menu;
-
-import android.os.Bundle;
-import androidx.fragment.app.Fragment;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.Button;
-import android.widget.TextView;
-import static org.vostan.banvor.App.theApp;
-import org.vostan.banvor.R;
-
-/**
- *
- * @author vahagnk
- */
-public class MainFragment extends Fragment
-{
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle icicle)
- {
- super.onCreate(icicle);
- View v = inflater.inflate(R.layout.main_fragment, container, false);
- if ( theApp().getAchivedLevel() == 1 )
- ((Button)v.findViewById(R.id.btn_start)).setText(R.string.btn_start_begin);
- //
- // Set Footer.
- //
- String str = getString(R.string.copyright) + "\n"
- +getString(R.string.version_tag) + " " + getString(R.string.git_version);
- ((TextView)v.findViewById(R.id.footer_txt)).setText(str);
-
- return v;
- }
-}
diff --git a/app/src/main/java/org/vostan/banvor/menu/PuzzleListFragment.java b/app/src/main/java/org/vostan/banvor/menu/PuzzleListFragment.java
deleted file mode 100644
index fd776e0..0000000
--- a/app/src/main/java/org/vostan/banvor/menu/PuzzleListFragment.java
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * To change this template, choose Tools | Templates
- * and open the template in the editor.
- */
-package org.vostan.banvor.menu;
-
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.os.Bundle;
-import androidx.fragment.app.Fragment;
-import android.util.TypedValue;
-import android.view.GestureDetector;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.BaseAdapter;
-import android.widget.GridView;
-import android.widget.ImageView;
-
-import org.vostan.banvor.R;
-
-import static org.vostan.banvor.App.theApp;
-
-/**
- *
- */
-public class PuzzleListFragment extends Fragment
-{
- protected GridView puzzleGrid;
- protected PuzzlesAdapter puzzleGridAdapter;
- protected GestureDetector gridViewXScrollDetector;
- protected OnPuzzleListAction actionListener;
-
- /*
- * These are events which the fragments delegates to activity.
- */
- public interface OnPuzzleListAction
- {
- public boolean onPuzzleGridDown();
- public boolean onPuzzleGridXScroll( float x );
- public void onPuzzleLevelClicked( int level );
- }
- public void setOnPuzzleListAction( OnPuzzleListAction l )
- {
- actionListener = l;
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle icicle)
- {
- super.onCreate(icicle);
- View v = inflater.inflate(R.layout.puzzle_list_fragment, container, false);
- //
- // Configure GridView.
- //
- puzzleGrid = (GridView)v.findViewById(R.id.puzzle_grid);
- puzzleGridAdapter = new PuzzlesAdapter(getActivity());
- puzzleGrid.setAdapter( puzzleGridAdapter );
- puzzleGrid.setOnItemClickListener(new AdapterView.OnItemClickListener() {
- public void onItemClick(AdapterView> parent, View v, int position, long id)
- {
- onPuzzleClicked(v,(int)id);
- }
- });
- puzzleGrid.setOnTouchListener( new View.OnTouchListener() {
- public boolean onTouch(View view, MotionEvent me) {
- gridViewXScrollDetector.onTouchEvent( me );
- return false;
- }
- });
- gridViewXScrollDetector = new GestureDetector(new GestureDetector.SimpleOnGestureListener() {
- public boolean onDown(MotionEvent e) {
- return (actionListener!=null) ? actionListener.onPuzzleGridDown() : false;
- }
- public boolean onScroll(MotionEvent e1, MotionEvent e2, float dx, float dy) {
- return (actionListener!=null) ? actionListener.onPuzzleGridXScroll(dx) : false;
- }
- });
-
- return v;
- }
-
- @Override
- public void onResume()
- {
- super.onResume();
- if ( puzzleGrid != null )
- puzzleGridAdapter.notifyDataSetChanged();
- }
-
- public void onPuzzleClicked(View v, int level )
- {
- if (actionListener!=null)
- actionListener.onPuzzleLevelClicked(level);
- }
-
- public class PuzzlesAdapter extends BaseAdapter
- {
- private Context context;
- private int icon_size;
- private int text_x;
- private int text_y;
- private Bitmap lock_icon;
- private Bitmap unlock_icon;
- private Paint paint;
-
- public PuzzlesAdapter(Context c)
- {
- context = c;
- icon_size = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_MM, 10, getResources().getDisplayMetrics() );
- int text_size = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_MM, 4, getResources().getDisplayMetrics() );
- text_x = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_MM, 9, getResources().getDisplayMetrics() );
- text_y = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_MM, 9, getResources().getDisplayMetrics() );
-
- Bitmap lock_icon_tmp = BitmapFactory.decodeResource( getResources(), R.drawable.lock );
- lock_icon = Bitmap.createBitmap(icon_size,icon_size,Bitmap.Config.ARGB_8888);
- Canvas lock_canvas = new Canvas(lock_icon);
- lock_canvas.drawBitmap(lock_icon_tmp,
- new Rect(0,0,lock_icon_tmp.getWidth()-1,lock_icon_tmp.getHeight()-1),
- new Rect(0,0,icon_size, icon_size),
- null);
-
- Bitmap unlock_icon_tmp = BitmapFactory.decodeResource( getResources(), R.drawable.unlock );
- unlock_icon = Bitmap.createBitmap(icon_size,icon_size,Bitmap.Config.ARGB_8888);
- Canvas unlock_canvas = new Canvas(unlock_icon);
- unlock_canvas.drawBitmap(unlock_icon_tmp,
- new Rect(0,0,unlock_icon_tmp.getWidth()-1,unlock_icon_tmp.getHeight()-1),
- new Rect(0,0,icon_size, icon_size),
- null);
-
- paint = new Paint();
- paint.setColor( Color.WHITE );
- paint.setTextSize( text_size );
- paint.setTextAlign(Paint.Align.RIGHT);
- }
-
- public int getCount()
- {
- return theApp().getPuzzleCount();
- }
-
- public Object getItem(int position)
- {
- return null;
- }
-
- public long getItemId(int position)
- {
- return position+1;
- }
-
- // create a new ImageView for each item referenced by the Adapter
- public View getView(int position, View convertView, ViewGroup parent)
- {
- ImageView imageView;
- if (convertView == null)
- { // if it's not recycled, initialize some attributes
- imageView = new ImageView(context);
- imageView.setLayoutParams(new GridView.LayoutParams(icon_size, icon_size));
- imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
- }
- else
- imageView = (ImageView) convertView;
-
- int id = (int)getItemId(position);
- Bitmap icon = ( id <= theApp().getAchivedLevel() )
- ? unlock_icon.copy(Bitmap.Config.ARGB_8888,true)
- : lock_icon.copy(Bitmap.Config.ARGB_8888,true);
- Canvas canvas = new Canvas(icon);
- canvas.drawText( Integer.toString(id), text_x, text_y, paint);
- imageView.setImageBitmap(icon);
- return imageView;
- }
- }
-
-}
diff --git a/app/src/main/java/org/vostan/banvor/model/Coord.java b/app/src/main/java/org/vostan/banvor/model/Coord.java
new file mode 100644
index 0000000..4d37602
--- /dev/null
+++ b/app/src/main/java/org/vostan/banvor/model/Coord.java
@@ -0,0 +1,6 @@
+package org.vostan.banvor.model;
+
+public class Coord {
+ public int x;
+ public int y;
+}
diff --git a/app/src/main/java/org/vostan/banvor/model/IPuzzleSource.java b/app/src/main/java/org/vostan/banvor/model/IPuzzleSource.java
new file mode 100644
index 0000000..3016e9a
--- /dev/null
+++ b/app/src/main/java/org/vostan/banvor/model/IPuzzleSource.java
@@ -0,0 +1,6 @@
+package org.vostan.banvor.model;
+
+public interface IPuzzleSource {
+ public int getCount();
+ public Puzzle getPuzzle( int i );
+}
diff --git a/app/src/main/java/org/vostan/banvor/Puzzle.java b/app/src/main/java/org/vostan/banvor/model/Puzzle.java
similarity index 99%
rename from app/src/main/java/org/vostan/banvor/Puzzle.java
rename to app/src/main/java/org/vostan/banvor/model/Puzzle.java
index 1e6974a..a6df76a 100644
--- a/app/src/main/java/org/vostan/banvor/Puzzle.java
+++ b/app/src/main/java/org/vostan/banvor/model/Puzzle.java
@@ -1,4 +1,4 @@
-package org.vostan.banvor;
+package org.vostan.banvor.model;
//import java.lang.Exception;
import java.io.*;
diff --git a/app/src/main/java/org/vostan/banvor/PuzzleContainer.java b/app/src/main/java/org/vostan/banvor/model/PuzzleContainer.java
similarity index 91%
rename from app/src/main/java/org/vostan/banvor/PuzzleContainer.java
rename to app/src/main/java/org/vostan/banvor/model/PuzzleContainer.java
index 3a5792a..efe8e92 100644
--- a/app/src/main/java/org/vostan/banvor/PuzzleContainer.java
+++ b/app/src/main/java/org/vostan/banvor/model/PuzzleContainer.java
@@ -1,12 +1,13 @@
-package org.vostan.banvor;
+package org.vostan.banvor.model;
import java.io.InputStream;
import java.io.IOException;
import static org.vostan.banvor.App.theApp;
+import org.vostan.banvor.model.Puzzle;
import org.vostan.banvor.R;
-public class PuzzleContainer
+public class PuzzleContainer implements IPuzzleSource
{
protected int count;
diff --git a/app/src/main/res/layout/activity_welcome.xml b/app/src/main/res/layout/activity_welcome.xml
new file mode 100644
index 0000000..c05fedf
--- /dev/null
+++ b/app/src/main/res/layout/activity_welcome.xml
@@ -0,0 +1,54 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/content_welcome.xml b/app/src/main/res/layout/content_welcome.xml
new file mode 100644
index 0000000..d93f42d
--- /dev/null
+++ b/app/src/main/res/layout/content_welcome.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_puzzle_board.xml b/app/src/main/res/layout/fragment_puzzle_board.xml
new file mode 100644
index 0000000..44e51c2
--- /dev/null
+++ b/app/src/main/res/layout/fragment_puzzle_board.xml
@@ -0,0 +1,118 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/fragment_puzzle_list.xml b/app/src/main/res/layout/fragment_puzzle_list.xml
new file mode 100644
index 0000000..6c2ed12
--- /dev/null
+++ b/app/src/main/res/layout/fragment_puzzle_list.xml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/fragment_welcome.xml b/app/src/main/res/layout/fragment_welcome.xml
new file mode 100644
index 0000000..1189602
--- /dev/null
+++ b/app/src/main/res/layout/fragment_welcome.xml
@@ -0,0 +1,107 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/main_activity.xml b/app/src/main/res/layout/main_activity.xml
deleted file mode 100644
index 5fcda9a..0000000
--- a/app/src/main/res/layout/main_activity.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
diff --git a/app/src/main/res/layout/main_fragment.xml b/app/src/main/res/layout/main_fragment.xml
deleted file mode 100644
index 85e3354..0000000
--- a/app/src/main/res/layout/main_fragment.xml
+++ /dev/null
@@ -1,61 +0,0 @@
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/puzzle_list_fragment.xml b/app/src/main/res/layout/puzzle_list_fragment.xml
deleted file mode 100644
index 16d0bfe..0000000
--- a/app/src/main/res/layout/puzzle_list_fragment.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
-
-
diff --git a/app/src/main/res/layout/puzzle_view_title.xml b/app/src/main/res/layout/puzzle_view_title.xml
deleted file mode 100644
index 6e7ff20..0000000
--- a/app/src/main/res/layout/puzzle_view_title.xml
+++ /dev/null
@@ -1,71 +0,0 @@
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/navigation/nav_graph.xml b/app/src/main/res/navigation/nav_graph.xml
new file mode 100644
index 0000000..c1cdfac
--- /dev/null
+++ b/app/src/main/res/navigation/nav_graph.xml
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values-land/dimens.xml b/app/src/main/res/values-land/dimens.xml
new file mode 100644
index 0000000..22d7f00
--- /dev/null
+++ b/app/src/main/res/values-land/dimens.xml
@@ -0,0 +1,3 @@
+
+ 48dp
+
\ No newline at end of file
diff --git a/app/src/main/res/values-night/themes.xml b/app/src/main/res/values-night/themes.xml
index bb48def..698af1a 100644
--- a/app/src/main/res/values-night/themes.xml
+++ b/app/src/main/res/values-night/themes.xml
@@ -1,16 +1,17 @@
-
\ No newline at end of file
diff --git a/app/src/main/res/values-w1240dp/dimens.xml b/app/src/main/res/values-w1240dp/dimens.xml
new file mode 100644
index 0000000..d73f4a3
--- /dev/null
+++ b/app/src/main/res/values-w1240dp/dimens.xml
@@ -0,0 +1,3 @@
+
+ 200dp
+
\ No newline at end of file
diff --git a/app/src/main/res/values-w600dp/dimens.xml b/app/src/main/res/values-w600dp/dimens.xml
new file mode 100644
index 0000000..22d7f00
--- /dev/null
+++ b/app/src/main/res/values-w600dp/dimens.xml
@@ -0,0 +1,3 @@
+
+ 48dp
+
\ No newline at end of file
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index 41338bc..ddf5bf1 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -18,13 +18,18 @@
*/
-->
- #80404040
+ #00000000
+ #80000000
+ #40FFFFFF
#C0C0C0C0
- #FFBB86FC
- #FF6200EE
- #FF3700B3
- #FF03DAC5
- #FF018786
- #FF000000
- #FFFFFFFF
+ #FFFFE680
+
+ #FFC107
+ #000000
+ #FF5722
+ #913213
+ #000000
+ #AA6601
+ #661C17
+ #FF5722
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
index 70c646d..737fb70 100644
--- a/app/src/main/res/values/dimens.xml
+++ b/app/src/main/res/values/dimens.xml
@@ -1,5 +1,4 @@
-
-
+ 95dp
+ 95dp
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index c9e1e3c..a0fdef2 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -9,4 +9,9 @@
Puzzles
Version:
(c) 2013 Vahagn Khachatryan
+ WelcomeActivity
+
+ Welcome Fragment
+ Puzzle List Fragment
+
diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml
index 3606529..042c897 100644
--- a/app/src/main/res/values/themes.xml
+++ b/app/src/main/res/values/themes.xml
@@ -1,16 +1,26 @@
-
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 2106b82..fa1f1dc 100644
--- a/build.gradle
+++ b/build.gradle
@@ -7,6 +7,9 @@ buildscript {
dependencies {
classpath "com.android.tools.build:gradle:7.0.2"
+ def nav_version = "2.3.5"
+ classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version"
+
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}