diff --git a/ui/rgb/src/lib.rs b/ui/rgb/src/lib.rs index ef12574e..d32ec261 100644 --- a/ui/rgb/src/lib.rs +++ b/ui/rgb/src/lib.rs @@ -136,6 +136,8 @@ impl Argb { pub const DIAMOND_CONE_AMBER: Argb = Argb(Some(Self::DIMMING_MAX_VALUE), 25, 18, 1); /// Error color for outer ring pub const DIAMOND_RING_ERROR_SALMON: Argb = Argb(Some(8), 127, 20, 0); + /// Error color for inner ring (shroud) + pub const DIAMOND_CENTER_ERROR_SALMON: Argb = Argb(Some(6), 255, 20, 0); /// QR Phase colors - diamond pub const DIAMOND_CENTER_WIFI_QR_SCAN: Argb = Self::DIAMOND_CENTER_USER_QR_SCAN; diff --git a/ui/src/engine/diamond.rs b/ui/src/engine/diamond.rs index 72bce29f..59813c9f 100644 --- a/ui/src/engine/diamond.rs +++ b/ui/src/engine/diamond.rs @@ -694,97 +694,6 @@ impl EventHandler for Runner { } } } - Event::BiometricCaptureFakeProgressStart { - timeout, - min_fast_forward_duration, - max_fast_forward_duration, - } => { - self.set_center( - LEVEL_FOREGROUND, - animations::Static::::new( - Argb::DIAMOND_CENTER_BIOMETRIC_CAPTURE_PROGRESS, - None, - ), - ); - self.set_ring( - LEVEL_NOTICE, - animations::fake_progress_v2::FakeProgress::::new( - Argb::DIAMOND_RING_BIOMETRIC_CAPTURE_PROGRESS, - *timeout, - *min_fast_forward_duration, - *max_fast_forward_duration, - ), - ); - } - Event::BiometricCaputreSuccessAndFastForwardFakeProgress => { - let ring_completion_time = self - .ring_animations_stack - .stack - .get_mut(&LEVEL_NOTICE) - .and_then(|RunningAnimation { animation, .. }| { - animation - .as_any_mut() - .downcast_mut::>() - }) - .map(|fake_progress| fake_progress.set_completed()) - .unwrap_or_default() - .as_secs_f64(); - - let mut total_duration = 0.0; - while let Some(melody) = self.capture_sound.peekable().peek() { - let melody = sound::Type::Melody(*melody); - let melody_duration = - self.sound.get_duration(melody).unwrap().as_secs_f64(); - if total_duration + melody_duration < ring_completion_time { - self.sound.queue(melody, Duration::ZERO)?; - self.capture_sound.next(); - total_duration += melody_duration; - } else { - break; - } - } - - // Sync biometric capture success animation + sounds, with the fake progress. - // Since the ring is ON after the fake progress, we turn it off smoothly in `fade_out_duration`, - // and then we do a double blink after `success_delay`. - let fade_out_duration = 0.3; - let success_delay = 0.4; - self.sound.queue( - sound::Type::Melody(sound::Melody::IrisScanSuccess), - Duration::from_millis( - ((ring_completion_time + fade_out_duration + success_delay) - * 1000.0) as u64, - ), - )?; - self.set_center( - LEVEL_FOREGROUND, - animations::alert_v2::Alert::::new( - Argb::DIAMOND_CENTER_BIOMETRIC_CAPTURE_PROGRESS, - SquarePulseTrain::from(vec![ - (0.0, 0.0), - (fade_out_duration + success_delay + 1.1, 3.4), - ]), - )? - .with_delay(ring_completion_time), - ); - self.set_ring( - LEVEL_FOREGROUND, - animations::alert_v2::Alert::::new( - Argb::DIAMOND_RING_BIOMETRIC_CAPTURE_SUCCESS, - SquarePulseTrain::from(vec![ - (0.0, 0.0), - (0.0, fade_out_duration), - (fade_out_duration + success_delay, 0.1), - (fade_out_duration + success_delay + 0.5, 0.1), - (fade_out_duration + success_delay + 1.0, 0.1), - (fade_out_duration + success_delay + 1.1, 3.5), - ]), - )? - .with_delay(ring_completion_time), - ); - } Event::BiometricCaptureProgressWithNotch { progress } => { // set progress but wait for wave to finish breathing let breathing = self @@ -934,6 +843,15 @@ impl EventHandler for Runner { } } } + // clears any stale state from PreflightCheckErrorNotification + self.set_center( + LEVEL_NOTICE, + animations::Static::new( + Argb::DIAMOND_CENTER_BIOMETRIC_CAPTURE_PROGRESS, + None, + ) + .fade_in(0.5), + ); } Event::BiometricFlowResult { is_success } => { if let Some(biometric_flow) = self @@ -975,6 +893,52 @@ impl EventHandler for Runner { } } + Event::PreflightCheckErrorNotification { set } => { + if self + .center_animations_stack + .stack + .get_mut(&LEVEL_NOTICE) + .and_then(|RunningAnimation { animation, .. }| { + animation + .as_any_mut() + .downcast_mut::>() + }) + .is_some() + { + if !*set { + self.set_center( + LEVEL_NOTICE, + animations::Static::new( + Argb::DIAMOND_CENTER_BIOMETRIC_CAPTURE_PROGRESS, + None, + ) + .fade_in(0.5), + ); + } else if *set { + self.set_center( + LEVEL_NOTICE, + animations::Static::new( + Argb::DIAMOND_CENTER_ERROR_SALMON, + None, + ) + .fade_in(0.5), + ); + } + } else { + if *set { + self.set_center( + LEVEL_NOTICE, + animations::sine_blend::SineBlend::::new( + Argb::DIAMOND_CENTER_USER_QR_SCAN_SUCCESS_BREATHING_LOW, + Argb::DIAMOND_CENTER_ERROR_SALMON, + 2.0, + 0.0, + )); + } + } + } Event::BiometricCaptureSuccess => { self.biometric_capture_success()?; } diff --git a/ui/src/engine/mod.rs b/ui/src/engine/mod.rs index 34df4caa..af899904 100644 --- a/ui/src/engine/mod.rs +++ b/ui/src/engine/mod.rs @@ -275,13 +275,6 @@ event_enum! { BiometricCaptureProgress { progress: f64, }, - /// Biometric capture start fake progress. - #[event_enum(method = biometric_capture_fake_progress_start)] - BiometricCaptureFakeProgressStart { - timeout: Duration, - min_fast_forward_duration: Duration, - max_fast_forward_duration: Duration, - }, /// Biometric flow start. #[event_enum(method = biometric_flow_start)] BiometricFlowStart { @@ -297,9 +290,11 @@ event_enum! { BiometricFlowResult { is_success: bool, }, - /// Biometric capture has finished successfully, command fake-progress to fast-forward - #[event_enum(method = biometric_capture_success_and_fast_forward_fake_progress)] - BiometricCaputreSuccessAndFastForwardFakeProgress, + /// Preflight check error notification. + #[event_enum(method = preflight_check_error_notification)] + PreflightCheckErrorNotification { + set: bool, + }, #[event_enum(method = biometric_capture_progress_with_notch)] BiometricCaptureProgressWithNotch { progress: f64, diff --git a/ui/src/engine/pearl/self_serve.rs b/ui/src/engine/pearl/self_serve.rs index 6a485b03..8ba4e3d3 100644 --- a/ui/src/engine/pearl/self_serve.rs +++ b/ui/src/engine/pearl/self_serve.rs @@ -385,21 +385,6 @@ impl Runner { } } } - Event::BiometricCaptureFakeProgressStart { - timeout, - min_fast_forward_duration, - max_fast_forward_duration, - } => { - self.set_ring( - LEVEL_NOTICE, - animations::fake_progress_v2::FakeProgress::::new( - Argb::PEARL_RING_USER_CAPTURE, - *timeout, - *min_fast_forward_duration, - *max_fast_forward_duration, - ), - ); - } Event::BiometricFlowStart { timeout, min_fast_forward_duration, @@ -420,6 +405,7 @@ impl Runner { ); self.stop_ring(LEVEL_FOREGROUND, Transition::ForceStop); self.stop_ring(LEVEL_BACKGROUND, Transition::ForceStop); + self.set_center(LEVEL_NOTICE, animations::Static::new(Argb::OFF, None)); } Event::BiometricFlowProgressFastForward => { if let Some(biometric_flow) = self @@ -447,6 +433,7 @@ impl Runner { } } } + self.stop_center(LEVEL_NOTICE, Transition::FadeOut(0.5)); } Event::BiometricFlowResult { is_success } => { if let Some(biometric_flow) = self @@ -488,83 +475,35 @@ impl Runner { } } - Event::BiometricCaputreSuccessAndFastForwardFakeProgress => { - let ring_completion_time = self - .ring_animations_stack + Event::PreflightCheckErrorNotification { set } => { + if let Some(animation) = self + .center_animations_stack .stack .get_mut(&LEVEL_NOTICE) .and_then(|RunningAnimation { animation, .. }| { animation .as_any_mut() - .downcast_mut::>() + .downcast_mut::>( + ) }) - .map(|fake_progress| fake_progress.set_completed()) - .unwrap_or_default() - .as_secs_f64(); - - let mut total_duration = 0.0; - while let Some(melody) = self.capture_sound.peekable().peek() { - let melody = sound::Type::Melody(*melody); - let melody_duration = - self.sound.get_duration(melody).unwrap().as_secs_f64(); - if total_duration + melody_duration < ring_completion_time { - self.sound.queue(melody, Duration::ZERO)?; - self.capture_sound.next(); - total_duration += melody_duration; - } else { - break; + { + let is_on = animation.color() != Argb::OFF; + if is_on && !*set { + self.set_center( + LEVEL_NOTICE, + animations::Static::new(Argb::OFF, None).fade_in(0.5), + ); + } else if !is_on && *set { + self.set_center( + LEVEL_NOTICE, + animations::Static::new( + Argb::PEARL_RING_ERROR_SALMON, + None, + ) + .fade_in(0.5), + ); } } - // Sync biometric capture success animation + sounds, with the fake progress. - // Since the ring is ON after the fake progress, we turn it off smoothly in `fade_out_duration`, - // and then we do a double blink after `success_delay`. - let fade_out_duration = 0.3; - let success_delay = 0.4; - self.sound.queue( - sound::Type::Melody(sound::Melody::IrisScanSuccess), - Duration::from_millis( - ((ring_completion_time + fade_out_duration + success_delay) - * 1000.0) as u64, - ), - )?; - self.stop_center( - LEVEL_FOREGROUND, - Transition::FadeOut(ring_completion_time), - ); - // in case nothing is running on center, make sure we set the background to off - self.set_center( - LEVEL_BACKGROUND, - animations::Static::::new(Argb::OFF, None), - ); - self.set_center( - LEVEL_FOREGROUND, - animations::alert_v2::Alert::::new( - Argb::PEARL_CENTER_CAPTURE_SUCCESS, - SquarePulseTrain::from(vec![ - (fade_out_duration + success_delay, 1.1), - (fade_out_duration + success_delay + 1.1, 3.4), - ]), - )? - .with_delay(ring_completion_time), - ); - self.set_ring( - LEVEL_FOREGROUND, - animations::alert_v2::Alert::::new( - Argb::PEARL_RING_CAPTURE_SUCCESS, - SquarePulseTrain::from(vec![ - (0.0, 0.0), - (0.0, fade_out_duration), - (fade_out_duration + success_delay, 0.1), - (fade_out_duration + success_delay + 0.5, 0.1), - (fade_out_duration + success_delay + 1.0, 0.1), - (fade_out_duration + success_delay + 1.1, 3.5), - ]), - )? - .with_delay(ring_completion_time), - ); - self.operator_signup_phase.iris_scan_complete(); } Event::BiometricCaptureProgressWithNotch { progress } => { // set progress but wait for wave to finish breathing