diff --git a/.circleci/config.yml b/.circleci/config.yml index ac1b6f299e..010547222b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -32,3 +32,9 @@ jobs: command: melos run gen_coverage - codecov/upload: file: coverage_report/lcov.info + - run: + name: Run flutter analyze + command: melos run analyze + - run: + name: Check That Flutter Code is Formatted Correctly + command: flutter format -o none --set-exit-if-changed . diff --git a/analysis_options.yaml b/analysis_options.yaml new file mode 100644 index 0000000000..f065cf1ea4 --- /dev/null +++ b/analysis_options.yaml @@ -0,0 +1,29 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:flutter_lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at + # https://dart-lang.github.io/linter/lints/index.html. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options \ No newline at end of file diff --git a/example/lib/main.dart b/example/lib/main.dart index eea3fc5cc1..8ff39ed120 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,31 +1,32 @@ import 'package:flutter/material.dart'; import 'package:flutter_html/flutter_html.dart'; import 'package:flutter_html_all/flutter_html_all.dart'; -import 'package:flutter_math_fork/flutter_math.dart'; -void main() => runApp(new MyApp()); +void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { + const MyApp({super.key}); + // This widget is the root of your application. @override Widget build(BuildContext context) { - return new MaterialApp( + return MaterialApp( title: 'Flutter Demo', - theme: new ThemeData( + theme: ThemeData( primarySwatch: Colors.deepPurple, ), - home: new MyHomePage(title: 'flutter_html Example'), + home: const MyHomePage(title: 'flutter_html Example'), ); } } class MyHomePage extends StatefulWidget { - MyHomePage({Key? key, required this.title}) : super(key: key); + const MyHomePage({Key? key, required this.title}) : super(key: key); final String title; @override - _MyHomePageState createState() => new _MyHomePageState(); + MyHomePageState createState() => MyHomePageState(); } const htmlData = r""" @@ -66,9 +67,9 @@ const htmlData = r"""
margin: 15px auto
margin-left: auto

With an image - non-block (should not center):

- +

block image (should center):

- +

Table support (with custom styling!):

