Browse Source

neon: Implement TimerBloc

pull/344/head
jld3103 2 years ago
parent
commit
e8a48c7869
No known key found for this signature in database
GPG Key ID: 9062417B9E8EB7B3
  1. 38
      .github/workflows/dart.yml
  2. 1
      packages/neon/neon/lib/neon.dart
  3. 85
      packages/neon/neon/lib/src/blocs/timer.dart
  4. 1
      packages/neon/neon/mono_pkg.yaml
  5. 1
      packages/neon/neon/pubspec.yaml
  6. 43
      packages/neon/neon/test/timer_bloc_test.dart
  7. 6
      tool/ci.sh

38
.github/workflows/dart.yml

@ -869,6 +869,38 @@ jobs:
needs:
- job_001
job_028:
name: "all; PKG: packages/neon/neon; `flutter test`"
runs-on: ubuntu-latest
steps:
- name: Cache Pub hosted dependencies
uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8
with:
path: "~/.pub-cache/hosted"
key: "os:ubuntu-latest;pub-cache-hosted;sdk:stable;packages:packages/neon/neon;commands:test_0"
restore-keys: |
os:ubuntu-latest;pub-cache-hosted;sdk:stable;packages:packages/neon/neon
os:ubuntu-latest;pub-cache-hosted;sdk:stable
os:ubuntu-latest;pub-cache-hosted
os:ubuntu-latest
- name: Setup Flutter SDK
uses: subosito/flutter-action@48cafc24713cca54bbe03cdc3a423187d413aafa
with:
channel: stable
- id: checkout
name: Checkout repository
uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab
- id: packages_neon_neon_pub_upgrade
name: packages/neon/neon; flutter pub upgrade
run: flutter pub upgrade
if: "always() && steps.checkout.conclusion == 'success'"
working-directory: packages/neon/neon
- name: packages/neon/neon; flutter test
run: flutter test
if: "always() && steps.packages_neon_neon_pub_upgrade.conclusion == 'success'"
working-directory: packages/neon/neon
needs:
- job_001
job_029:
name: "all; PKG: packages/nextcloud; `dart test`"
runs-on: ubuntu-latest
steps:
@ -876,7 +908,7 @@ jobs:
uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8
with:
path: "~/.pub-cache/hosted"
key: "os:ubuntu-latest;pub-cache-hosted;sdk:stable;packages:packages/nextcloud;commands:test"
key: "os:ubuntu-latest;pub-cache-hosted;sdk:stable;packages:packages/nextcloud;commands:test_1"
restore-keys: |
os:ubuntu-latest;pub-cache-hosted;sdk:stable;packages:packages/nextcloud
os:ubuntu-latest;pub-cache-hosted;sdk:stable
@ -900,7 +932,7 @@ jobs:
working-directory: packages/nextcloud
needs:
- job_001
job_029:
job_030:
name: "all; PKG: packages/sort_box; `dart test`"
runs-on: ubuntu-latest
steps:
@ -908,7 +940,7 @@ jobs:
uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8
with:
path: "~/.pub-cache/hosted"
key: "os:ubuntu-latest;pub-cache-hosted;sdk:stable;packages:packages/sort_box;commands:test"
key: "os:ubuntu-latest;pub-cache-hosted;sdk:stable;packages:packages/sort_box;commands:test_1"
restore-keys: |
os:ubuntu-latest;pub-cache-hosted;sdk:stable;packages:packages/sort_box
os:ubuntu-latest;pub-cache-hosted;sdk:stable

1
packages/neon/neon/lib/neon.dart

@ -56,6 +56,7 @@ part 'src/blocs/first_launch.dart';
part 'src/blocs/login.dart';
part 'src/blocs/next_push.dart';
part 'src/blocs/push_notifications.dart';
part 'src/blocs/timer.dart';
part 'src/blocs/user_details.dart';
part 'src/blocs/user_status.dart';
part 'src/interfaces/notifications.dart';

85
packages/neon/neon/lib/src/blocs/timer.dart

@ -0,0 +1,85 @@
part of '../../neon.dart';
abstract class TimerBlocEvents {
/// Register a [callback] that will be called periodically.
/// The time between the executions is defined by the [duration].
NeonTimer registerTimer(final Duration duration, final VoidCallback callback);
/// Unregister a timer that has been previously registered with the bloc.
/// You can also use [NeonTimer.cancel].
void unregisterTimer(final NeonTimer timer);
}
abstract class TimerBlocStates {}
/// Execute callbacks at defined periodic intervals.
/// Components can register their callbacks and everything with the same periodicity will be executed at the same time.
///
/// The [TimerBloc] is a singleton.
/// Sub-second timers are not supported.
class TimerBloc extends Bloc implements TimerBlocEvents, TimerBlocStates {
factory TimerBloc() => instance ??= TimerBloc._();
@visibleForTesting
factory TimerBloc.mocked(final TimerBloc mock) => instance ??= mock;
TimerBloc._();
@visibleForTesting
static TimerBloc? instance;
final Map<int, Timer> _timers = {};
final Map<int, Set<VoidCallback>> _callbacks = {};
@visibleForTesting
Map<int, Timer> get timers => _timers;
@visibleForTesting
Map<int, Set<VoidCallback>> get callbacks => _callbacks;
@override
void dispose() {
for (final timer in _timers.values) {
timer.cancel();
}
_timers.clear();
_callbacks.clear();
TimerBloc.instance = null;
}
@override
NeonTimer registerTimer(final Duration duration, final VoidCallback callback) {
if (_timers[duration.inSeconds] == null) {
_timers[duration.inSeconds] = Timer.periodic(duration, (final _) {
for (final callback in _callbacks[duration.inSeconds]!) {
callback();
}
});
_callbacks[duration.inSeconds] = {callback};
} else {
_callbacks[duration.inSeconds]!.add(callback);
}
return NeonTimer(duration, callback);
}
@override
void unregisterTimer(final NeonTimer timer) {
if (_timers[timer.duration.inSeconds] != null) {
_callbacks[timer.duration.inSeconds]!.remove(timer.callback);
}
}
}
class NeonTimer {
NeonTimer(
this.duration,
this.callback,
);
final Duration duration;
final VoidCallback callback;
void cancel() {
TimerBloc().unregisterTimer(this);
}
}

1
packages/neon/neon/mono_pkg.yaml

@ -5,3 +5,4 @@ stages:
- all:
- analyze: --fatal-infos .
- format: --output=none --set-exit-if-changed --line-length 120 .
- test

1
packages/neon/neon/pubspec.yaml

@ -64,6 +64,7 @@ dev_dependencies:
git:
url: https://github.com/stack11/dart_nit_picking
ref: 0b2ee0d
test: ^1.24.3
dependency_overrides:
wakelock_windows: # TODO: https://github.com/creativecreatorormaybenot/wakelock/pull/195

43
packages/neon/neon/test/timer_bloc_test.dart

@ -0,0 +1,43 @@
import 'package:neon/neon.dart';
import 'package:test/test.dart';
void main() {
group('TimerBloc', () {
tearDown(() {
TimerBloc().dispose();
});
test('Register timer', () async {
const duration = Duration(milliseconds: 100);
final stopwatch = Stopwatch()..start();
final callback = stopwatch.stop;
TimerBloc().registerTimer(duration, callback);
await Future.delayed(duration);
expect(stopwatch.elapsedMilliseconds, greaterThan(duration.inMilliseconds));
expect(stopwatch.elapsedMilliseconds, lessThan(duration.inMilliseconds * 1.1));
expect(TimerBloc().callbacks[duration.inSeconds], contains(callback));
expect(TimerBloc().timers[duration.inSeconds], isNot(isNull));
});
test('Unregister timer', () async {
const duration = Duration(milliseconds: 100);
final callback = neverCalled;
TimerBloc().registerTimer(duration, callback).cancel();
await Future.delayed(duration);
expect(TimerBloc().callbacks[duration.inSeconds], isNot(contains(callback)));
});
test('dispose', () {
TimerBloc().registerTimer(const Duration(minutes: 1), () {});
expect(TimerBloc().timers, hasLength(1));
expect(TimerBloc().callbacks, hasLength(1));
TimerBloc().dispose();
expect(TimerBloc().timers, isEmpty);
expect(TimerBloc().callbacks, isEmpty);
});
});
}

6
tool/ci.sh

@ -79,7 +79,11 @@ for PKG in ${PKGS}; do
echo 'dart format --output=none --set-exit-if-changed --line-length 120 .'
dart format --output=none --set-exit-if-changed --line-length 120 . || EXIT_CODE=$?
;;
test)
test_0)
echo 'flutter test'
flutter test || EXIT_CODE=$?
;;
test_1)
echo 'dart test'
dart test || EXIT_CODE=$?
;;

Loading…
Cancel
Save