Skip to content

Commit d27eafd

Browse files
authored
Implement periodic timer (#64)
1 parent 0c44383 commit d27eafd

File tree

5 files changed

+556
-174
lines changed

5 files changed

+556
-174
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
## 3.1.0
2+
3+
- Provide `.periodic` constructor (#45)
4+
- A periodic timer should behave similar to [Timer.periodic](https://api.dart.dev/stable/dart-async/Timer/Timer.periodic.html)
5+
16
## 3.0.0
27

38
- **BREAKING:** `PausableTimer` is now `final`

example/countdown.dart

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
// Example on how to implement countdown making a PausableTimer periodic.
2+
import 'dart:async';
3+
24
import 'package:pausable_timer/pausable_timer.dart';
35

46
void main() async {
@@ -7,21 +9,15 @@ void main() async {
79
var countDown = 5;
810

911
print('Create a periodic timer that fires every 1 second and starts it');
10-
timer = PausableTimer(
12+
timer = PausableTimer.periodic(
1113
Duration(seconds: 1),
1214
() {
1315
countDown--;
14-
// If we reached 0, we don't reset and restart the time, so it won't fire
15-
// again, but it can be reused afterwards if needed. If we cancel the
16-
// timer, then it can be reused after the countdown is over.
17-
if (countDown > 0) {
18-
// we know the callback won't be called before the constructor ends, so
19-
// it is safe to use !
20-
timer
21-
..reset()
22-
..start();
16+
17+
if (countDown == 0) {
18+
timer.pause();
2319
}
24-
// This is really what your callback do.
20+
2521
print('\t$countDown');
2622
},
2723
)..start();

lib/pausable_timer.dart

Lines changed: 66 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ final class PausableTimer implements Timer {
3939
/// When the timer expires, this stopwatch is set to null.
4040
Stopwatch? _stopwatch = clock.stopwatch();
4141

42+
final bool _periodic;
43+
4244
/// The currently active [Timer].
4345
///
4446
/// This is null whenever this timer is not currently active.
@@ -61,45 +63,91 @@ final class PausableTimer implements Timer {
6163
/// should make sure the timer wasn't cancelled before calling this function.
6264
void _startTimer() {
6365
assert(_stopwatch != null);
64-
_timer = _zone.createTimer(
65-
_originalDuration - _stopwatch!.elapsed,
66-
() {
67-
_tick++;
68-
_timer = null;
69-
_stopwatch = null;
70-
_zone.run(_callback!);
71-
},
72-
);
66+
67+
if (_periodic && _stopwatch!.elapsed == Duration.zero) {
68+
_timer = _zone.createPeriodicTimer(
69+
duration,
70+
(Timer timer) {
71+
_tick++;
72+
_zone.run(_callback!);
73+
_stopwatch = clock.stopwatch();
74+
_stopwatch!.start();
75+
},
76+
);
77+
} else {
78+
_timer = _zone.createTimer(
79+
duration - _stopwatch!.elapsed,
80+
() {
81+
_tick++;
82+
if (_periodic) {
83+
reset();
84+
} else {
85+
_timer = null;
86+
_stopwatch = null;
87+
}
88+
_zone.run(_callback!);
89+
},
90+
);
91+
}
92+
7393
_stopwatch!.start();
7494
}
7595

76-
/// Creates a new timer.
96+
/// Creates a new pausable timer.
7797
///
7898
/// The [callback] is invoked after the given [duration], but can be [pause]d
7999
/// in between or [reset]. The [elapsed] time is only accounted for while the
80-
/// timer [isActive].
100+
/// timer is active.
101+
///
102+
/// The timer is paused when created, and must be [start]ed manually.
103+
///
104+
/// The [duration] must be equals or bigger than [Duration.zero].
105+
/// If it is [Duration.zero], the [callback] will still not be called until
106+
/// the timer is [start]ed.
107+
PausableTimer(this.duration, void Function() callback)
108+
: assert(duration >= Duration.zero),
109+
_zone = Zone.current,
110+
_periodic = false {
111+
_callback = _zone.bindCallback(callback);
112+
}
113+
114+
/// Creates a new repeating pausable timer.
115+
///
116+
/// The [callback] is invoked repeatedly with [duration] intervals until
117+
/// canceled with the [cancel] function, but can be [pause]d
118+
/// in between or [reset]. The [elapsed] time is only accounted for while the
119+
/// timer is active.
120+
///
121+
/// The timer is paused when created, and must be [start]ed manually.
122+
///
123+
/// The exact timing depends on the underlying timer implementation.
124+
/// No more than `n` callbacks will be made in `duration * n` time,
125+
/// but the time between two consecutive callbacks
126+
/// can be shorter and longer than `duration`.
81127
///
82-
/// The timer [isPaused] when created, and must be [start]ed manually.
128+
/// In particular, an implementation may schedule the next callback, e.g.,
129+
/// a `duration` after either when the previous callback ended,
130+
/// when the previous callback started, or when the previous callback was
131+
/// scheduled for - even if the actual callback was delayed.
83132
///
84133
/// The [duration] must be equals or bigger than [Duration.zero].
85134
/// If it is [Duration.zero], the [callback] will still not be called until
86135
/// the timer is [start]ed.
87-
PausableTimer(Duration duration, void Function() callback)
136+
PausableTimer.periodic(this.duration, void Function() callback)
88137
: assert(duration >= Duration.zero),
89-
_originalDuration = duration,
90-
_zone = Zone.current {
138+
_zone = Zone.current,
139+
_periodic = true {
91140
_callback = _zone.bindCallback(callback);
92141
}
93142

94143
/// The original duration this [Timer] was created with.
95-
Duration get duration => _originalDuration;
96-
final Duration _originalDuration;
144+
final Duration duration;
97145

98146
/// The time this [Timer] have been active.
99147
///
100148
/// If the timer is paused, the elapsed time is also not computed anymore, so
101149
/// [elapsed] is always less than or equals to the [duration].
102-
Duration get elapsed => _stopwatch?.elapsed ?? _originalDuration;
150+
Duration get elapsed => _stopwatch?.elapsed ?? duration;
103151

104152
/// True if this [Timer] is armed but not currently active.
105153
///

pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ funding:
66
- https://github.com/sponsors/mateusfccp
77
- https://github.com/llucax/llucax/blob/main/sponsoring-platforms.md
88

9-
version: 3.0.0
9+
version: 3.1.0
1010

1111
environment:
1212
sdk: ">=3.0.0 <4.0.0"

0 commit comments

Comments
 (0)