Skip to content

Commit a3aa8da

Browse files
committed
Merge remote-tracking branch 'upstream/master' into fix-widget-rebuilds-profile-mode
# Conflicts: # packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md
2 parents b1455f8 + 644500c commit a3aa8da

4 files changed

Lines changed: 118 additions & 13 deletions

File tree

packages/devtools_app/lib/src/screens/inspector/inspector_screen_controller.dart

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,6 @@ class InspectorScreenController extends DevToolsScreenController
5252
ValueListenable<LinkedHashMap<String, DevToolsError>> get inspectorErrors =>
5353
_activeInspectorErrors;
5454

55-
/// The count of unread inspector errors (used for the badge).
56-
ValueListenable<int> get inspectorErrorCount => serviceConnection
57-
.errorBadgeManager
58-
.errorCountNotifier(InspectorScreen.id);
59-
6055
@override
6156
void init() {
6257
super.init();

packages/devtools_app/lib/src/shared/ui/side_panel.dart

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,17 @@ class SidePanel extends AnimatedWidget {
182182
: Expanded(
183183
child: Markdown(
184184
data: markdownData!,
185+
styleSheet: MarkdownStyleSheet(
186+
// [MarkdownStyleSheet.fromTheme], which supplies the
187+
// rest of the style sheet, hard codes
188+
// `Colors.blue.shade100` as the blockquote fill while
189+
// taking the text color from the theme. In the dark
190+
// theme that draws light gray text on light blue.
191+
blockquoteDecoration: BoxDecoration(
192+
color: theme.colorScheme.secondaryContainer,
193+
borderRadius: defaultBorderRadius,
194+
),
195+
),
185196
onTapLink: (text, url, title) =>
186197
unawaited(launchUrlWithErrorHandling(url!)),
187198
),

packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@ includes the following changes among other general improvements.
1111
To learn more about DevTools, check out the
1212
[DevTools overview](/tools/devtools).
1313
## General updates
14-
TODO: Remove this section if there are not any updates.
14+
15+
* Fixed unreadable text in the release notes panel, where blockquotes were
16+
drawn on a hard coded light blue background in the dark theme.
17+
[#9957](https://github.com/flutter/devtools/pull/9957)
1518
## Inspector updates
1619
TODO: Remove this section if there are not any updates.
1720
## Performance updates
@@ -31,14 +34,10 @@ TODO: Remove this section if there are not any updates.
3134
* Fix a bug in the TextMate grammar parser that could result in code after
3235
comments being classified as comments.
3336
[#9921](https://github.com/flutter/devtools/pull/9921).
34-
<<<<<<< HEAD
35-
=======
3637
* Fixed an overflow in the debugging controls when the Debugger screen is
3738
narrow, such as when DevTools is embedded in an IDE side panel. The controls
3839
now scroll horizontally instead of overflowing.
3940
[#9949](https://github.com/flutter/devtools/pull/9949)
40-
41-
>>>>>>> upstream/master
4241
## Network profiler updates
4342
* Fixed exported response status in HAR files so that they parse as integers
4443
instead of strings. [#9900](https://github.com/flutter/devtools/pull/9900)
@@ -50,10 +49,8 @@ TODO: Remove this section if there are not any updates.
5049
## Deep links tool updates
5150

5251
* Added a "Watch tutorial" link to the status line that points to the
53-
[deep links video tutorial](https://youtu.be/d7sZL6h1Elw).
52+
[deep links video tutorial](https://youtu.be/d7sZL6hIElw).
5453
[#9925](https://github.com/flutter/devtools/pull/9925)
55-
56-
>>>>>>> upstream/master
5754
## VS Code sidebar updates
5855
TODO: Remove this section if there are not any updates.
5956
## DevTools extension updates
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
// Copyright 2026 The Flutter Authors
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file or at https://developers.google.com/open-source/licenses/bsd.
4+
5+
import 'package:devtools_app/devtools_app.dart';
6+
import 'package:devtools_app_shared/ui.dart';
7+
import 'package:devtools_app_shared/utils.dart';
8+
import 'package:flutter/material.dart';
9+
import 'package:flutter_test/flutter_test.dart';
10+
11+
/// The smallest contrast ratio WCAG 2.1 accepts for body text at level AA.
12+
///
13+
/// See https://www.w3.org/TR/WCAG21/#contrast-minimum.
14+
const _minimumContrastRatio = 4.5;
15+
16+
void main() {
17+
setUp(() {
18+
setGlobal(IdeTheme, IdeTheme());
19+
});
20+
21+
group('$SidePanelViewer', () {
22+
// `MarkdownStyleSheet.fromTheme` fills blockquotes with
23+
// `Colors.blue.shade100` but takes the text color from the theme, so a
24+
// release note that opens with a blockquote drew `onSurface` text on light
25+
// blue in the dark theme.
26+
// Regression test for https://github.com/flutter/devtools/issues/9945.
27+
for (final useDarkTheme in [true, false]) {
28+
final themeName = useDarkTheme ? 'dark' : 'light';
29+
testWidgets('blockquote text is legible in the $themeName theme', (
30+
tester,
31+
) async {
32+
const summary = 'Release notes for Dart and Flutter DevTools.';
33+
final controller = SidePanelController();
34+
await tester.pumpWidget(
35+
MaterialApp(
36+
theme: themeFor(
37+
isDarkTheme: useDarkTheme,
38+
ideTheme: IdeTheme(),
39+
theme: ThemeData(
40+
useMaterial3: true,
41+
colorScheme: useDarkTheme ? darkColorScheme : lightColorScheme,
42+
),
43+
),
44+
home: SidePanelViewer(controller: controller),
45+
),
46+
);
47+
controller.markdown.value = '# Release notes\n\n> $summary';
48+
controller.toggleVisibility(true);
49+
await tester.pumpAndSettle();
50+
51+
final summaryFinder = find.byWidgetPredicate(
52+
(widget) =>
53+
widget is RichText && widget.text.toPlainText() == summary,
54+
);
55+
expect(summaryFinder, findsOneWidget);
56+
57+
final textColor = _colorOfSpan(
58+
tester.widget<RichText>(summaryFinder).text,
59+
summary,
60+
);
61+
final fillColor = tester
62+
.widgetList<DecoratedBox>(
63+
find.ancestor(
64+
of: summaryFinder,
65+
matching: find.byType(DecoratedBox),
66+
),
67+
)
68+
.map((box) => box.decoration)
69+
.whereType<BoxDecoration>()
70+
.map((decoration) => decoration.color)
71+
.nonNulls
72+
.first;
73+
74+
expect(
75+
_contrastRatio(textColor!, fillColor),
76+
greaterThanOrEqualTo(_minimumContrastRatio),
77+
);
78+
});
79+
}
80+
});
81+
}
82+
83+
/// The color the span holding [text] is painted with, or null if [root] holds
84+
/// no such span.
85+
Color? _colorOfSpan(InlineSpan root, String text) {
86+
Color? color;
87+
root.visitChildren((span) {
88+
if (span is TextSpan && span.text == text) {
89+
color = span.style?.color;
90+
return false;
91+
}
92+
return true;
93+
});
94+
return color;
95+
}
96+
97+
/// The WCAG contrast ratio between [a] and [b], from 1 (identical) to 21
98+
/// (black on white).
99+
double _contrastRatio(Color a, Color b) {
100+
final luminances = [a.computeLuminance(), b.computeLuminance()]..sort();
101+
return (luminances.last + 0.05) / (luminances.first + 0.05);
102+
}

0 commit comments

Comments
 (0)