[flutter_markdown] Replace deprecated API (#6134)

* Internally, removes use of the deprecated framework methods related to `textScaleFactor`, in favor of the newer `textScaler`.
* Plumbs that same change through the public API of this package, deprecating the style sheet's `textScaleFactor` and adding a `textScaler`.
* Updates the min Flutter SDK to 3.16 where the new APIs were added.
* Also updates test code that uses the deprecated `renderViewElement` to use `rootElement` instead.

Fixes https://github.com/flutter/flutter/issues/143400
Fixes https://github.com/flutter/flutter/issues/143448
This commit is contained in:
stuartmorgan
2024-02-20 07:51:08 -08:00
committed by GitHub
parent 84ff11d7ee
commit 947e34ce9f
11 changed files with 134 additions and 31 deletions

View File

@ -1,6 +1,10 @@
## NEXT ## 0.6.20
* Updates minimum supported SDK version to Flutter 3.13/Dart 3.1. * Adds `textScaler` to `MarkdownStyleSheet`, and deprecates `textScaleFactor`.
* Clients using `textScaleFactor: someFactor` should replace it with
`TextScaler.linear(someFactor)` to preserve behavior.
* Removes use of deprecated Flutter framework `textScaleFactor` methods.
* Updates minimum supported SDK version to Flutter 3.16.
## 0.6.19 ## 0.6.19
@ -44,7 +48,7 @@
* Introduces a new `MarkdownElementBuilder.visitElementAfterWithContext()` method passing the widget `BuildContext` and * Introduces a new `MarkdownElementBuilder.visitElementAfterWithContext()` method passing the widget `BuildContext` and
the parent text's `TextStyle`. the parent text's `TextStyle`.
## 0.6.16 ## 0.6.16
* Adds `tableVerticalAlignment` property to allow aligning table cells vertically. * Adds `tableVerticalAlignment` property to allow aligning table cells vertically.

View File

@ -3,8 +3,8 @@ description: Demonstrates how to use the flutter_markdown package.
publish_to: none publish_to: none
environment: environment:
sdk: ^3.1.0 sdk: ^3.2.0
flutter: ">=3.13.0" flutter: ">=3.16.0"
dependencies: dependencies:
flutter: flutter:

View File

@ -64,7 +64,7 @@ final MarkdownStyleSheet Function(BuildContext, MarkdownStyleSheetBaseTheme?)
} }
return result.copyWith( return result.copyWith(
textScaleFactor: MediaQuery.textScaleFactorOf(context), textScaler: MediaQuery.textScalerOf(context),
); );
}; };

View File

@ -66,7 +66,7 @@ final MarkdownStyleSheet Function(BuildContext, MarkdownStyleSheetBaseTheme?)
} }
return result.copyWith( return result.copyWith(
textScaleFactor: MediaQuery.textScaleFactorOf(context), textScaler: MediaQuery.textScalerOf(context),
); );
}; };

View File

