Skip to content

Commit 3741e50

Browse files
committed
Address PR review: extract _ReconnectActions widget, use MultiValueListenableBuilder and safeUnawaited
1 parent 51c7db0 commit 3741e50

1 file changed

Lines changed: 92 additions & 75 deletions

File tree

packages/devtools_app/lib/src/framework/observer/disconnect_observer.dart

Lines changed: 92 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ import '../../shared/config_specific/import_export/import_export.dart';
1818
import '../../shared/framework/routing.dart';
1919
import '../../shared/globals.dart';
2020
import '../../shared/primitives/query_parameters.dart';
21+
import '../../shared/ui/common_widgets.dart';
22+
import '../../shared/utils/utils.dart';
2123

2224
final _log = Logger('disconnect_observer');
2325

@@ -134,88 +136,54 @@ class DisconnectObserverState extends State<DisconnectObserver>
134136
widget.routerDelegate.navigate(snapshotScreenId, args);
135137
}
136138

137-
Widget _buildReconnectActions(ThemeData theme) {
138-
final reconnectButton = ElevatedButton(
139-
onPressed: _attemptReconnect,
140-
child: const Text('Reconnect'),
141-
);
142-
143-
if (!isEmbedded()) {
144-
return Row(
145-
mainAxisAlignment: MainAxisAlignment.center,
146-
children: [
147-
reconnectButton,
148-
const SizedBox(width: defaultSpacing),
149-
ConnectToNewAppButton(
150-
routerDelegate: widget.routerDelegate,
151-
onPressed: hideDisconnectedOverlay,
152-
gaScreen: gac.devToolsMain,
153-
),
154-
],
155-
);
156-
}
157-
158-
return Column(
159-
mainAxisSize: MainAxisSize.min,
160-
children: [
161-
reconnectButton,
162-
const SizedBox(height: defaultSpacing),
163-
Text(
164-
'Or run a new debug session to connect to it.',
165-
style: theme.textTheme.bodyMedium,
166-
),
167-
],
168-
);
169-
}
170-
171139
OverlayEntry _createDisconnectedOverlay() {
172140
final theme = Theme.of(context);
173141
currentDisconnectedOverlay = OverlayEntry(
174142
builder: (context) => Material(
175143
child: Container(
176144
color: theme.colorScheme.surface,
177-
child: ValueListenableBuilder<bool>(
178-
valueListenable: _isReconnecting,
179-
builder: (context, isReconnecting, _) =>
180-
ValueListenableBuilder<String?>(
181-
valueListenable: _reconnectErrorText,
182-
builder: (context, reconnectErrorText, _) => Center(
183-
child: Column(
184-
children: [
185-
const Spacer(),
186-
Text(
187-
'Disconnected',
188-
style: theme.textTheme.headlineMedium,
145+
child: MultiValueListenableBuilder(
146+
listenables: [_isReconnecting, _reconnectErrorText],
147+
builder: (context, values, _) {
148+
final isReconnecting = values[0]! as bool;
149+
final reconnectErrorText = values[1] as String?;
150+
return Center(
151+
child: Column(
152+
children: [
153+
const Spacer(),
154+
Text('Disconnected', style: theme.textTheme.headlineMedium),
155+
const SizedBox(height: defaultSpacing),
156+
if (isReconnecting)
157+
const CircularProgressIndicator()
158+
else
159+
_ReconnectActions(
160+
theme: theme,
161+
onReconnect: _attemptReconnect,
162+
routerDelegate: widget.routerDelegate,
163+
onConnectToNewApp: hideDisconnectedOverlay,
164+
),
165+
if (reconnectErrorText case final error?) ...[
166+
const SizedBox(height: denseSpacing),
167+
Text(
168+
error,
169+
style: theme.regularTextStyle.copyWith(
170+
color: theme.colorScheme.error,
189171
),
190-
const SizedBox(height: defaultSpacing),
191-
if (isReconnecting)
192-
const CircularProgressIndicator()
193-
else
194-
_buildReconnectActions(theme),
195-
if (reconnectErrorText case final error?) ...[
196-
const SizedBox(height: denseSpacing),
197-
Text(
198-
error,
199-
style: theme.regularTextStyle.copyWith(
200-
color: theme.colorScheme.error,
201-
),
202-
textAlign: TextAlign.center,
203-
),
204-
],
205-
const Spacer(),
206-
if (offlineDataController
207-
.offlineDataJson
208-
.isNotEmpty) ...[
209-
ElevatedButton(
210-
onPressed: _reviewHistory,
211-
child: const Text('Review recent data (offline)'),
212-
),
213-
const Spacer(),
214-
],
215-
],
216-
),
217-
),
172+
textAlign: TextAlign.center,
173+
),
174+
],
175+
const Spacer(),
176+
if (offlineDataController.offlineDataJson.isNotEmpty) ...[
177+
ElevatedButton(
178+
onPressed: _reviewHistory,
179+
child: const Text('Review recent data (offline)'),
180+
),
181+
const Spacer(),
182+
],
183+
],
218184
),
185+
);
186+
},
219187
),
220188
),
221189
),
@@ -254,7 +222,7 @@ class DisconnectObserverState extends State<DisconnectObserver>
254222
_isReconnecting.value = false;
255223

256224
if (reconnectionSuccess) {
257-
unawaited(
225+
safeUnawaited(
258226
widget.routerDelegate.updateArgsIfChanged({
259227
DevToolsQueryParams.vmServiceUriKey: _lastVmServiceUri,
260228
}),
@@ -266,3 +234,52 @@ class DisconnectObserverState extends State<DisconnectObserver>
266234
}
267235
}
268236
}
237+
238+
class _ReconnectActions extends StatelessWidget {
239+
const _ReconnectActions({
240+
required this.theme,
241+
required this.onReconnect,
242+
required this.routerDelegate,
243+
required this.onConnectToNewApp,
244+
});
245+
246+
final ThemeData theme;
247+
final VoidCallback onReconnect;
248+
final DevToolsRouterDelegate routerDelegate;
249+
final VoidCallback onConnectToNewApp;
250+
251+
@override
252+
Widget build(BuildContext context) {
253+
final reconnectButton = ElevatedButton(
254+
onPressed: onReconnect,
255+
child: const Text('Reconnect'),
256+
);
257+
258+
if (!isEmbedded()) {
259+
return Row(
260+
mainAxisAlignment: MainAxisAlignment.center,
261+
children: [
262+
reconnectButton,
263+
const SizedBox(width: defaultSpacing),
264+
ConnectToNewAppButton(
265+
routerDelegate: routerDelegate,
266+
onPressed: onConnectToNewApp,
267+
gaScreen: gac.devToolsMain,
268+
),
269+
],
270+
);
271+
}
272+
273+
return Column(
274+
mainAxisSize: MainAxisSize.min,
275+
children: [
276+
reconnectButton,
277+
const SizedBox(height: defaultSpacing),
278+
Text(
279+
'Or run a new debug session to connect to it.',
280+
style: theme.textTheme.bodyMedium,
281+
),
282+
],
283+
);
284+
}
285+
}

0 commit comments

Comments
 (0)