From b91b2c66cf5904c9b621c4aec9b0ecc529ba50bc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Beno=C3=AEt=20Harrault?= <benoit@harrault.fr>
Date: Mon, 21 Nov 2022 18:31:04 +0100
Subject: [PATCH] Fully draw board, do not use skin images

---
 android/gradle.properties                     |  4 +-
 .../metadata/android/en-US/changelogs/28.txt  |  1 +
 .../metadata/android/fr-FR/changelogs/28.txt  |  1 +
 lib/entities/cell.dart                        | 83 -------------------
 lib/layout/board.dart                         | 32 ++-----
 lib/layout/board_painter.dart                 | 83 +++++++++++++++++++
 lib/layout/game.dart                          |  4 +-
 lib/screens/home.dart                         |  3 +-
 8 files changed, 99 insertions(+), 112 deletions(-)
 create mode 100644 fastlane/metadata/android/en-US/changelogs/28.txt
 create mode 100644 fastlane/metadata/android/fr-FR/changelogs/28.txt
 create mode 100644 lib/layout/board_painter.dart

diff --git a/android/gradle.properties b/android/gradle.properties
index 408253c..e644338 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.27
-app.versionCode=27
+app.versionName=0.0.28
+app.versionCode=28
diff --git a/fastlane/metadata/android/en-US/changelogs/28.txt b/fastlane/metadata/android/en-US/changelogs/28.txt
new file mode 100644
index 0000000..ea008d0
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/28.txt
@@ -0,0 +1 @@
+Improve drawing for cells and borders
diff --git a/fastlane/metadata/android/fr-FR/changelogs/28.txt b/fastlane/metadata/android/fr-FR/changelogs/28.txt
new file mode 100644
index 0000000..536c565
--- /dev/null
+++ b/fastlane/metadata/android/fr-FR/changelogs/28.txt
@@ -0,0 +1 @@
+Amélioration du tracé des cellules et des bordures
diff --git a/lib/entities/cell.dart b/lib/entities/cell.dart
index a122cc8..b89ff47 100644
--- a/lib/entities/cell.dart
+++ b/lib/entities/cell.dart
@@ -1,4 +1,3 @@
-import 'package:colors/layout/color_theme.dart';
 import 'package:colors/provider/data.dart';
 import 'package:colors/utils/board_utils.dart';
 import 'package:flutter/material.dart';
@@ -10,51 +9,6 @@ class Cell {
     this.value,
   );
 
-  Widget widget(Data myProvider, int row, int col) {
-    String imageAsset = this.getImageAssetName(myProvider);
-
-    Image cellColorImage = Image(
-      image: AssetImage(imageAsset),
-      fit: BoxFit.fill,
-      key: ValueKey<int>(imageAsset.hashCode),
-    );
-
-    List<Widget> cellContent = [
-      cellColorImage,
-    ];
-
-    // Add black point on first cell
-    if ((row == 0) && (col == 0)) {
-      double blackPointFontSize = 30.0 - (myProvider.boardSize);
-
-      cellContent.add(
-        Center(
-          child: Text(
-            '•',
-            style: TextStyle(
-              color: Colors.black,
-              fontSize: blackPointFontSize,
-              fontWeight: FontWeight.w800,
-            ),
-            textAlign: TextAlign.center,
-          ),
-        ),
-      );
-    }
-
-    return Container(
-      margin: EdgeInsets.all(0),
-      padding: EdgeInsets.all(0),
-      decoration: BoxDecoration(
-        border: getCellBorders(myProvider, row, col),
-      ),
-      child: Stack(
-        alignment: Alignment.center,
-        children: cellContent,
-      ),
-    );
-  }
-
   Container widgetFillBoardWithColor(Data myProvider) {
     String imageAsset = this.getImageAssetName(myProvider);
 
@@ -85,41 +39,4 @@ class Cell {
     int cellValue = this.value;
     return 'assets/skins/' + myProvider.parameterSkin + '_' + cellValue.toString() + '.png';
   }
-
-  Border getCellBorders(Data myProvider, int row, int col) {
-    int value = myProvider.getCellValue(col, row);
-
-    int colorCode = ColorTheme.getColorCode(myProvider.parameterSkin, value);
-
-    double borderWidth = 2;
-    BorderSide solid = BorderSide(color: Colors.black87, width: borderWidth);
-    BorderSide none = BorderSide(color: Color(colorCode), width: borderWidth);
-
-    BorderSide topBorder = (row == 0) ? solid : none;
-    BorderSide bottomBorder = (row == myProvider.boardSize - 1) ? solid : none;
-    BorderSide leftBorder = (col == 0) ? solid : none;
-    BorderSide rightBorder = (col == myProvider.boardSize - 1) ? solid : none;
-
-    if (row > 1 && value != myProvider.getCellValue(col, row - 1)) {
-      topBorder = solid;
-    }
-    if ((row + 1) < myProvider.boardSize && value != myProvider.getCellValue(col, row + 1)) {
-      bottomBorder = solid;
-    }
-    if (col > 1 && value != myProvider.getCellValue(col - 1, row)) {
-      leftBorder = solid;
-    }
-    if ((col + 1) < myProvider.boardSize && value != myProvider.getCellValue(col + 1, row)) {
-      rightBorder = solid;
-    }
-
-    Border border = Border(
-      top: topBorder,
-      bottom: bottomBorder,
-      left: leftBorder,
-      right: rightBorder,
-    );
-
-    return border;
-  }
 }
