Merge pull request #57 from SecUSo/Sudoku-v3.0
Sudoku v3.0 - Added Darktheme - Added Custom Sudokus - Added Daily Sudoku - Added Sudoku Sharing - Several Bugfixes Fixes #45, Fixes #24
This commit is contained in:
commit
70a0a80b5f
188 changed files with 6239 additions and 789 deletions
|
@ -11,8 +11,8 @@ android {
|
||||||
applicationId "org.secuso.privacyfriendlysudoku"
|
applicationId "org.secuso.privacyfriendlysudoku"
|
||||||
minSdkVersion 16
|
minSdkVersion 16
|
||||||
targetSdkVersion 29
|
targetSdkVersion 29
|
||||||
versionCode 8
|
versionCode 9
|
||||||
versionName "2.2.1"
|
versionName "3.0.0"
|
||||||
vectorDrawables.useSupportLibrary = true
|
vectorDrawables.useSupportLibrary = true
|
||||||
}
|
}
|
||||||
buildTypes {
|
buildTypes {
|
||||||
|
@ -25,16 +25,23 @@ android {
|
||||||
sourceCompatibility JavaVersion.VERSION_1_8
|
sourceCompatibility JavaVersion.VERSION_1_8
|
||||||
targetCompatibility JavaVersion.VERSION_1_8
|
targetCompatibility JavaVersion.VERSION_1_8
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dataBinding {
|
||||||
|
enabled = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
||||||
|
implementation 'androidx.preference:preference:1.1.1'
|
||||||
testImplementation 'junit:junit:4.12'
|
testImplementation 'junit:junit:4.12'
|
||||||
implementation 'androidx.core:core:1.2.0'
|
implementation 'androidx.core:core:1.3.2'
|
||||||
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
|
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
|
||||||
implementation 'androidx.legacy:legacy-support-v13:1.0.0'
|
implementation 'androidx.legacy:legacy-support-v13:1.0.0'
|
||||||
implementation 'androidx.appcompat:appcompat:1.1.0'
|
implementation 'androidx.appcompat:appcompat:1.2.0'
|
||||||
implementation 'com.google.android.material:material:1.1.0'
|
implementation 'com.google.android.material:material:1.2.1'
|
||||||
implementation 'androidx.legacy:legacy-support-core-ui:1.0.0'
|
implementation 'androidx.legacy:legacy-support-core-ui:1.0.0'
|
||||||
implementation 'androidx.legacy:legacy-support-core-utils:1.0.0'
|
implementation 'androidx.legacy:legacy-support-core-utils:1.0.0'
|
||||||
|
implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,34 +2,39 @@
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="org.secuso.privacyfriendlysudoku.ui.view">
|
package="org.secuso.privacyfriendlysudoku.ui.view">
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
|
android:name="org.secuso.privacyfriendlysudoku.SudokuApp"
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/AppTheme"
|
android:theme="@style/AppTheme">
|
||||||
android:name="org.secuso.privacyfriendlysudoku.SudokuApp">
|
|
||||||
<activity
|
<activity
|
||||||
android:name="org.secuso.privacyfriendlysudoku.ui.SplashActivity"
|
android:name="org.secuso.privacyfriendlysudoku.ui.SplashActivity"
|
||||||
android:theme="@style/SplashTheme">
|
android:theme="@style/SplashTheme">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name="org.secuso.privacyfriendlysudoku.ui.MainActivity"
|
android:name="org.secuso.privacyfriendlysudoku.ui.MainActivity"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:theme="@style/AppTheme.NoActionBar">
|
android:theme="@style/AppTheme.NoActionBar" />
|
||||||
</activity>
|
|
||||||
<activity
|
<activity
|
||||||
android:name="org.secuso.privacyfriendlysudoku.ui.TutorialActivity"
|
android:name="org.secuso.privacyfriendlysudoku.ui.TutorialActivity"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:theme="@style/AppTheme.NoActionBar">
|
android:theme="@style/AppTheme.NoActionBar" />
|
||||||
</activity>
|
<activity
|
||||||
|
android:name="org.secuso.privacyfriendlysudoku.ui.DailySudokuActivity"
|
||||||
|
android:label="@string/Sudoku"
|
||||||
|
android:theme="@style/AppTheme.NoActionBar" />
|
||||||
|
<activity
|
||||||
|
android:name="org.secuso.privacyfriendlysudoku.ui.CreateSudokuActivity"
|
||||||
|
android:label="@string/Sudoku"
|
||||||
|
android:theme="@style/AppTheme.NoActionBar" />
|
||||||
<activity
|
<activity
|
||||||
android:name="org.secuso.privacyfriendlysudoku.ui.SettingsActivity"
|
android:name="org.secuso.privacyfriendlysudoku.ui.SettingsActivity"
|
||||||
android:label="@string/title_activity_settings"
|
android:label="@string/title_activity_settings"
|
||||||
|
@ -37,7 +42,26 @@
|
||||||
<activity
|
<activity
|
||||||
android:name="org.secuso.privacyfriendlysudoku.ui.GameActivity"
|
android:name="org.secuso.privacyfriendlysudoku.ui.GameActivity"
|
||||||
android:label="@string/title_activity_game_view"
|
android:label="@string/title_activity_game_view"
|
||||||
android:theme="@style/AppTheme.NoActionBar" />
|
android:launchMode="singleTask"
|
||||||
|
android:theme="@style/AppTheme.NoActionBar">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
<data android:scheme="sudoku" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
<data
|
||||||
|
android:host="sudoku.secuso.org"
|
||||||
|
android:scheme="http" />
|
||||||
|
<data
|
||||||
|
android:host="sudoku.secuso.org"
|
||||||
|
android:scheme="https" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
<activity android:name="org.secuso.privacyfriendlysudoku.ui.AboutActivity" />
|
<activity android:name="org.secuso.privacyfriendlysudoku.ui.AboutActivity" />
|
||||||
<activity android:name="org.secuso.privacyfriendlysudoku.ui.LoadGameActivity" />
|
<activity android:name="org.secuso.privacyfriendlysudoku.ui.LoadGameActivity" />
|
||||||
<activity
|
<activity
|
||||||
|
|
|
@ -1,3 +1,19 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package org.secuso.privacyfriendlysudoku;
|
package org.secuso.privacyfriendlysudoku;
|
||||||
|
|
||||||
import android.app.Application;
|
import android.app.Application;
|
||||||
|
|
|
@ -1,3 +1,19 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package org.secuso.privacyfriendlysudoku.controller;
|
package org.secuso.privacyfriendlysudoku.controller;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
@ -6,7 +22,10 @@ import android.os.Handler;
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
|
|
||||||
|
import org.secuso.privacyfriendlysudoku.controller.database.DatabaseHelper;
|
||||||
|
import org.secuso.privacyfriendlysudoku.controller.database.model.DailySudoku;
|
||||||
import org.secuso.privacyfriendlysudoku.controller.helper.GameInfoContainer;
|
import org.secuso.privacyfriendlysudoku.controller.helper.GameInfoContainer;
|
||||||
|
import org.secuso.privacyfriendlysudoku.controller.qqwing.QQWing;
|
||||||
import org.secuso.privacyfriendlysudoku.game.CellConflict;
|
import org.secuso.privacyfriendlysudoku.game.CellConflict;
|
||||||
import org.secuso.privacyfriendlysudoku.game.CellConflictList;
|
import org.secuso.privacyfriendlysudoku.game.CellConflictList;
|
||||||
import org.secuso.privacyfriendlysudoku.game.GameBoard;
|
import org.secuso.privacyfriendlysudoku.game.GameBoard;
|
||||||
|
@ -19,7 +38,10 @@ import org.secuso.privacyfriendlysudoku.game.listener.IHighlightChangedListener;
|
||||||
import org.secuso.privacyfriendlysudoku.game.listener.IHintListener;
|
import org.secuso.privacyfriendlysudoku.game.listener.IHintListener;
|
||||||
import org.secuso.privacyfriendlysudoku.game.listener.IModelChangedListener;
|
import org.secuso.privacyfriendlysudoku.game.listener.IModelChangedListener;
|
||||||
import org.secuso.privacyfriendlysudoku.game.listener.ITimerListener;
|
import org.secuso.privacyfriendlysudoku.game.listener.ITimerListener;
|
||||||
|
import org.secuso.privacyfriendlysudoku.ui.GameActivity;
|
||||||
|
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Timer;
|
import java.util.Timer;
|
||||||
|
@ -32,6 +54,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
public class GameController implements IModelChangedListener, Parcelable {
|
public class GameController implements IModelChangedListener, Parcelable {
|
||||||
|
|
||||||
// General
|
// General
|
||||||
|
public static final int DAILY_SUDOKU_ID = Integer.MAX_VALUE - 1;
|
||||||
private SharedPreferences settings;
|
private SharedPreferences settings;
|
||||||
|
|
||||||
// View
|
// View
|
||||||
|
@ -57,6 +80,7 @@ public class GameController implements IModelChangedListener, Parcelable {
|
||||||
private GameType gameType;
|
private GameType gameType;
|
||||||
private GameDifficulty difficulty;
|
private GameDifficulty difficulty;
|
||||||
private CellConflictList errorList = new CellConflictList();
|
private CellConflictList errorList = new CellConflictList();
|
||||||
|
private boolean gameIsCustom;
|
||||||
|
|
||||||
// Undo Redo
|
// Undo Redo
|
||||||
private UndoRedoManager undoRedoManager;
|
private UndoRedoManager undoRedoManager;
|
||||||
|
@ -84,6 +108,7 @@ public class GameController implements IModelChangedListener, Parcelable {
|
||||||
public GameController(GameType type, SharedPreferences pref, Context context) {
|
public GameController(GameType type, SharedPreferences pref, Context context) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.gameBoard = new GameBoard(type);
|
this.gameBoard = new GameBoard(type);
|
||||||
|
this.gameIsCustom = false;
|
||||||
|
|
||||||
setGameType(type);
|
setGameType(type);
|
||||||
setSettings(pref);
|
setSettings(pref);
|
||||||
|
@ -95,6 +120,8 @@ public class GameController implements IModelChangedListener, Parcelable {
|
||||||
return gameID;
|
return gameID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean gameIsCustom() { return gameIsCustom; }
|
||||||
|
|
||||||
public void loadNewLevel(GameType type, GameDifficulty difficulty) {
|
public void loadNewLevel(GameType type, GameDifficulty difficulty) {
|
||||||
NewLevelManager newLevelManager = NewLevelManager.getInstance(context, settings);
|
NewLevelManager newLevelManager = NewLevelManager.getInstance(context, settings);
|
||||||
|
|
||||||
|
@ -105,6 +132,23 @@ public class GameController implements IModelChangedListener, Parcelable {
|
||||||
newLevelManager.checkAndRestock();
|
newLevelManager.checkAndRestock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void loadNewDailySudokuLevel() {
|
||||||
|
NewLevelManager newLevelManager = NewLevelManager.getInstance(context, settings);
|
||||||
|
|
||||||
|
// generate the daily sudoku
|
||||||
|
int[] level = newLevelManager.loadDailySudoku();
|
||||||
|
|
||||||
|
// calculate the difficulty of the daily sudoku
|
||||||
|
QQWing difficultyCheck = new QQWing(GameType.Default_9x9, GameDifficulty.Unspecified);
|
||||||
|
difficultyCheck.setRecordHistory(true);
|
||||||
|
difficultyCheck.setPuzzle(level);
|
||||||
|
difficultyCheck.solve();
|
||||||
|
|
||||||
|
loadLevel(new GameInfoContainer(DAILY_SUDOKU_ID, difficultyCheck.getDifficulty(),
|
||||||
|
GameType.Default_9x9, level, null, null));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public int getTime() {
|
public int getTime() {
|
||||||
return time;
|
return time;
|
||||||
}
|
}
|
||||||
|
@ -117,6 +161,7 @@ public class GameController implements IModelChangedListener, Parcelable {
|
||||||
this.difficulty = gic.getDifficulty();
|
this.difficulty = gic.getDifficulty();
|
||||||
this.time = gic.getTimePlayed();
|
this.time = gic.getTimePlayed();
|
||||||
this.usedHints = gic.getHintsUsed();
|
this.usedHints = gic.getHintsUsed();
|
||||||
|
this.gameIsCustom = gic.isCustom();
|
||||||
|
|
||||||
setGameType(gic.getGameType());
|
setGameType(gic.getGameType());
|
||||||
this.gameBoard = new GameBoard(gic.getGameType());
|
this.gameBoard = new GameBoard(gic.getGameType());
|
||||||
|
@ -305,7 +350,7 @@ public class GameController implements IModelChangedListener, Parcelable {
|
||||||
|
|
||||||
SharedPreferences.Editor editor = settings.edit();
|
SharedPreferences.Editor editor = settings.edit();
|
||||||
// is anyone ever gonna play so many levels? :)
|
// is anyone ever gonna play so many levels? :)
|
||||||
if(gameID == Integer.MAX_VALUE-1) {
|
if(gameID == DAILY_SUDOKU_ID - 1) {
|
||||||
editor.putInt("lastGameID", 1);
|
editor.putInt("lastGameID", 1);
|
||||||
} else {
|
} else {
|
||||||
editor.putInt("lastGameID", gameID);
|
editor.putInt("lastGameID", gameID);
|
||||||
|
@ -318,6 +363,31 @@ public class GameController implements IModelChangedListener, Parcelable {
|
||||||
fm.saveGameState(this);
|
fm.saveGameState(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save progress on the current daily sudoku
|
||||||
|
* @param context the context in which this method is called
|
||||||
|
*/
|
||||||
|
public void saveDailySudoku(Context context) {
|
||||||
|
int amountOfCells = size * size;
|
||||||
|
int[] encodedBoard = new int[amountOfCells];
|
||||||
|
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
for (int j = 0; j < size; j++) {
|
||||||
|
encodedBoard[i * size + j] = gameBoard.getCell(i, j).getValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// turn the current date into an id
|
||||||
|
Calendar currentDate = Calendar.getInstance();
|
||||||
|
int id = currentDate.get(Calendar.DAY_OF_MONTH) * 1000000
|
||||||
|
+ (currentDate.get(Calendar.MONTH) + 1) * 10000 + currentDate.get(Calendar.YEAR);
|
||||||
|
|
||||||
|
// save the sudoku to the database using the previously calculated id
|
||||||
|
DatabaseHelper db = new DatabaseHelper(context);
|
||||||
|
DailySudoku dailySudoku = new DailySudoku(id, difficulty, gameType, encodedBoard, usedHints, GameActivity.timeToString(time));
|
||||||
|
db.addDailySudoku(dailySudoku);
|
||||||
|
}
|
||||||
|
|
||||||
public void deleteGame(Context context) {
|
public void deleteGame(Context context) {
|
||||||
if(gameID == 0) {
|
if(gameID == 0) {
|
||||||
throw new IllegalArgumentException("GameID may not be 0.");
|
throw new IllegalArgumentException("GameID may not be 0.");
|
||||||
|
@ -414,6 +484,7 @@ public class GameController implements IModelChangedListener, Parcelable {
|
||||||
return gameBoard.toString();
|
return gameBoard.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getCodeOfField() { return gameBoard.transformToCode(); }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,19 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package org.secuso.privacyfriendlysudoku.controller;
|
package org.secuso.privacyfriendlysudoku.controller;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
@ -20,6 +36,7 @@ public class GameStateManager {
|
||||||
|
|
||||||
Context context;
|
Context context;
|
||||||
private SharedPreferences settings;
|
private SharedPreferences settings;
|
||||||
|
private boolean includesDaily;
|
||||||
|
|
||||||
private static String FILE_EXTENSION = ".txt";
|
private static String FILE_EXTENSION = ".txt";
|
||||||
private static String SAVE_PREFIX = "save_";
|
private static String SAVE_PREFIX = "save_";
|
||||||
|
@ -87,6 +104,15 @@ public class GameStateManager {
|
||||||
gic.parseSetValues(values[i++]);
|
gic.parseSetValues(values[i++]);
|
||||||
gic.parseNotes(values[i++]);
|
gic.parseNotes(values[i++]);
|
||||||
gic.parseHintsUsed(values[i++]);
|
gic.parseHintsUsed(values[i++]);
|
||||||
|
|
||||||
|
if (values.length > i) {
|
||||||
|
gic.setCustom(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gic.getID() == GameController.DAILY_SUDOKU_ID) {
|
||||||
|
includesDaily = true;
|
||||||
|
}
|
||||||
|
|
||||||
} catch(IllegalArgumentException e) {
|
} catch(IllegalArgumentException e) {
|
||||||
file.delete();
|
file.delete();
|
||||||
continue;
|
continue;
|
||||||
|
@ -108,7 +134,7 @@ public class GameStateManager {
|
||||||
LinkedList<GameInfoContainer> removeList = new LinkedList<>();
|
LinkedList<GameInfoContainer> removeList = new LinkedList<>();
|
||||||
|
|
||||||
for(int i = 0; i < list.size(); i++) {
|
for(int i = 0; i < list.size(); i++) {
|
||||||
if(i >= MAX_NUM_OF_SAVED_GAMES) {
|
if((i >= MAX_NUM_OF_SAVED_GAMES && !includesDaily) || i > MAX_NUM_OF_SAVED_GAMES) {
|
||||||
deleteGameStateFile(list.get(i));
|
deleteGameStateFile(list.get(i));
|
||||||
removeList.add(list.get(i));
|
removeList.add(list.get(i));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,19 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package org.secuso.privacyfriendlysudoku.controller;
|
package org.secuso.privacyfriendlysudoku.controller;
|
||||||
|
|
||||||
import android.app.IntentService;
|
import android.app.IntentService;
|
||||||
|
|
|
@ -1,3 +1,19 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package org.secuso.privacyfriendlysudoku.controller;
|
package org.secuso.privacyfriendlysudoku.controller;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,3 +1,19 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package org.secuso.privacyfriendlysudoku.controller;
|
package org.secuso.privacyfriendlysudoku.controller;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
@ -15,6 +31,9 @@ import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.text.DateFormat;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
@ -37,6 +56,10 @@ public class NewLevelManager {
|
||||||
public static int PRE_SAVES_MIN = 3;
|
public static int PRE_SAVES_MIN = 3;
|
||||||
public static int PRE_SAVES_MAX = 10;
|
public static int PRE_SAVES_MAX = 10;
|
||||||
|
|
||||||
|
private final double CHALLENGE_GENERATION_PROBABILITY = 0.25;
|
||||||
|
private final int CHALLENGE_ITERATIONS = 4;
|
||||||
|
|
||||||
|
|
||||||
public static NewLevelManager getInstance(Context context, SharedPreferences settings) {
|
public static NewLevelManager getInstance(Context context, SharedPreferences settings) {
|
||||||
if(instance == null) {
|
if(instance == null) {
|
||||||
instance = new NewLevelManager(context, settings);
|
instance = new NewLevelManager(context, settings);
|
||||||
|
@ -75,6 +98,16 @@ public class NewLevelManager {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int[] loadDailySudoku() {
|
||||||
|
// create a seed from the current date
|
||||||
|
DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
|
||||||
|
String toHash = "Sudoku/.PrivacyFriendly/." + dateFormat.format(new Date());
|
||||||
|
QQWingController controller = new QQWingController();
|
||||||
|
|
||||||
|
// generate new sudoku using the previously computed seed
|
||||||
|
return controller.generateFromSeed(toHash.hashCode(), CHALLENGE_GENERATION_PROBABILITY, CHALLENGE_ITERATIONS);
|
||||||
|
}
|
||||||
|
|
||||||
public int[] loadLevel(GameType type, GameDifficulty diff) {
|
public int[] loadLevel(GameType type, GameDifficulty diff) {
|
||||||
Level level = dbHelper.getLevel(diff, type);
|
Level level = dbHelper.getLevel(diff, type);
|
||||||
dbHelper.deleteLevel(level.getId());
|
dbHelper.deleteLevel(level.getId());
|
||||||
|
|
|
@ -1,9 +1,26 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package org.secuso.privacyfriendlysudoku.controller;
|
package org.secuso.privacyfriendlysudoku.controller;
|
||||||
|
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
|
import java.util.Random;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
@ -53,6 +70,49 @@ public class QQWingController {
|
||||||
return generated;
|
return generated;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a new sudoku based on a given seed regardless of outcome difficulty
|
||||||
|
* @param seed the seed based on which the sudoku should be calculated
|
||||||
|
* @return the generated sudoku
|
||||||
|
*/
|
||||||
|
public int[] generateFromSeed(int seed) {
|
||||||
|
return generateFromSeed(seed, 1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a new sudoku based on a given seed, but only accept challenge sudokus with a certain probability
|
||||||
|
* @param seed the seed based on which the sudoku should be calculated
|
||||||
|
* @param challengePermission the probability with which a challenge sudoku is accepted upon calculation
|
||||||
|
* @param challengeIterations the amount of times a challenge sudoku can be rejected in a row before being
|
||||||
|
* accepted with a probability of 100%
|
||||||
|
* @return the generated sudoku
|
||||||
|
*/
|
||||||
|
public int[] generateFromSeed(int seed, double challengePermission, int challengeIterations) {
|
||||||
|
generated.clear();
|
||||||
|
QQWing generator = new QQWing(GameType.Default_9x9, GameDifficulty.Unspecified);
|
||||||
|
boolean continueSearch = true;
|
||||||
|
Random random = new Random(seed);
|
||||||
|
int seedFactor = 2;
|
||||||
|
|
||||||
|
while(continueSearch && challengeIterations > 0) {
|
||||||
|
seed *= seedFactor;
|
||||||
|
generator.setRandom(seed);
|
||||||
|
generator.setRecordHistory(true);
|
||||||
|
generator.generatePuzzle();
|
||||||
|
|
||||||
|
if (generator.getDifficulty() != GameDifficulty.Challenge || random.nextDouble() < challengePermission) {
|
||||||
|
continueSearch = false;
|
||||||
|
} else {
|
||||||
|
challengeIterations--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
generated.add(generator.getPuzzle());
|
||||||
|
opts.gameType = GameType.Default_9x9;
|
||||||
|
opts.gameDifficulty = generator.getDifficulty();
|
||||||
|
return generated.poll();
|
||||||
|
}
|
||||||
|
|
||||||
public int[] solve(GameBoard gameBoard) {
|
public int[] solve(GameBoard gameBoard) {
|
||||||
|
|
||||||
level = new int[gameBoard.getSize()*gameBoard.getSize()];
|
level = new int[gameBoard.getSize()*gameBoard.getSize()];
|
||||||
|
@ -200,6 +260,10 @@ public class QQWingController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isImpossible() {
|
||||||
|
return solveImpossible;
|
||||||
|
}
|
||||||
|
|
||||||
private static class QQWingOptions {
|
private static class QQWingOptions {
|
||||||
// defaults for options
|
// defaults for options
|
||||||
boolean needNow = false;
|
boolean needNow = false;
|
||||||
|
|
|
@ -1,3 +1,19 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package org.secuso.privacyfriendlysudoku.controller;
|
package org.secuso.privacyfriendlysudoku.controller;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
@ -204,12 +220,12 @@ public class SaveLoadStatistics implements ITimerListener, IHintListener {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTick(int time) {
|
public void onTick(int time) {
|
||||||
incTime(gc.getDifficulty(), gc.getGameType());
|
if (!gc.gameIsCustom()) incTime(gc.getDifficulty(), gc.getGameType());
|
||||||
//gc.getUsedHints();
|
//gc.getUsedHints();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onHintUsed() {
|
public void onHintUsed() {
|
||||||
incHints(gc.getDifficulty(),gc.getGameType());
|
if (!gc.gameIsCustom()) incHints(gc.getDifficulty(),gc.getGameType());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,19 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package org.secuso.privacyfriendlysudoku.controller;
|
package org.secuso.privacyfriendlysudoku.controller;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,3 +1,19 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package org.secuso.privacyfriendlysudoku.controller;
|
package org.secuso.privacyfriendlysudoku.controller;
|
||||||
|
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
|
|
|
@ -1,3 +1,19 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package org.secuso.privacyfriendlysudoku.controller.database;
|
package org.secuso.privacyfriendlysudoku.controller.database;
|
||||||
|
|
||||||
import android.content.ContentValues;
|
import android.content.ContentValues;
|
||||||
|
@ -6,7 +22,10 @@ import android.database.Cursor;
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
import android.database.sqlite.SQLiteOpenHelper;
|
import android.database.sqlite.SQLiteOpenHelper;
|
||||||
|
|
||||||
|
import org.secuso.privacyfriendlysudoku.controller.database.columns.DailySudokuColumns;
|
||||||
import org.secuso.privacyfriendlysudoku.controller.database.columns.LevelColumns;
|
import org.secuso.privacyfriendlysudoku.controller.database.columns.LevelColumns;
|
||||||
|
import org.secuso.privacyfriendlysudoku.controller.database.migration.MigrationUtil;
|
||||||
|
import org.secuso.privacyfriendlysudoku.controller.database.model.DailySudoku;
|
||||||
import org.secuso.privacyfriendlysudoku.controller.database.model.Level;
|
import org.secuso.privacyfriendlysudoku.controller.database.model.Level;
|
||||||
import org.secuso.privacyfriendlysudoku.game.GameDifficulty;
|
import org.secuso.privacyfriendlysudoku.game.GameDifficulty;
|
||||||
import org.secuso.privacyfriendlysudoku.game.GameType;
|
import org.secuso.privacyfriendlysudoku.game.GameType;
|
||||||
|
@ -18,7 +37,7 @@ import java.util.List;
|
||||||
|
|
||||||
public class DatabaseHelper extends SQLiteOpenHelper {
|
public class DatabaseHelper extends SQLiteOpenHelper {
|
||||||
|
|
||||||
public static final int DATABASE_VERSION = 1;
|
public static final int DATABASE_VERSION = 2;
|
||||||
public static final String DATABASE_NAME = "Database.db";
|
public static final String DATABASE_NAME = "Database.db";
|
||||||
|
|
||||||
public DatabaseHelper(Context context) {
|
public DatabaseHelper(Context context) {
|
||||||
|
@ -28,11 +47,16 @@ public class DatabaseHelper extends SQLiteOpenHelper {
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(SQLiteDatabase db) {
|
public void onCreate(SQLiteDatabase db) {
|
||||||
db.execSQL(LevelColumns.SQL_CREATE_ENTRIES);
|
db.execSQL(LevelColumns.SQL_CREATE_ENTRIES);
|
||||||
|
db.execSQL(DailySudokuColumns.SQL_CREATE_ENTRIES);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||||
db.execSQL(LevelColumns.SQL_DELETE_ENTRIES);
|
// fallback to destructive migration if no migration could be executed
|
||||||
onCreate(db);
|
if(!MigrationUtil.executeMigration(db, oldVersion, newVersion)) {
|
||||||
|
db.execSQL(LevelColumns.SQL_DELETE_ENTRIES);
|
||||||
|
db.execSQL(DailySudokuColumns.SQL_DELETE_ENTRIES);
|
||||||
|
onCreate(db);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||||
|
@ -80,6 +104,39 @@ public class DatabaseHelper extends SQLiteOpenHelper {
|
||||||
return levelList.get(0);
|
return levelList.get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of all the daily sudokus that have been solved and thus saved to the database
|
||||||
|
* @return a list of all the daily sudokus that have been solved so far
|
||||||
|
*/
|
||||||
|
public synchronized List<DailySudoku> getDailySudokus() {
|
||||||
|
List<DailySudoku> dailySudokuList = new LinkedList<>();
|
||||||
|
SQLiteDatabase database = getWritableDatabase();
|
||||||
|
|
||||||
|
// order results from most to least recent
|
||||||
|
String order = DailySudokuColumns._ID + " DESC";
|
||||||
|
|
||||||
|
// How you want the results sorted in the resulting Cursor
|
||||||
|
Cursor c = database.query(
|
||||||
|
DailySudokuColumns.TABLE_NAME, // The table to query
|
||||||
|
DailySudokuColumns.PROJECTION, // The columns to return
|
||||||
|
null, // select all rows
|
||||||
|
null, // select all rows
|
||||||
|
null, // don't group the rows
|
||||||
|
null, // don't filter by row groups
|
||||||
|
order // The sort order
|
||||||
|
);
|
||||||
|
|
||||||
|
if (c != null) {
|
||||||
|
while(c.moveToNext()) {
|
||||||
|
dailySudokuList.add(DailySudokuColumns.getLevel(c));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
c.close();
|
||||||
|
return dailySudokuList;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public synchronized void deleteLevel(int id) {
|
public synchronized void deleteLevel(int id) {
|
||||||
SQLiteDatabase database = getWritableDatabase();
|
SQLiteDatabase database = getWritableDatabase();
|
||||||
|
|
||||||
|
@ -93,5 +150,15 @@ public class DatabaseHelper extends SQLiteOpenHelper {
|
||||||
SQLiteDatabase database = getWritableDatabase();
|
SQLiteDatabase database = getWritableDatabase();
|
||||||
return database.insert(LevelColumns.TABLE_NAME, null, LevelColumns.getValues(level));
|
return database.insert(LevelColumns.TABLE_NAME, null, LevelColumns.getValues(level));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a new daily sudoku to the database
|
||||||
|
* @param ds the daily sudoku which is to be added to the database
|
||||||
|
* @return the row id of the newly inserted sudoku (or -1 if an error occurred)
|
||||||
|
*/
|
||||||
|
public synchronized long addDailySudoku(DailySudoku ds) {
|
||||||
|
SQLiteDatabase database = getWritableDatabase();
|
||||||
|
return database.insert(DailySudokuColumns.TABLE_NAME, null, DailySudokuColumns.getValues(ds));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,89 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.secuso.privacyfriendlysudoku.controller.database.columns;
|
||||||
|
|
||||||
|
import android.content.ContentValues;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.provider.BaseColumns;
|
||||||
|
|
||||||
|
import org.secuso.privacyfriendlysudoku.controller.database.model.DailySudoku;
|
||||||
|
import org.secuso.privacyfriendlysudoku.controller.database.model.Level;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines a database schema for saving daily sudokus
|
||||||
|
*/
|
||||||
|
public class DailySudokuColumns extends LevelColumns {
|
||||||
|
|
||||||
|
public static final String TABLE_NAME = "ds_levels";
|
||||||
|
|
||||||
|
public static final String HINTS_USED = "ds_hints_used";
|
||||||
|
public static final String TIME_NEEDED = "ds_time_needed";
|
||||||
|
public static final String[] PROJECTION = {
|
||||||
|
_ID,
|
||||||
|
DIFFICULTY,
|
||||||
|
GAMETYPE,
|
||||||
|
PUZZLE,
|
||||||
|
HINTS_USED,
|
||||||
|
TIME_NEEDED
|
||||||
|
};
|
||||||
|
|
||||||
|
private static final String TEXT_TYPE = " TEXT ";
|
||||||
|
private static final String INTEGER_TYPE = " INTEGER ";
|
||||||
|
private static final String TIME_TYPE = " TIME (0) ";
|
||||||
|
private static final String COMMA_SEP = ",";
|
||||||
|
|
||||||
|
public static String SQL_CREATE_ENTRIES =
|
||||||
|
"CREATE TABLE " + TABLE_NAME + " (" +
|
||||||
|
_ID + INTEGER_TYPE + " PRIMARY KEY" + COMMA_SEP +
|
||||||
|
DIFFICULTY + TEXT_TYPE + COMMA_SEP +
|
||||||
|
GAMETYPE + TEXT_TYPE + COMMA_SEP +
|
||||||
|
PUZZLE + TEXT_TYPE + COMMA_SEP +
|
||||||
|
HINTS_USED + INTEGER_TYPE + COMMA_SEP +
|
||||||
|
TIME_NEEDED + TIME_TYPE + " )";
|
||||||
|
|
||||||
|
public static String SQL_DELETE_ENTRIES =
|
||||||
|
"DROP TABLE IF EXISTS " + TABLE_NAME;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new DailySudoku object using the data stored in a specific database row
|
||||||
|
* @param c the cursor pointing to the row whose data should be used
|
||||||
|
* @return the DailySudoku object created using the data from the database row
|
||||||
|
*/
|
||||||
|
public static DailySudoku getLevel(Cursor c) {
|
||||||
|
Level level = LevelColumns.getLevel(c);
|
||||||
|
int hintsUsed = c.getInt(c.getColumnIndexOrThrow(HINTS_USED));
|
||||||
|
String timeNeeded = c.getString(c.getColumnIndexOrThrow(TIME_NEEDED));
|
||||||
|
return new DailySudoku(level.getId(), level.getDifficulty(), level.getGameType(), level.getPuzzle(), hintsUsed, timeNeeded);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a specific DailySudoku instance, extracts all relevant parameters and saves them to a ContentValues object
|
||||||
|
* @param record the DailySudoku instance whose parameters should be extracted
|
||||||
|
* @return the ContentValues instance containing the extracted parameters
|
||||||
|
*/
|
||||||
|
public static ContentValues getValues(DailySudoku record) {
|
||||||
|
ContentValues result = LevelColumns.getValues(record);
|
||||||
|
result.put(HINTS_USED, record.getHintsUsed());
|
||||||
|
result.put(TIME_NEEDED, record.getTimeNeeded());
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,3 +1,20 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
package org.secuso.privacyfriendlysudoku.controller.database.columns;
|
package org.secuso.privacyfriendlysudoku.controller.database.columns;
|
||||||
|
|
||||||
import android.content.ContentValues;
|
import android.content.ContentValues;
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package org.secuso.privacyfriendlysudoku.controller.database.migration;
|
||||||
|
|
||||||
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Similar idea to room migration class.
|
||||||
|
* @author Christopher Beckmann
|
||||||
|
*/
|
||||||
|
public abstract class Migration {
|
||||||
|
int from = 0;
|
||||||
|
int to = 0;
|
||||||
|
|
||||||
|
public Migration(int from, int to) {
|
||||||
|
this.from = from;
|
||||||
|
this.to = to;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void migrate(SQLiteDatabase db);
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package org.secuso.privacyfriendlysudoku.controller.database.migration;
|
||||||
|
|
||||||
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.secuso.privacyfriendlysudoku.controller.database.columns.DailySudokuColumns.SQL_CREATE_ENTRIES;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Christopher Beckmann
|
||||||
|
*/
|
||||||
|
public class MigrationUtil {
|
||||||
|
|
||||||
|
public static List<Migration> migrations = Arrays.asList(
|
||||||
|
new Migration(1,2) {
|
||||||
|
@Override
|
||||||
|
public void migrate(SQLiteDatabase db) {
|
||||||
|
db.execSQL(SQL_CREATE_ENTRIES);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
//TODO: for now just try to find the desired migration from the list.
|
||||||
|
// -> When more migrations are added, a chain could be found, e.g. 1->2->3
|
||||||
|
public static boolean executeMigration(SQLiteDatabase db, int from, int to) {
|
||||||
|
for(Migration m : migrations) {
|
||||||
|
if(m.from == from && m.to == to) {
|
||||||
|
m.migrate(db);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,86 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.secuso.privacyfriendlysudoku.controller.database.model;
|
||||||
|
|
||||||
|
import org.secuso.privacyfriendlysudoku.game.GameDifficulty;
|
||||||
|
import org.secuso.privacyfriendlysudoku.game.GameType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Models the content of a single row of the daily sudoku database
|
||||||
|
*/
|
||||||
|
public class DailySudoku extends Level {
|
||||||
|
private int hintsUsed;
|
||||||
|
private String timeNeeded;
|
||||||
|
|
||||||
|
public DailySudoku(int id, GameDifficulty gameDifficulty, GameType gameType, int[] puzzle, int hintsUsed, String timeNeeded) {
|
||||||
|
super(id, gameDifficulty, gameType, puzzle);
|
||||||
|
this.hintsUsed = hintsUsed;
|
||||||
|
this.timeNeeded = timeNeeded;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the amount of hints the user needed to solve this sudoku
|
||||||
|
* @return the amount of hints the user needed to solve this sudoku
|
||||||
|
*/
|
||||||
|
public int getHintsUsed() {
|
||||||
|
return hintsUsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a new value for the hintsUsed attribute of this daily sudoku
|
||||||
|
* @param hintsUsed the new value for the hintsUsed attribute
|
||||||
|
*/
|
||||||
|
public void setHintsUsed(int hintsUsed) {
|
||||||
|
this.hintsUsed = hintsUsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the time the user needed to solve this sudoku as a string
|
||||||
|
* @return the time the user needed to solve this sudoku as a string
|
||||||
|
*/
|
||||||
|
public String getTimeNeeded() {
|
||||||
|
return timeNeeded;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the time the user needed to solve this sudoku in seconds
|
||||||
|
* @return the time the user needed to solve this sudoku in seconds (or 0 if the timeNeeded parameter
|
||||||
|
* does not have the right format)
|
||||||
|
*/
|
||||||
|
public int getTimeNeededInSeconds() {
|
||||||
|
if (timeNeeded.matches("[0-9]{2}:[0-5][0-9]:[0-5][0-9]")) {
|
||||||
|
String[] timeInstances = timeNeeded.split(":");
|
||||||
|
int hourIndex = 0;
|
||||||
|
int minuteIndex = 1;
|
||||||
|
int secondIndex = 2;
|
||||||
|
|
||||||
|
int minutes = Integer.parseInt(timeInstances[hourIndex]) * 60 + Integer.parseInt(timeInstances[minuteIndex]);
|
||||||
|
return minutes * 60 + Integer.parseInt(timeInstances[secondIndex]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a new value for the timeNeeded attribute of this daily sudoku
|
||||||
|
* @param timeNeeded the new value for the timeNeeded attribute
|
||||||
|
*/
|
||||||
|
public void setTimeNeeded(String timeNeeded) {
|
||||||
|
this.timeNeeded = timeNeeded;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,19 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package org.secuso.privacyfriendlysudoku.controller.database.model;
|
package org.secuso.privacyfriendlysudoku.controller.database.model;
|
||||||
|
|
||||||
import org.secuso.privacyfriendlysudoku.controller.Symbol;
|
import org.secuso.privacyfriendlysudoku.controller.Symbol;
|
||||||
|
|
|
@ -1,3 +1,19 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package org.secuso.privacyfriendlysudoku.controller.helper;
|
package org.secuso.privacyfriendlysudoku.controller.helper;
|
||||||
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
@ -25,6 +41,7 @@ public class GameInfoContainer {
|
||||||
int[] setValues;
|
int[] setValues;
|
||||||
boolean[][] setNotes;
|
boolean[][] setNotes;
|
||||||
int hintsUsed;
|
int hintsUsed;
|
||||||
|
boolean isCustom;
|
||||||
|
|
||||||
public GameInfoContainer() {}
|
public GameInfoContainer() {}
|
||||||
public GameInfoContainer(int ID, GameDifficulty difficulty, GameType gameType, int[] fixedValues, int[] setValues, boolean[][] setNotes) {
|
public GameInfoContainer(int ID, GameDifficulty difficulty, GameType gameType, int[] fixedValues, int[] setValues, boolean[][] setNotes) {
|
||||||
|
@ -40,17 +57,19 @@ public class GameInfoContainer {
|
||||||
this.setValues = setValues;
|
this.setValues = setValues;
|
||||||
this.setNotes = setNotes;
|
this.setNotes = setNotes;
|
||||||
this.hintsUsed = hintsUsed;
|
this.hintsUsed = hintsUsed;
|
||||||
|
isCustom = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setID(int ID) {
|
public void setID(int ID) {
|
||||||
this.ID = ID;
|
this.ID = ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setCustom (boolean isCustom) { this.isCustom = isCustom; }
|
||||||
|
|
||||||
|
public boolean isCustom () { return isCustom; }
|
||||||
|
|
||||||
public void parseGameType(String s) {
|
public void parseGameType(String s) {
|
||||||
gameType = Enum.valueOf(GameType.class, s);
|
gameType = Enum.valueOf(GameType.class, s);
|
||||||
if(gameType == null) {
|
|
||||||
throw new IllegalArgumentException("GameInfoContainer: gameType could not be set.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getTimePlayed() {
|
public int getTimePlayed() {
|
||||||
|
@ -63,7 +82,7 @@ public class GameInfoContainer {
|
||||||
|
|
||||||
public void parseTime(String s) {
|
public void parseTime(String s) {
|
||||||
try {
|
try {
|
||||||
this.timePlayed = Integer.valueOf(s);
|
this.timePlayed = Integer.parseInt(s);
|
||||||
} catch(NumberFormatException e) {
|
} catch(NumberFormatException e) {
|
||||||
throw new IllegalArgumentException("GameInfoContainer: Can not parse time.", e);
|
throw new IllegalArgumentException("GameInfoContainer: Can not parse time.", e);
|
||||||
}
|
}
|
||||||
|
@ -71,7 +90,7 @@ public class GameInfoContainer {
|
||||||
|
|
||||||
public void parseHintsUsed(String s) {
|
public void parseHintsUsed(String s) {
|
||||||
try {
|
try {
|
||||||
this.hintsUsed = Integer.valueOf(s);
|
this.hintsUsed = Integer.parseInt(s);
|
||||||
} catch(NumberFormatException e) {
|
} catch(NumberFormatException e) {
|
||||||
throw new IllegalArgumentException("GameInfoContainer: Can not parse hints used.", e);
|
throw new IllegalArgumentException("GameInfoContainer: Can not parse hints used.", e);
|
||||||
}
|
}
|
||||||
|
@ -79,7 +98,7 @@ public class GameInfoContainer {
|
||||||
|
|
||||||
public void parseDate(String s) {
|
public void parseDate(String s) {
|
||||||
try {
|
try {
|
||||||
this.lastTimePlayed = new Date(Long.valueOf(s));
|
this.lastTimePlayed = new Date(Long.parseLong(s));
|
||||||
} catch(NumberFormatException e) {
|
} catch(NumberFormatException e) {
|
||||||
throw new IllegalArgumentException("GameInfoContainer: LastTimePlayed Date can not be extracted.", e);
|
throw new IllegalArgumentException("GameInfoContainer: LastTimePlayed Date can not be extracted.", e);
|
||||||
}
|
}
|
||||||
|
@ -87,9 +106,6 @@ public class GameInfoContainer {
|
||||||
|
|
||||||
public void parseDifficulty(String s) {
|
public void parseDifficulty(String s) {
|
||||||
difficulty = Enum.valueOf(GameDifficulty.class, s);
|
difficulty = Enum.valueOf(GameDifficulty.class, s);
|
||||||
if(difficulty == null) {
|
|
||||||
throw new IllegalArgumentException("GameInfoContainer: difficulty could not be set.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void parseFixedValues(String s){
|
public void parseFixedValues(String s){
|
||||||
|
@ -104,6 +120,11 @@ public class GameInfoContainer {
|
||||||
fixedValues = new int[s.length()];
|
fixedValues = new int[s.length()];
|
||||||
for(int i = 0; i < s.length(); i++) {
|
for(int i = 0; i < s.length(); i++) {
|
||||||
fixedValues[i] = Symbol.getValue(Symbol.SaveFormat, String.valueOf(s.charAt(i)))+1;
|
fixedValues[i] = Symbol.getValue(Symbol.SaveFormat, String.valueOf(s.charAt(i)))+1;
|
||||||
|
if (gameType != GameType.Unspecified && gameType != null) {
|
||||||
|
if (fixedValues[i] < 0 || fixedValues[i] > gameType.getSize()) {
|
||||||
|
throw new IllegalArgumentException("Fixed values must each be smaller than " + gameType.getSize() + ".");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,7 +149,7 @@ public class GameInfoContainer {
|
||||||
int size = gameType.getSize();
|
int size = gameType.getSize();
|
||||||
int sq = size*size;
|
int sq = size*size;
|
||||||
|
|
||||||
if(gameType != GameType.Unspecified && gameType != null) {
|
if(gameType != GameType.Unspecified) {
|
||||||
if(strings.length != sq) {
|
if(strings.length != sq) {
|
||||||
throw new IllegalArgumentException("The string array must have "+sq+" entries.");
|
throw new IllegalArgumentException("The string array must have "+sq+" entries.");
|
||||||
}
|
}
|
||||||
|
@ -174,6 +195,7 @@ public class GameInfoContainer {
|
||||||
public static String getGameInfo(GameController controller) {
|
public static String getGameInfo(GameController controller) {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
Date today = new Date();
|
Date today = new Date();
|
||||||
|
boolean custom = controller.gameIsCustom();
|
||||||
|
|
||||||
sb.append(controller.getGameType().name());
|
sb.append(controller.getGameType().name());
|
||||||
sb.append("/");
|
sb.append("/");
|
||||||
|
@ -191,6 +213,12 @@ public class GameInfoContainer {
|
||||||
sb.append("/");
|
sb.append("/");
|
||||||
sb.append(controller.getUsedHints());
|
sb.append(controller.getUsedHints());
|
||||||
|
|
||||||
|
// add additional information to custom sudokus to ensure they can be distinguished from 'regular' sudokus
|
||||||
|
if (custom) {
|
||||||
|
sb.append("/");
|
||||||
|
sb.append(custom);
|
||||||
|
}
|
||||||
|
|
||||||
String result = sb.toString();
|
String result = sb.toString();
|
||||||
|
|
||||||
Log.d("getGameInfo", result);
|
Log.d("getGameInfo", result);
|
||||||
|
|
|
@ -1,3 +1,19 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package org.secuso.privacyfriendlysudoku.controller.helper;
|
package org.secuso.privacyfriendlysudoku.controller.helper;
|
||||||
|
|
||||||
import org.secuso.privacyfriendlysudoku.controller.GameController;
|
import org.secuso.privacyfriendlysudoku.controller.GameController;
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
* the Free Software Foundation; either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
* the Free Software Foundation; either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
* the Free Software Foundation; either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
* the Free Software Foundation; either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
* the Free Software Foundation; either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
@ -199,6 +199,10 @@ public class QQWing {
|
||||||
return reset();
|
return reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setRandom(int seed) {
|
||||||
|
random = new Random(seed);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reset the board to its initial state with only the givens. This method
|
* Reset the board to its initial state with only the givens. This method
|
||||||
* clears any solution, resets statistics, and clears any history messages.
|
* clears any solution, resets statistics, and clears any history messages.
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
* the Free Software Foundation; either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
|
|
@ -1,3 +1,19 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package org.secuso.privacyfriendlysudoku.game;
|
package org.secuso.privacyfriendlysudoku.game;
|
||||||
|
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
|
|
|
@ -1,3 +1,19 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package org.secuso.privacyfriendlysudoku.game;
|
package org.secuso.privacyfriendlysudoku.game;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
|
@ -1,8 +1,25 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package org.secuso.privacyfriendlysudoku.game;
|
package org.secuso.privacyfriendlysudoku.game;
|
||||||
|
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
|
|
||||||
|
import org.secuso.privacyfriendlysudoku.controller.Symbol;
|
||||||
import org.secuso.privacyfriendlysudoku.game.listener.IModelChangedListener;
|
import org.secuso.privacyfriendlysudoku.game.listener.IModelChangedListener;
|
||||||
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
|
@ -214,6 +231,20 @@ public class GameBoard implements Cloneable, Parcelable {
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String transformToCode () {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for(int i = 0; i < field.length; i++) {
|
||||||
|
for (int j = 0; j < field[0].length; j++) {
|
||||||
|
if (field[i][j].getValue() == 0) {
|
||||||
|
sb.append(0);
|
||||||
|
} else {
|
||||||
|
sb.append(Symbol.getSymbol(Symbol.SaveFormat, field[i][j].getValue()-1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isFilled() {
|
public boolean isFilled() {
|
||||||
return actionOnCells(new ICellAction<Boolean>() {
|
return actionOnCells(new ICellAction<Boolean>() {
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -1,3 +1,19 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package org.secuso.privacyfriendlysudoku.game;
|
package org.secuso.privacyfriendlysudoku.game;
|
||||||
|
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
|
|
|
@ -1,3 +1,19 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package org.secuso.privacyfriendlysudoku.game;
|
package org.secuso.privacyfriendlysudoku.game;
|
||||||
|
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
|
|
|
@ -1,3 +1,19 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package org.secuso.privacyfriendlysudoku.game;
|
package org.secuso.privacyfriendlysudoku.game;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,3 +1,19 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package org.secuso.privacyfriendlysudoku.game;
|
package org.secuso.privacyfriendlysudoku.game;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,3 +1,19 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package org.secuso.privacyfriendlysudoku.game;
|
package org.secuso.privacyfriendlysudoku.game;
|
||||||
|
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
|
|
|
@ -1,3 +1,19 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package org.secuso.privacyfriendlysudoku.game;
|
package org.secuso.privacyfriendlysudoku.game;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,3 +1,19 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package org.secuso.privacyfriendlysudoku.game.listener;
|
package org.secuso.privacyfriendlysudoku.game.listener;
|
||||||
|
|
||||||
import org.secuso.privacyfriendlysudoku.game.CellConflict;
|
import org.secuso.privacyfriendlysudoku.game.CellConflict;
|
||||||
|
|
|
@ -1,3 +1,19 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package org.secuso.privacyfriendlysudoku.game.listener;
|
package org.secuso.privacyfriendlysudoku.game.listener;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,3 +1,19 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package org.secuso.privacyfriendlysudoku.game.listener;
|
package org.secuso.privacyfriendlysudoku.game.listener;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,3 +1,19 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package org.secuso.privacyfriendlysudoku.game.listener;
|
package org.secuso.privacyfriendlysudoku.game.listener;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,3 +1,19 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package org.secuso.privacyfriendlysudoku.game.listener;
|
package org.secuso.privacyfriendlysudoku.game.listener;
|
||||||
|
|
||||||
import org.secuso.privacyfriendlysudoku.game.GameCell;
|
import org.secuso.privacyfriendlysudoku.game.GameCell;
|
||||||
|
|
|
@ -1,3 +1,19 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package org.secuso.privacyfriendlysudoku.game.listener;
|
package org.secuso.privacyfriendlysudoku.game.listener;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,3 +1,19 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package org.secuso.privacyfriendlysudoku.ui;
|
package org.secuso.privacyfriendlysudoku.ui;
|
||||||
|
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
|
@ -11,6 +27,10 @@ import android.widget.TextView;
|
||||||
import org.secuso.privacyfriendlysudoku.ui.view.BuildConfig;
|
import org.secuso.privacyfriendlysudoku.ui.view.BuildConfig;
|
||||||
import org.secuso.privacyfriendlysudoku.ui.view.R;
|
import org.secuso.privacyfriendlysudoku.ui.view.R;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The AboutActivity is extended by the BaseActivity and is responsible for the content of the AboutActivity.
|
||||||
|
*/
|
||||||
|
|
||||||
public class AboutActivity extends BaseActivity {
|
public class AboutActivity extends BaseActivity {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -1,3 +1,19 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package org.secuso.privacyfriendlysudoku.ui;
|
package org.secuso.privacyfriendlysudoku.ui;
|
||||||
|
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
|
|
|
@ -1,3 +1,19 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package org.secuso.privacyfriendlysudoku.ui;
|
package org.secuso.privacyfriendlysudoku.ui;
|
||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
|
|
@ -0,0 +1,294 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package org.secuso.privacyfriendlysudoku.ui;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.content.res.Configuration;
|
||||||
|
import android.graphics.Point;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.WindowManager;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import androidx.appcompat.app.AppCompatDelegate;
|
||||||
|
import androidx.appcompat.widget.Toolbar;
|
||||||
|
|
||||||
|
import org.secuso.privacyfriendlysudoku.controller.GameController;
|
||||||
|
import org.secuso.privacyfriendlysudoku.controller.Symbol;
|
||||||
|
import org.secuso.privacyfriendlysudoku.controller.helper.GameInfoContainer;
|
||||||
|
import org.secuso.privacyfriendlysudoku.controller.qqwing.QQWing;
|
||||||
|
import org.secuso.privacyfriendlysudoku.game.GameDifficulty;
|
||||||
|
import org.secuso.privacyfriendlysudoku.game.GameType;
|
||||||
|
import org.secuso.privacyfriendlysudoku.ui.listener.IFinalizeDialogFragmentListener;
|
||||||
|
import org.secuso.privacyfriendlysudoku.ui.listener.IImportDialogFragmentListener;
|
||||||
|
import org.secuso.privacyfriendlysudoku.ui.view.CreateSudokuSpecialButtonLayout;
|
||||||
|
import org.secuso.privacyfriendlysudoku.ui.view.R;
|
||||||
|
import org.secuso.privacyfriendlysudoku.ui.view.SudokuFieldLayout;
|
||||||
|
import org.secuso.privacyfriendlysudoku.ui.view.SudokuKeyboardLayout;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The CreateSudokuActivity is an activity which extends the BaseActivity and implements the
|
||||||
|
* IFinalizeDialogFragementListener. It is used to create custom sudokus, which are passed to the
|
||||||
|
* GameActivity afterwards.
|
||||||
|
*/
|
||||||
|
public class CreateSudokuActivity extends BaseActivity implements IFinalizeDialogFragmentListener, IImportDialogFragmentListener {
|
||||||
|
|
||||||
|
GameController gameController;
|
||||||
|
SharedPreferences sharedPref;
|
||||||
|
SudokuFieldLayout layout;
|
||||||
|
SudokuKeyboardLayout keyboard;
|
||||||
|
CreateSudokuSpecialButtonLayout specialButtonLayout;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
|
||||||
|
|
||||||
|
if (sharedPref.getBoolean("pref_keep_screen_on", true)) {
|
||||||
|
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(savedInstanceState == null) {
|
||||||
|
|
||||||
|
gameController = new GameController(sharedPref, getApplicationContext());
|
||||||
|
|
||||||
|
Bundle extras = getIntent().getExtras();
|
||||||
|
GameType gameType = GameType.valueOf(extras.getString("gameType", GameType.Default_9x9.name()));
|
||||||
|
int sectionSize = gameType.getSize();
|
||||||
|
int boardSize = sectionSize * sectionSize;
|
||||||
|
|
||||||
|
GameInfoContainer container = new GameInfoContainer(0, GameDifficulty.Moderate,
|
||||||
|
gameType, new int[boardSize], new int[boardSize], new boolean[boardSize][sectionSize]);
|
||||||
|
gameController.loadLevel(container);
|
||||||
|
} else {
|
||||||
|
gameController = savedInstanceState.getParcelable("gameController");
|
||||||
|
if(gameController != null) {
|
||||||
|
gameController.removeAllListeners();
|
||||||
|
gameController.setContextAndSettings(getApplicationContext(), sharedPref);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setUpLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setUpLayout() {
|
||||||
|
|
||||||
|
setContentView(R.layout.activity_create_sudoku);
|
||||||
|
|
||||||
|
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
|
||||||
|
setSupportActionBar(toolbar);
|
||||||
|
getSupportActionBar().setTitle(getString(gameController.getGameType().getStringResID()));
|
||||||
|
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||||
|
|
||||||
|
layout = (SudokuFieldLayout)findViewById(R.id.sudokuLayout);
|
||||||
|
layout.setSettingsAndGame(sharedPref, gameController);
|
||||||
|
|
||||||
|
keyboard = (SudokuKeyboardLayout) findViewById(R.id.sudokuKeyboardLayout);
|
||||||
|
keyboard.removeAllViews();
|
||||||
|
keyboard.setGameController(gameController);
|
||||||
|
Point p = new Point();
|
||||||
|
getWindowManager().getDefaultDisplay().getSize(p);
|
||||||
|
|
||||||
|
int orientation = getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT ?
|
||||||
|
LinearLayout.HORIZONTAL : LinearLayout.VERTICAL;
|
||||||
|
|
||||||
|
keyboard.setKeyBoard(gameController.getSize(), p.x,layout.getHeight()-p.y, orientation);
|
||||||
|
|
||||||
|
specialButtonLayout = (CreateSudokuSpecialButtonLayout) findViewById(R.id.createSudokuLayout);
|
||||||
|
specialButtonLayout.setButtons(p.x, gameController, keyboard, getFragmentManager(), orientation,
|
||||||
|
CreateSudokuActivity.this, this, this);
|
||||||
|
|
||||||
|
gameController.notifyHighlightChangedListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onSupportNavigateUp() {
|
||||||
|
onBackPressed();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume(){
|
||||||
|
super.onResume();
|
||||||
|
|
||||||
|
View mainContent = findViewById(R.id.main_content);
|
||||||
|
if (mainContent != null) {
|
||||||
|
mainContent.animate().alpha(1).setDuration(MAIN_CONTENT_FADEOUT_DURATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
|
||||||
|
Symbol s;
|
||||||
|
try {
|
||||||
|
s = Symbol.valueOf(sharedPref.getString("pref_symbols", Symbol.Default.name()));
|
||||||
|
} catch(IllegalArgumentException e) {
|
||||||
|
s = Symbol.Default;
|
||||||
|
}
|
||||||
|
layout.setSymbols(s);
|
||||||
|
keyboard.setSymbols(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBackPressed() {
|
||||||
|
finish();
|
||||||
|
super.onBackPressed();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verifies an encoded sudoku board by testing whether or not it is uniquely solvable
|
||||||
|
* @param gameType the type of the encoded sudoku
|
||||||
|
* @param boardContent the encoded sudoku
|
||||||
|
* @return whether or not the sudoku is uniquely solvable
|
||||||
|
*/
|
||||||
|
public static boolean verify(GameType gameType, String boardContent) {
|
||||||
|
int boardSize = gameType.getSize() * gameType.getSize();
|
||||||
|
|
||||||
|
GameInfoContainer container = new GameInfoContainer(0, GameDifficulty.Unspecified,
|
||||||
|
gameType, new int [boardSize], new int [boardSize], new boolean [boardSize][gameType.getSize()]);
|
||||||
|
|
||||||
|
try {
|
||||||
|
container.parseFixedValues(boardContent);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QQWing verifier = new QQWing(gameType, GameDifficulty.Unspecified);
|
||||||
|
verifier.setRecordHistory(true);
|
||||||
|
verifier.setPuzzle(container.getFixedValues());
|
||||||
|
verifier.solve();
|
||||||
|
|
||||||
|
return verifier.hasUniqueSolution();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the positive button of the FinalizeDialog is clicked, verify the sudoku. Immediately pass
|
||||||
|
* it to the GameActivity, if the verification process is successful, and do nothing apart from
|
||||||
|
* notifying the user if not.
|
||||||
|
* Implements the onFinalizeDialogPositiveClick() method of the IFinalizeDialogFragmentListener
|
||||||
|
* interface.
|
||||||
|
*/
|
||||||
|
public void onFinalizeDialogPositiveClick() {
|
||||||
|
Toast.makeText(CreateSudokuActivity.this, R.string.verify_custom_sudoku_process_toast, Toast.LENGTH_SHORT).show();
|
||||||
|
String boardContent = gameController.getCodeOfField();
|
||||||
|
boolean distinctlySolvable = verify(gameController.getGameType(), boardContent);
|
||||||
|
|
||||||
|
if(distinctlySolvable) {
|
||||||
|
Toast.makeText(CreateSudokuActivity.this, R.string.finished_verifying_custom_sudoku_toast, Toast.LENGTH_LONG).show();
|
||||||
|
final Intent intent = new Intent(this, GameActivity.class);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Since the GameActivity expects the links of imported sudokus to start with an url scheme,
|
||||||
|
add one to the start of the encoded board
|
||||||
|
*/
|
||||||
|
String scheme = GameActivity.validUris.size() > 0 ? GameActivity.validUris.get(0).getScheme()
|
||||||
|
+ "://" + GameActivity.validUris.get(0).getHost() : "";
|
||||||
|
if (!scheme.equals("") && !scheme.endsWith("/")) scheme = scheme + "/";
|
||||||
|
|
||||||
|
intent.setData(Uri.parse(scheme + boardContent));
|
||||||
|
intent.putExtra("isCustom", true);
|
||||||
|
startActivity(intent);
|
||||||
|
finish();
|
||||||
|
} else {
|
||||||
|
Toast.makeText(CreateSudokuActivity.this, R.string.failed_to_verify_custom_sudoku_toast, Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
public void onImportDialogPositiveClick(String input) {
|
||||||
|
String inputSudoku = null;
|
||||||
|
String prefix;
|
||||||
|
StringBuilder errorMessage = new StringBuilder();
|
||||||
|
|
||||||
|
/* remove the present prefix, or, if the input contains none of the valid prefixes, notify the user
|
||||||
|
that their input is not valid */
|
||||||
|
for (int i = 0; i < GameActivity.validUris.size(); i++) {
|
||||||
|
prefix = GameActivity.validUris.get(i).getHost().equals("") ?
|
||||||
|
GameActivity.validUris.get(i).getScheme() + "://" :
|
||||||
|
GameActivity.validUris.get(i).getScheme() + "://" + GameActivity.validUris.get(i).getHost() + "/";
|
||||||
|
if (input.startsWith(prefix)) {
|
||||||
|
inputSudoku = input.replace(prefix, "");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
String endOfRecord = (i == GameActivity.validUris.size() - 1) ? "" : ", ";
|
||||||
|
errorMessage.append(prefix);
|
||||||
|
errorMessage.append(endOfRecord);
|
||||||
|
}
|
||||||
|
|
||||||
|
// the inputSudoku variable being null means the input did not match any of the valid prefixes
|
||||||
|
if (inputSudoku == null) {
|
||||||
|
Toast.makeText(CreateSudokuActivity.this,
|
||||||
|
this.getString(R.string.menu_import_wrong_format_custom_sudoku) + " " + errorMessage.toString(), Toast.LENGTH_LONG).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean validSize = Math.sqrt(inputSudoku.length()) == gameController.getSize();
|
||||||
|
|
||||||
|
if (!validSize) {
|
||||||
|
Toast.makeText(CreateSudokuActivity.this, R.string.failed_to_verify_custom_sudoku_toast, Toast.LENGTH_LONG).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//check whether or not the sudoku is valid and has a unique solution
|
||||||
|
boolean solvable = verify(gameController.getGameType(), inputSudoku);
|
||||||
|
|
||||||
|
// if the encoded sudoku is solvable, sent the code directly to the GameActivity; if not, notify the user
|
||||||
|
if (solvable) {
|
||||||
|
int boardSize = gameController.getGameType().getSize() * gameController.getGameType().getSize();
|
||||||
|
GameInfoContainer container = new GameInfoContainer(0, GameDifficulty.Unspecified,
|
||||||
|
gameController.getGameType(), new int [boardSize], new int [boardSize],
|
||||||
|
new boolean [boardSize][gameController.getGameType().getSize()]);
|
||||||
|
container.parseSetValues(inputSudoku);
|
||||||
|
|
||||||
|
gameController.loadLevel(container);
|
||||||
|
setUpLayout();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Toast.makeText(CreateSudokuActivity.this, R.string.failed_to_verify_custom_sudoku_toast, Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements the onDialogNegativeClick() method of the IFinalizeDialogFragmentListener
|
||||||
|
* interface.
|
||||||
|
*/
|
||||||
|
public void onDialogNegativeClick() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSaveInstanceState(Bundle savedInstanceState) {
|
||||||
|
// Always call the superclass so it can save the view hierarchy state
|
||||||
|
super.onSaveInstanceState(savedInstanceState);
|
||||||
|
|
||||||
|
// Save the user's current game state
|
||||||
|
savedInstanceState.putParcelable("gameController", gameController);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRestoreInstanceState(Bundle savedInstanceState) {
|
||||||
|
super.onRestoreInstanceState(savedInstanceState);
|
||||||
|
|
||||||
|
gameController = savedInstanceState.getParcelable("gameController");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,272 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package org.secuso.privacyfriendlysudoku.ui;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.Menu;
|
||||||
|
import android.view.MenuItem;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.BaseAdapter;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.widget.ListView;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.RatingBar;
|
||||||
|
import android.widget.Toast;
|
||||||
|
import org.secuso.privacyfriendlysudoku.controller.GameController;
|
||||||
|
import org.secuso.privacyfriendlysudoku.controller.GameStateManager;
|
||||||
|
import org.secuso.privacyfriendlysudoku.controller.NewLevelManager;
|
||||||
|
import org.secuso.privacyfriendlysudoku.controller.database.DatabaseHelper;
|
||||||
|
import org.secuso.privacyfriendlysudoku.controller.database.model.DailySudoku;
|
||||||
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
import androidx.appcompat.widget.Toolbar;
|
||||||
|
|
||||||
|
import org.secuso.privacyfriendlysudoku.controller.qqwing.QQWing;
|
||||||
|
import org.secuso.privacyfriendlysudoku.game.GameDifficulty;
|
||||||
|
import org.secuso.privacyfriendlysudoku.game.GameType;
|
||||||
|
import org.secuso.privacyfriendlysudoku.ui.view.R;
|
||||||
|
|
||||||
|
import java.text.DateFormat;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*The DailySudokuActivity is an activity that extends the AppCompatActivity.
|
||||||
|
*The activity is responsible for the logic of the DailySudoku.
|
||||||
|
*DailySudoku is a game mode where every day a different Sudoku is created for the user
|
||||||
|
*/
|
||||||
|
public class DailySudokuActivity extends AppCompatActivity {
|
||||||
|
|
||||||
|
List<DailySudoku> sudokuList;
|
||||||
|
SharedPreferences settings;
|
||||||
|
private final DatabaseHelper dbHelper = new DatabaseHelper(this);
|
||||||
|
RatingBar difficultyBar;
|
||||||
|
private SudokuListAdapter sudokuListAdapter;
|
||||||
|
private int dailyId;
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
setContentView(R.layout.activity_daily_sudoku);
|
||||||
|
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
|
||||||
|
setSupportActionBar(toolbar);
|
||||||
|
|
||||||
|
sudokuList = dbHelper.getDailySudokus();
|
||||||
|
TextView totalGamesTextView = findViewById(R.id.numb_of_total_games);
|
||||||
|
TextView hintsTextView = findViewById(R.id.numb_of_hints);
|
||||||
|
TextView totalTimeTextView = findViewById(R.id.numb_of_total_time);
|
||||||
|
totalGamesTextView.setText(String.valueOf(sudokuList.size()));
|
||||||
|
|
||||||
|
|
||||||
|
int sumHints = 0;
|
||||||
|
int sumTime = 0;
|
||||||
|
|
||||||
|
for (DailySudoku sudoku : sudokuList){
|
||||||
|
sumHints += sudoku.getHintsUsed();
|
||||||
|
sumTime += sudoku.getTimeNeededInSeconds();
|
||||||
|
}
|
||||||
|
|
||||||
|
int hours = sumTime / 3600;
|
||||||
|
int minutes = ( sumTime / 60 ) % 60;
|
||||||
|
int seconds = sumTime % 60;
|
||||||
|
String str = String.format(Locale.getDefault(), "%02d:%02d:%02d", hours, minutes, seconds);
|
||||||
|
|
||||||
|
hintsTextView.setText(String.valueOf(sumHints));
|
||||||
|
totalTimeTextView.setText(str);
|
||||||
|
|
||||||
|
androidx.appcompat.app.ActionBar actionBar = getSupportActionBar();
|
||||||
|
actionBar.setTitle(R.string.menu_daily_sudoku);
|
||||||
|
actionBar.setDisplayHomeAsUpEnabled(true);
|
||||||
|
|
||||||
|
difficultyBar = findViewById(R.id.first_diff_bar);
|
||||||
|
settings = PreferenceManager.getDefaultSharedPreferences(this);
|
||||||
|
|
||||||
|
ListView listView = (ListView)findViewById(R.id.sudoku_list);
|
||||||
|
sudokuListAdapter = new SudokuListAdapter(this, sudokuList);
|
||||||
|
listView.setAdapter(sudokuListAdapter);
|
||||||
|
|
||||||
|
// Calculate the current date as an int id
|
||||||
|
Calendar currentDate = Calendar.getInstance();
|
||||||
|
dailyId = currentDate.get(Calendar.DAY_OF_MONTH) * 1000000
|
||||||
|
+ (currentDate.get(Calendar.MONTH) + 1) * 10000 + currentDate.get(Calendar.YEAR);
|
||||||
|
|
||||||
|
GameDifficulty dailyDifficulty;
|
||||||
|
|
||||||
|
//only calculate the difficulty of the daily sudoku once a day
|
||||||
|
if (settings.getInt("lastCalculated", 0) != dailyId) {
|
||||||
|
// generate the daily sudoku
|
||||||
|
NewLevelManager newLevelManager = NewLevelManager.getInstance(getApplicationContext(), settings);
|
||||||
|
int[] level = newLevelManager.loadDailySudoku();
|
||||||
|
QQWing difficultyCheck = new QQWing(GameType.Default_9x9, GameDifficulty.Unspecified);
|
||||||
|
|
||||||
|
difficultyCheck.setRecordHistory(true);
|
||||||
|
difficultyCheck.setPuzzle(level);
|
||||||
|
difficultyCheck.solve();
|
||||||
|
|
||||||
|
dailyDifficulty = difficultyCheck.getDifficulty();
|
||||||
|
|
||||||
|
//save the index of the daily difficulty (in the valid difficulty list) and the day it was calculated for
|
||||||
|
SharedPreferences.Editor editor = settings.edit();
|
||||||
|
editor.putInt("lastCalculated", dailyId);
|
||||||
|
editor.putInt("dailyDifficultyIndex", GameDifficulty.getValidDifficultyList().indexOf(dailyDifficulty));
|
||||||
|
editor.apply();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// if the daily sudoku has been calculated already, the difficulty can be read from the settings attribute
|
||||||
|
int index = settings.getInt("dailyDifficultyIndex", GameDifficulty.getValidDifficultyList()
|
||||||
|
.indexOf(GameDifficulty.Unspecified));
|
||||||
|
dailyDifficulty = GameDifficulty.getValidDifficultyList().get(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
TextView diffTextView = findViewById(R.id.first_diff_text);
|
||||||
|
|
||||||
|
diffTextView.setText(dailyDifficulty.getStringResID());
|
||||||
|
difficultyBar.setNumStars(GameDifficulty.getValidDifficultyList().size());
|
||||||
|
difficultyBar.setMax(GameDifficulty.getValidDifficultyList().size());
|
||||||
|
difficultyBar.setRating(GameDifficulty.getValidDifficultyList().indexOf(dailyDifficulty)+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onClick(View view) {
|
||||||
|
final Intent intent = new Intent(this,GameActivity.class);
|
||||||
|
|
||||||
|
/*
|
||||||
|
If the 'lastPlayed' key does not return the calculated id, then the player has not played
|
||||||
|
the sudoku of the day yet, meaning it has yet to be saved on their phone and needs to be generated again
|
||||||
|
*/
|
||||||
|
if (settings.getInt("lastPlayed", 0) != dailyId) {
|
||||||
|
SharedPreferences.Editor editor = settings.edit();
|
||||||
|
editor.putInt("lastPlayed", dailyId);
|
||||||
|
|
||||||
|
//as the player just started a new daily sudoku, set the 'finishedForToday' setting to 'false'
|
||||||
|
editor.putBoolean("finishedForToday", false);
|
||||||
|
editor.apply();
|
||||||
|
|
||||||
|
//send everything to game activity, which calculates the daily sudoku
|
||||||
|
intent.putExtra("isDailySudoku", true);
|
||||||
|
startActivity(intent);
|
||||||
|
|
||||||
|
} else if (!settings.getBoolean("finishedForToday", true)) {
|
||||||
|
/*
|
||||||
|
if the 'finished for today' setting is 'false', the player has already started the sudoku
|
||||||
|
but has yet to finish it -> send the designated daily sudoku ID to the GameActivity
|
||||||
|
*/
|
||||||
|
GameStateManager fm = new GameStateManager(getBaseContext(), settings);
|
||||||
|
fm.loadGameStateInfo();
|
||||||
|
intent.putExtra("loadLevel", true);
|
||||||
|
intent.putExtra("loadLevelID", GameController.DAILY_SUDOKU_ID);
|
||||||
|
startActivity(intent);
|
||||||
|
} else {
|
||||||
|
Toast.makeText(this, R.string.finished_daily_sudoku, Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean onCreateOptionsMenu(Menu 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.
|
||||||
|
|
||||||
|
//noinspection SimplifiableIfStatement
|
||||||
|
if (item.getItemId() == android.R.id.home) {
|
||||||
|
finish();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.onOptionsItemSelected(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class SudokuListAdapter extends BaseAdapter {
|
||||||
|
|
||||||
|
private Context context;
|
||||||
|
private List<DailySudoku> sudokuList;
|
||||||
|
|
||||||
|
public SudokuListAdapter(Context context, List<DailySudoku> sudokuList) {
|
||||||
|
this.context = context;
|
||||||
|
this.sudokuList = sudokuList;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getCount() {
|
||||||
|
return sudokuList.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getItem(int position) {
|
||||||
|
return sudokuList.get(position);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getItemId(int position) {
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View getView(int position, View convertView, ViewGroup parent) {
|
||||||
|
DailySudoku sudoku = sudokuList.get(position);
|
||||||
|
|
||||||
|
if (convertView == null) {
|
||||||
|
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||||
|
convertView = (View) inflater.inflate(R.layout.list_entry_layout, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
TextView gameType = (TextView)convertView.findViewById(R.id.loadgame_listentry_gametype);
|
||||||
|
TextView difficulty =(TextView)convertView.findViewById(R.id.loadgame_listentry_difficultytext);
|
||||||
|
RatingBar difficultyBar =(RatingBar)convertView.findViewById(R.id.loadgame_listentry_difficultybar);
|
||||||
|
TextView playedTime = (TextView)convertView.findViewById(R.id.loadgame_listentry_timeplayed);
|
||||||
|
TextView lastTimePlayed = (TextView)convertView.findViewById(R.id.loadgame_listentry_lasttimeplayed);
|
||||||
|
ImageView image = (ImageView)convertView.findViewById(R.id.loadgame_listentry_gametypeimage);
|
||||||
|
ImageView customImage = (ImageView)convertView.findViewById(R.id.loadgame_listentry_custom_icon);
|
||||||
|
|
||||||
|
|
||||||
|
image.setImageResource(R.drawable.icon_default_9x9);
|
||||||
|
|
||||||
|
gameType.setText(sudoku.getGameType().getStringResID());
|
||||||
|
difficulty.setText(sudoku.getDifficulty().getStringResID());
|
||||||
|
difficultyBar.setNumStars(GameDifficulty.getValidDifficultyList().size());
|
||||||
|
difficultyBar.setMax(GameDifficulty.getValidDifficultyList().size());
|
||||||
|
difficultyBar.setRating(GameDifficulty.getValidDifficultyList().indexOf(sudoku.getDifficulty())+1);
|
||||||
|
customImage.setVisibility(View.INVISIBLE);
|
||||||
|
|
||||||
|
|
||||||
|
int id = sudoku.getId();
|
||||||
|
Calendar cal = Calendar.getInstance();
|
||||||
|
cal.set(id%10000, (id/10000) % 100, id/1000000, 0, 0, 0 );
|
||||||
|
|
||||||
|
|
||||||
|
DateFormat format = DateFormat.getDateInstance();
|
||||||
|
format.setTimeZone(TimeZone.getDefault());
|
||||||
|
|
||||||
|
lastTimePlayed.setText(format.format(cal.getTime()));
|
||||||
|
|
||||||
|
playedTime.setText(sudoku.getTimeNeeded());
|
||||||
|
return convertView;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,24 +1,49 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package org.secuso.privacyfriendlysudoku.ui;
|
package org.secuso.privacyfriendlysudoku.ui;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.app.DialogFragment;
|
import android.app.DialogFragment;
|
||||||
|
import android.content.ClipData;
|
||||||
|
import android.content.ClipboardManager;
|
||||||
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
import android.graphics.Point;
|
import android.graphics.Point;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.preference.PreferenceActivity;
|
import android.preference.PreferenceActivity;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import com.google.android.material.navigation.NavigationView;
|
import com.google.android.material.navigation.NavigationView;
|
||||||
|
|
||||||
|
import androidx.appcompat.app.AppCompatDelegate;
|
||||||
import androidx.core.view.GravityCompat;
|
import androidx.core.view.GravityCompat;
|
||||||
import androidx.drawerlayout.widget.DrawerLayout;
|
import androidx.drawerlayout.widget.DrawerLayout;
|
||||||
import androidx.appcompat.app.ActionBarDrawerToggle;
|
import androidx.appcompat.app.ActionBarDrawerToggle;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
import androidx.appcompat.widget.Toolbar;
|
import androidx.appcompat.widget.Toolbar;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
import android.view.Gravity;
|
import android.view.Gravity;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
@ -27,28 +52,40 @@ import android.widget.Button;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.RatingBar;
|
import android.widget.RatingBar;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
import org.secuso.privacyfriendlysudoku.controller.GameController;
|
import org.secuso.privacyfriendlysudoku.controller.GameController;
|
||||||
import org.secuso.privacyfriendlysudoku.controller.GameStateManager;
|
import org.secuso.privacyfriendlysudoku.controller.GameStateManager;
|
||||||
import org.secuso.privacyfriendlysudoku.controller.SaveLoadStatistics;
|
import org.secuso.privacyfriendlysudoku.controller.SaveLoadStatistics;
|
||||||
import org.secuso.privacyfriendlysudoku.controller.Symbol;
|
import org.secuso.privacyfriendlysudoku.controller.Symbol;
|
||||||
import org.secuso.privacyfriendlysudoku.controller.helper.GameInfoContainer;
|
import org.secuso.privacyfriendlysudoku.controller.helper.GameInfoContainer;
|
||||||
|
import org.secuso.privacyfriendlysudoku.controller.qqwing.QQWing;
|
||||||
import org.secuso.privacyfriendlysudoku.game.GameDifficulty;
|
import org.secuso.privacyfriendlysudoku.game.GameDifficulty;
|
||||||
import org.secuso.privacyfriendlysudoku.game.GameType;
|
import org.secuso.privacyfriendlysudoku.game.GameType;
|
||||||
import org.secuso.privacyfriendlysudoku.game.listener.IGameSolvedListener;
|
import org.secuso.privacyfriendlysudoku.game.listener.IGameSolvedListener;
|
||||||
import org.secuso.privacyfriendlysudoku.game.listener.ITimerListener;
|
import org.secuso.privacyfriendlysudoku.game.listener.ITimerListener;
|
||||||
import org.secuso.privacyfriendlysudoku.ui.listener.IHintDialogFragmentListener;
|
import org.secuso.privacyfriendlysudoku.ui.listener.IHintDialogFragmentListener;
|
||||||
import org.secuso.privacyfriendlysudoku.ui.listener.IResetDialogFragmentListener;
|
import org.secuso.privacyfriendlysudoku.ui.listener.IResetDialogFragmentListener;
|
||||||
|
import org.secuso.privacyfriendlysudoku.ui.listener.IShareDialogFragmentListener;
|
||||||
import org.secuso.privacyfriendlysudoku.ui.view.R;
|
import org.secuso.privacyfriendlysudoku.ui.view.R;
|
||||||
import org.secuso.privacyfriendlysudoku.ui.view.SudokuFieldLayout;
|
import org.secuso.privacyfriendlysudoku.ui.view.SudokuFieldLayout;
|
||||||
import org.secuso.privacyfriendlysudoku.ui.view.SudokuKeyboardLayout;
|
import org.secuso.privacyfriendlysudoku.ui.view.SudokuKeyboardLayout;
|
||||||
import org.secuso.privacyfriendlysudoku.ui.view.SudokuSpecialButtonLayout;
|
import org.secuso.privacyfriendlysudoku.ui.view.SudokuSpecialButtonLayout;
|
||||||
import org.secuso.privacyfriendlysudoku.ui.view.WinDialog;
|
import org.secuso.privacyfriendlysudoku.ui.view.WinDialog;
|
||||||
|
import org.secuso.privacyfriendlysudoku.ui.view.databinding.DialogFragmentShareBoardBinding;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class GameActivity extends BaseActivity implements NavigationView.OnNavigationItemSelectedListener, IGameSolvedListener ,ITimerListener, IHintDialogFragmentListener, IResetDialogFragmentListener {
|
public class GameActivity extends BaseActivity implements NavigationView.OnNavigationItemSelectedListener, IGameSolvedListener ,ITimerListener, IHintDialogFragmentListener, IResetDialogFragmentListener, IShareDialogFragmentListener {
|
||||||
|
|
||||||
|
public static final List<Uri> validUris = Arrays.asList(
|
||||||
|
Uri.parse("https://sudoku.secuso.org"),
|
||||||
|
Uri.parse("http://sudoku.secuso.org"),
|
||||||
|
Uri.parse("sudoku://")
|
||||||
|
);
|
||||||
|
|
||||||
GameController gameController;
|
GameController gameController;
|
||||||
SudokuFieldLayout layout;
|
SudokuFieldLayout layout;
|
||||||
|
@ -57,15 +94,27 @@ public class GameActivity extends BaseActivity implements NavigationView.OnNavig
|
||||||
TextView timerView;
|
TextView timerView;
|
||||||
TextView viewName ;
|
TextView viewName ;
|
||||||
RatingBar ratingBar;
|
RatingBar ratingBar;
|
||||||
private boolean gameSolved = false;
|
|
||||||
SaveLoadStatistics statistics = new SaveLoadStatistics(this);
|
SaveLoadStatistics statistics = new SaveLoadStatistics(this);
|
||||||
WinDialog dialog = null;
|
WinDialog dialog = null;
|
||||||
|
private boolean gameSolved = false;
|
||||||
|
private boolean startGame = true;
|
||||||
|
|
||||||
|
public static String timeToString(int time) {
|
||||||
|
int seconds = time % 60;
|
||||||
|
int minutes = ((time - seconds) / 60) % 60;
|
||||||
|
int hours = (time - minutes - seconds) / (3600);
|
||||||
|
String h, m, s;
|
||||||
|
s = (seconds < 10) ? "0" + String.valueOf(seconds) : String.valueOf(seconds);
|
||||||
|
m = (minutes < 10) ? "0" + String.valueOf(minutes) : String.valueOf(minutes);
|
||||||
|
h = (hours < 10) ? "0" + String.valueOf(hours) : String.valueOf(hours);
|
||||||
|
return h + ":" + m + ":" + s;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onPostCreate(Bundle savedInstanceState) {
|
protected void onPostCreate(Bundle savedInstanceState) {
|
||||||
super.onPostCreate(savedInstanceState);
|
super.onPostCreate(savedInstanceState);
|
||||||
|
|
||||||
if(gameSolved) {
|
if(gameSolved || !startGame) {
|
||||||
gameController.pauseTimer();
|
gameController.pauseTimer();
|
||||||
} else {
|
} else {
|
||||||
// start the game
|
// start the game
|
||||||
|
@ -80,41 +129,165 @@ public class GameActivity extends BaseActivity implements NavigationView.OnNavig
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
|
|
||||||
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
|
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
|
||||||
|
|
||||||
|
/*
|
||||||
|
If the app is started via a deeplink, the GameActivity is the first activity the user accesses,
|
||||||
|
so we need to set the dark mode settings in this activity as well
|
||||||
|
*/
|
||||||
|
if (sharedPref.getBoolean("pref_dark_mode_setting", false )) {
|
||||||
|
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
|
||||||
|
} else if (sharedPref.getBoolean("pref_dark_mode_automatically_by_system", false)) {
|
||||||
|
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);
|
||||||
|
|
||||||
|
} else if(sharedPref.getBoolean("pref_dark_mode_automatically_by_battery", false)){
|
||||||
|
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY);
|
||||||
|
} else {
|
||||||
|
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
|
||||||
|
}
|
||||||
|
|
||||||
if(sharedPref.getBoolean("pref_keep_screen_on", true)) {
|
if(sharedPref.getBoolean("pref_keep_screen_on", true)) {
|
||||||
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
GameType gameType = GameType.Unspecified;
|
GameType gameType = GameType.Unspecified;
|
||||||
GameDifficulty gameDifficulty = GameDifficulty.Unspecified;
|
GameDifficulty gameDifficulty = GameDifficulty.Unspecified;
|
||||||
int loadLevelID = 0;
|
int loadLevelID = 0;
|
||||||
boolean loadLevel = false;
|
boolean loadLevel = false;
|
||||||
|
|
||||||
if(savedInstanceState == null) {
|
if(savedInstanceState == null) {
|
||||||
|
|
||||||
Bundle extras = getIntent().getExtras();
|
Bundle extras = getIntent().getExtras();
|
||||||
if (extras != null) {
|
|
||||||
gameType = GameType.valueOf(extras.getString("gameType", GameType.Default_9x9.name()));
|
|
||||||
gameDifficulty = GameDifficulty.valueOf(extras.getString("gameDifficulty", GameDifficulty.Moderate.name()));
|
|
||||||
loadLevel = extras.getBoolean("loadLevel", false);
|
|
||||||
if (loadLevel) {
|
|
||||||
loadLevelID = extras.getInt("loadLevelID");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
If a (deep) link is used to access the activity, the content of the link cannot be accessed
|
||||||
|
as a part of the getExtras() bundle. Instead, it needs to be saved as an URI object
|
||||||
|
*/
|
||||||
|
Uri data = getIntent().getData();
|
||||||
gameController = new GameController(sharedPref, getApplicationContext());
|
gameController = new GameController(sharedPref, getApplicationContext());
|
||||||
|
|
||||||
List<GameInfoContainer> loadableGames = GameStateManager.getLoadableGameList();
|
// Intents coming from the LoadGameActivity and MainActivity can be identified based on the keys the getExtras() bundle contains
|
||||||
|
boolean intentReceivedFromMainActivity = extras != null &&
|
||||||
|
(extras.containsKey("gameType") || extras.containsKey("loadLevel"));
|
||||||
|
|
||||||
|
/*
|
||||||
|
If data is not null and the intent was not received from the MainActivity/ LoadGameActivity, the source of the intent must be the
|
||||||
|
CreateSudokuActivity, the ImportBoardDialog or a deep link, meaning data carries an URI containing an encoded sudoku
|
||||||
|
*/
|
||||||
|
if (data != null && !intentReceivedFromMainActivity) {
|
||||||
|
// extract encoded sudoku board from the URI
|
||||||
|
String input = "";
|
||||||
|
|
||||||
|
for (int i = 0; i < validUris.size(); i++) {
|
||||||
|
if (data.getScheme().equals(validUris.get(i).getScheme())) {
|
||||||
|
if (validUris.get(i).getHost().equals("")) {
|
||||||
|
input = data.getHost();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (data.getHost().equals(validUris.get(i).getHost())) {
|
||||||
|
input = data.getPath();
|
||||||
|
input =input.replace("/", "");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save all of the information that can be extracted from the encoded board in a GameInfoContainer object
|
||||||
|
int sectionSize = (int)Math.sqrt(input.length());
|
||||||
|
int boardSize = sectionSize * sectionSize;
|
||||||
|
QQWing difficultyCheck;
|
||||||
|
GameInfoContainer container = new GameInfoContainer(0, GameDifficulty.Unspecified,
|
||||||
|
GameType.Unspecified, new int [boardSize], new int [boardSize], new boolean [boardSize][sectionSize]);
|
||||||
|
container.setCustom(extras != null && extras.getBoolean("isCustom", false));
|
||||||
|
|
||||||
|
try {
|
||||||
|
container.parseGameType("Default_" + sectionSize + "x" + sectionSize);
|
||||||
|
container.parseFixedValues(input);
|
||||||
|
difficultyCheck = new QQWing(container.getGameType(), GameDifficulty.Unspecified);
|
||||||
|
|
||||||
|
// calculate difficulty of the imported sudoku
|
||||||
|
difficultyCheck.setRecordHistory(true);
|
||||||
|
difficultyCheck.setPuzzle(container.getFixedValues());
|
||||||
|
difficultyCheck.solve();
|
||||||
|
|
||||||
|
container.parseDifficulty(difficultyCheck.getDifficulty().toString());
|
||||||
|
|
||||||
|
// A sudoku is that does not have a unique solution is deemed 'unplayable' and may not be started
|
||||||
|
startGame = difficultyCheck.hasUniqueSolution();
|
||||||
|
|
||||||
|
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
// If the imported code does not actually encode a valid sudoku, it needs to be rejected
|
||||||
|
startGame = false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
set up a blank sudoku field that can be displayed in the activity while the player is notified that
|
||||||
|
the link they imported does not encode a valid sudoku
|
||||||
|
*/
|
||||||
|
sectionSize = GameType.Default_9x9.getSize();
|
||||||
|
boardSize = sectionSize * sectionSize;
|
||||||
|
container = new GameInfoContainer(0, GameDifficulty.Unspecified,
|
||||||
|
GameType.Default_9x9, new int [boardSize], new int [boardSize], new boolean [boardSize][sectionSize]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notify the user if the sudoku they tried to import cannot be played and finish the activity
|
||||||
|
if (!startGame) {
|
||||||
|
AlertDialog.Builder builder = new AlertDialog.Builder(GameActivity.this, R.style.AppTheme_Dialog);
|
||||||
|
builder.setMessage(R.string.impossible_import_notice)
|
||||||
|
.setCancelable(false)
|
||||||
|
.setPositiveButton(R.string.okay, new DialogInterface.OnClickListener() {
|
||||||
|
public void onClick(DialogInterface dialog, int id) {
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
AlertDialog alert = builder.create();
|
||||||
|
alert.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
gameController.loadLevel(container);
|
||||||
|
|
||||||
if (loadLevel && loadableGames.size() > loadLevelID) {
|
|
||||||
// load level from GameStateManager
|
|
||||||
gameController.loadLevel(loadableGames.get(loadLevelID));
|
|
||||||
} else {
|
} else {
|
||||||
// load a new level
|
boolean isDailySudoku = false;
|
||||||
gameController.loadNewLevel(gameType, gameDifficulty);
|
if (extras != null) {
|
||||||
|
gameType = GameType.valueOf(extras.getString("gameType", GameType.Default_9x9.name()));
|
||||||
|
gameDifficulty = GameDifficulty.valueOf(extras.getString("gameDifficulty", GameDifficulty.Moderate.name()));
|
||||||
|
isDailySudoku = extras.getBoolean("isDailySudoku", false);
|
||||||
|
loadLevel = extras.getBoolean("loadLevel", false);
|
||||||
|
if (loadLevel) {
|
||||||
|
loadLevelID = extras.getInt("loadLevelID");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
The 'isDailySudoku' key is only set by the DailySudokuActivity if a new daily sudoku needs to be calculated;
|
||||||
|
otherwise, the extras simply contain the id of the daily sudoku. Therefore, calculate the new daily sudoko if
|
||||||
|
'isDailySudoku' is true
|
||||||
|
*/
|
||||||
|
if (isDailySudoku) {
|
||||||
|
gameController.loadNewDailySudokuLevel();
|
||||||
|
} else {
|
||||||
|
|
||||||
|
List<GameInfoContainer> loadableGames = GameStateManager.getLoadableGameList();
|
||||||
|
|
||||||
|
if (loadLevel) {
|
||||||
|
if (loadableGames.size() > loadLevelID) {
|
||||||
|
// load level from GameStateManager
|
||||||
|
gameController.loadLevel(loadableGames.get(loadLevelID));
|
||||||
|
} else if (loadLevelID == GameController.DAILY_SUDOKU_ID) {
|
||||||
|
for (GameInfoContainer container : loadableGames) {
|
||||||
|
if (container.getID() == loadLevelID) {
|
||||||
|
gameController.loadLevel(container);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// load a new level
|
||||||
|
gameController.loadNewLevel(gameType, gameDifficulty);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
gameController = savedInstanceState.getParcelable("gameController");
|
gameController = savedInstanceState.getParcelable("gameController");
|
||||||
|
@ -170,7 +343,7 @@ public class GameActivity extends BaseActivity implements NavigationView.OnNavig
|
||||||
|
|
||||||
//set Special keys
|
//set Special keys
|
||||||
specialButtonLayout = (SudokuSpecialButtonLayout) findViewById(R.id.sudokuSpecialLayout);
|
specialButtonLayout = (SudokuSpecialButtonLayout) findViewById(R.id.sudokuSpecialLayout);
|
||||||
specialButtonLayout.setButtons(p.x, gameController, keyboard, getFragmentManager(), orientation);
|
specialButtonLayout.setButtons(p.x, gameController, keyboard, getFragmentManager(), orientation, GameActivity.this);
|
||||||
|
|
||||||
//set TimerView
|
//set TimerView
|
||||||
timerView = (TextView)findViewById(R.id.timerView);
|
timerView = (TextView)findViewById(R.id.timerView);
|
||||||
|
@ -217,11 +390,21 @@ public class GameActivity extends BaseActivity implements NavigationView.OnNavig
|
||||||
@Override
|
@Override
|
||||||
public void onPause(){
|
public void onPause(){
|
||||||
super.onPause();
|
super.onPause();
|
||||||
if(!gameSolved) {
|
|
||||||
|
// Do not save solved or unplayable sudokus
|
||||||
|
if(!gameSolved && startGame) {
|
||||||
gameController.saveGame(this);
|
gameController.saveGame(this);
|
||||||
}
|
}
|
||||||
gameController.deleteTimer();
|
gameController.deleteTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onNewIntent(Intent intent) {
|
||||||
|
super.onNewIntent(intent);
|
||||||
|
startActivity(intent);
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onResume(){
|
public void onResume(){
|
||||||
super.onResume();
|
super.onResume();
|
||||||
|
@ -233,7 +416,7 @@ public class GameActivity extends BaseActivity implements NavigationView.OnNavig
|
||||||
|
|
||||||
gameController.initTimer();
|
gameController.initTimer();
|
||||||
|
|
||||||
if(!gameSolved) {
|
if(!gameSolved && startGame) {
|
||||||
mHandler.postDelayed(new Runnable() {
|
mHandler.postDelayed(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
@ -253,6 +436,12 @@ public class GameActivity extends BaseActivity implements NavigationView.OnNavig
|
||||||
keyboard.setSymbols(s);
|
keyboard.setSymbols(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*@Override
|
||||||
|
public boolean onCreateOptionsMenu(Menu menu) {
|
||||||
|
// Inflate the menu; this adds items to the action bar if it is present.
|
||||||
|
getMenuInflater().inflate(R.menu.game_view, menu);
|
||||||
|
return true;
|
||||||
|
}*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBackPressed() {
|
public void onBackPressed() {
|
||||||
|
@ -265,13 +454,6 @@ public class GameActivity extends BaseActivity implements NavigationView.OnNavig
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*@Override
|
|
||||||
public boolean onCreateOptionsMenu(Menu menu) {
|
|
||||||
// Inflate the menu; this adds items to the action bar if it is present.
|
|
||||||
getMenuInflater().inflate(R.menu.game_view, menu);
|
|
||||||
return true;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
@SuppressWarnings("StatementWithEmptyBody")
|
@SuppressWarnings("StatementWithEmptyBody")
|
||||||
@Override
|
@Override
|
||||||
public boolean onNavigationItemSelected(MenuItem item) {
|
public boolean onNavigationItemSelected(MenuItem item) {
|
||||||
|
@ -286,6 +468,39 @@ public class GameActivity extends BaseActivity implements NavigationView.OnNavig
|
||||||
resetDialog.show(getFragmentManager(), "ResetDialogFragment");
|
resetDialog.show(getFragmentManager(), "ResetDialogFragment");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case R.id.menu_share:
|
||||||
|
// Create import link from current sudoku board
|
||||||
|
String scheme = GameActivity.validUris.size() > 0 ? GameActivity.validUris.get(0).getScheme()
|
||||||
|
+ "://" + GameActivity.validUris.get(0).getHost() : "";
|
||||||
|
if (!scheme.equals("") && !scheme.endsWith("/")) scheme = scheme + "/";
|
||||||
|
String codeForClipboard = scheme + gameController.getCodeOfField();
|
||||||
|
|
||||||
|
// Create new ShareBoardDialog using the previously created links
|
||||||
|
ShareBoardDialog shareDialog = new ShareBoardDialog();
|
||||||
|
shareDialog.setDisplayCode(codeForClipboard);
|
||||||
|
shareDialog.setCopyClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
// remember to include alternate code for older android versions
|
||||||
|
|
||||||
|
//save link to clipboard
|
||||||
|
ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
|
||||||
|
|
||||||
|
if (clipboard != null) {
|
||||||
|
ClipData clip = ClipData.newPlainText("BoardCode", codeForClipboard);
|
||||||
|
clipboard.setPrimaryClip(clip);
|
||||||
|
Toast.makeText(GameActivity.this, R.string.copy_code_confirmation_toast,
|
||||||
|
Toast.LENGTH_LONG).show();
|
||||||
|
} else {
|
||||||
|
Toast.makeText(GameActivity.this, R.string.copy_code_error_toast,
|
||||||
|
Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
shareDialog.show(getFragmentManager(), "ShareDialogFragment");
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
case R.id.nav_newgame:
|
case R.id.nav_newgame:
|
||||||
//create new game
|
//create new game
|
||||||
intent = new Intent(this, MainActivity.class);
|
intent = new Intent(this, MainActivity.class);
|
||||||
|
@ -296,8 +511,6 @@ public class GameActivity extends BaseActivity implements NavigationView.OnNavig
|
||||||
case R.id.menu_settings:
|
case R.id.menu_settings:
|
||||||
//open settings
|
//open settings
|
||||||
intent = new Intent(this,SettingsActivity.class);
|
intent = new Intent(this,SettingsActivity.class);
|
||||||
intent.putExtra( PreferenceActivity.EXTRA_SHOW_FRAGMENT, SettingsActivity.GamePreferenceFragment.class.getName() );
|
|
||||||
intent.putExtra( PreferenceActivity.EXTRA_NO_HEADERS, true );
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case R.id.nav_highscore:
|
case R.id.nav_highscore:
|
||||||
|
@ -341,7 +554,6 @@ public class GameActivity extends BaseActivity implements NavigationView.OnNavig
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSolved() {
|
public void onSolved() {
|
||||||
gameSolved = true;
|
gameSolved = true;
|
||||||
|
@ -350,12 +562,33 @@ public class GameActivity extends BaseActivity implements NavigationView.OnNavig
|
||||||
gameController.deleteGame(this);
|
gameController.deleteGame(this);
|
||||||
disableReset();
|
disableReset();
|
||||||
|
|
||||||
//Show time hints new plus old best time
|
//Save solved sudoku, if it happens to be a daily sudoku, to daily sudoku database
|
||||||
|
if(gameController.getGameID() == GameController.DAILY_SUDOKU_ID) {
|
||||||
|
gameController.saveDailySudoku(GameActivity.this);
|
||||||
|
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
|
||||||
|
SharedPreferences.Editor editor = sharedPref.edit();
|
||||||
|
/*
|
||||||
|
set 'finishedForToday' setting to 'true', signifying that the player has solved the daily
|
||||||
|
sudoku and can no longer play it today
|
||||||
|
*/
|
||||||
|
editor.putBoolean("finishedForToday", true);
|
||||||
|
editor.apply();
|
||||||
|
}
|
||||||
|
|
||||||
statistics.saveGameStats();
|
//Don't save statistics if game is custom
|
||||||
|
boolean isNewBestTime;
|
||||||
|
|
||||||
|
if (!gameController.gameIsCustom()) {
|
||||||
|
//Show time hints new plus old best time
|
||||||
|
statistics.saveGameStats();
|
||||||
|
isNewBestTime = gameController.getUsedHints() == 0
|
||||||
|
&& statistics.loadStats(gameController.getGameType(),gameController.getDifficulty()).getMinTime() >= gameController.getTime();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// cannot be best time if sudoku is custom
|
||||||
|
isNewBestTime = false;
|
||||||
|
}
|
||||||
|
|
||||||
boolean isNewBestTime = gameController.getUsedHints() == 0
|
|
||||||
&& statistics.loadStats(gameController.getGameType(),gameController.getDifficulty()).getMinTime() >= gameController.getTime();
|
|
||||||
|
|
||||||
dialog = new WinDialog(this, R.style.WinDialog , timeToString(gameController.getTime()), String.valueOf(gameController.getUsedHints()), isNewBestTime);
|
dialog = new WinDialog(this, R.style.WinDialog , timeToString(gameController.getTime()), String.valueOf(gameController.getUsedHints()), isNewBestTime);
|
||||||
|
|
||||||
|
@ -395,18 +628,6 @@ public class GameActivity extends BaseActivity implements NavigationView.OnNavig
|
||||||
specialButtonLayout.setButtonsEnabled(false);
|
specialButtonLayout.setButtonsEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String timeToString(int time) {
|
|
||||||
int seconds = time % 60;
|
|
||||||
int minutes = ((time - seconds) / 60) % 60;
|
|
||||||
int hours = (time - minutes - seconds) / (3600);
|
|
||||||
String h, m, s;
|
|
||||||
s = (seconds < 10) ? "0" + String.valueOf(seconds) : String.valueOf(seconds);
|
|
||||||
m = (minutes < 10) ? "0" + String.valueOf(minutes) : String.valueOf(minutes);
|
|
||||||
h = (hours < 10) ? "0" + String.valueOf(hours) : String.valueOf(hours);
|
|
||||||
return h + ":" + m + ":" + s;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void disableReset(){
|
private void disableReset(){
|
||||||
NavigationView navView = (NavigationView)findViewById(R.id.nav_view);
|
NavigationView navView = (NavigationView)findViewById(R.id.nav_view);
|
||||||
Menu navMenu = navView.getMenu();
|
Menu navMenu = navView.getMenu();
|
||||||
|
@ -418,7 +639,7 @@ public class GameActivity extends BaseActivity implements NavigationView.OnNavig
|
||||||
// display the time
|
// display the time
|
||||||
timerView.setText(timeToString(time));
|
timerView.setText(timeToString(time));
|
||||||
|
|
||||||
if(gameSolved) return;
|
if(gameSolved || !startGame) return;
|
||||||
// save time
|
// save time
|
||||||
gameController.saveGame(this);
|
gameController.saveGame(this);
|
||||||
}
|
}
|
||||||
|
@ -433,11 +654,100 @@ public class GameActivity extends BaseActivity implements NavigationView.OnNavig
|
||||||
gameController.resetLevel();
|
gameController.resetLevel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onShareDialogPositiveClick(String input) {
|
||||||
|
Intent sendBoardIntent = new Intent();
|
||||||
|
sendBoardIntent.setAction(Intent.ACTION_SEND);
|
||||||
|
sendBoardIntent.putExtra(Intent.EXTRA_TEXT, input);
|
||||||
|
sendBoardIntent.setType("text/plain");
|
||||||
|
|
||||||
|
Intent shareBoardIntent = Intent.createChooser(sendBoardIntent, null);
|
||||||
|
startActivity(shareBoardIntent);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDialogNegativeClick() {
|
public void onDialogNegativeClick() {
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSaveInstanceState(Bundle savedInstanceState) {
|
||||||
|
// Always call the superclass so it can save the view hierarchy state
|
||||||
|
super.onSaveInstanceState(savedInstanceState);
|
||||||
|
|
||||||
|
// Save the user's current game state
|
||||||
|
savedInstanceState.putParcelable("gameController", gameController);
|
||||||
|
savedInstanceState.putBoolean("gameSolved", gameSolved);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRestoreInstanceState(Bundle savedInstanceState) {
|
||||||
|
super.onRestoreInstanceState(savedInstanceState);
|
||||||
|
|
||||||
|
gameController = savedInstanceState.getParcelable("gameController");
|
||||||
|
gameSolved = savedInstanceState.getBoolean("gameSolved");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ShareBoardDialog extends DialogFragment {
|
||||||
|
private LinkedList<IShareDialogFragmentListener> listeners = new LinkedList<>();
|
||||||
|
|
||||||
|
/*declare empty display code and click listener in case anyone
|
||||||
|
* tries to call the ShareBoardDialog without setting those attributes first
|
||||||
|
*/
|
||||||
|
|
||||||
|
private String displayCode = "";
|
||||||
|
private View.OnClickListener copyClickListener = new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public void setDisplayCode(String displayCode) {
|
||||||
|
this.displayCode = displayCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCopyClickListener(View.OnClickListener listener) {
|
||||||
|
copyClickListener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAttach(Activity activity) {
|
||||||
|
super.onAttach(activity);
|
||||||
|
// Verify that the host activity implements the callback interface
|
||||||
|
if(activity instanceof IShareDialogFragmentListener) {
|
||||||
|
listeners.add((IShareDialogFragmentListener) activity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||||
|
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity(), R.style.AppTheme_Dialog);
|
||||||
|
|
||||||
|
LayoutInflater inflater = getActivity().getLayoutInflater();
|
||||||
|
DialogFragmentShareBoardBinding binding = DialogFragmentShareBoardBinding.inflate(inflater);
|
||||||
|
|
||||||
|
binding.ver3DisplaySudokuTextView.setText(displayCode);
|
||||||
|
binding.ver3DisplaySudokuTextView.setEnabled(false);
|
||||||
|
binding.ver3CopySudokuToClipboardButton.setOnClickListener(copyClickListener);
|
||||||
|
builder.setView(binding.getRoot());
|
||||||
|
|
||||||
|
builder.setPositiveButton(R.string.share_confirmation_confirm, new DialogInterface.OnClickListener() {
|
||||||
|
public void onClick(DialogInterface dialog, int id) {
|
||||||
|
for(IShareDialogFragmentListener l : listeners) {
|
||||||
|
l.onShareDialogPositiveClick(binding.ver3DisplaySudokuTextView.getText().toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
|
||||||
|
public void onClick(DialogInterface dialog, int id) {
|
||||||
|
// User cancelled the dialog
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return builder.create();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static class ResetConfirmationDialog extends DialogFragment {
|
public static class ResetConfirmationDialog extends DialogFragment {
|
||||||
|
|
||||||
LinkedList<IResetDialogFragmentListener> listeners = new LinkedList<>();
|
LinkedList<IResetDialogFragmentListener> listeners = new LinkedList<>();
|
||||||
|
@ -454,7 +764,7 @@ public class GameActivity extends BaseActivity implements NavigationView.OnNavig
|
||||||
@Override
|
@Override
|
||||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||||
// Use the Builder class for convenient dialog construction
|
// Use the Builder class for convenient dialog construction
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity(), R.style.AppTheme_Dialog);
|
||||||
builder.setMessage(R.string.reset_confirmation)
|
builder.setMessage(R.string.reset_confirmation)
|
||||||
.setPositiveButton(R.string.reset_confirmation_confirm, new DialogInterface.OnClickListener() {
|
.setPositiveButton(R.string.reset_confirmation_confirm, new DialogInterface.OnClickListener() {
|
||||||
public void onClick(DialogInterface dialog, int id) {
|
public void onClick(DialogInterface dialog, int id) {
|
||||||
|
@ -472,20 +782,4 @@ public class GameActivity extends BaseActivity implements NavigationView.OnNavig
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,19 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package org.secuso.privacyfriendlysudoku.ui;
|
package org.secuso.privacyfriendlysudoku.ui;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,19 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package org.secuso.privacyfriendlysudoku.ui;
|
package org.secuso.privacyfriendlysudoku.ui;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
@ -21,6 +37,7 @@ import android.widget.ListView;
|
||||||
import android.widget.RatingBar;
|
import android.widget.RatingBar;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import org.secuso.privacyfriendlysudoku.controller.GameController;
|
||||||
import org.secuso.privacyfriendlysudoku.controller.GameStateManager;
|
import org.secuso.privacyfriendlysudoku.controller.GameStateManager;
|
||||||
import org.secuso.privacyfriendlysudoku.controller.helper.GameInfoContainer;
|
import org.secuso.privacyfriendlysudoku.controller.helper.GameInfoContainer;
|
||||||
import org.secuso.privacyfriendlysudoku.game.GameDifficulty;
|
import org.secuso.privacyfriendlysudoku.game.GameDifficulty;
|
||||||
|
@ -70,6 +87,13 @@ public class LoadGameActivity extends BaseActivity implements IDeleteDialogFragm
|
||||||
GameStateManager gameStateManager = new GameStateManager(this, settings);
|
GameStateManager gameStateManager = new GameStateManager(this, settings);
|
||||||
loadableGameList = gameStateManager.loadGameStateInfo();
|
loadableGameList = gameStateManager.loadGameStateInfo();
|
||||||
|
|
||||||
|
for (GameInfoContainer container : loadableGameList) {
|
||||||
|
if (container.getID() == GameController.DAILY_SUDOKU_ID) {
|
||||||
|
loadableGameList.remove(container);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
AdapterView.OnItemClickListener clickListener = new AdapterView.OnItemClickListener() {
|
AdapterView.OnItemClickListener clickListener = new AdapterView.OnItemClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||||
|
@ -137,7 +161,7 @@ public class LoadGameActivity extends BaseActivity implements IDeleteDialogFragm
|
||||||
@Override
|
@Override
|
||||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||||
// Use the Builder class for convenient dialog construction
|
// Use the Builder class for convenient dialog construction
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity(), R.style.AppTheme_Dialog);
|
||||||
builder.setMessage(R.string.loadgame_delete_confirmation)
|
builder.setMessage(R.string.loadgame_delete_confirmation)
|
||||||
.setPositiveButton(R.string.loadgame_delete_confirm, new DialogInterface.OnClickListener() {
|
.setPositiveButton(R.string.loadgame_delete_confirm, new DialogInterface.OnClickListener() {
|
||||||
public void onClick(DialogInterface dialog, int id) {
|
public void onClick(DialogInterface dialog, int id) {
|
||||||
|
@ -201,6 +225,8 @@ public class LoadGameActivity extends BaseActivity implements IDeleteDialogFragm
|
||||||
TextView playedTime = (TextView)convertView.findViewById(R.id.loadgame_listentry_timeplayed);
|
TextView playedTime = (TextView)convertView.findViewById(R.id.loadgame_listentry_timeplayed);
|
||||||
TextView lastTimePlayed = (TextView)convertView.findViewById(R.id.loadgame_listentry_lasttimeplayed);
|
TextView lastTimePlayed = (TextView)convertView.findViewById(R.id.loadgame_listentry_lasttimeplayed);
|
||||||
ImageView image = (ImageView)convertView.findViewById(R.id.loadgame_listentry_gametypeimage);
|
ImageView image = (ImageView)convertView.findViewById(R.id.loadgame_listentry_gametypeimage);
|
||||||
|
ImageView customImage = (ImageView)convertView.findViewById(R.id.loadgame_listentry_custom_icon);
|
||||||
|
TextView customLabel = (TextView) convertView.findViewById(R.id.loadgame_listentry_custom_label);
|
||||||
|
|
||||||
switch(gic.getGameType()) {
|
switch(gic.getGameType()) {
|
||||||
case Default_6x6:
|
case Default_6x6:
|
||||||
|
@ -221,6 +247,9 @@ public class LoadGameActivity extends BaseActivity implements IDeleteDialogFragm
|
||||||
difficultyBar.setMax(GameDifficulty.getValidDifficultyList().size());
|
difficultyBar.setMax(GameDifficulty.getValidDifficultyList().size());
|
||||||
difficultyBar.setRating(GameDifficulty.getValidDifficultyList().indexOf(gic.getDifficulty())+1);
|
difficultyBar.setRating(GameDifficulty.getValidDifficultyList().indexOf(gic.getDifficulty())+1);
|
||||||
|
|
||||||
|
customImage.setImageResource(gic.isCustom() ? R.drawable.ic_circle_blue_36dp : R.drawable.ic_circle_grey_36dp);
|
||||||
|
customLabel.setVisibility(gic.isCustom() ? View.VISIBLE : View.GONE);
|
||||||
|
|
||||||
int time = gic.getTimePlayed();
|
int time = gic.getTimePlayed();
|
||||||
int seconds = time % 60;
|
int seconds = time % 60;
|
||||||
int minutes = ((time -seconds)/60)%60 ;
|
int minutes = ((time -seconds)/60)%60 ;
|
||||||
|
|
|
@ -1,11 +1,34 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package org.secuso.privacyfriendlysudoku.ui;
|
package org.secuso.privacyfriendlysudoku.ui;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.app.Dialog;
|
||||||
|
import android.app.DialogFragment;
|
||||||
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.preference.PreferenceActivity;
|
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import com.google.android.material.navigation.NavigationView;
|
import com.google.android.material.navigation.NavigationView;
|
||||||
|
|
||||||
|
import androidx.appcompat.app.AppCompatDelegate;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
import androidx.fragment.app.FragmentManager;
|
import androidx.fragment.app.FragmentManager;
|
||||||
import androidx.fragment.app.FragmentPagerAdapter;
|
import androidx.fragment.app.FragmentPagerAdapter;
|
||||||
|
@ -13,31 +36,36 @@ import androidx.core.view.GravityCompat;
|
||||||
import androidx.viewpager.widget.ViewPager;
|
import androidx.viewpager.widget.ViewPager;
|
||||||
import androidx.drawerlayout.widget.DrawerLayout;
|
import androidx.drawerlayout.widget.DrawerLayout;
|
||||||
import androidx.appcompat.app.ActionBarDrawerToggle;
|
import androidx.appcompat.app.ActionBarDrawerToggle;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
|
||||||
import androidx.appcompat.widget.Toolbar;
|
import androidx.appcompat.widget.Toolbar;
|
||||||
|
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
|
import android.widget.CheckBox;
|
||||||
|
import android.widget.CompoundButton;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.RatingBar;
|
import android.widget.RatingBar;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import org.secuso.privacyfriendlysudoku.controller.GameController;
|
||||||
import org.secuso.privacyfriendlysudoku.controller.GameStateManager;
|
import org.secuso.privacyfriendlysudoku.controller.GameStateManager;
|
||||||
import org.secuso.privacyfriendlysudoku.controller.NewLevelManager;
|
import org.secuso.privacyfriendlysudoku.controller.NewLevelManager;
|
||||||
import org.secuso.privacyfriendlysudoku.controller.helper.GameInfoContainer;
|
import org.secuso.privacyfriendlysudoku.controller.helper.GameInfoContainer;
|
||||||
import org.secuso.privacyfriendlysudoku.game.GameDifficulty;
|
import org.secuso.privacyfriendlysudoku.game.GameDifficulty;
|
||||||
import org.secuso.privacyfriendlysudoku.game.GameType;
|
import org.secuso.privacyfriendlysudoku.game.GameType;
|
||||||
|
import org.secuso.privacyfriendlysudoku.ui.listener.IImportDialogFragmentListener;
|
||||||
import org.secuso.privacyfriendlysudoku.ui.view.R;
|
import org.secuso.privacyfriendlysudoku.ui.view.R;
|
||||||
|
import org.secuso.privacyfriendlysudoku.ui.view.databinding.DialogFragmentImportBoardBinding;
|
||||||
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.secuso.privacyfriendlysudoku.ui.TutorialActivity.ACTION_SHOW_ANYWAYS;
|
import static org.secuso.privacyfriendlysudoku.ui.TutorialActivity.ACTION_SHOW_ANYWAYS;
|
||||||
|
|
||||||
public class MainActivity extends BaseActivity implements NavigationView.OnNavigationItemSelectedListener{
|
public class MainActivity extends BaseActivity implements NavigationView.OnNavigationItemSelectedListener, IImportDialogFragmentListener{
|
||||||
|
|
||||||
RatingBar difficultyBar;
|
RatingBar difficultyBar;
|
||||||
TextView difficultyText;
|
TextView difficultyText;
|
||||||
|
@ -53,9 +81,20 @@ public class MainActivity extends BaseActivity implements NavigationView.OnNavig
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
|
|
||||||
settings = PreferenceManager.getDefaultSharedPreferences(this);
|
settings = PreferenceManager.getDefaultSharedPreferences(this);
|
||||||
|
if (settings.getBoolean("pref_dark_mode_setting", false )) {
|
||||||
|
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
|
||||||
|
|
||||||
|
} else if (settings.getBoolean("pref_dark_mode_automatically_by_system", false)) {
|
||||||
|
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);
|
||||||
|
|
||||||
|
} else if(settings.getBoolean("pref_dark_mode_automatically_by_battery", false)){
|
||||||
|
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY);
|
||||||
|
} else {
|
||||||
|
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
|
||||||
|
}
|
||||||
|
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
NewLevelManager newLevelManager = NewLevelManager.getInstance(getApplicationContext(), settings);
|
NewLevelManager newLevelManager = NewLevelManager.getInstance(getApplicationContext(), settings);
|
||||||
|
|
||||||
|
@ -121,17 +160,44 @@ public class MainActivity extends BaseActivity implements NavigationView.OnNavig
|
||||||
final LinkedList<GameDifficulty> difficultyList = GameDifficulty.getValidDifficultyList();
|
final LinkedList<GameDifficulty> difficultyList = GameDifficulty.getValidDifficultyList();
|
||||||
difficultyBar.setNumStars(difficultyList.size());
|
difficultyBar.setNumStars(difficultyList.size());
|
||||||
difficultyBar.setMax(difficultyList.size());
|
difficultyBar.setMax(difficultyList.size());
|
||||||
|
CheckBox createGameBar = (CheckBox) findViewById(R.id.circleButton);
|
||||||
difficultyBar.setOnRatingBarChangeListener(new RatingBar.OnRatingBarChangeListener() {
|
difficultyBar.setOnRatingBarChangeListener(new RatingBar.OnRatingBarChangeListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onRatingChanged(RatingBar ratingBar, float rating, boolean fromUser) {
|
public void onRatingChanged(RatingBar ratingBar, float rating, boolean fromUser) {
|
||||||
if (rating < 1) {
|
createGameBar.setChecked(false);
|
||||||
ratingBar.setRating(1);
|
((Button) findViewById(R.id.playButton)).setText(R.string.new_game);
|
||||||
|
|
||||||
|
if (rating >= 1) {
|
||||||
|
difficultyText.setText(getString(difficultyList.get((int) ratingBar.getRating() - 1).getStringResID()));
|
||||||
|
} else {
|
||||||
|
difficultyText.setText(R.string.difficulty_custom);
|
||||||
|
createGameBar.setChecked(true);
|
||||||
|
((Button)findViewById(R.id.playButton)).setText(R.string.create_game);
|
||||||
}
|
}
|
||||||
difficultyText.setText(getString(difficultyList.get((int) ratingBar.getRating() - 1).getStringResID()));
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
GameDifficulty lastChosenDifficulty = GameDifficulty.valueOf(settings.getString("lastChosenDifficulty", "Moderate"));
|
|
||||||
difficultyBar.setRating(GameDifficulty.getValidDifficultyList().indexOf(lastChosenDifficulty) + 1);
|
createGameBar.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||||
|
@Override
|
||||||
|
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||||
|
if (isChecked) {
|
||||||
|
|
||||||
|
difficultyBar.setRating(0);
|
||||||
|
((Button)findViewById(R.id.playButton)).setText(R.string.create_game);
|
||||||
|
}
|
||||||
|
createGameBar.setChecked(isChecked);
|
||||||
|
}});
|
||||||
|
|
||||||
|
String retrievedDifficulty = settings.getString("lastChosenDifficulty", "Moderate");
|
||||||
|
GameDifficulty lastChosenDifficulty = GameDifficulty.valueOf(
|
||||||
|
retrievedDifficulty.equals("Custom")? GameDifficulty.Unspecified.toString() : retrievedDifficulty);
|
||||||
|
|
||||||
|
if (lastChosenDifficulty == GameDifficulty.Unspecified) {
|
||||||
|
difficultyBar.setRating(0);
|
||||||
|
createGameBar.setChecked(true);
|
||||||
|
} else {
|
||||||
|
difficultyBar.setRating(GameDifficulty.getValidDifficultyList().indexOf(lastChosenDifficulty) + 1);
|
||||||
|
}
|
||||||
/*LayerDrawable stars = (LayerDrawable)difficultyBar.getProgressDrawable();
|
/*LayerDrawable stars = (LayerDrawable)difficultyBar.getProgressDrawable();
|
||||||
stars.getDrawable(2).setColorFilter(getResources().getColor(R.color.colorPrimary), PorterDuff.Mode.SRC_ATOP);//Color for Stars fully selected
|
stars.getDrawable(2).setColorFilter(getResources().getColor(R.color.colorPrimary), PorterDuff.Mode.SRC_ATOP);//Color for Stars fully selected
|
||||||
stars.getDrawable(1).setColorFilter(getResources().getColor(R.color.middleblue), PorterDuff.Mode.SRC_ATOP);//Color for Stars partially selected
|
stars.getDrawable(1).setColorFilter(getResources().getColor(R.color.middleblue), PorterDuff.Mode.SRC_ATOP);//Color for Stars partially selected
|
||||||
|
@ -166,8 +232,6 @@ public class MainActivity extends BaseActivity implements NavigationView.OnNavig
|
||||||
winScreen.show(fm,"win_screen_layout");*/
|
winScreen.show(fm,"win_screen_layout");*/
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void onClick(View view) {
|
public void onClick(View view) {
|
||||||
|
|
||||||
Intent i = null;
|
Intent i = null;
|
||||||
|
@ -184,6 +248,18 @@ public class MainActivity extends BaseActivity implements NavigationView.OnNavig
|
||||||
break;
|
break;
|
||||||
case R.id.playButton:
|
case R.id.playButton:
|
||||||
GameType gameType = GameType.getValidGameTypes().get(mViewPager.getCurrentItem());
|
GameType gameType = GameType.getValidGameTypes().get(mViewPager.getCurrentItem());
|
||||||
|
if (((CheckBox)findViewById(R.id.circleButton)).isChecked()) {
|
||||||
|
// start CreateSudokuActivity
|
||||||
|
i = new Intent(this, CreateSudokuActivity.class);
|
||||||
|
i.putExtra("gameType", gameType.name());
|
||||||
|
|
||||||
|
SharedPreferences.Editor editor = settings.edit();
|
||||||
|
editor.putString("lastChosenGameType", gameType.name());
|
||||||
|
editor.putString("lastChosenDifficulty", "Custom");
|
||||||
|
editor.apply();
|
||||||
|
//i.putExtra("gameDifficulty", GameDifficulty.Easy);
|
||||||
|
break;
|
||||||
|
}
|
||||||
int index = difficultyBar.getProgress()-1;
|
int index = difficultyBar.getProgress()-1;
|
||||||
GameDifficulty gameDifficulty = GameDifficulty.getValidDifficultyList().get(index < 0 ? 0 : index);
|
GameDifficulty gameDifficulty = GameDifficulty.getValidDifficultyList().get(index < 0 ? 0 : index);
|
||||||
|
|
||||||
|
@ -242,7 +318,7 @@ public class MainActivity extends BaseActivity implements NavigationView.OnNavig
|
||||||
Button continueButton = (Button)findViewById(R.id.continueButton);
|
Button continueButton = (Button)findViewById(R.id.continueButton);
|
||||||
GameStateManager fm = new GameStateManager(getBaseContext(), settings);
|
GameStateManager fm = new GameStateManager(getBaseContext(), settings);
|
||||||
List<GameInfoContainer> gic = fm.loadGameStateInfo();
|
List<GameInfoContainer> gic = fm.loadGameStateInfo();
|
||||||
if(gic.size() > 0) {
|
if(gic.size() > 0 && !(gic.size() == 1 && gic.get(0).getID() == GameController.DAILY_SUDOKU_ID)) {
|
||||||
continueButton.setEnabled(true);
|
continueButton.setEnabled(true);
|
||||||
continueButton.setBackgroundResource(R.drawable.standalone_button);
|
continueButton.setBackgroundResource(R.drawable.standalone_button);
|
||||||
} else {
|
} else {
|
||||||
|
@ -254,7 +330,7 @@ public class MainActivity extends BaseActivity implements NavigationView.OnNavig
|
||||||
@Override
|
@Override
|
||||||
public boolean onNavigationItemSelected(MenuItem item) {
|
public boolean onNavigationItemSelected(MenuItem item) {
|
||||||
// Handle navigation view item clicks here.
|
// Handle navigation view item clicks here.
|
||||||
final int id = item.getItemId();
|
int id = item.getItemId();
|
||||||
|
|
||||||
drawer.closeDrawer(GravityCompat.START);
|
drawer.closeDrawer(GravityCompat.START);
|
||||||
|
|
||||||
|
@ -271,9 +347,9 @@ public class MainActivity extends BaseActivity implements NavigationView.OnNavig
|
||||||
}
|
}
|
||||||
}, NAVDRAWER_LAUNCH_DELAY);
|
}, NAVDRAWER_LAUNCH_DELAY);
|
||||||
|
|
||||||
// fade out the active activity
|
// fade out the active activity (but not if the user chose to open the ImportBoardDialog)
|
||||||
View mainContent = findViewById(R.id.main_content);
|
View mainContent = findViewById(R.id.main_content);
|
||||||
if (mainContent != null) {
|
if (mainContent != null && id != R.id.nav_import_sudoku) {
|
||||||
mainContent.animate().alpha(0).setDuration(MAIN_CONTENT_FADEOUT_DURATION);
|
mainContent.animate().alpha(0).setDuration(MAIN_CONTENT_FADEOUT_DURATION);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -292,11 +368,13 @@ public class MainActivity extends BaseActivity implements NavigationView.OnNavig
|
||||||
Intent intent;
|
Intent intent;
|
||||||
|
|
||||||
switch(id) {
|
switch(id) {
|
||||||
|
case R.id.nav_import_sudoku:
|
||||||
|
ImportBoardDialog dialog = new ImportBoardDialog();
|
||||||
|
dialog.show(getFragmentManager(), "ImportDialogFragment");
|
||||||
|
break;
|
||||||
case R.id.menu_settings_main:
|
case R.id.menu_settings_main:
|
||||||
//open settings
|
//open settings
|
||||||
intent = new Intent(this,SettingsActivity.class);
|
intent = new Intent(this, SettingsActivity.class);
|
||||||
intent.putExtra( PreferenceActivity.EXTRA_SHOW_FRAGMENT, SettingsActivity.GamePreferenceFragment.class.getName() );
|
|
||||||
intent.putExtra( PreferenceActivity.EXTRA_NO_HEADERS, true );
|
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
overridePendingTransition(0, 0);
|
overridePendingTransition(0, 0);
|
||||||
break;
|
break;
|
||||||
|
@ -330,6 +408,12 @@ public class MainActivity extends BaseActivity implements NavigationView.OnNavig
|
||||||
overridePendingTransition(0, 0);
|
overridePendingTransition(0, 0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case R.id.nav_dailySudoku_main:
|
||||||
|
intent = new Intent(this, DailySudokuActivity.class);
|
||||||
|
startActivity(intent);
|
||||||
|
overridePendingTransition(0, 0);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -345,6 +429,106 @@ public class MainActivity extends BaseActivity implements NavigationView.OnNavig
|
||||||
return super.onOptionsItemSelected(item);
|
return super.onOptionsItemSelected(item);
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
|
public void onImportDialogPositiveClick(String input) {
|
||||||
|
String inputSudoku = null;
|
||||||
|
String prefix = "";
|
||||||
|
StringBuilder errorMessage = new StringBuilder();
|
||||||
|
|
||||||
|
// a valid input needs to contain exactly one of the valid prefixes
|
||||||
|
for (int i = 0; i < GameActivity.validUris.size(); i++) {
|
||||||
|
prefix = GameActivity.validUris.get(i).getHost().equals("") ?
|
||||||
|
GameActivity.validUris.get(i).getScheme() + "://" :
|
||||||
|
GameActivity.validUris.get(i).getScheme() + "://" + GameActivity.validUris.get(i).getHost() + "/";
|
||||||
|
if (input.startsWith(prefix)) {
|
||||||
|
inputSudoku = input.replace(prefix, "");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
String endOfRecord = i == GameActivity.validUris.size() - 1 ? "" : ", ";
|
||||||
|
errorMessage.append(prefix);
|
||||||
|
errorMessage.append(endOfRecord);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inputSudoku == null) {
|
||||||
|
Toast.makeText(MainActivity.this,
|
||||||
|
this.getString(R.string.menu_import_wrong_format_custom_sudoku) + " " + errorMessage.toString(), Toast.LENGTH_LONG).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
double size = Math.sqrt(inputSudoku.length());
|
||||||
|
boolean validSize = false;
|
||||||
|
|
||||||
|
// check whether or not the size of the encoded sudoku is valid; if not, notify the user
|
||||||
|
for (GameType type : GameType.getValidGameTypes()) {
|
||||||
|
if (type.getSize() == size) {
|
||||||
|
validSize = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!validSize) {
|
||||||
|
Toast.makeText(MainActivity.this, R.string.failed_to_verify_custom_sudoku_toast, Toast.LENGTH_LONG).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
GameType gameType = Enum.valueOf(GameType.class, "Default_" + (int)size + "x" + (int)size);
|
||||||
|
|
||||||
|
//check whether or not the sudoku is valid and has a unique solution
|
||||||
|
boolean solvable = CreateSudokuActivity.verify(gameType, inputSudoku);
|
||||||
|
|
||||||
|
// if the encoded sudoku is solvable, sent the code directly to the GameActivity; if not, notify the user
|
||||||
|
if (solvable) {
|
||||||
|
Toast.makeText(MainActivity.this, R.string.finished_verifying_custom_sudoku_toast, Toast.LENGTH_LONG).show();
|
||||||
|
final Intent intent = new Intent(this, GameActivity.class);
|
||||||
|
intent.setData(Uri.parse(prefix + inputSudoku));
|
||||||
|
startActivity(intent);
|
||||||
|
finish();
|
||||||
|
} else {
|
||||||
|
Toast.makeText(MainActivity.this, R.string.failed_to_verify_custom_sudoku_toast, Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onDialogNegativeClick() {
|
||||||
|
mNavigationView.setCheckedItem(R.id.nav_newgame_main);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ImportBoardDialog extends DialogFragment {
|
||||||
|
private LinkedList<IImportDialogFragmentListener> listeners = new LinkedList<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAttach(Activity activity) {
|
||||||
|
super.onAttach(activity);
|
||||||
|
// Verify that the host activity implements the callback interface
|
||||||
|
if(activity instanceof IImportDialogFragmentListener) {
|
||||||
|
listeners.add((IImportDialogFragmentListener) activity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||||
|
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity(), R.style.AppTheme_Dialog);
|
||||||
|
LayoutInflater inflater = getActivity().getLayoutInflater();
|
||||||
|
DialogFragmentImportBoardBinding binding = DialogFragmentImportBoardBinding.inflate(inflater);
|
||||||
|
builder.setView(binding.getRoot());
|
||||||
|
builder.setMessage(R.string.dialog_import_custom_sudoku);
|
||||||
|
builder.setPositiveButton(R.string.dialog_import_custom_sudoku_positive_button, new DialogInterface.OnClickListener() {
|
||||||
|
public void onClick(DialogInterface dialog, int id) {
|
||||||
|
for(IImportDialogFragmentListener l : listeners) {
|
||||||
|
l.onImportDialogPositiveClick(binding.ver3ImportSudokuEditText.getText().toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
|
||||||
|
public void onClick(DialogInterface dialog, int id) {
|
||||||
|
for(IImportDialogFragmentListener l : listeners) {
|
||||||
|
l.onDialogNegativeClick();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return builder.create();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link FragmentPagerAdapter} that returns a fragment corresponding to
|
* A {@link FragmentPagerAdapter} that returns a fragment corresponding to
|
||||||
|
|
|
@ -1,3 +1,19 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package org.secuso.privacyfriendlysudoku.ui;
|
package org.secuso.privacyfriendlysudoku.ui;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
|
@ -1,192 +1,120 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package org.secuso.privacyfriendlysudoku.ui;
|
package org.secuso.privacyfriendlysudoku.ui;
|
||||||
|
|
||||||
|
import android.content.SharedPreferences;
|
||||||
import android.annotation.TargetApi;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.res.Configuration;
|
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.preference.ListPreference;
|
|
||||||
import android.preference.Preference;
|
|
||||||
import android.preference.PreferenceActivity;
|
|
||||||
import androidx.appcompat.app.ActionBar;
|
|
||||||
import android.preference.PreferenceFragment;
|
import android.preference.PreferenceFragment;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
|
||||||
|
|
||||||
|
import androidx.appcompat.app.ActionBar;
|
||||||
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
import androidx.appcompat.app.AppCompatDelegate;
|
||||||
|
import androidx.preference.Preference;
|
||||||
|
import androidx.preference.PreferenceFragmentCompat;
|
||||||
|
import androidx.preference.PreferenceGroup;
|
||||||
|
import androidx.preference.PreferenceScreen;
|
||||||
|
|
||||||
|
import org.secuso.privacyfriendlysudoku.ui.SettingsActivity;
|
||||||
import org.secuso.privacyfriendlysudoku.ui.view.R;
|
import org.secuso.privacyfriendlysudoku.ui.view.R;
|
||||||
|
|
||||||
import java.util.List;
|
public class SettingsActivity extends AppCompatActivity {
|
||||||
|
|
||||||
/**
|
|
||||||
* A {@link PreferenceActivity} that presents a set of application settings. On
|
|
||||||
* handset devices, settings are presented as a single list. On tablets,
|
|
||||||
* settings are split by category, with category headers shown to the left of
|
|
||||||
* the list of settings.
|
|
||||||
* <p>
|
|
||||||
* See <a href="http://developer.android.com/design/patterns/settings.html">
|
|
||||||
* Android Design: Settings</a> for design guidelines and the <a
|
|
||||||
* href="http://developer.android.com/guide/topics/ui/settings.html">Settings
|
|
||||||
* API Guide</a> for more information on developing a Settings UI.
|
|
||||||
*/
|
|
||||||
public class SettingsActivity extends AppCompatPreferenceActivity {
|
|
||||||
@Override
|
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
setupActionBar();
|
|
||||||
|
|
||||||
overridePendingTransition(0, 0);
|
|
||||||
|
|
||||||
View mainContent = findViewById(R.id.main_content);
|
|
||||||
if (mainContent != null) {
|
|
||||||
mainContent.setAlpha(0);
|
|
||||||
mainContent.animate().alpha(1).setDuration(BaseActivity.MAIN_CONTENT_FADEIN_DURATION);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set up the {@link android.app.ActionBar}, if the API is available.
|
|
||||||
*/
|
|
||||||
private void setupActionBar() {
|
|
||||||
ActionBar actionBar = getSupportActionBar();
|
|
||||||
if (actionBar != null) {
|
|
||||||
// Show the Up button in the action bar.
|
|
||||||
actionBar.setDisplayHomeAsUpEnabled(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onMenuItemSelected(int featureId, MenuItem item) {
|
|
||||||
int id = item.getItemId();
|
|
||||||
if (id == android.R.id.home) {
|
|
||||||
if (!super.onMenuItemSelected(featureId, item)) {
|
|
||||||
finish();
|
|
||||||
//NavUtils.navigateUpFromSameTask(this);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return super.onMenuItemSelected(featureId, item);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
private static SettingsFragment settingsFragment;
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean onIsMultiPane() {
|
|
||||||
return isXLargeTablet(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
private static void recheckNightModeProperties(SharedPreferences sharedPreferences) {
|
||||||
* Helper method to determine if the device has an extra-large screen. For
|
|
||||||
* example, 10" tablets are extra-large.
|
|
||||||
*/
|
|
||||||
private static boolean isXLargeTablet(Context context) {
|
|
||||||
return (context.getResources().getConfiguration().screenLayout
|
|
||||||
& Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_XLARGE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
|
|
||||||
public void onBuildHeaders(List<Header> target) {
|
|
||||||
loadHeadersFromResource(R.xml.pref_settings_headers, target);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
if (sharedPreferences.getBoolean("pref_dark_mode_setting", false)) {
|
||||||
* A preference value change listener that updates the preference's summary
|
|
||||||
* to reflect its new value.
|
|
||||||
*/
|
|
||||||
private static Preference.OnPreferenceChangeListener sBindPreferenceSummaryToValueListener = new Preference.OnPreferenceChangeListener() {
|
|
||||||
@Override
|
|
||||||
public boolean onPreferenceChange(Preference preference, Object value) {
|
|
||||||
String stringValue = value.toString();
|
|
||||||
|
|
||||||
if (preference instanceof ListPreference) {
|
|
||||||
// For list preferences, look up the correct display value in
|
|
||||||
// the preference's 'entries' list.
|
|
||||||
ListPreference listPreference = (ListPreference) preference;
|
|
||||||
int index = listPreference.findIndexOfValue(stringValue);
|
|
||||||
|
|
||||||
// Set the summary to reflect the new value.
|
|
||||||
preference.setSummary(
|
|
||||||
index >= 0
|
|
||||||
? listPreference.getEntries()[index]
|
|
||||||
: null);
|
|
||||||
|
|
||||||
|
settingsFragment.findPreference("pref_dark_mode_automatically_by_system").setEnabled(false);
|
||||||
|
settingsFragment.findPreference("pref_dark_mode_automatically_by_battery").setEnabled(false);
|
||||||
} else {
|
} else {
|
||||||
// For all other preferences, set the summary to the value's
|
if (sharedPreferences.getBoolean("pref_dark_mode_automatically_by_battery", false) && sharedPreferences.getBoolean("pref_dark_mode_automatically_by_system", false) ) {
|
||||||
// simple string representation.
|
sharedPreferences.edit().putBoolean("pref_dark_mode_automatically_by_battery", false).commit();
|
||||||
preference.setSummary(stringValue);
|
}
|
||||||
|
|
||||||
|
settingsFragment.findPreference("pref_dark_mode_automatically_by_system").setEnabled(!sharedPreferences.getBoolean("pref_dark_mode_automatically_by_battery", false));
|
||||||
|
settingsFragment.findPreference("pref_dark_mode_automatically_by_battery").setEnabled(!sharedPreferences.getBoolean("pref_dark_mode_automatically_by_system", false));
|
||||||
|
}}
|
||||||
|
|
||||||
|
if (sharedPreferences.getBoolean("pref_dark_mode_setting", false )) {
|
||||||
|
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
|
||||||
|
|
||||||
|
} else if (sharedPreferences.getBoolean("pref_dark_mode_automatically_by_system", false)) {
|
||||||
|
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);
|
||||||
|
} else if(sharedPreferences.getBoolean("pref_dark_mode_automatically_by_battery", false)){
|
||||||
|
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY);
|
||||||
|
} else {
|
||||||
|
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static SharedPreferences.OnSharedPreferenceChangeListener sharedPreferenceChangeListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||||
|
if (key.equals("pref_dark_mode_setting")|| key.equals("pref_dark_mode_automatically_by_system")||key.equals("pref_dark_mode_automatically_by_battery")) {
|
||||||
|
recheckNightModeProperties(sharedPreferences);
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Binds a preference's summary to its value. More specifically, when the
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
* preference's value is changed, its summary (line of text below the
|
super.onCreate(savedInstanceState);
|
||||||
* preference title) is updated to reflect the value. The summary is also
|
setContentView(R.layout.settings_activity);
|
||||||
* immediately updated upon calling this method. The exact display format is
|
settingsFragment = new SettingsFragment();
|
||||||
* dependent on the type of preference.
|
getSupportFragmentManager()
|
||||||
*
|
.beginTransaction()
|
||||||
* @see #sBindPreferenceSummaryToValueListener
|
.replace(R.id.settings, settingsFragment)
|
||||||
*/
|
.commit();
|
||||||
private static void bindPreferenceSummaryToValue(Preference preference) {
|
ActionBar actionBar = getSupportActionBar();
|
||||||
// Set the listener to watch for value changes.
|
if (actionBar != null) {
|
||||||
preference.setOnPreferenceChangeListener(sBindPreferenceSummaryToValueListener);
|
actionBar.setDisplayHomeAsUpEnabled(true);
|
||||||
|
|
||||||
// Trigger the listener immediately with the preference's
|
|
||||||
// current value.
|
|
||||||
sBindPreferenceSummaryToValueListener.onPreferenceChange(preference,
|
|
||||||
PreferenceManager
|
|
||||||
.getDefaultSharedPreferences(preference.getContext())
|
|
||||||
.getString(preference.getKey(), ""));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method stops fragment injection in malicious applications.
|
|
||||||
* Make sure to deny any unknown fragments here.
|
|
||||||
*/
|
|
||||||
protected boolean isValidFragment(String fragmentName) {
|
|
||||||
return PreferenceFragment.class.getName().equals(fragmentName)
|
|
||||||
|| GamePreferenceFragment.class.getName().equals(fragmentName);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This fragment shows general preferences only. It is used when the
|
|
||||||
* activity is showing a two-pane settings UI.
|
|
||||||
*/
|
|
||||||
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
|
|
||||||
public static class GamePreferenceFragment extends PreferenceFragment {
|
|
||||||
@Override
|
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
addPreferencesFromResource(R.xml.pref_settings_general);
|
|
||||||
setHasOptionsMenu(true);
|
|
||||||
|
|
||||||
// Bind the summaries of EditText/List/Dialog/Ringtone preferences
|
|
||||||
// to their values. When their values change, their summaries are
|
|
||||||
// updated to reflect the new value, per the Android Design
|
|
||||||
// guidelines.
|
|
||||||
|
|
||||||
//bindPreferenceSummaryToValue(findPreference("example_text"));
|
|
||||||
//bindPreferenceSummaryToValue(findPreference("example_list"));
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
|
int id = item.getItemId();
|
||||||
|
if (id == android.R.id.home) {
|
||||||
|
finish();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return super.onOptionsItemSelected(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static class SettingsFragment extends PreferenceFragmentCompat {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
||||||
int id = item.getItemId();
|
setPreferencesFromResource(R.xml.pref_settings_general, rootKey);
|
||||||
if (id == android.R.id.home) {
|
SharedPreferences preferenceManager = PreferenceManager
|
||||||
getActivity().finish();
|
.getDefaultSharedPreferences(getActivity());
|
||||||
//startActivity(new Intent(getActivity(), SettingsActivity.class));
|
preferenceManager.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
|
||||||
return true;
|
recheckNightModeProperties(preferenceManager);
|
||||||
}
|
|
||||||
return super.onOptionsItemSelected(item);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,3 +1,19 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package org.secuso.privacyfriendlysudoku.ui;
|
package org.secuso.privacyfriendlysudoku.ui;
|
||||||
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
|
|
@ -1,3 +1,19 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package org.secuso.privacyfriendlysudoku.ui;
|
package org.secuso.privacyfriendlysudoku.ui;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
|
@ -1,3 +1,19 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package org.secuso.privacyfriendlysudoku.ui;
|
package org.secuso.privacyfriendlysudoku.ui;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
@ -20,7 +36,6 @@ import android.widget.TextView;
|
||||||
|
|
||||||
import org.secuso.privacyfriendlysudoku.ui.view.R;
|
import org.secuso.privacyfriendlysudoku.ui.view.R;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class structure taken from tutorial at http://www.androidhive.info/2016/05/android-build-intro-slider-app/
|
* Class structure taken from tutorial at http://www.androidhive.info/2016/05/android-build-intro-slider-app/
|
||||||
* @author Karola Marky
|
* @author Karola Marky
|
||||||
|
|
|
@ -1,3 +1,19 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package org.secuso.privacyfriendlysudoku.ui.listener;
|
package org.secuso.privacyfriendlysudoku.ui.listener;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package org.secuso.privacyfriendlysudoku.ui.listener;
|
||||||
|
|
||||||
|
public interface IFinalizeDialogFragmentListener {
|
||||||
|
public void onFinalizeDialogPositiveClick();
|
||||||
|
public void onDialogNegativeClick();
|
||||||
|
}
|
|
@ -1,3 +1,19 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package org.secuso.privacyfriendlysudoku.ui.listener;
|
package org.secuso.privacyfriendlysudoku.ui.listener;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package org.secuso.privacyfriendlysudoku.ui.listener;
|
||||||
|
|
||||||
|
public interface IImportDialogFragmentListener {
|
||||||
|
public void onImportDialogPositiveClick(String input);
|
||||||
|
public void onDialogNegativeClick();
|
||||||
|
}
|
|
@ -1,3 +1,19 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package org.secuso.privacyfriendlysudoku.ui.listener;
|
package org.secuso.privacyfriendlysudoku.ui.listener;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package org.secuso.privacyfriendlysudoku.ui.listener;
|
||||||
|
|
||||||
|
public interface IShareDialogFragmentListener {
|
||||||
|
public void onShareDialogPositiveClick(String input);
|
||||||
|
public void onDialogNegativeClick();
|
||||||
|
}
|
|
@ -1,3 +1,19 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package org.secuso.privacyfriendlysudoku.ui.view;
|
package org.secuso.privacyfriendlysudoku.ui.view;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package org.secuso.privacyfriendlysudoku.ui.view;
|
||||||
|
|
||||||
|
import androidx.annotation.DrawableRes;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public enum CreateSudokuButtonType {
|
||||||
|
Unspecified(R.drawable.ic_accessibility_black_48dp),// placeholder
|
||||||
|
Value(R.drawable.ic_accessibility_black_48dp), // should be non picture
|
||||||
|
Do(R.drawable.ic_redo_black_48dp),
|
||||||
|
Undo(R.drawable.ic_undo_black_48dp),
|
||||||
|
Import(R.drawable.ic_import),
|
||||||
|
Spacer(R.drawable.ic_accessibility_black_48dp),//placeholder
|
||||||
|
Delete(R.drawable.ic_delete_black_48dp),
|
||||||
|
Finalize(R.drawable.ic_finalize),
|
||||||
|
Reset(R.drawable.ic_settings_backup_restore_black_48dp);
|
||||||
|
|
||||||
|
|
||||||
|
private int resID;
|
||||||
|
|
||||||
|
CreateSudokuButtonType(@DrawableRes int res){
|
||||||
|
this.resID = res;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getResID() {
|
||||||
|
return resID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<CreateSudokuButtonType> getSpecialButtons() {
|
||||||
|
ArrayList<CreateSudokuButtonType> result = new ArrayList<CreateSudokuButtonType>();
|
||||||
|
result.add(Undo);
|
||||||
|
result.add(Do);
|
||||||
|
result.add(Finalize);
|
||||||
|
//result.add(Spacer);
|
||||||
|
result.add(Delete);
|
||||||
|
result.add(Import);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
public static String getName(CreateSudokuButtonType type) {
|
||||||
|
switch (type) {
|
||||||
|
case Do: return "Do";
|
||||||
|
case Undo: return "Un";
|
||||||
|
case Finalize: return "Fi";
|
||||||
|
case Import: return "Im";
|
||||||
|
case Spacer: return "";
|
||||||
|
case Delete: return "Del";
|
||||||
|
default:return "NotSet";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package org.secuso.privacyfriendlysudoku.ui.view;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.widget.ImageButton;
|
||||||
|
|
||||||
|
public class CreateSudokuSpecialButton extends androidx.appcompat.widget.AppCompatImageButton {
|
||||||
|
private int value = -1;
|
||||||
|
private CreateSudokuButtonType type = CreateSudokuButtonType.Unspecified;
|
||||||
|
|
||||||
|
public CreateSudokuSpecialButton(Context context, AttributeSet attrs) {
|
||||||
|
super(context, attrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(int value) { this.value = value; }
|
||||||
|
public void setType(CreateSudokuButtonType type) { this.type = type; }
|
||||||
|
public int getValue () { return value; }
|
||||||
|
public CreateSudokuButtonType getType() { return type; }
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,233 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package org.secuso.privacyfriendlysudoku.ui.view;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.app.Dialog;
|
||||||
|
import android.app.DialogFragment;
|
||||||
|
import android.app.FragmentManager;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.BitmapFactory;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import androidx.core.content.ContextCompat;
|
||||||
|
|
||||||
|
import org.secuso.privacyfriendlysudoku.controller.GameController;
|
||||||
|
import org.secuso.privacyfriendlysudoku.game.listener.IHighlightChangedListener;
|
||||||
|
import org.secuso.privacyfriendlysudoku.ui.GameActivity;
|
||||||
|
import org.secuso.privacyfriendlysudoku.ui.MainActivity;
|
||||||
|
import org.secuso.privacyfriendlysudoku.ui.listener.IFinalizeDialogFragmentListener;
|
||||||
|
import org.secuso.privacyfriendlysudoku.ui.listener.IHintDialogFragmentListener;
|
||||||
|
import org.secuso.privacyfriendlysudoku.ui.listener.IImportDialogFragmentListener;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
|
|
||||||
|
import static org.secuso.privacyfriendlysudoku.ui.view.CreateSudokuButtonType.Spacer;
|
||||||
|
import static org.secuso.privacyfriendlysudoku.ui.view.CreateSudokuButtonType.getSpecialButtons;
|
||||||
|
|
||||||
|
public class CreateSudokuSpecialButtonLayout extends LinearLayout implements IHighlightChangedListener {
|
||||||
|
|
||||||
|
IFinalizeDialogFragmentListener finalizeDialogFragmentListener;
|
||||||
|
IImportDialogFragmentListener importDialogFragmentListener;
|
||||||
|
CreateSudokuSpecialButton[] fixedButtons;
|
||||||
|
public int fixedButtonsCount = getSpecialButtons().size();
|
||||||
|
GameController gameController;
|
||||||
|
SudokuKeyboardLayout keyboard;
|
||||||
|
Bitmap bitMap,bitResult;
|
||||||
|
Canvas canvas;
|
||||||
|
FragmentManager fragmentManager;
|
||||||
|
Context context;
|
||||||
|
|
||||||
|
OnClickListener listener = new OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
if(v instanceof CreateSudokuSpecialButton) {
|
||||||
|
CreateSudokuSpecialButton btn = (CreateSudokuSpecialButton)v;
|
||||||
|
|
||||||
|
//int row = gameController.getSelectedRow();
|
||||||
|
//int col = gameController.getSelectedCol();
|
||||||
|
|
||||||
|
switch(btn.getType()) {
|
||||||
|
case Delete:
|
||||||
|
gameController.deleteSelectedCellsValue();
|
||||||
|
break;
|
||||||
|
case Import:
|
||||||
|
MainActivity.ImportBoardDialog impDialog = new MainActivity.ImportBoardDialog();
|
||||||
|
impDialog.show(fragmentManager, "ImportDialogFragment");
|
||||||
|
break;
|
||||||
|
case Do:
|
||||||
|
gameController.ReDo();
|
||||||
|
break;
|
||||||
|
case Undo:
|
||||||
|
gameController.UnDo();
|
||||||
|
break;
|
||||||
|
case Finalize:
|
||||||
|
FinalizeConfirmationDialog dialog = new FinalizeConfirmationDialog();
|
||||||
|
dialog.show(fragmentManager, "FinalizeDialogFragment");
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
public CreateSudokuSpecialButtonLayout(Context context, AttributeSet attrs) {
|
||||||
|
super(context, attrs);
|
||||||
|
setWeightSum(fixedButtonsCount);
|
||||||
|
this.context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setButtonsEnabled(boolean enabled) {
|
||||||
|
for(CreateSudokuSpecialButton b : fixedButtons) {
|
||||||
|
b.setEnabled(enabled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setButtons(int width, GameController gc, SudokuKeyboardLayout key, FragmentManager fm,
|
||||||
|
int orientation, Context cxt, IFinalizeDialogFragmentListener finalizeListener,
|
||||||
|
IImportDialogFragmentListener importListener) {
|
||||||
|
fragmentManager = fm;
|
||||||
|
keyboard=key;
|
||||||
|
gameController = gc;
|
||||||
|
context = cxt;
|
||||||
|
finalizeDialogFragmentListener = finalizeListener;
|
||||||
|
importDialogFragmentListener = importListener;
|
||||||
|
if(gameController != null) {
|
||||||
|
gameController.registerHighlightChangedListener(this);
|
||||||
|
}
|
||||||
|
fixedButtons = new CreateSudokuSpecialButton[fixedButtonsCount];
|
||||||
|
LayoutParams p;
|
||||||
|
int i = 0;
|
||||||
|
//ArrayList<SudokuButtonType> type = (ArrayList<SudokuButtonType>) SudokuButtonType.getSpecialButtons();
|
||||||
|
for (CreateSudokuButtonType t : getSpecialButtons()){
|
||||||
|
fixedButtons[i] = new CreateSudokuSpecialButton(getContext(),null);
|
||||||
|
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);
|
||||||
|
//p.width= width2-15;
|
||||||
|
if(t == Spacer) {
|
||||||
|
fixedButtons[i].setVisibility(View.INVISIBLE);
|
||||||
|
}
|
||||||
|
/*if(t == SudokuButtonType.Do && !gameController.isRedoAvailable()) {
|
||||||
|
fixedButtons[i].setEnabled(false);
|
||||||
|
}
|
||||||
|
if(t == SudokuButtonType.Undo && !gameController.isUndoAvailable()) {
|
||||||
|
fixedButtons[i].setEnabled(false);
|
||||||
|
}*/
|
||||||
|
fixedButtons[i].setLayoutParams(p);
|
||||||
|
fixedButtons[i].setType(t);
|
||||||
|
fixedButtons[i].setImageDrawable(getResources().getDrawable(t.getResID()));
|
||||||
|
// fixedButtons[i].setText(SudokuButtonType.getName(t));
|
||||||
|
fixedButtons[i].setScaleType(ImageView.ScaleType.CENTER);
|
||||||
|
fixedButtons[i].setAdjustViewBounds(true);
|
||||||
|
fixedButtons[i].setOnClickListener(listener);
|
||||||
|
fixedButtons[i].setBackgroundResource(R.drawable.numpad_highlighted_four);
|
||||||
|
addView(fixedButtons[i]);
|
||||||
|
|
||||||
|
if(fixedButtons[i].getVisibility() == View.VISIBLE) {
|
||||||
|
Drawable drawable = ContextCompat.getDrawable(context, fixedButtons[i].getType().getResID());
|
||||||
|
setUpVectorDrawable(drawable);
|
||||||
|
drawable.draw(canvas);
|
||||||
|
fixedButtons[i].setImageBitmap(bitResult);
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onHighlightChanged() {
|
||||||
|
for(int i = 0; i < fixedButtons.length; i++) {
|
||||||
|
switch(fixedButtons[i].getType()) {
|
||||||
|
case Undo:
|
||||||
|
fixedButtons[i].setBackgroundResource(gameController.isUndoAvailable() ?
|
||||||
|
R.drawable.numpad_highlighted_four : R.drawable.inactive_button);
|
||||||
|
break;
|
||||||
|
case Do:
|
||||||
|
fixedButtons[i].setBackgroundResource(gameController.isRedoAvailable() ?
|
||||||
|
R.drawable.numpad_highlighted_four : R.drawable.inactive_button);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Set up the vector drawables so that they can be properly displayed despite using theme attributes for their fill color
|
||||||
|
*/
|
||||||
|
private void setUpVectorDrawable(Drawable drawable) {
|
||||||
|
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
|
||||||
|
bitMap = Bitmap.createBitmap(drawable.getIntrinsicWidth(),
|
||||||
|
drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
|
||||||
|
bitResult = Bitmap.createBitmap(bitMap.getWidth(), bitMap.getHeight(), Bitmap.Config.ARGB_8888);
|
||||||
|
|
||||||
|
canvas = new Canvas(bitResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class FinalizeConfirmationDialog extends DialogFragment {
|
||||||
|
|
||||||
|
LinkedList<IFinalizeDialogFragmentListener> listeners = new LinkedList<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAttach(Activity activity) {
|
||||||
|
super.onAttach(activity);
|
||||||
|
// Verify that the host activity implements the callback interface
|
||||||
|
if(activity instanceof IFinalizeDialogFragmentListener) {
|
||||||
|
listeners.add((IFinalizeDialogFragmentListener) activity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||||
|
// Use the Builder class for convenient dialog construction
|
||||||
|
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity(), R.style.AppTheme_Dialog);
|
||||||
|
builder.setMessage(R.string.finalize_custom_sudoku_dialog)
|
||||||
|
.setPositiveButton(R.string.okay, new DialogInterface.OnClickListener() {
|
||||||
|
public void onClick(DialogInterface dialog, int id) {
|
||||||
|
for(IFinalizeDialogFragmentListener l : listeners) {
|
||||||
|
l.onFinalizeDialogPositiveClick();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
|
||||||
|
public void onClick(DialogInterface dialog, int id) {
|
||||||
|
// User cancelled the dialog
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return builder.create();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,19 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package org.secuso.privacyfriendlysudoku.ui.view;
|
package org.secuso.privacyfriendlysudoku.ui.view;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
@ -12,7 +28,7 @@ import android.widget.Button;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public class SudokuButton extends Button {
|
public class SudokuButton extends androidx.appcompat.widget.AppCompatButton {
|
||||||
|
|
||||||
private int value = -1;
|
private int value = -1;
|
||||||
private SudokuButtonType type = SudokuButtonType.Unspecified;
|
private SudokuButtonType type = SudokuButtonType.Unspecified;
|
||||||
|
|
|
@ -1,3 +1,19 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package org.secuso.privacyfriendlysudoku.ui.view;
|
package org.secuso.privacyfriendlysudoku.ui.view;
|
||||||
|
|
||||||
import androidx.annotation.DrawableRes;
|
import androidx.annotation.DrawableRes;
|
||||||
|
|
|
@ -1,6 +1,24 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package org.secuso.privacyfriendlysudoku.ui.view;
|
package org.secuso.privacyfriendlysudoku.ui.view;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.res.Configuration;
|
||||||
|
import android.content.res.TypedArray;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
|
@ -31,15 +49,32 @@ public class SudokuCellView extends View {
|
||||||
Symbol symbolsToUse = Symbol.Default;
|
Symbol symbolsToUse = Symbol.Default;
|
||||||
RelativeLayout.LayoutParams params;
|
RelativeLayout.LayoutParams params;
|
||||||
|
|
||||||
|
int backgroundColor;
|
||||||
public SudokuCellView(Context context) {
|
int backgroundErrorColor;
|
||||||
super(context);
|
int backgroundSelectedColor;
|
||||||
}
|
int backgroundConnectedOuterColor;
|
||||||
|
int backgroundConnectedInnerColor;
|
||||||
|
int backgroundValueHighlightedColor;
|
||||||
|
int backgroundValueHighlightedSelectedColor;
|
||||||
|
int textColor;
|
||||||
|
|
||||||
public SudokuCellView(Context context, AttributeSet attrs){
|
public SudokuCellView(Context context, AttributeSet attrs){
|
||||||
super(context, attrs);
|
super(context, attrs);
|
||||||
|
|
||||||
|
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SudokuCellView);
|
||||||
|
backgroundColor = a.getColor(R.styleable.SudokuCellView_sudokuCellBackgroundColor, Color.argb(255, 200, 200, 200));
|
||||||
|
backgroundErrorColor = a.getColor(R.styleable.SudokuCellView_sudokuCellBackgroundErrorColor, Color.argb(255, 200, 200, 200));
|
||||||
|
backgroundSelectedColor = a.getColor(R.styleable.SudokuCellView_sudokuCellBackgroundSelectedColor, Color.argb(255, 200, 200, 200));
|
||||||
|
backgroundConnectedOuterColor = a.getColor(R.styleable.SudokuCellView_sudokuCellBackgroundConnectedOuterColor, Color.argb(255, 200, 200, 200));
|
||||||
|
backgroundConnectedInnerColor = a.getColor(R.styleable.SudokuCellView_sudokuCellBackgroundConnectedInnerColor, Color.argb(255, 200, 200, 200));
|
||||||
|
backgroundValueHighlightedColor = a.getColor(R.styleable.SudokuCellView_sudokuCellBackgroundValueHighlightedColor, Color.argb(255, 200, 200, 200));
|
||||||
|
backgroundValueHighlightedSelectedColor = a.getColor(R.styleable.SudokuCellView_sudokuCellBackgroundValueHighlightedSelectedColor, Color.argb(255, 200, 200, 200));
|
||||||
|
textColor = a.getColor(R.styleable.SudokuCellView_sudokuCellTextColor, Color.argb(255, 200, 200, 200));
|
||||||
|
a.recycle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public void setSelected(boolean b) {
|
public void setSelected(boolean b) {
|
||||||
this.selected = b;
|
this.selected = b;
|
||||||
}
|
}
|
||||||
|
@ -89,13 +124,6 @@ public class SudokuCellView extends View {
|
||||||
return true;
|
return true;
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
|
||||||
super.onLayout(changed, left, top, right, bottom);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDraw(Canvas canvas) {
|
public void onDraw(Canvas canvas) {
|
||||||
super.onDraw(canvas);
|
super.onDraw(canvas);
|
||||||
|
@ -108,27 +136,28 @@ public class SudokuCellView extends View {
|
||||||
Paint p = new Paint();
|
Paint p = new Paint();
|
||||||
switch(highlightType) {
|
switch(highlightType) {
|
||||||
case Default:
|
case Default:
|
||||||
p.setColor(Color.WHITE);
|
p.setColor(backgroundColor);
|
||||||
break;
|
break;
|
||||||
case Error:
|
case Error:
|
||||||
p.setColor(Color.LTGRAY);
|
p.setColor(backgroundErrorColor);
|
||||||
break;
|
break;
|
||||||
case Selected:
|
case Selected:
|
||||||
p.setColor(Color.GREEN);
|
p.setColor(backgroundSelectedColor);
|
||||||
break;
|
break;
|
||||||
case Connected:
|
case Connected:
|
||||||
p.setColor(Color.WHITE);
|
p.setColor(backgroundConnectedOuterColor);
|
||||||
drawBackground(canvas, 3, 3, mWidth - 3, mHeight - 3, p);
|
drawBackground(canvas, 3, 3, mWidth - 3, mHeight - 3, p);
|
||||||
p.setColor(Color.YELLOW);
|
p.setColor(backgroundConnectedInnerColor);
|
||||||
p.setAlpha(100);
|
p.setAlpha(100);
|
||||||
break;
|
break;
|
||||||
case Value_Highlighted:
|
case Value_Highlighted:
|
||||||
p.setColor(Color.YELLOW);
|
p.setColor(backgroundValueHighlightedColor);
|
||||||
break;
|
break;
|
||||||
case Value_Highlighted_Selected:
|
case Value_Highlighted_Selected:
|
||||||
p.setColor(Color.CYAN);
|
p.setColor(backgroundValueHighlightedSelectedColor);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
p.setColor(Color.WHITE);
|
p.setColor(backgroundColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -147,6 +176,7 @@ public class SudokuCellView extends View {
|
||||||
|
|
||||||
public void drawValue(Canvas canvas) {
|
public void drawValue(Canvas canvas) {
|
||||||
Paint p = new Paint();
|
Paint p = new Paint();
|
||||||
|
p.setColor(textColor);
|
||||||
int root = (int) Math.sqrt(size);
|
int root = (int) Math.sqrt(size);
|
||||||
int j= root+1;
|
int j= root+1;
|
||||||
int k = root;
|
int k = root;
|
||||||
|
|
|
@ -1,7 +1,25 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package org.secuso.privacyfriendlysudoku.ui.view;
|
package org.secuso.privacyfriendlysudoku.ui.view;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
|
import android.content.res.Configuration;
|
||||||
|
import android.content.res.TypedArray;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
|
@ -31,6 +49,9 @@ public class SudokuFieldLayout extends RelativeLayout implements IHighlightChang
|
||||||
private int gameCellHeight;
|
private int gameCellHeight;
|
||||||
private SharedPreferences settings;
|
private SharedPreferences settings;
|
||||||
private Paint p = new Paint();
|
private Paint p = new Paint();
|
||||||
|
int backgroundColor;
|
||||||
|
int errorColor;
|
||||||
|
int sectionLineColor;
|
||||||
|
|
||||||
private OnTouchListener listener = new OnTouchListener() {
|
private OnTouchListener listener = new OnTouchListener() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -55,8 +76,15 @@ public class SudokuFieldLayout extends RelativeLayout implements IHighlightChang
|
||||||
public SudokuFieldLayout(Context context, AttributeSet attrs) {
|
public SudokuFieldLayout(Context context, AttributeSet attrs) {
|
||||||
super(context, attrs);
|
super(context, attrs);
|
||||||
this.attrs=attrs;
|
this.attrs=attrs;
|
||||||
|
|
||||||
|
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SudokuFieldLayout);
|
||||||
|
backgroundColor = a.getColor(R.styleable.SudokuFieldLayout_sudokuFieldGridColor, Color.argb(255, 200, 200, 200));
|
||||||
|
errorColor = a.getColor(R.styleable.SudokuFieldLayout_sudokuFieldErrorColor, Color.RED);
|
||||||
|
sectionLineColor = a.getColor(R.styleable.SudokuFieldLayout_sudokuFieldSectionLineColor, Color.BLACK);
|
||||||
|
a.recycle();
|
||||||
|
|
||||||
setWillNotDraw(false);
|
setWillNotDraw(false);
|
||||||
setBackgroundColor(Color.argb(255, 200, 200, 200));
|
setBackgroundColor(backgroundColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSettingsAndGame(SharedPreferences sharedPref, GameController gc) {
|
public void setSettingsAndGame(SharedPreferences sharedPref, GameController gc) {
|
||||||
|
@ -98,7 +126,7 @@ public class SudokuFieldLayout extends RelativeLayout implements IHighlightChang
|
||||||
|
|
||||||
if(gameController == null) return;
|
if(gameController == null) return;
|
||||||
|
|
||||||
p.setColor(Color.BLACK);
|
p.setColor(sectionLineColor);
|
||||||
p.setStrokeWidth(5);
|
p.setStrokeWidth(5);
|
||||||
|
|
||||||
int horizontalSections = gameController.getSize() / sectionWidth;
|
int horizontalSections = gameController.getSize() / sectionWidth;
|
||||||
|
@ -222,7 +250,7 @@ public class SudokuFieldLayout extends RelativeLayout implements IHighlightChang
|
||||||
p = new Paint(Paint.ANTI_ALIAS_FLAG);
|
p = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||||
p.setStyle(Paint.Style.STROKE);
|
p.setStyle(Paint.Style.STROKE);
|
||||||
p.setStrokeWidth(4);
|
p.setStrokeWidth(4);
|
||||||
p.setColor(Color.RED);
|
p.setColor(errorColor);
|
||||||
|
|
||||||
float offsetX = 0;
|
float offsetX = 0;
|
||||||
float offsetY = 0;
|
float offsetY = 0;
|
||||||
|
|
|
@ -1,3 +1,19 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package org.secuso.privacyfriendlysudoku.ui.view;
|
package org.secuso.privacyfriendlysudoku.ui.view;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
|
@ -1,3 +1,19 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package org.secuso.privacyfriendlysudoku.ui.view;
|
package org.secuso.privacyfriendlysudoku.ui.view;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
@ -7,7 +23,7 @@ import android.widget.ImageButton;
|
||||||
/**
|
/**
|
||||||
* Created by TMZ_LToP on 07.12.2015.
|
* Created by TMZ_LToP on 07.12.2015.
|
||||||
*/
|
*/
|
||||||
public class SudokuSpecialButton extends ImageButton {
|
public class SudokuSpecialButton extends androidx.appcompat.widget.AppCompatImageButton {
|
||||||
private int value = -1;
|
private int value = -1;
|
||||||
private SudokuButtonType type = SudokuButtonType.Unspecified;
|
private SudokuButtonType type = SudokuButtonType.Unspecified;
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,19 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package org.secuso.privacyfriendlysudoku.ui.view;
|
package org.secuso.privacyfriendlysudoku.ui.view;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
@ -10,6 +26,7 @@ import android.content.DialogInterface;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.BitmapFactory;
|
import android.graphics.BitmapFactory;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
@ -18,8 +35,11 @@ import android.widget.ImageView;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import androidx.core.content.ContextCompat;
|
||||||
|
|
||||||
import org.secuso.privacyfriendlysudoku.controller.GameController;
|
import org.secuso.privacyfriendlysudoku.controller.GameController;
|
||||||
import org.secuso.privacyfriendlysudoku.game.listener.IHighlightChangedListener;
|
import org.secuso.privacyfriendlysudoku.game.listener.IHighlightChangedListener;
|
||||||
|
import org.secuso.privacyfriendlysudoku.ui.GameActivity;
|
||||||
import org.secuso.privacyfriendlysudoku.ui.listener.IHintDialogFragmentListener;
|
import org.secuso.privacyfriendlysudoku.ui.listener.IHintDialogFragmentListener;
|
||||||
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
|
@ -40,6 +60,7 @@ public class SudokuSpecialButtonLayout extends LinearLayout implements IHighligh
|
||||||
Bitmap bitMap,bitResult;
|
Bitmap bitMap,bitResult;
|
||||||
Canvas canvas;
|
Canvas canvas;
|
||||||
FragmentManager fragmentManager;
|
FragmentManager fragmentManager;
|
||||||
|
Context context;
|
||||||
|
|
||||||
OnClickListener listener = new OnClickListener() {
|
OnClickListener listener = new OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -68,7 +89,7 @@ public class SudokuSpecialButtonLayout extends LinearLayout implements IHighligh
|
||||||
break;
|
break;
|
||||||
case Hint:
|
case Hint:
|
||||||
if(gameController.isValidCellSelected()) {
|
if(gameController.isValidCellSelected()) {
|
||||||
if(gameController.getUsedHints() == 0) {
|
if(gameController.getUsedHints() == 0 && !gameController.gameIsCustom()) {
|
||||||
// are you sure you want to use a hint?
|
// are you sure you want to use a hint?
|
||||||
HintConfirmationDialog hintDialog = new HintConfirmationDialog();
|
HintConfirmationDialog hintDialog = new HintConfirmationDialog();
|
||||||
hintDialog.show(fragmentManager, "HintDialogFragment");
|
hintDialog.show(fragmentManager, "HintDialogFragment");
|
||||||
|
@ -93,6 +114,7 @@ public class SudokuSpecialButtonLayout extends LinearLayout implements IHighligh
|
||||||
public SudokuSpecialButtonLayout(Context context, AttributeSet attrs) {
|
public SudokuSpecialButtonLayout(Context context, AttributeSet attrs) {
|
||||||
super(context, attrs);
|
super(context, attrs);
|
||||||
setWeightSum(fixedButtonsCount);
|
setWeightSum(fixedButtonsCount);
|
||||||
|
this.context = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setButtonsEnabled(boolean enabled) {
|
public void setButtonsEnabled(boolean enabled) {
|
||||||
|
@ -101,10 +123,11 @@ public class SudokuSpecialButtonLayout extends LinearLayout implements IHighligh
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setButtons(int width, GameController gc, SudokuKeyboardLayout key, FragmentManager fm, int orientation) {
|
public void setButtons(int width, GameController gc, SudokuKeyboardLayout key, FragmentManager fm, int orientation, Context cxt) {
|
||||||
fragmentManager = fm;
|
fragmentManager = fm;
|
||||||
keyboard=key;
|
keyboard=key;
|
||||||
gameController = gc;
|
gameController = gc;
|
||||||
|
context = cxt;
|
||||||
if(gameController != null) {
|
if(gameController != null) {
|
||||||
gameController.registerHighlightChangedListener(this);
|
gameController.registerHighlightChangedListener(this);
|
||||||
}
|
}
|
||||||
|
@ -142,6 +165,13 @@ public class SudokuSpecialButtonLayout extends LinearLayout implements IHighligh
|
||||||
fixedButtons[i].setOnClickListener(listener);
|
fixedButtons[i].setOnClickListener(listener);
|
||||||
fixedButtons[i].setBackgroundResource(R.drawable.numpad_highlighted_four);
|
fixedButtons[i].setBackgroundResource(R.drawable.numpad_highlighted_four);
|
||||||
addView(fixedButtons[i]);
|
addView(fixedButtons[i]);
|
||||||
|
|
||||||
|
if(fixedButtons[i].getVisibility() == View.VISIBLE) {
|
||||||
|
Drawable drawable = ContextCompat.getDrawable(context, fixedButtons[i].getType().getResID());
|
||||||
|
setUpVectorDrawable(drawable);
|
||||||
|
drawable.draw(canvas);
|
||||||
|
fixedButtons[i].setImageBitmap(bitResult);
|
||||||
|
}
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,12 +190,13 @@ public class SudokuSpecialButtonLayout extends LinearLayout implements IHighligh
|
||||||
R.drawable.numpad_highlighted_four : R.drawable.inactive_button);
|
R.drawable.numpad_highlighted_four : R.drawable.inactive_button);
|
||||||
break;
|
break;
|
||||||
case NoteToggle:
|
case NoteToggle:
|
||||||
bitMap = BitmapFactory.decodeResource(getResources(), fixedButtons[i].getType().getResID());
|
Drawable drawable = ContextCompat.getDrawable(context, fixedButtons[i].getType().getResID());
|
||||||
bitResult = Bitmap.createBitmap(bitMap.getWidth(), bitMap.getHeight(), Bitmap.Config.ARGB_8888);
|
// prepare canvas for the rotation of the note drawable
|
||||||
|
setUpVectorDrawable(drawable);
|
||||||
|
|
||||||
canvas = new Canvas(bitResult);
|
|
||||||
canvas.rotate(gameController.getNoteStatus() ? 45.0f : 0.0f, bitMap.getWidth()/2, bitMap.getHeight()/2);
|
canvas.rotate(gameController.getNoteStatus() ? 45.0f : 0.0f, bitMap.getWidth()/2, bitMap.getHeight()/2);
|
||||||
canvas.drawBitmap(bitMap, 0, 0, null);
|
canvas.drawBitmap(bitMap, 0, 0, null);
|
||||||
|
drawable.draw(canvas);
|
||||||
|
|
||||||
fixedButtons[i].setImageBitmap(bitResult);
|
fixedButtons[i].setImageBitmap(bitResult);
|
||||||
fixedButtons[i].setBackgroundResource(gameController.getNoteStatus() ? R.drawable.numpad_highlighted_three : R.drawable.numpad_highlighted_four);
|
fixedButtons[i].setBackgroundResource(gameController.getNoteStatus() ? R.drawable.numpad_highlighted_three : R.drawable.numpad_highlighted_four);
|
||||||
|
@ -179,6 +210,18 @@ public class SudokuSpecialButtonLayout extends LinearLayout implements IHighligh
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Set up the vector drawables so that they can be properly displayed despite using theme attributes for their fill color
|
||||||
|
*/
|
||||||
|
private void setUpVectorDrawable(Drawable drawable) {
|
||||||
|
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
|
||||||
|
bitMap = Bitmap.createBitmap(drawable.getIntrinsicWidth(),
|
||||||
|
drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
|
||||||
|
bitResult = Bitmap.createBitmap(bitMap.getWidth(), bitMap.getHeight(), Bitmap.Config.ARGB_8888);
|
||||||
|
|
||||||
|
canvas = new Canvas(bitResult);
|
||||||
|
}
|
||||||
|
|
||||||
public static class HintConfirmationDialog extends DialogFragment {
|
public static class HintConfirmationDialog extends DialogFragment {
|
||||||
|
|
||||||
LinkedList<IHintDialogFragmentListener> listeners = new LinkedList<>();
|
LinkedList<IHintDialogFragmentListener> listeners = new LinkedList<>();
|
||||||
|
@ -195,7 +238,7 @@ public class SudokuSpecialButtonLayout extends LinearLayout implements IHighligh
|
||||||
@Override
|
@Override
|
||||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||||
// Use the Builder class for convenient dialog construction
|
// Use the Builder class for convenient dialog construction
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity(), R.style.AppTheme_Dialog);
|
||||||
builder.setMessage(R.string.hint_confirmation)
|
builder.setMessage(R.string.hint_confirmation)
|
||||||
.setPositiveButton(R.string.hint_confirmation_confirm, new DialogInterface.OnClickListener() {
|
.setPositiveButton(R.string.hint_confirmation_confirm, new DialogInterface.OnClickListener() {
|
||||||
public void onClick(DialogInterface dialog, int id) {
|
public void onClick(DialogInterface dialog, int id) {
|
||||||
|
|
|
@ -1,3 +1,19 @@
|
||||||
|
/*
|
||||||
|
This file is part of Privacy Friendly Sudoku.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is free software:
|
||||||
|
you can redistribute it and/or modify it under the terms of the
|
||||||
|
GNU General Public License as published by the Free Software Foundation,
|
||||||
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
|
Privacy Friendly Sudoku is distributed in the hope
|
||||||
|
that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Privacy Friendly Sudoku. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package org.secuso.privacyfriendlysudoku.ui.view;
|
package org.secuso.privacyfriendlysudoku.ui.view;
|
||||||
|
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
|
|
|
@ -4,6 +4,6 @@
|
||||||
android:viewportWidth="24.0"
|
android:viewportWidth="24.0"
|
||||||
android:viewportHeight="24.0">
|
android:viewportHeight="24.0">
|
||||||
<path
|
<path
|
||||||
android:fillColor="#FF000000"
|
android:fillColor="?attr/standardVectorGraphic"
|
||||||
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zm1,15h-2v-6h2v6zm0,-8h-2V7h2v2z"/>
|
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zm1,15h-2v-6h2v6zm0,-8h-2V7h2v2z"/>
|
||||||
</vector>
|
</vector>
|
||||||
|
|
|
@ -18,17 +18,17 @@
|
||||||
<item android:id="@android:id/background">
|
<item android:id="@android:id/background">
|
||||||
<bitmap
|
<bitmap
|
||||||
android:src="@drawable/ic_star_black_48dp"
|
android:src="@drawable/ic_star_black_48dp"
|
||||||
android:tint="@color/middlegrey" />
|
android:tint="?attr/rankingStarNotSelected" />
|
||||||
</item>
|
</item>
|
||||||
<item android:id="@android:id/secondaryProgress">
|
<item android:id="@android:id/secondaryProgress">
|
||||||
<bitmap
|
<bitmap
|
||||||
android:src="@drawable/ic_star_half_black_48dp"
|
android:src="@drawable/ic_star_half_black_48dp"
|
||||||
android:tint="@color/middlegrey" />
|
android:tint="?attr/rankingStarNotSelected" />
|
||||||
</item>
|
</item>
|
||||||
<item android:id="@android:id/progress">
|
<item android:id="@android:id/progress">
|
||||||
<bitmap
|
<bitmap
|
||||||
android:src="@drawable/ic_star_black_48dp"
|
android:src="@drawable/ic_star_black_48dp"
|
||||||
android:tint="@color/colorAccent" />
|
android:tint="?attr/colorAccent" />
|
||||||
</item>
|
</item>
|
||||||
</layer-list>
|
</layer-list>
|
||||||
|
|
||||||
|
|
4
app/src/main/res/drawable/create_game_src.xml
Normal file
4
app/src/main/res/drawable/create_game_src.xml
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:state_checked="true" android:drawable="@drawable/ic_circle_blue_36dp"/>
|
||||||
|
<item android:state_checked="false" android:drawable="@drawable/ic_circle_grey_36dp"/>
|
||||||
|
</selector>
|
Binary file not shown.
Before Width: | Height: | Size: 572 B |
14
app/src/main/res/drawable/ic_accessibility_black_48dp.xml
Normal file
14
app/src/main/res/drawable/ic_accessibility_black_48dp.xml
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="192dp"
|
||||||
|
android:height="192dp"
|
||||||
|
android:viewportWidth="192"
|
||||||
|
android:viewportHeight="192">
|
||||||
|
<path
|
||||||
|
android:pathData="M89.5,17.4c-10.1,4.4 -12.5,17.8 -4.6,25.7 6.5,6.5 15.7,6.5 22.2,-0 12.4,-12.4 -1.5,-32.7 -17.6,-25.7z"
|
||||||
|
android:fillColor= "?attr/standardVectorGraphic"
|
||||||
|
android:strokeColor="?attr/standardVectorGraphic"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M24,64l0,8 24,-0 24,-0 0,52 0,52 8,-0 8,-0 0,-24 0,-24 8,-0 8,-0 0,24 0,24 8,-0 8,-0 0,-52 0,-52 24,-0 24,-0 0,-8 0,-8 -72,-0 -72,-0 0,8z"
|
||||||
|
android:fillColor="?attr/standardVectorGraphic"
|
||||||
|
android:strokeColor="?attr/standardVectorGraphic"/>
|
||||||
|
</vector>
|
9
app/src/main/res/drawable/ic_circle_blue_36dp.xml
Normal file
9
app/src/main/res/drawable/ic_circle_blue_36dp.xml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="37dp"
|
||||||
|
android:height="37dp"
|
||||||
|
android:viewportWidth="24.0"
|
||||||
|
android:viewportHeight="24.0">
|
||||||
|
<path
|
||||||
|
android:fillColor="?attr/rankingCircleSelected"
|
||||||
|
android:pathData="M12,12m-10,0a10,10 0,1 1,20 0a10,10 0,1 1,-20 0"/>
|
||||||
|
</vector>
|
9
app/src/main/res/drawable/ic_circle_grey_36dp.xml
Normal file
9
app/src/main/res/drawable/ic_circle_grey_36dp.xml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="37dp"
|
||||||
|
android:height="37dp"
|
||||||
|
android:viewportWidth="24.0"
|
||||||
|
android:viewportHeight="24.0">
|
||||||
|
<path
|
||||||
|
android:fillColor="?attr/rankingCircleNotSelected"
|
||||||
|
android:pathData="M12,12m-10,0a10,10 0,1 1,20 0a10,10 0,1 1,-20 0"/>
|
||||||
|
</vector>
|
Binary file not shown.
Before Width: | Height: | Size: 578 B |
14
app/src/main/res/drawable/ic_create_black_48dp.xml
Normal file
14
app/src/main/res/drawable/ic_create_black_48dp.xml
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="192dp"
|
||||||
|
android:height="192dp"
|
||||||
|
android:viewportWidth="192"
|
||||||
|
android:viewportHeight="192">
|
||||||
|
<path
|
||||||
|
android:pathData="M136.5,25.9c-1.6,1 -5.9,4.9 -9.5,8.5l-6.5,6.6 15,15 15,15 8.8,-8.8c6.8,-7 8.7,-9.5 8.7,-11.8 0,-2.3 -2.3,-5.1 -11.8,-14.6 -12.7,-12.7 -14.1,-13.4 -19.7,-9.9z"
|
||||||
|
android:fillColor="?attr/standardVectorGraphic"
|
||||||
|
android:strokeColor="?attr/standardVectorGraphic"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M67.7,93.8l-43.7,43.7 0,15.3 0,15.2 14.8,-0 14.7,-0 44.5,-44.5 44.5,-44.5 -14.5,-14.5c-8,-8 -14.9,-14.5 -15.5,-14.5 -0.6,-0 -20.7,19.7 -44.8,43.8z"
|
||||||
|
android:fillColor="?attr/standardVectorGraphic"
|
||||||
|
android:strokeColor="?attr/standardVectorGraphic"/>
|
||||||
|
</vector>
|
Binary file not shown.
Before Width: | Height: | Size: 498 B |
14
app/src/main/res/drawable/ic_delete_black_48dp.xml
Normal file
14
app/src/main/res/drawable/ic_delete_black_48dp.xml
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="192dp"
|
||||||
|
android:height="192dp"
|
||||||
|
android:viewportWidth="192"
|
||||||
|
android:viewportHeight="192">
|
||||||
|
<path
|
||||||
|
android:pathData="M71.5,28l-3.9,4 -13.8,-0 -13.8,-0 0,8 0,8 56,-0 56,-0 0,-8 0,-8 -13.8,-0 -13.8,-0 -3.9,-4 -3.9,-4 -20.6,-0 -20.6,-0 -3.9,4z"
|
||||||
|
android:fillColor="?attr/standardVectorGraphic"
|
||||||
|
android:strokeColor="?attr/standardVectorGraphic"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M48.2,106.9c0.3,49.7 0.4,51 2.4,53.7 1.1,1.5 3.3,3.7 4.8,4.8 2.7,2 3.9,2.1 40.6,2.1 36.7,-0 37.9,-0.1 40.6,-2.1 1.5,-1.1 3.7,-3.3 4.8,-4.8 2,-2.7 2.1,-4 2.4,-53.7l0.3,-50.9 -48.1,-0 -48.1,-0 0.3,50.9z"
|
||||||
|
android:fillColor="?attr/standardVectorGraphic"
|
||||||
|
android:strokeColor="?attr/standardVectorGraphic"/>
|
||||||
|
</vector>
|
10
app/src/main/res/drawable/ic_finalize.xml
Normal file
10
app/src/main/res/drawable/ic_finalize.xml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="192dp"
|
||||||
|
android:height="192dp"
|
||||||
|
android:viewportWidth="192"
|
||||||
|
android:viewportHeight="192">
|
||||||
|
<path
|
||||||
|
android:pathData="M109,89.5l-30.5,30.5 -12,-12 -12.1,-12 -3.9,4 -3.9,4 16.2,16.3 16.2,16.2 34,-34c18.7,-18.7 34,-34.5 34,-35 0,-0.6 -1.7,-2.8 -3.8,-4.8l-3.7,-3.7 -30.5,30.5z"
|
||||||
|
android:fillColor="?attr/standardVectorGraphic"
|
||||||
|
android:strokeColor="?attr/standardVectorGraphic"/>
|
||||||
|
</vector>
|
4
app/src/main/res/drawable/ic_import.xml
Normal file
4
app/src/main/res/drawable/ic_import.xml
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
<vector android:height="192dp" android:viewportHeight="24"
|
||||||
|
android:viewportWidth="24" android:width="192dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="?attr/standardVectorGraphic" android:pathData="m12 2v10l2 -2h1l2 2v-10zm-9 1v19h18v-19h-3v16h-12v-13h5v-3z"/>
|
||||||
|
</vector>
|
Binary file not shown.
Before Width: | Height: | Size: 321 B |
10
app/src/main/res/drawable/ic_info_black_24dp.xml
Normal file
10
app/src/main/res/drawable/ic_info_black_24dp.xml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="36dp"
|
||||||
|
android:height="36dp"
|
||||||
|
android:viewportWidth="36"
|
||||||
|
android:viewportHeight="36">
|
||||||
|
<path
|
||||||
|
android:pathData="M11.2,4.7c-7.1,3.5 -10.2,13.3 -6.4,20.3 2.3,4.2 8.4,8 13,8 7.9,-0 15.2,-7.3 15.2,-15.2 -0.1,-10.6 -12.1,-17.9 -21.8,-13.1zM19,12c0,0.5 -0.4,1 -1,1 -0.5,-0 -1,-0.5 -1,-1 0,-0.6 0.5,-1 1,-1 0.6,-0 1,0.4 1,1zM19,21c0,2.2 -0.4,4 -1,4 -0.5,-0 -1,-1.8 -1,-4 0,-2.2 0.5,-4 1,-4 0.6,-0 1,1.8 1,4z"
|
||||||
|
android:fillColor="?attr/standardVectorGraphic"
|
||||||
|
android:strokeColor="?attr/standardVectorGraphic"/>
|
||||||
|
</vector>
|
|
@ -4,6 +4,6 @@
|
||||||
android:viewportWidth="24.0"
|
android:viewportWidth="24.0"
|
||||||
android:viewportHeight="24.0">
|
android:viewportHeight="24.0">
|
||||||
<path
|
<path
|
||||||
android:fillColor="#FF000000"
|
android:fillColor="?attr/standardVectorGraphic"
|
||||||
android:pathData="M15.41,16.09l-4.58,-4.59 4.58,-4.59L14,5.5l-6,6 6,6z"/>
|
android:pathData="M15.41,16.09l-4.58,-4.59 4.58,-4.59L14,5.5l-6,6 6,6z"/>
|
||||||
</vector>
|
</vector>
|
|
@ -4,6 +4,6 @@
|
||||||
android:viewportWidth="24.0"
|
android:viewportWidth="24.0"
|
||||||
android:viewportHeight="24.0">
|
android:viewportHeight="24.0">
|
||||||
<path
|
<path
|
||||||
android:fillColor="#FF000000"
|
android:fillColor="?attr/standardVectorGraphic"
|
||||||
android:pathData="M8.59,16.34l4.58,-4.59 -4.58,-4.59L10,5.75l6,6 -6,6z"/>
|
android:pathData="M8.59,16.34l4.58,-4.59 -4.58,-4.59L10,5.75l6,6 -6,6z"/>
|
||||||
</vector>
|
</vector>
|
|
@ -5,32 +5,32 @@
|
||||||
android:viewportHeight="512">
|
android:viewportHeight="512">
|
||||||
<path
|
<path
|
||||||
android:pathData="M174.65,41.63h13.43v429.87h-13.43z"
|
android:pathData="M174.65,41.63h13.43v429.87h-13.43z"
|
||||||
android:fillColor="#fff"/>
|
android:fillColor="?attr/lightestBackGround"/>
|
||||||
<path
|
<path
|
||||||
android:pathData="M322.42,41.63h13.43v429.87h-13.43z"
|
android:pathData="M322.42,41.63h13.43v429.87h-13.43z"
|
||||||
android:fillColor="#fff"/>
|
android:fillColor="?attr/lightestBackGround"/>
|
||||||
<path
|
<path
|
||||||
android:pathData="M40.31,337.17l0,-13.43l429.87,-0l0,13.43z"
|
android:pathData="M40.31,337.17l0,-13.43l429.87,-0l0,13.43z"
|
||||||
android:fillColor="#fff"/>
|
android:fillColor="?attr/lightestBackGround"/>
|
||||||
<path
|
<path
|
||||||
android:pathData="M40.31,189.4l0,-13.43l429.87,-0l0,13.43z"
|
android:pathData="M40.31,189.4l0,-13.43l429.87,-0l0,13.43z"
|
||||||
android:fillColor="#fff"/>
|
android:fillColor="?attr/lightestBackGround"/>
|
||||||
<path
|
<path
|
||||||
android:pathData="M94.05,68.49h40.3V55.06H94.05a26.87,26.87 0,0 0,0 53.73h13.43a13.44,13.44 0,1 1,0 26.87H67.18v13.43h40.3a26.87,26.87 0,0 0,0 -53.73H94.05a13.44,13.44 0,0 1,0 -26.87Z"
|
android:pathData="M94.05,68.49h40.3V55.06H94.05a26.87,26.87 0,0 0,0 53.73h13.43a13.44,13.44 0,1 1,0 26.87H67.18v13.43h40.3a26.87,26.87 0,0 0,0 -53.73H94.05a13.44,13.44 0,0 1,0 -26.87Z"
|
||||||
android:fillColor="#fff"/>
|
android:fillColor="?attr/lightestBackGround"/>
|
||||||
<path
|
<path
|
||||||
android:pathData="M262,206.19h-40.3v94L262,300.19a26.86,26.86 0,0 0,26.86 -26.87v-40.3A26.86,26.86 0,0 0,262 206.19ZM262,286.79L235.1,286.79L235.1,219.62L262,219.62a13.43,13.43 0,0 1,13.43 13.43v40.3A13.43,13.43 0,0 1,262 286.79Z"
|
android:pathData="M262,206.19h-40.3v94L262,300.19a26.86,26.86 0,0 0,26.86 -26.87v-40.3A26.86,26.86 0,0 0,262 206.19ZM262,286.79L235.1,286.79L235.1,219.62L262,219.62a13.43,13.43 0,0 1,13.43 13.43v40.3A13.43,13.43 0,0 1,262 286.79Z"
|
||||||
android:fillColor="#fff"/>
|
android:fillColor="?attr/lightestBackGround"/>
|
||||||
<path
|
<path
|
||||||
android:pathData="M406.38,206.19L392.94,206.19a26.86,26.86 0,0 0,-26.86 26.86v40.3a26.86,26.86 0,0 0,26.86 26.87h13.44a26.87,26.87 0,0 0,26.86 -26.87v-40.3A26.87,26.87 0,0 0,406.38 206.19ZM419.81,273.35a13.48,13.48 0,0 1,-13.43 13.44L392.94,286.79a13.47,13.47 0,0 1,-13.43 -13.44v-40.3a13.47,13.47 0,0 1,13.43 -13.43h13.44a13.48,13.48 0,0 1,13.43 13.43Z"
|
android:pathData="M406.38,206.19L392.94,206.19a26.86,26.86 0,0 0,-26.86 26.86v40.3a26.86,26.86 0,0 0,26.86 26.87h13.44a26.87,26.87 0,0 0,26.86 -26.87v-40.3A26.87,26.87 0,0 0,406.38 206.19ZM419.81,273.35a13.48,13.48 0,0 1,-13.43 13.44L392.94,286.79a13.47,13.47 0,0 1,-13.43 -13.44v-40.3a13.47,13.47 0,0 1,13.43 -13.43h13.44a13.48,13.48 0,0 1,13.43 13.43Z"
|
||||||
android:fillColor="#fff"/>
|
android:fillColor="?attr/lightestBackGround"/>
|
||||||
<path
|
<path
|
||||||
android:pathData="M134.35,374.01l0,0l0,0l0,0l0,-9.5l-9.36,0l-0.04,0.1l-0.1,-0.1l-37.91,37.91l-6.32,6.32l0,-12.56l0,-31.67l-13.44,0l0,19.82l0,17.34l0,20.51l0,17.64l0,18.72l13.44,0l0,-30.8l6.45,-6.45l37.78,37.25l0,0l9.5,0l0,-9.36l-37.85,-37.33l37.84,-37.84l0.01,0z"
|
android:pathData="M134.35,374.01l0,0l0,0l0,0l0,-9.5l-9.36,0l-0.04,0.1l-0.1,-0.1l-37.91,37.91l-6.32,6.32l0,-12.56l0,-31.67l-13.44,0l0,19.82l0,17.34l0,20.51l0,17.64l0,18.72l13.44,0l0,-30.8l6.45,-6.45l37.78,37.25l0,0l9.5,0l0,-9.36l-37.85,-37.33l37.84,-37.84l0.01,0z"
|
||||||
android:fillColor="#fff"/>
|
android:fillColor="?attr/lightestBackGround"/>
|
||||||
<path
|
<path
|
||||||
android:pathData="M275.4,58.42v60.45a20.15,20.15 0,1 1,-40.3 0V58.42H221.67v60.45a33.58,33.58 0,1 0,67.16 0V58.42Z"
|
android:pathData="M275.4,58.42v60.45a20.15,20.15 0,1 1,-40.3 0V58.42H221.67v60.45a33.58,33.58 0,1 0,67.16 0V58.42Z"
|
||||||
android:fillColor="#fff"/>
|
android:fillColor="?attr/lightestBackGround"/>
|
||||||
<path
|
<path
|
||||||
android:pathData="M275.4,364.51V425a20.15,20.15 0,1 1,-40.3 0V364.51H221.67V425a33.58,33.58 0,1 0,67.16 0V364.51Z"
|
android:pathData="M275.4,364.51V425a20.15,20.15 0,1 1,-40.3 0V364.51H221.67V425a33.58,33.58 0,1 0,67.16 0V364.51Z"
|
||||||
android:fillColor="#fff"/>
|
android:fillColor="?attr/lightestBackGround"/>
|
||||||
</vector>
|
</vector>
|
||||||
|
|
|
@ -2,16 +2,16 @@
|
||||||
xmlns:aapt="http://schemas.android.com/aapt"
|
xmlns:aapt="http://schemas.android.com/aapt"
|
||||||
android:width="512dp"
|
android:width="512dp"
|
||||||
android:height="512dp"
|
android:height="512dp"
|
||||||
android:viewportWidth="512"
|
android:viewportWidth="600"
|
||||||
android:viewportHeight="512">
|
android:viewportHeight="600">
|
||||||
<path
|
<path
|
||||||
android:pathData="M510.91,471.7V216.47L336.27,41.83H323.68V93.05L289.26,58.62H275.82v40.3l-40.3,-40.3H222.09l0,16.77L188.51,41.83H175.07l0.12,54.69L134.35,55.68 88.6,62 71.8,76.25l2.52,17.64 5,6.71 -5.88,-0.84 38.62,38.62 -44.49,-2.52V149.3l27,27 -53.83,-0.1V189.6L174.23,323.09H40.74v14.28l26.87,26.86v94L121.34,512H470.61A40.42,40.42 0,0 0,510.91 471.7Z">
|
android:pathData="M659,552.9V364.5L336.3,41.8h-12.6V93l-34.4,-34.4h-13.4v40.3l-40.3,-40.3h-13.4v16.8l-33.6,-33.6h-13.4l0.1,54.7l-40.8,-40.8L88.6,62L71.8,76.2l2.5,17.6l5,6.7l-5.9,-0.8l38.6,38.6l-44.5,-2.5v13.4l27,27l-53.8,-0.1v13.4l133.5,133.5H40.7v14.3l26.9,26.9v94l141.5,141.6L633,611.9C655.2,611.8 658.9,575.1 659,552.9z">
|
||||||
<aapt:attr name="android:fillColor">
|
<aapt:attr name="android:fillColor">
|
||||||
<gradient
|
<gradient
|
||||||
android:startY="43.94"
|
android:startY="30.4022"
|
||||||
android:startX="119.85"
|
android:startX="143.3293"
|
||||||
android:endY="551.52"
|
android:endY="680.6151"
|
||||||
android:endX="412.9"
|
android:endX="518.728"
|
||||||
android:type="linear">
|
android:type="linear">
|
||||||
<item android:offset="0" android:color="#FF004492"/>
|
<item android:offset="0" android:color="#FF004492"/>
|
||||||
<item android:offset="0.22" android:color="#F9004593"/>
|
<item android:offset="0.22" android:color="#F9004593"/>
|
||||||
|
@ -25,33 +25,33 @@
|
||||||
</aapt:attr>
|
</aapt:attr>
|
||||||
</path>
|
</path>
|
||||||
<path
|
<path
|
||||||
android:pathData="M174.65,41.63h13.43v429.87h-13.43z"
|
android:pathData="M174.6,41.6h13.4v429.9h-13.4z"
|
||||||
android:fillColor="#fff"/>
|
android:fillColor="#FFFFFF"/>
|
||||||
<path
|
<path
|
||||||
android:pathData="M322.42,41.63h13.43v429.87h-13.43z"
|
android:pathData="M322.4,41.6h13.4v429.9h-13.4z"
|
||||||
android:fillColor="#fff"/>
|
android:fillColor="#FFFFFF"/>
|
||||||
<path
|
<path
|
||||||
android:pathData="M40.31,337.17l0,-13.43l429.87,-0l0,13.43z"
|
android:pathData="M40.3,323.7h429.9v13.4h-429.9z"
|
||||||
android:fillColor="#fff"/>
|
android:fillColor="#FFFFFF"/>
|
||||||
<path
|
<path
|
||||||
android:pathData="M40.31,189.4l0,-13.43l429.87,-0l0,13.43z"
|
android:pathData="M40.3,176h429.9v13.4h-429.9z"
|
||||||
android:fillColor="#fff"/>
|
android:fillColor="#FFFFFF"/>
|
||||||
<path
|
<path
|
||||||
android:pathData="M94.05,68.49h40.3V55.06H94.05a26.87,26.87 0,0 0,0 53.73h13.43a13.44,13.44 0,1 1,0 26.87H67.18v13.43h40.3a26.87,26.87 0,0 0,0 -53.73H94.05a13.44,13.44 0,0 1,0 -26.87Z"
|
android:pathData="M94.1,68.5h40.3V55.1H94.1c-14.8,0.3 -26.6,12.5 -26.3,27.4c0.3,14.4 11.9,26.1 26.3,26.3h13.4c7.4,-0.2 13.6,5.6 13.8,13.1c0.2,7.4 -5.6,13.6 -13.1,13.8c-0.2,0 -0.5,0 -0.7,0H67.2v13.4h40.3c14.8,-0.3 26.6,-12.5 26.3,-27.4c-0.3,-14.4 -11.9,-26.1 -26.3,-26.3H94.1C86.6,95.2 80.8,89 81,81.6C81.2,74.4 86.9,68.7 94.1,68.5z"
|
||||||
android:fillColor="#fff"/>
|
android:fillColor="#FFFFFF"/>
|
||||||
<path
|
<path
|
||||||
android:pathData="M262,206.19h-40.3v94L262,300.19a26.86,26.86 0,0 0,26.86 -26.87v-40.3A26.86,26.86 0,0 0,262 206.19ZM262,286.79L235.1,286.79L235.1,219.62L262,219.62a13.43,13.43 0,0 1,13.43 13.43v40.3A13.43,13.43 0,0 1,262 286.79Z"
|
android:pathData="M262,206.2h-40.3v94H262c14.8,0 26.9,-12 26.9,-26.9c0,0 0,0 0,0V233C288.8,218.2 276.8,206.2 262,206.2zM262,286.8h-26.9v-67.2H262c7.4,0 13.4,6 13.4,13.4v40.3C275.4,280.8 269.4,286.8 262,286.8C262,286.8 262,286.8 262,286.8z"
|
||||||
android:fillColor="#fff"/>
|
android:fillColor="#FFFFFF"/>
|
||||||
<path
|
<path
|
||||||
android:pathData="M406.38,206.19L392.94,206.19a26.86,26.86 0,0 0,-26.86 26.86v40.3a26.86,26.86 0,0 0,26.86 26.87h13.44a26.87,26.87 0,0 0,26.86 -26.87v-40.3A26.87,26.87 0,0 0,406.38 206.19ZM419.81,273.35a13.48,13.48 0,0 1,-13.43 13.44L392.94,286.79a13.47,13.47 0,0 1,-13.43 -13.44v-40.3a13.47,13.47 0,0 1,13.43 -13.43h13.44a13.48,13.48 0,0 1,13.43 13.43Z"
|
android:pathData="M406.4,206.2h-13.4c-14.8,0 -26.9,12 -26.9,26.9v40.3c0,14.8 12,26.9 26.9,26.9c0,0 0,0 0,0h13.4c14.8,0 26.9,-12 26.9,-26.9v-40.3C433.2,218.2 421.2,206.2 406.4,206.2zM419.8,273.4c0,7.4 -6,13.4 -13.4,13.4h-13.4c-7.4,0 -13.4,-6 -13.4,-13.4v-40.3c0,-7.4 6,-13.4 13.4,-13.4h13.4c7.4,0 13.4,6 13.4,13.4V273.4z"
|
||||||
android:fillColor="#fff"/>
|
android:fillColor="#FFFFFF"/>
|
||||||
<path
|
<path
|
||||||
android:pathData="M134.35,374.01l0,0l0,0l0,0l0,-9.5l-9.36,0l-0.04,0.1l-0.1,-0.1l-37.91,37.91l-6.32,6.32l0,-12.56l0,-31.67l-13.44,0l0,19.82l0,17.34l0,20.51l0,17.64l0,18.72l13.44,0l0,-30.8l6.45,-6.45l37.78,37.25l0,0l9.5,0l0,-9.36l-37.85,-37.33l37.84,-37.84l0.01,0z"
|
android:pathData="M134.4,374l0,0l0,0l0,0l0,-9.5l-9.4,0l-0.1,0.1l-0.1,-0.1l-37.9,37.9l-6.3,6.3l0,-12.5l0,-31.7l-13.4,0l0,19.8l0,17.4l0,20.5l0,17.6l0,18.7l13.4,0l0,-30.8l6.5,-6.4l37.7,37.2l0,0l9.6,0l0,-9.3l-37.9,-37.3l37.8,-37.9z"
|
||||||
android:fillColor="#fff"/>
|
android:fillColor="#FFFFFF"/>
|
||||||
<path
|
<path
|
||||||
android:pathData="M275.4,58.42v60.45a20.15,20.15 0,1 1,-40.3 0V58.42H221.67v60.45a33.58,33.58 0,1 0,67.16 0V58.42Z"
|
android:pathData="M275.4,58.4v60.4c0,11.1 -9,20.2 -20.1,20.2s-20.2,-9 -20.2,-20.2l0,0V58.4h-13.4v60.4c0,18.5 15,33.6 33.6,33.6c18.5,0 33.6,-15 33.6,-33.6V58.4H275.4z"
|
||||||
android:fillColor="#fff"/>
|
android:fillColor="#FFFFFF"/>
|
||||||
<path
|
<path
|
||||||
android:pathData="M275.4,364.51V425a20.15,20.15 0,1 1,-40.3 0V364.51H221.67V425a33.58,33.58 0,1 0,67.16 0V364.51Z"
|
android:pathData="M275.4,364.5V425c0,11.1 -9,20.1 -20.1,20.1s-20.2,-9 -20.2,-20.1l0,0v-60.5h-13.4V425c0,18.5 15,33.6 33.6,33.6c18.5,0 33.6,-15 33.6,-33.6v-60.5H275.4z"
|
||||||
android:fillColor="#fff"/>
|
android:fillColor="#FFFFFF"/>
|
||||||
</vector>
|
</vector>
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:aapt="http://schemas.android.com/aapt"
|
||||||
|
android:width="512dp"
|
||||||
|
android:height="512dp"
|
||||||
|
android:viewportWidth="512"
|
||||||
|
android:viewportHeight="512">
|
||||||
|
<path
|
||||||
|
android:pathData="M510.91,471.7V216.47L336.27,41.83H323.68V93.05L289.26,58.62H275.82v40.3l-40.3,-40.3H222.09l0,16.77L188.51,41.83H175.07l0.12,54.69L134.35,55.68 88.6,62 71.8,76.25l2.52,17.64 5,6.71 -5.88,-0.84 38.62,38.62 -44.49,-2.52V149.3l27,27 -53.83,-0.1V189.6L174.23,323.09H40.74v14.28l26.87,26.86v94L121.34,512H470.61A40.42,40.42 0,0 0,510.91 471.7Z">
|
||||||
|
<aapt:attr name="android:fillColor">
|
||||||
|
<gradient
|
||||||
|
android:startY="43.94"
|
||||||
|
android:startX="119.85"
|
||||||
|
android:endY="551.52"
|
||||||
|
android:endX="412.9"
|
||||||
|
android:type="linear">
|
||||||
|
<item android:offset="0" android:color="#FF004492"/>
|
||||||
|
<item android:offset="0.22" android:color="#F9004593"/>
|
||||||
|
<item android:offset="0.39" android:color="#E8024894"/>
|
||||||
|
<item android:offset="0.55" android:color="#C9044E97"/>
|
||||||
|
<item android:offset="0.7" android:color="#A007569B"/>
|
||||||
|
<item android:offset="0.84" android:color="#6B0A60A0"/>
|
||||||
|
<item android:offset="0.97" android:color="#280F6CA6"/>
|
||||||
|
<item android:offset="1" android:color="#19106FA8"/>
|
||||||
|
</gradient>
|
||||||
|
</aapt:attr>
|
||||||
|
</path>
|
||||||
|
<path
|
||||||
|
android:pathData="M174.65,41.63h13.43v429.87h-13.43z"
|
||||||
|
android:fillColor="#fff"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M322.42,41.63h13.43v429.87h-13.43z"
|
||||||
|
android:fillColor="#fff"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M40.31,337.17l0,-13.43l429.87,-0l0,13.43z"
|
||||||
|
android:fillColor="#fff"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M40.31,189.4l0,-13.43l429.87,-0l0,13.43z"
|
||||||
|
android:fillColor="#fff"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M94.05,68.49h40.3V55.06H94.05a26.87,26.87 0,0 0,0 53.73h13.43a13.44,13.44 0,1 1,0 26.87H67.18v13.43h40.3a26.87,26.87 0,0 0,0 -53.73H94.05a13.44,13.44 0,0 1,0 -26.87Z"
|
||||||
|
android:fillColor="#fff"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M262,206.19h-40.3v94L262,300.19a26.86,26.86 0,0 0,26.86 -26.87v-40.3A26.86,26.86 0,0 0,262 206.19ZM262,286.79L235.1,286.79L235.1,219.62L262,219.62a13.43,13.43 0,0 1,13.43 13.43v40.3A13.43,13.43 0,0 1,262 286.79Z"
|
||||||
|
android:fillColor="#fff"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M406.38,206.19L392.94,206.19a26.86,26.86 0,0 0,-26.86 26.86v40.3a26.86,26.86 0,0 0,26.86 26.87h13.44a26.87,26.87 0,0 0,26.86 -26.87v-40.3A26.87,26.87 0,0 0,406.38 206.19ZM419.81,273.35a13.48,13.48 0,0 1,-13.43 13.44L392.94,286.79a13.47,13.47 0,0 1,-13.43 -13.44v-40.3a13.47,13.47 0,0 1,13.43 -13.43h13.44a13.48,13.48 0,0 1,13.43 13.43Z"
|
||||||
|
android:fillColor="#fff"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M134.35,374.01l0,0l0,0l0,0l0,-9.5l-9.36,0l-0.04,0.1l-0.1,-0.1l-37.91,37.91l-6.32,6.32l0,-12.56l0,-31.67l-13.44,0l0,19.82l0,17.34l0,20.51l0,17.64l0,18.72l13.44,0l0,-30.8l6.45,-6.45l37.78,37.25l0,0l9.5,0l0,-9.36l-37.85,-37.33l37.84,-37.84l0.01,0z"
|
||||||
|
android:fillColor="#fff"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M275.4,58.42v60.45a20.15,20.15 0,1 1,-40.3 0V58.42H221.67v60.45a33.58,33.58 0,1 0,67.16 0V58.42Z"
|
||||||
|
android:fillColor="#fff"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M275.4,364.51V425a20.15,20.15 0,1 1,-40.3 0V364.51H221.67V425a33.58,33.58 0,1 0,67.16 0V364.51Z"
|
||||||
|
android:fillColor="#fff"/>
|
||||||
|
</vector>
|
Binary file not shown.
Before Width: | Height: | Size: 1.6 KiB |
|
@ -0,0 +1,14 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="192dp"
|
||||||
|
android:height="192dp"
|
||||||
|
android:viewportWidth="192"
|
||||||
|
android:viewportHeight="192">
|
||||||
|
<path
|
||||||
|
android:pathData="M84.5,17.2c-9,1.6 -20.7,8.1 -27.9,15.4 -22.3,22.2 -21.8,57.6 1.1,80l6.3,6.1 0,10.2c0,9.5 0.2,10.4 2.5,12.6l2.4,2.5 27.1,-0 27.1,-0 2.4,-2.5c2.3,-2.2 2.5,-3.1 2.5,-12.6l0,-10.2 6.3,-6.1c23,-22.4 23.4,-57.6 1.1,-80 -13.4,-13.4 -31.9,-19 -50.9,-15.4zM113.6,36.4c8.6,4.3 14.3,10.2 18.8,19.6 2.8,5.9 3.1,7.4 3.1,16 0,8.3 -0.4,10.3 -2.8,15.4 -3.6,7.7 -8.1,13.1 -15.1,18.1l-5.6,4 0,9.2 0,9.3 -16,-0 -16,-0 0,-9.3 0,-9.2 -5.1,-3.5c-7,-4.7 -11.6,-10.1 -15.3,-17.9 -2.8,-6 -3.1,-7.5 -3.1,-16.1 0,-8.6 0.3,-10.1 3.2,-16.2 4,-8.5 9.7,-14.7 17.2,-18.6 7.9,-4.3 12.2,-5.2 21.5,-4.7 6.6,0.3 9.1,0.9 15.2,3.9z"
|
||||||
|
android:fillColor="?attr/standardVectorGraphic"
|
||||||
|
android:strokeColor="?attr/standardVectorGraphic"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M72,165.5c0,4.6 0.4,6 2.5,8 2.4,2.5 2.6,2.5 21.5,2.5 18.9,-0 19.1,-0 21.5,-2.5 2.1,-2 2.5,-3.4 2.5,-8l0,-5.5 -24,-0 -24,-0 0,5.5z"
|
||||||
|
android:fillColor="?attr/standardVectorGraphic"
|
||||||
|
android:strokeColor="?attr/standardVectorGraphic"/>
|
||||||
|
</vector>
|
|
@ -4,6 +4,6 @@
|
||||||
android:viewportWidth="24.0"
|
android:viewportWidth="24.0"
|
||||||
android:viewportHeight="24.0">
|
android:viewportHeight="24.0">
|
||||||
<path
|
<path
|
||||||
android:fillColor="#FF000000"
|
android:fillColor="?attr/standardVectorGraphic"
|
||||||
android:pathData="M11,17h2v-6h-2v6zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM11,9h2L13,7h-2v2z"/>
|
android:pathData="M11,17h2v-6h-2v6zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM11,9h2L13,7h-2v2z"/>
|
||||||
</vector>
|
</vector>
|
9
app/src/main/res/drawable/ic_menu_daily_sudoku.xml
Normal file
9
app/src/main/res/drawable/ic_menu_daily_sudoku.xml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24.0"
|
||||||
|
android:viewportHeight="24.0">
|
||||||
|
<path
|
||||||
|
android:fillColor="?attr/standardVectorGraphic"
|
||||||
|
android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8zM12.5,7H11v6l5.25,3.15 0.75,-1.23 -4.5,-2.67z"/>
|
||||||
|
</vector>
|
|
@ -4,6 +4,6 @@
|
||||||
android:viewportWidth="24.0"
|
android:viewportWidth="24.0"
|
||||||
android:viewportHeight="24.0">
|
android:viewportHeight="24.0">
|
||||||
<path
|
<path
|
||||||
android:fillColor="#FF000000"
|
android:fillColor="?attr/standardVectorGraphic"
|
||||||
android:pathData="M11,18h2v-2h-2v2zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM12,6c-2.21,0 -4,1.79 -4,4h2c0,-1.1 0.9,-2 2,-2s2,0.9 2,2c0,2 -3,1.75 -3,5h2c0,-2.25 3,-2.5 3,-5 0,-2.21 -1.79,-4 -4,-4z"/>
|
android:pathData="M11,18h2v-2h-2v2zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM12,6c-2.21,0 -4,1.79 -4,4h2c0,-1.1 0.9,-2 2,-2s2,0.9 2,2c0,2 -3,1.75 -3,5h2c0,-2.25 3,-2.5 3,-5 0,-2.21 -1.79,-4 -4,-4z"/>
|
||||||
</vector>
|
</vector>
|
|
@ -4,6 +4,6 @@
|
||||||
android:viewportWidth="24.0"
|
android:viewportWidth="24.0"
|
||||||
android:viewportHeight="24.0">
|
android:viewportHeight="24.0">
|
||||||
<path
|
<path
|
||||||
android:fillColor="#FF000000"
|
android:fillColor="?attr/standardVectorGraphic"
|
||||||
android:pathData="M10,20v-6h4v6h5v-8h3L12,3 2,12h3v8z"/>
|
android:pathData="M10,20v-6h4v6h5v-8h3L12,3 2,12h3v8z"/>
|
||||||
</vector>
|
</vector>
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue