feat: delay when the avatar is not detected (#327)

* test: included undectedDelay

* docs: documented change

* refactor: changed material import for meta

* docs: removed comma

* refactor: fixed typo for "undected"
This commit is contained in:
Alejandro Santiago
2023-01-12 11:33:12 +00:00
committed by GitHub
parent 3a727c3ab2
commit 5f85e547d8
2 changed files with 58 additions and 9 deletions

View File

@ -4,6 +4,7 @@ import 'package:avatar_detector_repository/avatar_detector_repository.dart';
import 'package:bloc/bloc.dart';
import 'package:camera/camera.dart';
import 'package:equatable/equatable.dart';
import 'package:meta/meta.dart';
import 'package:tensorflow_models/tensorflow_models.dart' as tf;
part 'avatar_detector_event.dart';
@ -18,6 +19,16 @@ class AvatarDetectorBloc
}
final AvatarDetectorRepository _avatarDetectorRepository;
/// The time to wait before considering the [Avatar] as not detected.
@visibleForTesting
static const undetectedDelay = Duration(seconds: 2);
/// The last time the [Avatar] was detected.
///
/// Initially set to [DateTime.now] after the model is [_initialized]; then
/// set to [DateTime.now] after every [Avatar] detection.
late DateTime _lastAvatarDetection;
@override
Future<void> close() {
_avatarDetectorRepository.dispose();
@ -37,6 +48,7 @@ class AvatarDetectorBloc
emit(
state.copyWith(status: AvatarDetectorStatus.loaded),
);
_lastAvatarDetection = DateTime.now();
} on Exception catch (error, trace) {
addError(error, trace);
emit(
@ -61,9 +73,11 @@ class AvatarDetectorBloc
try {
final avatar = await _avatarDetectorRepository.detectAvatar(imageData);
if (avatar == null) {
emit(
state.copyWith(status: AvatarDetectorStatus.notDetected),
);
if (DateTime.now().difference(_lastAvatarDetection) > undetectedDelay) {
emit(
state.copyWith(status: AvatarDetectorStatus.notDetected),
);
}
} else {
emit(
state.copyWith(
@ -71,6 +85,7 @@ class AvatarDetectorBloc
avatar: avatar,
),
);
_lastAvatarDetection = DateTime.now();
}
} catch (error, stackTrace) {
addError(error, stackTrace);

View File

@ -161,7 +161,46 @@ void main() {
blocTest<AvatarDetectorBloc, AvatarDetectorState>(
'emits [AvatarDetectorStatus.loading, AvatarDetectorStatus.loaded, '
'AvatarDetectorStatus.estimating, AvatarDetectorStatus.notDetected] '
'if detectAvatar returns null.',
'if detectAvatar returns null and undetectedDelay elapsed.',
setUp: () {
when(
() => avatarDetectorRepository.detectAvatar(any()),
).thenAnswer((_) async => null);
},
build: () => AvatarDetectorBloc(avatarDetectorRepository),
act: (bloc) async {
bloc.add(AvatarDetectorInitialized());
await Future<void>.delayed(AvatarDetectorBloc.undetectedDelay);
bloc.add(AvatarDetectorEstimateRequested(_FakeCameraImage()));
},
expect: () => [
isInstanceOf<AvatarDetectorState>().having(
(state) => state.status,
'status',
equals(AvatarDetectorStatus.loading),
),
isInstanceOf<AvatarDetectorState>().having(
(state) => state.status,
'status',
equals(AvatarDetectorStatus.loaded),
),
isInstanceOf<AvatarDetectorState>().having(
(state) => state.status,
'status',
equals(AvatarDetectorStatus.estimating),
),
isInstanceOf<AvatarDetectorState>().having(
(state) => state.status,
'status',
equals(AvatarDetectorStatus.notDetected),
),
],
);
blocTest<AvatarDetectorBloc, AvatarDetectorState>(
'emits [AvatarDetectorStatus.loading, AvatarDetectorStatus.loaded, '
'AvatarDetectorStatus.estimating] '
'if detectAvatar returns null and undetectedDelay not elapsed.',
setUp: () {
when(
() => avatarDetectorRepository.detectAvatar(any()),
@ -189,11 +228,6 @@ void main() {
'status',
equals(AvatarDetectorStatus.estimating),
),
isInstanceOf<AvatarDetectorState>().having(
(state) => state.status,
'status',
equals(AvatarDetectorStatus.notDetected),
),
],
);