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"
|
||||
minSdkVersion 16
|
||||
targetSdkVersion 29
|
||||
versionCode 8
|
||||
versionName "2.2.1"
|
||||
versionCode 9
|
||||
versionName "3.0.0"
|
||||
vectorDrawables.useSupportLibrary = true
|
||||
}
|
||||
buildTypes {
|
||||
|
@ -25,16 +25,23 @@ android {
|
|||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
dataBinding {
|
||||
enabled = true
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
||||
implementation 'androidx.preference:preference:1.1.1'
|
||||
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-v13:1.0.0'
|
||||
implementation 'androidx.appcompat:appcompat:1.1.0'
|
||||
implementation 'com.google.android.material:material:1.1.0'
|
||||
implementation 'androidx.appcompat:appcompat:1.2.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-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"
|
||||
package="org.secuso.privacyfriendlysudoku.ui.view">
|
||||
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
|
||||
<application
|
||||
android:name="org.secuso.privacyfriendlysudoku.SudokuApp"
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme"
|
||||
android:name="org.secuso.privacyfriendlysudoku.SudokuApp">
|
||||
android:theme="@style/AppTheme">
|
||||
<activity
|
||||
android:name="org.secuso.privacyfriendlysudoku.ui.SplashActivity"
|
||||
android:theme="@style/SplashTheme">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name="org.secuso.privacyfriendlysudoku.ui.MainActivity"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/AppTheme.NoActionBar">
|
||||
</activity>
|
||||
android:theme="@style/AppTheme.NoActionBar" />
|
||||
<activity
|
||||
android:name="org.secuso.privacyfriendlysudoku.ui.TutorialActivity"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/AppTheme.NoActionBar">
|
||||
</activity>
|
||||
android:theme="@style/AppTheme.NoActionBar" />
|
||||
<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
|
||||
android:name="org.secuso.privacyfriendlysudoku.ui.SettingsActivity"
|
||||
android:label="@string/title_activity_settings"
|
||||
|
@ -37,7 +42,26 @@
|
|||
<activity
|
||||
android:name="org.secuso.privacyfriendlysudoku.ui.GameActivity"
|
||||
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.LoadGameActivity" />
|
||||
<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;
|
||||
|
||||
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;
|
||||
|
||||
import android.content.Context;
|
||||
|
@ -6,7 +22,10 @@ import android.os.Handler;
|
|||
import android.os.Parcel;
|
||||
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.qqwing.QQWing;
|
||||
import org.secuso.privacyfriendlysudoku.game.CellConflict;
|
||||
import org.secuso.privacyfriendlysudoku.game.CellConflictList;
|
||||
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.IModelChangedListener;
|
||||
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.List;
|
||||
import java.util.Timer;
|
||||
|
@ -32,6 +54,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||
public class GameController implements IModelChangedListener, Parcelable {
|
||||
|
||||
// General
|
||||
public static final int DAILY_SUDOKU_ID = Integer.MAX_VALUE - 1;
|
||||
private SharedPreferences settings;
|
||||
|
||||
// View
|
||||
|
@ -57,6 +80,7 @@ public class GameController implements IModelChangedListener, Parcelable {
|
|||
private GameType gameType;
|
||||
private GameDifficulty difficulty;
|
||||
private CellConflictList errorList = new CellConflictList();
|
||||
private boolean gameIsCustom;
|
||||
|
||||
// Undo Redo
|
||||
private UndoRedoManager undoRedoManager;
|
||||
|
@ -84,6 +108,7 @@ public class GameController implements IModelChangedListener, Parcelable {
|
|||
public GameController(GameType type, SharedPreferences pref, Context context) {
|
||||
this.context = context;
|
||||
this.gameBoard = new GameBoard(type);
|
||||
this.gameIsCustom = false;
|
||||
|
||||
setGameType(type);
|
||||
setSettings(pref);
|
||||
|
@ -95,6 +120,8 @@ public class GameController implements IModelChangedListener, Parcelable {
|
|||
return gameID;
|
||||
}
|
||||
|
||||
public boolean gameIsCustom() { return gameIsCustom; }
|
||||
|
||||
public void loadNewLevel(GameType type, GameDifficulty difficulty) {
|
||||
NewLevelManager newLevelManager = NewLevelManager.getInstance(context, settings);
|
||||
|
||||
|
@ -105,6 +132,23 @@ public class GameController implements IModelChangedListener, Parcelable {
|
|||
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() {
|
||||
return time;
|
||||
}
|
||||
|
@ -117,6 +161,7 @@ public class GameController implements IModelChangedListener, Parcelable {
|
|||
this.difficulty = gic.getDifficulty();
|
||||
this.time = gic.getTimePlayed();
|
||||
this.usedHints = gic.getHintsUsed();
|
||||
this.gameIsCustom = gic.isCustom();
|
||||
|
||||
setGameType(gic.getGameType());
|
||||
this.gameBoard = new GameBoard(gic.getGameType());
|
||||
|
@ -305,7 +350,7 @@ public class GameController implements IModelChangedListener, Parcelable {
|
|||
|
||||
SharedPreferences.Editor editor = settings.edit();
|
||||
// is anyone ever gonna play so many levels? :)
|
||||
if(gameID == Integer.MAX_VALUE-1) {
|
||||
if(gameID == DAILY_SUDOKU_ID - 1) {
|
||||
editor.putInt("lastGameID", 1);
|
||||
} else {
|
||||
editor.putInt("lastGameID", gameID);
|
||||
|
@ -318,6 +363,31 @@ public class GameController implements IModelChangedListener, Parcelable {
|
|||
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) {
|
||||
if(gameID == 0) {
|
||||
throw new IllegalArgumentException("GameID may not be 0.");
|
||||
|
@ -414,6 +484,7 @@ public class GameController implements IModelChangedListener, Parcelable {
|
|||
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;
|
||||
|
||||
import android.content.Context;
|
||||
|
@ -20,6 +36,7 @@ public class GameStateManager {
|
|||
|
||||
Context context;
|
||||
private SharedPreferences settings;
|
||||
private boolean includesDaily;
|
||||
|
||||
private static String FILE_EXTENSION = ".txt";
|
||||
private static String SAVE_PREFIX = "save_";
|
||||
|
@ -87,6 +104,15 @@ public class GameStateManager {
|
|||
gic.parseSetValues(values[i++]);
|
||||
gic.parseNotes(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) {
|
||||
file.delete();
|
||||
continue;
|
||||
|
@ -108,7 +134,7 @@ public class GameStateManager {
|
|||
LinkedList<GameInfoContainer> removeList = new LinkedList<>();
|
||||
|
||||
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));
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
|
||||
import android.content.Context;
|
||||
|
@ -15,6 +31,9 @@ import java.io.File;
|
|||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
@ -37,6 +56,10 @@ public class NewLevelManager {
|
|||
public static int PRE_SAVES_MIN = 3;
|
||||
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) {
|
||||
if(instance == null) {
|
||||
instance = new NewLevelManager(context, settings);
|
||||
|
@ -75,6 +98,16 @@ public class NewLevelManager {
|
|||
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) {
|
||||
Level level = dbHelper.getLevel(diff, type);
|
||||
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;
|
||||
|
||||
import android.os.Parcelable;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.Date;
|
||||
|
@ -53,6 +70,49 @@ public class QQWingController {
|
|||
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) {
|
||||
|
||||
level = new int[gameBoard.getSize()*gameBoard.getSize()];
|
||||
|
@ -200,6 +260,10 @@ public class QQWingController {
|
|||
}
|
||||
}
|
||||
|
||||
public boolean isImpossible() {
|
||||
return solveImpossible;
|
||||
}
|
||||
|
||||
private static class QQWingOptions {
|
||||
// defaults for options
|
||||
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;
|
||||
|
||||
import android.content.Context;
|
||||
|
@ -204,12 +220,12 @@ public class SaveLoadStatistics implements ITimerListener, IHintListener {
|
|||
|
||||
@Override
|
||||
public void onTick(int time) {
|
||||
incTime(gc.getDifficulty(), gc.getGameType());
|
||||
if (!gc.gameIsCustom()) incTime(gc.getDifficulty(), gc.getGameType());
|
||||
//gc.getUsedHints();
|
||||
}
|
||||
|
||||
@Override
|
||||
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;
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
|
||||
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;
|
||||
|
||||
import android.content.ContentValues;
|
||||
|
@ -6,7 +22,10 @@ import android.database.Cursor;
|
|||
import android.database.sqlite.SQLiteDatabase;
|
||||
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.migration.MigrationUtil;
|
||||
import org.secuso.privacyfriendlysudoku.controller.database.model.DailySudoku;
|
||||
import org.secuso.privacyfriendlysudoku.controller.database.model.Level;
|
||||
import org.secuso.privacyfriendlysudoku.game.GameDifficulty;
|
||||
import org.secuso.privacyfriendlysudoku.game.GameType;
|
||||
|
@ -18,7 +37,7 @@ import java.util.List;
|
|||
|
||||
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 DatabaseHelper(Context context) {
|
||||
|
@ -28,12 +47,17 @@ public class DatabaseHelper extends SQLiteOpenHelper {
|
|||
@Override
|
||||
public void onCreate(SQLiteDatabase db) {
|
||||
db.execSQL(LevelColumns.SQL_CREATE_ENTRIES);
|
||||
db.execSQL(DailySudokuColumns.SQL_CREATE_ENTRIES);
|
||||
}
|
||||
|
||||
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||
// fallback to destructive migration if no migration could be executed
|
||||
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) {
|
||||
onUpgrade(db, oldVersion, newVersion);
|
||||
|
@ -80,6 +104,39 @@ public class DatabaseHelper extends SQLiteOpenHelper {
|
|||
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) {
|
||||
SQLiteDatabase database = getWritableDatabase();
|
||||
|
||||
|
@ -93,5 +150,15 @@ public class DatabaseHelper extends SQLiteOpenHelper {
|
|||
SQLiteDatabase database = getWritableDatabase();
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
import android.util.Log;
|
||||
|
@ -25,6 +41,7 @@ public class GameInfoContainer {
|
|||
int[] setValues;
|
||||
boolean[][] setNotes;
|
||||
int hintsUsed;
|
||||
boolean isCustom;
|
||||
|
||||
public GameInfoContainer() {}
|
||||
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.setNotes = setNotes;
|
||||
this.hintsUsed = hintsUsed;
|
||||
isCustom = false;
|
||||
}
|
||||
|
||||
public void setID(int ID) {
|
||||
this.ID = ID;
|
||||
}
|
||||
|
||||
public void setCustom (boolean isCustom) { this.isCustom = isCustom; }
|
||||
|
||||
public boolean isCustom () { return isCustom; }
|
||||
|
||||
public void parseGameType(String s) {
|
||||
gameType = Enum.valueOf(GameType.class, s);
|
||||
if(gameType == null) {
|
||||
throw new IllegalArgumentException("GameInfoContainer: gameType could not be set.");
|
||||
}
|
||||
}
|
||||
|
||||
public int getTimePlayed() {
|
||||
|
@ -63,7 +82,7 @@ public class GameInfoContainer {
|
|||
|
||||
public void parseTime(String s) {
|
||||
try {
|
||||
this.timePlayed = Integer.valueOf(s);
|
||||
this.timePlayed = Integer.parseInt(s);
|
||||
} catch(NumberFormatException e) {
|
||||
throw new IllegalArgumentException("GameInfoContainer: Can not parse time.", e);
|
||||
}
|
||||
|
@ -71,7 +90,7 @@ public class GameInfoContainer {
|
|||
|
||||
public void parseHintsUsed(String s) {
|
||||
try {
|
||||
this.hintsUsed = Integer.valueOf(s);
|
||||
this.hintsUsed = Integer.parseInt(s);
|
||||
} catch(NumberFormatException e) {
|
||||
throw new IllegalArgumentException("GameInfoContainer: Can not parse hints used.", e);
|
||||
}
|
||||
|
@ -79,7 +98,7 @@ public class GameInfoContainer {
|
|||
|
||||
public void parseDate(String s) {
|
||||
try {
|
||||
this.lastTimePlayed = new Date(Long.valueOf(s));
|
||||
this.lastTimePlayed = new Date(Long.parseLong(s));
|
||||
} catch(NumberFormatException e) {
|
||||
throw new IllegalArgumentException("GameInfoContainer: LastTimePlayed Date can not be extracted.", e);
|
||||
}
|
||||
|
@ -87,9 +106,6 @@ public class GameInfoContainer {
|
|||
|
||||
public void parseDifficulty(String s) {
|
||||
difficulty = Enum.valueOf(GameDifficulty.class, s);
|
||||
if(difficulty == null) {
|
||||
throw new IllegalArgumentException("GameInfoContainer: difficulty could not be set.");
|
||||
}
|
||||
}
|
||||
|
||||
public void parseFixedValues(String s){
|
||||
|
@ -104,6 +120,11 @@ public class GameInfoContainer {
|
|||
fixedValues = new int[s.length()];
|
||||
for(int i = 0; i < s.length(); i++) {
|
||||
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 sq = size*size;
|
||||
|
||||
if(gameType != GameType.Unspecified && gameType != null) {
|
||||
if(gameType != GameType.Unspecified) {
|
||||
if(strings.length != sq) {
|
||||
throw new IllegalArgumentException("The string array must have "+sq+" entries.");
|
||||
}
|
||||
|
@ -174,6 +195,7 @@ public class GameInfoContainer {
|
|||
public static String getGameInfo(GameController controller) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
Date today = new Date();
|
||||
boolean custom = controller.gameIsCustom();
|
||||
|
||||
sb.append(controller.getGameType().name());
|
||||
sb.append("/");
|
||||
|
@ -191,6 +213,12 @@ public class GameInfoContainer {
|
|||
sb.append("/");
|
||||
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();
|
||||
|
||||
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;
|
||||
|
||||
import org.secuso.privacyfriendlysudoku.controller.GameController;
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*
|
||||
* 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
|
||||
* 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.
|
||||
*
|
||||
* 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
|
||||
* 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.
|
||||
*
|
||||
* 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
|
||||
* 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.
|
||||
*
|
||||
* 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
|
||||
* 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.
|
||||
*
|
||||
* 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
|
||||
* 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.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
|
@ -199,6 +199,10 @@ public class QQWing {
|
|||
return reset();
|
||||
}
|
||||
|
||||
public void setRandom(int seed) {
|
||||
random = new Random(seed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the board to its initial state with only the givens. This method
|
||||
* 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
|
||||
* 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.
|
||||
*
|
||||
* 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;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import org.secuso.privacyfriendlysudoku.controller.Symbol;
|
||||
import org.secuso.privacyfriendlysudoku.game.listener.IModelChangedListener;
|
||||
|
||||
import java.util.LinkedList;
|
||||
|
@ -214,6 +231,20 @@ public class GameBoard implements Cloneable, Parcelable {
|
|||
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() {
|
||||
return actionOnCells(new ICellAction<Boolean>() {
|
||||
@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;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
|
||||
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.R;
|
||||
|
||||
/**
|
||||
* The AboutActivity is extended by the BaseActivity and is responsible for the content of the AboutActivity.
|
||||
*/
|
||||
|
||||
public class AboutActivity extends BaseActivity {
|
||||
|
||||
@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;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.app.DialogFragment;
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
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.PreferenceActivity;
|
||||
import android.preference.PreferenceManager;
|
||||
import com.google.android.material.navigation.NavigationView;
|
||||
|
||||
import androidx.appcompat.app.AppCompatDelegate;
|
||||
import androidx.core.view.GravityCompat;
|
||||
import androidx.drawerlayout.widget.DrawerLayout;
|
||||
import androidx.appcompat.app.ActionBarDrawerToggle;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
|
||||
import android.util.Log;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
|
@ -27,28 +52,40 @@ import android.widget.Button;
|
|||
import android.widget.LinearLayout;
|
||||
import android.widget.RatingBar;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.secuso.privacyfriendlysudoku.controller.GameController;
|
||||
import org.secuso.privacyfriendlysudoku.controller.GameStateManager;
|
||||
import org.secuso.privacyfriendlysudoku.controller.SaveLoadStatistics;
|
||||
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.game.listener.IGameSolvedListener;
|
||||
import org.secuso.privacyfriendlysudoku.game.listener.ITimerListener;
|
||||
import org.secuso.privacyfriendlysudoku.ui.listener.IHintDialogFragmentListener;
|
||||
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.SudokuFieldLayout;
|
||||
import org.secuso.privacyfriendlysudoku.ui.view.SudokuKeyboardLayout;
|
||||
import org.secuso.privacyfriendlysudoku.ui.view.SudokuSpecialButtonLayout;
|
||||
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.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;
|
||||
SudokuFieldLayout layout;
|
||||
|
@ -57,15 +94,27 @@ public class GameActivity extends BaseActivity implements NavigationView.OnNavig
|
|||
TextView timerView;
|
||||
TextView viewName ;
|
||||
RatingBar ratingBar;
|
||||
private boolean gameSolved = false;
|
||||
SaveLoadStatistics statistics = new SaveLoadStatistics(this);
|
||||
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
|
||||
protected void onPostCreate(Bundle savedInstanceState) {
|
||||
super.onPostCreate(savedInstanceState);
|
||||
|
||||
if(gameSolved) {
|
||||
if(gameSolved || !startGame) {
|
||||
gameController.pauseTimer();
|
||||
} else {
|
||||
// start the game
|
||||
|
@ -80,14 +129,29 @@ public class GameActivity extends BaseActivity implements NavigationView.OnNavig
|
|||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
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)) {
|
||||
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
||||
}
|
||||
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
GameType gameType = GameType.Unspecified;
|
||||
GameDifficulty gameDifficulty = GameDifficulty.Unspecified;
|
||||
int loadLevelID = 0;
|
||||
|
@ -96,26 +160,135 @@ public class GameActivity extends BaseActivity implements NavigationView.OnNavig
|
|||
if(savedInstanceState == null) {
|
||||
|
||||
Bundle extras = getIntent().getExtras();
|
||||
|
||||
/*
|
||||
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());
|
||||
|
||||
// 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);
|
||||
|
||||
} else {
|
||||
boolean isDailySudoku = false;
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
gameController = new GameController(sharedPref, getApplicationContext());
|
||||
/*
|
||||
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 && loadableGames.size() > loadLevelID) {
|
||||
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 {
|
||||
gameController = savedInstanceState.getParcelable("gameController");
|
||||
// in case we get the same object back
|
||||
|
@ -170,7 +343,7 @@ public class GameActivity extends BaseActivity implements NavigationView.OnNavig
|
|||
|
||||
//set Special keys
|
||||
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
|
||||
timerView = (TextView)findViewById(R.id.timerView);
|
||||
|
@ -217,11 +390,21 @@ public class GameActivity extends BaseActivity implements NavigationView.OnNavig
|
|||
@Override
|
||||
public void onPause(){
|
||||
super.onPause();
|
||||
if(!gameSolved) {
|
||||
|
||||
// Do not save solved or unplayable sudokus
|
||||
if(!gameSolved && startGame) {
|
||||
gameController.saveGame(this);
|
||||
}
|
||||
gameController.deleteTimer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNewIntent(Intent intent) {
|
||||
super.onNewIntent(intent);
|
||||
startActivity(intent);
|
||||
finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume(){
|
||||
super.onResume();
|
||||
|
@ -233,7 +416,7 @@ public class GameActivity extends BaseActivity implements NavigationView.OnNavig
|
|||
|
||||
gameController.initTimer();
|
||||
|
||||
if(!gameSolved) {
|
||||
if(!gameSolved && startGame) {
|
||||
mHandler.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
@ -253,6 +436,12 @@ public class GameActivity extends BaseActivity implements NavigationView.OnNavig
|
|||
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
|
||||
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")
|
||||
@Override
|
||||
public boolean onNavigationItemSelected(MenuItem item) {
|
||||
|
@ -286,6 +468,39 @@ public class GameActivity extends BaseActivity implements NavigationView.OnNavig
|
|||
resetDialog.show(getFragmentManager(), "ResetDialogFragment");
|
||||
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:
|
||||
//create new game
|
||||
intent = new Intent(this, MainActivity.class);
|
||||
|
@ -296,8 +511,6 @@ public class GameActivity extends BaseActivity implements NavigationView.OnNavig
|
|||
case R.id.menu_settings:
|
||||
//open settings
|
||||
intent = new Intent(this,SettingsActivity.class);
|
||||
intent.putExtra( PreferenceActivity.EXTRA_SHOW_FRAGMENT, SettingsActivity.GamePreferenceFragment.class.getName() );
|
||||
intent.putExtra( PreferenceActivity.EXTRA_NO_HEADERS, true );
|
||||
break;
|
||||
|
||||
case R.id.nav_highscore:
|
||||
|
@ -341,7 +554,6 @@ public class GameActivity extends BaseActivity implements NavigationView.OnNavig
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onSolved() {
|
||||
gameSolved = true;
|
||||
|
@ -350,13 +562,34 @@ public class GameActivity extends BaseActivity implements NavigationView.OnNavig
|
|||
gameController.deleteGame(this);
|
||||
disableReset();
|
||||
|
||||
//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();
|
||||
}
|
||||
|
||||
//Don't save statistics if game is custom
|
||||
boolean isNewBestTime;
|
||||
|
||||
if (!gameController.gameIsCustom()) {
|
||||
//Show time hints new plus old best time
|
||||
|
||||
statistics.saveGameStats();
|
||||
|
||||
boolean isNewBestTime = gameController.getUsedHints() == 0
|
||||
isNewBestTime = gameController.getUsedHints() == 0
|
||||
&& statistics.loadStats(gameController.getGameType(),gameController.getDifficulty()).getMinTime() >= gameController.getTime();
|
||||
|
||||
} else {
|
||||
// cannot be best time if sudoku is custom
|
||||
isNewBestTime = false;
|
||||
}
|
||||
|
||||
|
||||
dialog = new WinDialog(this, R.style.WinDialog , timeToString(gameController.getTime()), String.valueOf(gameController.getUsedHints()), isNewBestTime);
|
||||
|
||||
dialog.getWindow().setContentView(R.layout.win_screen_layout);
|
||||
|
@ -395,18 +628,6 @@ public class GameActivity extends BaseActivity implements NavigationView.OnNavig
|
|||
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(){
|
||||
NavigationView navView = (NavigationView)findViewById(R.id.nav_view);
|
||||
Menu navMenu = navView.getMenu();
|
||||
|
@ -418,7 +639,7 @@ public class GameActivity extends BaseActivity implements NavigationView.OnNavig
|
|||
// display the time
|
||||
timerView.setText(timeToString(time));
|
||||
|
||||
if(gameSolved) return;
|
||||
if(gameSolved || !startGame) return;
|
||||
// save time
|
||||
gameController.saveGame(this);
|
||||
}
|
||||
|
@ -433,11 +654,100 @@ public class GameActivity extends BaseActivity implements NavigationView.OnNavig
|
|||
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
|
||||
public void onDialogNegativeClick() {
|
||||
// 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 {
|
||||
|
||||
LinkedList<IResetDialogFragmentListener> listeners = new LinkedList<>();
|
||||
|
@ -454,7 +764,7 @@ public class GameActivity extends BaseActivity implements NavigationView.OnNavig
|
|||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
// 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)
|
||||
.setPositiveButton(R.string.reset_confirmation_confirm, new DialogInterface.OnClickListener() {
|
||||
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;
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
import android.app.Activity;
|
||||
|
@ -21,6 +37,7 @@ import android.widget.ListView;
|
|||
import android.widget.RatingBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.secuso.privacyfriendlysudoku.controller.GameController;
|
||||
import org.secuso.privacyfriendlysudoku.controller.GameStateManager;
|
||||
import org.secuso.privacyfriendlysudoku.controller.helper.GameInfoContainer;
|
||||
import org.secuso.privacyfriendlysudoku.game.GameDifficulty;
|
||||
|
@ -70,6 +87,13 @@ public class LoadGameActivity extends BaseActivity implements IDeleteDialogFragm
|
|||
GameStateManager gameStateManager = new GameStateManager(this, settings);
|
||||
loadableGameList = gameStateManager.loadGameStateInfo();
|
||||
|
||||
for (GameInfoContainer container : loadableGameList) {
|
||||
if (container.getID() == GameController.DAILY_SUDOKU_ID) {
|
||||
loadableGameList.remove(container);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
AdapterView.OnItemClickListener clickListener = new AdapterView.OnItemClickListener() {
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
|
@ -137,7 +161,7 @@ public class LoadGameActivity extends BaseActivity implements IDeleteDialogFragm
|
|||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
// 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)
|
||||
.setPositiveButton(R.string.loadgame_delete_confirm, new DialogInterface.OnClickListener() {
|
||||
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 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);
|
||||
TextView customLabel = (TextView) convertView.findViewById(R.id.loadgame_listentry_custom_label);
|
||||
|
||||
switch(gic.getGameType()) {
|
||||
case Default_6x6:
|
||||
|
@ -221,6 +247,9 @@ public class LoadGameActivity extends BaseActivity implements IDeleteDialogFragm
|
|||
difficultyBar.setMax(GameDifficulty.getValidDifficultyList().size());
|
||||
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 seconds = time % 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;
|
||||
|
||||
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.SharedPreferences;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceActivity;
|
||||
import android.preference.PreferenceManager;
|
||||
import com.google.android.material.navigation.NavigationView;
|
||||
|
||||
import androidx.appcompat.app.AppCompatDelegate;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentPagerAdapter;
|
||||
|
@ -13,31 +36,36 @@ import androidx.core.view.GravityCompat;
|
|||
import androidx.viewpager.widget.ViewPager;
|
||||
import androidx.drawerlayout.widget.DrawerLayout;
|
||||
import androidx.appcompat.app.ActionBarDrawerToggle;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.RatingBar;
|
||||
import android.widget.TextView;
|
||||
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.helper.GameInfoContainer;
|
||||
import org.secuso.privacyfriendlysudoku.game.GameDifficulty;
|
||||
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.databinding.DialogFragmentImportBoardBinding;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
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;
|
||||
TextView difficultyText;
|
||||
|
@ -53,9 +81,20 @@ public class MainActivity extends BaseActivity implements NavigationView.OnNavig
|
|||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
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);
|
||||
|
||||
|
@ -121,17 +160,44 @@ public class MainActivity extends BaseActivity implements NavigationView.OnNavig
|
|||
final LinkedList<GameDifficulty> difficultyList = GameDifficulty.getValidDifficultyList();
|
||||
difficultyBar.setNumStars(difficultyList.size());
|
||||
difficultyBar.setMax(difficultyList.size());
|
||||
CheckBox createGameBar = (CheckBox) findViewById(R.id.circleButton);
|
||||
difficultyBar.setOnRatingBarChangeListener(new RatingBar.OnRatingBarChangeListener() {
|
||||
@Override
|
||||
public void onRatingChanged(RatingBar ratingBar, float rating, boolean fromUser) {
|
||||
if (rating < 1) {
|
||||
ratingBar.setRating(1);
|
||||
}
|
||||
createGameBar.setChecked(false);
|
||||
((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);
|
||||
}
|
||||
}
|
||||
});
|
||||
GameDifficulty lastChosenDifficulty = GameDifficulty.valueOf(settings.getString("lastChosenDifficulty", "Moderate"));
|
||||
|
||||
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();
|
||||
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
|
||||
|
@ -166,8 +232,6 @@ public class MainActivity extends BaseActivity implements NavigationView.OnNavig
|
|||
winScreen.show(fm,"win_screen_layout");*/
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void onClick(View view) {
|
||||
|
||||
Intent i = null;
|
||||
|
@ -184,6 +248,18 @@ public class MainActivity extends BaseActivity implements NavigationView.OnNavig
|
|||
break;
|
||||
case R.id.playButton:
|
||||
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;
|
||||
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);
|
||||
GameStateManager fm = new GameStateManager(getBaseContext(), settings);
|
||||
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.setBackgroundResource(R.drawable.standalone_button);
|
||||
} else {
|
||||
|
@ -254,7 +330,7 @@ public class MainActivity extends BaseActivity implements NavigationView.OnNavig
|
|||
@Override
|
||||
public boolean onNavigationItemSelected(MenuItem item) {
|
||||
// Handle navigation view item clicks here.
|
||||
final int id = item.getItemId();
|
||||
int id = item.getItemId();
|
||||
|
||||
drawer.closeDrawer(GravityCompat.START);
|
||||
|
||||
|
@ -271,9 +347,9 @@ public class MainActivity extends BaseActivity implements NavigationView.OnNavig
|
|||
}
|
||||
}, 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);
|
||||
if (mainContent != null) {
|
||||
if (mainContent != null && id != R.id.nav_import_sudoku) {
|
||||
mainContent.animate().alpha(0).setDuration(MAIN_CONTENT_FADEOUT_DURATION);
|
||||
}
|
||||
|
||||
|
@ -292,11 +368,13 @@ public class MainActivity extends BaseActivity implements NavigationView.OnNavig
|
|||
Intent intent;
|
||||
|
||||
switch(id) {
|
||||
case R.id.nav_import_sudoku:
|
||||
ImportBoardDialog dialog = new ImportBoardDialog();
|
||||
dialog.show(getFragmentManager(), "ImportDialogFragment");
|
||||
break;
|
||||
case R.id.menu_settings_main:
|
||||
//open settings
|
||||
intent = new Intent(this,SettingsActivity.class);
|
||||
intent.putExtra( PreferenceActivity.EXTRA_SHOW_FRAGMENT, SettingsActivity.GamePreferenceFragment.class.getName() );
|
||||
intent.putExtra( PreferenceActivity.EXTRA_NO_HEADERS, true );
|
||||
intent = new Intent(this, SettingsActivity.class);
|
||||
startActivity(intent);
|
||||
overridePendingTransition(0, 0);
|
||||
break;
|
||||
|
@ -330,6 +408,12 @@ public class MainActivity extends BaseActivity implements NavigationView.OnNavig
|
|||
overridePendingTransition(0, 0);
|
||||
break;
|
||||
|
||||
case R.id.nav_dailySudoku_main:
|
||||
intent = new Intent(this, DailySudokuActivity.class);
|
||||
startActivity(intent);
|
||||
overridePendingTransition(0, 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
}
|
||||
return true;
|
||||
|
@ -345,6 +429,106 @@ public class MainActivity extends BaseActivity implements NavigationView.OnNavig
|
|||
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
|
||||
|
|
|
@ -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;
|
||||
|
||||
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;
|
||||
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Build;
|
||||
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.PreferenceManager;
|
||||
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 java.util.List;
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
public class SettingsActivity extends AppCompatActivity {
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean onIsMultiPane() {
|
||||
return isXLargeTablet(this);
|
||||
}
|
||||
private static SettingsFragment settingsFragment;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
private static void recheckNightModeProperties(SharedPreferences sharedPreferences) {
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
|
||||
public void onBuildHeaders(List<Header> target) {
|
||||
loadHeadersFromResource(R.xml.pref_settings_headers, target);
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
|
||||
/**
|
||||
* 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);
|
||||
if (sharedPreferences.getBoolean("pref_dark_mode_setting", false)) {
|
||||
|
||||
settingsFragment.findPreference("pref_dark_mode_automatically_by_system").setEnabled(false);
|
||||
settingsFragment.findPreference("pref_dark_mode_automatically_by_battery").setEnabled(false);
|
||||
} else {
|
||||
// For all other preferences, set the summary to the value's
|
||||
// simple string representation.
|
||||
preference.setSummary(stringValue);
|
||||
if (sharedPreferences.getBoolean("pref_dark_mode_automatically_by_battery", false) && sharedPreferences.getBoolean("pref_dark_mode_automatically_by_system", false) ) {
|
||||
sharedPreferences.edit().putBoolean("pref_dark_mode_automatically_by_battery", false).commit();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Binds a preference's summary to its value. More specifically, when the
|
||||
* preference's value is changed, its summary (line of text below the
|
||||
* preference title) is updated to reflect the value. The summary is also
|
||||
* immediately updated upon calling this method. The exact display format is
|
||||
* dependent on the type of preference.
|
||||
*
|
||||
* @see #sBindPreferenceSummaryToValueListener
|
||||
*/
|
||||
private static void bindPreferenceSummaryToValue(Preference preference) {
|
||||
// Set the listener to watch for value changes.
|
||||
preference.setOnPreferenceChangeListener(sBindPreferenceSummaryToValueListener);
|
||||
|
||||
// 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) {
|
||||
protected 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"));
|
||||
|
||||
setContentView(R.layout.settings_activity);
|
||||
settingsFragment = new SettingsFragment();
|
||||
getSupportFragmentManager()
|
||||
.beginTransaction()
|
||||
.replace(R.id.settings, settingsFragment)
|
||||
.commit();
|
||||
ActionBar actionBar = getSupportActionBar();
|
||||
if (actionBar != null) {
|
||||
actionBar.setDisplayHomeAsUpEnabled(true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
int id = item.getItemId();
|
||||
if (id == android.R.id.home) {
|
||||
getActivity().finish();
|
||||
//startActivity(new Intent(getActivity(), SettingsActivity.class));
|
||||
finish();
|
||||
return true;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
|
||||
public static class SettingsFragment extends PreferenceFragmentCompat {
|
||||
|
||||
@Override
|
||||
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
||||
setPreferencesFromResource(R.xml.pref_settings_general, rootKey);
|
||||
SharedPreferences preferenceManager = PreferenceManager
|
||||
.getDefaultSharedPreferences(getActivity());
|
||||
preferenceManager.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
|
||||
recheckNightModeProperties(preferenceManager);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
import android.content.Context;
|
||||
|
@ -20,7 +36,6 @@ import android.widget.TextView;
|
|||
|
||||
import org.secuso.privacyfriendlysudoku.ui.view.R;
|
||||
|
||||
|
||||
/**
|
||||
* Class structure taken from tutorial at http://www.androidhive.info/2016/05/android-build-intro-slider-app/
|
||||
* @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;
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
|
||||
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 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;
|
||||
|
||||
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;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
|
@ -31,15 +49,32 @@ public class SudokuCellView extends View {
|
|||
Symbol symbolsToUse = Symbol.Default;
|
||||
RelativeLayout.LayoutParams params;
|
||||
|
||||
|
||||
public SudokuCellView(Context context) {
|
||||
super(context);
|
||||
}
|
||||
int backgroundColor;
|
||||
int backgroundErrorColor;
|
||||
int backgroundSelectedColor;
|
||||
int backgroundConnectedOuterColor;
|
||||
int backgroundConnectedInnerColor;
|
||||
int backgroundValueHighlightedColor;
|
||||
int backgroundValueHighlightedSelectedColor;
|
||||
int textColor;
|
||||
|
||||
public SudokuCellView(Context context, AttributeSet 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) {
|
||||
this.selected = b;
|
||||
}
|
||||
|
@ -89,13 +124,6 @@ public class SudokuCellView extends View {
|
|||
return true;
|
||||
}*/
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||
super.onLayout(changed, left, top, right, bottom);
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDraw(Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
|
@ -108,27 +136,28 @@ public class SudokuCellView extends View {
|
|||
Paint p = new Paint();
|
||||
switch(highlightType) {
|
||||
case Default:
|
||||
p.setColor(Color.WHITE);
|
||||
p.setColor(backgroundColor);
|
||||
break;
|
||||
case Error:
|
||||
p.setColor(Color.LTGRAY);
|
||||
p.setColor(backgroundErrorColor);
|
||||
break;
|
||||
case Selected:
|
||||
p.setColor(Color.GREEN);
|
||||
p.setColor(backgroundSelectedColor);
|
||||
break;
|
||||
case Connected:
|
||||
p.setColor(Color.WHITE);
|
||||
p.setColor(backgroundConnectedOuterColor);
|
||||
drawBackground(canvas, 3, 3, mWidth - 3, mHeight - 3, p);
|
||||
p.setColor(Color.YELLOW);
|
||||
p.setColor(backgroundConnectedInnerColor);
|
||||
p.setAlpha(100);
|
||||
break;
|
||||
case Value_Highlighted:
|
||||
p.setColor(Color.YELLOW);
|
||||
p.setColor(backgroundValueHighlightedColor);
|
||||
break;
|
||||
case Value_Highlighted_Selected:
|
||||
p.setColor(Color.CYAN);
|
||||
p.setColor(backgroundValueHighlightedSelectedColor);
|
||||
break;
|
||||
default:
|
||||
p.setColor(Color.WHITE);
|
||||
p.setColor(backgroundColor);
|
||||
}
|
||||
|
||||
|
||||
|
@ -147,6 +176,7 @@ public class SudokuCellView extends View {
|
|||
|
||||
public void drawValue(Canvas canvas) {
|
||||
Paint p = new Paint();
|
||||
p.setColor(textColor);
|
||||
int root = (int) Math.sqrt(size);
|
||||
int j= root+1;
|
||||
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;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
|
@ -31,6 +49,9 @@ public class SudokuFieldLayout extends RelativeLayout implements IHighlightChang
|
|||
private int gameCellHeight;
|
||||
private SharedPreferences settings;
|
||||
private Paint p = new Paint();
|
||||
int backgroundColor;
|
||||
int errorColor;
|
||||
int sectionLineColor;
|
||||
|
||||
private OnTouchListener listener = new OnTouchListener() {
|
||||
@Override
|
||||
|
@ -55,8 +76,15 @@ public class SudokuFieldLayout extends RelativeLayout implements IHighlightChang
|
|||
public SudokuFieldLayout(Context context, AttributeSet attrs) {
|
||||
super(context, 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);
|
||||
setBackgroundColor(Color.argb(255, 200, 200, 200));
|
||||
setBackgroundColor(backgroundColor);
|
||||
}
|
||||
|
||||
public void setSettingsAndGame(SharedPreferences sharedPref, GameController gc) {
|
||||
|
@ -98,7 +126,7 @@ public class SudokuFieldLayout extends RelativeLayout implements IHighlightChang
|
|||
|
||||
if(gameController == null) return;
|
||||
|
||||
p.setColor(Color.BLACK);
|
||||
p.setColor(sectionLineColor);
|
||||
p.setStrokeWidth(5);
|
||||
|
||||
int horizontalSections = gameController.getSize() / sectionWidth;
|
||||
|
@ -222,7 +250,7 @@ public class SudokuFieldLayout extends RelativeLayout implements IHighlightChang
|
|||
p = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
p.setStyle(Paint.Style.STROKE);
|
||||
p.setStrokeWidth(4);
|
||||
p.setColor(Color.RED);
|
||||
p.setColor(errorColor);
|
||||
|
||||
float offsetX = 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;
|
||||
|
||||
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;
|
||||
|
||||
import android.content.Context;
|
||||
|
@ -7,7 +23,7 @@ import android.widget.ImageButton;
|
|||
/**
|
||||
* 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 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;
|
||||
|
||||
import android.app.Activity;
|
||||
|
@ -10,6 +26,7 @@ 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;
|
||||
|
@ -18,8 +35,11 @@ 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.listener.IHintDialogFragmentListener;
|
||||
|
||||
import java.util.LinkedList;
|
||||
|
@ -40,6 +60,7 @@ public class SudokuSpecialButtonLayout extends LinearLayout implements IHighligh
|
|||
Bitmap bitMap,bitResult;
|
||||
Canvas canvas;
|
||||
FragmentManager fragmentManager;
|
||||
Context context;
|
||||
|
||||
OnClickListener listener = new OnClickListener() {
|
||||
@Override
|
||||
|
@ -68,7 +89,7 @@ public class SudokuSpecialButtonLayout extends LinearLayout implements IHighligh
|
|||
break;
|
||||
case Hint:
|
||||
if(gameController.isValidCellSelected()) {
|
||||
if(gameController.getUsedHints() == 0) {
|
||||
if(gameController.getUsedHints() == 0 && !gameController.gameIsCustom()) {
|
||||
// are you sure you want to use a hint?
|
||||
HintConfirmationDialog hintDialog = new HintConfirmationDialog();
|
||||
hintDialog.show(fragmentManager, "HintDialogFragment");
|
||||
|
@ -93,6 +114,7 @@ public class SudokuSpecialButtonLayout extends LinearLayout implements IHighligh
|
|||
public SudokuSpecialButtonLayout(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
setWeightSum(fixedButtonsCount);
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
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;
|
||||
keyboard=key;
|
||||
gameController = gc;
|
||||
context = cxt;
|
||||
if(gameController != null) {
|
||||
gameController.registerHighlightChangedListener(this);
|
||||
}
|
||||
|
@ -142,6 +165,13 @@ public class SudokuSpecialButtonLayout extends LinearLayout implements IHighligh
|
|||
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++;
|
||||
}
|
||||
|
||||
|
@ -160,12 +190,13 @@ public class SudokuSpecialButtonLayout extends LinearLayout implements IHighligh
|
|||
R.drawable.numpad_highlighted_four : R.drawable.inactive_button);
|
||||
break;
|
||||
case NoteToggle:
|
||||
bitMap = BitmapFactory.decodeResource(getResources(), fixedButtons[i].getType().getResID());
|
||||
bitResult = Bitmap.createBitmap(bitMap.getWidth(), bitMap.getHeight(), Bitmap.Config.ARGB_8888);
|
||||
Drawable drawable = ContextCompat.getDrawable(context, fixedButtons[i].getType().getResID());
|
||||
// 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.drawBitmap(bitMap, 0, 0, null);
|
||||
drawable.draw(canvas);
|
||||
|
||||
fixedButtons[i].setImageBitmap(bitResult);
|
||||
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 {
|
||||
|
||||
LinkedList<IHintDialogFragmentListener> listeners = new LinkedList<>();
|
||||
|
@ -195,7 +238,7 @@ public class SudokuSpecialButtonLayout extends LinearLayout implements IHighligh
|
|||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
// 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)
|
||||
.setPositiveButton(R.string.hint_confirmation_confirm, new DialogInterface.OnClickListener() {
|
||||
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;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
|
|
|
@ -4,6 +4,6 @@
|
|||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<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"/>
|
||||
</vector>
|
||||
|
|
|
@ -18,17 +18,17 @@
|
|||
<item android:id="@android:id/background">
|
||||
<bitmap
|
||||
android:src="@drawable/ic_star_black_48dp"
|
||||
android:tint="@color/middlegrey" />
|
||||
android:tint="?attr/rankingStarNotSelected" />
|
||||
</item>
|
||||
<item android:id="@android:id/secondaryProgress">
|
||||
<bitmap
|
||||
android:src="@drawable/ic_star_half_black_48dp"
|
||||
android:tint="@color/middlegrey" />
|
||||
android:tint="?attr/rankingStarNotSelected" />
|
||||
</item>
|
||||
<item android:id="@android:id/progress">
|
||||
<bitmap
|
||||
android:src="@drawable/ic_star_black_48dp"
|
||||
android:tint="@color/colorAccent" />
|
||||
android:tint="?attr/colorAccent" />
|
||||
</item>
|
||||
</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:viewportHeight="24.0">
|
||||
<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"/>
|
||||
</vector>
|
|
@ -4,6 +4,6 @@
|
|||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<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"/>
|
||||
</vector>
|
|
@ -5,32 +5,32 @@
|
|||
android:viewportHeight="512">
|
||||
<path
|
||||
android:pathData="M174.65,41.63h13.43v429.87h-13.43z"
|
||||
android:fillColor="#fff"/>
|
||||
android:fillColor="?attr/lightestBackGround"/>
|
||||
<path
|
||||
android:pathData="M322.42,41.63h13.43v429.87h-13.43z"
|
||||
android:fillColor="#fff"/>
|
||||
android:fillColor="?attr/lightestBackGround"/>
|
||||
<path
|
||||
android:pathData="M40.31,337.17l0,-13.43l429.87,-0l0,13.43z"
|
||||
android:fillColor="#fff"/>
|
||||
android:fillColor="?attr/lightestBackGround"/>
|
||||
<path
|
||||
android:pathData="M40.31,189.4l0,-13.43l429.87,-0l0,13.43z"
|
||||
android:fillColor="#fff"/>
|
||||
android:fillColor="?attr/lightestBackGround"/>
|
||||
<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"/>
|
||||
android:fillColor="?attr/lightestBackGround"/>
|
||||
<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"/>
|
||||
android:fillColor="?attr/lightestBackGround"/>
|
||||
<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"/>
|
||||
android:fillColor="?attr/lightestBackGround"/>
|
||||
<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"/>
|
||||
android:fillColor="?attr/lightestBackGround"/>
|
||||
<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"/>
|
||||
android:fillColor="?attr/lightestBackGround"/>
|
||||
<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"/>
|
||||
android:fillColor="?attr/lightestBackGround"/>
|
||||
</vector>
|
||||
|
|
|
@ -2,16 +2,16 @@
|
|||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="512dp"
|
||||
android:height="512dp"
|
||||
android:viewportWidth="512"
|
||||
android:viewportHeight="512">
|
||||
android:viewportWidth="600"
|
||||
android:viewportHeight="600">
|
||||
<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">
|
||||
<gradient
|
||||
android:startY="43.94"
|
||||
android:startX="119.85"
|
||||
android:endY="551.52"
|
||||
android:endX="412.9"
|
||||
android:startY="30.4022"
|
||||
android:startX="143.3293"
|
||||
android:endY="680.6151"
|
||||
android:endX="518.728"
|
||||
android:type="linear">
|
||||
<item android:offset="0" android:color="#FF004492"/>
|
||||
<item android:offset="0.22" android:color="#F9004593"/>
|
||||
|
@ -25,33 +25,33 @@
|
|||
</aapt:attr>
|
||||
</path>
|
||||
<path
|
||||
android:pathData="M174.65,41.63h13.43v429.87h-13.43z"
|
||||
android:fillColor="#fff"/>
|
||||
android:pathData="M174.6,41.6h13.4v429.9h-13.4z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
<path
|
||||
android:pathData="M322.42,41.63h13.43v429.87h-13.43z"
|
||||
android:fillColor="#fff"/>
|
||||
android:pathData="M322.4,41.6h13.4v429.9h-13.4z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
<path
|
||||
android:pathData="M40.31,337.17l0,-13.43l429.87,-0l0,13.43z"
|
||||
android:fillColor="#fff"/>
|
||||
android:pathData="M40.3,323.7h429.9v13.4h-429.9z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
<path
|
||||
android:pathData="M40.31,189.4l0,-13.43l429.87,-0l0,13.43z"
|
||||
android:fillColor="#fff"/>
|
||||
android:pathData="M40.3,176h429.9v13.4h-429.9z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
<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"/>
|
||||
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="#FFFFFF"/>
|
||||
<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"/>
|
||||
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="#FFFFFF"/>
|
||||
<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"/>
|
||||
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="#FFFFFF"/>
|
||||
<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"/>
|
||||
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="#FFFFFF"/>
|
||||
<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"/>
|
||||
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="#FFFFFF"/>
|
||||
<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"/>
|
||||
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="#FFFFFF"/>
|
||||
</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:viewportHeight="24.0">
|
||||
<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"/>
|
||||
</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:viewportHeight="24.0">
|
||||
<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"/>
|
||||
</vector>
|
|
@ -4,6 +4,6 @@
|
|||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:fillColor="?attr/standardVectorGraphic"
|
||||
android:pathData="M10,20v-6h4v6h5v-8h3L12,3 2,12h3v8z"/>
|
||||
</vector>
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue