Переглянути джерело

improve prganization and states

Gabriel Capella 2 роки тому
батько
коміт
69aca53d1a

+ 67 - 55
lib/grid.dart

@@ -1,3 +1,4 @@
+import 'dart:async';
 import 'dart:math';
 import 'package:flutter/material.dart';
 import 'package:grpc/grpc_web.dart';
@@ -15,15 +16,13 @@ class TransformationsDemo extends StatefulWidget {
   State<TransformationsDemo> createState() => _TransformationsDemoState();
 }
 
-
 class _TransformationsDemoState extends State<TransformationsDemo>
     with TickerProviderStateMixin {
   final GlobalKey _targetKey = GlobalKey();
-  Map<Point<int>, Widget> elements = <Point<int>, Widget>{};
-  Color appbarColor = Colors.blueGrey;
+  final Map<Point<int>, Widget> elements = <Point<int>, Widget>{};
   Set<Color> swatches = Colors.primaries.map((e) => Color(e.value)).toSet();
-  double minScale = 2;
-  ColorRef cc = ColorRef();
+  final double minScale = 2;
+  final ColorRef cc = ColorRef(Colors.blueGrey);
 
   final TransformationController _transformationController =
       TransformationController();
@@ -37,9 +36,6 @@ class _TransformationsDemoState extends State<TransformationsDemo>
   void initState() {
     super.initState();
     WebRTCChannels().connect((x) {});
-    // _controllerReset = AnimationController(
-    //   vsync: this,
-    // );
   }
 
   @override
@@ -61,13 +57,7 @@ class _TransformationsDemoState extends State<TransformationsDemo>
               _homeMatrix = Matrix4.identity() * minScale
                 ..translate(0, 0);
               _transformationController.value = _homeMatrix!;
-
-              elements = _start(
-                  context: context,
-                  channel: channel,
-                  transformationController: _transformationController);
-
-              // _onUpdate(context: context);
+              createComponentMap();
             }
 
             return ClipRect(
@@ -80,7 +70,7 @@ class _TransformationsDemoState extends State<TransformationsDemo>
                     constrained: false,
                     key: _targetKey,
                     transformationController: _transformationController,
-                    boundaryMargin: EdgeInsets.all(0),
+                    boundaryMargin: const EdgeInsets.all(0),
                     minScale: minScale,
                     maxScale: 30,
                     // onInteractionStart: _onScaleStart,
@@ -89,7 +79,9 @@ class _TransformationsDemoState extends State<TransformationsDemo>
                     child: SizedBox(
                       width: 256 * 90,
                       height: 256 * 53,
-                      child: Stack(children: elements.values.toList()),
+                      child: GridPaper(
+                        child: Stack(children: elements.values.toList()),
+                      ),
                     ),
                   ),
                 ),
@@ -102,7 +94,7 @@ class _TransformationsDemoState extends State<TransformationsDemo>
       floatingActionButton: ColorButton(
         darkMode: true,
         key: const Key('c2'),
-        color: appbarColor,
+        color: cc.getColor(),
         boxShape: BoxShape.circle,
         swatches: swatches,
         size: 64,
@@ -110,10 +102,9 @@ class _TransformationsDemoState extends State<TransformationsDemo>
           enableOpacity: false,
           enableLibrary: true,
         ),
-        onColorChanged: (value) => setState(()  {
-          appbarColor = value;
-          cc.setColor(appbarColor);
-          }),
+        onColorChanged: (value) => setState(() {
+          cc.setColor(value);
+        }),
         onSwatchesChanged: (newSwatches) =>
             setState(() => swatches = newSwatches),
       ),
@@ -126,31 +117,26 @@ class _TransformationsDemoState extends State<TransformationsDemo>
     super.dispose();
   }
 
