[flutter_markdown] add padding for p, h1-h6 (#465)

diff --git a/packages/flutter_markdown/CHANGELOG.md b/packages/flutter_markdown/CHANGELOG.md
index 484fb46..6a6a568 100644
--- a/packages/flutter_markdown/CHANGELOG.md
+++ b/packages/flutter_markdown/CHANGELOG.md
@@ -1,6 +1,8 @@
-## NEXT
+## 0.6.7
 
-* Fix `unnecessary_import` lint errors.
+ * Fix `unnecessary_import` lint errors.
+ * Added option pPadding
+ * Added options h1Padding - h6Padding
 
 ## 0.6.6
 
diff --git a/packages/flutter_markdown/example/lib/demos/wrap_alignment_demo.dart b/packages/flutter_markdown/example/lib/demos/wrap_alignment_demo.dart
index f1a086e..74faa29 100644
--- a/packages/flutter_markdown/example/lib/demos/wrap_alignment_demo.dart
+++ b/packages/flutter_markdown/example/lib/demos/wrap_alignment_demo.dart
@@ -109,12 +109,19 @@
                       MarkdownStyleSheet.fromTheme(Theme.of(context)).copyWith(
                     blockSpacing: _blockSpacing,
                     textAlign: _wrapAlignment,
+                    pPadding: const EdgeInsets.only(bottom: 4.0),
                     h1Align: _wrapAlignment,
+                    h1Padding: const EdgeInsets.only(left: 4.0),
                     h2Align: _wrapAlignment,
+                    h2Padding: const EdgeInsets.only(left: 8.0),
                     h3Align: _wrapAlignment,
+                    h3Padding: const EdgeInsets.only(left: 12.0),
                     h4Align: _wrapAlignment,
+                    h4Padding: const EdgeInsets.only(left: 16.0),
                     h5Align: _wrapAlignment,
+                    h5Padding: const EdgeInsets.only(left: 20.0),
                     h6Align: _wrapAlignment,
+                    h6Padding: const EdgeInsets.only(left: 24.0),
                     unorderedListAlign: _wrapAlignment,
                     orderedListAlign: _wrapAlignment,
                     blockquoteAlign: _wrapAlignment,
diff --git a/packages/flutter_markdown/lib/src/builder.dart b/packages/flutter_markdown/lib/src/builder.dart
index dfa53e6..a9be31f 100644
--- a/packages/flutter_markdown/lib/src/builder.dart
+++ b/packages/flutter_markdown/lib/src/builder.dart
@@ -598,9 +598,11 @@
 
     WrapAlignment blockAlignment = WrapAlignment.start;
     TextAlign textAlign = TextAlign.start;
+    EdgeInsets textPadding = EdgeInsets.zero;
     if (_isBlockTag(_currentBlockTag)) {
       blockAlignment = _wrapAlignmentForBlockTag(_currentBlockTag);
       textAlign = _textAlignForBlockTag(_currentBlockTag);
+      textPadding = _textPaddingForBlockTag(_currentBlockTag);
     }
 
     final _InlineElement inline = _inlines.single;
@@ -614,7 +616,14 @@
         children: mergedInlines,
         alignment: blockAlignment,
       );
-      _addBlockChild(wrap);
+
+      if (textPadding == EdgeInsets.zero) {
+        _addBlockChild(wrap);
+      } else {
+        final Padding padding = Padding(padding: textPadding, child: wrap);
+        _addBlockChild(padding);
+      }
+
       _inlines.clear();
     }
   }
@@ -722,6 +731,26 @@
     return WrapAlignment.start;
   }
 
