mirror of
https://github.com/flutter/holobooth.git
synced 2025-05-19 14:26:26 +08:00
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:

committed by
GitHub

parent
3a727c3ab2
commit
5f85e547d8
@ -4,6 +4,7 @@ import 'package:avatar_detector_repository/avatar_detector_repository.dart';
|
|||||||
import 'package:bloc/bloc.dart';
|
import 'package:bloc/bloc.dart';
|
||||||
import 'package:camera/camera.dart';
|
import 'package:camera/camera.dart';
|
||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
|
import 'package:meta/meta.dart';
|
||||||
import 'package:tensorflow_models/tensorflow_models.dart' as tf;
|
import 'package:tensorflow_models/tensorflow_models.dart' as tf;
|
||||||
|
|
||||||
part 'avatar_detector_event.dart';
|
part 'avatar_detector_event.dart';
|
||||||
@ -18,6 +19,16 @@ class AvatarDetectorBloc
|
|||||||
}
|
}
|
||||||
final AvatarDetectorRepository _avatarDetectorRepository;
|
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
|
@override
|
||||||
Future<void> close() {
|
Future<void> close() {
|
||||||
_avatarDetectorRepository.dispose();
|
_avatarDetectorRepository.dispose();
|
||||||
@ -37,6 +48,7 @@ class AvatarDetectorBloc
|
|||||||
emit(
|
emit(
|
||||||
state.copyWith(status: AvatarDetectorStatus.loaded),
|
state.copyWith(status: AvatarDetectorStatus.loaded),
|
||||||
);
|
);
|
||||||
|
_lastAvatarDetection = DateTime.now();
|
||||||
} on Exception catch (error, trace) {
|
} on Exception catch (error, trace) {
|
||||||
addError(error, trace);
|
addError(error, trace);
|
||||||
emit(
|
emit(
|
||||||
@ -61,9 +73,11 @@ class AvatarDetectorBloc
|
|||||||
try {
|
try {
|
||||||
final avatar = await _avatarDetectorRepository.detectAvatar(imageData);
|
final avatar = await _avatarDetectorRepository.detectAvatar(imageData);
|
||||||
if (avatar == null) {
|
if (avatar == null) {
|
||||||
emit(
|
if (DateTime.now().difference(_lastAvatarDetection) > undetectedDelay) {
|
||||||
state.copyWith(status: AvatarDetectorStatus.notDetected),
|
emit(
|
||||||
);
|
state.copyWith(status: AvatarDetectorStatus.notDetected),
|
||||||
|
);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
emit(
|
emit(
|
||||||
state.copyWith(
|
state.copyWith(
|
||||||
@ -71,6 +85,7 @@ class AvatarDetectorBloc
|
|||||||
avatar: avatar,
|
avatar: avatar,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
_lastAvatarDetection = DateTime.now();
|
||||||
}
|
}
|
||||||
} catch (error, stackTrace) {
|
} catch (error, stackTrace) {
|
||||||
addError(error, stackTrace);
|
addError(error, stackTrace);
|
||||||
|
@ -161,7 +161,46 @@ void main() {
|
|||||||
blocTest<AvatarDetectorBloc, AvatarDetectorState>(
|
blocTest<AvatarDetectorBloc, AvatarDetectorState>(
|
||||||
'emits [AvatarDetectorStatus.loading, AvatarDetectorStatus.loaded, '
|
'emits [AvatarDetectorStatus.loading, AvatarDetectorStatus.loaded, '
|
||||||
'AvatarDetectorStatus.estimating, AvatarDetectorStatus.notDetected] '
|
'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: () {
|
setUp: () {
|
||||||
when(
|
when(
|
||||||
() => avatarDetectorRepository.detectAvatar(any()),
|
() => avatarDetectorRepository.detectAvatar(any()),
|
||||||
@ -189,11 +228,6 @@ void main() {
|
|||||||
'status',
|
'status',
|
||||||
equals(AvatarDetectorStatus.estimating),
|
equals(AvatarDetectorStatus.estimating),
|
||||||
),
|
),
|
||||||
isInstanceOf<AvatarDetectorState>().having(
|
|
||||||
(state) => state.status,
|
|
||||||
'status',
|
|
||||||
equals(AvatarDetectorStatus.notDetected),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user