diff --git a/packages/flutter_markdown/CHANGELOG.md b/packages/flutter_markdown/CHANGELOG.md index 8af3162986de..36ff215e015f 100644 --- a/packages/flutter_markdown/CHANGELOG.md +++ b/packages/flutter_markdown/CHANGELOG.md @@ -1,3 +1,9 @@ +## 0.7.0 + +* **BREAKING CHANGES**: + * Replaces parameters at `bulletBuilder` with `MarkdownBulletParameters`. + * Introduces a new parameter `nestLevel` that exposes the bullet item's nesting level. + ## 0.6.23 * Gracefully handle image dimension parsing failures. diff --git a/packages/flutter_markdown/example/lib/demos/custom_bullet_list_demo.dart b/packages/flutter_markdown/example/lib/demos/custom_bullet_list_demo.dart new file mode 100644 index 000000000000..e04a29ef1432 --- /dev/null +++ b/packages/flutter_markdown/example/lib/demos/custom_bullet_list_demo.dart @@ -0,0 +1,84 @@ +// 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. + +// TODO(goderbauer): Restructure the examples to avoid this ignore, https://github.com/flutter/flutter/issues/110208. +// ignore_for_file: avoid_implementing_value_types + +import 'package:flutter/material.dart'; +import 'package:flutter_markdown/flutter_markdown.dart'; +import '../shared/markdown_demo_widget.dart'; + +// ignore_for_file: public_member_api_docs + +const String _markdownData = ''' +# Custom Ordered List Demo + +## Unordered List + +- first +- second + - first + - first + - second + - first + - second + +## Ordered List + +1. first +2. second + 1. first + 1. first + 2. second + 1. first + 1. second +'''; + +const String _notes = ''' +# Custom Bullet List Demo +--- + +## Overview + +This is the custom bullet list demo. This demo shows how to customize the bullet list style. +This demo example is being preserved for reference purposes. +'''; + +class CustomBulletListDemo extends StatelessWidget + implements MarkdownDemoWidget { + const CustomBulletListDemo({super.key}); + + static const String _title = 'Custom Bullet List Demo'; + + @override + String get title => CustomBulletListDemo._title; + + @override + String get description => 'Shows how to customize the bullet list style.'; + + @override + Future get data => Future.value(_markdownData); + + @override + Future get notes => Future.value(_notes); + + @override + Widget build(BuildContext context) { + return Scaffold( + body: SafeArea( + child: Markdown( + data: _markdownData, + bulletBuilder: (MarkdownBulletParameters parameters) => FittedBox( + fit: BoxFit.scaleDown, + child: switch (parameters.style) { + BulletStyle.unorderedList => const Text('・'), + BulletStyle.orderedList => + Text('${parameters.nestLevel}-${parameters.index + 1}.'), + }, + ), + ), + ), + ); + } +} diff --git a/packages/flutter_markdown/example/lib/screens/home_screen.dart b/packages/flutter_markdown/example/lib/screens/home_screen.dart index 8933ee57ea4d..23ad62f60832 100644 --- a/packages/flutter_markdown/example/lib/screens/home_screen.dart +++ b/packages/flutter_markdown/example/lib/screens/home_screen.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import '../demos/basic_markdown_demo.dart'; import '../demos/centered_header_demo.dart'; +import '../demos/custom_bullet_list_demo.dart'; import '../demos/extended_emoji_demo.dart'; import '../demos/markdown_body_shrink_wrap_demo.dart'; import '../demos/minimal_markdown_demo.dart'; @@ -30,6 +31,7 @@ class HomeScreen extends StatelessWidget { OriginalMarkdownDemo(), const CenteredHeaderDemo(), const MarkdownBodyShrinkWrapDemo(), + const CustomBulletListDemo(), ]; @override diff --git a/packages/flutter_markdown/lib/src/builder.dart b/packages/flutter_markdown/lib/src/builder.dart index 7352886eb173..7bd96b90dfc9 100644 --- a/packages/flutter_markdown/lib/src/builder.dart +++ b/packages/flutter_markdown/lib/src/builder.dart @@ -611,8 +611,15 @@ class MarkdownBuilder implements md.NodeVisitor { if (bulletBuilder != null) { return Padding( padding: styleSheet.listBulletPadding!, - child: bulletBuilder!(index, - isUnordered ? BulletStyle.unorderedList : BulletStyle.orderedList), + child: bulletBuilder!( + MarkdownBulletParameters( + index: index, + style: isUnordered + ? BulletStyle.unorderedList + : BulletStyle.orderedList, + nestLevel: _listIndents.length - 1, + ), + ), ); } diff --git a/packages/flutter_markdown/lib/src/widget.dart b/packages/flutter_markdown/lib/src/widget.dart index 38ffbdcc32ef..be7f9d7047c3 100644 --- a/packages/flutter_markdown/lib/src/widget.dart +++ b/packages/flutter_markdown/lib/src/widget.dart @@ -46,7 +46,30 @@ typedef MarkdownCheckboxBuilder = Widget Function(bool value); /// Signature for custom bullet widget. /// /// Used by [MarkdownWidget.bulletBuilder] -typedef MarkdownBulletBuilder = Widget Function(int index, BulletStyle style); +typedef MarkdownBulletBuilder = Widget Function( + MarkdownBulletParameters parameters, +); + +/// An parameters of [MarkdownBulletBuilder]. +/// +/// Used by [MarkdownWidget.bulletBuilder] +class MarkdownBulletParameters { + /// Creates a new instance of [MarkdownBulletParameters]. + const MarkdownBulletParameters({ + required this.index, + required this.style, + required this.nestLevel, + }); + + /// The index of the bullet on that nesting level. + final int index; + + /// The style of the bullet. + final BulletStyle style; + + /// The nest level of the bullet. + final int nestLevel; +} /// Enumeration sent to the user when calling [MarkdownBulletBuilder] /// diff --git a/packages/flutter_markdown/pubspec.yaml b/packages/flutter_markdown/pubspec.yaml index 42106f1d537a..b5e2c9456223 100644 --- a/packages/flutter_markdown/pubspec.yaml +++ b/packages/flutter_markdown/pubspec.yaml @@ -4,7 +4,7 @@ description: A Markdown renderer for Flutter. Create rich text output, formatted with simple Markdown tags. repository: https://github.com/flutter/packages/tree/main/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.23 +version: 0.7.0 environment: sdk: ^3.3.0 diff --git a/packages/flutter_markdown/test/list_test.dart b/packages/flutter_markdown/test/list_test.dart index 05464e7b93fc..59574e42c27a 100644 --- a/packages/flutter_markdown/test/list_test.dart +++ b/packages/flutter_markdown/test/list_test.dart @@ -94,6 +94,35 @@ void defineTests() { ]); }, ); + + testWidgets('custom bullet builder', (WidgetTester tester) async { + const String data = + '* Item 1\n * Item 2\n * Item 3\n * Item 4\n* Item 5'; + Widget builder(MarkdownBulletParameters parameters) => Text( + '${parameters.index} ${parameters.style == BulletStyle.orderedList ? 'ordered' : 'unordered'} ${parameters.nestLevel}', + ); + + await tester.pumpWidget( + boilerplate( + Markdown(data: data, bulletBuilder: builder), + ), + ); + + final Iterable widgets = tester.allWidgets; + + expectTextStrings(widgets, [ + '0 unordered 0', + 'Item 1', + '0 unordered 1', + 'Item 2', + '0 unordered 2', + 'Item 3', + '1 unordered 1', + 'Item 4', + '1 unordered 0', + 'Item 5', + ]); + }); }); group('Ordered List', () { @@ -135,6 +164,35 @@ void defineTests() { final Iterable widgets = tester.allWidgets; expectTextStrings(widgets, ['1.', 'one', 'two']); }); + + testWidgets('custom bullet builder', (WidgetTester tester) async { + const String data = + '1. Item 1\n 1. Item 2\n 1. Item 3\n 1. Item 4\n1. Item 5'; + Widget builder(MarkdownBulletParameters parameters) => Text( + '${parameters.index} ${parameters.style == BulletStyle.orderedList ? 'ordered' : 'unordered'} ${parameters.nestLevel}', + ); + + await tester.pumpWidget( + boilerplate( + Markdown(data: data, bulletBuilder: builder), + ), + ); + + final Iterable widgets = tester.allWidgets; + + expectTextStrings(widgets, [ + '0 ordered 0', + 'Item 1', + '0 ordered 1', + 'Item 2', + '0 ordered 2', + 'Item 3', + '1 ordered 1', + 'Item 4', + '1 ordered 0', + 'Item 5', + ]); + }); }); group('Task List', () { @@ -161,8 +219,8 @@ void defineTests() { testWidgets('custom bullet builder', (WidgetTester tester) async { const String data = '* Item 1\n* Item 2\n1) Item 3\n2) Item 4'; - Widget builder(int index, BulletStyle style) => Text( - '$index ${style == BulletStyle.orderedList ? 'ordered' : 'unordered'}'); + Widget builder(MarkdownBulletParameters parameters) => Text( + '${parameters.index} ${parameters.style == BulletStyle.orderedList ? 'ordered' : 'unordered'}'); await tester.pumpWidget( boilerplate(