1
import 'dart:async';
2

3
import 'package:connectivity/connectivity.dart';
4
import 'package:flutter/widgets.dart';
5
import 'package:flutter_offline/src/utils.dart';
6

7
const kOfflineDebounceDuration = Duration(seconds: 3);
8

9
class OfflineBuilder extends StatefulWidget {
10 13
  factory OfflineBuilder({
11
    Key key,
12
    @required ValueWidgetBuilder<ConnectivityResult> connectivityBuilder,
13
    Duration debounceDuration = kOfflineDebounceDuration,
14
    WidgetBuilder builder,
15
    Widget child,
16
    WidgetBuilder errorBuilder,
17
  }) {
18 13
    return OfflineBuilder.initialize(
19
      key: key,
20
      connectivityBuilder: connectivityBuilder,
21 13
      connectivityService: Connectivity(),
22
      debounceDuration: debounceDuration,
23
      builder: builder,
24
      child: child,
25
      errorBuilder: errorBuilder,
26
    );
27
  }
28

29 13
  @visibleForTesting
30
  OfflineBuilder.initialize({
31
    Key key,
32
    @required this.connectivityBuilder,
33
    @required this.connectivityService,
34
    this.debounceDuration = kOfflineDebounceDuration,
35
    this.builder,
36
    this.child,
37
    this.errorBuilder,
38 13
  })  : assert(connectivityBuilder != null, 'connectivityBuilder cannot be null'),
39 13
        assert(debounceDuration != null, 'debounceDuration cannot be null'),
40 13
        assert(connectivityService != null, 'connectivityService cannot be null'),
41 13
        assert(!(builder is WidgetBuilder && child is Widget) && !(builder == null && child == null),
42
            'You should specify either a builder or a child'),
43 13
        super(key: key);
44

45
  /// Override connectivity service used for testing
46
  final Connectivity connectivityService;
47

48
  /// Debounce duration from epileptic network situations
49
  final Duration debounceDuration;
50

51
  /// Used for building the Offline and/or Online UI
52
  final ValueWidgetBuilder<ConnectivityResult> connectivityBuilder;
53

54
  /// Used for building the child widget
55
  final WidgetBuilder builder;
56

57
  /// The widget below this widget in the tree.
58
  final Widget child;
59

60
  /// Used for building the error widget incase of any platform errors
61
  final WidgetBuilder errorBuilder;
62

63 13
  @override
64 13
  OfflineBuilderState createState() => OfflineBuilderState();
65
}
66

67
class OfflineBuilderState extends State<OfflineBuilder> {
68
  Stream<ConnectivityResult> _connectivityStream;
69

70 13
  @override
71
  void initState() {
72 13
    super.initState();
73

74 13
    _connectivityStream = Stream.fromFuture(widget.connectivityService.checkConnectivity())
75 13
        .asyncExpand((data) => widget.connectivityService.onConnectivityChanged.transform(startsWith(data)))
76 13
        .transform(debounce(widget.debounceDuration));
77
  }
78

79 13
  @override
80
  Widget build(BuildContext context) {
81 13
    return StreamBuilder<ConnectivityResult>(
82 13
      stream: _connectivityStream,
83 13
      builder: (BuildContext context, AsyncSnapshot<ConnectivityResult> snapshot) {
84 13
        if (!snapshot.hasData && !snapshot.hasError) {
85
          return const SizedBox();
86
        }
87

88 13
        if (snapshot.hasError) {
89 13
          if (widget.errorBuilder != null) {
90 13
            return widget.errorBuilder(context);
91
          }
92 13
          throw OfflineBuilderError(snapshot.error);
93
        }
94

95 13
        return widget.connectivityBuilder(context, snapshot.data, widget.child ?? widget.builder(context));
96
      },
97
    );
98
  }
99
}
100

101
class OfflineBuilderError extends Error {
102 13
  OfflineBuilderError(this.error);
103

104
  final Object error;
105

106 13
  @override
107 13
  String toString() => error.toString();
108
}

Read our documentation on viewing source code .

Loading