LCOV - code coverage report
Current view: top level - src - stream_chat_core.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 54 54 100.0 %
Date: 2021-05-27 10:59:48 Functions: 0 0 -

          Line data    Source code
       1             : import 'dart:async';
       2             : 
       3             : import 'package:connectivity_plus/connectivity_plus.dart';
       4             : import 'package:flutter/foundation.dart';
       5             : import 'package:flutter/material.dart';
       6             : import 'package:stream_chat/stream_chat.dart';
       7             : import 'package:stream_chat_flutter_core/src/typedef.dart';
       8             : 
       9             : /// Widget used to provide information about the chat to the widget tree.
      10             : /// This Widget is used to react to life cycle changes and system updates.
      11             : /// When the app goes into the background, the websocket connection is kept
      12             : /// alive for two minutes before being terminated.
      13             : ///
      14             : /// Conversely, when app is resumed or restarted, a new connection is initiated.
      15             : ///
      16             : /// ```dart
      17             : /// class MyApp extends StatelessWidget {
      18             : ///   final StreamChatClient client;
      19             : ///
      20             : ///   MyApp(this.client);
      21             : ///
      22             : ///   @override
      23             : ///   Widget build(BuildContext context) {
      24             : ///     return MaterialApp(
      25             : ///       home: Container(
      26             : ///         child: StreamChatCore(
      27             : ///           client: client,
      28             : ///           child: ChannelListPage(),
      29             : ///         ),
      30             : ///       ),
      31             : ///     );
      32             : ///   }
      33             : /// }
      34             : /// ```
      35             : ///
      36             : class StreamChatCore extends StatefulWidget {
      37             :   /// Constructor used for creating a new instance of [StreamChatCore].
      38             :   ///
      39             :   /// [StreamChatCore] is a stateful widget which reacts to system events and
      40             :   /// updates Stream's connection status accordingly.
      41           7 :   const StreamChatCore({
      42             :     Key? key,
      43             :     required this.client,
      44             :     required this.child,
      45             :     this.onBackgroundEventReceived,
      46             :     this.backgroundKeepAlive = const Duration(minutes: 1),
      47             :     this.connectivityStream,
      48           7 :   }) : super(key: key);
      49             : 
      50             :   /// Instance of Stream Chat Client containing information about the current
      51             :   /// application.
      52             :   final StreamChatClient client;
      53             : 
      54             :   /// Widget descendant.
      55             :   final Widget child;
      56             : 
      57             :   /// The amount of time that will pass before disconnecting the client in
      58             :   /// the background
      59             :   final Duration backgroundKeepAlive;
      60             : 
      61             :   /// Handler called whenever the [client] receives a new [Event] while the app
      62             :   /// is in background. Can be used to display various notifications depending
      63             :   /// upon the [Event.type]
      64             :   final EventHandler? onBackgroundEventReceived;
      65             : 
      66             :   @visibleForTesting
      67             :   final Stream<ConnectivityResult>? connectivityStream;
      68             : 
      69           7 :   @override
      70           7 :   StreamChatCoreState createState() => StreamChatCoreState();
      71             : 
      72             :   /// Use this method to get the current [StreamChatCoreState] instance
      73           6 :   static StreamChatCoreState of(BuildContext context) {
      74             :     StreamChatCoreState? streamChatState;
      75             : 
      76           6 :     streamChatState = context.findAncestorStateOfType<StreamChatCoreState>();
      77             : 
      78             :     assert(
      79           3 :       streamChatState != null,
      80             :       'You must have a StreamChat widget at the top of your widget tree',
      81             :     );
      82             : 
      83             :     return streamChatState!;
      84             :   }
      85             : }
      86             : 
      87             : /// State class associated with [StreamChatCore].
      88             : class StreamChatCoreState extends State<StreamChatCore>
      89             :     with WidgetsBindingObserver {
      90             :   /// Initialized client used throughout the application.
      91          21 :   StreamChatClient get client => widget.client;
      92             : 
      93             :   Timer? _disconnectTimer;
      94             : 
      95           7 :   @override
      96          14 :   Widget build(BuildContext context) => widget.child;
      97             : 
      98             :   /// The current user
      99           4 :   User? get user => client.state.user;
     100             : 
     101             :   /// The current user as a stream
     102           4 :   Stream<User?> get userStream => client.state.userStream;
     103             : 
     104             :   late final StreamSubscription<ConnectivityResult> _connectivitySubscription;
     105             : 
     106             :   var _isInForeground = true;
     107             :   var _isConnectionAvailable = true;
     108             : 
     109           7 :   @override
     110             :   void initState() {
     111           7 :     super.initState();
     112          14 :     WidgetsBinding.instance?.addObserver(this);
     113           7 :     _connectivitySubscription =
     114          28 :         (widget.connectivityStream ?? Connectivity().onConnectivityChanged)
     115           8 :             .listen((ConnectivityResult result) async {
     116           2 :       _isConnectionAvailable = result != ConnectivityResult.none;
     117           1 :       if (!_isInForeground) {
     118             :         return;
     119             :       }
     120           1 :       if (_isConnectionAvailable) {
     121           3 :         if (client.wsConnectionStatus == ConnectionStatus.disconnected) {
     122           3 :           await client.connect();
     123             :         }
     124             :       } else {
     125           3 :         if (client.wsConnectionStatus == ConnectionStatus.connected) {
     126           3 :           await client.disconnect();
     127             :         }
     128             :       }
     129             :     });
     130             :   }
     131             : 
     132             :   StreamSubscription? _eventSubscription;
     133             : 
     134           1 :   @override
     135             :   void didChangeAppLifecycleState(AppLifecycleState state) {
     136           2 :     _isInForeground = state == AppLifecycleState.resumed;
     137           1 :     if (user != null) {
     138           1 :       if (!_isInForeground) {
     139           1 :         _onBackground();
     140             :       } else {
     141           1 :         _onForeground();
     142             :       }
     143             :     }
     144             :   }
     145             : 
     146           1 :   void _onForeground() {
     147           3 :     if (_disconnectTimer?.isActive == true) {
     148           2 :       _eventSubscription?.cancel();
     149           2 :       _disconnectTimer?.cancel();
     150           3 :     } else if (client.wsConnectionStatus == ConnectionStatus.disconnected &&
     151           1 :         _isConnectionAvailable) {
     152           2 :       client.connect();
     153             :     }
     154             :   }
     155             : 
     156           1 :   void _onBackground() {
     157           2 :     if (widget.onBackgroundEventReceived == null) {
     158           3 :       if (client.wsConnectionStatus != ConnectionStatus.disconnected) {
     159           2 :         client.disconnect();
     160             :       }
     161             :       return;
     162             :     }
     163           4 :     _eventSubscription = client.on().listen(
     164           2 :           widget.onBackgroundEventReceived,
     165             :         );
     166             : 
     167           1 :     void onTimerComplete() {
     168           2 :       _eventSubscription?.cancel();
     169           2 :       client.disconnect();
     170             :     }
     171             : 
     172           4 :     _disconnectTimer = Timer(widget.backgroundKeepAlive, onTimerComplete);
     173             :     return;
     174             :   }
     175             : 
     176           7 :   @override
     177             :   void dispose() {
     178          14 :     WidgetsBinding.instance?.removeObserver(this);
     179           8 :     _eventSubscription?.cancel();
     180           8 :     _disconnectTimer?.cancel();
     181          14 :     _connectivitySubscription.cancel();
     182           7 :     super.dispose();
     183             :   }
     184             : }

Generated by: LCOV version 1.14