@@ -9,6 +9,7 @@ import 'package:amplify_api_dart/src/graphql/web_socket/services/web_socket_serv
9
9
import 'package:amplify_api_dart/src/graphql/web_socket/state/web_socket_state.dart' ;
10
10
import 'package:amplify_api_dart/src/graphql/web_socket/state/ws_subscriptions_state.dart' ;
11
11
import 'package:amplify_api_dart/src/graphql/web_socket/types/connectivity_platform.dart' ;
12
+ import 'package:amplify_api_dart/src/graphql/web_socket/types/process_life_cycle.dart' ;
12
13
import 'package:amplify_api_dart/src/graphql/web_socket/types/subscriptions_event.dart' ;
13
14
import 'package:amplify_api_dart/src/graphql/web_socket/types/web_socket_types.dart' ;
14
15
import 'package:amplify_core/amplify_core.dart' hide SubscriptionEvent;
@@ -33,8 +34,10 @@ class WebSocketBloc with AWSDebuggable, AmplifyLoggerMixin {
33
34
required WebSocketService wsService,
34
35
required GraphQLSubscriptionOptions subscriptionOptions,
35
36
required ConnectivityPlatform connectivity,
37
+ required ProcessLifeCycle processLifeCycle,
36
38
AWSHttpClient ? pollClientOverride,
37
39
}) : _connectivity = connectivity,
40
+ _processLifeCycle = processLifeCycle,
38
41
_pollClient = pollClientOverride ?? AWSHttpClient () {
39
42
final subBlocs = < String , SubscriptionBloc <Object ?>> {};
40
43
@@ -49,6 +52,7 @@ class WebSocketBloc with AWSDebuggable, AmplifyLoggerMixin {
49
52
);
50
53
final blocStream = _wsEventStream.asyncExpand (_eventTransformer);
51
54
_networkSubscription = _getConnectivityStream ();
55
+ _processLifeCycleSubscription = _getProcessLifecycleStream ();
52
56
_stateSubscription = blocStream.listen (_emit);
53
57
add (const InitEvent ());
54
58
}
@@ -81,10 +85,14 @@ class WebSocketBloc with AWSDebuggable, AmplifyLoggerMixin {
81
85
late final Stream <WebSocketEvent > _wsEventStream = _wsEventController.stream;
82
86
late final StreamSubscription <WebSocketState > _stateSubscription;
83
87
late final StreamSubscription <ConnectivityStatus > _networkSubscription;
88
+ late final StreamSubscription <ProcessStatus > _processLifeCycleSubscription;
84
89
85
90
/// Creates a stream representing network connectivity at the hardware level.
86
91
final ConnectivityPlatform _connectivity;
87
92
93
+ /// Creates a stream representing the process life cycle state.
94
+ final ProcessLifeCycle _processLifeCycle;
95
+
88
96
/// The underlying event stream, used only in testing.
89
97
@visibleForTesting
90
98
Stream <WebSocketEvent > get wsEventStream => _wsEventStream;
@@ -164,6 +172,8 @@ class WebSocketBloc with AWSDebuggable, AmplifyLoggerMixin {
164
172
yield * _networkLoss ();
165
173
} else if (event is NetworkFoundEvent ) {
166
174
yield * _networkFound ();
175
+ } else if (event is ProcessUnpausedEvent ) {
176
+ yield * _processUnpaused ();
167
177
} else if (event is PollSuccessEvent ) {
168
178
yield * _pollSuccess ();
169
179
} else if (event is PollFailedEvent ) {
@@ -328,6 +338,16 @@ class WebSocketBloc with AWSDebuggable, AmplifyLoggerMixin {
328
338
yield * const Stream .empty ();
329
339
}
330
340
341
+ Stream <WebSocketState > _processUnpaused () async * {
342
+ final state = _currentState;
343
+ if (state is ConnectedState ) {
344
+ yield state.reconnecting (networkState: NetworkState .disconnected);
345
+ add (const ReconnectEvent ());
346
+ }
347
+ // TODO(dnys1): Yield broken on web debug build.
348
+ yield * const Stream .empty ();
349
+ }
350
+
331
351
/// Handle successful polls
332
352
Stream <WebSocketState > _pollSuccess () async * {
333
353
// TODO(dnys1): Yield broken on web debug build.
@@ -467,6 +487,7 @@ class WebSocketBloc with AWSDebuggable, AmplifyLoggerMixin {
467
487
await Future .wait <void >([
468
488
// TODO(equartey): https://github.com/fluttercommunity/plus_plugins/issues/1382
469
489
if (! isWindows ()) _networkSubscription.cancel (),
490
+ _processLifeCycleSubscription.cancel (),
470
491
Future .value (_pollClient.close ()),
471
492
_stateSubscription.cancel (),
472
493
_wsEventController.close (),
@@ -507,6 +528,41 @@ class WebSocketBloc with AWSDebuggable, AmplifyLoggerMixin {
507
528
);
508
529
}
509
530
531
+ /// Process life cycle stream monitors when the process resumes from a paused state.
532
+ StreamSubscription <ProcessStatus > _getProcessLifecycleStream () {
533
+ var prev = ProcessStatus .detached;
534
+ return _processLifeCycle.onStateChanged.listen (
535
+ (state) {
536
+ if (_isUnpausing (state, prev)) {
537
+ // ignore: invalid_use_of_internal_member
538
+ if (! WebSocketOptions .autoReconnect) {
539
+ _shutdownWithException (
540
+ const NetworkException (
541
+ 'Unable to recover network connection, web socket will close.' ,
542
+ recoverySuggestion: 'Avoid pausing the process.' ,
543
+ ),
544
+ StackTrace .current,
545
+ );
546
+ } else {
547
+ add (const ProcessUnpausedEvent ());
548
+ }
549
+ }
550
+
551
+ prev = state;
552
+ },
553
+ onError: (Object e, StackTrace st) =>
554
+ logger.error ('Error in process life cycle stream $e , $st ' ),
555
+ );
556
+ }
557
+
558
+ bool _isUnpausing (ProcessStatus current, ProcessStatus previous) {
559
+ if (previous != ProcessStatus .paused) return false ;
560
+
561
+ return current == ProcessStatus .hidden ||
562
+ current == ProcessStatus .inactive ||
563
+ current == ProcessStatus .resumed;
564
+ }
565
+
510
566
Future <void > _poll () async {
511
567
try {
512
568
final res = await _sendPollRequest ();
0 commit comments