From 91530e3efad070c8cf1a541e622226495f3110ee Mon Sep 17 00:00:00 2001 From: Christopher Beckmann Date: Sat, 30 Jan 2016 23:05:32 +0100 Subject: [PATCH 1/4] Made the GameActivity Rotatable. (Sounds easy.... wasn't though) --- .../controller/GameController.java | 107 ++++++++++++++++-- .../controller/QQWingController.java | 1 + .../controller/UndoRedoManager.java | 34 +++++- .../privacyfriendlysudoku/game/GameBoard.java | 52 ++++++++- .../privacyfriendlysudoku/game/GameCell.java | 43 ++++++- .../game/GameDifficulty.java | 28 ++++- .../privacyfriendlysudoku/game/GameType.java | 39 ++++++- .../ui/GameActivity.java | 96 +++++++++++----- .../ui/MainActivity.java | 5 +- .../ui/view/SudokuKeyboardLayout.java | 18 ++- .../ui/view/SudokuSpecialButtonLayout.java | 27 ++--- .../res/layout-land/content_game_view.xml | 54 ++++----- 12 files changed, 418 insertions(+), 86 deletions(-) diff --git a/app/src/main/java/org/secuso/privacyfriendlysudoku/controller/GameController.java b/app/src/main/java/org/secuso/privacyfriendlysudoku/controller/GameController.java index df6e6b0..f7120bd 100644 --- a/app/src/main/java/org/secuso/privacyfriendlysudoku/controller/GameController.java +++ b/app/src/main/java/org/secuso/privacyfriendlysudoku/controller/GameController.java @@ -3,11 +3,15 @@ package org.secuso.privacyfriendlysudoku.controller; import android.content.Context; import android.content.SharedPreferences; import android.os.Handler; +import android.os.Parcel; +import android.os.Parcelable; +import android.util.Log; import java.util.LinkedList; import java.util.List; import java.util.Timer; import java.util.TimerTask; +import java.util.concurrent.atomic.AtomicBoolean; import org.secuso.privacyfriendlysudoku.controller.helper.GameInfoContainer; import org.secuso.privacyfriendlysudoku.game.CellConflict; @@ -26,7 +30,7 @@ import org.secuso.privacyfriendlysudoku.game.listener.ITimerListener; /** * Created by Chris on 06.11.2015. */ -public class GameController implements IModelChangedListener { +public class GameController implements IModelChangedListener, Parcelable { // General private SharedPreferences settings; @@ -63,11 +67,12 @@ public class GameController implements IModelChangedListener { // Timer private int time = 0; - private boolean timerRunning = false; + private AtomicBoolean timerRunning = new AtomicBoolean(false); private LinkedList timerListeners = new LinkedList<>(); private Handler timerHandler = new Handler(); private Timer timer = new Timer(); private TimerTask timerTask; + private boolean noteStatus = false; // Constructors @@ -584,31 +589,40 @@ public class GameController implements IModelChangedListener { return usedHints; } - private void initTimer() { + public void initTimer() { + deleteTimer(); + timerTask = new TimerTask() { @Override public void run() { timerHandler.post(new Runnable() { @Override public void run() { - if(timerRunning) { + if(timerRunning.get()) { notifyTimerListener(time++); + //Log.d("Timer", "calling notifyTimerListener(" + time + ");"); } } }); } }; timer = new Timer(); - timer.scheduleAtFixedRate(timerTask,0,1000); + timer.scheduleAtFixedRate(timerTask, 0, 1000); + } + + public void deleteTimer() { + pauseTimer(); + timer.cancel(); + timer.purge(); } public void startTimer() { - timerRunning = true; + timerRunning.set(true); notifyHighlightChangedListeners(); } public void pauseTimer(){ - timerRunning = false; + timerRunning.set(false); } public void ReDo() { @@ -665,4 +679,83 @@ public class GameController implements IModelChangedListener { }, 0); } + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel out, int flags) { + + // get the gamecontroller a new context + out.writeInt(selectedRow); + out.writeInt(selectedCol); + out.writeInt(selectedValue); + out.writeInt(highlightValue); + out.writeInt(gameID); + out.writeInt(size); + out.writeInt(sectionHeight); + out.writeInt(sectionWidth); + out.writeInt(usedHints); + out.writeInt(time); + + out.writeIntArray(solution); + + out.writeInt(noteStatus ? 1 : 0); + out.writeInt(notifiedOnSolvedListeners ? 1 : 0); + + out.writeParcelable(gameType, 0); + out.writeParcelable(difficulty, 0); + out.writeParcelable(gameBoard, 0); + out.writeParcelable(undoRedoManager, 0); + + // delete lists, in case we get the same object back from Parcel + removeAllListeners(); + + } + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + public GameController createFromParcel(Parcel in) { + return new GameController(in); + } + + public GameController[] newArray(int size) { + return new GameController[size]; + } + }; + + /** recreate object from parcel */ + private GameController(Parcel in) { + + selectedRow = in.readInt(); + selectedCol = in.readInt(); + selectedValue = in.readInt(); + highlightValue = in.readInt(); + gameID = in.readInt(); + size = in.readInt(); + sectionHeight = in.readInt(); + sectionWidth = in.readInt(); + usedHints = in.readInt(); + time = in.readInt(); + + in.readIntArray(solution); + + noteStatus = in.readInt() == 1; + notifiedOnSolvedListeners = in.readInt() == 1; + + gameType = in.readParcelable(null); + difficulty = in.readParcelable(null); + gameBoard = in.readParcelable(null); + undoRedoManager = in.readParcelable(null); + + removeAllListeners(); + + } + + public void removeAllListeners() { + highlightListeners = new LinkedList<>(); + solvedListeners = new LinkedList<>(); + hintListener = new LinkedList<>(); + timerListeners = new LinkedList<>(); + } } diff --git a/app/src/main/java/org/secuso/privacyfriendlysudoku/controller/QQWingController.java b/app/src/main/java/org/secuso/privacyfriendlysudoku/controller/QQWingController.java index e8a6751..0bafec8 100644 --- a/app/src/main/java/org/secuso/privacyfriendlysudoku/controller/QQWingController.java +++ b/app/src/main/java/org/secuso/privacyfriendlysudoku/controller/QQWingController.java @@ -1,5 +1,6 @@ package org.secuso.privacyfriendlysudoku.controller; +import android.os.Parcelable; import android.util.Log; import java.util.LinkedList; diff --git a/app/src/main/java/org/secuso/privacyfriendlysudoku/controller/UndoRedoManager.java b/app/src/main/java/org/secuso/privacyfriendlysudoku/controller/UndoRedoManager.java index 7230c4b..c6c4ce1 100644 --- a/app/src/main/java/org/secuso/privacyfriendlysudoku/controller/UndoRedoManager.java +++ b/app/src/main/java/org/secuso/privacyfriendlysudoku/controller/UndoRedoManager.java @@ -1,5 +1,8 @@ package org.secuso.privacyfriendlysudoku.controller; +import android.os.Parcel; +import android.os.Parcelable; + import java.util.LinkedList; import org.secuso.privacyfriendlysudoku.game.GameBoard; @@ -7,7 +10,7 @@ import org.secuso.privacyfriendlysudoku.game.GameBoard; /** * Created by Chris on 24.11.2015. */ -public class UndoRedoManager { +public class UndoRedoManager implements Parcelable { private int activeState; private LinkedList states = new LinkedList<>(); @@ -78,4 +81,33 @@ public class UndoRedoManager { e.printStackTrace(); } } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeInt(activeState); + out.writeTypedList(states); + } + + public static final Parcelable.Creator CREATOR + = new Parcelable.Creator() { + public UndoRedoManager createFromParcel(Parcel in) { + return new UndoRedoManager(in); + } + + public UndoRedoManager[] newArray(int size) { + return new UndoRedoManager[size]; + } + }; + + /** recreate object from parcel */ + private UndoRedoManager(Parcel in) { + activeState = in.readInt(); + in.readTypedList(states, GameBoard.CREATOR); + } + } diff --git a/app/src/main/java/org/secuso/privacyfriendlysudoku/game/GameBoard.java b/app/src/main/java/org/secuso/privacyfriendlysudoku/game/GameBoard.java index 27d5af1..ae34c9f 100644 --- a/app/src/main/java/org/secuso/privacyfriendlysudoku/game/GameBoard.java +++ b/app/src/main/java/org/secuso/privacyfriendlysudoku/game/GameBoard.java @@ -1,5 +1,8 @@ package org.secuso.privacyfriendlysudoku.game; +import android.os.Parcel; +import android.os.Parcelable; + import java.util.LinkedList; import java.util.List; @@ -8,7 +11,7 @@ import org.secuso.privacyfriendlysudoku.game.listener.IModelChangedListener; /** * Created by Christopher Beckmann on 06.11.2015. */ -public class GameBoard implements Cloneable { +public class GameBoard implements Cloneable, Parcelable { //private int id; private GameType gameType; @@ -272,4 +275,51 @@ public class GameBoard implements Cloneable { } return false; } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + + dest.writeParcelable(gameType, 0); + dest.writeInt(sectionHeight); + dest.writeInt(sectionWidth); + dest.writeInt(size); + + for(int i = 0; i < field.length; i++) { + dest.writeParcelableArray(field[i], 0); + } + + } + public static final Parcelable.Creator CREATOR + = new Parcelable.Creator() { + public GameBoard createFromParcel(Parcel in) { + return new GameBoard(in); + } + + public GameBoard[] newArray(int size) { + return new GameBoard[size]; + } + }; + + /** recreate object from parcel */ + private GameBoard(Parcel in) { + //private int id; + gameType = in.readParcelable(null); + sectionHeight = in.readInt(); + sectionWidth = in.readInt(); + size = in.readInt(); + + field = new GameCell[size][size]; + + for(int i = 0; i < field.length; i++) { + // TODO: does this work?! + field[i] = (GameCell[]) in.readParcelableArray(null); + } + + modelChangedListeners = new LinkedList<>(); + } } diff --git a/app/src/main/java/org/secuso/privacyfriendlysudoku/game/GameCell.java b/app/src/main/java/org/secuso/privacyfriendlysudoku/game/GameCell.java index 93e28df..2b9e456 100644 --- a/app/src/main/java/org/secuso/privacyfriendlysudoku/game/GameCell.java +++ b/app/src/main/java/org/secuso/privacyfriendlysudoku/game/GameCell.java @@ -1,5 +1,8 @@ package org.secuso.privacyfriendlysudoku.game; +import android.os.Parcel; +import android.os.Parcelable; + import java.util.Arrays; import java.util.LinkedList; import java.util.List; @@ -9,7 +12,7 @@ import org.secuso.privacyfriendlysudoku.game.listener.IModelChangedListener; /** * Created by Chris on 06.11.2015. */ -public class GameCell implements Cloneable { +public class GameCell implements Cloneable, Parcelable { private int row = 0; private int col = 0; @@ -199,4 +202,42 @@ public class GameCell implements Cloneable { m.onModelChange(this); } } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(row); + dest.writeInt(col); + dest.writeInt(value); + dest.writeInt(fixed ? 1 : 0); + dest.writeInt(noteCount); + dest.writeBooleanArray(notes); + dest.writeInt(size); + } + + public static final Parcelable.Creator CREATOR + = new Parcelable.Creator() { + public GameCell createFromParcel(Parcel in) { + return new GameCell(in); + } + + public GameCell[] newArray(int size) { + return new GameCell[size]; + } + }; + + /** recreate object from parcel */ + private GameCell(Parcel in) { + row = in.readInt(); + col = in.readInt(); + value = in.readInt(); + fixed = in.readInt() == 1; + noteCount = in.readInt(); + in.readBooleanArray(notes); + size = in.readInt(); + } } diff --git a/app/src/main/java/org/secuso/privacyfriendlysudoku/game/GameDifficulty.java b/app/src/main/java/org/secuso/privacyfriendlysudoku/game/GameDifficulty.java index f6e2304..44dfe0d 100644 --- a/app/src/main/java/org/secuso/privacyfriendlysudoku/game/GameDifficulty.java +++ b/app/src/main/java/org/secuso/privacyfriendlysudoku/game/GameDifficulty.java @@ -1,5 +1,7 @@ package org.secuso.privacyfriendlysudoku.game; +import android.os.Parcel; +import android.os.Parcelable; import android.support.annotation.StringRes; import java.util.LinkedList; @@ -9,7 +11,7 @@ import org.secuso.privacyfriendlysudoku.ui.view.R; /** * Created by Chris on 18.11.2015. */ -public enum GameDifficulty { +public enum GameDifficulty implements Parcelable { Unspecified(R.string.gametype_unspecified), Easy(R.string.difficulty_easy), @@ -35,4 +37,28 @@ public enum GameDifficulty { return validList; } + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(ordinal()); + dest.writeInt(resID); + } + + public static final Parcelable.Creator CREATOR + = new Parcelable.Creator() { + public GameDifficulty createFromParcel(Parcel in) { + GameDifficulty g = GameDifficulty.values()[in.readInt()]; + g.resID = in.readInt(); + return g; + } + + public GameDifficulty[] newArray(int size) { + return new GameDifficulty[size]; + } + }; + } diff --git a/app/src/main/java/org/secuso/privacyfriendlysudoku/game/GameType.java b/app/src/main/java/org/secuso/privacyfriendlysudoku/game/GameType.java index 49b9a80..4643f1f 100644 --- a/app/src/main/java/org/secuso/privacyfriendlysudoku/game/GameType.java +++ b/app/src/main/java/org/secuso/privacyfriendlysudoku/game/GameType.java @@ -1,5 +1,8 @@ package org.secuso.privacyfriendlysudoku.game; +import android.os.Parcel; +import android.os.Parcelable; + import java.util.LinkedList; import org.secuso.privacyfriendlysudoku.ui.view.R; @@ -7,14 +10,15 @@ import org.secuso.privacyfriendlysudoku.ui.view.R; /** * Created by Chris on 09.11.2015. */ -public enum GameType { +public enum GameType implements Parcelable{ Unspecified(1,1,1,R.string.gametype_unspecified,R.drawable.icon_default_6x6), Default_9x9(9,3,3,R.string.gametype_default_9x9,R.drawable.icon_default_9x9), Default_12x12(12,3,4,R.string.gametype_default_12x12,R.drawable.icon_default_12x12), Default_6x6(6,2,3,R.string.gametype_default_6x6,R.drawable.icon_default_6x6), X_9x9(9,3,3,R.string.gametype_x_9x9,R.drawable.icon_default_9x9), Hyper_9x9(9,3,3,R.string.gametype_hyper_9x9,R.drawable.icon_default_9x9); - //TODO: change pictures for unsepc x9x9 and hyper 9x9 as soon as available + + // change pictures for unsepc x9x9 and hyper 9x9 as soon as available int resIDString; int sectionWidth; int sectionHeight; @@ -53,4 +57,35 @@ public enum GameType { return resIDString; } + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(ordinal()); + dest.writeInt(resIDString); + dest.writeInt(sectionWidth); + dest.writeInt(sectionHeight); + dest.writeInt(size); + dest.writeInt(resIDImage); + } + + public static final Parcelable.Creator CREATOR + = new Parcelable.Creator() { + public GameType createFromParcel(Parcel in) { + GameType g = GameType.values()[in.readInt()]; + g.resIDString = in.readInt(); + g.sectionWidth = in.readInt(); + g.sectionHeight = in.readInt(); + g.size = in.readInt(); + g.resIDImage = in.readInt(); + return g; + } + + public GameType[] newArray(int size) { + return new GameType[size]; + } + }; } diff --git a/app/src/main/java/org/secuso/privacyfriendlysudoku/ui/GameActivity.java b/app/src/main/java/org/secuso/privacyfriendlysudoku/ui/GameActivity.java index d5c2561..6451142 100644 --- a/app/src/main/java/org/secuso/privacyfriendlysudoku/ui/GameActivity.java +++ b/app/src/main/java/org/secuso/privacyfriendlysudoku/ui/GameActivity.java @@ -8,8 +8,10 @@ import android.app.DialogFragment; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; +import android.content.res.Configuration; import android.graphics.Point; import android.os.Bundle; +import android.os.Parcelable; import android.preference.PreferenceActivity; import android.preference.PreferenceManager; import android.support.design.widget.NavigationView; @@ -22,6 +24,7 @@ import android.support.v7.widget.Toolbar; import android.view.Gravity; import android.view.MenuItem; import android.view.WindowManager; +import android.widget.LinearLayout; import android.widget.RatingBar; import android.widget.TextView; import android.widget.Toast; @@ -62,25 +65,45 @@ public class GameActivity extends AppCompatActivity implements NavigationView.On protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + + SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this); GameType gameType = GameType.Unspecified; GameDifficulty gameDifficulty = GameDifficulty.Unspecified; int loadLevelID = 0; boolean loadLevel = false; - Bundle extras = getIntent().getExtras(); - if (extras != null) { - Object o = extras.get("gameType"); - if(o instanceof GameType) { - gameType = (GameType)extras.get("gameType"); + if(savedInstanceState == null) { + + Bundle extras = getIntent().getExtras(); + if (extras != null) { + Object o = extras.get("gameType"); + if (o instanceof GameType) { + gameType = (GameType) extras.get("gameType"); + } + gameDifficulty = (GameDifficulty) (extras.get("gameDifficulty")); + loadLevel = extras.getBoolean("loadLevel", false); + if (loadLevel) { + loadLevelID = extras.getInt("loadLevelID"); + } } - gameDifficulty = (GameDifficulty)(extras.get("gameDifficulty")); - loadLevel = extras.getBoolean("loadLevel", false); - if(loadLevel) { - loadLevelID = extras.getInt("loadLevelID"); + + gameController = new GameController(sharedPref, getApplicationContext()); + + List loadableGames = GameStateManager.getLoadableGameList(); + + if (loadLevel && loadableGames.size() > loadLevelID) { + // load level from GameStateManager + gameController.loadLevel(loadableGames.get(loadLevelID)); + } else { + // load a new level + gameController.loadNewLevel(gameType, gameDifficulty); } + } else { + gameController = savedInstanceState.getParcelable("gameController"); + gameController.removeAllListeners(); + gameSolved = savedInstanceState.getInt("gameSolved") == 1; } - SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this); setContentView(R.layout.activity_game_view); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); @@ -89,19 +112,9 @@ public class GameActivity extends AppCompatActivity implements NavigationView.On //Create new GameField layout = (SudokuFieldLayout)findViewById(R.id.sudokuLayout); - gameController = new GameController(sharedPref, getApplicationContext()); gameController.registerGameSolvedListener(this); gameController.registerTimerListener(this); statistics.setGameController(gameController); - List loadableGames = GameStateManager.getLoadableGameList(); - - if(loadLevel && loadableGames.size() > loadLevelID) { - // load level from GameStateManager - gameController.loadLevel(loadableGames.get(loadLevelID)); - } else { - // load a new level - gameController.loadNewLevel(gameType, gameDifficulty); - } layout.setSettingsAndGame(sharedPref, gameController); @@ -114,8 +127,11 @@ public class GameActivity extends AppCompatActivity implements NavigationView.On Point p = new Point(); getWindowManager().getDefaultDisplay().getSize(p); - //int width = p.x; - keyboard.setKeyBoard(gameController.getSize(), p.x,layout.getHeight()-p.y); + // set keyboard orientation + int orientation = getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT ? + LinearLayout.HORIZONTAL : LinearLayout.VERTICAL; + + keyboard.setKeyBoard(gameController.getSize(), p.x,layout.getHeight()-p.y, orientation); //set Special keys @@ -130,7 +146,6 @@ public class GameActivity extends AppCompatActivity implements NavigationView.On viewName = (TextView) findViewById(R.id.gameModeText); viewName.setText(getString(gameController.getGameType().getStringResID())); - //set Rating bar List difficutyList = GameDifficulty.getValidDifficultyList(); int numberOfStarts = difficutyList.size(); @@ -150,8 +165,16 @@ public class GameActivity extends AppCompatActivity implements NavigationView.On NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view); navigationView.setNavigationItemSelectedListener(this); - // start the game - gameController.startTimer(); + if(gameSolved) { + layout.setEnabled(false); + keyboard.setButtonsEnabled(false); + specialButtonLayout.setButtonsEnabled(false); + gameController.pauseTimer(); + } else { + // start the game + gameController.startTimer(); + } + onTick(gameController.getTime()); } @Override @@ -159,12 +182,14 @@ public class GameActivity extends AppCompatActivity implements NavigationView.On super.onPause(); if(!gameSolved) { gameController.saveGame(this); - gameController.pauseTimer(); } + gameController.deleteTimer(); } @Override public void onResume(){ super.onResume(); + gameController.initTimer(); + if(!gameSolved) { gameController.startTimer(); } @@ -277,7 +302,6 @@ public class GameActivity extends AppCompatActivity implements NavigationView.On @Override public void onTick(int time) { - if(gameSolved) return; //do something not so awesome int seconds = time % 60; @@ -289,6 +313,7 @@ public class GameActivity extends AppCompatActivity implements NavigationView.On h = (hours< 10)? "0"+String.valueOf(hours):String.valueOf(hours); timerView.setText(h + ":" + m + ":" + s); + if(gameSolved) return; // save time gameController.saveGame(this); } @@ -341,4 +366,21 @@ public class GameActivity extends AppCompatActivity implements NavigationView.On return builder.create(); } } + + @Override + public void onSaveInstanceState(Bundle savedInstanceState) { + // Save the user's current game state + + savedInstanceState.putParcelable("gameController", gameController); + savedInstanceState.putInt("gameSolved", gameSolved ? 1 : 0); + + // Always call the superclass so it can save the view hierarchy state + super.onSaveInstanceState(savedInstanceState); + } + + @Override + public void onRestoreInstanceState(Bundle savedInstanceState) { + //super.onRestoreInstanceState(savedInstanceState); + } + } diff --git a/app/src/main/java/org/secuso/privacyfriendlysudoku/ui/MainActivity.java b/app/src/main/java/org/secuso/privacyfriendlysudoku/ui/MainActivity.java index b9f5661..a62b4ab 100644 --- a/app/src/main/java/org/secuso/privacyfriendlysudoku/ui/MainActivity.java +++ b/app/src/main/java/org/secuso/privacyfriendlysudoku/ui/MainActivity.java @@ -31,6 +31,7 @@ import android.widget.RatingBar; import android.widget.TextView; import android.widget.Toast; +import java.io.Serializable; import java.util.LinkedList; import java.util.List; @@ -176,8 +177,8 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On // send everything to game activity i = new Intent(this, GameActivity.class); - i.putExtra("gameType", gameType); - i.putExtra("gameDifficulty", gameDifficulty); + i.putExtra("gameType", (Serializable)gameType); + i.putExtra("gameDifficulty", (Serializable)gameDifficulty); } else { newLevelManager.checkAndRestock(); Toast t = Toast.makeText(getApplicationContext(), R.string.generating, Toast.LENGTH_SHORT); diff --git a/app/src/main/java/org/secuso/privacyfriendlysudoku/ui/view/SudokuKeyboardLayout.java b/app/src/main/java/org/secuso/privacyfriendlysudoku/ui/view/SudokuKeyboardLayout.java index 75f0330..884a539 100644 --- a/app/src/main/java/org/secuso/privacyfriendlysudoku/ui/view/SudokuKeyboardLayout.java +++ b/app/src/main/java/org/secuso/privacyfriendlysudoku/ui/view/SudokuKeyboardLayout.java @@ -1,5 +1,6 @@ package org.secuso.privacyfriendlysudoku.ui.view; +import android.app.Activity; import android.content.Context; import android.graphics.Canvas; import android.util.AttributeSet; @@ -52,7 +53,7 @@ public class SudokuKeyboardLayout extends LinearLayout implements IHighlightChan } } - public void setKeyBoard(int size,int width, int height) { + public void setKeyBoard(int size,int width, int height, int orientation) { LayoutParams p; int number = 0; int numberOfButtonsPerRow = (size % 2 == 0) ? size/2 :(size+1)/2; @@ -60,16 +61,19 @@ public class SudokuKeyboardLayout extends LinearLayout implements IHighlightChan buttons = new SudokuButton[numberOfButtons]; - //set layout parameters and init Layouts for (int i = 0; i < 2; i++) { - p = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,0,1); + if(orientation == LinearLayout.HORIZONTAL) { + p = new LayoutParams(LayoutParams.MATCH_PARENT, 0, 1); + } else { + p = new LayoutParams(0, LayoutParams.MATCH_PARENT, 1); + } //if (i == 0) p.bottomMargin=10; else p.topMargin=10; p.setMargins(0,5,0,5); layouts[i] = new LinearLayout(getContext(),null); layouts[i].setLayoutParams(p); layouts[i].setWeightSum(numberOfButtonsPerRow); - layouts[i].setOrientation(LinearLayout.HORIZONTAL); + layouts[i].setOrientation(orientation); addView(layouts[i]); } @@ -81,7 +85,11 @@ public class SudokuKeyboardLayout extends LinearLayout implements IHighlightChan for (int i = 0; i < numberOfButtonsPerRow; i++){ int buttonIndex = i + layoutNumber * numberOfButtonsPerRow; buttons[buttonIndex] = new SudokuButton(getContext(),null); - p = new LayoutParams(0, LayoutParams.MATCH_PARENT,1); + if(orientation == LinearLayout.HORIZONTAL) { + p = new LayoutParams(0, LayoutParams.MATCH_PARENT, 1); + } else { + p = new LayoutParams(LayoutParams.MATCH_PARENT, 0, 1); + } p.setMargins(5,5,5,5); buttons[buttonIndex].setLayoutParams(p); /* removed GridLayout because of bad scaling will use now a Linearlayout diff --git a/app/src/main/java/org/secuso/privacyfriendlysudoku/ui/view/SudokuSpecialButtonLayout.java b/app/src/main/java/org/secuso/privacyfriendlysudoku/ui/view/SudokuSpecialButtonLayout.java index 2791586..fd229b9 100644 --- a/app/src/main/java/org/secuso/privacyfriendlysudoku/ui/view/SudokuSpecialButtonLayout.java +++ b/app/src/main/java/org/secuso/privacyfriendlysudoku/ui/view/SudokuSpecialButtonLayout.java @@ -58,17 +58,7 @@ public class SudokuSpecialButtonLayout extends LinearLayout implements IHighligh // rotates the Drawable gameController.setNoteStatus(!gameController.getNoteStatus()); keyboard.updateNotesEnabled(); - - bitMap = BitmapFactory.decodeResource(getResources(), btn.getType().getResID()); - bitResult = Bitmap.createBitmap(bitMap.getWidth(), bitMap.getHeight(), Bitmap.Config.ARGB_8888); - - canvas = new Canvas(bitResult); - canvas.rotate(gameController.getNoteStatus() ? 45.0f : 0.0f, bitMap.getWidth()/2, bitMap.getHeight()/2); - canvas.drawBitmap(bitMap, 0, 0, null); - - btn.setImageBitmap(bitResult); - btn.setBackgroundResource(gameController.getNoteStatus() ? R.drawable.numpad_highlighted_three : R.drawable.numpad_highlighted_four); - + onHighlightChanged(); break; case Do: gameController.ReDo(); @@ -117,8 +107,8 @@ public class SudokuSpecialButtonLayout extends LinearLayout implements IHighligh fragmentManager = fm; keyboard=key; gameController = gc; - if(gc != null) { - gc.registerHighlightChangedListener(this); + if(gameController != null) { + gameController.registerHighlightChangedListener(this); } fixedButtons = new SudokuSpecialButton[fixedButtonsCount]; LayoutParams p; @@ -166,6 +156,17 @@ public class SudokuSpecialButtonLayout extends LinearLayout implements IHighligh fixedButtons[i].setBackgroundResource(gameController.isRedoAvailable() ? R.drawable.numpad_highlighted_four : R.drawable.inactive_button); break; + case NoteToggle: + bitMap = BitmapFactory.decodeResource(getResources(), fixedButtons[i].getType().getResID()); + bitResult = Bitmap.createBitmap(bitMap.getWidth(), bitMap.getHeight(), Bitmap.Config.ARGB_8888); + + canvas = new Canvas(bitResult); + canvas.rotate(gameController.getNoteStatus() ? 45.0f : 0.0f, bitMap.getWidth()/2, bitMap.getHeight()/2); + canvas.drawBitmap(bitMap, 0, 0, null); + + fixedButtons[i].setImageBitmap(bitResult); + fixedButtons[i].setBackgroundResource(gameController.getNoteStatus() ? R.drawable.numpad_highlighted_three : R.drawable.numpad_highlighted_four); + break; default: break; } diff --git a/app/src/main/res/layout-land/content_game_view.xml b/app/src/main/res/layout-land/content_game_view.xml index 0107be5..58929cb 100644 --- a/app/src/main/res/layout-land/content_game_view.xml +++ b/app/src/main/res/layout-land/content_game_view.xml @@ -11,40 +11,42 @@ app:layout_behavior="@string/appbar_scrolling_view_behavior" tools:context="tu_darmstadt.sudoku.activity.GameActivity"> + + + + + - + android:weightSum="2"> - - - - - - - - - + From 54bf935685d232e5aee1e06ff5c1d0fecfeb04be Mon Sep 17 00:00:00 2001 From: Christopher Beckmann Date: Sun, 31 Jan 2016 01:06:34 +0100 Subject: [PATCH 2/4] Modified the Landscape GameView a bit. Looks a lot cleaner now. Not tested on smaller and bigger devices yet. Also added the landscape version of the stats page. --- .../ui/GameActivity.java | 4 +- .../ui/view/SudokuSpecialButtonLayout.java | 9 +- .../res/layout-land/content_game_view.xml | 70 ++-- .../main/res/layout-land/fragment_stats.xml | 202 +++++------ .../res/layout-xlarge-land/fragment_stats.xml | 316 ++++++++++++++++++ .../main/res/layout-xlarge/fragment_stats.xml | 316 ++++++++++++++++++ 6 files changed, 786 insertions(+), 131 deletions(-) create mode 100644 app/src/main/res/layout-xlarge-land/fragment_stats.xml create mode 100644 app/src/main/res/layout-xlarge/fragment_stats.xml diff --git a/app/src/main/java/org/secuso/privacyfriendlysudoku/ui/GameActivity.java b/app/src/main/java/org/secuso/privacyfriendlysudoku/ui/GameActivity.java index 6451142..b8606c2 100644 --- a/app/src/main/java/org/secuso/privacyfriendlysudoku/ui/GameActivity.java +++ b/app/src/main/java/org/secuso/privacyfriendlysudoku/ui/GameActivity.java @@ -100,6 +100,8 @@ public class GameActivity extends AppCompatActivity implements NavigationView.On } } else { gameController = savedInstanceState.getParcelable("gameController"); + // in case we get the same object back + // because parceling the Object does not always parcel it. Only if needed. gameController.removeAllListeners(); gameSolved = savedInstanceState.getInt("gameSolved") == 1; } @@ -136,7 +138,7 @@ public class GameActivity extends AppCompatActivity implements NavigationView.On //set Special keys specialButtonLayout = (SudokuSpecialButtonLayout) findViewById(R.id.sudokuSpecialLayout); - specialButtonLayout.setButtons(p.x, gameController, keyboard, getFragmentManager()); + specialButtonLayout.setButtons(p.x, gameController, keyboard, getFragmentManager(), orientation); //set TimerView timerView = (TextView)findViewById(R.id.timerView); diff --git a/app/src/main/java/org/secuso/privacyfriendlysudoku/ui/view/SudokuSpecialButtonLayout.java b/app/src/main/java/org/secuso/privacyfriendlysudoku/ui/view/SudokuSpecialButtonLayout.java index fd229b9..f431f55 100644 --- a/app/src/main/java/org/secuso/privacyfriendlysudoku/ui/view/SudokuSpecialButtonLayout.java +++ b/app/src/main/java/org/secuso/privacyfriendlysudoku/ui/view/SudokuSpecialButtonLayout.java @@ -103,7 +103,7 @@ public class SudokuSpecialButtonLayout extends LinearLayout implements IHighligh } } - public void setButtons(int width, GameController gc, SudokuKeyboardLayout key, FragmentManager fm) { + public void setButtons(int width, GameController gc, SudokuKeyboardLayout key, FragmentManager fm, int orientation) { fragmentManager = fm; keyboard=key; gameController = gc; @@ -116,7 +116,12 @@ public class SudokuSpecialButtonLayout extends LinearLayout implements IHighligh //ArrayList type = (ArrayList) SudokuButtonType.getSpecialButtons(); for (SudokuButtonType t : getSpecialButtons()){ fixedButtons[i] = new SudokuSpecialButton(getContext(),null); - p = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT,1); + if(orientation == LinearLayout.HORIZONTAL) { + p = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, 1); + } else { + p = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, 1); + fixedButtons[i].setPadding(25, 0, 25, 0); + } p.setMargins(5, 5, 5, 5); //int width2 =width/(fixedButtonsCount); diff --git a/app/src/main/res/layout-land/content_game_view.xml b/app/src/main/res/layout-land/content_game_view.xml index 58929cb..619a7ff 100644 --- a/app/src/main/res/layout-land/content_game_view.xml +++ b/app/src/main/res/layout-land/content_game_view.xml @@ -11,42 +11,42 @@ app:layout_behavior="@string/appbar_scrolling_view_behavior" tools:context="tu_darmstadt.sudoku.activity.GameActivity"> - + - + - - - - - - + diff --git a/app/src/main/res/layout-land/fragment_stats.xml b/app/src/main/res/layout-land/fragment_stats.xml index 34a4496..bc719a9 100644 --- a/app/src/main/res/layout-land/fragment_stats.xml +++ b/app/src/main/res/layout-land/fragment_stats.xml @@ -1,20 +1,104 @@ + + + + + + + + + + + + + + + + android:layout_weight="0.5"> + + + + + + + + - - - - - - - - - - - - - - - - - + + - - + - - - - - - - + + - + + - - diff --git a/app/src/main/res/layout-xlarge-land/fragment_stats.xml b/app/src/main/res/layout-xlarge-land/fragment_stats.xml new file mode 100644 index 0000000..34a4496 --- /dev/null +++ b/app/src/main/res/layout-xlarge-land/fragment_stats.xml @@ -0,0 +1,316 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout-xlarge/fragment_stats.xml b/app/src/main/res/layout-xlarge/fragment_stats.xml new file mode 100644 index 0000000..34a4496 --- /dev/null +++ b/app/src/main/res/layout-xlarge/fragment_stats.xml @@ -0,0 +1,316 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From a4e7a693f9ddee8e3eb4dd165505a4762cdad0ee Mon Sep 17 00:00:00 2001 From: Christopher Beckmann Date: Sun, 31 Jan 2016 12:46:22 +0100 Subject: [PATCH 3/4] Corrected Parceable Implementation. Wasn't aware that my code was not called. Had to force it to clear the app out of the memory. --- .../controller/GameController.java | 18 ++++++++++++------ .../privacyfriendlysudoku/game/GameBoard.java | 7 +++---- .../privacyfriendlysudoku/game/GameCell.java | 5 +++-- .../privacyfriendlysudoku/game/GameType.java | 3 +-- .../privacyfriendlysudoku/ui/GameActivity.java | 1 + 5 files changed, 20 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/org/secuso/privacyfriendlysudoku/controller/GameController.java b/app/src/main/java/org/secuso/privacyfriendlysudoku/controller/GameController.java index f7120bd..8ffc158 100644 --- a/app/src/main/java/org/secuso/privacyfriendlysudoku/controller/GameController.java +++ b/app/src/main/java/org/secuso/privacyfriendlysudoku/controller/GameController.java @@ -54,7 +54,7 @@ public class GameController implements IModelChangedListener, Parcelable { private int sectionWidth; private int usedHints = 0; private GameBoard gameBoard; - private int[] solution; + private int[] solution = new int[0]; private GameType gameType; private GameDifficulty difficulty; private CellConflictList errorList = new CellConflictList(); @@ -699,6 +699,7 @@ public class GameController implements IModelChangedListener, Parcelable { out.writeInt(usedHints); out.writeInt(time); + out.writeInt(solution.length); out.writeIntArray(solution); out.writeInt(noteStatus ? 1 : 0); @@ -738,18 +739,18 @@ public class GameController implements IModelChangedListener, Parcelable { usedHints = in.readInt(); time = in.readInt(); + solution = new int[in.readInt()]; in.readIntArray(solution); noteStatus = in.readInt() == 1; notifiedOnSolvedListeners = in.readInt() == 1; - gameType = in.readParcelable(null); - difficulty = in.readParcelable(null); - gameBoard = in.readParcelable(null); - undoRedoManager = in.readParcelable(null); + gameType = in.readParcelable(GameType.class.getClassLoader()); + difficulty = in.readParcelable(GameDifficulty.class.getClassLoader()); + gameBoard = in.readParcelable(GameBoard.class.getClassLoader()); + undoRedoManager = in.readParcelable(UndoRedoManager.class.getClassLoader()); removeAllListeners(); - } public void removeAllListeners() { @@ -758,4 +759,9 @@ public class GameController implements IModelChangedListener, Parcelable { hintListener = new LinkedList<>(); timerListeners = new LinkedList<>(); } + + public void setContextAndSettings(Context applicationContext, SharedPreferences sharedPref) { + context = applicationContext; + setSettings(sharedPref); + } } diff --git a/app/src/main/java/org/secuso/privacyfriendlysudoku/game/GameBoard.java b/app/src/main/java/org/secuso/privacyfriendlysudoku/game/GameBoard.java index ae34c9f..febef69 100644 --- a/app/src/main/java/org/secuso/privacyfriendlysudoku/game/GameBoard.java +++ b/app/src/main/java/org/secuso/privacyfriendlysudoku/game/GameBoard.java @@ -290,7 +290,7 @@ public class GameBoard implements Cloneable, Parcelable { dest.writeInt(size); for(int i = 0; i < field.length; i++) { - dest.writeParcelableArray(field[i], 0); + dest.writeTypedArray(field[i], 0); } } @@ -308,7 +308,7 @@ public class GameBoard implements Cloneable, Parcelable { /** recreate object from parcel */ private GameBoard(Parcel in) { //private int id; - gameType = in.readParcelable(null); + gameType = in.readParcelable(GameType.class.getClassLoader()); sectionHeight = in.readInt(); sectionWidth = in.readInt(); size = in.readInt(); @@ -316,8 +316,7 @@ public class GameBoard implements Cloneable, Parcelable { field = new GameCell[size][size]; for(int i = 0; i < field.length; i++) { - // TODO: does this work?! - field[i] = (GameCell[]) in.readParcelableArray(null); + field[i] = in.createTypedArray(GameCell.CREATOR); } modelChangedListeners = new LinkedList<>(); diff --git a/app/src/main/java/org/secuso/privacyfriendlysudoku/game/GameCell.java b/app/src/main/java/org/secuso/privacyfriendlysudoku/game/GameCell.java index 2b9e456..928d72d 100644 --- a/app/src/main/java/org/secuso/privacyfriendlysudoku/game/GameCell.java +++ b/app/src/main/java/org/secuso/privacyfriendlysudoku/game/GameCell.java @@ -213,10 +213,10 @@ public class GameCell implements Cloneable, Parcelable { dest.writeInt(row); dest.writeInt(col); dest.writeInt(value); + dest.writeInt(size); dest.writeInt(fixed ? 1 : 0); dest.writeInt(noteCount); dest.writeBooleanArray(notes); - dest.writeInt(size); } public static final Parcelable.Creator CREATOR @@ -235,9 +235,10 @@ public class GameCell implements Cloneable, Parcelable { row = in.readInt(); col = in.readInt(); value = in.readInt(); + size = in.readInt(); fixed = in.readInt() == 1; noteCount = in.readInt(); + notes = new boolean[size]; in.readBooleanArray(notes); - size = in.readInt(); } } diff --git a/app/src/main/java/org/secuso/privacyfriendlysudoku/game/GameType.java b/app/src/main/java/org/secuso/privacyfriendlysudoku/game/GameType.java index 4643f1f..a93478a 100644 --- a/app/src/main/java/org/secuso/privacyfriendlysudoku/game/GameType.java +++ b/app/src/main/java/org/secuso/privacyfriendlysudoku/game/GameType.java @@ -72,8 +72,7 @@ public enum GameType implements Parcelable{ dest.writeInt(resIDImage); } - public static final Parcelable.Creator CREATOR - = new Parcelable.Creator() { + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { public GameType createFromParcel(Parcel in) { GameType g = GameType.values()[in.readInt()]; g.resIDString = in.readInt(); diff --git a/app/src/main/java/org/secuso/privacyfriendlysudoku/ui/GameActivity.java b/app/src/main/java/org/secuso/privacyfriendlysudoku/ui/GameActivity.java index b8606c2..ba358ee 100644 --- a/app/src/main/java/org/secuso/privacyfriendlysudoku/ui/GameActivity.java +++ b/app/src/main/java/org/secuso/privacyfriendlysudoku/ui/GameActivity.java @@ -103,6 +103,7 @@ public class GameActivity extends AppCompatActivity implements NavigationView.On // in case we get the same object back // because parceling the Object does not always parcel it. Only if needed. gameController.removeAllListeners(); + gameController.setContextAndSettings(getApplicationContext(), sharedPref); gameSolved = savedInstanceState.getInt("gameSolved") == 1; } From 229f167c2e2ff2987165527da4d4705b4a579c82 Mon Sep 17 00:00:00 2001 From: Christopher Beckmann Date: Sun, 31 Jan 2016 14:10:33 +0100 Subject: [PATCH 4/4] Fixed the Delete Button. It would not delete notes. --- .../controller/GameController.java | 7 +++-- .../privacyfriendlysudoku/game/GameBoard.java | 28 ++++++------------- .../privacyfriendlysudoku/game/GameCell.java | 10 +++++++ 3 files changed, 24 insertions(+), 21 deletions(-) diff --git a/app/src/main/java/org/secuso/privacyfriendlysudoku/controller/GameController.java b/app/src/main/java/org/secuso/privacyfriendlysudoku/controller/GameController.java index 8ffc158..8e60fb7 100644 --- a/app/src/main/java/org/secuso/privacyfriendlysudoku/controller/GameController.java +++ b/app/src/main/java/org/secuso/privacyfriendlysudoku/controller/GameController.java @@ -160,7 +160,7 @@ public class GameController implements IModelChangedListener, Parcelable { public int[] solve() { - if(solution == null) { + if(solution == null || solution.length == 0) { solution = qqWingController.solve(gameBoard); } return solution; @@ -469,7 +469,7 @@ public class GameController implements IModelChangedListener, Parcelable { } public void deleteSelectedCellsValue() { - if(isValidCellSelected() && getSelectedCellsValue() != 0) { + if(isValidCellSelected()) { deleteValue(selectedRow, selectedCol); // add state to undo undoRedoManager.addState(gameBoard); @@ -751,6 +751,9 @@ public class GameController implements IModelChangedListener, Parcelable { undoRedoManager = in.readParcelable(UndoRedoManager.class.getClassLoader()); removeAllListeners(); + + gameBoard.removeAllListeners(); + gameBoard.registerOnModelChangeListener(this); } public void removeAllListeners() { diff --git a/app/src/main/java/org/secuso/privacyfriendlysudoku/game/GameBoard.java b/app/src/main/java/org/secuso/privacyfriendlysudoku/game/GameBoard.java index febef69..defb466 100644 --- a/app/src/main/java/org/secuso/privacyfriendlysudoku/game/GameBoard.java +++ b/app/src/main/java/org/secuso/privacyfriendlysudoku/game/GameBoard.java @@ -20,7 +20,6 @@ public class GameBoard implements Cloneable, Parcelable { //private List additionalSections private int size; private GameCell[][] field; - private List modelChangedListeners = new LinkedList<>(); public GameBoard(GameType gameType) { this.gameType = gameType; @@ -223,7 +222,6 @@ public class GameBoard implements Cloneable, Parcelable { } public void registerOnModelChangeListener(final IModelChangedListener listener) { - if(!modelChangedListeners.contains(listener)) { actionOnCells(new ICellAction() { @Override public Boolean action(GameCell gc, Boolean existing) { @@ -231,22 +229,6 @@ public class GameBoard implements Cloneable, Parcelable { return existing; } }, false); - modelChangedListeners.add(listener); - } - } - - public void deleteOnModelChangeListener(final IModelChangedListener listener) { - if(modelChangedListeners.contains(listener)) { - actionOnCells(new ICellAction() { - - @Override - public Boolean action(GameCell gc, Boolean existing) { - gc.removeOnModelChangeListener(listener); - return existing; - } - }, false); - modelChangedListeners.remove(listener); - } } @Override @@ -318,7 +300,15 @@ public class GameBoard implements Cloneable, Parcelable { for(int i = 0; i < field.length; i++) { field[i] = in.createTypedArray(GameCell.CREATOR); } + } - modelChangedListeners = new LinkedList<>(); + public void removeAllListeners() { + actionOnCells(new ICellAction() { + @Override + public Boolean action(GameCell gc, Boolean existing) { + gc.removeAllListeners(); + return existing; + } + }, false); } } diff --git a/app/src/main/java/org/secuso/privacyfriendlysudoku/game/GameCell.java b/app/src/main/java/org/secuso/privacyfriendlysudoku/game/GameCell.java index 928d72d..62dbcc4 100644 --- a/app/src/main/java/org/secuso/privacyfriendlysudoku/game/GameCell.java +++ b/app/src/main/java/org/secuso/privacyfriendlysudoku/game/GameCell.java @@ -2,10 +2,14 @@ package org.secuso.privacyfriendlysudoku.game; import android.os.Parcel; import android.os.Parcelable; +import android.support.annotation.NonNull; import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; import java.util.LinkedList; import java.util.List; +import java.util.ListIterator; import org.secuso.privacyfriendlysudoku.game.listener.IModelChangedListener; @@ -240,5 +244,11 @@ public class GameCell implements Cloneable, Parcelable { noteCount = in.readInt(); notes = new boolean[size]; in.readBooleanArray(notes); + + removeAllListeners(); + } + + public void removeAllListeners() { + modelChangedListeners = new LinkedList<>(); } }