LCOV - code coverage report
Current view: top level - src/ui/shared/utilities - element_finder.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 48 64 75.0 %
Date: 2020-12-04 18:41:24 Functions: 0 0 -

          Line data    Source code
       1             : import 'package:flutter/material.dart';
       2             : 
       3             : /// This class helps you find element within your app
       4             : /// use [searchChildElement] with a String containing key value
       5             : /// result is available in [result] and returns an [Element]
       6             : class ElementFinder {
       7             : 
       8             :   // Prefer use the navigatorContext to get full context tree
       9             :   final BuildContext context;
      10             : 
      11           6 :   ElementFinder(this.context);
      12             : 
      13             :   // this method scan all child recursively to get all widget bounds we could select for an helper
      14           3 :   Map<String, ElementModel> scan({Key omitChildsOf, bool debugMode = false}) {
      15           3 :     Map<String, ElementModel> results = Map<String, ElementModel>();
      16          12 :     context.visitChildElements((element) => _scanChildElement(
      17           6 :         context.findRenderObject(),
      18             :         element,
      19             :         results,
      20             :         omitChildsOf: omitChildsOf,
      21             :         debugMode: debugMode
      22             :       ));
      23             :     return results;
      24             :   }
      25             : 
      26             :   // List all pages from this context
      27           0 :   List<PageElement> scanPages() {
      28           0 :     var pages = List<PageElement>();
      29           0 :     context.visitChildElements((element) => _scanPageChildElement(element, pages));
      30             :     return pages;
      31             :   }
      32             : 
      33             :   // this method scan all child recursively to find a widget having a key == searchedKey
      34           3 :   ElementModel searchChildElement(String key) {
      35           3 :     ElementModel result = ElementModel.empty();
      36          12 :     context.visitChildElements((element) => _searchChildElement(element, key, result));
      37           3 :     if(result.element != null) {
      38          12 :       return _createElementModel(context.findRenderObject(), result.element);
      39             :     }
      40             :     return result;
      41             :   }
      42             : 
      43             :   /// This functions search for the maximum rect available space
      44             :   /// We use it for example to find the most available space to write a text in our anchored helper
      45           1 :   Rect getLargestAvailableSpace(ElementModel elementModel) {
      46           2 :     var parentObject = context.findRenderObject();
      47           1 :     var element = elementModel.element;
      48           3 :     var translation = element.renderObject.getTransformTo(parentObject).getTranslation();
      49           1 :     var objectX = translation.x;
      50           3 :     var objectEndX = objectX + element.size.width;
      51           1 :     var objectY = translation.y;
      52           3 :     var objectEndY = objectY + element.size.height;
      53           1 :     var layerRect = parentObject.paintBounds;
      54             : 
      55             :     Rect availableHSpace;
      56             :     Rect availableWSpace;
      57           3 :     if(objectY > layerRect.height - objectEndY) {
      58           0 :       availableHSpace = Rect.fromLTWH(0, 0, layerRect.width, objectY);
      59             :     } else {
      60           4 :       availableHSpace = Rect.fromLTWH(0, objectEndY, layerRect.width, layerRect.height - objectEndY);
      61             :     }
      62           3 :     if(objectX > layerRect.width - objectEndX) {
      63           0 :       availableWSpace = Rect.fromLTWH(0, 0, objectX, layerRect.height);
      64             :     } else {
      65           4 :       availableWSpace = Rect.fromLTWH(objectEndX, 0, layerRect.width - objectEndX, layerRect.height);
      66             :     }
      67             :     // check area to use the largest
      68           5 :     var availableHSpaceArea =  availableHSpace.size.width * availableHSpace.size.height;
      69           5 :     var availableWSpaceArea =  availableWSpace.size.width * availableWSpace.size.height;
      70             :     const MIN_WRITABLE_SPACE = 100;
      71           1 :     if(availableWSpaceArea > availableHSpaceArea && availableWSpace.width > MIN_WRITABLE_SPACE) {
      72             :       return availableWSpace;
      73             :     }
      74             :     return availableHSpace;
      75             :   }
      76             : 
      77             :   // -----------------------------------------------------------
      78             :   // private
      79             :   // -----------------------------------------------------------
      80           3 :   _searchChildElement(Element element, String key, ElementModel result, {int n = 0}) {
      81          21 :     if(result.element == null && element.widget.key != null && element.widget.key.toString().contains(key)) {
      82           3 :       result.element = element;
      83             :     }
      84           3 :     if(result.element != null) {
      85             :       return;
      86             :     }
      87          12 :     element.visitChildElements((visitor) => _searchChildElement(visitor, key, result, n: n + 1));
      88             :   }
      89             : 
      90             :   // omits elements with key starting with anything other than [<
      91             :   // flutter makes key with "[<_myKey_>]" for our keys
      92             :   // scan all elements in the current page tree and add their bounds to the results map
      93           3 :   _scanChildElement(RenderObject parentObject, Element element, Map<String, ElementModel> results, {int n = 0, Key omitChildsOf, bool debugMode = true}) {
      94             :     if(debugMode) {
      95           0 :       var nbChilds = element.debugDescribeChildren().length;
      96           0 :       var pre = StringBuffer();
      97           0 :       for(int i = 0; i<n ; i++) {
      98           0 :         pre.write(" ");
      99             :       }
     100           0 :       print("$pre ${element?.widget.runtimeType}  $n => $nbChilds ");
     101             :     }
     102           6 :     if(element.widget.key != null && omitChildsOf !=null && element.widget.key.toString() == omitChildsOf.toString()) {
     103             :       return;
     104             :     }
     105          30 :     if(element.widget.key != null && element.widget.key.toString().startsWith("[<") && !results.containsKey(element.widget.key.toString())) {
     106             :       if(debugMode) {
     107           0 :         print("  added ${element?.widget?.key.toString()} : $n");
     108             :       }
     109           3 :       var model = _createElementModel(parentObject, element);
     110          30 :       if(results.values.firstWhere((element) => element.bounds == model.bounds && element.offset == model.offset, orElse: () => null) == null) {
     111          15 :         results.putIfAbsent(element.widget.key.toString(), () => model);
     112             :       }
     113             :     }
     114          12 :     element.visitChildElements((visitor) =>  _scanChildElement(parentObject, visitor, results, n: n + 1, omitChildsOf: omitChildsOf, debugMode: debugMode));
     115             :   }
     116             : 
     117             :   // search first entries that contains our pages
     118           0 :   _scanPageChildElement(Element element, List<PageElement> pages) {
     119           0 :     if(element.runtimeType.toString() == "_Theatre") {
     120           0 :       element.visitChildElements((visitor) => pages.add(PageElement(element)));
     121             :     } else {
     122           0 :       element.visitChildElements((visitor) => _scanPageChildElement(element, pages));
     123             :     }
     124             :   }
     125             : 
     126           3 :   ElementModel _createElementModel(RenderObject parentObject, Element element) {
     127           3 :     var renderObject = element.findRenderObject();
     128           6 :     var bounds = element.findRenderObject().paintBounds;
     129           6 :     var translation = renderObject.getTransformTo(parentObject).getTranslation();
     130           9 :     var offset = Offset(translation.x, translation.y);
     131           3 :     return ElementModel(
     132           9 :       element.widget.key.toString(),
     133             :       bounds,
     134             :       offset,
     135           6 :       element.widget.runtimeType,
     136             :       element: element
     137             :     );
     138             :   }
     139             : }
     140             : 
     141             : class PageElement {
     142             : 
     143             :   Element element;
     144             : 
     145           0 :   PageElement(this.element);
     146             : }
     147             : 
     148             : class ElementModel {
     149             : 
     150             :   String key;
     151             : 
     152             :   Rect bounds;
     153             : 
     154             :   Offset offset;
     155             : 
     156             :   Element element;
     157             : 
     158             :   Type runtimeType;
     159             : 
     160           3 :   ElementModel(this.key, this.bounds, this.offset, this.runtimeType, {this.element});
     161             : 
     162           6 :   factory ElementModel.empty() => ElementModel(null, null, null, null);
     163             : }
     164             : 

Generated by: LCOV version 1.14