Skip to content

Commit 52d26f4

Browse files
Fix a bug with the review history on disconnect experience (#8985)
1 parent 15bb326 commit 52d26f4

5 files changed

Lines changed: 63 additions & 40 deletions

File tree

packages/devtools_app/lib/src/app.dart

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -141,12 +141,23 @@ class DevToolsAppState extends State<DevToolsApp> with AutoDisposeMixin {
141141
}
142142
});
143143
addAutoDisposeListener(serviceConnection.serviceManager.connectedState, () {
144-
final connected =
145-
serviceConnection.serviceManager.connectedState.value.connected;
144+
final connectionState =
145+
serviceConnection.serviceManager.connectedState.value;
146+
147+
// When disconnecting from an app, prepare the offline state for reviewing
148+
// history.
149+
screenControllers.forEachInitialized((screenController) {
150+
if (screenController is OfflineScreenControllerMixin &&
151+
!connectionState.connected &&
152+
!connectionState.userInitiatedConnectionState) {
153+
screenController.maybePrepareDataForReviewingHistory();
154+
}
155+
});
156+
146157
// Dispose the current connected controllers, if any, for any change to
147158
// the connected state.
148159
screenControllers.disposeConnectedControllers();
149-
_initScreenControllers(connected: connected);
160+
_initScreenControllers(connected: connectionState.connected);
150161
});
151162

152163
// TODO(https://github.com/flutter/devtools/issues/6018): Once
@@ -582,14 +593,10 @@ class DevToolsScreen<C extends DevToolsScreenController> {
582593
DevToolsRouterDelegate routerDelegate, {
583594
required bool offline,
584595
}) {
585-
screenControllers.register<C>(() {
586-
final controller =
587-
createController!(routerDelegate) as DisposableController;
588-
if (controller is OfflineScreenControllerMixin) {
589-
controller.initReviewHistoryOnDisconnectListener();
590-
}
591-
return controller as C;
592-
}, offline: offline);
596+
screenControllers.register<C>(
597+
() => createController!(routerDelegate),
598+
offline: offline,
599+
);
593600
}
594601
}
595602

packages/devtools_app/lib/src/shared/framework/screen_controllers.dart

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,25 @@ class ScreenControllers {
8282
}
8383
offlineControllers.clear();
8484
}
85+
86+
/// Calls the [callback] function on each initialized screen controller.
87+
///
88+
/// Optionally, calls the [callback] on the offline screen controllers when
89+
/// [includeOfflineControllers] is true.
90+
void forEachInitialized(
91+
void Function(DevToolsScreenController screenController) callback, {
92+
bool includeOfflineControllers = false,
93+
}) {
94+
final controllers =
95+
includeOfflineControllers
96+
? [...this.controllers.values, ...offlineControllers.values]
97+
: this.controllers.values;
98+
for (final lazyController in controllers) {
99+
if (lazyController.initialized) {
100+
callback(lazyController.controller);
101+
}
102+
}
103+
}
85104
}
86105

87106
/// Helper class that performs lazy initialization for
@@ -96,6 +115,9 @@ class _LazyController<T extends DevToolsScreenController> {
96115
T get controller => _controller ??= creator()..init();
97116
T? _controller;
98117

118+
/// Whether the controller has been initialized.
119+
bool get initialized => _controller != null;
120+
99121
void dispose() {
100122
_controller?.dispose();
101123
_controller = null;

packages/devtools_app/lib/src/shared/offline/offline_data.dart

Lines changed: 15 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -192,37 +192,24 @@ mixin OfflineScreenControllerMixin<T>
192192
_exportController.downloadFile(encodedData);
193193
}
194194

195-
/// Adds a listener that will prepare the screen's current data for offline
196-
/// viewing after an app disconnect.
195+
/// Prepare the screen's current data for offline viewing after an app
196+
/// disconnect.
197197
///
198198
/// This is in preparation for the user clicking the 'Review History' button
199199
/// from the disconnect screen.
200-
///
201-
/// For screens that support the disconnect experience, which is a screen that
202-
/// allows you to view historical data from before the app was disconnected
203-
/// even after we lose connection to the device, this should be called in the
204-
/// controller's initialization.
205-
void initReviewHistoryOnDisconnectListener() {
206-
addAutoDisposeListener(serviceConnection.serviceManager.connectedState, () {
207-
final connectionState =
208-
serviceConnection.serviceManager.connectedState.value;
209-
if (!connectionState.connected &&
210-
!connectionState.userInitiatedConnectionState) {
211-
final currentScreenData = prepareOfflineScreenData();
212-
// Only store data for the current page. We can change this in the
213-
// future if we support offline imports for more than once screen at a
214-
// time.
215-
if (DevToolsRouterDelegate.currentPage == currentScreenData.screenId) {
216-
final previouslyConnectedApp =
217-
offlineDataController.previousConnectedApp;
218-
final offlineData = _exportController.generateDataForExport(
219-
offlineScreenData: currentScreenData.toJson(),
220-
connectedApp: previouslyConnectedApp,
221-
);
222-
offlineDataController.offlineDataJson = offlineData;
223-
}
224-
}
225-
});
200+
void maybePrepareDataForReviewingHistory() {
201+
final currentScreenData = prepareOfflineScreenData();
202+
// Only store data for the current page. We can change this in the
203+
// future if we support offline imports for more than once screen at a
204+
// time.
205+
if (DevToolsRouterDelegate.currentPage == currentScreenData.screenId) {
206+
final previouslyConnectedApp = offlineDataController.previousConnectedApp;
207+
final offlineData = _exportController.generateDataForExport(
208+
offlineScreenData: currentScreenData.toJson(),
209+
connectedApp: previouslyConnectedApp,
210+
);
211+
offlineDataController.offlineDataJson = offlineData;
212+
}
226213
}
227214
}
228215

packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ To learn more about DevTools, check out the
1515

1616
## General updates
1717

18-
TODO: Remove this section if there are not any general updates.
18+
* Fix a bug with the review history on disconnect experience. -
19+
[#8985](https://github.com/flutter/devtools/pull/8985)
1920

2021
## Inspector updates
2122

packages/devtools_app/test/shared/framework/screen_controllers_test.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@ void main() {
7272

7373
verifyNever(controller1.init());
7474
verifyNever(controller2.init());
75+
expect(
76+
screenControllers.controllers.values.any((c) => c.initialized),
77+
false,
78+
);
7579
});
7680

7781
test('register overwrites existing controller', () {
@@ -170,9 +174,11 @@ void main() {
170174
);
171175

172176
verifyNever(controller.init()); // Not initialized yet
177+
expect(screenControllers.controllers.values.first.initialized, false);
173178

174179
screenControllers.lookup<MockDevToolsScreenController>();
175180
verify(controller.init()).called(1); // Now it's initialized
181+
expect(screenControllers.controllers.values.first.initialized, true);
176182
});
177183
});
178184
}

0 commit comments

Comments
 (0)