@ -867,7 +867,7 @@ class MarkdownBuilder implements md.NodeVisitor {
if (selectable) { if (selectable) {
return SelectableText.rich( return SelectableText.rich(
text!, text!,
textScaleFactor: styleSheet.textScaleFactor, textScaler: styleSheet.textScaler,
textAlign: textAlign ?? TextAlign.start, textAlign: textAlign ?? TextAlign.start,
onTap: onTapText, onTap: onTapText,
key: k, key: k,
@ -875,7 +875,7 @@ class MarkdownBuilder implements md.NodeVisitor {
} else { } else {
return Text.rich( return Text.rich(
text!, text!,
textScaleFactor: styleSheet.textScaleFactor, textScaler: styleSheet.textScaler,
textAlign: textAlign ?? TextAlign.start, textAlign: textAlign ?? TextAlign.start,
key: k, key: k,
); );

View File

@ -59,8 +59,19 @@ class MarkdownStyleSheet {
this.orderedListAlign = WrapAlignment.start, this.orderedListAlign = WrapAlignment.start,
this.blockquoteAlign = WrapAlignment.start, this.blockquoteAlign = WrapAlignment.start,
this.codeblockAlign = WrapAlignment.start, this.codeblockAlign = WrapAlignment.start,
this.textScaleFactor, @Deprecated('Use textScaler instead.') this.textScaleFactor,
}) : _styles = <String, TextStyle?>{ TextScaler? textScaler,
}) : assert(
textScaler == null || textScaleFactor == null,
'textScaleFactor is deprecated and cannot be specified when textScaler is specified.',
),
textScaler = textScaler ??
// Internally, only textScaler is used, so convert the scale factor
// to a linear scaler.
(textScaleFactor == null
? null
: TextScaler.linear(textScaleFactor)),
_styles = <String, TextStyle?>{
'a': a, 'a': a,
'p': p, 'p': p,
'li': p, 'li': p,
@ -380,8 +391,19 @@ class MarkdownStyleSheet {
WrapAlignment? orderedListAlign, WrapAlignment? orderedListAlign,
WrapAlignment? blockquoteAlign, WrapAlignment? blockquoteAlign,
WrapAlignment? codeblockAlign, WrapAlignment? codeblockAlign,
double? textScaleFactor, @Deprecated('Use textScaler instead.') double? textScaleFactor,
TextScaler? textScaler,
}) { }) {
assert(
textScaler == null || textScaleFactor == null,
'textScaleFactor is deprecated and cannot be specified when textScaler is specified.',
);
// If either of textScaler or textScaleFactor is non-null, pass null for the
// other instead of the previous value, since only one is allowed.
final TextScaler? newTextScaler =
textScaler ?? (textScaleFactor == null ? this.textScaler : null);
final double? nextTextScaleFactor =
textScaleFactor ?? (textScaler == null ? this.textScaleFactor : null);
return MarkdownStyleSheet( return MarkdownStyleSheet(
a: a ?? this.a, a: a ?? this.a,
p: p ?? this.p, p: p ?? this.p,
@ -435,7 +457,8 @@ class MarkdownStyleSheet {
orderedListAlign: orderedListAlign ?? this.orderedListAlign, orderedListAlign: orderedListAlign ?? this.orderedListAlign,
blockquoteAlign: blockquoteAlign ?? this.blockquoteAlign, blockquoteAlign: blockquoteAlign ?? this.blockquoteAlign,
codeblockAlign: codeblockAlign ?? this.codeblockAlign, codeblockAlign: codeblockAlign ?? this.codeblockAlign,
textScaleFactor: textScaleFactor ?? this.textScaleFactor, textScaler: newTextScaler,
textScaleFactor: nextTextScaleFactor,
); );
} }
@ -497,6 +520,11 @@ class MarkdownStyleSheet {
blockquoteAlign: other.blockquoteAlign, blockquoteAlign: other.blockquoteAlign,
codeblockAlign: other.codeblockAlign, codeblockAlign: other.codeblockAlign,
textScaleFactor: other.textScaleFactor, textScaleFactor: other.textScaleFactor,
// Only one of textScaler and textScaleFactor can be passed. If
// other.textScaleFactor is non-null, then the sheet was created with a
// textScaleFactor and the textScaler was derived from that, so should be
// ignored so that the textScaleFactor continues to be set.
textScaler: other.textScaleFactor == null ? other.textScaler : null,
); );
} }
@ -650,7 +678,14 @@ class MarkdownStyleSheet {
/// The [WrapAlignment] to use for a code block. Defaults to start. /// The [WrapAlignment] to use for a code block. Defaults to start.
final WrapAlignment codeblockAlign; final WrapAlignment codeblockAlign;
/// The text scale factor to use in textual elements /// The text scaler to use in textual elements.
final TextScaler? textScaler;
/// The text scale factor to use in textual elements.
///
/// This will be non-null only if the sheet was created with the deprecated
/// [textScaleFactor] instead of [textScaler].
@Deprecated('Use textScaler instead.')
final double? textScaleFactor; final double? textScaleFactor;
/// A [Map] from element name to the corresponding [TextStyle] object. /// A [Map] from element name to the corresponding [TextStyle] object.
@ -717,7 +752,7 @@ class MarkdownStyleSheet {
other.orderedListAlign == orderedListAlign && other.orderedListAlign == orderedListAlign &&
other.blockquoteAlign == blockquoteAlign && other.blockquoteAlign == blockquoteAlign &&
other.codeblockAlign == codeblockAlign && other.codeblockAlign == codeblockAlign &&
other.textScaleFactor == textScaleFactor; other.textScaler == textScaler;
} }
@override @override
@ -774,6 +809,7 @@ class MarkdownStyleSheet {
orderedListAlign, orderedListAlign,
blockquoteAlign, blockquoteAlign,
codeblockAlign, codeblockAlign,
textScaler,
textScaleFactor, textScaleFactor,
]); ]);
} }

