-
Notifications
You must be signed in to change notification settings - Fork 15
/
Copy pathpresence_widget.dart
157 lines (126 loc) · 3.75 KB
/
presence_widget.dart
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
import 'dart:async';
import 'package:flutter/widgets.dart';
import 'package:pubnub/pubnub.dart';
import '../provider.dart';
import '../utils/did_init_mixin.dart';
/// Widget that manages presence of an user.
///
/// This widget couples presence to it's lifecycle.
/// As long as the widget is mounted and [online] is set to `true`,
/// heartbeats will be sent to the server.
///
/// If [announceLeave] is set to `true`, then leave events will be generated:
/// * when [online] changes from `true` to `false`,
/// * when this widget is unmounted.
///
/// [child] is optional. If `null`, then this widget will be invisible.
///
/// Example:
/// ```dart
/// PresenceWidget(
/// online: true,
/// announceLeave: true,
/// )
/// ```
class PresenceWidget extends StatefulWidget {
/// Optional child widget for convinience.
final Widget child;
/// [Keyset] instance that will be used by this widget.
final Keyset keyset;
/// Name of a named keyset that will be used by this widget.
final String using;
/// Whether heartbeats should be sent or not.
final bool online;
/// Whether leave events should be announced.
final bool announceLeave;
/// Amount of time between heartbeats.
final int heartbeatInterval;
/// Optional set of channels to override heartbeat channels.
final Set<String> channels;
/// Optional set of channel groups to override heartbeat channel groups.
final Set<String> channelGroups;
PresenceWidget({
this.child,
this.keyset,
this.using,
this.online = true,
this.announceLeave = false,
this.heartbeatInterval = 200,
this.channels = const <String>{},
this.channelGroups = const <String>{},
});
@override
PresenceWidgetState createState() => PresenceWidgetState();
}
class PresenceWidgetState extends State<PresenceWidget> with DidInitState {
Timer timer;
PubNub _pubnub;
@override
void dispose() {
_cancelTimer();
_announceLeave();
super.dispose();
}
@override
void didInitState() {
_pubnub = PubNubProvider.of(context).instance;
_setupTimer();
}
@override
void didUpdateWidget(covariant PresenceWidget oldWidget) {
super.didUpdateWidget(oldWidget);
_cancelTimer();
if (oldWidget.online == true && widget.online == false) {
_announceLeave();
}
if (widget.online) {
_setupTimer();
}
}
void _cancelTimer() {
if (timer != null) {
timer.cancel();
timer = null;
}
}
void _setupTimer() {
if (timer != null) {
_cancelTimer();
}
timer = Timer.periodic(
Duration(seconds: widget.heartbeatInterval), _sendHeartbeat);
}
Future<void> _sendHeartbeat(Timer timer) async {
var keyset = _pubnub.keysets.obtain(widget.keyset, widget.using);
var channels =
widget.channels ?? _pubnub.getSubscribedChannelsForUUID(keyset.uuid);
var channelGroups = widget.channelGroups ??
_pubnub.getSubscribedChannelGroupsForUUID(keyset.uuid);
await _pubnub.announceHeartbeat(
heartbeat: widget.heartbeatInterval,
channels: channels,
channelGroups: channelGroups,
keyset: widget.keyset,
using: widget.using,
);
}
Future<void> _announceLeave() async {
if (widget.announceLeave) {
var keyset = _pubnub.keysets.obtain(widget.keyset, widget.using);
var channels =
widget.channels ?? _pubnub.getSubscribedChannelsForUUID(keyset.uuid);
var channelGroups = widget.channelGroups ??
_pubnub.getSubscribedChannelGroupsForUUID(keyset.uuid);
await _pubnub.announceLeave(
keyset: widget.keyset,
using: widget.using,
channels: channels,
channelGroups: channelGroups,
);
}
}
@override
Widget build(BuildContext context) {
return widget.child ?? SizedBox.shrink();
}
}