From ae2ed56302a78bc1f07d4bbe0d003e099c79111a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Beno=C3=AEt=20Harrault?= <benoit@harrault.fr>
Date: Fri, 10 Sep 2021 16:22:26 +0200
Subject: [PATCH] Fix freeze on end game animation, clean some code, minor
 improvements

---
 android/gradle.properties                     |   4 +-
 .../metadata/android/en-US/changelogs/46.txt  |   1 +
 .../metadata/android/fr-FR/changelogs/46.txt  |   1 +
 lib/entities/cell.dart                        | 163 ++++++++++--------
 lib/layout/board.dart                         |  18 +-
 lib/layout/game.dart                          |  54 +++---
 lib/layout/parameters.dart                    |   8 +-
 lib/provider/data.dart                        |  51 +++---
 lib/screens/home.dart                         |  51 +++++-
 lib/utils/board_animate.dart                  |  27 ++-
 lib/utils/board_utils.dart                    |   7 +-
 lib/utils/game_utils.dart                     |  12 +-
 12 files changed, 246 insertions(+), 151 deletions(-)
 create mode 100644 fastlane/metadata/android/en-US/changelogs/46.txt
 create mode 100644 fastlane/metadata/android/fr-FR/changelogs/46.txt

diff --git a/android/gradle.properties b/android/gradle.properties
index d6af5de..7d3ad5f 100644
--- a/android/gradle.properties
+++ b/android/gradle.properties
@@ -1,5 +1,5 @@
 org.gradle.jvmargs=-Xmx1536M
 android.useAndroidX=true
 android.enableJetifier=true
-app.versionName=0.0.45
-app.versionCode=45
+app.versionName=0.0.46
+app.versionCode=46
diff --git a/fastlane/metadata/android/en-US/changelogs/46.txt b/fastlane/metadata/android/en-US/changelogs/46.txt
new file mode 100644
index 0000000..ba9b39d
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/46.txt
@@ -0,0 +1 @@
+Fix freeze on end game animation, clean some code, minor improvements
diff --git a/fastlane/metadata/android/fr-FR/changelogs/46.txt b/fastlane/metadata/android/fr-FR/changelogs/46.txt
new file mode 100644
index 0000000..a12f663
--- /dev/null
+++ b/fastlane/metadata/android/fr-FR/changelogs/46.txt
@@ -0,0 +1 @@
+Correction du blocage sur l'animation de fin de partie, nettoyage de code, améliorations mineures
diff --git a/lib/entities/cell.dart b/lib/entities/cell.dart
index 78b448f..8a664e5 100644
--- a/lib/entities/cell.dart
+++ b/lib/entities/cell.dart
@@ -1,12 +1,14 @@
 import 'package:flutter/material.dart';
 
 import '../provider/data.dart';