diff --git a/lib/layout/board.dart b/lib/layout/board.dart
index a6aee30..8d0b03c 100644
--- a/lib/layout/board.dart
+++ b/lib/layout/board.dart
@@ -1,38 +1,22 @@
+import 'package:colors/layout/board_painter.dart';
 import 'package:colors/provider/data.dart';
 import 'package:flutter/material.dart';
 
 class Board {
-  static Container buildGameBoard(Data myProvider) {
+  static Container buildGameBoard(Data myProvider, double boardWidth) {
     return Container(
       margin: EdgeInsets.all(4),
       padding: EdgeInsets.all(4),
       child: Column(
         children: [
-          buildGameTileset(myProvider),
+          CustomPaint(
+            size: Size(boardWidth, boardWidth),
+            willChange: false,
+            painter: BoardPainter(myProvider),
+            isComplex: true,
+          ),
         ],
       ),
     );
   }
-
-  static Table buildGameTileset(Data myProvider) {
-    int boardSize = myProvider.boardSize;
-    List cells = myProvider.cells;
-
-    return Table(
-      defaultColumnWidth: IntrinsicColumnWidth(),
-      children: [
-        for (var row = 0; row < boardSize; row++)
-          TableRow(
-            children: [
-              for (var col = 0; col < boardSize; col++)
-                Column(
-                  children: [
-                    cells[row][col].widget(myProvider, row, col),
-                  ],
-                ),
-            ],
-          ),
-      ],
-    );
-  }
 }
diff --git a/lib/layout/board_painter.dart b/lib/layout/board_painter.dart
new file mode 100644
index 0000000..e966e7c
--- /dev/null
+++ b/lib/layout/board_painter.dart
@@ -0,0 +1,83 @@
+import 'package:colors/entities/cell.dart';
+import 'package:colors/layout/color_theme.dart';
+import 'package:colors/provider/data.dart';
+import 'package:flutter/material.dart';
+
+class BoardPainter extends CustomPainter {
+  const BoardPainter(this.myProvider);
+
+  final Data myProvider;
+
+  @override
+  void paint(Canvas canvas, Size size) {
+    int boardSize = myProvider.boardSize;
+    List cells = myProvider.cells;
+    double cellSize = size.width / boardSize;
+
+    // background
+    for (var row = 0; row < boardSize; row++) {
+      double y = cellSize * row;
+      for (var col = 0; col < boardSize; col++) {
+        double x = cellSize * col;
+
+        final Cell cell = cells[row][col];
+        final int cellValue = cell.value;
+        final int colorCode = ColorTheme.getColorCode(myProvider.parameterSkin, cellValue);
+
+        final cellPaintBackground = Paint();
+        cellPaintBackground.color = Color(colorCode);
+        cellPaintBackground.style = PaintingStyle.fill;
+
+        final Rect cellBackground =
+            Rect.fromPoints(Offset(x - 1, y - 1), Offset(x + cellSize + 2, y + cellSize + 2));
+
+        canvas.drawRect(cellBackground, cellPaintBackground);
+      }
+    }
+
+    // borders
+    double borderSize = 4;
+    final cellPaintBorder = Paint();
+    cellPaintBorder.color = Colors.black;
+    cellPaintBorder.strokeWidth = borderSize;
+    cellPaintBorder.strokeCap = StrokeCap.round;
+
+    for (var row = 0; row < boardSize; row++) {
+      double y = cellSize * row;
+      for (var col = 0; col < boardSize; col++) {
+        double x = cellSize * col;
+
+        final Cell cell = cells[row][col];
+        final int cellValue = cell.value;
+
+        if ((row == 0) || (row > 1 && cellValue != myProvider.getCellValue(col, row - 1))) {
+          Offset borderStart = Offset(x, y);
+          Offset borderStop = Offset(x + cellSize, y);
+          canvas.drawLine(borderStart, borderStop, cellPaintBorder);
+        }
+        if ((row == boardSize - 1) ||
+            ((row + 1) < boardSize && cellValue != myProvider.getCellValue(col, row + 1))) {
+          Offset borderStart = Offset(x, y + cellSize);
+          Offset borderStop = Offset(x + cellSize, y + cellSize);
+          canvas.drawLine(borderStart, borderStop, cellPaintBorder);
+        }
+        if ((col == 0) || (col > 1 && cellValue != myProvider.getCellValue(col - 1, row))) {
+          Offset borderStart = Offset(x, y);
+          Offset borderStop = Offset(x, y + cellSize);
+          canvas.drawLine(borderStart, borderStop, cellPaintBorder);
+        }
+        if ((col == boardSize - 1) ||
+            ((col + 1) < boardSize && cellValue != myProvider.getCellValue(col + 1, row))) {
+          Offset borderStart = Offset(x + cellSize, y);
+          Offset borderStop = Offset(x + cellSize, y + cellSize);
+          canvas.drawLine(borderStart, borderStop, cellPaintBorder);
+        }
+      }
+    }
+  }
+
+  @override
+  bool shouldRepaint(CustomPainter oldDelegate) {
+    return false;
+  }
+}
diff --git a/lib/layout/game.dart b/lib/layout/game.dart
index 6ceeaf6..81fb64d 100644
--- a/lib/layout/game.dart
+++ b/lib/layout/game.dart
@@ -5,7 +5,7 @@ import 'package:colors/utils/game_utils.dart';
 import 'package:flutter/material.dart';
 
 class Game {
-  static Container buildGameWidget(Data myProvider) {
+  static Container buildGameWidget(Data myProvider, double boardWidth) {
     bool gameIsFinished = myProvider.isGameFinished();
 
     return Container(
@@ -17,7 +17,7 @@ class Game {
           Game.buildTopIndicatorWidget(myProvider),
           SizedBox(height: 2),
           Expanded(
-            child: Board.buildGameBoard(myProvider),
+            child: Board.buildGameBoard(myProvider, boardWidth),
           ),
           SizedBox(height: 2),
           Container(
diff --git a/lib/screens/home.dart b/lib/screens/home.dart
index 40ff3ff..ac80b66 100644
--- a/lib/screens/home.dart
+++ b/lib/screens/home.dart
@@ -25,6 +25,7 @@ class _HomeState extends State<Home> {
   @override
   Widget build(BuildContext context) {
     Data myProvider = Provider.of<Data>(context);
+    double boardWidth = MediaQuery.of(context).size.width;
 
     List<Widget> menuActions = [];
 
@@ -50,7 +51,7 @@ class _HomeState extends State<Home> {
       body: SafeArea(
         child: Center(
           child: myProvider.gameIsRunning
-              ? Game.buildGameWidget(myProvider)
+              ? Game.buildGameWidget(myProvider, boardWidth)
               : Parameters.buildParametersSelector(myProvider),
         ),
       ),
-- 
GitLab