Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ class PerformanceController extends DevToolsScreenController
Future<void> _loadOfflineData(OfflinePerformanceData data) async {
await clearData();
offlinePerformanceData = data;
selectedFeatureTabIndex = data.selectedTab;
Comment thread
gords2 marked this conversation as resolved.
await _applyToFeatureControllersAsync(
(c) => c.setOfflineData(offlinePerformanceData!),
);
Expand Down Expand Up @@ -285,6 +286,7 @@ class PerformanceController extends DevToolsScreenController
selectedFrame: flutterFramesController.selectedFrame.value,
rebuildCountModel: rebuildCountModel,
displayRefreshRate: flutterFramesController.displayRefreshRate.value,
selectedTab: selectedFeatureTabIndex,
).toJson(),
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class OfflinePerformanceData {
this.frames = const <FlutterFrame>[],
this.selectedFrame,
this.rebuildCountModel,
this.selectedTab = 0,
double? displayRefreshRate,
}) : displayRefreshRate = displayRefreshRate ?? defaultRefreshRate;

Expand All @@ -36,6 +37,7 @@ class OfflinePerformanceData {
selectedFrame: selectedFrame,
rebuildCountModel: json.rebuildCountModel,
displayRefreshRate: json.displayRefreshRate,
selectedTab: json.selectedTab,
);
}

Expand All @@ -44,6 +46,7 @@ class OfflinePerformanceData {
static const displayRefreshRateKey = 'displayRefreshRate';
static const flutterFramesKey = 'flutterFrames';
static const selectedFrameIdKey = 'selectedFrameId';
static const selectedTabKey = 'selectedTab';

final Uint8List? perfettoTraceBinary;

Expand All @@ -56,6 +59,12 @@ class OfflinePerformanceData {

final FlutterFrame? selectedFrame;

/// The index of the feature tab that was selected when the data was exported.
///
/// This is restored when loading offline data so the user lands on the same
/// tab they exported from.
final int selectedTab;

bool get isEmpty => perfettoTraceBinary == null;

Map<String, Object?> toJson() => {
Expand All @@ -64,6 +73,7 @@ class OfflinePerformanceData {
selectedFrameIdKey: selectedFrame?.id,
displayRefreshRateKey: displayRefreshRate,
rebuildCountModelKey: rebuildCountModel?.toJson(),
selectedTabKey: selectedTab,
};
}

Expand All @@ -77,6 +87,9 @@ extension type _PerformanceDataJson(Map<String, Object?> json) {
int? get selectedFrameId =>
json[OfflinePerformanceData.selectedFrameIdKey] as int?;

int get selectedTab =>
json[OfflinePerformanceData.selectedTabKey] as int? ?? 0;

List<FlutterFrame> get frames =>
(json[OfflinePerformanceData.flutterFramesKey] as List? ?? [])
.cast<Map>()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,17 +80,27 @@ class _TabbedPerformanceViewState extends State<TabbedPerformanceView>
.map((t) => t.featureController)
.toList();

// If there is not an active feature, activate the first.
// The set of visible tabs can differ between when offline data was exported
// and when it is loaded (e.g. the Frame Analysis and Rebuild Stats tabs are
// only shown for Flutter apps with the relevant data). Clamp the restored
// tab index to the tabs that are actually available to avoid an
// out-of-bounds selection.
final selectedTabIndex = controller.selectedFeatureTabIndex.clamp(
0,
tabs.length - 1,
);

// If there is not an active feature, activate the selected one.
if (featureControllers.firstWhereOrNull(
(controller) => controller?.isActiveFeature ?? false,
) ==
null) {
_setActiveFeature(0, featureControllers[0]);
_setActiveFeature(selectedTabIndex, featureControllers[selectedTabIndex]);
}

return AnalyticsTabbedView(
tabs: tabs,
initialSelectedIndex: controller.selectedFeatureTabIndex,
initialSelectedIndex: selectedTabIndex,
gaScreen: gac.performance,
onTabChanged: (int index) {
_setActiveFeature(index, featureControllers[index]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ void main() {
expect(offlineData.selectedFrame, isNull);
expect(offlineData.rebuildCountModel, isNull);
expect(offlineData.displayRefreshRate, 60.0);
expect(offlineData.selectedTab, 0);
});

test('init from parse', () {
Expand All @@ -32,6 +33,7 @@ void main() {
expect(offlineData.selectedFrame!.id, equals(2));
expect(offlineData.displayRefreshRate, equals(60));
expect(offlineData.rebuildCountModel, isNull);
expect(offlineData.selectedTab, equals(0));
});

test('to json', () {
Expand All @@ -44,12 +46,22 @@ void main() {
OfflinePerformanceData.selectedFrameIdKey: null,
OfflinePerformanceData.displayRefreshRateKey: 60,
OfflinePerformanceData.rebuildCountModelKey: null,
OfflinePerformanceData.selectedTabKey: 0,
Comment thread
gords2 marked this conversation as resolved.
}),
);

offlineData = OfflinePerformanceData.fromJson(rawPerformanceData);
expect(offlineData.toJson(), rawPerformanceData);
});

test('round trips a non-zero selectedTab', () {
final offlineData = OfflinePerformanceData(selectedTab: 2);
final json = offlineData.toJson();
expect(json[OfflinePerformanceData.selectedTabKey], equals(2));

final parsed = OfflinePerformanceData.fromJson(json);
expect(parsed.selectedTab, equals(2));
});
});

group('$FlutterTimelineEvent', () {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108244,7 +108244,8 @@ final Map<String, Object?> samplePerformanceData = json.decode('''
}
],
"displayRefreshRate": 60,
"rebuildCountModel": null
"rebuildCountModel": null,
"selectedTab": 0
}
}
''');