+import '../utils/board_animate.dart';
 import '../utils/board_utils.dart';
 
 class Cell {
   int value;
   bool isFixed;
   int conflictsCount = 0;
+
   bool isAnimated = false;
 
   Cell(
@@ -14,21 +16,16 @@ class Cell {
     @required this.isFixed,
   );
 
-  static Color cellBorderDarkColor = Colors.black;
-  static Color cellBorderLightColor = Colors.grey;
-  static Color cellBorderSelectedColor = Colors.red;
-
-  Container widget(Data myProvider, Border borders, int row, int col) {
-    String imageAsset = 'assets/skins/empty.png';
-    if (this.value > 0) {
-      int cellValue = myProvider.getTranslatedValueForDisplay(this.value);
-      imageAsset = 'assets/skins/' + myProvider.skin + '_' + cellValue.toString() + '.png';
-    }
+  /*
+  * Build widget for board cell, with interactions
+  */
+  Container widget(Data myProvider, int row, int col) {
+    String imageAsset = this.getImageAssetName(myProvider);
 
     return Container(
       decoration: BoxDecoration(
         color: this.getBackgroundColor(myProvider),
-        border: borders,
+        border: this.getCellBorders(myProvider, row, col),
       ),
       child: GestureDetector(
         child: AnimatedSwitcher(
@@ -39,7 +36,7 @@ class Cell {
           child: Image(
             image: AssetImage(imageAsset),
             fit: BoxFit.fill,
-            key: ValueKey<int>(this.value),
+            key: ValueKey<int>(imageAsset.hashCode),
           ),
         ),
         onTap: () {
@@ -55,69 +52,26 @@ class Cell {
     );
   }
 
-  Color getBackgroundColor(Data myProvider) {
-    Color editableCellColor = Colors.grey[100];
-    Color editableCellColorConflict = Colors.pink[100];
-    Color fixedCellColor = Colors.grey[300];
-    Color fixedCellColorConflict = Colors.pink[200];
-    Color editableSelectedValueColor = Colors.green[100];
-    Color fixedSelectedValueColor = Colors.green[300];
-
-    Color backgroundColor = editableCellColor;
-
-    if (this.isFixed) {
-      backgroundColor = fixedCellColor;
-    }
-
-    if (myProvider.showConflicts && (this.conflictsCount != 0)) {
-      if (this.isFixed) {
-        backgroundColor = fixedCellColorConflict;
-      } else {
-        backgroundColor = editableCellColorConflict;
-      }
-    }
-
-    if (myProvider.showConflicts && (this.value == myProvider.currentCellValue)) {
-      if (this.isFixed) {
-        backgroundColor = fixedSelectedValueColor;
-      } else {
-        backgroundColor = editableSelectedValueColor;
-      }
-    }
-
-    if (this.isAnimated) {
-      if (this.isFixed) {
-        backgroundColor = Colors.green[300];
-      } else {
-        backgroundColor = Colors.green[200];
-      }
-    }
-
-    return backgroundColor;
-  }
-
+  /*
+  * Build widget for select/update value cell, with interactions
+  */
   Container widgetUpdateValue(Data myProvider) {
     if (this.value < 0) {
       return Container();
     }
 
-    String imageAsset = 'assets/skins/empty.png';
-    if (this.value > 0) {
-      int cellValue = myProvider.getTranslatedValueForDisplay(this.value);
-      imageAsset = 'assets/skins/' + myProvider.skin + '_' + cellValue.toString() + '.png';
-    }
-
+    String imageAsset = this.getImageAssetName(myProvider);
     Color backgroundColor = Colors.grey[200];
 
-    List cells = myProvider.cells;
-    int blockSizeHorizontal = myProvider.blockSizeHorizontal;
-    int blockSizeVertical = myProvider.blockSizeVertical;
-
     if (
       myProvider.showConflicts
       && myProvider.currentCellCol != null
       && myProvider.currentCellRow != null
     ) {
+      List cells = myProvider.cells;
+      int blockSizeHorizontal = myProvider.blockSizeHorizontal;
+      int blockSizeVertical = myProvider.blockSizeVertical;
+
       if (!BoardUtils.isValueAllowed(cells, blockSizeHorizontal, blockSizeVertical, myProvider.currentCellCol, myProvider.currentCellRow, this.value)) {
         backgroundColor = Colors.pink[100];
       }
@@ -141,30 +95,102 @@ class Cell {
             myProvider.updateCellValue(myProvider.currentCellCol, myProvider.currentCellRow, this.value);
           }
           myProvider.selectCell(null, null);
-          BoardUtils.computeConflictsInBoard(myProvider);
+          if (BoardUtils.checkBoardIsSolved(myProvider)) {
+            BoardAnimate.startAnimation(myProvider, 'win');
+          }
         },
       )
     );
   }
 
-  static Border getCellBorders(Data myProvider, int row, int col) {
+  /*
+  * Compute image asset name, from skin and cell value/state
+  */
+  String getImageAssetName(Data myProvider) {
+    String imageAsset = 'assets/skins/empty.png';
+    if (this.value > 0) {
+      int cellValue = myProvider.getTranslatedValueForDisplay(this.value);
+      imageAsset = 'assets/skins/' + myProvider.skin + '_' + cellValue.toString() + '.png';
+    }
+
+    return imageAsset;
+  }
+
+  // Compute cell background color, from cell state
+  Color getBackgroundColor(Data myProvider) {
+    Color editableCellColor = Colors.grey[100];
+    Color editableCellColorConflict = Colors.pink[100];
+    Color fixedCellColor = Colors.grey[300];
+    Color fixedCellColorConflict = Colors.pink[200];
+    Color editableSelectedValueColor = Colors.green[100];
+    Color fixedSelectedValueColor = Colors.green[300];
+    Color editableAnimated = Colors.green[200];
+    Color fixedAnimated = Colors.green[300];
+
+    Color backgroundColor = editableCellColor;
+
+    if (this.isFixed) {
+      backgroundColor = fixedCellColor;
+    }
+
+    if (myProvider.showConflicts && (this.conflictsCount != 0)) {
+      if (this.isFixed) {
+        backgroundColor = fixedCellColorConflict;
+      } else {
+        backgroundColor = editableCellColorConflict;
+      }
+    }
+
+    if (myProvider.showConflicts && (this.value == myProvider.currentCellValue)) {
+      if (this.isFixed) {
+        backgroundColor = fixedSelectedValueColor;
+      } else {
+        backgroundColor = editableSelectedValueColor;
+      }
+    }
+
+    if (this.isAnimated) {
+      if (this.isFixed) {
+        backgroundColor = fixedAnimated;
+      } else {
+        backgroundColor = editableAnimated;
+      }
+    }
+
+    return backgroundColor;
+  }
+
+  // Compute cell borders, from board size and cell state
+  Border getCellBorders(Data myProvider, int row, int col) {
     int blockSizeHorizontal = myProvider.blockSizeHorizontal;
     int blockSizeVertical = myProvider.blockSizeVertical;
 
+    Color cellBorderDarkColor = Colors.black;
+    Color cellBorderLightColor = Colors.grey;
+    Color cellBorderSelectedColor = Colors.red;
+
+    Color cellBorderColor = cellBorderSelectedColor;
     double cellBorderWidth = 4;
 
-    if (blockSizeVertical * blockSizeHorizontal > 8) {
+    // Reduce cell border width on big boards
+    int boardSize = blockSizeVertical * blockSizeHorizontal;
+    if (boardSize > 8) {
         cellBorderWidth = 2;
-        if (blockSizeVertical * blockSizeHorizontal > 10) {
+        if (boardSize > 10) {
             cellBorderWidth = 1;
         }
     }
 
+    if (!myProvider.gameIsRunning) {
+      cellBorderColor = Colors.green[700];
+    }
+
     Border borders = Border.all(
-      color: cellBorderSelectedColor,
+      color: cellBorderColor,
       width: cellBorderWidth,
     );
 
+    // Update cell borders if not currently selected cell
     if (col != myProvider.currentCellCol || row != myProvider.currentCellRow) {
       borders = Border(
         top: BorderSide(width: cellBorderWidth, color: ((row % blockSizeVertical) == 0) ? cellBorderDarkColor : cellBorderLightColor),
@@ -176,5 +202,4 @@ class Cell {
 
     return borders;
   }
-
 }
diff --git a/lib/layout/board.dart b/lib/layout/board.dart
index d68a621..9871246 100644
--- a/lib/layout/board.dart
+++ b/lib/layout/board.dart
@@ -1,27 +1,28 @@
-import 'dart:math';
-
 import 'package:flutter/material.dart';
 
-import '../entities/cell.dart';
 import '../provider/data.dart';
-import '../utils/board_utils.dart';
 
 class Board {
 
   static Container buildGameBoard(Data myProvider) {
+    Color borderColor = Colors.black;
+
     return Container(
       margin: EdgeInsets.all(2),
       padding: EdgeInsets.all(2),
       decoration: BoxDecoration(
-        color: Colors.black,
+        color: borderColor,
         borderRadius: BorderRadius.circular(2),
         border: Border.all(
-          color: Colors.black,
+          color: borderColor,
           width: 2,
         ),
       ),
-
-      child: buildGameTileset(myProvider),
+      child: Column(
+        children: [
+          buildGameTileset(myProvider),
+        ],
+      ),
     );
   }
 
@@ -38,7 +39,6 @@ class Board {
               Column(children: [
                 cells[row][col].widget(
                   myProvider,
-                  Cell.getCellBorders(myProvider, row, col),
                   row,
                   col
                 )
diff --git a/lib/layout/game.dart b/lib/layout/game.dart
index 67c8177..7ebbc93 100644
--- a/lib/layout/game.dart
+++ b/lib/layout/game.dart
@@ -5,7 +5,6 @@ import 'package:flutter/material.dart';
 import '../entities/cell.dart';
 import '../layout/board.dart';
 import '../provider/data.dart';
-import '../utils/board_animate.dart';
 import '../utils/board_utils.dart';
 import '../utils/game_utils.dart';
 
@@ -13,24 +12,22 @@ class Game {
 
   static Container buildGameWidget(Data myProvider) {
     bool gameIsFinished = BoardUtils.checkBoardIsSolved(myProvider);
-    if (gameIsFinished) {
-      BoardAnimate.startAnimation(myProvider, 'win');
-    }
 
     return Container(
       child: Column(
         mainAxisAlignment: MainAxisAlignment.start,
-        crossAxisAlignment: CrossAxisAlignment.start,
+        crossAxisAlignment: CrossAxisAlignment.center,
         children: [
           Board.buildGameBoard(myProvider),
           SizedBox(height: 2),
-          gameIsFinished ? Game.buildWinMessage(myProvider) : Game.buildSelectCellValueBar(myProvider),
+          gameIsFinished
+            ? Game.buildEndGameMessage(myProvider)
+            : Game.buildSelectCellValueBar(myProvider),
         ],
       ),
     );
   }
 
-
   static Container buildSelectCellValueBar(Data myProvider) {
     List cells = myProvider.cells;
 
@@ -74,15 +71,24 @@ class Game {
     );
   }
 
-
-  static Container buildWinMessage(Data myProvider) {
-    Column decorationImage = Column(
-      children: [
-        Image(
-          image: AssetImage('assets/icons/game_win.png'),
-          fit: BoxFit.fill
+  static FlatButton buildRestartGameButton(Data myProvider) {
+    return FlatButton(
+      child: Container(
+        child: Image(
+          image: AssetImage('assets/icons/button_back.png'),
+          fit: BoxFit.fill,
         ),
-      ]
+      ),
+      onPressed: () => GameUtils.resetGame(myProvider),
+    );
+  }
+
+  static Container buildEndGameMessage(Data myProvider) {
+    Image decorationImage = Image(
+      image: AssetImage(
+        'assets/icons/game_win.png'
+      ),
+      fit: BoxFit.fill
     );
 
     return Container(
@@ -94,21 +100,9 @@ class Game {
         children: [
           TableRow(
             children: [
-              decorationImage,
-              Column(
-                children: [
-                  FlatButton(
-                    child: Container(
-                      child: Image(
-                        image: AssetImage('assets/icons/button_back.png'),
-                        fit: BoxFit.fill
-                      ),
-                    ),
-                    onPressed: () => GameUtils.resetGame(myProvider),
-                  ),
-                ]
-              ),
-              decorationImage,
+              Column(children: [ decorationImage ]),
+              Column(children: [ myProvider.animationInProgress ? decorationImage : buildRestartGameButton(myProvider) ]),
+              Column(children: [ decorationImage ]),
             ],
           ),
         ]
diff --git a/lib/layout/parameters.dart b/lib/layout/parameters.dart
index f5bd84d..e63d3c7 100644
--- a/lib/layout/parameters.dart
+++ b/lib/layout/parameters.dart
@@ -26,7 +26,6 @@ class Parameters {
     );
   }
 
-
   static Container buildStartGameButton(Data myProvider) {
     Column decorationImage = Column(
       children: [
@@ -53,7 +52,7 @@ class Parameters {
                     child: Container(
                       child: Image(
                         image: AssetImage('assets/icons/button_start.png'),
-                        fit: BoxFit.fill
+                        fit: BoxFit.fill,
                       ),
                     ),
                     onPressed: () => GameUtils.startGame(myProvider),
@@ -68,7 +67,6 @@ class Parameters {
     );
   }
 
-
   static Table buildParameterSelector(Data myProvider, String parameterCode) {
     List availableValues = myProvider.getParameterAvailableValues(parameterCode);
 
@@ -89,7 +87,6 @@ class Parameters {
     );
   }
 
-
   static FlatButton _buildParameterButton(Data myProvider, String parameterCode, String parameterValue) {
     String currentValue = myProvider.getParameterValue(parameterCode).toString();
 
@@ -109,12 +106,11 @@ class Parameters {
         ),
         child: Image(
           image: AssetImage(imageAsset),
-          fit: BoxFit.fill
+          fit: BoxFit.fill,
         ),
       ),
       onPressed: () => myProvider.setParameterValue(parameterCode, parameterValue),
     );
   }
 
-
 }
diff --git a/lib/provider/data.dart b/lib/provider/data.dart
index 073682d..b3ca4b0 100644
--- a/lib/provider/data.dart
+++ b/lib/provider/data.dart
@@ -20,23 +20,24 @@ class Data extends ChangeNotifier {
   String _sizeDefault = '3x3';
   String _skin = null;
   String _skinDefault = 'default';
-  bool _showConflicts = false;
 
   // Game data
-  bool _stateRunning = false;
+  bool _assetsPreloaded = false;
+  bool _gameIsRunning = false;
+  bool _animationInProgress = false;
   int _blockSizeVertical = null;
   int _blockSizeHorizontal = null;
   List _cells = [];
   List _cellsSolved = [];
+  List _shuffledCellValues = [];
   int _currentCellCol = null;
   int _currentCellRow = null;
   int _currentCellValue = null;
+  bool _showConflicts = false;
   int _givenTipsCount = 0;
-  bool _animationInProgress = false;
-  List _shuffledCellValues = [];
 
   String get level => _level;
-  set updateLevel(String level) {
+  void updateLevel(String level) {
     _level = level;
     notifyListeners();
   }
@@ -44,7 +45,7 @@ class Data extends ChangeNotifier {
   String get size => _size;
   int get blockSizeVertical => _blockSizeVertical;
   int get blockSizeHorizontal => _blockSizeHorizontal;
-  set updateSize(String size) {
+  void updateSize(String size) {
     _size = size;
     _blockSizeHorizontal = int.parse(_size.split('x')[0]);
     _blockSizeVertical = int.parse(_size.split('x')[1]);
@@ -52,17 +53,11 @@ class Data extends ChangeNotifier {
   }
 
   String get skin => _skin;
-  set updateSkin(String skin) {
+  void updateSkin(String skin) {
     _skin = skin;
     notifyListeners();
   }
 
-  bool get showConflicts => _showConflicts;
-  set updateShowConflicts(bool showConflicts) {
-    _showConflicts = showConflicts;
-    notifyListeners();
-  }
-
   getParameterValue(String parameterCode) {
     switch(parameterCode) {
       case 'difficulty': { return _level; }
@@ -87,11 +82,11 @@ class Data extends ChangeNotifier {
 
   setParameterValue(String parameterCode, String parameterValue) async {
     switch(parameterCode) {
-      case 'difficulty': { updateLevel = parameterValue; }
+      case 'difficulty': { updateLevel(parameterValue); }
       break;
-      case 'size': { updateSize = parameterValue; }
+      case 'size': { updateSize(parameterValue); }
       break;
-      case 'skin': { updateSkin = parameterValue; }
+      case 'skin': { updateSkin(parameterValue); }
       break;
     }
     final prefs = await SharedPreferences.getInstance();
@@ -105,14 +100,25 @@ class Data extends ChangeNotifier {
     setParameterValue('skin', prefs.getString('skin') ?? _skinDefault);
   }
 
+  bool get gameIsRunning => _gameIsRunning;
+  void updateGameIsRunning(bool gameIsRunning) {
+    _gameIsRunning = gameIsRunning;
+    notifyListeners();
+  }
+
+  bool get assetsPreloaded => _assetsPreloaded;
+  void updateAssetsPreloaded(bool assetsPreloaded) {
+    _assetsPreloaded = assetsPreloaded;
+  }
+
   List get cells => _cells;
-  set updateCells(List cells) {
+  void updateCells(List cells) {
     _cells = cells;
     notifyListeners();
   }
 
   List get cellsSolved => _cellsSolved;
-  set updateCellsSolved(List cells) {
+  void updateCellsSolved(List cells) {
     _cellsSolved = cells;
   }
 
@@ -178,11 +184,14 @@ class Data extends ChangeNotifier {
     notifyListeners();
   }
 
-  bool get stateRunning => _stateRunning;
-  set updateStateRunning(bool stateRunning) {
-    _stateRunning = stateRunning;
+  bool get showConflicts => _showConflicts;
+  void updateShowConflicts(bool showConflicts) {
+    _showConflicts = showConflicts;
     notifyListeners();
   }
+  void toggleShowConflicts() {
+    updateShowConflicts(!showConflicts);
+  }
 
   bool get animationInProgress => _animationInProgress;
   void updateAnimationInProgress(bool animationInProgress) {
diff --git a/lib/screens/home.dart b/lib/screens/home.dart
index e797369..8b05ae8 100644
--- a/lib/screens/home.dart
+++ b/lib/screens/home.dart
@@ -23,13 +23,58 @@ class _HomeState extends State<Home> {
     myProvider.initParametersValues();
   }
 
+  List getImagesAssets(Data myProvider) {
+    List assets = [];
+
+    List gameImages = [
+      'button_back',
+      'button_help',
+      'button_show_conflicts',
+      'button_start',
+      'game_win',
+    ];
+    myProvider.availableDifficultyLevels.forEach(
+      (difficulty) => gameImages.add('difficulty_' + difficulty)
+    );
+    myProvider.availableSizes.forEach(
+      (size) => gameImages.add('size_' + size)
+    );
+
+    gameImages.forEach(
+      (image) => assets.add('assets/icons/' + image + '.png')
+    );
+
+    List skinImages = [];
+    for (int value = 1; value <= 16; value++) {
+      skinImages.add(value.toString());
+    }
+
+    myProvider.availableSkins.forEach(
+      (skin) => skinImages.forEach(
+        (image) => assets.add('assets/skins/' + skin + '_' + image + '.png')
+      )
+    );
+
+    assets.add('assets/skins/empty.png');
+
+    return assets;
+  }
+
   @override
   Widget build(BuildContext context) {
     Data myProvider = Provider.of<Data>(context);
 
+    if (!myProvider.assetsPreloaded) {
+      List assets = getImagesAssets(myProvider);
+      assets.forEach(
+        (asset) => precacheImage(AssetImage(asset), context)
+      );
+      myProvider.updateAssetsPreloaded(true);
+    }
+
     List<Widget> menuActions = [];
 
-    if (myProvider.stateRunning) {
+    if (myProvider.gameIsRunning) {
       menuActions = [
         FlatButton(
           child: Container(
@@ -79,7 +124,7 @@ class _HomeState extends State<Home> {
             ),
           ),
           onPressed: () {
-            myProvider.updateShowConflicts = !myProvider.showConflicts;
+            myProvider.toggleShowConflicts();
           },
         ),
         FlatButton(
@@ -108,7 +153,7 @@ class _HomeState extends State<Home> {
       ),
       body: SafeArea(
         child: Center(
-          child: myProvider.stateRunning
+          child: myProvider.gameIsRunning
             ? Game.buildGameWidget(myProvider)
             : Parameters.buildParametersSelector(myProvider)
         ),
diff --git a/lib/utils/board_animate.dart b/lib/utils/board_animate.dart
index e328a0e..cd07690 100644
--- a/lib/utils/board_animate.dart
+++ b/lib/utils/board_animate.dart
@@ -1,5 +1,4 @@
 import 'dart:async';
-import 'dart:math';
 
 import '../entities/cell.dart';
 import '../provider/data.dart';
@@ -40,7 +39,29 @@ class BoardAnimate {
       for (var row = 0; row < boardSideLength; row++) {
         List<bool> patternRow = [];
         for (var col = 0; col < boardSideLength; col++) {
-          patternRow.add(row > (patternIndex - 3));
+          patternRow.add(row > (patternIndex - 4));
+        }
+        pattern.add(patternRow);
+      }
+      patterns.add(pattern);
+    }
+
+    return patterns;
+  }
+
+  // Default multi-purpose animation: sliding stripes, from top left to right bottom
+  static List createDefaultAnimationPatterns(Data myProvider) {
+    List<List> patterns = [];
+
+    int boardSideLength = myProvider.blockSizeHorizontal * myProvider.blockSizeVertical;
+    int patternsCount = boardSideLength;
+
+    for (var patternIndex = 0; patternIndex < patternsCount; patternIndex++) {
+      List<List> pattern = [];
+      for (var row = 0; row < boardSideLength; row++) {
+        List<bool> patternRow = [];
+        for (var col = 0; col < boardSideLength; col++) {
+          patternRow.add(((patternIndex + row + col) % 4 == 0));
         }
         pattern.add(patternRow);
       }
@@ -60,6 +81,8 @@ class BoardAnimate {
       case 'win':
         patterns = createWinGameAnimationPatterns(myProvider);
         break;
+      default:
+        patterns = createDefaultAnimationPatterns(myProvider);
     }
 
     int _patternIndex = patterns.length;
diff --git a/lib/utils/board_utils.dart b/lib/utils/board_utils.dart
index bc5f4f0..2f75359 100644
--- a/lib/utils/board_utils.dart
+++ b/lib/utils/board_utils.dart
@@ -1,8 +1,8 @@
 import 'dart:math';
 
 import '../entities/cell.dart';
-import '../utils/random_pick_grid.dart';
 import '../provider/data.dart';
+import '../utils/random_pick_grid.dart';
 
 class BoardUtils {
 
@@ -23,7 +23,6 @@ class BoardUtils {
     print('');
   }
 
-
   static Future<void> pickGrid(Data myProvider) async {
     String grid;
     RandomPickGrid randomPickGrid;
@@ -41,8 +40,8 @@ class BoardUtils {
     if (grid.length == pow(blockSizeHorizontal * blockSizeVertical, 2)) {
       print('Picked grid from template: ' + grid);
       bool isSymetric = (blockSizeHorizontal == blockSizeVertical);
-      myProvider.updateCells = BoardUtils.createBoardFromTemplate(grid, isSymetric);
-      myProvider.updateCellsSolved = BoardUtils.getSolvedGrid(myProvider);
+      myProvider.updateCells(BoardUtils.createBoardFromTemplate(grid, isSymetric));
+      myProvider.updateCellsSolved(BoardUtils.getSolvedGrid(myProvider));
       myProvider.selectCell(null, null);
 
       printGrid(myProvider.cells, myProvider.cellsSolved);
diff --git a/lib/utils/game_utils.dart b/lib/utils/game_utils.dart
index 51758ba..abca12e 100644
--- a/lib/utils/game_utils.dart
+++ b/lib/utils/game_utils.dart
@@ -6,15 +6,15 @@ import '../utils/game_utils.dart';
 class GameUtils {
 
   static Future<void> resetGame(Data myProvider) async {
-    myProvider.updateStateRunning = false;
+    myProvider.updateGameIsRunning(false);
   }
 
   static Future<void> startGame(Data myProvider) async {
-    myProvider.updateSize = myProvider.size;
-    myProvider.updateStateRunning = true;
+    myProvider.updateSize(myProvider.size);
+    myProvider.updateGameIsRunning(true);
     myProvider.resetGivenTipsCount();
     myProvider.shuffleCellValues();
-    myProvider.updateCells = BoardUtils.createEmptyBoard(myProvider.blockSizeHorizontal * myProvider.blockSizeVertical);
+    myProvider.updateCells(BoardUtils.createEmptyBoard(myProvider.blockSizeHorizontal * myProvider.blockSizeVertical));
     BoardUtils.pickGrid(myProvider);
     BoardAnimate.startAnimation(myProvider, 'start');
   }
@@ -86,7 +86,9 @@ class GameUtils {
 
     myProvider.updateCellValue(myProvider.currentCellCol, myProvider.currentCellRow, allowedValuesCount == 1 ? eligibleValue : 0);
     myProvider.selectCell(null, null);
-    BoardUtils.computeConflictsInBoard(myProvider);
+    if (BoardUtils.checkBoardIsSolved(myProvider)) {
+      BoardAnimate.startAnimation(myProvider, 'win');
+    }
   }
 
 }
-- 
GitLab