| // Copyright 2013 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import 'package:flutter/material.dart'; |
| import 'package:flutter/services.dart'; |
| import 'package:flutter_markdown/flutter_markdown.dart'; |
| import 'package:markdown/markdown.dart' as md; |
| import '../shared/dropdown_menu.dart'; |
| import '../shared/markdown_demo_widget.dart'; |
| import '../shared/markdown_extensions.dart'; |
| |
| // ignore_for_file: public_member_api_docs |
| |
| const String _notes = ''' |
| # Wrap Alignment Demo |
| --- |
| The Wrap Alignment Demo shows the effect of defining a wrap alignment for |
| various Markdown elements. Wrap alignments for the block elements text |
| paragraphs, headers, ordered and unordered lists, blockquotes, and code blocks |
| are set in the **MarkdownStyleSheet**. This demo shows the effect of setting |
| this parameter universally on these block elements for illustration purposes, |
| but they are independent settings. |
| |
| This demo also shows the effect of setting the **MarkdownStyleSheet** block |
| spacing parameter. The Markdown widget lays out block elements in a column using |
| **SizedBox** widgets to separate widgets with formatted output. The block |
| spacing parameter sets the height of the **SizedBox**. |
| '''; |
| |
| // TODO(goderbauer): Restructure the examples to avoid this ignore, https://github.com/flutter/flutter/issues/110208. |
| // ignore: avoid_implementing_value_types |
| class WrapAlignmentDemo extends StatefulWidget implements MarkdownDemoWidget { |
| const WrapAlignmentDemo({Key? key}) : super(key: key); |
| |
| static const String _title = 'Wrap Alignment Demo'; |
| |
| @override |
| String get title => WrapAlignmentDemo._title; |
| |
| @override |
| String get description => 'Shows the effect the wrap alignment and block ' |
| 'spacing parameters have on various Markdown tagged elements.'; |
| |
| @override |
| Future<String> get data => |
| rootBundle.loadString('assets/markdown_test_page.md'); |
| |
| @override |
| Future<String> get notes => Future<String>.value(_notes); |
| |
| @override |
| State<WrapAlignmentDemo> createState() => _WrapAlignmentDemoState(); |
| } |
| |
| class _WrapAlignmentDemoState extends State<WrapAlignmentDemo> { |
| double _blockSpacing = 8.0; |
| |
| WrapAlignment _wrapAlignment = WrapAlignment.start; |
| |
| final Map<String, WrapAlignment> _wrapAlignmentMenuItems = |
| Map<String, WrapAlignment>.fromIterables( |
| WrapAlignment.values.map((WrapAlignment e) => e.displayTitle), |
| WrapAlignment.values, |
| ); |
| |
| static const List<double> _spacing = <double>[4.0, 8.0, 16.0, 24.0, 32.0]; |
| final Map<String, double> _blockSpacingMenuItems = |
| Map<String, double>.fromIterables( |
| _spacing.map((double e) => e.toString()), |
| _spacing, |
| ); |
| |
| @override |
| Widget build(BuildContext context) { |
| return FutureBuilder<String>( |
| future: widget.data, |
| builder: (BuildContext context, AsyncSnapshot<String> snapshot) { |
| if (snapshot.connectionState == ConnectionState.done) { |
| return Column( |
| children: <Widget>[ |
| DropdownMenu<WrapAlignment>( |
| items: _wrapAlignmentMenuItems, |
| label: 'Wrap Alignment:', |
| initialValue: _wrapAlignment, |
| onChanged: (WrapAlignment? value) { |
| if (value != _wrapAlignment) { |
| setState(() { |
| _wrapAlignment = value!; |
| }); |
| } |
| }, |
| ), |
| DropdownMenu<double>( |
| items: _blockSpacingMenuItems, |
| label: 'Block Spacing:', |
| initialValue: _blockSpacing, |
| onChanged: (double? value) { |
| if (value != _blockSpacing) { |
| setState(() { |
| _blockSpacing = value!; |
| }); |
| } |
| }, |
| ), |
| Expanded( |
| child: Markdown( |
| key: Key(_wrapAlignment.toString()), |
| data: snapshot.data!, |
| imageDirectory: 'https://raw.githubusercontent.com', |
| styleSheet: |
| 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, |
| codeblockAlign: _wrapAlignment, |
| ), |
| paddingBuilders: <String, MarkdownPaddingBuilder>{ |
| 'p': CustomPaddingBuilder() |
| }, |
| ), |
| ), |
| ], |
| ); |
| } else { |
| return const CircularProgressIndicator(); |
| } |
| }, |
| ); |
| } |
| } |
| |
| class CustomPaddingBuilder extends MarkdownPaddingBuilder { |
| final EdgeInsets _padding = const EdgeInsets.only(left: 10.0); |
| bool paddingUse = true; |
| |
| @override |
| void visitElementBefore(md.Element element) { |
| if (element.children!.length == 1 && element.children![0] is md.Element) { |
| final md.Element child = element.children![0] as md.Element; |
| |
| paddingUse = child.tag != 'img'; |
| } else { |
| paddingUse = true; |
| } |
| } |
| |
| @override |
| EdgeInsets getPadding() { |
| if (paddingUse) { |
| return _padding; |
| } else { |
| return EdgeInsets.zero; |
| } |
| } |
| } |