From cf9f079273d104ab94d9077369e2050619c1de73 Mon Sep 17 00:00:00 2001 From: Prateek Jain Date: Sun, 11 Oct 2026 10:59:51 +0530 Subject: [PATCH 1/5] Fix treemap tooltip text color across light and dark themes --- packages/devtools_app/lib/src/shared/charts/treemap.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/devtools_app/lib/src/shared/charts/treemap.dart b/packages/devtools_app/lib/src/shared/charts/treemap.dart index dae9c34600e..1ce51b08191 100644 --- a/packages/devtools_app/lib/src/shared/charts/treemap.dart +++ b/packages/devtools_app/lib/src/shared/charts/treemap.dart @@ -401,6 +401,7 @@ class _TreemapState extends State { richMessage: hoveredNode?.displayTextSpan( defaultTextStyle: defaultTextStyle, + color: Theme.of(context).colorScheme.tooltipTextColor ) ?? const TextSpan(text: ''), waitDuration: tooltipWaitLong, From 765702687b7987496a56a90b3ce2d0eb5cbbef61 Mon Sep 17 00:00:00 2001 From: Prateek Jain Date: Sun, 11 Oct 2026 15:38:27 +0530 Subject: [PATCH 2/5] Formatting change --- packages/devtools_app/lib/src/shared/charts/treemap.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/devtools_app/lib/src/shared/charts/treemap.dart b/packages/devtools_app/lib/src/shared/charts/treemap.dart index 1ce51b08191..7580a0e4036 100644 --- a/packages/devtools_app/lib/src/shared/charts/treemap.dart +++ b/packages/devtools_app/lib/src/shared/charts/treemap.dart @@ -401,7 +401,7 @@ class _TreemapState extends State { richMessage: hoveredNode?.displayTextSpan( defaultTextStyle: defaultTextStyle, - color: Theme.of(context).colorScheme.tooltipTextColor + color: Theme.of(context).colorScheme.tooltipTextColor, ) ?? const TextSpan(text: ''), waitDuration: tooltipWaitLong, From 4e172399307091c4d52173785166cce35b68a990 Mon Sep 17 00:00:00 2001 From: Prateek Jain Date: Sun, 11 Oct 2026 15:39:01 +0530 Subject: [PATCH 3/5] Add tests for treemap tooltip text color across themes and update wrapper helpers to support dark theme --- .../test/shared/charts/treemap_test.dart | 54 ++++++++++++++++++- .../lib/src/helpers/wrappers.dart | 27 +++++++--- 2 files changed, 72 insertions(+), 9 deletions(-) diff --git a/packages/devtools_app/test/shared/charts/treemap_test.dart b/packages/devtools_app/test/shared/charts/treemap_test.dart index f5d24be6baa..2324a985448 100644 --- a/packages/devtools_app/test/shared/charts/treemap_test.dart +++ b/packages/devtools_app/test/shared/charts/treemap_test.dart @@ -3,6 +3,7 @@ // found in the LICENSE file or at https://developers.google.com/open-source/licenses/bsd. import 'dart:convert'; +import 'dart:ui'; import 'package:devtools_app/src/service/service_manager.dart'; import 'package:devtools_app/src/shared/charts/treemap.dart'; @@ -29,7 +30,11 @@ void main() { } // Pump treemap widget with tree built with test data. - Future pumpTreemapWidget(WidgetTester tester, Key treemapKey) async { + Future pumpTreemapWidget( + WidgetTester tester, + Key treemapKey, { + bool isDarkTheme = false, + }) async { await tester.pumpWidget( wrap( LayoutBuilder( @@ -45,6 +50,7 @@ void main() { ); }, ), + isDarkTheme: isDarkTheme, ), ); await tester.pumpAndSettle(); @@ -221,6 +227,52 @@ void main() { await tester.pumpAndSettle(const Duration(seconds: 2)); }, skip: kIsWeb); }); + + group('Treemap tooltip text color', () { + setUp(() { + root = TreemapNode(name: 'root') + ..addChild( + TreemapNode(name: 'parent', byteSize: 1000) + ..addChild(TreemapNode(name: 'leaf_1', byteSize: 500)) + ..addChild(TreemapNode(name: 'leaf_2', byteSize: 500)), + ); + }); + for (final isDarkTheme in [false, true]) { + final themeName = isDarkTheme ? 'dark' : 'light'; + testWidgetsWithWindowSize( + 'tooltip has correct text color in $themeName theme', + windowSize, + (WidgetTester tester) async { + const treemapKey = Key('Treemap'); + await pumpTreemapWidget(tester, treemapKey, isDarkTheme: isDarkTheme); + + final tooltipFinder = find.byWidgetPredicate( + (widget) => widget is DevToolsTooltip && widget.richMessage != null, + ); + final customPaint = find.descendant( + of: tooltipFinder, + matching: find.byType(CustomPaint), + ); + + // Hover over the painted cell. + final gesture = await tester.createGesture( + kind: PointerDeviceKind.mouse, + ); + await gesture.addPointer(location: Offset.zero); + addTearDown(gesture.removePointer); + await gesture.moveTo(tester.getCenter(customPaint)); + await tester.pumpAndSettle(); + + final tooltip = tester.widget(tooltipFinder); + final textSpan = tooltip.richMessage as TextSpan?; + final expectedColor = isDarkTheme ? Colors.black : Colors.white; + expect(textSpan, isNotNull); + expect(textSpan!.text, isNotEmpty); + expect(textSpan.style?.color, equals(expectedColor)); + }, + ); + } + }); } Future _loadSnapshotJsonAsTree(String snapshotJson) async { diff --git a/packages/devtools_test/lib/src/helpers/wrappers.dart b/packages/devtools_test/lib/src/helpers/wrappers.dart index 0a70c24940c..6b3da215ec7 100644 --- a/packages/devtools_test/lib/src/helpers/wrappers.dart +++ b/packages/devtools_test/lib/src/helpers/wrappers.dart @@ -27,13 +27,20 @@ final _testNavigatorKey = GlobalKey(); /// This includes a [MaterialApp] to provide context like [Theme.of], a /// [Material] to support elements like [TextField] that draw ink effects, and a /// [Directionality] to support [RenderFlex] widgets like [Row] and [Column]. -Widget wrap(Widget widget, {DevToolsQueryParams? queryParams}) { +Widget wrap( + Widget widget, { + DevToolsQueryParams? queryParams, + bool isDarkTheme = false, +}) { setGlobal(GlobalKey, _testNavigatorKey); return MaterialApp.router( theme: themeFor( - isDarkTheme: false, + isDarkTheme: isDarkTheme, ideTheme: IdeTheme(), - theme: ThemeData(useMaterial3: true, colorScheme: lightColorScheme), + theme: ThemeData( + useMaterial3: true, + colorScheme: isDarkTheme ? darkColorScheme : lightColorScheme, + ), ), routerDelegate: DevToolsRouterDelegate.test( (context, page, args, state) => MaterialPage( @@ -62,12 +69,15 @@ Widget wrap(Widget widget, {DevToolsQueryParams? queryParams}) { /// This includes a [MaterialApp] to provide context like [Theme.of], a /// [Material] to support elements like [TextField] that draw ink effects, and a /// [Directionality] to support [RenderFlex] widgets like [Row] and [Column]. -Widget wrapSimple(Widget widget) { +Widget wrapSimple(Widget widget, {bool isDarkTheme = false}) { return MaterialApp( theme: themeFor( - isDarkTheme: false, + isDarkTheme: isDarkTheme, ideTheme: IdeTheme(), - theme: ThemeData(useMaterial3: true, colorScheme: lightColorScheme), + theme: ThemeData( + useMaterial3: true, + colorScheme: isDarkTheme ? darkColorScheme : lightColorScheme, + ), ), home: Material( child: Directionality( @@ -99,6 +109,7 @@ Widget wrapWithControllers( AccessibilityController? accessibility, bool includeRouter = true, DevToolsQueryParams? queryParams, + bool isDarkTheme = false, }) { // The [ScreenControllers] class uses the [OfflineDataController] class to // determine which type of controller should be returned from @@ -192,8 +203,8 @@ Widget wrapWithControllers( child = MultiProvider(providers: providers, child: child); } return includeRouter - ? wrap(child, queryParams: queryParams) - : wrapSimple(child); + ? wrap(child, queryParams: queryParams, isDarkTheme: isDarkTheme) + : wrapSimple(child, isDarkTheme: isDarkTheme); } Widget wrapWithNotifications(Widget child) { From e1b0193bec43d1a6cfa84560a0ce6718acd38cc5 Mon Sep 17 00:00:00 2001 From: Prateek Jain Date: Sun, 11 Oct 2026 16:10:49 +0530 Subject: [PATCH 4/5] Update NEXT_RELEASE_NOTES.md file --- packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md b/packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md index b3097459877..669450b922b 100644 --- a/packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md +++ b/packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md @@ -90,7 +90,8 @@ To learn more about DevTools, check out the ## App size tool updates -TODO: Remove this section if there are not any updates. +* Fixed treemap tooltip text color across light and dark theme + [#10035](https://github.com/flutter/devtools/pull/10035) ## Deep links tool updates From a9974320ab89c9dfdf2b8d5f7f68edf8c278a80a Mon Sep 17 00:00:00 2001 From: Prateek Jain Date: Sun, 11 Oct 2026 17:52:57 +0530 Subject: [PATCH 5/5] Extract duplicate theme configuration block in the test wrappers into a helper function to adhere to the DRY principle --- .../lib/src/helpers/wrappers.dart | 30 +++++++++---------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/packages/devtools_test/lib/src/helpers/wrappers.dart b/packages/devtools_test/lib/src/helpers/wrappers.dart index 6b3da215ec7..fc7f002abee 100644 --- a/packages/devtools_test/lib/src/helpers/wrappers.dart +++ b/packages/devtools_test/lib/src/helpers/wrappers.dart @@ -21,6 +21,18 @@ import 'package:provider/provider.dart'; /// for widget state to be preserved. final _testNavigatorKey = GlobalKey(); +/// Returns the [ThemeData] used by [wrap] and [wrapSimple] test helper widgets. +ThemeData _testTheme({required bool isDarkTheme}) { + return themeFor( + isDarkTheme: isDarkTheme, + ideTheme: IdeTheme(), + theme: ThemeData( + useMaterial3: true, + colorScheme: isDarkTheme ? darkColorScheme : lightColorScheme, + ), + ); +} + /// Wraps [widget] with the build context it needs to load in a test as well as /// the [DevToolsRouterDelegate]. /// @@ -34,14 +46,7 @@ Widget wrap( }) { setGlobal(GlobalKey, _testNavigatorKey); return MaterialApp.router( - theme: themeFor( - isDarkTheme: isDarkTheme, - ideTheme: IdeTheme(), - theme: ThemeData( - useMaterial3: true, - colorScheme: isDarkTheme ? darkColorScheme : lightColorScheme, - ), - ), + theme: _testTheme(isDarkTheme: isDarkTheme), routerDelegate: DevToolsRouterDelegate.test( (context, page, args, state) => MaterialPage( child: Material( @@ -71,14 +76,7 @@ Widget wrap( /// [Directionality] to support [RenderFlex] widgets like [Row] and [Column]. Widget wrapSimple(Widget widget, {bool isDarkTheme = false}) { return MaterialApp( - theme: themeFor( - isDarkTheme: isDarkTheme, - ideTheme: IdeTheme(), - theme: ThemeData( - useMaterial3: true, - colorScheme: isDarkTheme ? darkColorScheme : lightColorScheme, - ), - ), + theme: _testTheme(isDarkTheme: isDarkTheme), home: Material( child: Directionality( textDirection: TextDirection.ltr,