Merge branch 'Sudoku-v3.0' of https://github.com/SecUSo/privacy-friendly-sudoku into Sudoku-v3.0

This commit is contained in:
ErikWaegerle 2020-07-22 02:22:19 +02:00
commit 13bd2deee1
10 changed files with 272 additions and 249 deletions

View file

@ -64,6 +64,7 @@ public class GameController implements IModelChangedListener, Parcelable {
private GameType gameType; private GameType gameType;
private GameDifficulty difficulty; private GameDifficulty difficulty;
private CellConflictList errorList = new CellConflictList(); private CellConflictList errorList = new CellConflictList();
private boolean gameIsCustom;
// Undo Redo // Undo Redo
private UndoRedoManager undoRedoManager; private UndoRedoManager undoRedoManager;
@ -91,6 +92,7 @@ public class GameController implements IModelChangedListener, Parcelable {
public GameController(GameType type, SharedPreferences pref, Context context) { public GameController(GameType type, SharedPreferences pref, Context context) {
this.context = context; this.context = context;
this.gameBoard = new GameBoard(type); this.gameBoard = new GameBoard(type);
this.gameIsCustom = false;
setGameType(type); setGameType(type);
setSettings(pref); setSettings(pref);
@ -102,6 +104,8 @@ public class GameController implements IModelChangedListener, Parcelable {
return gameID; return gameID;
} }
public boolean gameIsCustom() { return gameIsCustom; }
public void loadNewLevel(GameType type, GameDifficulty difficulty) { public void loadNewLevel(GameType type, GameDifficulty difficulty) {
NewLevelManager newLevelManager = NewLevelManager.getInstance(context, settings); NewLevelManager newLevelManager = NewLevelManager.getInstance(context, settings);
@ -141,6 +145,7 @@ public class GameController implements IModelChangedListener, Parcelable {
this.difficulty = gic.getDifficulty(); this.difficulty = gic.getDifficulty();
this.time = gic.getTimePlayed(); this.time = gic.getTimePlayed();
this.usedHints = gic.getHintsUsed(); this.usedHints = gic.getHintsUsed();
this.gameIsCustom = gic.isCustom();
setGameType(gic.getGameType()); setGameType(gic.getGameType());
this.gameBoard = new GameBoard(gic.getGameType()); this.gameBoard = new GameBoard(gic.getGameType());

View file

@ -89,6 +89,10 @@ public class GameStateManager {
gic.parseNotes(values[i++]); gic.parseNotes(values[i++]);
gic.parseHintsUsed(values[i++]); gic.parseHintsUsed(values[i++]);
if (values.length > i) {
gic.setCustom(true);
}
if (gic.getID() == GameController.DAILY_SUDOKU_ID) { if (gic.getID() == GameController.DAILY_SUDOKU_ID) {
includesDaily = true; includesDaily = true;
} }

View file

@ -40,7 +40,8 @@ public class NewLevelManager {
public static int PRE_SAVES_MIN = 3; public static int PRE_SAVES_MIN = 3;
public static int PRE_SAVES_MAX = 10; public static int PRE_SAVES_MAX = 10;
private final double CHALLENGE_GENERATION_PROBABILITY = 0.9; private final double CHALLENGE_GENERATION_PROBABILITY = 0.25;
private final int CHALLENGE_ITERATIONS = 4;
public static NewLevelManager getInstance(Context context, SharedPreferences settings) { public static NewLevelManager getInstance(Context context, SharedPreferences settings) {
@ -84,16 +85,8 @@ public class NewLevelManager {
public int[] loadDailySudoku() { public int[] loadDailySudoku() {
DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy"); DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
String toHash = "Sudoku/.PrivacyFriendly/." + dateFormat.format(new Date()); String toHash = "Sudoku/.PrivacyFriendly/." + dateFormat.format(new Date());
boolean generateChallenge = new Random(toHash.hashCode()).nextDouble() >= CHALLENGE_GENERATION_PROBABILITY;
QQWingController controller = new QQWingController(); QQWingController controller = new QQWingController();
int[] result; return controller.generateFromSeed(toHash.hashCode(), CHALLENGE_GENERATION_PROBABILITY, CHALLENGE_ITERATIONS);
if (generateChallenge) {
result = controller.generateFromSeed(toHash.hashCode(), GameDifficulty.Challenge);
} else {
result = controller.generateFromSeed(toHash.hashCode(), GameDifficulty.Unspecified);
}
return result;
} }
public int[] loadLevel(GameType type, GameDifficulty diff) { public int[] loadLevel(GameType type, GameDifficulty diff) {

View file

@ -4,6 +4,7 @@ import android.os.Parcelable;
import android.util.Log; import android.util.Log;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.Random;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.Date; import java.util.Date;
@ -53,20 +54,27 @@ public class QQWingController {
return generated; return generated;
} }
public int[] generateFromSeed(int seed, GameDifficulty difficulty) { public int[] generateFromSeed(int seed) {
return generateFromSeed(seed, 1, 1);
}
public int[] generateFromSeed(int seed, double challengePermission, int challengeIterations) {
generated.clear(); generated.clear();
QQWing generator = new QQWing(GameType.Default_9x9, GameDifficulty.Unspecified); QQWing generator = new QQWing(GameType.Default_9x9, GameDifficulty.Unspecified);
boolean havePuzzle = false; boolean continueSearch = true;
Random random = new Random(seed);
int seedFactor = 2;
while(!havePuzzle) { while(continueSearch && challengeIterations > 0) {
seed++; seed *= seedFactor;
generator.setRandom(seed); generator.setRandom(seed);
generator.setRecordHistory(true); generator.setRecordHistory(true);
generator.generatePuzzle(); generator.generatePuzzle();
if (difficulty == GameDifficulty.Unspecified && generator.getDifficulty() != GameDifficulty.Challenge if (generator.getDifficulty() != GameDifficulty.Challenge || random.nextDouble() < challengePermission) {
|| difficulty == generator.getDifficulty()) { continueSearch = false;
havePuzzle = true; } else {
challengeIterations--;
} }
} }
@ -223,6 +231,10 @@ public class QQWingController {
} }
} }
public boolean isImpossible() {
return solveImpossible;
}
private static class QQWingOptions { private static class QQWingOptions {
// defaults for options // defaults for options
boolean needNow = false; boolean needNow = false;

View file

@ -204,12 +204,12 @@ public class SaveLoadStatistics implements ITimerListener, IHintListener {
@Override @Override
public void onTick(int time) { public void onTick(int time) {
incTime(gc.getDifficulty(), gc.getGameType()); if (!gc.gameIsCustom()) incTime(gc.getDifficulty(), gc.getGameType());
//gc.getUsedHints(); //gc.getUsedHints();
} }
@Override @Override
public void onHintUsed() { public void onHintUsed() {
incHints(gc.getDifficulty(),gc.getGameType()); if (!gc.gameIsCustom()) incHints(gc.getDifficulty(),gc.getGameType());
} }
} }

View file

@ -25,6 +25,7 @@ public class GameInfoContainer {
int[] setValues; int[] setValues;
boolean[][] setNotes; boolean[][] setNotes;
int hintsUsed; int hintsUsed;
boolean isCustom;
public GameInfoContainer() {} public GameInfoContainer() {}
public GameInfoContainer(int ID, GameDifficulty difficulty, GameType gameType, int[] fixedValues, int[] setValues, boolean[][] setNotes) { public GameInfoContainer(int ID, GameDifficulty difficulty, GameType gameType, int[] fixedValues, int[] setValues, boolean[][] setNotes) {
@ -40,12 +41,17 @@ public class GameInfoContainer {
this.setValues = setValues; this.setValues = setValues;
this.setNotes = setNotes; this.setNotes = setNotes;
this.hintsUsed = hintsUsed; this.hintsUsed = hintsUsed;
isCustom = false;
} }
public void setID(int ID) { public void setID(int ID) {
this.ID = ID; this.ID = ID;
} }
public void setCustom (boolean isCustom) { this.isCustom = isCustom; }
public boolean isCustom () { return isCustom; }
public void parseGameType(String s) { public void parseGameType(String s) {
gameType = Enum.valueOf(GameType.class, s); gameType = Enum.valueOf(GameType.class, s);
if(gameType == null) { if(gameType == null) {
@ -179,6 +185,7 @@ public class GameInfoContainer {
public static String getGameInfo(GameController controller) { public static String getGameInfo(GameController controller) {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
Date today = new Date(); Date today = new Date();
boolean custom = controller.gameIsCustom();
sb.append(controller.getGameType().name()); sb.append(controller.getGameType().name());
sb.append("/"); sb.append("/");
@ -196,6 +203,11 @@ public class GameInfoContainer {
sb.append("/"); sb.append("/");
sb.append(controller.getUsedHints()); sb.append(controller.getUsedHints());
if (custom) {
sb.append("/");
sb.append(custom);
}
String result = sb.toString(); String result = sb.toString();
Log.d("getGameInfo", result); Log.d("getGameInfo", result);

View file

@ -131,6 +131,7 @@ public class CreateSudokuActivity extends BaseActivity implements IFinalizeDialo
Toast.makeText(CreateSudokuActivity.this, R.string.finished_verifying_custom_sudoku_toast, Toast.LENGTH_LONG).show(); Toast.makeText(CreateSudokuActivity.this, R.string.finished_verifying_custom_sudoku_toast, Toast.LENGTH_LONG).show();
final Intent intent = new Intent(this, GameActivity.class); final Intent intent = new Intent(this, GameActivity.class);
intent.setData(Uri.parse(GameActivity.URL_SCHEME_WITHOUT_HOST + "://" + boardContent)); intent.setData(Uri.parse(GameActivity.URL_SCHEME_WITHOUT_HOST + "://" + boardContent));
intent.putExtra("isCustom", true);
startActivity(intent); startActivity(intent);
finish(); finish();
} else { } else {

View file

@ -140,6 +140,7 @@ public class GameActivity extends BaseActivity implements NavigationView.OnNavig
QQWing difficultyCheck; QQWing difficultyCheck;
GameInfoContainer container = new GameInfoContainer(0, GameDifficulty.Unspecified, GameInfoContainer container = new GameInfoContainer(0, GameDifficulty.Unspecified,
GameType.Unspecified, new int [boardSize], new int [boardSize], new boolean [boardSize][sectionSize]); GameType.Unspecified, new int [boardSize], new int [boardSize], new boolean [boardSize][sectionSize]);
container.setCustom(extras.getBoolean("isCustom", false));
try { try {
container.parseGameType("Default_" + sectionSize + "x" + sectionSize); container.parseGameType("Default_" + sectionSize + "x" + sectionSize);
@ -149,8 +150,9 @@ public class GameActivity extends BaseActivity implements NavigationView.OnNavig
difficultyCheck.setPuzzle(container.getFixedValues()); difficultyCheck.setPuzzle(container.getFixedValues());
difficultyCheck.solve(); difficultyCheck.solve();
startGame = difficultyCheck.hasUniqueSolution();
container.parseDifficulty(difficultyCheck.getDifficulty().toString()); container.parseDifficulty(difficultyCheck.getDifficulty().toString());
startGame = difficultyCheck.hasUniqueSolution();
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
startGame = false; startGame = false;
@ -487,13 +489,20 @@ public class GameActivity extends BaseActivity implements NavigationView.OnNavig
editor.apply(); editor.apply();
} }
//Don't save statistics if game is custom
boolean isNewBestTime;
if (!gameController.gameIsCustom()) {
//Show time hints new plus old best time //Show time hints new plus old best time
statistics.saveGameStats(); statistics.saveGameStats();
isNewBestTime = gameController.getUsedHints() == 0
boolean isNewBestTime = gameController.getUsedHints() == 0
&& statistics.loadStats(gameController.getGameType(),gameController.getDifficulty()).getMinTime() >= gameController.getTime(); && statistics.loadStats(gameController.getGameType(),gameController.getDifficulty()).getMinTime() >= gameController.getTime();
} else {
isNewBestTime = false;
}
dialog = new WinDialog(this, R.style.WinDialog , timeToString(gameController.getTime()), String.valueOf(gameController.getUsedHints()), isNewBestTime); dialog = new WinDialog(this, R.style.WinDialog , timeToString(gameController.getTime()), String.valueOf(gameController.getUsedHints()), isNewBestTime);
dialog.getWindow().setContentView(R.layout.win_screen_layout); dialog.getWindow().setContentView(R.layout.win_screen_layout);

View file

@ -388,6 +388,7 @@ public class MainActivity extends BaseActivity implements NavigationView.OnNavig
case R.id.nav_dailySudoku_main: case R.id.nav_dailySudoku_main:
intent = new Intent(this, DailySudokuActivity.class); intent = new Intent(this, DailySudokuActivity.class);
startActivity(intent); startActivity(intent);
overridePendingTransition(0, 0);
break; break;
default: default:
@ -409,7 +410,7 @@ public class MainActivity extends BaseActivity implements NavigationView.OnNavig
boolean solvable = CreateSudokuActivity.verify(MainActivity.this, GameType.Default_9x9, input); boolean solvable = CreateSudokuActivity.verify(MainActivity.this, GameType.Default_9x9, input);
if (solvable) { if (solvable) {
Toast.makeText(MainActivity.this, R.string.finished_verifying_custom_sudoku_toast, Toast.LENGTH_LONG).show(); Toast.makeText(MainActivity.this, R.string.finished_verifying_custom_sudoku_toast, Toast.LENGTH_LONG).show();
final Intent intent = new Intent(this, MainActivity.class); final Intent intent = new Intent(this, GameActivity.class);
intent.setData(Uri.parse(GameActivity.URL_SCHEME_WITHOUT_HOST + "://" + input)); intent.setData(Uri.parse(GameActivity.URL_SCHEME_WITHOUT_HOST + "://" + input));
startActivity(intent); startActivity(intent);
finish(); finish();

View file

@ -1,29 +1,197 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout android:id="@+id/drawer_layout_main"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent"
android:fitsSystemWindows="true"
tools:openDrawer="start"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/linearLayout5" xmlns:app="http://schemas.android.com/apk/res-auto">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/linearLayout10"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:fitsSystemWindows="true" android:fitsSystemWindows="true"
app:statusBarBackground="?attr/colorPrimary"> app:statusBarBackground="?attr/colorPrimary">
<LinearLayout <View
android:id="@+id/linearLayout6" android:id="@+id/view3"
android:layout_width="0dp"
android:layout_height="2dp"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:layout_gravity="center_vertical"
android:background="?attr/colorPrimary"
android:foregroundGravity="center_vertical"
android:layout_marginStart="16dp"
android:layout_marginLeft="16dp"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/appbar" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/linearLayout11"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="16dp"
android:layout_marginBottom="8dp"
android:weightSum="5"
app:layout_constraintBottom_toTopOf="@+id/view3"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/appbar">
<ImageView
android:id="@+id/statistic_image"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginLeft="16dp"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
android:adjustViewBounds="true"
android:src="@drawable/icon_default_9x9"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/view"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.25" />
<RatingBar
android:id="@+id/first_diff_bar"
style="?android:attr/ratingBarStyleSmall"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintBottom_toTopOf="@+id/main_content" android:layout_marginEnd="8dp"
app:layout_constraintStart_toStartOf="parent" android:layout_marginRight="8dp"
app:layout_constraintTop_toTopOf="parent"> android:numStars="4"
android:scaleX="1.5"
android:scaleY="1.5"
app:layout_constraintBottom_toBottomOf="@+id/view"
app:layout_constraintEnd_toEndOf="@+id/statistic_image"
app:layout_constraintStart_toStartOf="@+id/statistic_image"
app:layout_constraintTop_toBottomOf="@+id/statistic_image"
app:layout_constraintVertical_bias="0.75" />
<TextView
android:id="@+id/first_diff_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:gravity="center|center_horizontal"
android:text="diffi"
android:textSize="22sp"
app:layout_constraintBottom_toTopOf="@+id/first_diff_bar"
app:layout_constraintEnd_toEndOf="@+id/first_diff_bar"
app:layout_constraintStart_toStartOf="@+id/first_diff_bar"
app:layout_constraintTop_toBottomOf="@+id/statistic_image"
app:layout_constraintVertical_bias="1.0" />
<View
android:id="@+id/view"
android:layout_width="1dp"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
android:foregroundGravity="center_vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/textView4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/daily_number_of_hints"
app:layout_constraintBottom_toBottomOf="@+id/statistic_image"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.25"
app:layout_constraintStart_toStartOf="@id/view"
app:layout_constraintTop_toTopOf="@+id/statistic_image"
app:layout_constraintVertical_bias="0.0" />
<TextView
android:id="@+id/numb_of_hints"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="0"
app:layout_constraintBottom_toBottomOf="@+id/statistic_image"
app:layout_constraintEnd_toEndOf="@+id/textView4"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="@+id/textView4"
app:layout_constraintTop_toBottomOf="@+id/textView4"
app:layout_constraintVertical_bias="0.0" />
<TextView
android:id="@+id/textView5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/number_of_completed_games"
app:layout_constraintBottom_toTopOf="@+id/textView6"
app:layout_constraintEnd_toEndOf="@+id/numb_of_hints"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="@+id/numb_of_hints"
app:layout_constraintTop_toBottomOf="@+id/textView4" />
<TextView
android:id="@+id/numb_of_total_games"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="0"
app:layout_constraintBottom_toBottomOf="@+id/statistic_image"
app:layout_constraintEnd_toEndOf="@+id/textView5"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="@+id/textView5"
app:layout_constraintTop_toBottomOf="@+id/textView5"
app:layout_constraintVertical_bias="0.0" />
<TextView
android:id="@+id/textView6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/total_of_time"
app:layout_constraintBottom_toTopOf="@+id/numb_of_total_time"
app:layout_constraintEnd_toEndOf="@+id/numb_of_total_games"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="@+id/numb_of_total_games"
app:layout_constraintTop_toTopOf="@+id/statistic_image"
app:layout_constraintVertical_bias="1.0" />
<TextView
android:id="@+id/numb_of_total_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="0"
app:layout_constraintBottom_toBottomOf="@+id/statistic_image"
app:layout_constraintEnd_toEndOf="@+id/textView6"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="@+id/textView6"
app:layout_constraintTop_toBottomOf="@+id/numb_of_total_games"
app:layout_constraintVertical_bias="1.0" />
</androidx.constraintlayout.widget.ConstraintLayout>
<com.google.android.material.appbar.AppBarLayout <com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar" android:id="@+id/appbar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:clipChildren="false" android:clipChildren="false"
android:theme="@style/AppTheme.AppBarOverlay"> android:theme="@style/AppTheme.AppBarOverlay"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0">
<androidx.appcompat.widget.Toolbar <androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar" android:id="@+id/toolbar"
@ -38,212 +206,28 @@
</com.google.android.material.appbar.AppBarLayout> </com.google.android.material.appbar.AppBarLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
android:weightSum="10"
tools:context="org.secuso.privacyfriendlysudoku.ui.StatsActivity$PlaceholderFragment">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="10"
android:weightSum="5">
<LinearLayout
android:layout_width="0dp"
android:layout_height="fill_parent"
android:layout_weight="2.0"
android:orientation="vertical">
<ImageView
android:id="@+id/statistic_image"
android:layout_width="match_parent"
android:layout_height="fill_parent"
android:layout_gravity="center_horizontal"
android:layout_weight="1.0"
android:adjustViewBounds="true"
android:src="@drawable/icon_default_9x9" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="2.5"
android:gravity="center_horizontal">
<RatingBar
android:id="@+id/first_diff_bar"
style="?android:attr/ratingBarStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/first_diff_text"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_gravity="center_horizontal"
android:layout_marginLeft="10dp"
android:layout_marginTop="5dp"
android:layout_marginRight="10dp"
android:layout_marginBottom="10dp"
android:numStars="4"
android:scaleX="1.5"
android:scaleY="1.5" />
<TextView
android:id="@+id/first_diff_text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:gravity="center|center_horizontal"
android:text="diffi"
android:textSize="22sp" />
</RelativeLayout>
</LinearLayout>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:minHeight="5dp">
<View
android:layout_width="1dp"
android:layout_height="match_parent"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_gravity="center_vertical"
android:layout_marginTop="0dp"
android:layout_marginBottom="50dp"
android:background="?attr/colorPrimary"
android:foregroundGravity="center_vertical" />
</RelativeLayout>
<LinearLayout
android:layout_width="2dp"
android:layout_height="match_parent"
android:layout_weight="2"
android:orientation="vertical"
android:paddingTop="0dp"
android:weightSum="6">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="top"
android:layout_marginRight="0dp"
android:layout_marginBottom="10dp"
android:layout_weight="1"
android:orientation="vertical"
android:paddingTop="0dp"
android:weightSum="10">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginBottom="0dp"
android:layout_weight="2"
android:text="@string/daily_number_of_hints" />
<TextView
android:id="@+id/numb_of_hints"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginBottom="0dp"
android:layout_weight="1"
android:text="0" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="2"
android:gravity="center"
android:text="@string/number_of_completed_games" />
<TextView
android:id="@+id/numb_of_total_games"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1"
android:text="0" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="2"
android:text="@string/total_of_time" />
<TextView
android:id="@+id/numb_of_total_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1"
android:text="0" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="300dp"
android:orientation="vertical"
android:paddingTop="@dimen/activity_horizontal_margin"
android:weightSum="6">
</LinearLayout>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1.0">
<View
android:layout_width="wrap_content"
android:layout_height="2dp"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:layout_gravity="center_vertical"
android:background="?attr/colorPrimary"
android:foregroundGravity="center_vertical" />
</LinearLayout>
<ListView <ListView
android:id="@+id/sudoku_list" android:id="@+id/sudoku_list"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="270dp" android:layout_height="0dp"
android:layout_weight="6" /> android:layout_weight="6"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
</LinearLayout> app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/view3" />
</LinearLayout>
<com.google.android.material.floatingactionbutton.FloatingActionButton <com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/floatingActionButton" android:id="@+id/floatingActionButton"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginEnd="20dp"
android:layout_marginRight="25dp"
android:layout_marginBottom="290dp"
android:clickable="true" android:clickable="true"
android:onClick="onClick" android:onClick="onClick"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toTopOf="@+id/view3"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="@+id/view3"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/appbar"
app:layout_constraintVertical_bias="0.95"
app:srcCompat="@android:drawable/ic_media_play" /> app:srcCompat="@android:drawable/ic_media_play" />
@ -253,10 +237,12 @@
android:layout_height="0dp" android:layout_height="0dp"
app:layout_behavior="@string/appbar_scrolling_view_behavior" app:layout_behavior="@string/appbar_scrolling_view_behavior"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="@+id/linearLayout6" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/linearLayout6" > app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="parent">
</androidx.viewpager.widget.ViewPager> </androidx.viewpager.widget.ViewPager>
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
</androidx.drawerlayout.widget.DrawerLayout>