getAllLayouts method

Future<List<Map<String, dynamic>>> getAllLayouts()

Retrieves and processes information about the widgets in the current Flutter widget tree and returns a list of layout data structures.

These layout data structures contain information about the position, size, and other properties of the widgets in the tree.

Returns: A list of layout data structures. Each layout data structure is a map.

Implementation

Future<List<Map<String, dynamic>>> getAllLayouts() async {
  final List<Map<String, dynamic>> layouts = [];
  final List<dynamic> pathList = WidgetPath.entryList();
  final int pathCount = pathList.length;
  bool hasGestures = false;

  if (createRootLayout) {
    layouts.add(createRootLayoutControl());
  }

  for (dynamic entry in pathList) {
    final MapEntry<int, dynamic> widgetEntry =
        entry as MapEntry<int, dynamic>;
    final int key = widgetEntry.key;
    final WidgetPath wp = widgetEntry.value as WidgetPath;
    final BuildContext? context = wp.context;

    if (context == null) {
      tlLogger.w('Context null for path (removed): ${wp.path}');
      WidgetPath.removePath(key);
      continue;
    }
    final String contextString = context.toString();
    if (contextString.startsWith('State') &&
        contextString.endsWith('(DEFUNCT)(no widget)')) {
      tlLogger
          .v("Deleting obsolete path item: $key, context: $contextString");
      WidgetPath.removePath(key);
      continue;
    }
    final Widget widget = context.widget;
    final Map<String, dynamic> args = wp.parameters;
    final String? type = args['type'] ?? '';
    final String? subType = args['subType'] ?? '';

    wp.usedInLayout = true;

    if (type != null && type.compareTo("GestureDetector") == 0) {
      hasGestures = true;
    } else if (subType != null) {
      final String path = wp.widgetPath();
      final dynamic getData = args['data'];
      Map<String, dynamic>? aStyle;
      Map<String, dynamic>? font;
      Map<String, dynamic>? image;
      String? text;

      Map<String, dynamic>? accessibility = args['accessibility'];
      bool? maskingEnabled = await getMaskingEnabled();
      bool masked = maskingEnabled! &&
          (maskIds!.contains(path) || maskIds!.contains(wp.widgetDigest()));

      if (subType.compareTo("ImageView") == 0) {
        image = await getData(widget);
        if (image == null) {
          tlLogger.v("Image is empty!");
          continue;
        }
        tlLogger.v('Image is available: ${widget.runtimeType.toString()}');
      } else if (subType.compareTo("TextView") == 0) {
        text = getData(widget) ?? '';

        final TextStyle style = args['style'] ?? TextStyle();
        final TextAlign align = args['align'] ?? TextAlign.left;

        if (maskingEnabled && !masked && maskValuePatterns != null) {
          for (final String pattern in maskValuePatterns!) {
            if (text!.contains(RegExp(pattern))) {
              masked = true;
              tlLogger.v(
                  'Masking matched content with RE: $pattern, text: $text');
              break;
            }
          }
        }
        if (masked) {
          try {
            text = await maskText(text!);
          } on TealeafException catch (te) {
            tlLogger.v('Unable to mask text. ${te.getMsg}');
          }

          tlLogger.v(
              "Text Layout masked text: $text, Widget: ${widget.runtimeType.toString()}, "
              "Digest for MASKING: ${wp.widgetDigest()}");
        } else {
          tlLogger.v(
              "Text Layout text: $text, Widget: ${widget.runtimeType.toString()}");
        }

        font = {
          'family': style.fontFamily,
          'size': style.fontSize.toString(),
          'bold': (FontWeight.values.indexOf(style.fontWeight!) >
                  FontWeight.values.indexOf(FontWeight.normal))
              .toString(),
          'italic': (style.fontStyle == FontStyle.italic).toString()
        };

        double top = 0, bottom = 0, left = 0, right = 0;

        if (wp.parent!.widget is Padding) {
          final Padding padding = wp.parent!.widget as Padding;
          if (padding.padding is EdgeInsets) {
            final EdgeInsets eig = padding.padding as EdgeInsets;
            top = eig.top;
            bottom = eig.bottom;
            left = eig.left;
            right = eig.right;
          }
        }

        if (subType.compareTo("TextField") == 0) {
          var textField = widget as TextField;
          var controller = textField.controller;
          controller?.addListener(() { });
        }

        aStyle = {
          'textColor': (style.color!.value & 0xFFFFFF).toString(),
          'textAlphaColor': (style.color?.alpha ?? 0).toString(),
          'textAlphaBGColor': (style.backgroundColor?.alpha ?? 0).toString(),
          'textAlign': align.toString().split('.').last,
          'paddingBottom': bottom.toInt().toString(),
          'paddingTop': top.toInt().toString(),
          'paddingLeft': left.toInt().toString(),
          'paddingRight': right.toInt().toString(),
          'hidden': (style.color!.opacity == 1.0).toString(),
          'colorPrimary': (style.foreground?.color ?? 0).toString(),
          'colorPrimaryDark': 0.toString(), // TBD: Dark theme??
          'colorAccent': (style.decorationColor?.value ?? 0)
              .toString(), // TBD: are this the same??
        };
      }

      final RenderBox box = context.findRenderObject() as RenderBox;
      final Offset position = box.localToGlobal(Offset.zero);

      if (image != null) {
        tlLogger.v("Adding image to layouts....");
      }
      tlLogger.v(
          '--> Layout Flutter -- x: ${position.dx}, y: ${position.dy}, width: ${box.size.width.toInt()}, text: $text');

      layouts.add(<String, dynamic>{
        'id': path,
        'cssId': wp.widgetDigest(),
        'idType': (-4).toString(),
        'tlType': (image != null)
            ? 'image'
            : (text != null && text.contains('\n') ? 'textArea' : 'label'),
        'type': type,
        'subType': subType,
        'position': <String, String>{
          'x': position.dx.toInt().toString(),
          'y': position.dy.toInt().toString(),
          'width': box.size.width.toInt().toString(),
          'height': box.size.height.toInt().toString(),
        },
        'zIndex': "501",
        'currState': <String, dynamic>{
          'text': text,
          'placeHolder': "", // TBD??
          'font': font
        },
        if (image != null) 'image': image,
        if (aStyle != null) 'style': aStyle,
        if (accessibility != null) 'accessibility': accessibility,
        'originalId': path.replaceAll("/", ""),
        'masked': '$masked'
      });
    }
  }
  layoutParametersForGestures =
      hasGestures ? List.unmodifiable(layouts) : null;

  tlLogger.v(
      "WigetPath cache size, before: $pathCount, after: ${WidgetPath.size}, # of layouts: ${layouts.length}");

  return layouts;
}