-  void _onInteractionUpdate(ScaleUpdateDetails details) {
+  void _onInteractionUpdate(ScaleUpdateDetails details) => _onUpdate();
+  void _onInteractionEnd(ScaleEndDetails details) {
     _onUpdate();
+    Timer(const Duration(milliseconds: 250), () => _onUpdate());
+    Timer(const Duration(milliseconds: 500), () => _onUpdate());
   }
 
-  void _onUpdate({BuildContext? context}) {
-    var context2 = context ?? _targetKey.currentContext!;
+  void _onUpdate() {
     setState(() {
-      _start(
-          context: context2,
-          channel: channel,
-          transformationController: _transformationController,
-          elements: elements);
+      createComponentMap();
     });
   }
 
-   Map<Point<int>, Widget> _start(
-      {required BuildContext context,
-      required GrpcWebClientChannel channel,
-      required TransformationController transformationController,
-      Map<Point<int>, Widget>? elements}) {
+  void createComponentMap() {
     var bounds = MediaQuery.of(context).size;
 
-    var topLeft = transformationController.toScene(bounds.topLeft(Offset.zero));
+    var topLeft =
+        _transformationController.toScene(bounds.topLeft(Offset.zero));
     var bottomRight =
-        transformationController.toScene(bounds.bottomRight(Offset.zero));
+        _transformationController.toScene(bounds.bottomRight(Offset.zero));
 
     var newSet = <Point<int>>{};
 
@@ -162,25 +148,29 @@ class _TransformationsDemoState extends State<TransformationsDemo>
       }
     }
 
-    var elements2 = elements ?? <Point<int>, Widget>{};
-    newSet
-        .difference(Set.from(elements2.keys))
-        .forEach((point) => elements2[point] ??= Container(
-              margin:
-                  EdgeInsets.only(left: 256.0 * point.x, top: 256.0 * point.y),
-              child: SquareComponent(point, cc),
-            ));
-
-    Set.from(elements2.keys).difference(newSet).forEach(
-          (point) => elements2.remove(point),
-        );
-    // print(elements2.length);
-    // WebRTCChannels().connect();
-
-    return elements2;
-  }
+    final oldKeys = Set.from(elements.keys);
+    final newPoints = newSet.difference(oldKeys);
+    final disposePoints = oldKeys.difference(newSet);
+
+    for (var point in newPoints) {
+      elements[point] = Container(
+          key: Key(point.toString()),
+          margin: EdgeInsets.only(left: 256.0 * point.x, top: 256.0 * point.y),
+          child: Stack(children: [
+            CustomPaint(
+              painter: OpenPainter(point),
+            ),
+            Text(point.toString()),
+            SquareComponent(color: cc, tile: point, key: Key(point.toString())),
+          ])
+          // child: SquareComponent(point, cc),
+          );
+    }
 
-  void _onInteractionEnd(ScaleEndDetails details) => _onUpdate();
+    for (var point in disposePoints) {
+      elements.remove(point);
+    }
+  }
 }
 
 Point<int> _offsetToIndex(Offset offset) {
@@ -191,3 +181,25 @@ Point<int> _offsetToIndex(Offset offset) {
   if (y < 0) y = 0;
   return Point<int>(x, y);
 }
+
+class OpenPainter extends CustomPainter {
+  Point<int> point;
+
+  OpenPainter(Point<int> this.point);
+
+  @override
+  void paint(Canvas canvas, Size size) {
+    var paint1 = Paint()
+      ..color = Color.fromARGB(
+        100,
+        ((point.x * point.y * 7) % 64) * 4,
+        ((point.x * 10039) % 64) * 4,
+        ((point.y * 10061) % 64) * 4,
+      )
+      ..style = PaintingStyle.fill;
+    canvas.drawRect(const Offset(0, 0) & const Size(256, 256), paint1);
+  }
+
+  @override
+  bool shouldRepaint(CustomPainter oldDelegate) => true;
+}

+ 6 - 3
lib/src/color_ref.dart

@@ -2,7 +2,10 @@
 import 'dart:ui';
 
 class ColorRef {
-  Color? color;
-  getColor() => color;
-  setColor(Color c) => color = c;
+  Color color;
+  
+  ColorRef(this.color);
+
+  Color getColor() => color;
+  void setColor(Color c) => color = c;
 }

+ 1 - 1
lib/src/square/in_memory.dart

@@ -21,7 +21,7 @@ class InMemorySquereData extends SquereData {
 
   @override
   void paint(Point<int> point, Color color) {
-    print(point.toString());
+    // print(point.toString());
     streamChannel.add(MonitorReply(points: [
       MonitorPoint(
           point: BPoint(x: point.x, y: point.y),

+ 1 - 1
lib/src/square/square.dart

@@ -7,7 +7,7 @@ import '../generated/client.pb.dart';
  * Simple interfaxe to interact with the UI
  */
 abstract class SquereData {
-  SquereData(Point<int> point);
+  SquereData(Point<int> tile);
   Stream<MonitorReply> getSteam();
   void paint(Point<int> point, Color color);
 }

+ 67 - 48
lib/src/widget/square.dart

@@ -11,77 +11,96 @@ import '../square/in_memory.dart';
 import '../square/square.dart';
 
 class SquareComponent extends StatefulWidget {
-  Point<int> tile;
-  ColorRef color;
-  SquareComponent(this.tile, this.color, {Key? key}) : super(key: key);
+  final Point<int> tile;
+  final ColorRef color;
+  const SquareComponent({super.key, required this.tile, required this.color});
 
   @override
   SquareComponentState createState() => SquareComponentState();
 }
 
 class SquareComponentState extends State<SquareComponent> {
-  // late ResponseStream<MonitorReply> responses;
-  late final SquereData __serverSquareData;
-  bool __updated = false;
-  ui.Image? img;
-  Uint8List data = Uint8List(256 * 256 * 4);
+  late final SquereData __serverSquareData = InMemorySquereData(widget.tile);
+  final Uint8List data = Uint8List(256 * 256 * 4);
 
-  void renderImage() {
-    ui.decodeImageFromPixels(data, 256, 256, ui.PixelFormat.rgba8888, setImg,
-        allowUpscaling: false);
+  Future<ui.Image> _loadImage() async {
+    final Completer<ui.Image> completer = Completer<ui.Image>();
+    ui.decodeImageFromPixels(
+      data,
+      256,
+      256,
+      ui.PixelFormat.rgba8888,
+      (ui.Image image) => completer.complete(image.clone()),
+      allowUpscaling: false,
+    );
+    return completer.future;
+  }
+
+  @override
+  void initState() {
+    super.initState();
+    streamSub();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return GestureDetector(
+        onTapDown: (details) {
+          var point = Point<int>(
+            details.localPosition.dx.floor(),
+            details.localPosition.dy.floor(),
+          );
+
+          __serverSquareData.paint(point, widget.color.getColor());
+        },
+        child: Stack(children: [
+          // Text(this.hashCode.toString()),
+          FutureBuilder<ui.Image>(
+            future: _loadImage(),
+            builder: getImage,
+          )
+        ]));
   }
 
-  void setImg(ui.Image data) {
-    if (mounted) {
+  Future<void> streamSub() async {
+    await for (var event in __serverSquareData.getSteam()) {
       setState(() {
-        img = data;
+        storePoint(event);
       });
     }
   }
 
-  @override
-  void initState() {
-    __serverSquareData = InMemorySquereData(widget.tile);
-    loadPoints();
-    super.initState();
-  }
+  void storePoint(MonitorReply dd) {
+    BPoint? lastPosition;
+    for (var point in dd.points) {
+      lastPosition = point.point;
+      var p = lastPosition;
+      final startByte = (p.x + p.y * 256) * 4;
 
-  Future<void> loadPoints() async {
-    // TODO: only update the image if the last update hapenned in less than 200ms
-    await for (var value in __serverSquareData.getSteam()) {
-      BPoint? lastPosition;
-      for (var point in value.points) {
-        lastPosition = point.point;
-        var p = lastPosition;
-        final startByte = (p.x + p.y * 256) * 4;
-        List.generate(
-            4,
-            (index) =>
-                data[startByte + index] = point.color.rgba >> 8 * index & 0xff);
+      for (int index in [0, 1, 2, 3]) {
+        data[startByte + index] = point.color.rgba >> 8 * index & 0xff;
       }
-      renderImage();
     }
   }
 
-  @override
-  Widget build(BuildContext context) {
-    return GestureDetector(
-      onTapDown: (details) {
-        var point = Point<int>(
-          details.localPosition.dx.floor(),
-          details.localPosition.dy.floor(),
-        );
-        __serverSquareData.paint(point, widget.color.getColor());
-      },
-      child: RawImage(
-        image: img,
+  Widget getImage(BuildContext context, AsyncSnapshot<ui.Image> snapshot) {
+    if (snapshot.hasData) {
+      var image = snapshot.data?.clone();
+      // snapshot.data?.dispose();
+      return RawImage(
+        image: image,
         filterQuality: FilterQuality.none,
-      ),
-    );
+      );
+    } else if (snapshot.hasError) {
+      print('${snapshot.error}');
+      return Text('${snapshot.error}');
+    }
+    // By default, show a loading spinner.
+    return const CircularProgressIndicator();
   }
 
   @override
   void dispose() {
     super.dispose();
   }
-}
+}