@@ -18,6 +18,8 @@ import '../../shared/config_specific/import_export/import_export.dart';
1818import '../../shared/framework/routing.dart' ;
1919import '../../shared/globals.dart' ;
2020import '../../shared/primitives/query_parameters.dart' ;
21+ import '../../shared/ui/common_widgets.dart' ;
22+ import '../../shared/utils/utils.dart' ;
2123
2224final _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