+  EdgeInsets _textPaddingForBlockTag(String? blockTag) {
+    switch (blockTag) {
+      case 'p':
+        return styleSheet.pPadding!;
+      case 'h1':
+        return styleSheet.h1Padding!;
+      case 'h2':
+        return styleSheet.h2Padding!;
+      case 'h3':
+        return styleSheet.h3Padding!;
+      case 'h4':
+        return styleSheet.h4Padding!;
+      case 'h5':
+        return styleSheet.h5Padding!;
+      case 'h6':
+        return styleSheet.h6Padding!;
+    }
+    return EdgeInsets.zero;
+  }
+
   /// Combine text spans with equivalent properties into a single span.
   TextSpan? _mergeSimilarTextSpans(List<TextSpan>? textSpans) {
     if (textSpans == null || textSpans.length < 2) {
diff --git a/packages/flutter_markdown/lib/src/style_sheet.dart b/packages/flutter_markdown/lib/src/style_sheet.dart
index 8916779..d25780b 100644
--- a/packages/flutter_markdown/lib/src/style_sheet.dart
+++ b/packages/flutter_markdown/lib/src/style_sheet.dart
@@ -11,13 +11,20 @@
   MarkdownStyleSheet({
     this.a,
     this.p,
+    this.pPadding,
     this.code,
     this.h1,
+    this.h1Padding,
     this.h2,
+    this.h2Padding,
     this.h3,
+    this.h3Padding,
     this.h4,
+    this.h4Padding,
     this.h5,
+    this.h5Padding,
     this.h6,
+    this.h6Padding,
     this.em,
     this.strong,
     this.del,
@@ -81,17 +88,24 @@
     return MarkdownStyleSheet(
       a: const TextStyle(color: Colors.blue),
       p: theme.textTheme.bodyText2,
+      pPadding: EdgeInsets.zero,
       code: theme.textTheme.bodyText2!.copyWith(
         backgroundColor: theme.cardTheme.color ?? theme.cardColor,
         fontFamily: 'monospace',
         fontSize: theme.textTheme.bodyText2!.fontSize! * 0.85,
       ),
       h1: theme.textTheme.headline5,
+      h1Padding: EdgeInsets.zero,
       h2: theme.textTheme.headline6,
+      h2Padding: EdgeInsets.zero,
       h3: theme.textTheme.subtitle1,
+      h3Padding: EdgeInsets.zero,
       h4: theme.textTheme.bodyText1,
+      h4Padding: EdgeInsets.zero,
       h5: theme.textTheme.bodyText1,
+      h5Padding: EdgeInsets.zero,
       h6: theme.textTheme.bodyText1,
+      h6Padding: EdgeInsets.zero,
       em: const TextStyle(fontStyle: FontStyle.italic),
       strong: const TextStyle(fontWeight: FontWeight.bold),
       del: const TextStyle(decoration: TextDecoration.lineThrough),
@@ -145,6 +159,7 @@
             : CupertinoColors.link.color,
       ),
       p: theme.textTheme.textStyle,
+      pPadding: EdgeInsets.zero,
       code: theme.textTheme.textStyle.copyWith(
         backgroundColor: theme.brightness == Brightness.dark
             ? CupertinoColors.systemGrey6.darkColor
@@ -156,25 +171,31 @@
         fontWeight: FontWeight.w500,
         fontSize: theme.textTheme.textStyle.fontSize! + 10,
       ),
+      h1Padding: EdgeInsets.zero,
       h2: theme.textTheme.textStyle.copyWith(
         fontWeight: FontWeight.w500,
         fontSize: theme.textTheme.textStyle.fontSize! + 8,
       ),
+      h2Padding: EdgeInsets.zero,
       h3: theme.textTheme.textStyle.copyWith(
         fontWeight: FontWeight.w500,
         fontSize: theme.textTheme.textStyle.fontSize! + 6,
       ),
+      h3Padding: EdgeInsets.zero,
       h4: theme.textTheme.textStyle.copyWith(
         fontWeight: FontWeight.w500,
         fontSize: theme.textTheme.textStyle.fontSize! + 4,
       ),
+      h4Padding: EdgeInsets.zero,
       h5: theme.textTheme.textStyle.copyWith(
         fontWeight: FontWeight.w500,
         fontSize: theme.textTheme.textStyle.fontSize! + 2,
       ),
+      h5Padding: EdgeInsets.zero,
       h6: theme.textTheme.textStyle.copyWith(
         fontWeight: FontWeight.w500,
       ),
+      h6Padding: EdgeInsets.zero,
       em: theme.textTheme.textStyle.copyWith(
         fontStyle: FontStyle.italic,
       ),
@@ -247,17 +268,24 @@
     return MarkdownStyleSheet(
       a: const TextStyle(color: Colors.blue),
       p: theme.textTheme.bodyText2,
+      pPadding: EdgeInsets.zero,
       code: theme.textTheme.bodyText2!.copyWith(
         backgroundColor: theme.cardTheme.color ?? theme.cardColor,
         fontFamily: 'monospace',
         fontSize: theme.textTheme.bodyText2!.fontSize! * 0.85,
       ),
       h1: theme.textTheme.headline2,
+      h1Padding: EdgeInsets.zero,
       h2: theme.textTheme.headline3,
+      h2Padding: EdgeInsets.zero,
       h3: theme.textTheme.headline4,
+      h3Padding: EdgeInsets.zero,
       h4: theme.textTheme.headline5,
+      h4Padding: EdgeInsets.zero,
       h5: theme.textTheme.headline6,
+      h5Padding: EdgeInsets.zero,
       h6: theme.textTheme.subtitle1,
+      h6Padding: EdgeInsets.zero,
       em: const TextStyle(fontStyle: FontStyle.italic),
       strong: const TextStyle(fontWeight: FontWeight.bold),
       del: const TextStyle(decoration: TextDecoration.lineThrough),
@@ -305,13 +333,20 @@
   MarkdownStyleSheet copyWith({
     TextStyle? a,
     TextStyle? p,
+    EdgeInsets? pPadding,
     TextStyle? code,
     TextStyle? h1,
+    EdgeInsets? h1Padding,
     TextStyle? h2,
+    EdgeInsets? h2Padding,
     TextStyle? h3,
+    EdgeInsets? h3Padding,
     TextStyle? h4,
+    EdgeInsets? h4Padding,
     TextStyle? h5,
+    EdgeInsets? h5Padding,
     TextStyle? h6,
+    EdgeInsets? h6Padding,
     TextStyle? em,
     TextStyle? strong,
     TextStyle? del,
@@ -350,13 +385,20 @@
     return MarkdownStyleSheet(
       a: a ?? this.a,
       p: p ?? this.p,
+      pPadding: pPadding ?? this.pPadding,
       code: code ?? this.code,
       h1: h1 ?? this.h1,
+      h1Padding: h1Padding ?? this.h1Padding,
       h2: h2 ?? this.h2,
+      h2Padding: h2Padding ?? this.h2Padding,
       h3: h3 ?? this.h3,
+      h3Padding: h3Padding ?? this.h3Padding,
       h4: h4 ?? this.h4,
+      h4Padding: h4Padding ?? this.h4Padding,
       h5: h5 ?? this.h5,
+      h5Padding: h5Padding ?? this.h5Padding,
       h6: h6 ?? this.h6,
+      h6Padding: h6Padding ?? this.h6Padding,
       em: em ?? this.em,
       strong: strong ?? this.strong,
       del: del ?? this.del,
@@ -404,13 +446,20 @@
     return copyWith(
       a: a!.merge(other.a),
       p: p!.merge(other.p),
+      pPadding: other.pPadding,
       code: code!.merge(other.code),
       h1: h1!.merge(other.h1),
+      h1Padding: other.h1Padding,
       h2: h2!.merge(other.h2),
+      h2Padding: other.h2Padding,
       h3: h3!.merge(other.h3),
+      h3Padding: other.h3Padding,
       h4: h4!.merge(other.h4),
+      h4Padding: other.h4Padding,
       h5: h5!.merge(other.h5),
+      h5Padding: other.h5Padding,
       h6: h6!.merge(other.h6),
+      h6Padding: other.h6Padding,
       em: em!.merge(other.em),
       strong: strong!.merge(other.strong),
       del: del!.merge(other.del),
@@ -454,27 +503,48 @@
   /// The [TextStyle] to use for `p` elements.
   final TextStyle? p;
 
+  /// The padding to use for `p` elements.
+  final EdgeInsets? pPadding;
+
   /// The [TextStyle] to use for `code` elements.
   final TextStyle? code;
 
   /// The [TextStyle] to use for `h1` elements.
   final TextStyle? h1;
 
+  /// The padding to use for `h1` elements.
+  final EdgeInsets? h1Padding;
+
   /// The [TextStyle] to use for `h2` elements.
   final TextStyle? h2;
 
+  /// The padding to use for `h2` elements.
+  final EdgeInsets? h2Padding;
+
   /// The [TextStyle] to use for `h3` elements.
   final TextStyle? h3;
 
+  /// The padding to use for `h3` elements.
+  final EdgeInsets? h3Padding;
+
   /// The [TextStyle] to use for `h4` elements.
   final TextStyle? h4;
 
+  /// The padding to use for `h4` elements.
+  final EdgeInsets? h4Padding;
+
   /// The [TextStyle] to use for `h5` elements.
   final TextStyle? h5;
 
+  /// The padding to use for `h5` elements.
+  final EdgeInsets? h5Padding;
+
   /// The [TextStyle] to use for `h6` elements.
   final TextStyle? h6;
 
+  /// The padding to use for `h6` elements.
+  final EdgeInsets? h6Padding;
+
   /// The [TextStyle] to use for `em` elements.
   final TextStyle? em;
 
@@ -593,13 +663,20 @@
     final MarkdownStyleSheet typedOther = other;
     return typedOther.a == a &&
         typedOther.p == p &&
+        typedOther.pPadding == pPadding &&
         typedOther.code == code &&
         typedOther.h1 == h1 &&
+        typedOther.h1Padding == h1Padding &&
         typedOther.h2 == h2 &&
+        typedOther.h2Padding == h2Padding &&
         typedOther.h3 == h3 &&
+        typedOther.h3Padding == h3Padding &&
         typedOther.h4 == h4 &&
+        typedOther.h4Padding == h4Padding &&
         typedOther.h5 == h5 &&
+        typedOther.h5Padding == h5Padding &&
         typedOther.h6 == h6 &&
+        typedOther.h6Padding == h6Padding &&
         typedOther.em == em &&
         typedOther.strong == strong &&
         typedOther.del == del &&
@@ -642,13 +719,20 @@
     return hashList(<Object?>[
       a,
       p,
+      pPadding,
       code,
       h1,
+      h1Padding,
       h2,
+      h2Padding,
       h3,
+      h3Padding,
       h4,
+      h4Padding,
       h5,
+      h5Padding,
       h6,
+      h6Padding,
       em,
       strong,
       del,
diff --git a/packages/flutter_markdown/pubspec.yaml b/packages/flutter_markdown/pubspec.yaml
index 51a8b84..0ce150c 100644
--- a/packages/flutter_markdown/pubspec.yaml
+++ b/packages/flutter_markdown/pubspec.yaml
@@ -4,7 +4,7 @@
   formatted with simple Markdown tags.
 repository: https://github.com/flutter/packages/tree/master/packages/flutter_markdown
 issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+flutter_markdown%22
-version: 0.6.6
+version: 0.6.7
 
 environment:
   sdk: ">=2.12.0 <3.0.0"
diff --git a/packages/flutter_markdown/test/style_sheet_test.dart b/packages/flutter_markdown/test/style_sheet_test.dart
index 3738362..349e8e6 100644
--- a/packages/flutter_markdown/test/style_sheet_test.dart
+++ b/packages/flutter_markdown/test/style_sheet_test.dart
@@ -302,5 +302,98 @@
         );
       },
     );
+
+    testWidgets(
+      'check widgets for use stylesheet option h1Padding',
+      (WidgetTester tester) async {
+        const String data = '# Header';
+        const double paddingX = 20.0;
+        final MarkdownStyleSheet style = MarkdownStyleSheet(
+          h1Padding: const EdgeInsets.symmetric(horizontal: paddingX),
+        );
+
+        await tester.pumpWidget(boilerplate(MarkdownBody(
+          data: data,
+          styleSheet: style,
+        )));
+
+        final Iterable<Widget> widgets = tester.allWidgets;
+        expectWidgetTypes(widgets, <Type>[
+          Directionality,
+          MarkdownBody,
+          Column,
+          Padding,
+          Wrap,
+          RichText,
+        ]);
+        expectTextStrings(widgets, <String>['Header']);
+      },
+    );
+
+    testWidgets(
+      'use stylesheet option pPadding',
+      (WidgetTester tester) async {
+        const double paddingX = 20.0;
+        final MarkdownStyleSheet style = MarkdownStyleSheet(
+          pPadding: const EdgeInsets.symmetric(horizontal: paddingX),
+        );
+
+        await tester.pumpWidget(
+          boilerplate(
+            Markdown(
+              data: 'Test line 1\n\nTest line 2\n\nTest line 3\n# H1',
+              styleSheet: style,
+            ),
+          ),
+        );
+
+        final List<Padding> paddings =
+            tester.widgetList<Padding>(find.byType(Padding)).toList();
+
+        expect(paddings.length, 3);
+        expect(
+          paddings.every(
+            (Padding p) => p.padding.along(Axis.horizontal) == paddingX * 2,
+          ),
+          true,
+        );
+      },
+    );
+
+    testWidgets(
+      'use stylesheet option h1Padding-h6Padding',
+      (WidgetTester tester) async {
+        const double paddingX = 20.0;
+        final MarkdownStyleSheet style = MarkdownStyleSheet(
+          h1Padding: const EdgeInsets.symmetric(horizontal: paddingX),
+          h2Padding: const EdgeInsets.symmetric(horizontal: paddingX),
+          h3Padding: const EdgeInsets.symmetric(horizontal: paddingX),
+          h4Padding: const EdgeInsets.symmetric(horizontal: paddingX),
+          h5Padding: const EdgeInsets.symmetric(horizontal: paddingX),
+          h6Padding: const EdgeInsets.symmetric(horizontal: paddingX),
+        );
+
+        await tester.pumpWidget(
+          boilerplate(
+            Markdown(
+              data:
+                  'Test\n\n# H1\n## H2\n### H3\n#### H4\n##### H5\n###### H6\n',
+              styleSheet: style,
+            ),
+          ),
+        );
+
+        final List<Padding> paddings =
+            tester.widgetList<Padding>(find.byType(Padding)).toList();
+
+        expect(paddings.length, 6);
+        expect(
+          paddings.every(
+            (Padding p) => p.padding.along(Axis.horizontal) == paddingX * 2,
+          ),
+          true,
+        );
+      },
+    );
   });
 }