View File

@ -4,11 +4,11 @@ description: A Markdown renderer for Flutter. Create rich text output,
formatted with simple Markdown tags. formatted with simple Markdown tags.
repository: https://github.com/flutter/packages/tree/main/packages/flutter_markdown 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 issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+flutter_markdown%22
version: 0.6.19 version: 0.6.20
environment: environment:
sdk: ^3.1.0 sdk: ^3.2.0
flutter: ">=3.13.0" flutter: ">=3.16.0"
dependencies: dependencies:
flutter: flutter:

View File

@ -18,7 +18,7 @@ import 'selection_area_compatibility_test.dart' as selection_area_test;
import 'style_sheet_test.dart' as style_sheet_test; import 'style_sheet_test.dart' as style_sheet_test;
import 'table_test.dart' as table_test; import 'table_test.dart' as table_test;
import 'text_alignment_test.dart' as text_alignment_test; import 'text_alignment_test.dart' as text_alignment_test;
import 'text_scale_factor_test.dart' as text_scale_factor; import 'text_scaler_test.dart' as text_scaler;
import 'text_test.dart' as text_test; import 'text_test.dart' as text_test;
import 'uri_test.dart' as uri_test; import 'uri_test.dart' as uri_test;
@ -40,6 +40,6 @@ void main() {
table_test.defineTests(); table_test.defineTests();
text_test.defineTests(); text_test.defineTests();
text_alignment_test.defineTests(); text_alignment_test.defineTests();
text_scale_factor.defineTests(); text_scaler.defineTests();
uri_test.defineTests(); uri_test.defineTests();
} }

View File

@ -398,5 +398,65 @@ void defineTests() {
); );
}, },
); );
testWidgets(
'deprecated textScaleFactor is converted to linear scaler',
(WidgetTester tester) async {
const double scaleFactor = 2.0;
final MarkdownStyleSheet style = MarkdownStyleSheet(
textScaleFactor: scaleFactor,
);
expect(style.textScaler, const TextScaler.linear(scaleFactor));
expect(style.textScaleFactor, scaleFactor);
},
);
testWidgets(
'deprecated textScaleFactor is null when a scaler is provided',
(WidgetTester tester) async {
const TextScaler scaler = TextScaler.linear(2.0);
final MarkdownStyleSheet style = MarkdownStyleSheet(
textScaler: scaler,
);
expect(style.textScaler, scaler);
expect(style.textScaleFactor, null);
},
);
testWidgets(
'copyWith textScaler overwrites both textScaler and textScaleFactor',
(WidgetTester tester) async {
final MarkdownStyleSheet original = MarkdownStyleSheet(
textScaleFactor: 2.0,
);
const TextScaler newScaler = TextScaler.linear(3.0);
final MarkdownStyleSheet copy = original.copyWith(
textScaler: newScaler,
);
expect(copy.textScaler, newScaler);
expect(copy.textScaleFactor, null);
},
);
testWidgets(
'copyWith textScaleFactor overwrites both textScaler and textScaleFactor',
(WidgetTester tester) async {
final MarkdownStyleSheet original = MarkdownStyleSheet(
textScaleFactor: 2.0,
);
const double newScaleFactor = 3.0;
final MarkdownStyleSheet copy = original.copyWith(
textScaleFactor: newScaleFactor,
);
expect(copy.textScaler, const TextScaler.linear(newScaleFactor));
expect(copy.textScaleFactor, newScaleFactor);
},
);
}); });
} }

