jogboms / flutter_offline
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
import 'package:wifi_info_flutter/wifi_info_flutter.dart';
7

8
const kOfflineDebounceDuration = Duration(seconds: 3);
9
typedef ValueWidgetBuilder<T> = Widget Function(BuildContext context, T value, Widget child);
10

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

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

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

49
  final WifiInfo wifiInfo;
50

51
  /// Debounce duration from epileptic network situations
52
  final Duration debounceDuration;
53

54
  /// Used for building the Offline and/or Online UI
55
  final ValueWidgetBuilder<ConnectivityResult> connectivityBuilder;
56

57
  /// Used for building the child widget
58
  final WidgetBuilder? builder;
59

60
  /// The widget below this widget in the tree.
61
  final Widget? child;
62

63
  /// Used for building the error widget incase of any platform errors
64
  final WidgetBuilder? errorBuilder;
65

66 13
  @override
67 13
  OfflineBuilderState createState() => OfflineBuilderState();
68
}
69

70
class OfflineBuilderState extends State<OfflineBuilder> {
71
  late Stream<ConnectivityResult> _connectivityStream;
72

73 13
  @override
74
  void initState() {
75 13
    super.initState();
76

77 13
    _connectivityStream = Stream.fromFuture(widget.connectivityService.checkConnectivity())
78 13
        .asyncExpand((data) => widget.connectivityService.onConnectivityChanged.transform(startsWith(data)))
79 13
        .transform(debounce(widget.debounceDuration));
80
  }
81

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

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

98 13
        return widget.connectivityBuilder(context, snapshot.data!, widget.child ?? widget.builder!(context));
99
      },
100
    );
101
  }
102
}
103

104
class OfflineBuilderError extends Error {
105 13
  OfflineBuilderError(this.error);
106

107
  final Object error;
108

109 13
  @override
110 13
  String toString() => error.toString();
111
}

Read our documentation on viewing source code .

Loading