From 4c11861bf75e0c62533010a0800c6ea5d0358d14 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Beno=C3=AEt=20Harrault?= <benoit@harrault.fr>
Date: Sun, 23 May 2021 21:42:40 +0200
Subject: [PATCH] Add split image and display tiles

---
 android/gradle.properties |   4 +-
 lib/provider/data.dart    |  10 ++-
 lib/screens/home.dart     | 167 +++++++++++++++++++++++++++++++-------
 pubspec.lock              |  35 ++++++++
 pubspec.yaml              |   1 +
 5 files changed, 184 insertions(+), 33 deletions(-)

diff --git a/android/gradle.properties b/android/gradle.properties
index 818e87b..db7a1ee 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.2
-app.versionCode=2
+app.versionName=0.0.3
+app.versionCode=3
diff --git a/lib/provider/data.dart b/lib/provider/data.dart
index d61bebb..6104e40 100644
--- a/lib/provider/data.dart
+++ b/lib/provider/data.dart
@@ -4,8 +4,9 @@ class Data extends ChangeNotifier {
 
   // application data
   List _images = [];
-
   String _image = '';
+  List _tiles = [];
+
 
   String get image => _image;
 
@@ -21,6 +22,13 @@ class Data extends ChangeNotifier {
     notifyListeners();
   }
 
+  List get tiles => _tiles;
+
+  set updateTiles(List value) {
+    _tiles = value;
+    notifyListeners();
+  }
+
   void resetGame() {
     _image = '';
     notifyListeners();
diff --git a/lib/screens/home.dart b/lib/screens/home.dart
index 8e10bef..92ae40c 100644
--- a/lib/screens/home.dart
+++ b/lib/screens/home.dart
@@ -1,4 +1,8 @@
+import 'dart:typed_data';
+
 import 'package:flutter/material.dart';
+import 'package:flutter/services.dart' show rootBundle;
+import 'package:image/image.dart' as imglib;
 import 'package:provider/provider.dart';
 
 import '../provider/data.dart';
@@ -7,10 +11,21 @@ import '../utils/get_images_list.dart';
 class Home extends StatelessWidget {
   static const String id = 'home';
 
+  int _linesCount = 3;
+  int _columnsCount = 3;
+
+  double _selectorImageSize = 200;
+  double _tipImageSize = 100;
+  double _tileImageSize = 80;
+
   Future<void> resetGame(Data myProvider) async {
     myProvider.updateImage = '';
   }
 
+  String getImageAssetName(String imageCode) {
+    return 'assets/images/'+imageCode+'.png';
+  }
+
   Future<void> getImagesList(Data myProvider) async {
     GetImagesList getImagesList;
     getImagesList = GetImagesList();
@@ -20,10 +35,12 @@ class Home extends StatelessWidget {
     }
   }
 
-  Container _buildImageSelectorItem(Data myProvider, String image) {
-    double imageSize = 200;
-    String imageAsset = 'assets/images/'+image+'.png';
+  Future<void> selectImage(Data myProvider, String imageCode) async {
+    myProvider.updateImage = imageCode;
+    myProvider.updateTiles = await splitImageInTiles(myProvider);
+  }
 
+  Container _buildImageSelectorItem(Data myProvider, String image) {
     return Container(
       child: FlatButton(
         child: Container(
@@ -36,15 +53,13 @@ class Home extends StatelessWidget {
           ),
           margin: EdgeInsets.all(2),
           child: Image(
-            image: AssetImage(imageAsset),
-            width: imageSize,
-            height: imageSize,
+            image: AssetImage(getImageAssetName(image)),
+            width: _selectorImageSize,
+            height: _selectorImageSize,
             fit: BoxFit.fill
           ),
         ),
-        onPressed: () {
-          myProvider.updateImage = image;
-        },
+        onPressed: () { selectImage(myProvider, image); },
       ),
     );
   }
@@ -66,33 +81,125 @@ class Home extends StatelessWidget {
     );
   }
 
-  Container _buildGameWidget(Data myProvider) {
-    double imageSize = 250;
-    String imageAsset = 'assets/images/'+myProvider.image+'.png';
+  Future<List<Image>> splitImageInTiles(Data myProvider) async {
+    String imageAsset = getImageAssetName(myProvider.image);
+    Uint8List imageData = (await rootBundle.load(imageAsset))
+      .buffer
+      .asUint8List();
+    imglib.Image image = imglib.decodeImage(imageData);
+
+    int x = 0, y = 0;
+    int width = (image.width / _linesCount).round();
+    int height = (image.height / _columnsCount).round();
+
+    List<imglib.Image> parts = List<imglib.Image>();
+    for (int i = 0; i < _linesCount; i++) {
+      for (int j = 0; j < _columnsCount; j++) {
+        parts.add(imglib.copyCrop(image, x, y, width, height));
+        x += width;
+      }
+      x = 0;
+      y += height;
+    }
 
+    List<Image> tiles = List<Image>();
+    for (var img in parts) {
+      tiles.add(Image.memory(imglib.encodeJpg(img)));
+    }
+
+    return tiles;
+  }
+
+  Container _buildImageTileItem(Image tile) {
+    return Container(
+      child: Image(
+        image: tile.image,
+        width: _tileImageSize,
+        height: _tileImageSize,
+        fit: BoxFit.fill
+      )
+    );
+  }
+
+  Container _buildTilesetWidget(Data myProvider) {
+    List tiles = myProvider.tiles;
+
+    tiles.shuffle();
+
+    int tileIndex = 0;
+
+    Table tileset = Table(
+      defaultColumnWidth: IntrinsicColumnWidth(),
+
+      border: TableBorder.all(
+        color: Colors.black,
+        style: BorderStyle.solid,
+        width: 2,
+      ),
+      children: [
+        TableRow(children: [
+          Column(children: [_buildImageTileItem(tiles[tileIndex++])]),
+          Column(children: [_buildImageTileItem(tiles[tileIndex++])]),
+          Column(children: [_buildImageTileItem(tiles[tileIndex++])]),
+        ]),
+        TableRow(children: [
+          Column(children: [_buildImageTileItem(tiles[tileIndex++])]),
+          Column(children: [_buildImageTileItem(tiles[tileIndex++])]),
+          Column(children: [_buildImageTileItem(tiles[tileIndex++])]),
+        ]),
+        TableRow(children: [
+          Column(children: [_buildImageTileItem(tiles[tileIndex++])]),
+          Column(children: [_buildImageTileItem(tiles[tileIndex++])]),
+          Column(children: [_buildImageTileItem(tiles[tileIndex++])]),
+        ]),
+      ],
+    );
+
+    return Container(
+      margin: EdgeInsets.all(4),
+      padding: EdgeInsets.all(4),
+      decoration: BoxDecoration(
+        color: Colors.blue,
+        borderRadius: BorderRadius.circular(4),
+        border: Border.all(
+          color: Colors.green,
+          width: 4,
+        ),
+      ),
+      child: tileset,
+    );
+  }
+
+  Container _buildTipWidget(Data myProvider) {
+    return Container(
+      margin: EdgeInsets.all(4),
+      padding: EdgeInsets.all(4),
+      decoration: BoxDecoration(
+        color: Colors.blue,
+        borderRadius: BorderRadius.circular(4),
+        border: Border.all(
+          color: Colors.green,
+          width: 4,
+        ),
+      ),
+      child: Image(
+        image: AssetImage(getImageAssetName(myProvider.image)),
+        width: _tipImageSize,
+        height: _tipImageSize,
+        fit: BoxFit.fill
+      ),
+    );
+  }
+
+  Container _buildGameWidget(Data myProvider) {
     return Container(
       child: Column(
         mainAxisSize: MainAxisSize.min,
         mainAxisAlignment: MainAxisAlignment.center,
         children: [
-          Container(
-            margin: EdgeInsets.all(4),
-            padding: EdgeInsets.all(4),
-            decoration: BoxDecoration(
-              color: Colors.blue,
-              borderRadius: BorderRadius.circular(4),
-              border: Border.all(
-                color: Colors.green,
-                width: 4,
-              ),
-            ),
-            child: Image(
-              image: AssetImage(imageAsset),
-              width: imageSize,
-              height: imageSize,
-              fit: BoxFit.fill
-            ),
-          ),
+          _buildTilesetWidget(myProvider),
+          SizedBox(height: 20),
+          _buildTipWidget(myProvider),
         ],
       ),
     );
diff --git a/pubspec.lock b/pubspec.lock
index 8fe48be..e4a9ea5 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -1,6 +1,13 @@
 # Generated by pub
 # See https://dart.dev/tools/pub/glossary#lockfile
 packages:
+  archive:
+    dependency: transitive
+    description:
+      name: archive
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "3.1.2"
   async:
     dependency: transitive
     description:
@@ -43,6 +50,13 @@ packages:
       url: "https://pub.dartlang.org"
     source: hosted
     version: "1.15.0"
+  crypto:
+    dependency: transitive
+    description:
+      name: crypto
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "3.0.1"
   fake_async:
     dependency: transitive
     description:
@@ -60,6 +74,13 @@ packages:
     description: flutter
     source: sdk
     version: "0.0.0"
+  image:
+    dependency: "direct main"
+    description:
+      name: image
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "3.0.2"
   matcher:
     dependency: transitive
     description:
@@ -88,6 +109,13 @@ packages:
       url: "https://pub.dartlang.org"
     source: hosted
     version: "1.8.0"
+  petitparser:
+    dependency: transitive
+    description:
+      name: petitparser
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "4.1.0"
   provider:
     dependency: "direct main"
     description:
@@ -156,6 +184,13 @@ packages:
       url: "https://pub.dartlang.org"
     source: hosted
     version: "2.1.0"
+  xml:
+    dependency: transitive
+    description:
+      name: xml
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "5.1.1"
 sdks:
   dart: ">=2.12.0 <3.0.0"
   flutter: ">=1.16.0"
diff --git a/pubspec.yaml b/pubspec.yaml
index b580f69..12fb8fd 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -9,6 +9,7 @@ environment:
 dependencies:
   flutter:
     sdk: flutter
+  image: ^3.0.2
   provider: ^5.0.0
 
 dev_dependencies:
-- 
GitLab