View File

@ -10,33 +10,35 @@ import 'utils.dart';
void main() => defineTests(); void main() => defineTests();
void defineTests() { void defineTests() {
group('Text Scale Factor', () { group('Text Scaler', () {
testWidgets( testWidgets(
'should use style textScaleFactor in RichText', 'should use style textScaler in RichText',
(WidgetTester tester) async { (WidgetTester tester) async {
const TextScaler scaler = TextScaler.linear(2.0);
const String data = 'Hello'; const String data = 'Hello';
await tester.pumpWidget( await tester.pumpWidget(
boilerplate( boilerplate(
MarkdownBody( MarkdownBody(
styleSheet: MarkdownStyleSheet(textScaleFactor: 2.0), styleSheet: MarkdownStyleSheet(textScaler: scaler),
data: data, data: data,
), ),
), ),
); );
final RichText richText = tester.widget(find.byType(RichText)); final RichText richText = tester.widget(find.byType(RichText));
expect(richText.textScaleFactor, 2.0); expect(richText.textScaler, scaler);
}, },
); );
testWidgets( testWidgets(
'should use MediaQuery textScaleFactor in RichText', 'should use MediaQuery textScaler in RichText',
(WidgetTester tester) async { (WidgetTester tester) async {
const TextScaler scaler = TextScaler.linear(2.0);
const String data = 'Hello'; const String data = 'Hello';
await tester.pumpWidget( await tester.pumpWidget(
boilerplate( boilerplate(
const MediaQuery( const MediaQuery(
data: MediaQueryData(textScaleFactor: 2.0), data: MediaQueryData(textScaler: scaler),
child: MarkdownBody( child: MarkdownBody(
data: data, data: data,
), ),
@ -45,18 +47,19 @@ void defineTests() {
); );
final RichText richText = tester.widget(find.byType(RichText)); final RichText richText = tester.widget(find.byType(RichText));
expect(richText.textScaleFactor, 2.0); expect(richText.textScaler, scaler);
}, },
); );
testWidgets( testWidgets(
'should use MediaQuery textScaleFactor in SelectableText.rich', 'should use MediaQuery textScaler in SelectableText.rich',
(WidgetTester tester) async { (WidgetTester tester) async {
const TextScaler scaler = TextScaler.linear(2.0);
const String data = 'Hello'; const String data = 'Hello';
await tester.pumpWidget( await tester.pumpWidget(
boilerplate( boilerplate(
const MediaQuery( const MediaQuery(
data: MediaQueryData(textScaleFactor: 2.0), data: MediaQueryData(textScaler: scaler),
child: MarkdownBody( child: MarkdownBody(
data: data, data: data,
selectable: true, selectable: true,
@ -67,7 +70,7 @@ void defineTests() {
final SelectableText selectableText = final SelectableText selectableText =
tester.widget(find.byType(SelectableText)); tester.widget(find.byType(SelectableText));
expect(selectableText.textScaleFactor, 2.0); expect(selectableText.textScaler, scaler);
}, },
); );
}); });

View File

@ -169,7 +169,7 @@ void expectLinkTap(MarkdownLink? actual, MarkdownLink expected) {
} }
String dumpRenderView() { String dumpRenderView() {
return WidgetsBinding.instance.renderViewElement!.toStringDeep().replaceAll( return WidgetsBinding.instance.rootElement!.toStringDeep().replaceAll(
RegExp(r'SliverChildListDelegate#\d+', multiLine: true), RegExp(r'SliverChildListDelegate#\d+', multiLine: true),
'SliverChildListDelegate', 'SliverChildListDelegate',
); );