Famous quote... @@ -253,18 +254,19 @@ const htmlData = r""" final staticAnchorKey = GlobalKey(); -class _MyHomePageState extends State { +class MyHomePageState extends State { @override Widget build(BuildContext context) { - return new Scaffold( + return Scaffold( appBar: AppBar( - title: Text('flutter_html Example'), + title: const Text('flutter_html Example'), centerTitle: true, ), floatingActionButton: FloatingActionButton( - child: Icon(Icons.arrow_downward), + child: const Icon(Icons.arrow_downward), onPressed: () { - final anchorContext = AnchorKey.forId(staticAnchorKey, "bottom")?.currentContext; + final anchorContext = + AnchorKey.forId(staticAnchorKey, "bottom")?.currentContext; if (anchorContext != null) { Scrollable.ensureVisible(anchorContext); } @@ -276,85 +278,99 @@ class _MyHomePageState extends State { data: htmlData, style: { "table": Style( - backgroundColor: Color.fromARGB(0x50, 0xee, 0xee, 0xee), + backgroundColor: const Color.fromARGB(0x50, 0xee, 0xee, 0xee), ), "tr": Style( - border: Border(bottom: BorderSide(color: Colors.grey)), + border: const Border(bottom: BorderSide(color: Colors.grey)), ), "th": Style( - padding: EdgeInsets.all(6), + padding: const EdgeInsets.all(6), backgroundColor: Colors.grey, ), "td": Style( - padding: EdgeInsets.all(6), + padding: const EdgeInsets.all(6), alignment: Alignment.topLeft, ), 'h5': Style(maxLines: 2, textOverflow: TextOverflow.ellipsis), }, tagsList: Html.tags..addAll(['tex', 'bird', 'flutter']), customRenders: { - tagMatcher("tex"): CustomRender.widget(widget: (context, buildChildren) => Math.tex( - context.tree.element?.innerHtml ?? '', - mathStyle: MathStyle.display, - textStyle: context.style.generateTextStyle(), - onErrorFallback: (FlutterMathException e) { - return Text(e.message); - }, - )), - tagMatcher("bird"): CustomRender.inlineSpan(inlineSpan: (context, buildChildren) => TextSpan(text: "🐦")), - tagMatcher("flutter"): CustomRender.widget(widget: (context, buildChildren) => FlutterLogo( - style: (context.tree.element!.attributes['horizontal'] != null) - ? FlutterLogoStyle.horizontal - : FlutterLogoStyle.markOnly, - textColor: context.style.color!, - size: context.style.fontSize!.value * 5, - )), - tagMatcher("table"): CustomRender.widget(widget: (context, buildChildren) => SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: tableRender.call().widget!.call(context, buildChildren), - )), + tagMatcher("tex"): CustomRender.widget( + widget: (context, buildChildren) => Math.tex( + context.tree.element?.innerHtml ?? '', + mathStyle: MathStyle.display, + textStyle: context.style.generateTextStyle(), + onErrorFallback: (FlutterMathException e) { + return Text(e.message); + }, + )), + tagMatcher("bird"): CustomRender.inlineSpan( + inlineSpan: (context, buildChildren) => + const TextSpan(text: "🐦")), + tagMatcher("flutter"): CustomRender.widget( + widget: (context, buildChildren) => FlutterLogo( + style: (context.tree.element!.attributes['horizontal'] != + null) + ? FlutterLogoStyle.horizontal + : FlutterLogoStyle.markOnly, + textColor: context.style.color!, + size: context.style.fontSize!.value * 5, + )), + tagMatcher("table"): CustomRender.widget( + widget: (context, buildChildren) => SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: tableRender + .call() + .widget! + .call(context, buildChildren), + )), audioMatcher(): audioRender(), iframeMatcher(): iframeRender(), - mathMatcher(): mathRender(onMathError: (error, exception, exceptionWithType) { - print(exception); + mathMatcher(): + mathRender(onMathError: (error, exception, exceptionWithType) { + debugPrint(exception); return Text(exception); }), svgTagMatcher(): svgTagRender(), svgDataUriMatcher(): svgDataImageRender(), svgAssetUriMatcher(): svgAssetImageRender(), svgNetworkSourceMatcher(): svgNetworkImageRender(), - networkSourceMatcher(domains: ["flutter.dev"]): CustomRender.widget( - widget: (context, buildChildren) { - return FlutterLogo(size: 36); - }), + networkSourceMatcher(domains: ["flutter.dev"]): + CustomRender.widget(widget: (context, buildChildren) { + return const FlutterLogo(size: 36); + }), networkSourceMatcher(domains: ["mydomain.com"]): networkImageRender( headers: {"Custom-Header": "some-value"}, altWidget: (alt) => Text(alt ?? ""), - loadingWidget: () => Text("Loading..."), + loadingWidget: () => const Text("Loading..."), ), // On relative paths starting with /wiki, prefix with a base url - (context) => context.tree.element?.attributes["src"] != null - && context.tree.element!.attributes["src"]!.startsWith("/wiki"): - networkImageRender(mapUrl: (url) => "https://upload.wikimedia.org" + url!), + (context) => + context.tree.element?.attributes["src"] != null && + context.tree.element!.attributes["src"]! + .startsWith("/wiki"): networkImageRender( + mapUrl: (url) => "https://upload.wikimedia.org${url!}"), // Custom placeholder image for broken links - networkSourceMatcher(): networkImageRender(altWidget: (_) => FlutterLogo()), + networkSourceMatcher(): + networkImageRender(altWidget: (_) => const FlutterLogo()), videoMatcher(): videoRender(), }, onLinkTap: (url, _, __, ___) { - print("Opening $url..."); + debugPrint("Opening $url..."); }, onImageTap: (src, _, __, ___) { - print(src); + debugPrint(src); }, onImageError: (exception, stackTrace) { - print(exception); + debugPrint(exception.toString()); }, onCssParseError: (css, messages) { - print("css that errored: $css"); - print("error messages:"); - messages.forEach((element) { - print(element); - }); + debugPrint("css that errored: $css"); + debugPrint("error messages:"); + for (var element in messages) { + debugPrint(element.toString()); + } + return ''; }, ), ), @@ -362,8 +378,11 @@ class _MyHomePageState extends State { } } -CustomRenderMatcher texMatcher() => (context) => context.tree.element?.localName == 'tex'; +CustomRenderMatcher texMatcher() => + (context) => context.tree.element?.localName == 'tex'; -CustomRenderMatcher birdMatcher() => (context) => context.tree.element?.localName == 'bird'; +CustomRenderMatcher birdMatcher() => + (context) => context.tree.element?.localName == 'bird'; -CustomRenderMatcher flutterMatcher() => (context) => context.tree.element?.localName == 'flutter'; +CustomRenderMatcher flutterMatcher() => + (context) => context.tree.element?.localName == 'flutter'; diff --git a/example/pubspec.yaml b/example/pubspec.yaml index ffde7654f9..71e0332d40 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -17,6 +17,7 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter + flutter_lints: ^2.0.1 flutter: diff --git a/lib/custom_render.dart b/lib/custom_render.dart index 27d15f13ff..35e678beec 100644 --- a/lib/custom_render.dart +++ b/lib/custom_render.dart @@ -16,14 +16,14 @@ CustomRenderMatcher tagMatcher(String tag) => (context) { }; CustomRenderMatcher blockElementMatcher() => (context) { - return (context.tree.style.display == Display.BLOCK || - context.tree.style.display == Display.INLINE_BLOCK) && + return (context.tree.style.display == Display.block || + context.tree.style.display == Display.inlineBlock) && (context.tree.children.isNotEmpty || context.tree.element?.localName == "hr"); }; CustomRenderMatcher listElementMatcher() => (context) { - return context.tree.style.display == Display.LIST_ITEM; + return context.tree.style.display == Display.listItem; }; CustomRenderMatcher replacedElementMatcher() => (context) { @@ -44,7 +44,7 @@ CustomRenderMatcher dataUriMatcher( }; CustomRenderMatcher networkSourceMatcher({ - List schemas: const ["https", "http"], + List schemas = const ["https", "http"], List? domains, String? extension, }) => @@ -81,7 +81,7 @@ CustomRenderMatcher layoutElementMatcher() => (context) { CustomRenderMatcher verticalAlignMatcher() => (context) { return context.tree.style.verticalAlign != null && - context.tree.style.verticalAlign != VerticalAlign.BASELINE; + context.tree.style.verticalAlign != VerticalAlign.baseline; }; CustomRenderMatcher fallbackMatcher() => (context) { @@ -120,10 +120,10 @@ CustomRender blockElementRender({Style? style, List? children}) => .expandIndexed((i, childTree) => [ context.parser.parseTree(context, childTree), if (i != context.tree.children.length - 1 && - childTree.style.display == Display.BLOCK && + childTree.style.display == Display.block && childTree.element?.localName != "html" && childTree.element?.localName != "body") - TextSpan(text: "\n"), + const TextSpan(text: "\n"), ]) .toList(), ); @@ -136,17 +136,17 @@ CustomRender blockElementRender({Style? style, List? children}) => style: style ?? context.tree.style, shrinkWrap: context.parser.shrinkWrap, childIsReplaced: - REPLACED_EXTERNAL_ELEMENTS.contains(context.tree.name), + HtmlElements.replacedExternalElements.contains(context.tree.name), children: children ?? context.tree.children .expandIndexed((i, childTree) => [ context.parser.parseTree(context, childTree), //TODO can this newline be added in a different step? if (i != context.tree.children.length - 1 && - childTree.style.display == Display.BLOCK && + childTree.style.display == Display.block && childTree.element?.localName != "html" && childTree.element?.localName != "body") - TextSpan(text: "\n"), + const TextSpan(text: "\n"), ]) .toList(), ), @@ -168,7 +168,7 @@ CustomRender listElementRender( children: [ (style?.listStylePosition ?? context.tree.style.listStylePosition) == - ListStylePosition.OUTSIDE + ListStylePosition.outside ? Padding( padding: style?.padding?.nonNegative ?? context.tree.style.padding?.nonNegative ?? @@ -185,15 +185,15 @@ CustomRender listElementRender( : 0.0), child: style?.markerContent ?? context.style.markerContent) - : Container(height: 0, width: 0), - Text("\u0020", + : const SizedBox(height: 0, width: 0), + const Text("\u0020", textAlign: TextAlign.right, style: TextStyle(fontWeight: FontWeight.w400)), Expanded( child: Padding( padding: (style?.listStylePosition ?? context.tree.style.listStylePosition) == - ListStylePosition.INSIDE + ListStylePosition.inside ? EdgeInsets.only( left: (style?.direction ?? context.tree.style.direction) != @@ -214,13 +214,13 @@ CustomRender listElementRender( ..insertAll( 0, context.tree.style.listStylePosition == - ListStylePosition.INSIDE + ListStylePosition.inside ? [ WidgetSpan( alignment: PlaceholderAlignment.middle, child: style?.markerContent ?? context.style.markerContent ?? - Container(height: 0, width: 0)) + const SizedBox(height: 0, width: 0)) ] : []), style: style ?? context.style, @@ -370,16 +370,20 @@ CustomRender networkImageRender({ if (!completer.isCompleted) { context.parser.cachedImageSizes[src] = size; completer.complete(size); - image.image.resolve(ImageConfiguration()).removeListener(listener!); + image.image + .resolve(const ImageConfiguration()) + .removeListener(listener!); } }, onError: (object, stacktrace) { if (!completer.isCompleted) { completer.completeError(object); - image.image.resolve(ImageConfiguration()).removeListener(listener!); + image.image + .resolve(const ImageConfiguration()) + .removeListener(listener!); } }); - image.image.resolve(ImageConfiguration()).addListener(listener); + image.image.resolve(const ImageConfiguration()).addListener(listener); } final attributes = context.tree.element!.attributes.cast(); @@ -487,12 +491,12 @@ CustomRender fallbackRender({Style? style, List? children}) => children: context.tree.children .expand((tree) => [ context.parser.parseTree(context, tree), - if (tree.style.display == Display.BLOCK && + if (tree.style.display == Display.block && tree.element?.parent?.localName != "th" && tree.element?.parent?.localName != "td" && tree.element?.localName != "html" && tree.element?.localName != "body") - TextSpan(text: "\n"), + const TextSpan(text: "\n"), ]) .toList(), )); @@ -516,8 +520,8 @@ Map generateDefaultRenders() { List _getListElementChildren( ListStylePosition? position, Function() buildChildren) { List children = buildChildren.call(); - if (position == ListStylePosition.INSIDE) { - final tabSpan = WidgetSpan( + if (position == ListStylePosition.inside) { + const tabSpan = WidgetSpan( child: Text("\t", textAlign: TextAlign.right, style: TextStyle(fontWeight: FontWeight.w400)), @@ -567,13 +571,13 @@ InlineSpan _getInteractableChildren(RenderContext context, } final _dataUriFormat = RegExp( - "^(?data):(?image\/[\\w\+\-\.]+)(?;base64)?\,(?.*)"); + "^(?data):(?image\\/[\\w\\+\\-\\.]+)(?;base64)?\\,(?.*)"); double _getVerticalOffset(StyledElement tree) { switch (tree.style.verticalAlign) { - case VerticalAlign.SUB: + case VerticalAlign.sub: return tree.style.fontSize!.value / 2.5; - case VerticalAlign.SUPER: + case VerticalAlign.sup: return tree.style.fontSize!.value / -2.5; default: return 0; @@ -618,5 +622,5 @@ double _aspectRatio( extension ClampedEdgeInsets on EdgeInsetsGeometry { EdgeInsetsGeometry get nonNegative => - this.clamp(EdgeInsets.zero, const EdgeInsets.all(double.infinity)); + clamp(EdgeInsets.zero, const EdgeInsets.all(double.infinity)); } diff --git a/lib/flutter_html.dart b/lib/flutter_html.dart index ec60476178..1b5d7fe55e 100644 --- a/lib/flutter_html.dart +++ b/lib/flutter_html.dart @@ -82,7 +82,7 @@ class Html extends StatefulWidget { this.style = const {}, }) : data = null, assert(document != null), - this.documentElement = document!.documentElement, + documentElement = document!.documentElement, _anchorKey = anchorKey ?? GlobalKey(), super(key: key); @@ -143,13 +143,13 @@ class Html extends StatefulWidget { /// An API that allows you to override the default style for any HTML element final Map style; - static List get tags => new List.from(STYLED_ELEMENTS) - ..addAll(INTERACTABLE_ELEMENTS) - ..addAll(REPLACED_ELEMENTS) - ..addAll(LAYOUT_ELEMENTS) - ..addAll(TABLE_CELL_ELEMENTS) - ..addAll(TABLE_DEFINITION_ELEMENTS) - ..addAll(EXTERNAL_ELEMENTS); + static List get tags => List.from(HtmlElements.styledElements) + ..addAll(HtmlElements.interactableElements) + ..addAll(HtmlElements.replacedElements) + ..addAll(HtmlElements.layoutElements) + ..addAll(HtmlElements.tableCellElements) + ..addAll(HtmlElements.tableDefinitionElements) + ..addAll(HtmlElements.externalElements); @override State createState() => _HtmlState(); @@ -263,7 +263,7 @@ class SelectableHtml extends StatefulWidget { this.scrollPhysics, }) : data = null, assert(document != null), - this.documentElement = document!.documentElement, + documentElement = document!.documentElement, _anchorKey = anchorKey ?? GlobalKey(), super(key: key); @@ -327,7 +327,8 @@ class SelectableHtml extends StatefulWidget { /// fallback to the default rendering. final Map customRenders; - static List get tags => new List.from(SELECTABLE_ELEMENTS); + static List get tags => + List.from(HtmlElements.selectableElements); @override State createState() => _SelectableHtmlState(); @@ -346,7 +347,7 @@ class _SelectableHtmlState extends State { @override Widget build(BuildContext context) { - return Container( + return SizedBox( width: widget.shrinkWrap ? null : MediaQuery.of(context).size.width, child: HtmlParser( key: widget._anchorKey, diff --git a/lib/html_parser.dart b/lib/html_parser.dart index 7ed4e959af..8d73cc5d18 100644 --- a/lib/html_parser.dart +++ b/lib/html_parser.dart @@ -25,7 +25,6 @@ typedef OnCssParseError = String? Function( ); class HtmlParser extends StatelessWidget { - final Key? key; final dom.Element htmlData; final OnTap? onLinkTap; final OnTap? onAnchorTap; @@ -46,7 +45,7 @@ class HtmlParser extends StatelessWidget { final Map cachedImageSizes = {}; HtmlParser({ - required this.key, + required super.key, required this.htmlData, required this.onLinkTap, required this.onAnchorTap, @@ -61,12 +60,8 @@ class HtmlParser extends StatelessWidget { this.root, this.selectionControls, this.scrollPhysics, - }) : this.internalOnAnchorTap = onAnchorTap != null - ? onAnchorTap - : key != null - ? _handleAnchorTap(key, onLinkTap) - : onLinkTap, - super(key: key); + }) : internalOnAnchorTap = onAnchorTap ?? + (key != null ? _handleAnchorTap(key, onLinkTap) : onLinkTap); /// As the widget [build]s, the HTML data is processed into a tree of [StyledElement]s, /// which are then parsed into an [InlineSpan] tree that is then rendered to the screen by Flutter @@ -137,7 +132,7 @@ class HtmlParser extends StatelessWidget { style: Style.fromTextStyle(Theme.of(context).textTheme.bodyText2!), ); - html.nodes.forEach((node) { + for (var node in html.nodes) { tree.children.add(_recursiveLexer( node, customRenderMatchers, @@ -145,7 +140,7 @@ class HtmlParser extends StatelessWidget { context, parser, )); - }); + } return tree; } @@ -163,7 +158,7 @@ class HtmlParser extends StatelessWidget { ) { List children = []; - node.nodes.forEach((childNode) { + for (var childNode in node.nodes) { children.add(_recursiveLexer( childNode, customRenderMatchers, @@ -171,24 +166,25 @@ class HtmlParser extends StatelessWidget { context, parser, )); - }); + } //TODO(Sub6Resources): There's probably a more efficient way to look this up. if (node is dom.Element) { if (!tagsList.contains(node.localName)) { return EmptyContentElement(); } - if (STYLED_ELEMENTS.contains(node.localName)) { + if (HtmlElements.styledElements.contains(node.localName)) { return parseStyledElement(node, children); - } else if (INTERACTABLE_ELEMENTS.contains(node.localName)) { + } else if (HtmlElements.interactableElements.contains(node.localName)) { return parseInteractableElement(node, children); - } else if (REPLACED_ELEMENTS.contains(node.localName)) { + } else if (HtmlElements.replacedElements.contains(node.localName)) { return parseReplacedElement(node, children); - } else if (LAYOUT_ELEMENTS.contains(node.localName)) { + } else if (HtmlElements.layoutElements.contains(node.localName)) { return parseLayoutElement(node, children); - } else if (TABLE_CELL_ELEMENTS.contains(node.localName)) { + } else if (HtmlElements.tableCellElements.contains(node.localName)) { return parseTableCellElement(node, children); - } else if (TABLE_DEFINITION_ELEMENTS.contains(node.localName)) { + } else if (HtmlElements.tableDefinitionElements + .contains(node.localName)) { return parseTableDefinitionElement(node, children); } else { final StyledElement tree = parseStyledElement(node, children); @@ -245,7 +241,9 @@ class HtmlParser extends StatelessWidget { } catch (_) {} }); - tree.children.forEach((e) => _applyExternalCss(declarations, e)); + for (var element in tree.children) { + _applyExternalCss(declarations, element); + } return tree; } @@ -259,7 +257,9 @@ class HtmlParser extends StatelessWidget { } } - tree.children.forEach((e) => _applyInlineStyles(e, errorHandler)); + for (var element in tree.children) { + _applyInlineStyles(element, errorHandler); + } return tree; } @@ -274,7 +274,9 @@ class HtmlParser extends StatelessWidget { } } catch (_) {} }); - tree.children.forEach((e) => _applyCustomStyles(style, e)); + for (var element in tree.children) { + _applyCustomStyles(style, element); + } return tree; } @@ -283,10 +285,10 @@ class HtmlParser extends StatelessWidget { /// child that doesn't specify a different style. static StyledElement _cascadeStyles( Map style, StyledElement tree) { - tree.children.forEach((child) { + for (var child in tree.children) { child.style = tree.style.copyOnlyInherited(child.style); _cascadeStyles(style, child); - }); + } return tree; } @@ -342,11 +344,11 @@ class HtmlParser extends StatelessWidget { for (final entry in customRenders.keys) { if (entry.call(newContext)) { - final buildChildren = () => + buildChildren() => tree.children.map((tree) => parseTree(newContext, tree)).toList(); if (newContext.parser.selectable && customRenders[entry] is SelectableCustomRender) { - final selectableBuildChildren = () => tree.children + selectableBuildChildren() => tree.children .map((tree) => parseTree(newContext, tree) as TextSpan) .toList(); return (customRenders[entry] as SelectableCustomRender) @@ -367,14 +369,14 @@ class HtmlParser extends StatelessWidget { child: CssBoxWidget( style: tree.style, shrinkWrap: newContext.parser.shrinkWrap, + childIsReplaced: true, //TODO is this true? child: customRenders[entry]!.widget!.call(newContext, buildChildren), - childIsReplaced: true, //TODO is this true? ), ); } } - return WidgetSpan(child: Container(height: 0, width: 0)); + return const WidgetSpan(child: SizedBox(height: 0, width: 0)); } static OnTap _handleAnchorTap(Key key, OnTap? onLinkTap) => (String? url, @@ -398,7 +400,7 @@ class HtmlParser extends StatelessWidget { /// at https://www.w3.org/TR/css-text-3/ /// and summarized at https://medium.com/@patrickbrosset/when-does-white-space-matter-in-html-b90e8a7cdd33 static StyledElement _processInternalWhitespace(StyledElement tree) { - if ((tree.style.whiteSpace ?? WhiteSpace.NORMAL) == WhiteSpace.PRE) { + if ((tree.style.whiteSpace ?? WhiteSpace.normal) == WhiteSpace.pre) { // Preserve this whitespace } else if (tree is TextContentElement) { tree.text = _removeUnnecessaryWhitespace(tree.text!); @@ -479,7 +481,7 @@ class HtmlParser extends StatelessWidget { if (textIndex < 1 && tree.text!.startsWith(' ') && tree.element?.localName != "br" && - (!keepLeadingSpace.data || tree.style.display == Display.BLOCK) && + (!keepLeadingSpace.data || tree.style.display == Display.block) && (elementIndex < 1 || (elementIndex >= 1 && parentNodes?[elementIndex - 1] is dom.Text && @@ -505,8 +507,9 @@ class HtmlParser extends StatelessWidget { } } - tree.children - .forEach((e) => _processInlineWhitespaceRecursive(e, keepLeadingSpace)); + for (var element in tree.children) { + _processInlineWhitespaceRecursive(element, keepLeadingSpace); + } return tree; } @@ -520,8 +523,8 @@ class HtmlParser extends StatelessWidget { /// (4) Replace any instances of two or more spaces with a single space. static String _removeUnnecessaryWhitespace(String text) { return text - .replaceAll(RegExp("\ *(?=\n)"), "\n") - .replaceAll(RegExp("(?:\n)\ *"), "\n") + .replaceAll(RegExp("\\ *(?=\n)"), "\n") + .replaceAll(RegExp("(?:\n)\\ *"), "\n") .replaceAll("\n", " ") .replaceAll("\t", " ") .replaceAll(RegExp(" {2,}"), " "); @@ -540,17 +543,15 @@ class HtmlParser extends StatelessWidget { /// bullet all list items according to the [ListStyleType] they have been given. static StyledElement _processListCharactersRecursive( StyledElement tree, ListQueue olStack) { - if (tree.style.listStylePosition == null) { - tree.style.listStylePosition = ListStylePosition.OUTSIDE; - } + tree.style.listStylePosition ??= ListStylePosition.outside; if (tree.name == 'ol' && tree.style.listStyleType != null && tree.style.listStyleType!.type == "marker") { switch (tree.style.listStyleType!) { - case ListStyleType.LOWER_LATIN: - case ListStyleType.LOWER_ALPHA: - case ListStyleType.UPPER_LATIN: - case ListStyleType.UPPER_ALPHA: + case ListStyleType.lowerLatin: + case ListStyleType.lowerAlpha: + case ListStyleType.upperLatin: + case ListStyleType.upperAlpha: olStack.add(Context('a')); if ((tree.attributes['start'] != null ? int.tryParse(tree.attributes['start']!) @@ -571,30 +572,30 @@ class HtmlParser extends StatelessWidget { 1)); break; } - } else if (tree.style.display == Display.LIST_ITEM && + } else if (tree.style.display == Display.listItem && tree.style.listStyleType != null && tree.style.listStyleType!.type == "widget") { tree.style.markerContent = tree.style.listStyleType!.widget!; - } else if (tree.style.display == Display.LIST_ITEM && + } else if (tree.style.display == Display.listItem && tree.style.listStyleType != null && tree.style.listStyleType!.type == "image") { tree.style.markerContent = Image.network(tree.style.listStyleType!.text); - } else if (tree.style.display == Display.LIST_ITEM && + } else if (tree.style.display == Display.listItem && tree.style.listStyleType != null) { String marker = ""; switch (tree.style.listStyleType!) { - case ListStyleType.NONE: + case ListStyleType.none: break; - case ListStyleType.CIRCLE: + case ListStyleType.circle: marker = '○'; break; - case ListStyleType.SQUARE: + case ListStyleType.square: marker = '■'; break; - case ListStyleType.DISC: + case ListStyleType.disc: marker = '•'; break; - case ListStyleType.DECIMAL: + case ListStyleType.decimal: if (olStack.isEmpty) { olStack.add(Context((tree.attributes['start'] != null ? int.tryParse(tree.attributes['start'] ?? "") ?? 1 @@ -604,8 +605,8 @@ class HtmlParser extends StatelessWidget { olStack.last.data += 1; marker = '${olStack.last.data}.'; break; - case ListStyleType.LOWER_LATIN: - case ListStyleType.LOWER_ALPHA: + case ListStyleType.lowerLatin: + case ListStyleType.lowerAlpha: if (olStack.isEmpty) { olStack.add(Context('a')); if ((tree.attributes['start'] != null @@ -620,11 +621,11 @@ class HtmlParser extends StatelessWidget { } } } - marker = olStack.last.data.toString() + "."; + marker = "${olStack.last.data}."; olStack.last.data = olStack.last.data.toString().nextLetter(); break; - case ListStyleType.UPPER_LATIN: - case ListStyleType.UPPER_ALPHA: + case ListStyleType.upperLatin: + case ListStyleType.upperAlpha: if (olStack.isEmpty) { olStack.add(Context('a')); if ((tree.attributes['start'] != null @@ -639,10 +640,10 @@ class HtmlParser extends StatelessWidget { } } } - marker = olStack.last.data.toString().toUpperCase() + "."; + marker = "${olStack.last.data.toString().toUpperCase()}."; olStack.last.data = olStack.last.data.toString().nextLetter(); break; - case ListStyleType.LOWER_ROMAN: + case ListStyleType.lowerRoman: if (olStack.isEmpty) { olStack.add(Context((tree.attributes['start'] != null ? int.tryParse(tree.attributes['start'] ?? "") ?? 1 @@ -653,13 +654,11 @@ class HtmlParser extends StatelessWidget { if (olStack.last.data <= 0) { marker = '${olStack.last.data}.'; } else { - marker = (olStack.last.data as int) - .toRomanNumeralString()! - .toLowerCase() + - "."; + marker = + "${(olStack.last.data as int).toRomanNumeralString()!.toLowerCase()}."; } break; - case ListStyleType.UPPER_ROMAN: + case ListStyleType.upperRoman: if (olStack.isEmpty) { olStack.add(Context((tree.attributes['start'] != null ? int.tryParse(tree.attributes['start'] ?? "") ?? 1 @@ -670,7 +669,7 @@ class HtmlParser extends StatelessWidget { if (olStack.last.data <= 0) { marker = '${olStack.last.data}.'; } else { - marker = (olStack.last.data as int).toRomanNumeralString()! + "."; + marker = "${(olStack.last.data as int).toRomanNumeralString()!}."; } break; } @@ -681,7 +680,9 @@ class HtmlParser extends StatelessWidget { ); } - tree.children.forEach((e) => _processListCharactersRecursive(e, olStack)); + for (var element in tree.children) { + _processListCharactersRecursive(element, olStack); + } if (tree.name == 'ol') { olStack.removeLast(); @@ -700,7 +701,7 @@ class HtmlParser extends StatelessWidget { TextContentElement( text: tree.style.before, style: tree.style - .copyWith(beforeAfterNull: true, display: Display.INLINE), + .copyWith(beforeAfterNull: true, display: Display.inline), ), ); } @@ -708,7 +709,7 @@ class HtmlParser extends StatelessWidget { tree.children.add(TextContentElement( text: tree.style.after, style: - tree.style.copyWith(beforeAfterNull: true, display: Display.INLINE), + tree.style.copyWith(beforeAfterNull: true, display: Display.inline), )); } @@ -838,31 +839,31 @@ class HtmlParser extends StatelessWidget { ((tree.name == "body" && (index == 0 || index + 1 == tree.children.length || - tree.children[index - 1].style.display == Display.BLOCK || + tree.children[index - 1].style.display == Display.block || tree.children[index + 1].style.display == - Display.BLOCK)) || + Display.block)) || tree.name == "ul") && child.text!.replaceAll(' ', '').isEmpty) { toRemove.add(child); } else if (child is TextContentElement && child.text!.isEmpty && - child.style.whiteSpace != WhiteSpace.PRE) { + child.style.whiteSpace != WhiteSpace.pre) { toRemove.add(child); } else if (child is TextContentElement && - child.style.whiteSpace != WhiteSpace.PRE && - tree.style.display == Display.BLOCK && + child.style.whiteSpace != WhiteSpace.pre && + tree.style.display == Display.block && child.text!.isEmpty && lastChildBlock) { toRemove.add(child); - } else if (child.style.display == Display.NONE) { + } else if (child.style.display == Display.none) { toRemove.add(child); } else { _removeEmptyElements(child); } // This is used above to check if the previous element is a block element or a line break. - lastChildBlock = (child.style.display == Display.BLOCK || - child.style.display == Display.LIST_ITEM || + lastChildBlock = (child.style.display == Display.block || + child.style.display == Display.listItem || (child is TextContentElement && child.text == '\n')); }); tree.children.removeWhere((element) => toRemove.contains(element)); @@ -896,7 +897,7 @@ class HtmlParser extends StatelessWidget { final parentFontSize = tree.style.fontSize!.value; - tree.children.forEach((child) { + for (var child in tree.children) { if (child.style.fontSize == null) { child.style.fontSize = FontSize(parentFontSize); } else { @@ -928,7 +929,7 @@ class HtmlParser extends StatelessWidget { tree.style.setRelativeValues(remFontSize, emSize); _applyRelativeValuesRecursive(child, remFontSize, devicePixelRatio); - }); + } } } @@ -954,7 +955,7 @@ class RenderContext { extension IterateLetters on String { String nextLetter() { - String s = this.toLowerCase(); + String s = toLowerCase(); if (s == "z") { return String.fromCharCode(s.codeUnitAt(0) - 25) + String.fromCharCode(s.codeUnitAt(0) - 25); // AA or aa @@ -965,7 +966,7 @@ extension IterateLetters on String { // If a string of length > 1 ends in Z/z, // increment the string (excluding the last Z/z) recursively, // and append A/a (depending on casing) to it - return sub.nextLetter() + 'a'; + return '${sub.nextLetter()}a'; } else { // (take till last char) append with (increment last char) return sub + String.fromCharCode(lastChar.codeUnitAt(0) + 1); diff --git a/lib/src/css_box_widget.dart b/lib/src/css_box_widget.dart index 5bfffd82da..727095c0f4 100644 --- a/lib/src/css_box_widget.dart +++ b/lib/src/css_box_widget.dart @@ -5,18 +5,18 @@ import 'package:flutter/rendering.dart'; import 'package:flutter_html/flutter_html.dart'; class CssBoxWidget extends StatelessWidget { - CssBoxWidget({ - this.key, + const CssBoxWidget({ + super.key, required this.child, required this.style, this.textDirection, this.childIsReplaced = false, this.shrinkWrap = false, - }) : super(key: key); + }); /// Generates a CSSBoxWidget that contains a list of InlineSpan children. CssBoxWidget.withInlineSpanChildren({ - this.key, + super.key, required List children, required this.style, this.textDirection, @@ -25,18 +25,14 @@ class CssBoxWidget extends StatelessWidget { bool selectable = false, TextSelectionControls? selectionControls, ScrollPhysics? scrollPhysics, - }) : this.child = selectable + }) : child = selectable ? _generateSelectableWidgetChild( children, style, selectionControls, scrollPhysics, ) - : _generateWidgetChild(children, style), - super(key: key); - - /// An optional anchor key to use in finding this box - final AnchorKey? key; + : _generateWidgetChild(children, style); /// The child to be rendered within the CSS Box. final Widget child; @@ -67,7 +63,7 @@ class CssBoxWidget extends StatelessWidget { paddingSize: style.padding?.collapsedSize ?? Size.zero, borderSize: style.border?.dimensions.collapsedSize ?? Size.zero, margins: style.margin ?? Margins.zero, - display: style.display ?? Display.INLINE, + display: style.display ?? Display.inline, childIsReplaced: childIsReplaced, emValue: _calculateEmValue(style, context), textDirection: _checkTextDirection(context, textDirection), @@ -132,8 +128,8 @@ class CssBoxWidget extends StatelessWidget { /// width available to it or if it should just let its inner content /// determine the content-box's width. bool _shouldExpandToFillBlock() { - return (style.display == Display.BLOCK || - style.display == Display.LIST_ITEM) && + return (style.display == Display.block || + style.display == Display.listItem) && !childIsReplaced && !shrinkWrap; } @@ -244,7 +240,7 @@ class _CSSBoxRenderer extends MultiChildRenderObjectWidget { // and https://drafts.csswg.org/css2/#inline-replaced-width // and https://drafts.csswg.org/css2/#inlineblock-width // and https://drafts.csswg.org/css2/#inlineblock-replaced-width - if (display == Display.INLINE || display == Display.INLINE_BLOCK) { + if (display == Display.inline || display == Display.inlineBlock) { if (margins.left?.unit == Unit.auto) { leftMargin = Margin.zero(); } @@ -379,8 +375,9 @@ class _RenderCSSBox extends RenderBox @override void setupParentData(RenderBox child) { - if (child.parentData is! CSSBoxParentData) + if (child.parentData is! CSSBoxParentData) { child.parentData = CSSBoxParentData(); + } } static double getIntrinsicDimension(RenderBox? firstChild, @@ -453,13 +450,13 @@ class _RenderCSSBox extends RenderBox maxWidth: (this.width.unit != Unit.auto) ? this.width.value : containingBlockSize.width - - (this.margins.left?.value ?? 0) - - (this.margins.right?.value ?? 0), + (margins.left?.value ?? 0) - + (margins.right?.value ?? 0), maxHeight: (this.height.unit != Unit.auto) ? this.height.value : containingBlockSize.height - - (this.margins.top?.value ?? 0) - - (this.margins.bottom?.value ?? 0), + (margins.top?.value ?? 0) - + (margins.bottom?.value ?? 0), minWidth: (this.width.unit != Unit.auto) ? this.width.value : 0, minHeight: (this.height.unit != Unit.auto) ? this.height.value : 0, ); @@ -475,27 +472,27 @@ class _RenderCSSBox extends RenderBox //Calculate Width and Height of CSS Box height = childSize.height; switch (display) { - case Display.BLOCK: + case Display.block: width = (shrinkWrap || childIsReplaced) ? childSize.width + horizontalMargins : containingBlockSize.width; height = childSize.height + verticalMargins; break; - case Display.INLINE: + case Display.inline: width = childSize.width + horizontalMargins; height = childSize.height; break; - case Display.INLINE_BLOCK: + case Display.inlineBlock: width = childSize.width + horizontalMargins; height = childSize.height + verticalMargins; break; - case Display.LIST_ITEM: + case Display.listItem: width = shrinkWrap ? childSize.width + horizontalMargins : containingBlockSize.width; height = childSize.height + verticalMargins; break; - case Display.NONE: + case Display.none: width = 0; height = 0; break; @@ -528,22 +525,22 @@ class _RenderCSSBox extends RenderBox double leftOffset = 0; double topOffset = 0; switch (display) { - case Display.BLOCK: + case Display.block: leftOffset = leftMargin; topOffset = topMargin; break; - case Display.INLINE: + case Display.inline: leftOffset = leftMargin; break; - case Display.INLINE_BLOCK: + case Display.inlineBlock: leftOffset = leftMargin; topOffset = topMargin; break; - case Display.LIST_ITEM: + case Display.listItem: leftOffset = leftMargin; topOffset = topMargin; break; - case Display.NONE: + case Display.none: //No offset break; } @@ -568,7 +565,7 @@ class _RenderCSSBox extends RenderBox bool marginLeftIsAuto = marginLeft.unit == Unit.auto; bool marginRightIsAuto = marginRight.unit == Unit.auto; - if (display == Display.BLOCK) { + if (display == Display.block) { if (childIsReplaced) { widthIsAuto = false; } @@ -673,19 +670,18 @@ class _RenderCSSBox extends RenderBox void paint(PaintingContext context, Offset offset) { defaultPaint(context, offset); } - - @override - void dispose() { - super.dispose(); - } } extension Normalize on Dimension { void normalize(double emValue) { - switch (this.unit) { + switch (unit) { + case Unit.rem: + // Because CSSBoxWidget doesn't have any information about any + // sort of tree structure, treat rem the same as em. The HtmlParser + // widget handles rem/em values before they get to CSSBoxWidget. case Unit.em: - this.value *= emValue; - this.unit = Unit.px; + value *= emValue; + unit = Unit.px; return; case Unit.px: case Unit.auto: diff --git a/lib/src/css_parser.dart b/lib/src/css_parser.dart index 2d709187e9..c191a2907d 100644 --- a/lib/src/css_parser.dart +++ b/lib/src/css_parser.dart @@ -8,7 +8,7 @@ import 'package:flutter_html/flutter_html.dart'; import 'package:flutter_html/src/utils.dart'; Style declarationsToStyle(Map> declarations) { - Style style = new Style(); + Style style = Style(); declarations.forEach((property, value) { if (value.isNotEmpty) { switch (property) { @@ -27,11 +27,11 @@ Style declarationsToStyle(Map> declarations) { (element.text != "thin" && element.text != "medium" && element.text != "thick" && - !(element is css.LengthTerm) && - !(element is css.PercentageTerm) && - !(element is css.EmTerm) && - !(element is css.RemTerm) && - !(element is css.NumberTerm))); + element is! css.LengthTerm && + element is! css.PercentageTerm && + element is! css.EmTerm && + element is! css.RemTerm && + element is! css.NumberTerm)); List? borderColors = value .where((element) => ExpressionMapping.expressionToColor(element) != null) @@ -70,11 +70,11 @@ Style declarationsToStyle(Map> declarations) { (element.text != "thin" && element.text != "medium" && element.text != "thick" && - !(element is css.LengthTerm) && - !(element is css.PercentageTerm) && - !(element is css.EmTerm) && - !(element is css.RemTerm) && - !(element is css.NumberTerm))); + element is! css.LengthTerm && + element is! css.PercentageTerm && + element is! css.EmTerm && + element is! css.RemTerm && + element is! css.NumberTerm)); css.LiteralTerm? borderWidth = borderWidths.firstWhereOrNull((element) => element != null); css.Expression? borderColor = value.firstWhereOrNull((element) => @@ -128,11 +128,11 @@ Style declarationsToStyle(Map> declarations) { (element.text != "thin" && element.text != "medium" && element.text != "thick" && - !(element is css.LengthTerm) && - !(element is css.PercentageTerm) && - !(element is css.EmTerm) && - !(element is css.RemTerm) && - !(element is css.NumberTerm))); + element is! css.LengthTerm && + element is! css.PercentageTerm && + element is! css.EmTerm && + element is! css.RemTerm && + element is! css.NumberTerm)); css.LiteralTerm? borderWidth = borderWidths.firstWhereOrNull((element) => element != null); css.Expression? borderColor = value.firstWhereOrNull((element) => @@ -186,11 +186,11 @@ Style declarationsToStyle(Map> declarations) { (element.text != "thin" && element.text != "medium" && element.text != "thick" && - !(element is css.LengthTerm) && - !(element is css.PercentageTerm) && - !(element is css.EmTerm) && - !(element is css.RemTerm) && - !(element is css.NumberTerm))); + element is! css.LengthTerm && + element is! css.PercentageTerm && + element is! css.EmTerm && + element is! css.RemTerm && + element is! css.NumberTerm)); css.LiteralTerm? borderWidth = borderWidths.firstWhereOrNull((element) => element != null); css.Expression? borderColor = value.firstWhereOrNull((element) => @@ -244,11 +244,11 @@ Style declarationsToStyle(Map> declarations) { (element.text != "thin" && element.text != "medium" && element.text != "thick" && - !(element is css.LengthTerm) && - !(element is css.PercentageTerm) && - !(element is css.EmTerm) && - !(element is css.RemTerm) && - !(element is css.NumberTerm))); + element is! css.LengthTerm && + element is! css.PercentageTerm && + element is! css.EmTerm && + element is! css.RemTerm && + element is! css.NumberTerm)); css.LiteralTerm? borderWidth = borderWidths.firstWhereOrNull((element) => element != null); css.Expression? borderColor = value.firstWhereOrNull((element) => @@ -342,10 +342,10 @@ Style declarationsToStyle(Map> declarations) { if (position != null) { switch (position.text) { case 'outside': - style.listStylePosition = ListStylePosition.OUTSIDE; + style.listStylePosition = ListStylePosition.outside; break; case 'inside': - style.listStylePosition = ListStylePosition.INSIDE; + style.listStylePosition = ListStylePosition.inside; break; } } @@ -370,10 +370,10 @@ Style declarationsToStyle(Map> declarations) { if (value.first is css.LiteralTerm) { switch ((value.first as css.LiteralTerm).text) { case 'outside': - style.listStylePosition = ListStylePosition.OUTSIDE; + style.listStylePosition = ListStylePosition.outside; break; case 'inside': - style.listStylePosition = ListStylePosition.INSIDE; + style.listStylePosition = ListStylePosition.inside; break; } } @@ -395,10 +395,10 @@ Style declarationsToStyle(Map> declarations) { /// List might include other values than the ones we want for margin length, so make sure to remove those before passing it to [ExpressionMapping] marginLengths.removeWhere((element) => - !(element is css.LengthTerm) && - !(element is css.EmTerm) && - !(element is css.RemTerm) && - !(element is css.NumberTerm) && + element is! css.LengthTerm && + element is! css.EmTerm && + element is! css.RemTerm && + element is! css.NumberTerm && !(element.text == 'auto')); Margins margin = ExpressionMapping.expressionToMargins(marginLengths); style.margin = (style.margin ?? Margins.all(0)).copyWith( @@ -430,10 +430,10 @@ Style declarationsToStyle(Map> declarations) { /// List might include other values than the ones we want for padding length, so make sure to remove those before passing it to [ExpressionMapping] paddingLengths.removeWhere((element) => - !(element is css.LengthTerm) && - !(element is css.EmTerm) && - !(element is css.RemTerm) && - !(element is css.NumberTerm)); + element is! css.LengthTerm && + element is! css.EmTerm && + element is! css.RemTerm && + element is! css.NumberTerm); List padding = ExpressionMapping.expressionToPadding(paddingLengths); style.padding = (style.padding ?? EdgeInsets.zero).copyWith( @@ -494,14 +494,16 @@ Style declarationsToStyle(Map> declarations) { style.textDecoration = ExpressionMapping.expressionToTextDecorationLine( textDecorationList); - if (textDecorationColor != null) + if (textDecorationColor != null) { style.textDecorationColor = ExpressionMapping.expressionToColor(textDecorationColor) ?? style.textDecorationColor; - if (textDecorationStyle != null) + } + if (textDecorationStyle != null) { style.textDecorationStyle = ExpressionMapping.expressionToTextDecorationStyle( textDecorationStyle); + } break; case 'text-decoration-color': style.textDecorationColor = @@ -576,14 +578,14 @@ Map>> parseExternalCss( } class DeclarationVisitor extends css.Visitor { - Map>> _result = {}; - Map> _properties = {}; + final Map>> _result = {}; + final Map> _properties = {}; late String _selector; late String _currentProperty; Map>> getDeclarations( css.StyleSheet sheet) { - sheet.topLevels.forEach((element) { + for (var element in sheet.topLevels) { if (element.span != null) { _selector = element.span!.text; element.visit(this); @@ -591,18 +593,18 @@ class DeclarationVisitor extends css.Visitor { _properties.forEach((key, value) { if (_result[_selector]![key] != null) { _result[_selector]![key]! - .addAll(new List.from(value)); + .addAll(List.from(value)); } else { - _result[_selector]![key] = new List.from(value); + _result[_selector]![key] = List.from(value); } }); } else { _result[_selector] = - new Map>.from(_properties); + Map>.from(_properties); } _properties.clear(); } - }); + } return _result; } @@ -732,7 +734,7 @@ class ExpressionMapping { return double.tryParse(value.text) ?? 1.0; } else if (value is css.LengthTerm) { return double.tryParse( - value.text.replaceAll(new RegExp(r'\s+(\d+\.\d+)\s+'), '')) ?? + value.text.replaceAll(RegExp(r'\s+(\d+\.\d+)\s+'), '')) ?? 1.0; } else if (value is css.LiteralTerm) { switch (value.text) { @@ -787,18 +789,18 @@ class ExpressionMapping { if (value is css.LiteralTerm) { switch (value.text) { case 'block': - return Display.BLOCK; + return Display.block; case 'inline-block': - return Display.INLINE_BLOCK; + return Display.inlineBlock; case 'inline': - return Display.INLINE; + return Display.inline; case 'list-item': - return Display.LIST_ITEM; + return Display.listItem; case 'none': - return Display.NONE; + return Display.none; } } - return Display.INLINE; + return Display.inline; } static List expressionToFontFeatureSettings( @@ -844,7 +846,7 @@ class ExpressionMapping { // return FontSize.rem(double.tryParse(value.text) ?? 1, Unit.em); } else if (value is css.LengthTerm) { return FontSize(double.tryParse( - value.text.replaceAll(new RegExp(r'\s+(\d+\.\d+)\s+'), '')) ?? + value.text.replaceAll(RegExp(r'\s+(\d+\.\d+)\s+'), '')) ?? 16); } else if (value is css.LiteralTerm) { switch (value.text) { @@ -932,7 +934,7 @@ class ExpressionMapping { } else if (value is css.LengthTerm) { return LineHeight( double.tryParse( - value.text.replaceAll(new RegExp(r'\s+(\d+\.\d+)\s+'), '')), + value.text.replaceAll(RegExp(r'\s+(\d+\.\d+)\s+'), '')), units: "length"); } return LineHeight.normal; @@ -944,27 +946,27 @@ class ExpressionMapping { } switch (value.text) { case 'disc': - return ListStyleType.DISC; + return ListStyleType.disc; case 'circle': - return ListStyleType.CIRCLE; + return ListStyleType.circle; case 'decimal': - return ListStyleType.DECIMAL; + return ListStyleType.decimal; case 'lower-alpha': - return ListStyleType.LOWER_ALPHA; + return ListStyleType.lowerAlpha; case 'lower-latin': - return ListStyleType.LOWER_LATIN; + return ListStyleType.lowerLatin; case 'lower-roman': - return ListStyleType.LOWER_ROMAN; + return ListStyleType.lowerRoman; case 'square': - return ListStyleType.SQUARE; + return ListStyleType.square; case 'upper-alpha': - return ListStyleType.UPPER_ALPHA; + return ListStyleType.upperAlpha; case 'upper-latin': - return ListStyleType.UPPER_LATIN; + return ListStyleType.upperLatin; case 'upper-roman': - return ListStyleType.UPPER_ROMAN; + return ListStyleType.upperRoman; case 'none': - return ListStyleType.NONE; + return ListStyleType.none; } return null; } @@ -1067,7 +1069,7 @@ class ExpressionMapping { return double.tryParse(value.text); } else if (value is css.LengthTerm) { return double.tryParse( - value.text.replaceAll(new RegExp(r'\s+(\d+\.\d+)\s+'), '')); + value.text.replaceAll(RegExp(r'\s+(\d+\.\d+)\s+'), '')); } return null; } @@ -1081,8 +1083,8 @@ class ExpressionMapping { // return LengthOrPercent(double.parse(value.text), Unit.rem); // TODO there are several other available terms processed by the CSS parser } else if (value is css.LengthTerm) { - double number = double.parse( - value.text.replaceAll(new RegExp(r'\s+(\d+\.\d+)\s+'), '')); + double number = + double.parse(value.text.replaceAll(RegExp(r'\s+(\d+\.\d+)\s+'), '')); Unit unit = _unitMap(value.unit); return LengthOrPercent(number, unit); } @@ -1139,8 +1141,9 @@ class ExpressionMapping { } } } - if (decorationList.contains(TextDecoration.none)) + if (decorationList.contains(TextDecoration.none)) { decorationList = [TextDecoration.none]; + } return TextDecoration.combine(decorationList); } @@ -1181,7 +1184,7 @@ class ExpressionMapping { css.Expression? blurRadius; css.Expression? color; int expressionIndex = 0; - list.forEach((element) { + for (var element in list) { if (element is css.HexColorTerm || element is css.FunctionTerm) { color = element; } else if (expressionIndex == 0) { @@ -1193,7 +1196,7 @@ class ExpressionMapping { } else { blurRadius = element; } - }); + } RegExp nonNumberRegex = RegExp(r'\s+(\d+\.\d+)\s+'); if (offsetX is css.LiteralTerm && offsetY is css.LiteralTerm) { if (color != null && @@ -1201,31 +1204,23 @@ class ExpressionMapping { shadow.add(Shadow( color: expressionToColor(color)!, offset: Offset( - double.tryParse((offsetX as css.LiteralTerm) - .text - .replaceAll(nonNumberRegex, ''))!, - double.tryParse((offsetY as css.LiteralTerm) - .text - .replaceAll(nonNumberRegex, ''))!), + double.tryParse((offsetX).text.replaceAll(nonNumberRegex, ''))!, + double.tryParse( + (offsetY).text.replaceAll(nonNumberRegex, ''))!), blurRadius: (blurRadius is css.LiteralTerm) - ? double.tryParse((blurRadius as css.LiteralTerm) - .text - .replaceAll(nonNumberRegex, ''))! + ? double.tryParse( + (blurRadius).text.replaceAll(nonNumberRegex, ''))! : 0.0, )); } else { shadow.add(Shadow( offset: Offset( - double.tryParse((offsetX as css.LiteralTerm) - .text - .replaceAll(nonNumberRegex, ''))!, - double.tryParse((offsetY as css.LiteralTerm) - .text - .replaceAll(nonNumberRegex, ''))!), + double.tryParse((offsetX).text.replaceAll(nonNumberRegex, ''))!, + double.tryParse( + (offsetY).text.replaceAll(nonNumberRegex, ''))!), blurRadius: (blurRadius is css.LiteralTerm) - ? double.tryParse((blurRadius as css.LiteralTerm) - .text - .replaceAll(nonNumberRegex, ''))! + ? double.tryParse( + (blurRadius).text.replaceAll(nonNumberRegex, ''))! : 0.0, )); } @@ -1235,17 +1230,18 @@ class ExpressionMapping { return finalShadows; } - static Color stringToColor(String _text) { - var text = _text.replaceFirst('#', ''); - if (text.length == 3) + static Color stringToColor(String rawText) { + var text = rawText.replaceFirst('#', ''); + if (text.length == 3) { text = text.replaceAllMapped(RegExp(r"[a-f]|\d", caseSensitive: false), (match) => '${match.group(0)}${match.group(0)}'); + } if (text.length > 6) { - text = "0x" + text; + text = "0x$text"; } else { - text = "0xFF" + text; + text = "0xFF$text"; } - return new Color(int.parse(text)); + return Color(int.parse(text)); } static Color? rgbOrRgbaToColor(String text) { @@ -1278,7 +1274,7 @@ class ExpressionMapping { final hslText = text.replaceAll(')', '').replaceAll(' ', ''); final hslValues = hslText.split(',').toList(); List parsedHsl = []; - hslValues.forEach((element) { + for (var element in hslValues) { if (element.contains("%") && double.tryParse(element.replaceAll("%", "")) != null) { parsedHsl.add(double.tryParse(element.replaceAll("%", ""))! * 0.01); @@ -1291,7 +1287,7 @@ class ExpressionMapping { parsedHsl.add(double.tryParse(element)); } } - }); + } if (parsedHsl.length == 4 && !parsedHsl.contains(null)) { return HSLColor.fromAHSL( parsedHsl.last!, parsedHsl.first!, parsedHsl[1]!, parsedHsl[2]!) @@ -1300,8 +1296,9 @@ class ExpressionMapping { return HSLColor.fromAHSL( 1.0, parsedHsl.first!, parsedHsl[1]!, parsedHsl.last!) .toColor(); - } else + } else { return Colors.black; + } } static Color? namedColorToColor(String text) { @@ -1310,7 +1307,8 @@ class ExpressionMapping { orElse: () => ""); if (namedColor != "") { return stringToColor(namedColors[namedColor]!); - } else + } else { return null; + } } } diff --git a/lib/src/html_elements.dart b/lib/src/html_elements.dart index bf4e363024..304c9ff395 100644 --- a/lib/src/html_elements.dart +++ b/lib/src/html_elements.dart @@ -2,292 +2,206 @@ export 'styled_element.dart'; export 'interactable_element.dart'; export 'replaced_element.dart'; -const STYLED_ELEMENTS = [ - "abbr", - "acronym", - "address", - "b", - "bdi", - "bdo", - "big", - "cite", - "code", - "data", - "del", - "dfn", - "em", - "font", - "i", - "ins", - "kbd", - "mark", - "q", - "rt", - "s", - "samp", - "small", - "span", - "strike", - "strong", - "sub", - "sup", - "time", - "tt", - "u", - "var", - "wbr", +class HtmlElements { + static const styledElements = [ + "abbr", + "acronym", + "address", + "b", + "bdi", + "bdo", + "big", + "cite", + "code", + "data", + "del", + "dfn", + "em", + "font", + "i", + "ins", + "kbd", + "mark", + "q", + "rt", + "s", + "samp", + "small", + "span", + "strike", + "strong", + "sub", + "sup", + "time", + "tt", + "u", + "var", + "wbr", - //BLOCK ELEMENTS - "article", - "aside", - "blockquote", - "body", - "center", - "dd", - "div", - "dl", - "dt", - "figcaption", - "figure", - "footer", - "h1", - "h2", - "h3", - "h4", - "h5", - "h6", - "header", - "hr", - "html", - "li", - "main", - "nav", - "noscript", - "ol", - "p", - "pre", - "section", - "summary", - "ul", -]; + //BLOCK ELEMENTS + "article", + "aside", + "blockquote", + "body", + "center", + "dd", + "div", + "dl", + "dt", + "figcaption", + "figure", + "footer", + "h1", + "h2", + "h3", + "h4", + "h5", + "h6", + "header", + "hr", + "html", + "li", + "main", + "nav", + "noscript", + "ol", + "p", + "pre", + "section", + "summary", + "ul", + ]; -const BLOCK_ELEMENTS = [ - "article", - "aside", - "blockquote", - "body", - "center", - "dd", - "div", - "dl", - "dt", - "figcaption", - "figure", - "footer", - "h1", - "h2", - "h3", - "h4", - "h5", - "h6", - "header", - "hr", - "html", - "li", - "main", - "nav", - "noscript", - "ol", - "p", - "pre", - "section", - "summary", - "ul", -]; + static const blockElements = [ + "article", + "aside", + "blockquote", + "body", + "center", + "dd", + "div", + "dl", + "dt", + "figcaption", + "figure", + "footer", + "h1", + "h2", + "h3", + "h4", + "h5", + "h6", + "header", + "hr", + "html", + "li", + "main", + "nav", + "noscript", + "ol", + "p", + "pre", + "section", + "summary", + "ul", + ]; -const INTERACTABLE_ELEMENTS = [ - "a", -]; + static const interactableElements = [ + "a", + ]; -const REPLACED_ELEMENTS = [ - "br", - "template", - "rp", - "rt", - "ruby", -]; + static const replacedElements = [ + "br", + "template", + "rp", + "rt", + "ruby", + ]; -const LAYOUT_ELEMENTS = [ - "details", - "tr", - "tbody", - "tfoot", - "thead", -]; + static const layoutElements = [ + "details", + "tr", + "tbody", + "tfoot", + "thead", + ]; -const TABLE_CELL_ELEMENTS = ["th", "td"]; + static const tableCellElements = ["th", "td"]; -const TABLE_DEFINITION_ELEMENTS = ["col", "colgroup"]; + static const tableDefinitionElements = ["col", "colgroup"]; -const EXTERNAL_ELEMENTS = [ - "audio", - "iframe", - "img", - "math", - "svg", - "table", - "video" -]; + static const externalElements = [ + "audio", + "iframe", + "img", + "math", + "svg", + "table", + "video" + ]; -const REPLACED_EXTERNAL_ELEMENTS = ["iframe", "img", "video", "audio"]; + static const replacedExternalElements = ["iframe", "img", "video", "audio"]; -const SELECTABLE_ELEMENTS = [ - "br", - "a", - "article", - "aside", - "blockquote", - "body", - "center", - "dd", - "div", - "dl", - "dt", - "figcaption", - "figure", - "footer", - "h1", - "h2", - "h3", - "h4", - "h5", - "h6", - "header", - "hr", - "html", - "main", - "nav", - "noscript", - "p", - "pre", - "section", - "summary", - "abbr", - "acronym", - "address", - "b", - "bdi", - "bdo", - "big", - "cite", - "code", - "data", - "del", - "dfn", - "em", - "font", - "i", - "ins", - "kbd", - "mark", - "q", - "s", - "samp", - "small", - "span", - "strike", - "strong", - "time", - "tt", - "u", - "var", - "wbr", -]; - -/** - Here is a list of elements with planned support: - a - i [x] - abbr - s [x] - acronym - s [x] - address - s [x] - audio - c [x] - article - b [x] - aside - b [x] - b - s [x] - bdi - s [x] - bdo - s [x] - big - s [x] - blockquote- b [x] - body - b [x] - br - b [x] - button - i [ ] - caption - b [ ] - center - b [x] - cite - s [x] - code - s [x] - data - s [x] - dd - b [x] - del - s [x] - dfn - s [x] - div - b [x] - dl - b [x] - dt - b [x] - em - s [x] - figcaption- b [x] - figure - b [x] - font - s [x] - footer - b [x] - h1 - b [x] - h2 - b [x] - h3 - b [x] - h4 - b [x] - h5 - b [x] - h6 - b [x] - head - e [x] - header - b [x] - hr - b [x] - html - b [x] - i - s [x] - img - c [x] - ins - s [x] - kbd - s [x] - li - b [x] - main - b [x] - mark - s [x] - nav - b [x] - noscript - b [x] - ol - b [x] post - p - b [x] - pre - b [x] - q - s [x] post - rp - s [x] - rt - s [x] - ruby - s [x] - s - s [x] - samp - s [x] - section - b [x] - small - s [x] - source - [-] child of content - span - s [x] - strike - s [x] - strong - s [x] - sub - s [x] - sup - s [x] - svg - c [x] - table - b [x] - tbody - b [x] - td - s [ ] - template - e [x] - tfoot - b [x] - th - s [ ] - thead - b [x] - time - s [x] - tr - ? [ ] - track - [-] child of content - tt - s [x] - u - s [x] - ul - b [x] post - var - s [x] - video - c [x] - wbr - s [x] - */ + static const selectableElements = [ + "br", + "a", + "article", + "aside", + "blockquote", + "body", + "center", + "dd", + "div", + "dl", + "dt", + "figcaption", + "figure", + "footer", + "h1", + "h2", + "h3", + "h4", + "h5", + "h6", + "header", + "hr", + "html", + "main", + "nav", + "noscript", + "p", + "pre", + "section", + "summary", + "abbr", + "acronym", + "address", + "b", + "bdi", + "bdo", + "big", + "cite", + "code", + "data", + "del", + "dfn", + "em", + "font", + "i", + "ins", + "kbd", + "mark", + "q", + "s", + "samp", + "small", + "span", + "strike", + "strong", + "time", + "tt", + "u", + "var", + "wbr", + ]; +} diff --git a/lib/src/interactable_element.dart b/lib/src/interactable_element.dart index 57a918fdbe..6a1bf90a4f 100644 --- a/lib/src/interactable_element.dart +++ b/lib/src/interactable_element.dart @@ -19,7 +19,7 @@ class InteractableElement extends StyledElement { /// A [Gesture] indicates the type of interaction by a user. enum Gesture { - TAP, + tap, } StyledElement parseInteractableElement( diff --git a/lib/src/layout_element.dart b/lib/src/layout_element.dart index d366ce1fc3..d5ac7e8cb4 100644 --- a/lib/src/layout_element.dart +++ b/lib/src/layout_element.dart @@ -29,7 +29,7 @@ class TableSectionLayoutElement extends LayoutElement { @override Widget toWidget(RenderContext context) { // Not rendered; TableLayoutElement will instead consume its children - return Container(child: Text("TABLE SECTION")); + return const Text("TABLE SECTION"); } } @@ -43,7 +43,7 @@ class TableRowLayoutElement extends LayoutElement { @override Widget toWidget(RenderContext context) { // Not rendered; TableLayoutElement will instead consume its children - return Container(child: Text("TABLE ROW")); + return const Text("TABLE ROW"); } } @@ -158,7 +158,7 @@ class DetailsContentElement extends LayoutElement { children: firstChild == null ? [] : [firstChild], style: style, ) - : Text("Details"), + : const Text("Details"), children: [ CssBoxWidget.withInlineSpanChildren( children: getChildren( @@ -188,7 +188,7 @@ class EmptyLayoutElement extends LayoutElement { ); @override - Widget? toWidget(_) => null; + Widget? toWidget(context) => null; } LayoutElement parseLayoutElement( diff --git a/lib/src/replaced_element.dart b/lib/src/replaced_element.dart index 3234da0f1d..582c35432d 100644 --- a/lib/src/replaced_element.dart +++ b/lib/src/replaced_element.dart @@ -59,7 +59,7 @@ class TextContentElement extends ReplacedElement { } @override - Widget? toWidget(_) => null; + Widget? toWidget(context) => null; } class EmptyContentElement extends ReplacedElement { @@ -67,10 +67,11 @@ class EmptyContentElement extends ReplacedElement { : super(name: name, style: Style(), elementId: "[[No ID]]"); @override - Widget? toWidget(_) => null; + Widget? toWidget(context) => null; } class RubyElement extends ReplacedElement { + @override dom.Element element; RubyElement({ @@ -97,12 +98,12 @@ class RubyElement extends ReplacedElement { (element.text ?? "").trim().isEmpty && index > 0 && index + 1 < context.tree.children.length && - !(context.tree.children[index - 1] is TextContentElement) && - !(context.tree.children[index + 1] is TextContentElement))) { + context.tree.children[index - 1] is! TextContentElement && + context.tree.children[index + 1] is! TextContentElement)) { children.add(element); } }); - children.forEach((c) { + for (var c in children) { if (c.name == "rt" && node != null) { final widget = Stack( alignment: Alignment.center, @@ -128,10 +129,10 @@ class RubyElement extends ReplacedElement { style: context.style, child: node is TextContentElement ? Text( - (node as TextContentElement).text?.trim() ?? "", + node.text?.trim() ?? "", style: context.style.generateTextStyle(), ) - : RichText(text: context.parser.parseTree(context, node!)), + : RichText(text: context.parser.parseTree(context, node)), ), ], ); @@ -139,7 +140,7 @@ class RubyElement extends ReplacedElement { } else { node = c; } - }); + } return Padding( padding: EdgeInsets.only(top: rubySize), child: Wrap( @@ -166,7 +167,7 @@ ReplacedElement parseReplacedElement( case "br": return TextContentElement( text: "\n", - style: Style(whiteSpace: WhiteSpace.PRE), + style: Style(whiteSpace: WhiteSpace.pre), element: element, node: element, ); diff --git a/lib/src/style/fontsize.dart b/lib/src/style/fontsize.dart index 5d766c630a..d3ed2c13ef 100644 --- a/lib/src/style/fontsize.dart +++ b/lib/src/style/fontsize.dart @@ -1,5 +1,3 @@ -//TODO implement dimensionality - import 'length.dart'; class FontSize extends LengthOrPercent { @@ -35,5 +33,5 @@ class FontSize extends LengthOrPercent { return parent; } - double get emValue => this.value; + double get emValue => value; } diff --git a/lib/src/style/length.dart b/lib/src/style/length.dart index 3fab69263d..b63e8ebb55 100644 --- a/lib/src/style/length.dart +++ b/lib/src/style/length.dart @@ -1,16 +1,17 @@ /// These are the base unit types -enum _UnitType { +enum UnitType { percent, length, auto, - lengthPercent(children: [_UnitType.length, _UnitType.percent]), - lengthPercentAuto(children: [_UnitType.length, _UnitType.percent, _UnitType.auto]); + lengthPercent(children: [UnitType.length, UnitType.percent]), + lengthPercentAuto( + children: [UnitType.length, UnitType.percent, UnitType.auto]); - final List<_UnitType> children; + final List children; - const _UnitType({this.children = const []}); + const UnitType({this.children = const []}); - bool matches(_UnitType other) { + bool matches(UnitType other) { return this == other || children.contains(other); } } @@ -18,18 +19,18 @@ enum _UnitType { /// A Unit represents a CSS unit enum Unit { //ch, - em(_UnitType.length), + em(UnitType.length), //ex, - percent(_UnitType.percent), - px(_UnitType.length), - rem(_UnitType.length), + percent(UnitType.percent), + px(UnitType.length), + rem(UnitType.length), //Q, //vh, //vw, - auto(_UnitType.auto); + auto(UnitType.auto); const Unit(this.unitType); - final _UnitType unitType; + final UnitType unitType; } /// Represents a CSS dimension https://drafts.csswg.org/css-values/#dimensions @@ -37,15 +38,16 @@ abstract class Dimension { double value; Unit unit; - Dimension(this.value, this.unit, _UnitType _dimensionUnitType) - : assert(_dimensionUnitType.matches(unit.unitType), + Dimension(this.value, this.unit, UnitType dimensionUnitType) + : assert(dimensionUnitType.matches(unit.unitType), "This Dimension was given a Unit that isn't specified."); } /// This dimension takes a value with a length unit such as px or em. Note that /// these can be fixed or relative (but they must not be a percent) class Length extends Dimension { - Length(double value, [Unit unit = Unit.px]) : super(value, unit, _UnitType.length); + Length(double value, [Unit unit = Unit.px]) + : super(value, unit, UnitType.length); } /// This dimension takes a value with a length-percent unit such as px or em @@ -53,10 +55,10 @@ class Length extends Dimension { /// percent) class LengthOrPercent extends Dimension { LengthOrPercent(double value, [Unit unit = Unit.px]) - : super(value, unit, _UnitType.lengthPercent); + : super(value, unit, UnitType.lengthPercent); } class AutoOrLengthOrPercent extends Dimension { AutoOrLengthOrPercent(double value, [Unit unit = Unit.px]) - : super(value, unit, _UnitType.lengthPercentAuto); + : super(value, unit, UnitType.lengthPercentAuto); } diff --git a/lib/src/styled_element.dart b/lib/src/styled_element.dart index 8434544c50..87625b2d98 100644 --- a/lib/src/styled_element.dart +++ b/lib/src/styled_element.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; import 'package:flutter_html/src/css_parser.dart'; -import 'package:flutter_html/src/style/margin.dart'; import 'package:flutter_html/style.dart'; import 'package:html/dom.dart' as dom; //TODO(Sub6Resources): don't use the internal code of the html package as it may change unexpectedly. @@ -23,7 +22,7 @@ class StyledElement { required this.children, required this.style, required dom.Element? node, - }) : this._node = node; + }) : _node = node; bool matchesSelector(String selector) => (_node != null && matches(_node!, selector)) || name == selector; @@ -32,7 +31,7 @@ class StyledElement { _node?.attributes.map((key, value) { return MapEntry(key.toString(), value); }) ?? - Map(); + {}; dom.Element? get element => _node; @@ -40,10 +39,10 @@ class StyledElement { String toString() { String selfData = "[$name] ${children.length} ${elementClasses.isNotEmpty == true ? 'C:${elementClasses.toString()}' : ''}${elementId.isNotEmpty == true ? 'ID: $elementId' : ''}"; - children.forEach((child) { + for (var child in children) { selfData += ("\n${child.toString()}") .replaceAll(RegExp("^", multiLine: true), "-"); - }); + } return selfData; } } @@ -73,12 +72,12 @@ StyledElement parseStyledElement( continue italics; case "article": styledElement.style = Style( - display: Display.BLOCK, + display: Display.block, ); break; case "aside": styledElement.style = Style( - display: Display.BLOCK, + display: Display.block, ); break; bold: @@ -106,25 +105,25 @@ StyledElement parseStyledElement( if (element.parent!.localName == "blockquote") { styledElement.style = Style( margin: Margins.only(left: 40.0, right: 40.0, bottom: 14.0), - display: Display.BLOCK, + display: Display.block, ); } else { styledElement.style = Style( margin: Margins.symmetric(horizontal: 40.0, vertical: 14.0), - display: Display.BLOCK, + display: Display.block, ); } break; case "body": styledElement.style = Style( margin: Margins.all(8.0), - display: Display.BLOCK, + display: Display.block, ); break; case "center": styledElement.style = Style( alignment: Alignment.center, - display: Display.BLOCK, + display: Display.block, ); break; case "cite": @@ -138,7 +137,7 @@ StyledElement parseStyledElement( case "dd": styledElement.style = Style( margin: Margins.only(left: 40.0), - display: Display.BLOCK, + display: Display.block, ); break; strikeThrough: @@ -152,36 +151,36 @@ StyledElement parseStyledElement( case "div": styledElement.style = Style( margin: Margins.all(0), - display: Display.BLOCK, + display: Display.block, ); break; case "dl": styledElement.style = Style( margin: Margins.symmetric(vertical: 14.0), - display: Display.BLOCK, + display: Display.block, ); break; case "dt": styledElement.style = Style( - display: Display.BLOCK, + display: Display.block, ); break; case "em": continue italics; case "figcaption": styledElement.style = Style( - display: Display.BLOCK, + display: Display.block, ); break; case "figure": styledElement.style = Style( margin: Margins.symmetric(vertical: 14.0, horizontal: 40.0), - display: Display.BLOCK, + display: Display.block, ); break; case "footer": styledElement.style = Style( - display: Display.BLOCK, + display: Display.block, ); break; case "font": @@ -203,7 +202,7 @@ StyledElement parseStyledElement( fontSize: FontSize(2, Unit.em), fontWeight: FontWeight.bold, margin: Margins.symmetric(vertical: 0.67, unit: Unit.em), - display: Display.BLOCK, + display: Display.block, ); break; case "h2": @@ -211,7 +210,7 @@ StyledElement parseStyledElement( fontSize: FontSize(1.5, Unit.em), fontWeight: FontWeight.bold, margin: Margins.symmetric(vertical: 0.83, unit: Unit.em), - display: Display.BLOCK, + display: Display.block, ); break; case "h3": @@ -219,14 +218,14 @@ StyledElement parseStyledElement( fontSize: FontSize(1.17, Unit.em), fontWeight: FontWeight.bold, margin: Margins.symmetric(vertical: 1, unit: Unit.em), - display: Display.BLOCK, + display: Display.block, ); break; case "h4": styledElement.style = Style( fontWeight: FontWeight.bold, margin: Margins.symmetric(vertical: 1.33, unit: Unit.em), - display: Display.BLOCK, + display: Display.block, ); break; case "h5": @@ -234,7 +233,7 @@ StyledElement parseStyledElement( fontSize: FontSize(0.83, Unit.em), fontWeight: FontWeight.bold, margin: Margins.symmetric(vertical: 1.67, unit: Unit.em), - display: Display.BLOCK, + display: Display.block, ); break; case "h6": @@ -242,12 +241,12 @@ StyledElement parseStyledElement( fontSize: FontSize(0.67, Unit.em), fontWeight: FontWeight.bold, margin: Margins.symmetric(vertical: 2.33, unit: Unit.em), - display: Display.BLOCK, + display: Display.block, ); break; case "header": styledElement.style = Style( - display: Display.BLOCK, + display: Display.block, ); break; case "hr": @@ -259,12 +258,12 @@ StyledElement parseStyledElement( right: Margin.auto(), ), border: Border.all(), - display: Display.BLOCK, + display: Display.block, ); break; case "html": styledElement.style = Style( - display: Display.BLOCK, + display: Display.block, ); break; italics: @@ -279,12 +278,12 @@ StyledElement parseStyledElement( continue monospace; case "li": styledElement.style = Style( - display: Display.LIST_ITEM, + display: Display.listItem, ); break; case "main": styledElement.style = Style( - display: Display.BLOCK, + display: Display.block, ); break; case "mark": @@ -295,12 +294,12 @@ StyledElement parseStyledElement( break; case "nav": styledElement.style = Style( - display: Display.BLOCK, + display: Display.block, ); break; case "noscript": styledElement.style = Style( - display: Display.BLOCK, + display: Display.block, ); break; case "ol": @@ -309,33 +308,33 @@ StyledElement parseStyledElement( if (element.parent!.localName == "li") { styledElement.style = Style( // margin: EdgeInsets.only(left: 30.0), - display: Display.BLOCK, + display: Display.block, listStyleType: element.localName == "ol" - ? ListStyleType.DECIMAL - : ListStyleType.DISC, + ? ListStyleType.decimal + : ListStyleType.disc, ); } else { styledElement.style = Style( // margin: EdgeInsets.only(left: 30.0, top: 14.0, bottom: 14.0), - display: Display.BLOCK, + display: Display.block, listStyleType: element.localName == "ol" - ? ListStyleType.DECIMAL - : ListStyleType.DISC, + ? ListStyleType.decimal + : ListStyleType.disc, ); } break; case "p": styledElement.style = Style( margin: Margins.symmetric(vertical: 1, unit: Unit.em), - display: Display.BLOCK, + display: Display.block, ); break; case "pre": styledElement.style = Style( fontFamily: 'monospace', margin: Margins.symmetric(vertical: 14.0), - whiteSpace: WhiteSpace.PRE, - display: Display.BLOCK, + whiteSpace: WhiteSpace.pre, + display: Display.block, ); break; case "q": @@ -350,7 +349,7 @@ StyledElement parseStyledElement( continue monospace; case "section": styledElement.style = Style( - display: Display.BLOCK, + display: Display.block, ); break; case "small": @@ -365,13 +364,13 @@ StyledElement parseStyledElement( case "sub": styledElement.style = Style( fontSize: FontSize.smaller, - verticalAlign: VerticalAlign.SUB, + verticalAlign: VerticalAlign.sub, ); break; case "sup": styledElement.style = Style( fontSize: FontSize.smaller, - verticalAlign: VerticalAlign.SUPER, + verticalAlign: VerticalAlign.sup, ); break; case "tt": diff --git a/lib/style.dart b/lib/style.dart index 38d12ca136..d9993d1ba5 100644 --- a/lib/style.dart +++ b/lib/style.dart @@ -243,9 +243,9 @@ class Style { this.textOverflow, this.textTransform = TextTransform.none, }) { - if (this.alignment == null && - (display == Display.BLOCK || display == Display.LIST_ITEM)) { - this.alignment = Alignment.centerLeft; + if (alignment == null && + (display == Display.block || display == Display.listItem)) { + alignment = Alignment.centerLeft; } } @@ -358,7 +358,7 @@ class Style { : backgroundColor, color: child.color ?? color, direction: child.direction ?? direction, - display: display == Display.NONE ? display : child.display, + display: display == Display.none ? display : child.display, fontFamily: child.fontFamily ?? fontFamily, fontFamilyFallback: child.fontFamilyFallback ?? fontFamilyFallback, fontFeatureSettings: child.fontFeatureSettings ?? fontFeatureSettings, @@ -462,24 +462,24 @@ class Style { } Style.fromTextStyle(TextStyle textStyle) { - this.backgroundColor = textStyle.backgroundColor; - this.color = textStyle.color; - this.textDecoration = textStyle.decoration; - this.textDecorationColor = textStyle.decorationColor; - this.textDecorationStyle = textStyle.decorationStyle; - this.textDecorationThickness = textStyle.decorationThickness; - this.fontFamily = textStyle.fontFamily; - this.fontFamilyFallback = textStyle.fontFamilyFallback; - this.fontFeatureSettings = textStyle.fontFeatures; - this.fontSize = + backgroundColor = textStyle.backgroundColor; + color = textStyle.color; + textDecoration = textStyle.decoration; + textDecorationColor = textStyle.decorationColor; + textDecorationStyle = textStyle.decorationStyle; + textDecorationThickness = textStyle.decorationThickness; + fontFamily = textStyle.fontFamily; + fontFamilyFallback = textStyle.fontFamilyFallback; + fontFeatureSettings = textStyle.fontFeatures; + fontSize = textStyle.fontSize != null ? FontSize(textStyle.fontSize!) : null; - this.fontStyle = textStyle.fontStyle; - this.fontWeight = textStyle.fontWeight; - this.letterSpacing = textStyle.letterSpacing; - this.textShadow = textStyle.shadows; - this.wordSpacing = textStyle.wordSpacing; - this.lineHeight = LineHeight(textStyle.height ?? 1.2); - this.textTransform = TextTransform.none; + fontStyle = textStyle.fontStyle; + fontWeight = textStyle.fontWeight; + letterSpacing = textStyle.letterSpacing; + textShadow = textStyle.shadows; + wordSpacing = textStyle.wordSpacing; + lineHeight = LineHeight(textStyle.height ?? 1.2); + textTransform = TextTransform.none; } /// Sets any dimensions set to rem or em to the computed size @@ -541,11 +541,11 @@ class Style { } enum Display { - BLOCK, - INLINE, - INLINE_BLOCK, - LIST_ITEM, - NONE, + block, + inline, + inlineBlock, + listItem, + none, } class ListStyleType { @@ -561,22 +561,22 @@ class ListStyleType { factory ListStyleType.fromWidget(Widget widget) => ListStyleType("", widget: widget, type: "widget"); - static const LOWER_ALPHA = ListStyleType("LOWER_ALPHA"); - static const UPPER_ALPHA = ListStyleType("UPPER_ALPHA"); - static const LOWER_LATIN = ListStyleType("LOWER_LATIN"); - static const UPPER_LATIN = ListStyleType("UPPER_LATIN"); - static const CIRCLE = ListStyleType("CIRCLE"); - static const DISC = ListStyleType("DISC"); - static const DECIMAL = ListStyleType("DECIMAL"); - static const LOWER_ROMAN = ListStyleType("LOWER_ROMAN"); - static const UPPER_ROMAN = ListStyleType("UPPER_ROMAN"); - static const SQUARE = ListStyleType("SQUARE"); - static const NONE = ListStyleType("NONE"); + static const lowerAlpha = ListStyleType("LOWER_ALPHA"); + static const upperAlpha = ListStyleType("UPPER_ALPHA"); + static const lowerLatin = ListStyleType("LOWER_LATIN"); + static const upperLatin = ListStyleType("UPPER_LATIN"); + static const circle = ListStyleType("CIRCLE"); + static const disc = ListStyleType("DISC"); + static const decimal = ListStyleType("DECIMAL"); + static const lowerRoman = ListStyleType("LOWER_ROMAN"); + static const upperRoman = ListStyleType("UPPER_ROMAN"); + static const square = ListStyleType("SQUARE"); + static const none = ListStyleType("NONE"); } enum ListStylePosition { - OUTSIDE, - INSIDE, + outside, + inside, } enum TextTransform { @@ -587,12 +587,12 @@ enum TextTransform { } enum VerticalAlign { - BASELINE, - SUB, - SUPER, + baseline, + sub, + sup, } enum WhiteSpace { - NORMAL, - PRE, + normal, + pre, } diff --git a/packages/flutter_html_all/analysis_options.yaml b/packages/flutter_html_all/analysis_options.yaml new file mode 100644 index 0000000000..f065cf1ea4 --- /dev/null +++ b/packages/flutter_html_all/analysis_options.yaml @@ -0,0 +1,29 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:flutter_lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at + # https://dart-lang.github.io/linter/lints/index.html. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options \ No newline at end of file diff --git a/packages/flutter_html_all/pubspec.yaml b/packages/flutter_html_all/pubspec.yaml index ab76f12164..82e60c2be3 100644 --- a/packages/flutter_html_all/pubspec.yaml +++ b/packages/flutter_html_all/pubspec.yaml @@ -34,5 +34,6 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter + flutter_lints: ^2.0.1 flutter: diff --git a/packages/flutter_html_all/pubspec_overrides.yaml b/packages/flutter_html_all/pubspec_overrides.yaml new file mode 100644 index 0000000000..54b3d46a71 --- /dev/null +++ b/packages/flutter_html_all/pubspec_overrides.yaml @@ -0,0 +1,16 @@ +# melos_managed_dependency_overrides: flutter_html,flutter_html_audio,flutter_html_iframe,flutter_html_math,flutter_html_svg,flutter_html_table,flutter_html_video +dependency_overrides: + flutter_html: + path: ../.. + flutter_html_audio: + path: ../flutter_html_audio + flutter_html_iframe: + path: ../flutter_html_iframe + flutter_html_math: + path: ../flutter_html_math + flutter_html_svg: + path: ../flutter_html_svg + flutter_html_table: + path: ../flutter_html_table + flutter_html_video: + path: ../flutter_html_video diff --git a/packages/flutter_html_audio/analysis_options.yaml b/packages/flutter_html_audio/analysis_options.yaml new file mode 100644 index 0000000000..f065cf1ea4 --- /dev/null +++ b/packages/flutter_html_audio/analysis_options.yaml @@ -0,0 +1,29 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:flutter_lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at + # https://dart-lang.github.io/linter/lints/index.html. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options \ No newline at end of file diff --git a/packages/flutter_html_audio/lib/flutter_html_audio.dart b/packages/flutter_html_audio/lib/flutter_html_audio.dart index c542f12242..d9dbe0825f 100644 --- a/packages/flutter_html_audio/lib/flutter_html_audio.dart +++ b/packages/flutter_html_audio/lib/flutter_html_audio.dart @@ -28,10 +28,11 @@ class AudioWidget extends StatefulWidget { final RenderContext context; final AudioControllerCallback? callback; - AudioWidget({ + const AudioWidget({ + Key? key, required this.context, this.callback, - }); + }) : super(key: key); @override State createState() => _AudioWidgetState(); @@ -78,16 +79,16 @@ class _AudioWidgetState extends State { @override Widget build(BuildContext bContext) { if (sources.isEmpty || sources.first == null) { - return Container(height: 0, width: 0); + return const SizedBox(height: 0, width: 0); } return CssBoxWidget( key: widget.context.key, style: widget.context.style, + childIsReplaced: true, child: ChewieAudio( controller: chewieAudioController!, ), - childIsReplaced: true, ); } } diff --git a/packages/flutter_html_audio/pubspec.yaml b/packages/flutter_html_audio/pubspec.yaml index 426fafb794..9f2ec7000e 100644 --- a/packages/flutter_html_audio/pubspec.yaml +++ b/packages/flutter_html_audio/pubspec.yaml @@ -21,5 +21,6 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter + flutter_lints: ^2.0.1 flutter: diff --git a/packages/flutter_html_audio/pubspec_overrides.yaml b/packages/flutter_html_audio/pubspec_overrides.yaml new file mode 100644 index 0000000000..65126a9bbf --- /dev/null +++ b/packages/flutter_html_audio/pubspec_overrides.yaml @@ -0,0 +1,4 @@ +# melos_managed_dependency_overrides: flutter_html +dependency_overrides: + flutter_html: + path: ../.. diff --git a/packages/flutter_html_iframe/analysis_options.yaml b/packages/flutter_html_iframe/analysis_options.yaml new file mode 100644 index 0000000000..f065cf1ea4 --- /dev/null +++ b/packages/flutter_html_iframe/analysis_options.yaml @@ -0,0 +1,29 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:flutter_lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at + # https://dart-lang.github.io/linter/lints/index.html. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options \ No newline at end of file diff --git a/packages/flutter_html_iframe/lib/iframe_mobile.dart b/packages/flutter_html_iframe/lib/iframe_mobile.dart index b35f7c7e3b..f6fb7eb683 100644 --- a/packages/flutter_html_iframe/lib/iframe_mobile.dart +++ b/packages/flutter_html_iframe/lib/iframe_mobile.dart @@ -12,7 +12,7 @@ CustomRender iframeRender({NavigationDelegate? navigationDelegate}) => double.tryParse(context.tree.element?.attributes['width'] ?? ""); final givenHeight = double.tryParse(context.tree.element?.attributes['height'] ?? ""); - return Container( + return SizedBox( width: givenWidth ?? (givenHeight ?? 150) * 2, height: givenHeight ?? (givenWidth ?? 300) / 2, child: CssBoxWidget( diff --git a/packages/flutter_html_iframe/lib/iframe_unsupported.dart b/packages/flutter_html_iframe/lib/iframe_unsupported.dart index 588552d36f..fcc858c865 100644 --- a/packages/flutter_html_iframe/lib/iframe_unsupported.dart +++ b/packages/flutter_html_iframe/lib/iframe_unsupported.dart @@ -4,7 +4,6 @@ import 'package:webview_flutter/webview_flutter.dart'; CustomRender iframeRender({NavigationDelegate? navigationDelegate}) => CustomRender.widget(widget: (context, buildChildren) { - return Container( - child: Text("Iframes are currently not supported in this environment"), - ); + return const Text( + "Iframes are currently not supported in this environment"); }); diff --git a/packages/flutter_html_iframe/lib/iframe_web.dart b/packages/flutter_html_iframe/lib/iframe_web.dart index aaf81c23ff..78d7e7d092 100644 --- a/packages/flutter_html_iframe/lib/iframe_web.dart +++ b/packages/flutter_html_iframe/lib/iframe_web.dart @@ -23,7 +23,7 @@ CustomRender iframeRender({NavigationDelegate? navigationDelegate}) => final String createdViewId = getRandString(10); ui.platformViewRegistry .registerViewFactory(createdViewId, (int viewId) => iframe); - return Container( + return SizedBox( width: double.tryParse(context.tree.element?.attributes['width'] ?? "") ?? (double.tryParse( diff --git a/packages/flutter_html_iframe/pubspec.yaml b/packages/flutter_html_iframe/pubspec.yaml index d7207c433c..95bb7b6f28 100644 --- a/packages/flutter_html_iframe/pubspec.yaml +++ b/packages/flutter_html_iframe/pubspec.yaml @@ -20,5 +20,6 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter + flutter_lints: ^2.0.1 flutter: diff --git a/packages/flutter_html_iframe/pubspec_overrides.yaml b/packages/flutter_html_iframe/pubspec_overrides.yaml new file mode 100644 index 0000000000..65126a9bbf --- /dev/null +++ b/packages/flutter_html_iframe/pubspec_overrides.yaml @@ -0,0 +1,4 @@ +# melos_managed_dependency_overrides: flutter_html +dependency_overrides: + flutter_html: + path: ../.. diff --git a/packages/flutter_html_math/analysis_options.yaml b/packages/flutter_html_math/analysis_options.yaml new file mode 100644 index 0000000000..f065cf1ea4 --- /dev/null +++ b/packages/flutter_html_math/analysis_options.yaml @@ -0,0 +1,29 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:flutter_lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at + # https://dart-lang.github.io/linter/lints/index.html. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options \ No newline at end of file diff --git a/packages/flutter_html_math/lib/flutter_html_math.dart b/packages/flutter_html_math/lib/flutter_html_math.dart index 2af8ce170e..8785d410de 100644 --- a/packages/flutter_html_math/lib/flutter_html_math.dart +++ b/packages/flutter_html_math/lib/flutter_html_math.dart @@ -5,13 +5,15 @@ import 'package:flutter/material.dart'; import 'package:flutter_html/flutter_html.dart'; import 'package:flutter_math_fork/flutter_math.dart'; +export 'package:flutter_math_fork/flutter_math.dart'; + /// The CustomRender function for the tag. CustomRender mathRender({OnMathError? onMathError}) => CustomRender.widget(widget: (context, buildChildren) { String texStr = context.tree.element == null ? '' : _parseMathRecursive(context.tree.element!, r''); - return Container( + return SizedBox( width: context.parser.shrinkWrap ? null : MediaQuery.of(context.buildContext).size.width, @@ -38,9 +40,9 @@ String _parseMathRecursive(dom.Node node, String parsed) { if (node is dom.Element) { List nodeList = node.nodes.whereType().toList(); if (node.localName == "math" || node.localName == "mrow") { - nodeList.forEach((element) { + for (var element in nodeList) { parsed = _parseMathRecursive(element, parsed); - }); + } } // note: munder, mover, and munderover do not support placing braces and other // markings above/below elements, instead they are treated as super/subscripts for now. @@ -50,37 +52,34 @@ String _parseMathRecursive(dom.Node node, String parsed) { node.localName == "mover") && nodeList.length == 2) { parsed = _parseMathRecursive(nodeList[0], parsed); - parsed = _parseMathRecursive( - nodeList[1], - parsed + - "${node.localName == "msup" || node.localName == "mover" ? "^" : "_"}{") + - "}"; + parsed = + "${_parseMathRecursive(nodeList[1], "$parsed${node.localName == "msup" || node.localName == "mover" ? "^" : "_"}{")}}"; } if ((node.localName == "msubsup" || node.localName == "munderover") && nodeList.length == 3) { parsed = _parseMathRecursive(nodeList[0], parsed); - parsed = _parseMathRecursive(nodeList[1], parsed + "_{") + "}"; - parsed = _parseMathRecursive(nodeList[2], parsed + "^{") + "}"; + parsed = "${_parseMathRecursive(nodeList[1], "${parsed}_{")}}"; + parsed = "${_parseMathRecursive(nodeList[2], "$parsed^{")}}"; } if (node.localName == "mfrac" && nodeList.length == 2) { - parsed = _parseMathRecursive(nodeList[0], parsed + r"\frac{") + "}"; - parsed = _parseMathRecursive(nodeList[1], parsed + "{") + "}"; + parsed = "${_parseMathRecursive(nodeList[0], parsed + r"\frac{")}}"; + parsed = "${_parseMathRecursive(nodeList[1], "$parsed{")}}"; } // note: doesn't support answer & intermediate steps if (node.localName == "mlongdiv" && nodeList.length == 4) { parsed = _parseMathRecursive(nodeList[0], parsed); - parsed = _parseMathRecursive(nodeList[2], parsed + r"\overline{)") + "}"; + parsed = "${_parseMathRecursive(nodeList[2], parsed + r"\overline{)")}}"; } if (node.localName == "msqrt") { parsed = parsed + r"\sqrt{"; - nodeList.forEach((element) { + for (var element in nodeList) { parsed = _parseMathRecursive(element, parsed); - }); - parsed = parsed + "}"; + } + parsed = "$parsed}"; } if (node.localName == "mroot" && nodeList.length == 2) { - parsed = _parseMathRecursive(nodeList[1], parsed + r"\sqrt[") + "]"; - parsed = _parseMathRecursive(nodeList[0], parsed + "{") + "}"; + parsed = "${_parseMathRecursive(nodeList[1], parsed + r"\sqrt[")}]"; + parsed = "${_parseMathRecursive(nodeList[0], "$parsed{")}}"; } if (node.localName == "mi" || node.localName == "mn" || diff --git a/packages/flutter_html_math/pubspec.yaml b/packages/flutter_html_math/pubspec.yaml index 8a2fa63e50..e67e69a4eb 100644 --- a/packages/flutter_html_math/pubspec.yaml +++ b/packages/flutter_html_math/pubspec.yaml @@ -20,5 +20,6 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter + flutter_lints: ^2.0.1 flutter: diff --git a/packages/flutter_html_math/pubspec_overrides.yaml b/packages/flutter_html_math/pubspec_overrides.yaml new file mode 100644 index 0000000000..65126a9bbf --- /dev/null +++ b/packages/flutter_html_math/pubspec_overrides.yaml @@ -0,0 +1,4 @@ +# melos_managed_dependency_overrides: flutter_html +dependency_overrides: + flutter_html: + path: ../.. diff --git a/packages/flutter_html_svg/analysis_options.yaml b/packages/flutter_html_svg/analysis_options.yaml new file mode 100644 index 0000000000..f065cf1ea4 --- /dev/null +++ b/packages/flutter_html_svg/analysis_options.yaml @@ -0,0 +1,29 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:flutter_lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at + # https://dart-lang.github.io/linter/lints/index.html. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options \ No newline at end of file diff --git a/packages/flutter_html_svg/lib/flutter_html_svg.dart b/packages/flutter_html_svg/lib/flutter_html_svg.dart index dd5b1ff53d..a34bcceb84 100644 --- a/packages/flutter_html_svg/lib/flutter_html_svg.dart +++ b/packages/flutter_html_svg/lib/flutter_html_svg.dart @@ -42,7 +42,7 @@ CustomRender svgDataImageRender() => final dataUri = _dataUriFormat.firstMatch( _src(context.tree.element?.attributes.cast() ?? {})!); final data = dataUri?.namedGroup('data'); - if (data == null) return Container(height: 0, width: 0); + if (data == null) return const SizedBox(height: 0, width: 0); return Builder( key: context.key, builder: (buildContext) { @@ -74,7 +74,7 @@ CustomRender svgDataImageRender() => CustomRender svgNetworkImageRender() => CustomRender.widget(widget: (context, buildChildren) { if (context.tree.element?.attributes["src"] == null) { - return Container(height: 0, width: 0); + return const SizedBox(height: 0, width: 0); } return Builder( key: context.key, @@ -104,7 +104,7 @@ CustomRender svgAssetImageRender() => CustomRender.widget(widget: (context, buildChildren) { if (_src(context.tree.element?.attributes.cast() ?? {}) == null) { - return Container(height: 0, width: 0); + return const SizedBox(height: 0, width: 0); } final assetPath = _src(context.tree.element!.attributes.cast())! .replaceFirst('asset:', ''); @@ -148,7 +148,7 @@ CustomRenderMatcher svgDataUriMatcher( /// A CustomRenderMatcher for an tag with an svg tag over the network CustomRenderMatcher svgNetworkSourceMatcher({ - List schemas: const ["https", "http"], + List schemas = const ["https", "http"], List? domains, String? extension = "svg", }) => @@ -178,7 +178,7 @@ CustomRenderMatcher svgAssetUriMatcher() => (context) => .endsWith(".svg"); final _dataUriFormat = RegExp( - "^(?data):(?image\/[\\w\+\-\.]+)(?;base64)?\,(?.*)"); + "^(?data):(?image\\/[\\w\\+\\-\\.]+)(?;base64)?\\,(?.*)"); String? _src(Map attributes) { return attributes["src"]; diff --git a/packages/flutter_html_svg/pubspec.yaml b/packages/flutter_html_svg/pubspec.yaml index f00202478d..85e9464ef5 100644 --- a/packages/flutter_html_svg/pubspec.yaml +++ b/packages/flutter_html_svg/pubspec.yaml @@ -20,5 +20,7 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter + flutter_lints: ^2.0.1 + meta: ^1.8.0 flutter: diff --git a/packages/flutter_html_svg/pubspec_overrides.yaml b/packages/flutter_html_svg/pubspec_overrides.yaml new file mode 100644 index 0000000000..65126a9bbf --- /dev/null +++ b/packages/flutter_html_svg/pubspec_overrides.yaml @@ -0,0 +1,4 @@ +# melos_managed_dependency_overrides: flutter_html +dependency_overrides: + flutter_html: + path: ../.. diff --git a/packages/flutter_html_svg/test/svg_image_matcher_source_matcher_test.dart b/packages/flutter_html_svg/test/svg_image_matcher_source_matcher_test.dart index eb31307d7a..21debbb8a4 100644 --- a/packages/flutter_html_svg/test/svg_image_matcher_source_matcher_test.dart +++ b/packages/flutter_html_svg/test/svg_image_matcher_source_matcher_test.dart @@ -64,7 +64,7 @@ void main() { String _fakeElement(String? src) { return """ - + """; } @@ -83,7 +83,7 @@ void testImgSrcMatcher( customRenders: { matcher: CustomRender.widget( widget: (RenderContext context, _) { - return Text("Success"); + return const Text("Success"); }, ), }, @@ -98,14 +98,14 @@ void testImgSrcMatcher( class TestApp extends StatelessWidget { final Widget body; - TestApp(this.body); + const TestApp(this.body, {Key? key}) : super(key: key); @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( body: body, - appBar: AppBar(title: Text('flutter_html')), + appBar: AppBar(title: const Text('flutter_html')), ), ); } diff --git a/packages/flutter_html_table/analysis_options.yaml b/packages/flutter_html_table/analysis_options.yaml new file mode 100644 index 0000000000..f065cf1ea4 --- /dev/null +++ b/packages/flutter_html_table/analysis_options.yaml @@ -0,0 +1,29 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:flutter_lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at + # https://dart-lang.github.io/linter/lints/index.html. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options \ No newline at end of file diff --git a/packages/flutter_html_table/lib/flutter_html_table.dart b/packages/flutter_html_table/lib/flutter_html_table.dart index 8a207abbf3..b6fe35c0f4 100644 --- a/packages/flutter_html_table/lib/flutter_html_table.dart +++ b/packages/flutter_html_table/lib/flutter_html_table.dart @@ -13,7 +13,7 @@ CustomRender tableRender() => key: context.key, style: context.style, child: LayoutBuilder( - builder: (_, constraints) => _layoutCells(context, constraints), + builder: (_, constraints) => _layoutCells(context, constraints), ), ); }); @@ -38,20 +38,20 @@ Widget _layoutCells(RenderContext context, BoxConstraints constraints) { if (colWidth != null && colWidth.endsWith("%")) { if (!constraints.hasBoundedWidth) { // In a horizontally unbounded container; always wrap content instead of applying flex - return IntrinsicContentTrackSize(); + return const IntrinsicContentTrackSize(); } final percentageSize = double.tryParse(colWidth.substring(0, colWidth.length - 1)); return percentageSize != null && !percentageSize.isNaN ? FlexibleTrackSize(percentageSize * 0.01) - : IntrinsicContentTrackSize(); + : const IntrinsicContentTrackSize(); } else if (colWidth != null) { final fixedPxSize = double.tryParse(colWidth); return fixedPxSize != null ? FixedTrackSize(fixedPxSize) - : IntrinsicContentTrackSize(); + : const IntrinsicContentTrackSize(); } else { - return IntrinsicContentTrackSize(); + return const IntrinsicContentTrackSize(); } }); }) @@ -66,7 +66,7 @@ Widget _layoutCells(RenderContext context, BoxConstraints constraints) { // All table rows have a height intrinsic to their (spanned) contents final rowSizes = - List.generate(rows.length, (_) => IntrinsicContentTrackSize()); + List.generate(rows.length, (_) => const IntrinsicContentTrackSize()); // Calculate column bounds int columnMax = 0; @@ -103,6 +103,10 @@ Widget _layoutCells(RenderContext context, BoxConstraints constraints) { columnColspanOffset[columni].clamp(1, columnMax - columni - 1); } cells.add(GridPlacement( + columnStart: columni, + columnSpan: min(child.colspan, columnMax - columni), + rowStart: rowi, + rowSpan: min(child.rowspan, rows.length - rowi), child: CssBoxWidget( style: child.style .merge(row.style), //TODO padding/decoration(color/border) @@ -118,10 +122,6 @@ Widget _layoutCells(RenderContext context, BoxConstraints constraints) { ), ), ), - columnStart: columni, - columnSpan: min(child.colspan, columnMax - columni), - rowStart: rowi, - rowSpan: min(child.rowspan, rows.length - rowi), )); columnRowOffset[columni] = child.rowspan - 1; columnColspanOffset[columni] = child.colspan; @@ -138,11 +138,11 @@ Widget _layoutCells(RenderContext context, BoxConstraints constraints) { // Create column tracks (insofar there were no colgroups that already defined them) List finalColumnSizes = columnSizes.take(columnMax).toList(); finalColumnSizes += List.generate(max(0, columnMax - finalColumnSizes.length), - (_) => IntrinsicContentTrackSize()); + (_) => const IntrinsicContentTrackSize()); if (finalColumnSizes.isEmpty || rowSizes.isEmpty) { // No actual cells to show - return SizedBox(); + return const SizedBox(); } return LayoutGrid( diff --git a/packages/flutter_html_table/pubspec.yaml b/packages/flutter_html_table/pubspec.yaml index 564dfb9fe2..4bee5c2ab0 100644 --- a/packages/flutter_html_table/pubspec.yaml +++ b/packages/flutter_html_table/pubspec.yaml @@ -21,5 +21,6 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter + flutter_lints: ^2.0.1 flutter: diff --git a/packages/flutter_html_table/pubspec_overrides.yaml b/packages/flutter_html_table/pubspec_overrides.yaml new file mode 100644 index 0000000000..65126a9bbf --- /dev/null +++ b/packages/flutter_html_table/pubspec_overrides.yaml @@ -0,0 +1,4 @@ +# melos_managed_dependency_overrides: flutter_html +dependency_overrides: + flutter_html: + path: ../.. diff --git a/packages/flutter_html_video/analysis_options.yaml b/packages/flutter_html_video/analysis_options.yaml new file mode 100644 index 0000000000..f065cf1ea4 --- /dev/null +++ b/packages/flutter_html_video/analysis_options.yaml @@ -0,0 +1,29 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:flutter_lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at + # https://dart-lang.github.io/linter/lints/index.html. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options \ No newline at end of file diff --git a/packages/flutter_html_video/lib/flutter_html_video.dart b/packages/flutter_html_video/lib/flutter_html_video.dart index 2dc6faa62d..b1ea0ca2de 100644 --- a/packages/flutter_html_video/lib/flutter_html_video.dart +++ b/packages/flutter_html_video/lib/flutter_html_video.dart @@ -25,10 +25,11 @@ class VideoWidget extends StatefulWidget { final RenderContext context; final VideoControllerCallback? callback; - VideoWidget({ + const VideoWidget({ + Key? key, required this.context, this.callback, - }); + }) : super(key: key); @override State createState() => _VideoWidgetState(); @@ -83,7 +84,7 @@ class _VideoWidgetState extends State { @override Widget build(BuildContext bContext) { if (_chewieController == null) { - return Container(height: 0, width: 0); + return const SizedBox(height: 0, width: 0); } final child = Container( key: widget.context.key, diff --git a/packages/flutter_html_video/pubspec.yaml b/packages/flutter_html_video/pubspec.yaml index 50354655c1..9a07f6052c 100644 --- a/packages/flutter_html_video/pubspec.yaml +++ b/packages/flutter_html_video/pubspec.yaml @@ -21,5 +21,6 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter + flutter_lints: ^2.0.1 flutter: diff --git a/packages/flutter_html_video/pubspec_overrides.yaml b/packages/flutter_html_video/pubspec_overrides.yaml new file mode 100644 index 0000000000..65126a9bbf --- /dev/null +++ b/packages/flutter_html_video/pubspec_overrides.yaml @@ -0,0 +1,4 @@ +# melos_managed_dependency_overrides: flutter_html +dependency_overrides: + flutter_html: + path: ../.. diff --git a/pubspec.yaml b/pubspec.yaml index 6f1baadd9f..9799b727ec 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -26,5 +26,7 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter + flutter_lints: ^2.0.1 + meta: ^1.8.0 flutter: diff --git a/test/flutter_html_test.dart b/test/flutter_html_test.dart index 9a5a752c70..30acdbe449 100644 --- a/test/flutter_html_test.dart +++ b/test/flutter_html_test.dart @@ -33,7 +33,7 @@ void main() { testWidgets( "Check that widget displays given text", - (tester) async { + (tester) async { await tester.pumpWidget( MaterialApp( home: Html( @@ -56,24 +56,28 @@ void main() { expect(find.text('Text', findRichText: true), findsOneWidget); }); - testWidgets('Check that a simple element is hidden when tagsList does not contain it', (tester) async { + testWidgets( + 'Check that a simple element is hidden when tagsList does not contain it', + (tester) async { await tester.pumpWidget( MaterialApp( home: Html( data: "

Text

", - tagsList: ['div'], //Anything but `p` + tagsList: const ['div'], //Anything but `p` ), ), ); expect(find.text('Text', findRichText: true), findsNothing); }); - testWidgets('Check that a simple element is displayed when it is included in tagsList', (tester) async { + testWidgets( + 'Check that a simple element is displayed when it is included in tagsList', + (tester) async { await tester.pumpWidget( MaterialApp( home: Html( data: "

Text

", - tagsList: ['html', 'body', 'p'], + tagsList: const ['html', 'body', 'p'], ), ), ); diff --git a/test/golden_test.dart b/test/golden_test.dart index 131ee5a948..1f62cfb414 100644 --- a/test/golden_test.dart +++ b/test/golden_test.dart @@ -7,7 +7,7 @@ import 'test_data.dart'; class TestApp extends StatelessWidget { final Widget body; - TestApp(this.body); + const TestApp(this.body, {super.key}); @override Widget build(BuildContext context) { @@ -62,11 +62,12 @@ void main() { // await expectLater(find.byType(Html), matchesGoldenFile('./goldens/whitespace.png')); }); - testWidgets('whitespace between inline elements golden test', (WidgetTester tester) async { + testWidgets('whitespace between inline elements golden test', + (WidgetTester tester) async { await tester.pumpWidget( TestApp( Html( - data:"""Harry Potter""", + data: """Harry Potter""", ), ), ); diff --git a/test/html_parser_test.dart b/test/html_parser_test.dart index 3937c4a296..056de9c148 100644 --- a/test/html_parser_test.dart +++ b/test/html_parser_test.dart @@ -15,14 +15,15 @@ void main() { ), ); }); - testWidgets('Test new parser (hacky workaround to get BuildContext)', (WidgetTester tester) async { + testWidgets('Test new parser (hacky workaround to get BuildContext)', + (WidgetTester tester) async { await tester.pumpWidget( Builder( builder: (BuildContext context) { testNewParser(context); // The builder function must return a widget. - return Placeholder(); + return const Placeholder(); }, ), ); @@ -32,9 +33,8 @@ void main() { void testNewParser(BuildContext context) { HtmlParser.parseHTML("Hello, World!"); - StyledElement tree = HtmlParser.lexDomTree( - HtmlParser.parseHTML( - "Hello! Hello, World!Hello, New World!"), + HtmlParser.lexDomTree( + HtmlParser.parseHTML("Hello! Hello, World!Hello, New World!"), [], Html.tags, context, @@ -49,16 +49,15 @@ void testNewParser(BuildContext context) { onImageError: null, shrinkWrap: false, selectable: true, - style: {}, + style: const {}, customRenders: generateDefaultRenders(), tagsList: Html.tags, selectionControls: null, scrollPhysics: null, ), ); - print(tree.toString()); - tree = HtmlParser.lexDomTree( + HtmlParser.lexDomTree( HtmlParser.parseHTML( "Hello, World! This is a link"), [], @@ -75,23 +74,23 @@ void testNewParser(BuildContext context) { onImageError: null, shrinkWrap: false, selectable: true, - style: {}, + style: const {}, customRenders: generateDefaultRenders(), tagsList: Html.tags, selectionControls: null, scrollPhysics: null, ), ); - print(tree.toString()); - tree = HtmlParser.lexDomTree( - HtmlParser.parseHTML(""), + HtmlParser.lexDomTree( + HtmlParser.parseHTML(""), [], Html.tags, context, HtmlParser( key: null, - htmlData: HtmlParser.parseHTML(""), + htmlData: HtmlParser.parseHTML( + ""), onLinkTap: null, onAnchorTap: null, onImageTap: null, @@ -99,25 +98,24 @@ void testNewParser(BuildContext context) { onImageError: null, shrinkWrap: false, selectable: true, - style: {}, + style: const {}, customRenders: generateDefaultRenders(), tagsList: Html.tags, selectionControls: null, scrollPhysics: null, ), ); - print(tree.toString()); - tree = HtmlParser.lexDomTree( + HtmlParser.lexDomTree( HtmlParser.parseHTML( - "
Link
Hello, World! Bold and Italic
"), + "
Link
Hello, World! Bold and Italic
"), [], Html.tags, context, HtmlParser( key: null, htmlData: HtmlParser.parseHTML( - "
Link
Hello, World! Bold and Italic
"), + "
Link
Hello, World! Bold and Italic
"), onLinkTap: null, onAnchorTap: null, onImageTap: null, @@ -125,14 +123,13 @@ void testNewParser(BuildContext context) { onImageError: null, shrinkWrap: false, selectable: true, - style: {}, + style: const {}, customRenders: generateDefaultRenders(), tagsList: Html.tags, selectionControls: null, scrollPhysics: null, ), ); - print(tree.toString()); /*ReplacedElement videoContentElement = parseReplacedElement( HtmlParser.parseHTML(""" @@ -174,7 +171,7 @@ void testNewParser(BuildContext context) { }*/ Style style1 = Style( - display: Display.BLOCK, + display: Display.block, fontWeight: FontWeight.bold, ); @@ -186,7 +183,7 @@ void testNewParser(BuildContext context) { Style finalStyle = style1.merge(style2); - expect(finalStyle.display, equals(Display.BLOCK)); + expect(finalStyle.display, equals(Display.block)); expect(finalStyle.before, equals("* ")); expect(finalStyle.direction, equals(TextDirection.rtl)); expect(finalStyle.fontStyle, equals(FontStyle.italic)); diff --git a/test/image_render_source_matcher_test.dart b/test/image_render_source_matcher_test.dart index a259d161d2..579a9c2f75 100644 --- a/test/image_render_source_matcher_test.dart +++ b/test/image_render_source_matcher_test.dart @@ -87,25 +87,29 @@ void main() { testImgSrcMatcher( "matches schema, domain and extension", matcher, - imgSrc: 'https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_92x30dp.png', + imgSrc: + 'https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_92x30dp.png', shouldMatch: true, ); testImgSrcMatcher( "doesn't match if schema is different", matcher, - imgSrc: 'http://www.google.com/images/branding/googlelogo/2x/googlelogo_color_92x30dp.png', + imgSrc: + 'http://www.google.com/images/branding/googlelogo/2x/googlelogo_color_92x30dp.png', shouldMatch: false, ); testImgSrcMatcher( "doesn't match if domain is different", matcher, - imgSrc: 'https://google.com/images/branding/googlelogo/2x/googlelogo_color_92x30dp.png', + imgSrc: + 'https://google.com/images/branding/googlelogo/2x/googlelogo_color_92x30dp.png', shouldMatch: false, ); testImgSrcMatcher( "doesn't match if file extension is different", matcher, - imgSrc: 'https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_92x30dppng', + imgSrc: + 'https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_92x30dppng', shouldMatch: false, ); testImgSrcMatcher( @@ -179,7 +183,7 @@ void main() { String _fakeElement(String? src) { return """ - + """; } @@ -198,13 +202,14 @@ void testImgSrcMatcher( customRenders: { matcher: CustomRender.widget( widget: (RenderContext context, _) { - return Text("Success"); + return const Text("Success"); }, ), }, ), ), ); - await expectLater(find.text("Success"), shouldMatch ? findsOneWidget : findsNothing); + await expectLater( + find.text("Success"), shouldMatch ? findsOneWidget : findsNothing); }); } diff --git a/test/style/dimension_test.dart b/test/style/dimension_test.dart index cf239249f2..8ddedcd32e 100644 --- a/test/style/dimension_test.dart +++ b/test/style/dimension_test.dart @@ -41,4 +41,4 @@ void main() { expect(lengthPercent.value, equals(nonZeroNumber)); expect(lengthPercent.unit, equals(Unit.percent)); }); -} \ No newline at end of file +} diff --git a/test/style/fontsize_test.dart b/test/style/fontsize_test.dart index e985d73706..36b8e29605 100644 --- a/test/style/fontsize_test.dart +++ b/test/style/fontsize_test.dart @@ -5,7 +5,7 @@ import 'package:flutter_test/flutter_test.dart'; void main() { test('Check basic FontSize inheritance', () { final FontSize parent = FontSize(16); - final FontSize? child = null; + const FontSize? child = null; final result = FontSize.inherit(parent, child); @@ -13,8 +13,8 @@ void main() { }); test('Check double null FontSize inheritance', () { - final FontSize? parent = null; - final FontSize? child = null; + const FontSize? parent = null; + const FontSize? child = null; final result = FontSize.inherit(parent, child); @@ -22,8 +22,8 @@ void main() { }); test('Check basic em inheritance', () { - final FontSize? parent = FontSize(16); - final FontSize? child = FontSize(1, Unit.em); + final FontSize parent = FontSize(16); + final FontSize child = FontSize(1, Unit.em); final result = FontSize.inherit(parent, child); @@ -31,8 +31,8 @@ void main() { }); test('Check factor em inheritance', () { - final FontSize? parent = FontSize(16); - final FontSize? child = FontSize(0.5, Unit.em); + final FontSize parent = FontSize(16); + final FontSize child = FontSize(0.5, Unit.em); final result = FontSize.inherit(parent, child); @@ -40,8 +40,8 @@ void main() { }); test('Check basic % inheritance', () { - final FontSize? parent = FontSize(16); - final FontSize? child = FontSize(100, Unit.percent); + final FontSize parent = FontSize(16); + final FontSize child = FontSize(100, Unit.percent); final result = FontSize.inherit(parent, child); @@ -49,11 +49,11 @@ void main() { }); test('Check scaled % inheritance', () { - final FontSize? parent = FontSize(16); - final FontSize? child = FontSize(50, Unit.percent); + final FontSize parent = FontSize(16); + final FontSize child = FontSize(50, Unit.percent); final result = FontSize.inherit(parent, child); expect(result?.value, equals(8)); }); -} \ No newline at end of file +} diff --git a/test/test_data.dart b/test/test_data.dart index c2fc16a601..f9c74ea1ce 100644 --- a/test/test_data.dart +++ b/test/test_data.dart @@ -49,12 +49,18 @@ const testData = { 'nav': '', 'noscript': '', 'p': '

Hello, World!

', - 'p-with-inline-css-text-align-center': '

Hello, World!

', - 'p-with-inline-css-text-align-right': '

Hello, World!

', - 'p-with-inline-css-text-align-left': '

Hello, World!

', - 'p-with-inline-css-text-align-justify': '

Hello, World!

', - 'p-with-inline-css-text-align-end': '

Hello, World!

', - 'p-with-inline-css-text-align-start': '

Hello, World!

', + 'p-with-inline-css-text-align-center': + '

Hello, World!

', + 'p-with-inline-css-text-align-right': + '

Hello, World!

', + 'p-with-inline-css-text-align-left': + '

Hello, World!

', + 'p-with-inline-css-text-align-justify': + '

Hello, World!

', + 'p-with-inline-css-text-align-end': + '

Hello, World!

', + 'p-with-inline-css-text-align-start': + '

Hello, World!

', 'pre': '
Hello, World!
', 'q': 'Hello, World!', 'rp': ' ㄏㄢˋ ', @@ -65,12 +71,18 @@ const testData = { 'section': '
Hello, World!
', 'small': 'Hello, World!', 'span': 'Hello, World!', - 'span-with-inline-css-color': '

Hello, World!

', - 'span-with-inline-css-color-rgb': '

Hello, World!

', - 'span-with-inline-css-color-rgba': '

Hello, World!

', - 'span-with-inline-css-backgroundcolor': '

Hello, World!

', - 'span-with-inline-css-backgroundcolor-rgb': '

Hello, World!

', - 'span-with-inline-css-backgroundcolor-rgba': '

Hello, World!

', + 'span-with-inline-css-color': + '

Hello, World!

', + 'span-with-inline-css-color-rgb': + '

Hello, World!

', + 'span-with-inline-css-color-rgba': + '

Hello, World!

', + 'span-with-inline-css-backgroundcolor': + '

Hello, World!

', + 'span-with-inline-css-backgroundcolor-rgb': + '

Hello, World!

', + 'span-with-inline-css-backgroundcolor-rgba': + '

Hello, World!

', 'strike': 'Hello, World!', 'strong': 'Hello, World!', 'sub': 'Hello, World!', diff --git a/test/utils_test.dart b/test/utils_test.dart index c4cec61f93..47d532d8a4 100644 --- a/test/utils_test.dart +++ b/test/utils_test.dart @@ -7,14 +7,15 @@ import 'package:flutter_test/flutter_test.dart'; void main() { test('Tests that namedColors returns a valid color', () { - expect(ExpressionMapping.namedColorToColor('red'), equals(ExpressionMapping.stringToColor(namedColors['Red']!))); + expect(ExpressionMapping.namedColorToColor('red'), + equals(ExpressionMapping.stringToColor(namedColors['Red']!))); expect(namedColors['Red'], equals('#FF0000')); }); test('CustomBorderSide does not allow negative width', () { expect(() => CustomBorderSide(width: -5), throwsAssertionError); - expect(CustomBorderSide(width: 0), TypeMatcher()); - expect(CustomBorderSide(width: 5), TypeMatcher()); + expect(CustomBorderSide(width: 0), const TypeMatcher()); + expect(CustomBorderSide(width: 5), const TypeMatcher()); }); const originalString = 'Hello'; @@ -25,18 +26,21 @@ void main() { expect(originalString.transformed(null), equals(originalString)); }); - test('TextTransformUtil uppercases correctly', () { - expect(originalString.transformed(TextTransform.uppercase), equals(uppercaseString)); + test('TextTransformUtil uppercase-s correctly', () { + expect(originalString.transformed(TextTransform.uppercase), + equals(uppercaseString)); }); - test('TextTransformUtil lowercases correctly', () { - expect(originalString.transformed(TextTransform.lowercase), equals(lowercaseString)); + test('TextTransformUtil lowercase-s correctly', () { + expect(originalString.transformed(TextTransform.lowercase), + equals(lowercaseString)); }); const originalLongString = 'Hello, world! pub.dev'; const capitalizedLongString = 'Hello, World! Pub.Dev'; - test('TextTransformUtil capitalizs correctly', () { - expect(originalLongString.transformed(TextTransform.capitalize), equals(capitalizedLongString)); + test('TextTransformUtil capitalizes correctly', () { + expect(originalLongString.transformed(TextTransform.capitalize), + equals(capitalizedLongString)); }); -} \ No newline at end of file +}