Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • android/org.benoitharrault.sudoku
1 result
Show changes
Commits on Source (6)
Showing
with 462 additions and 165 deletions
image: ghcr.io/cirruslabs/flutter:latest image: ghcr.io/cirruslabs/flutter:latest
stages: stages:
- update
- build-debug - build-debug
- build-release - build-release
- release - release
- deploy - deploy
update:
stage: update
except:
- tags
script:
- flutter packages get
- flutter packages upgrade
interruptible: true
android:build-debug: android:build-debug:
stage: build-debug stage: build-debug
except: except:
- tags - tags
- master
script: script:
# Flutter local configuration # Flutter local configuration
- echo flutter.sdk=$FLUTTER_PATH > android/local.properties - echo flutter.sdk=$FLUTTER_PATH > android/local.properties
...@@ -49,8 +40,6 @@ android:build-release: ...@@ -49,8 +40,6 @@ android:build-release:
- master - master
except: except:
- tags - tags
dependencies:
- android:build-debug
script: script:
# Flutter local configuration # Flutter local configuration
- echo flutter.sdk=$FLUTTER_PATH > android/local.properties - echo flutter.sdk=$FLUTTER_PATH > android/local.properties
...@@ -121,4 +110,4 @@ android:deploy: ...@@ -121,4 +110,4 @@ android:deploy:
dependencies: dependencies:
- application:release - application:release
script: script:
- curl "${REPOSITORY_UPDATE_WEBHOOK}?token=${REPOSITORY_TOKEN}" - curl "${REPOSITORY_UPDATE_WEBHOOK}?token=${REPOSITORY_TOKEN}" --fail
org.gradle.jvmargs=-Xmx1536M org.gradle.jvmargs=-Xmx1536M
android.useAndroidX=true android.useAndroidX=true
android.enableJetifier=true android.enableJetifier=true
app.versionName=0.1.15 app.versionName=0.1.18
app.versionCode=64 app.versionCode=67
Improve CI/CD, remove "update" step, disable "build-debug" in master branch.
Improve game architecture.
Add a timer after use of "help" button.
Amélioration de la CI/CD. Suppression de "update" et désactivation de "build-debug" sur master.
Amélioration de la conception du jeu.
Ajout d'une temporisation pour réactiver le bouton "aide" après usage.
...@@ -5,27 +5,30 @@ import 'package:sudoku/utils/board_animate.dart'; ...@@ -5,27 +5,30 @@ import 'package:sudoku/utils/board_animate.dart';
import 'package:sudoku/utils/board_utils.dart'; import 'package:sudoku/utils/board_utils.dart';
class Cell { class Cell {
int value; const Cell({
bool isFixed; required this.row,
int conflictsCount = 0; required this.col,
required this.value,
required this.isFixed,
});
bool isAnimated = false; final int row;
final int col;
final int value;
final bool isFixed;
Cell( static const Cell none = Cell(row: 0, col: 0, value: 0, isFixed: true);
this.value,
this.isFixed,
);
/* /*
* Build widget for board cell, with interactions * Build widget for board cell, with interactions
*/ */
Container widget(Data myProvider, int row, int col) { Widget widget(Data myProvider) {
final String imageAsset = getImageAssetName(myProvider); final String imageAsset = getImageAssetName(myProvider);
return Container( return Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: getBackgroundColor(myProvider), color: getBackgroundColor(myProvider),
border: getCellBorders(myProvider, row, col), border: getCellBorders(myProvider),
), ),
child: GestureDetector( child: GestureDetector(
child: AnimatedSwitcher( child: AnimatedSwitcher(
...@@ -40,7 +43,7 @@ class Cell { ...@@ -40,7 +43,7 @@ class Cell {
), ),
), ),
onTap: () { onTap: () {
if (col != myProvider.currentCellCol || row != myProvider.currentCellRow) { if (col != myProvider.selectedCellCol || row != myProvider.selectedCellRow) {
myProvider.selectCell(col, row); myProvider.selectCell(col, row);
} else { } else {
myProvider.selectCell(null, null); myProvider.selectCell(null, null);
...@@ -62,14 +65,14 @@ class Cell { ...@@ -62,14 +65,14 @@ class Cell {
Color backgroundColor = Colors.grey.shade200; Color backgroundColor = Colors.grey.shade200;
if (myProvider.showConflicts && if (myProvider.showConflicts &&
myProvider.currentCellCol != null && myProvider.selectedCellCol != null &&
myProvider.currentCellRow != null) { myProvider.selectedCellRow != null) {
final List<List<Cell>> cells = myProvider.cells; final Board cells = myProvider.board;
final int blockSizeHorizontal = myProvider.blockSizeHorizontal; final int blockSizeHorizontal = myProvider.blockSizeHorizontal;
final int blockSizeVertical = myProvider.blockSizeVertical; final int blockSizeVertical = myProvider.blockSizeVertical;
if (!BoardUtils.isValueAllowed(cells, blockSizeHorizontal, blockSizeVertical, if (!BoardUtils.isValueAllowed(cells, blockSizeHorizontal, blockSizeVertical,
myProvider.currentCellCol, myProvider.currentCellRow, value)) { myProvider.selectedCellCol, myProvider.selectedCellRow, value)) {
backgroundColor = Colors.pink.shade100; backgroundColor = Colors.pink.shade100;
} }
} }
...@@ -85,9 +88,9 @@ class Cell { ...@@ -85,9 +88,9 @@ class Cell {
child: GestureDetector( child: GestureDetector(
child: Image(image: AssetImage(imageAsset), fit: BoxFit.fill), child: Image(image: AssetImage(imageAsset), fit: BoxFit.fill),
onTap: () { onTap: () {
if (myProvider.currentCellCol != null && myProvider.currentCellRow != null) { if (myProvider.selectedCellCol != null && myProvider.selectedCellRow != null) {
myProvider.updateCellValue( myProvider.updateCellValue(
myProvider.currentCellCol, myProvider.currentCellRow, value); myProvider.selectedCellCol, myProvider.selectedCellRow, value);
} }
myProvider.selectCell(null, null); myProvider.selectCell(null, null);
if (BoardUtils.checkBoardIsSolved(myProvider)) { if (BoardUtils.checkBoardIsSolved(myProvider)) {
...@@ -126,6 +129,8 @@ class Cell { ...@@ -126,6 +129,8 @@ class Cell {
backgroundColor = fixedCellColor; backgroundColor = fixedCellColor;
} }
final int conflictsCount = myProvider.boardConflicts[row][col];
if (myProvider.showConflicts && (conflictsCount != 0)) { if (myProvider.showConflicts && (conflictsCount != 0)) {
if (isFixed) { if (isFixed) {
backgroundColor = fixedCellColorConflict; backgroundColor = fixedCellColorConflict;
...@@ -134,7 +139,7 @@ class Cell { ...@@ -134,7 +139,7 @@ class Cell {
} }
} }
if (myProvider.showConflicts && (value == myProvider.currentCellValue)) { if (myProvider.showConflicts && (value == myProvider.selectedCellValue)) {
if (isFixed) { if (isFixed) {
backgroundColor = fixedSelectedValueColor; backgroundColor = fixedSelectedValueColor;
} else { } else {
...@@ -142,6 +147,8 @@ class Cell { ...@@ -142,6 +147,8 @@ class Cell {
} }
} }
final bool isAnimated = myProvider.boardAnimated[row][col];
if (isAnimated) { if (isAnimated) {
if (isFixed) { if (isFixed) {
backgroundColor = fixedAnimated; backgroundColor = fixedAnimated;
...@@ -154,7 +161,9 @@ class Cell { ...@@ -154,7 +161,9 @@ class Cell {
} }
// Compute cell borders, from board size and cell state // Compute cell borders, from board size and cell state
Border getCellBorders(Data myProvider, int row, int col) { Border getCellBorders(Data myProvider) {
// final int row = , int col;
final int blockSizeHorizontal = myProvider.blockSizeHorizontal; final int blockSizeHorizontal = myProvider.blockSizeHorizontal;
final int blockSizeVertical = myProvider.blockSizeVertical; final int blockSizeVertical = myProvider.blockSizeVertical;
...@@ -184,7 +193,7 @@ class Cell { ...@@ -184,7 +193,7 @@ class Cell {
); );
// Update cell borders if not currently selected cell // Update cell borders if not currently selected cell
if (col != myProvider.currentCellCol || row != myProvider.currentCellRow) { if (col != myProvider.selectedCellCol || row != myProvider.selectedCellRow) {
borders = Border( borders = Border(
top: BorderSide( top: BorderSide(
width: cellBorderWidth, width: cellBorderWidth,
......
...@@ -4,7 +4,7 @@ import 'package:provider/provider.dart'; ...@@ -4,7 +4,7 @@ import 'package:provider/provider.dart';
import 'package:overlay_support/overlay_support.dart'; import 'package:overlay_support/overlay_support.dart';
import 'package:sudoku/provider/data.dart'; import 'package:sudoku/provider/data.dart';
import 'package:sudoku/screens/home.dart'; import 'package:sudoku/ui/screens/home.dart';
void main() { void main() {
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
...@@ -27,9 +27,6 @@ class MyApp extends StatelessWidget { ...@@ -27,9 +27,6 @@ class MyApp extends StatelessWidget {
visualDensity: VisualDensity.adaptivePlatformDensity, visualDensity: VisualDensity.adaptivePlatformDensity,
), ),
home: const Home(), home: const Home(),
routes: {
Home.id: (context) => const Home(),
},
), ),
); );
}), }),
......
import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
...@@ -6,6 +7,11 @@ import 'package:shared_preferences/shared_preferences.dart'; ...@@ -6,6 +7,11 @@ import 'package:shared_preferences/shared_preferences.dart';
import 'package:sudoku/entities/cell.dart'; import 'package:sudoku/entities/cell.dart';
import 'package:sudoku/utils/tools.dart'; import 'package:sudoku/utils/tools.dart';
typedef Board = List<List<Cell>>;
typedef ConflictsCount = List<List<int>>;
typedef AnimatedBoard = List<List<bool>>;
typedef AnimatedBoardSequence = List<AnimatedBoard>;
class Data extends ChangeNotifier { class Data extends ChangeNotifier {
// Configuration available values // Configuration available values
final List<String> _availableParameters = ['level', 'size', 'skin']; final List<String> _availableParameters = ['level', 'size', 'skin'];
...@@ -39,15 +45,18 @@ class Data extends ChangeNotifier { ...@@ -39,15 +45,18 @@ class Data extends ChangeNotifier {
bool _animationInProgress = false; bool _animationInProgress = false;
int _blockSizeVertical = 0; int _blockSizeVertical = 0;
int _blockSizeHorizontal = 0; int _blockSizeHorizontal = 0;
List<List<Cell>> _cells = []; Board _board = [];
List<List<Cell>> _cellsSolved = []; Board _boardSolved = [];
ConflictsCount _boardConflicts = [];
AnimatedBoard _boardAnimated = [];
List<int> _shuffledCellValues = []; List<int> _shuffledCellValues = [];
int? _currentCellCol; int? _selectedCellCol;
int? _currentCellRow; int? _selectedCellRow;
int? _currentCellValue; int? _selectedCellValue;
bool _showConflicts = false; bool _showConflicts = false;
int _givenTipsCount = 0; int _givenTipsCount = 0;
String _currentState = ''; int _givenTipsCountEnableCountdown = 0;
String _currentSavedState = '';
void updateParameterLevel(String parameterLevel) { void updateParameterLevel(String parameterLevel) {
_parameterLevel = parameterLevel; _parameterLevel = parameterLevel;
...@@ -115,15 +124,15 @@ class Data extends ChangeNotifier { ...@@ -115,15 +124,15 @@ class Data extends ChangeNotifier {
setParameterValue('skin', prefs.getString('skin') ?? _parameterSkinDefault); setParameterValue('skin', prefs.getString('skin') ?? _parameterSkinDefault);
} }
String get currentState => _currentState; String get currentSavedState => _currentSavedState;
String computeCurrentGameState() { String computeCurrentGameState() {
String cellsValues = ''; String cellsValues = '';
const String stringValues = '0123456789ABCDEFG'; const String stringValues = '0123456789ABCDEFG';
for (int rowIndex = 0; rowIndex < _cells.length; rowIndex++) { for (int rowIndex = 0; rowIndex < _board.length; rowIndex++) {
for (int colIndex = 0; colIndex < _cells[rowIndex].length; colIndex++) { for (int colIndex = 0; colIndex < _board[rowIndex].length; colIndex++) {
cellsValues += stringValues[_cells[rowIndex][colIndex].value]; cellsValues += stringValues[_board[rowIndex][colIndex].value];
cellsValues += _cells[rowIndex][colIndex].isFixed ? 'x' : ' '; cellsValues += _board[rowIndex][colIndex].isFixed ? 'x' : ' ';
} }
} }
...@@ -140,35 +149,35 @@ class Data extends ChangeNotifier { ...@@ -140,35 +149,35 @@ class Data extends ChangeNotifier {
void saveCurrentGameState() async { void saveCurrentGameState() async {
if (_gameIsRunning) { if (_gameIsRunning) {
_currentState = computeCurrentGameState(); _currentSavedState = computeCurrentGameState();
final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
prefs.setString('savedState', _currentState); prefs.setString('savedState', _currentSavedState);
} else { } else {
resetCurrentSavedState(); resetCurrentSavedState();
} }
} }
void resetCurrentSavedState() async { void resetCurrentSavedState() async {
_currentState = ''; _currentSavedState = '';
final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
prefs.setString('savedState', _currentState); prefs.setString('savedState', _currentSavedState);
notifyListeners(); notifyListeners();
} }
void loadCurrentSavedState() async { void loadCurrentSavedState() async {
final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
_currentState = prefs.getString('savedState') ?? ''; _currentSavedState = prefs.getString('savedState') ?? '';
} }
bool hasCurrentSavedState() { bool hasCurrentSavedState() {
return (_currentState != ''); return (_currentSavedState != '');
} }
Map<String, dynamic> getCurrentSavedState() { Map<String, dynamic> getCurrentSavedState() {
if (_currentState != '') { if (_currentSavedState != '') {
Map<String, dynamic> savedState = json.decode(_currentState); Map<String, dynamic> savedState = json.decode(_currentSavedState);
if (savedState.isNotEmpty) { if (savedState.isNotEmpty) {
return savedState; return savedState;
} }
...@@ -187,17 +196,20 @@ class Data extends ChangeNotifier { ...@@ -187,17 +196,20 @@ class Data extends ChangeNotifier {
_assetsPreloaded = assetsPreloaded; _assetsPreloaded = assetsPreloaded;
} }
List<List<Cell>> get cells => _cells; Board get board => _board;
void updateCells(List<List<Cell>> cells) { void updateCells(Board board) {
_cells = cells; _board = board;
notifyListeners(); notifyListeners();
} }
List<List<Cell>> get cellsSolved => _cellsSolved; Board get boardSolved => _boardSolved;
void updateCellsSolved(List<List<Cell>> cells) { void updateCellsSolved(Board boardSolved) {
_cellsSolved = cells; _boardSolved = boardSolved;
} }
AnimatedBoard get boardAnimated => _boardAnimated;
ConflictsCount get boardConflicts => _boardConflicts;
void shuffleCellValues() { void shuffleCellValues() {
const int maxCellValue = 16; const int maxCellValue = 16;
final List<int> values = List<int>.generate(maxCellValue, (i) => i + 1); final List<int> values = List<int>.generate(maxCellValue, (i) => i + 1);
...@@ -218,56 +230,100 @@ class Data extends ChangeNotifier { ...@@ -218,56 +230,100 @@ class Data extends ChangeNotifier {
return _shuffledCellValues[originalValue - 1]; return _shuffledCellValues[originalValue - 1];
} }
int? get currentCellCol => _currentCellCol; int? get selectedCellCol => _selectedCellCol;
set updateCurrentCellCol(int? currentCellCol) { set updateCelectedCellCol(int? selectedCellCol) {
_currentCellCol = currentCellCol; _selectedCellCol = selectedCellCol;
notifyListeners(); notifyListeners();
} }
int? get currentCellRow => _currentCellRow; int? get selectedCellRow => _selectedCellRow;
set updateCurrentCellRow(int? currentCellRow) { set updateSelectedCellRow(int? selectedCellRow) {
_currentCellRow = currentCellRow; _selectedCellRow = selectedCellRow;
notifyListeners(); notifyListeners();
} }
int? get currentCellValue => _currentCellValue; int? get selectedCellValue => _selectedCellValue;
set updateCurrentCellValue(int? currentCellValue) { set updateSelectedCellValue(int? selectedCellValue) {
_currentCellValue = currentCellValue; _selectedCellValue = selectedCellValue;
notifyListeners(); notifyListeners();
} }
int get givenTipsCountEnableCountdown => _givenTipsCountEnableCountdown;
int get givenTipsCount => _givenTipsCount; int get givenTipsCount => _givenTipsCount;
increaseGivenTipsCount() { void increaseGivenTipsCount() {
_givenTipsCount = _givenTipsCount + 1; _givenTipsCount = _givenTipsCount + 1;
_givenTipsCountEnableCountdown = 60;
const Duration interval = Duration(milliseconds: 500);
Timer.periodic(
interval,
(Timer timer) {
if (_givenTipsCountEnableCountdown == 0) {
timer.cancel();
notifyListeners();
} else {
_givenTipsCountEnableCountdown--;
notifyListeners();
}
},
);
saveCurrentGameState(); saveCurrentGameState();
notifyListeners(); notifyListeners();
} }
setGivenTipsCount(int value) { void setGivenTipsCount(int value) {
_givenTipsCount = value; _givenTipsCount = value;
_givenTipsCountEnableCountdown = 0;
notifyListeners(); notifyListeners();
} }
resetGivenTipsCount() { bool canGiveTip() {
return (_givenTipsCountEnableCountdown == 0);
}
void resetGivenTipsCount() {
setGivenTipsCount(0); setGivenTipsCount(0);
} }
selectCell(int? col, int? row) { void selectCell(int? col, int? row) {
_currentCellCol = col; _selectedCellCol = col;
_currentCellRow = row; _selectedCellRow = row;
_currentCellValue = null; _selectedCellValue = null;
if (row != null && col != null) { if (row != null && col != null) {
if (_cells[row][col].value != 0) { if (_board[row][col].value != 0) {
_currentCellValue = _cells[row][col].value; _selectedCellValue = _board[row][col].value;
} }
} }
notifyListeners(); notifyListeners();
} }
updateCellValue(int? col, int? row, int value) { void initConflictsBoard() {
ConflictsCount nonConflictedBoard = [];
final int boardSideLength = _blockSizeHorizontal * _blockSizeVertical;
for (int row = 0; row < boardSideLength; row++) {
List<int> line = [];
for (int col = 0; col < boardSideLength; col++) {
line.add(0);
}
nonConflictedBoard.add(line);
}
_boardConflicts = nonConflictedBoard;
}
void updateConflicts(ConflictsCount conflictsCount) {
_boardConflicts = conflictsCount;
}
void updateCellValue(int? col, int? row, int value) {
if ((col != null) && (row != null)) { if ((col != null) && (row != null)) {
if (!_cells[row][col].isFixed) { if (!_board[row][col].isFixed) {
_cells[row][col].value = value; _board[row][col] = Cell(
row: row,
col: col,
value: value,
isFixed: false,
);
saveCurrentGameState(); saveCurrentGameState();
notifyListeners(); notifyListeners();
...@@ -292,11 +348,24 @@ class Data extends ChangeNotifier { ...@@ -292,11 +348,24 @@ class Data extends ChangeNotifier {
notifyListeners(); notifyListeners();
} }
void initAnimatedBackground() {
AnimatedBoard staticBoard = [];
final int boardSideLength = _blockSizeHorizontal * _blockSizeVertical;
for (int row = 0; row < boardSideLength; row++) {
List<bool> line = [];
for (int col = 0; col < boardSideLength; col++) {
line.add(false);
}
staticBoard.add(line);
}
_boardAnimated = staticBoard;
}
void setAnimatedBackground(List animatedCellsPattern) { void setAnimatedBackground(List animatedCellsPattern) {
final int boardSideLength = _blockSizeHorizontal * _blockSizeVertical; final int boardSideLength = _blockSizeHorizontal * _blockSizeVertical;
for (int row = 0; row < boardSideLength; row++) { for (int row = 0; row < boardSideLength; row++) {
for (int col = 0; col < boardSideLength; col++) { for (int col = 0; col < boardSideLength; col++) {
_cells[row][col].isAnimated = animatedCellsPattern[row][col]; _boardAnimated[row][col] = animatedCellsPattern[row][col];
} }
} }
notifyListeners(); notifyListeners();
...@@ -306,7 +375,7 @@ class Data extends ChangeNotifier { ...@@ -306,7 +375,7 @@ class Data extends ChangeNotifier {
final int boardSideLength = _blockSizeHorizontal * _blockSizeVertical; final int boardSideLength = _blockSizeHorizontal * _blockSizeVertical;
for (int row = 0; row < boardSideLength; row++) { for (int row = 0; row < boardSideLength; row++) {
for (int col = 0; col < boardSideLength; col++) { for (int col = 0; col < boardSideLength; col++) {
_cells[row][col].isAnimated = false; _boardAnimated[row][col] = false;
} }
} }
} }
......
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:sudoku/entities/cell.dart';
import 'package:sudoku/provider/data.dart'; import 'package:sudoku/provider/data.dart';
class Board { class BoardLayout extends StatelessWidget {
static Container buildGameBoard(Data myProvider) { const BoardLayout({super.key, required this.myProvider});
final Data myProvider;
@override
Container build(BuildContext context) {
const Color borderColor = Colors.black; const Color borderColor = Colors.black;
final int boardSize = myProvider.blockSizeHorizontal * myProvider.blockSizeVertical;
final Widget gameTileset = Table(
defaultColumnWidth: const IntrinsicColumnWidth(),
children: [
for (int row = 0; row < boardSize; row++)
TableRow(
children: [
for (int col = 0; col < boardSize; col++)
Column(
children: [myProvider.board[row][col].widget(myProvider)],
),
],
),
],
);
return Container( return Container(
margin: const EdgeInsets.all(2), margin: const EdgeInsets.all(2),
...@@ -20,22 +40,9 @@ class Board { ...@@ -20,22 +40,9 @@ class Board {
), ),
child: Column( child: Column(
children: [ children: [
buildGameTileset(myProvider), gameTileset,
], ],
), ),
); );
} }
static Widget buildGameTileset(Data myProvider) {
final int boardSize = myProvider.blockSizeHorizontal * myProvider.blockSizeVertical;
final List<List<Cell>> cells = myProvider.cells;
return Table(defaultColumnWidth: const IntrinsicColumnWidth(), children: [
for (int row = 0; row < boardSize; row++)
TableRow(children: [
for (int col = 0; col < boardSize; col++)
Column(children: [cells[row][col].widget(myProvider, row, col)]),
]),
]);
}
} }
import 'package:flutter/material.dart';
import 'package:sudoku/ui/layout/board.dart';
import 'package:sudoku/ui/widgets/message_game_end.dart';
import 'package:sudoku/ui/widgets/bar_select_cell_value.dart';
import 'package:sudoku/provider/data.dart';
import 'package:sudoku/utils/board_utils.dart';
class Game extends StatelessWidget {
const Game({super.key, required this.myProvider});
final Data myProvider;
@override
Widget build(BuildContext context) {
final bool gameIsFinished = BoardUtils.checkBoardIsSolved(myProvider);
return Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
BoardLayout(myProvider: myProvider),
const SizedBox(height: 2),
gameIsFinished
? EndGameMessage(myProvider: myProvider)
: SelectCellValueBar(myProvider: myProvider),
],
);
}
}
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:sudoku/provider/data.dart'; import 'package:sudoku/provider/data.dart';
import 'package:sudoku/utils/game_utils.dart'; import 'package:sudoku/ui/widgets/button_game_resume.dart';
import 'package:sudoku/ui/widgets/button_game_start_new.dart';
class Parameters extends StatelessWidget {
const Parameters({super.key, required this.myProvider});
final Data myProvider;
class Parameters {
static const double separatorHeight = 2.0; static const double separatorHeight = 2.0;
static const double blockMargin = 3.0; static const double blockMargin = 3.0;
static const double blockPadding = 2.0; static const double blockPadding = 2.0;
...@@ -15,7 +20,8 @@ class Parameters { ...@@ -15,7 +20,8 @@ class Parameters {
static const double buttonPadding = 0.0; static const double buttonPadding = 0.0;
static const double buttonMargin = 0.0; static const double buttonMargin = 0.0;
static Widget buildParametersSelector(Data myProvider) { @override
Widget build(BuildContext context) {
List<Widget> lines = []; List<Widget> lines = [];
List<String> parameters = myProvider.availableParameters; List<String> parameters = myProvider.availableParameters;
...@@ -26,8 +32,8 @@ class Parameters { ...@@ -26,8 +32,8 @@ class Parameters {
myProvider.loadCurrentSavedState(); myProvider.loadCurrentSavedState();
Widget buttonsBlock = myProvider.hasCurrentSavedState() Widget buttonsBlock = myProvider.hasCurrentSavedState()
? buildResumeGameButton(myProvider) ? ResumeGameButton(myProvider: myProvider)
: buildStartNewGameButton(myProvider); : StartNewGameButton(myProvider: myProvider);
return Column( return Column(
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
...@@ -73,66 +79,7 @@ class Parameters { ...@@ -73,66 +79,7 @@ class Parameters {
); );
} }
static Container buildStartNewGameButton(Data myProvider) { Widget buildParameterSelector(Data myProvider, String parameterCode) {
return Container(
margin: const EdgeInsets.all(blockMargin),
padding: const EdgeInsets.all(blockPadding),
child: Table(
defaultColumnWidth: const IntrinsicColumnWidth(),
children: [
TableRow(
children: [
buildDecorationImageWidget(),
Column(
children: [
TextButton(
child: buildImageContainerWidget('button_start'),
onPressed: () => GameUtils.startNewGame(myProvider),
),
],
),
buildDecorationImageWidget(),
],
),
],
),
);
}
static Container buildResumeGameButton(Data myProvider) {
return Container(
margin: const EdgeInsets.all(blockMargin),
padding: const EdgeInsets.all(blockPadding),
child: Table(
defaultColumnWidth: const IntrinsicColumnWidth(),
children: [
TableRow(
children: [
Column(
children: [
TextButton(
child: buildImageContainerWidget('button_delete_saved_game'),
onPressed: () => GameUtils.deleteSavedGame(myProvider),
),
],
),
Column(
children: [
TextButton(
child: buildImageContainerWidget('button_resume_game'),
onPressed: () => GameUtils.resumeSavedGame(myProvider),
),
],
),
buildDecorationImageWidget(),
],
),
],
),
);
}
static Widget buildParameterSelector(Data myProvider, String parameterCode) {
List<String> availableValues = myProvider.getParameterAvailableValues(parameterCode); List<String> availableValues = myProvider.getParameterAvailableValues(parameterCode);
if (availableValues.length == 1) { if (availableValues.length == 1) {
...@@ -156,8 +103,7 @@ class Parameters { ...@@ -156,8 +103,7 @@ class Parameters {
); );
} }
static Widget _buildParameterButton( Widget _buildParameterButton(Data myProvider, String parameterCode, String parameterValue) {
Data myProvider, String parameterCode, String parameterValue) {
String currentValue = myProvider.getParameterValue(parameterCode).toString(); String currentValue = myProvider.getParameterValue(parameterCode).toString();
bool isActive = (parameterValue == currentValue); bool isActive = (parameterValue == currentValue);
......
...@@ -3,14 +3,12 @@ import 'package:provider/provider.dart'; ...@@ -3,14 +3,12 @@ import 'package:provider/provider.dart';
import 'package:badges/badges.dart' as badges; import 'package:badges/badges.dart' as badges;
import 'package:overlay_support/overlay_support.dart'; import 'package:overlay_support/overlay_support.dart';
import 'package:sudoku/layout/game.dart'; import 'package:sudoku/ui/layout/game.dart';
import 'package:sudoku/layout/parameters.dart'; import 'package:sudoku/ui/layout/parameters.dart';
import 'package:sudoku/provider/data.dart'; import 'package:sudoku/provider/data.dart';
import 'package:sudoku/utils/game_utils.dart'; import 'package:sudoku/utils/game_utils.dart';
class Home extends StatefulWidget { class Home extends StatefulWidget {
static const String id = 'home';
const Home({super.key}); const Home({super.key});
@override @override
...@@ -69,7 +67,7 @@ class HomeState extends State<Home> { ...@@ -69,7 +67,7 @@ class HomeState extends State<Home> {
final Data myProvider = Provider.of<Data>(context); final Data myProvider = Provider.of<Data>(context);
if (!myProvider.assetsPreloaded) { if (!myProvider.assetsPreloaded) {
List<String> assets = getImagesAssets(myProvider); final List<String> assets = getImagesAssets(myProvider);
for (String asset in assets) { for (String asset in assets) {
precacheImage(AssetImage(asset), context); precacheImage(AssetImage(asset), context);
} }
...@@ -119,13 +117,16 @@ class HomeState extends State<Home> { ...@@ -119,13 +117,16 @@ class HomeState extends State<Home> {
myProvider.givenTipsCount == 0 ? '' : myProvider.givenTipsCount.toString(), myProvider.givenTipsCount == 0 ? '' : myProvider.givenTipsCount.toString(),
style: const TextStyle(color: Colors.white), style: const TextStyle(color: Colors.white),
), ),
child: const Image( child: Container(
image: AssetImage('assets/icons/button_help.png'), padding: EdgeInsets.all(myProvider.givenTipsCountEnableCountdown / 4),
fit: BoxFit.fill, child: const Image(
image: AssetImage('assets/icons/button_help.png'),
fit: BoxFit.fill,
),
), ),
), ),
), ),
onPressed: () => GameUtils.showTip(myProvider), onPressed: () => myProvider.canGiveTip() ? GameUtils.showTip(myProvider) : null,
)); ));
menuActions.add(const Spacer()); menuActions.add(const Spacer());
menuActions.add(TextButton( menuActions.add(TextButton(
...@@ -155,8 +156,8 @@ class HomeState extends State<Home> { ...@@ -155,8 +156,8 @@ class HomeState extends State<Home> {
body: SafeArea( body: SafeArea(
child: Center( child: Center(
child: myProvider.gameIsRunning child: myProvider.gameIsRunning
? Game.buildGameWidget(myProvider) ? Game(myProvider: myProvider)
: Parameters.buildParametersSelector(myProvider), : Parameters(myProvider: myProvider),
), ),
), ),
); );
......
...@@ -3,35 +3,21 @@ import 'dart:math'; ...@@ -3,35 +3,21 @@ import 'dart:math';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:sudoku/entities/cell.dart'; import 'package:sudoku/entities/cell.dart';
import 'package:sudoku/layout/board.dart';
import 'package:sudoku/provider/data.dart'; import 'package:sudoku/provider/data.dart';
import 'package:sudoku/utils/board_utils.dart';
import 'package:sudoku/utils/game_utils.dart';
class Game { class SelectCellValueBar extends StatelessWidget {
static Widget buildGameWidget(Data myProvider) { const SelectCellValueBar({super.key, required this.myProvider});
final bool gameIsFinished = BoardUtils.checkBoardIsSolved(myProvider);
return Column( final Data myProvider;
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Board.buildGameBoard(myProvider),
const SizedBox(height: 2),
gameIsFinished
? Game.buildEndGameMessage(myProvider)
: Game.buildSelectCellValueBar(myProvider),
],
);
}
static Container buildSelectCellValueBar(Data myProvider) { @override
final List<List<Cell>> cells = myProvider.cells; Widget build(BuildContext context) {
final Board cells = myProvider.board;
final bool isCellSelected = final bool isCellSelected =
(myProvider.currentCellCol != null && myProvider.currentCellRow != null); (myProvider.selectedCellCol != null && myProvider.selectedCellRow != null);
final bool isUpdatableCellSelected = isCellSelected final bool isUpdatableCellSelected = isCellSelected
? !cells[myProvider.currentCellRow ?? 0][myProvider.currentCellCol ?? 0].isFixed ? !cells[myProvider.selectedCellRow ?? 0][myProvider.selectedCellCol ?? 0].isFixed
: false; : false;
final int maxValue = myProvider.blockSizeHorizontal * myProvider.blockSizeVertical; final int maxValue = myProvider.blockSizeHorizontal * myProvider.blockSizeVertical;
...@@ -53,9 +39,12 @@ class Game { ...@@ -53,9 +39,12 @@ class Game {
value++) value++)
Column( Column(
children: [ children: [
Cell(isUpdatableCellSelected ? (value <= maxValue ? value : -1) : -1, Cell(
false) row: 1,
.widgetUpdateValue(myProvider) col: value,
value: isUpdatableCellSelected ? (value <= maxValue ? value : -1) : -1,
isFixed: false,
).widgetUpdateValue(myProvider)
], ],
), ),
], ],
...@@ -64,48 +53,4 @@ class Game { ...@@ -64,48 +53,4 @@ class Game {
), ),
); );
} }
static Widget buildRestartGameButton(Data myProvider) {
return TextButton(
child: const Image(
image: AssetImage('assets/icons/button_back.png'),
fit: BoxFit.fill,
),
onPressed: () => GameUtils.quitGame(myProvider),
);
}
static Container buildEndGameMessage(Data myProvider) {
const Image decorationImage = Image(
image: AssetImage('assets/icons/game_win.png'),
fit: BoxFit.fill,
);
return Container(
margin: const EdgeInsets.all(2),
padding: const EdgeInsets.all(2),
child: Table(
defaultColumnWidth: const IntrinsicColumnWidth(),
children: [
TableRow(
children: [
const Column(
children: [decorationImage],
),
Column(
children: [
myProvider.animationInProgress
? decorationImage
: buildRestartGameButton(myProvider)
],
),
const Column(
children: [decorationImage],
),
],
),
],
),
);
}
} }
import 'package:flutter/material.dart';
import 'package:sudoku/provider/data.dart';
import 'package:sudoku/utils/game_utils.dart';
class RestartGameButton extends StatelessWidget {
const RestartGameButton({super.key, required this.myProvider});
final Data myProvider;
@override
Widget build(BuildContext context) {
return TextButton(
child: const Image(
image: AssetImage('assets/icons/button_back.png'),
fit: BoxFit.fill,
),
onPressed: () => GameUtils.quitGame(myProvider),
);
}
}
import 'package:flutter/material.dart';
import 'package:sudoku/ui/layout/parameters.dart';
import 'package:sudoku/utils/game_utils.dart';
class ResumeGameButton extends Parameters {
const ResumeGameButton({super.key, required super.myProvider});
@override
Widget build(BuildContext context) {
return Container(
margin: const EdgeInsets.all(Parameters.blockMargin),
padding: const EdgeInsets.all(Parameters.blockPadding),
child: Table(
defaultColumnWidth: const IntrinsicColumnWidth(),
children: [
TableRow(
children: [
Column(
children: [
TextButton(
child: Parameters.buildImageContainerWidget('button_delete_saved_game'),
onPressed: () => GameUtils.deleteSavedGame(myProvider),
),
],
),
Column(
children: [
TextButton(
child: Parameters.buildImageContainerWidget('button_resume_game'),
onPressed: () => GameUtils.resumeSavedGame(myProvider),
),
],
),
Parameters.buildDecorationImageWidget(),
],
),
],
),
);
}
}
import 'package:flutter/material.dart';
import 'package:sudoku/provider/data.dart';
import 'package:sudoku/ui/layout/parameters.dart';
import 'package:sudoku/utils/game_utils.dart';
class StartNewGameButton extends StatelessWidget {
const StartNewGameButton({super.key, required this.myProvider});
final Data myProvider;
@override
Widget build(BuildContext context) {
return Container(
margin: const EdgeInsets.all(Parameters.blockMargin),
padding: const EdgeInsets.all(Parameters.blockPadding),
child: Table(
defaultColumnWidth: const IntrinsicColumnWidth(),
children: [
TableRow(
children: [
Parameters.buildDecorationImageWidget(),
Column(
children: [
TextButton(
child: Parameters.buildImageContainerWidget('button_start'),
onPressed: () => GameUtils.startNewGame(myProvider),
),
],
),
Parameters.buildDecorationImageWidget(),
],
),
],
),
);
}
}
import 'package:flutter/material.dart';
import 'package:sudoku/ui/widgets/button_game_restart.dart';
import 'package:sudoku/provider/data.dart';
class EndGameMessage extends StatelessWidget {
const EndGameMessage({super.key, required this.myProvider});
final Data myProvider;
@override
Widget build(BuildContext context) {
const Image decorationImage = Image(
image: AssetImage('assets/icons/game_win.png'),
fit: BoxFit.fill,
);
return Container(
margin: const EdgeInsets.all(2),
padding: const EdgeInsets.all(2),
child: Table(
defaultColumnWidth: const IntrinsicColumnWidth(),
children: [
TableRow(
children: [
const Column(
children: [decorationImage],
),
Column(
children: [
myProvider.animationInProgress
? decorationImage
: RestartGameButton(myProvider: myProvider)
],
),
const Column(
children: [decorationImage],
),
],
),
],
),
);
}
}