From 5f85e547d82fd6e51ca8f270cc3506ec2af913d5 Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Thu, 12 Jan 2023 11:33:12 +0000 Subject: [PATCH] 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" --- .../bloc/avatar_detector_bloc.dart | 21 +++++++-- .../bloc/avatar_detector_bloc_test.dart | 46 ++++++++++++++++--- 2 files changed, 58 insertions(+), 9 deletions(-) diff --git a/lib/avatar_detector/bloc/avatar_detector_bloc.dart b/lib/avatar_detector/bloc/avatar_detector_bloc.dart index 6ea8a441..43b76286 100644 --- a/lib/avatar_detector/bloc/avatar_detector_bloc.dart +++ b/lib/avatar_detector/bloc/avatar_detector_bloc.dart @@ -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 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); diff --git a/test/avatar_detector/bloc/avatar_detector_bloc_test.dart b/test/avatar_detector/bloc/avatar_detector_bloc_test.dart index d8eee423..d07105b4 100644 --- a/test/avatar_detector/bloc/avatar_detector_bloc_test.dart +++ b/test/avatar_detector/bloc/avatar_detector_bloc_test.dart @@ -161,7 +161,46 @@ void main() { blocTest( '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.delayed(AvatarDetectorBloc.undetectedDelay); + bloc.add(AvatarDetectorEstimateRequested(_FakeCameraImage())); + }, + expect: () => [ + isInstanceOf().having( + (state) => state.status, + 'status', + equals(AvatarDetectorStatus.loading), + ), + isInstanceOf().having( + (state) => state.status, + 'status', + equals(AvatarDetectorStatus.loaded), + ), + isInstanceOf().having( + (state) => state.status, + 'status', + equals(AvatarDetectorStatus.estimating), + ), + isInstanceOf().having( + (state) => state.status, + 'status', + equals(AvatarDetectorStatus.notDetected), + ), + ], + ); + + blocTest( + '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().having( - (state) => state.status, - 'status', - equals(AvatarDetectorStatus.notDetected), - ), ], );