Show debug-mode message for widget rebuilds in profile mode (#9755) When running in profile mode, the Performance panel showed a disabled 'Count widget builds' checkbox which was misleading. Widget rebuild counts rely on debugOnRebuildDirtyWidget which is only available in debug mode. This change: - Removes the checkbox when running in profile mode - Shows a clear message: 'Rebuild information is not available for this frame. Widget rebuild counts are only available when running an app in debug-mode.' - Adds widget tests for both profile mode and debug mode behavior Fixes #9730 --------- Co-authored-by: Sam Rawlins <srawlins@google.com>
diff --git a/packages/devtools_app/lib/src/screens/performance/panes/rebuild_stats/rebuild_stats.dart b/packages/devtools_app/lib/src/screens/performance/panes/rebuild_stats/rebuild_stats.dart index a19d250..6b7ec33 100644 --- a/packages/devtools_app/lib/src/screens/performance/panes/rebuild_stats/rebuild_stats.dart +++ b/packages/devtools_app/lib/src/screens/performance/panes/rebuild_stats/rebuild_stats.dart
@@ -20,6 +20,12 @@ import '../flutter_frames/flutter_frame_model.dart'; import 'rebuild_stats_model.dart'; +@visibleForTesting +const debugModeOnlyMessage = + 'Rebuild information is not available for this frame.\n' + 'Widget rebuild counts are only available when running ' + 'an app in debug mode.'; + class RebuildStatsView extends StatefulWidget { const RebuildStatsView({ super.key, @@ -92,6 +98,12 @@ @override Widget build(BuildContext context) { + final isProfileBuild = + serviceConnection.serviceManager.connectedApp?.isProfileBuildNow ?? + false; + if (isProfileBuild) { + return const CenteredMessage(message: debugModeOnlyMessage); + } return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [
diff --git a/packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md b/packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md index 1e4cda3..10b1377 100644 --- a/packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md +++ b/packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md
@@ -31,6 +31,9 @@ * Fixed a bug where the Flutter frames chart could appear frozen after switching away from the Performance screen and coming back. [#9960](https://github.com/flutter/devtools/pull/9960) +* Added a message in the Performance panel when widget rebuild tracking is + unavailable because the app is running in profile mode. + [#9755](https://github.com/flutter/devtools/pull/9755) ## CPU profiler updates @@ -40,15 +43,16 @@ ## Memory updates -* Added the ability to pin classes to the top of the Profile Memory table. [#8898](https://github.com/flutter/devtools/issues/8898) +* Added the ability to pin classes to the top of the Profile Memory table. + [#8898](https://github.com/flutter/devtools/issues/8898) ## Debugger updates -* Prevent values from being garbage-collected, while being evaluated. +* Prevented values from being garbage-collected, while being evaluated. [#9885](https://github.com/flutter/devtools/pull/9885) * Update to latest version of the Dart syntax highlighting grammar [#9920](https://github.com/flutter/devtools/pull/9920). -* Fix a bug in the TextMate grammar parser that could result in code after +* Fixed a bug in the TextMate grammar parser that could result in code after comments being classified as comments. [#9921](https://github.com/flutter/devtools/pull/9921). * Fixed an overflow in the debugging controls when the Debugger screen is @@ -70,7 +74,7 @@ ## Logging updates -* Correct time units and cumulative nature of GC events. +* Corrected time units and cumulative nature of GC events. [#9890](https://github.com/flutter/devtools/pull/9890) * Fixed a bug where long `dart:developer` log messages lost their structured Details view. - @@ -83,7 +87,7 @@ ## Deep links tool updates * Added a "Watch tutorial" link to the status line that points to the - [deep links video tutorial](https://youtu.be/d7sZL6h1Elw). + [deep links video tutorial](https://youtu.be/d7sZL6hIElw). [#9925](https://github.com/flutter/devtools/pull/9925) ## VS Code sidebar updates @@ -92,12 +96,13 @@ ## DevTools extension updates -* Hide the DevTools extensions menu button in single-screen embedded mode (`EmbedMode.embedOne`) on standard screens. +* Hide the DevTools extensions menu button in single-screen embedded mode + (`EmbedMode.embedOne`) on standard screens. [#8507](https://github.com/flutter/devtools/issues/8507) * Added iframe sandboxing for embedded DevTools extensions to enforce origin isolation. [#9967](https://github.com/flutter/devtools/pull/9967) -* Improved DevTools extension isolation by tracking the providing package name for - enablement, deduplication, and asset loading. +* Improved DevTools extension isolation by tracking the providing package + name for enablement, deduplication, and asset loading. [#9981](https://github.com/flutter/devtools/pull/9981) ## Advanced developer mode updates @@ -107,4 +112,4 @@ ## Full commit history To find a complete list of changes in this release, check out the -[DevTools git log](https://github.com/flutter/devtools/tree/v2.61.0). +[DevTools git log](https://github.com/flutter/devtools/tree/v2.61.0). \ No newline at end of file
diff --git a/packages/devtools_app/test/screens/performance/performance_screen_test.dart b/packages/devtools_app/test/screens/performance/performance_screen_test.dart index 6f23218..8d24ef2 100644 --- a/packages/devtools_app/test/screens/performance/performance_screen_test.dart +++ b/packages/devtools_app/test/screens/performance/performance_screen_test.dart
@@ -9,6 +9,7 @@ import 'package:devtools_app/devtools_app.dart'; import 'package:devtools_app/src/screens/performance/panes/controls/performance_controls.dart'; +import 'package:devtools_app/src/screens/performance/panes/rebuild_stats/rebuild_stats.dart'; import 'package:devtools_app/src/screens/performance/panes/timeline_events/timeline_events_view.dart'; import 'package:devtools_app/src/screens/performance/tabbed_performance_view.dart'; import 'package:devtools_app/src/shared/feature_flags.dart'; @@ -218,7 +219,6 @@ await tester.runAsync(() async { await pumpPerformanceScreen(tester, runAsync: true); await tester.pumpAndSettle(); - final chartButtonFinder = find.byType(VisibilityButton); expect(chartButtonFinder, findsOneWidget); @@ -231,7 +231,6 @@ await tester.tap(chartButtonFinder); await tester.pumpAndSettle(); - // The flutter frames chart should no longer be visible. expect(find.byType(FramesChartControls), findsNothing); expect( @@ -395,6 +394,64 @@ }, ); }); + + group('RebuildStatsView', () { + late FakeServiceConnectionManager fakeServiceConnection; + late RebuildCountModel model; + late ValueNotifier<FlutterFrame?> selectedFrame; + + setUp(() { + fakeServiceConnection = FakeServiceConnectionManager(); + mockConnectedApp(fakeServiceConnection.serviceManager.connectedApp!); + setGlobal(ServiceConnectionManager, fakeServiceConnection); + setGlobal(IdeTheme, IdeTheme()); + setGlobal(NotificationService, NotificationService()); + setGlobal(BannerMessagesController, BannerMessagesController()); + setGlobal(PreferencesController, PreferencesController()); + setGlobal(OfflineDataController, OfflineDataController()); + model = RebuildCountModel(); + selectedFrame = ValueNotifier<FlutterFrame?>(null); + }); + + testWidgets('shows message when running in profile mode', ( + WidgetTester tester, + ) async { + mockConnectedApp( + fakeServiceConnection.serviceManager.connectedApp!, + isProfileBuild: true, + ); + + await tester.pumpWidget( + wrapWithControllers( + RebuildStatsView(model: model, selectedFrame: selectedFrame), + ), + ); + await tester.pump(); + + expect( + find.textContaining('Widget rebuild counts are only available'), + findsOneWidget, + ); + }); + + testWidgets('shows normal UI when running in debug mode', ( + WidgetTester tester, + ) async { + mockConnectedApp(fakeServiceConnection.serviceManager.connectedApp!); + + await tester.pumpWidget( + wrapWithControllers( + RebuildStatsView(model: model, selectedFrame: selectedFrame), + ), + ); + await tester.pump(); + + expect( + find.textContaining('Widget rebuild counts are only available'), + findsNothing, + ); + }); + }); }); }