Skip to content

Commit

Permalink
fix(core/ui): draw hold-to-confirm loader over dialog title
Browse files Browse the repository at this point in the history
[no changelog]
  • Loading branch information
mmilata committed Sep 29, 2023
1 parent 6069120 commit aa6574e
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 20 deletions.
11 changes: 11 additions & 0 deletions core/embed/rust/src/ui/component/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,7 @@ pub struct EventCtx {
paint_requested: bool,
anim_frame_scheduled: bool,
page_count: Option<usize>,
root_repaint_requested: bool,
}

impl EventCtx {
Expand All @@ -421,6 +422,7 @@ impl EventCtx {
* `Child::marked_for_paint` being true. */
anim_frame_scheduled: false,
page_count: None,
root_repaint_requested: false,
}
}

Expand Down Expand Up @@ -459,6 +461,14 @@ impl EventCtx {
}
}

pub fn request_repaint_root(&mut self) {
self.root_repaint_requested = true;
}

pub fn needs_repaint_root(&self) -> bool {
self.root_repaint_requested
}

pub fn set_page_count(&mut self, count: usize) {
#[cfg(feature = "ui_debug")]
assert!(self.page_count.is_none());
Expand All @@ -478,6 +488,7 @@ impl EventCtx {
self.paint_requested = false;
self.anim_frame_scheduled = false;
self.page_count = None;
self.root_repaint_requested = false;
}

fn register_timer(&mut self, token: TimerToken, deadline: Duration) {
Expand Down
23 changes: 20 additions & 3 deletions core/embed/rust/src/ui/layout/obj.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,9 +158,6 @@ impl LayoutObj {
// SAFETY: `inner.root` is unique because of the `inner.borrow_mut()`.
let msg = unsafe { Gc::as_mut(&mut inner.root) }.obj_event(&mut inner.event_ctx, event)?;

// All concerning `Child` wrappers should have already marked themselves for
// painting by now, and we're prepared for a paint pass.

// Drain any pending timers into the callback.
while let Some((token, deadline)) = inner.event_ctx.pop_timer() {
let token = token.try_into();
Expand All @@ -176,9 +173,28 @@ impl LayoutObj {
inner.page_count = count as u16;
}

// Mark whole component tree for repaint if requested by inner component.
if inner.event_ctx.needs_repaint_root() {
inner.event_ctx.clear();
// SAFETY: `inner.root` is unique because of the `inner.borrow_mut()`.
let paint_msg = unsafe { Gc::as_mut(&mut inner.root) }
.obj_event(&mut inner.event_ctx, Event::RequestPaint)?;
assert!(paint_msg == Obj::const_none());
unsafe { Gc::as_mut(&mut inner.root) }.obj_request_clear();
}

// All concerning `Child` wrappers should have already marked themselves for
// painting by now, and we're prepared for a paint pass.

Ok(msg)
}

fn obj_request_clear(&self) {
let mut inner = self.inner.borrow_mut();
// SAFETY: `inner.root` is unique because of the `inner.borrow_mut()`.
unsafe { Gc::as_mut(&mut inner.root) }.obj_request_clear();
}

/// Run a paint pass over the component tree. Returns true if any component
/// actually requested painting since last invocation of the function.
fn obj_paint_if_requested(&self) -> bool {
Expand Down Expand Up @@ -432,6 +448,7 @@ extern "C" fn ui_layout_request_complete_repaint(this: Obj) -> Obj {
#[cfg(feature = "ui_debug")]
panic!("cannot raise messages during RequestPaint");
};
this.obj_request_clear();
Ok(Obj::const_none())
};
unsafe { util::try_or_raise(block) }
Expand Down
26 changes: 14 additions & 12 deletions core/embed/rust/src/ui/model_tt/component/loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::{
time::{Duration, Instant},
ui::{
animation::Animation,
component::{Component, Event, EventCtx},
component::{Component, Event, EventCtx, Pad},
display::{self, toif::Icon, Color},
geometry::{Offset, Rect},
model_tt::constant,
Expand All @@ -27,7 +27,7 @@ enum State {
}

pub struct Loader {
offset_y: i16,
pub pad: Pad,
state: State,
growing_duration: Duration,
shrinking_duration: Duration,
Expand All @@ -38,12 +38,13 @@ impl Loader {
pub const SIZE: Offset = Offset::new(120, 120);

pub fn new() -> Self {
let styles = theme::loader_default();
Self {
offset_y: 0,
pad: Pad::with_background(styles.normal.background_color),
state: State::Initial,
growing_duration: Duration::from_millis(GROWING_DURATION_MS),
shrinking_duration: Duration::from_millis(SHRINKING_DURATION_MS),
styles: theme::loader_default(),
styles,
}
}

Expand Down Expand Up @@ -130,13 +131,8 @@ impl Component for Loader {
type Msg = LoaderMsg;

fn place(&mut self, bounds: Rect) -> Rect {
// Current loader API only takes Y-offset relative to screen center, which we
// compute from the bounds center point.
// NOTE: SwipeHoldPage relies on Loader being X-centered regardless of bounds.
// If this changes then SwipeHoldPage needs to be changed too.
let screen_center = constant::screen().center();
self.offset_y = bounds.center().y - screen_center.y;
Rect::from_center_and_size(screen_center + Offset::y(self.offset_y), Self::SIZE)
self.pad.place(bounds);
Rect::from_center_and_size(bounds.center(), Self::SIZE)
}

fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<Self::Msg> {
Expand Down Expand Up @@ -177,9 +173,15 @@ impl Component for Loader {
self.styles.active
};

// Current loader API only takes Y-offset relative to screen center, which we
// compute from the bounds center point.
let screen_center = constant::screen().center();
let offset_y = self.pad.area.center().y - screen_center.y;

self.pad.paint();
display::loader(
progress,
self.offset_y,
offset_y,
style.loader_color,
style.background_color,
style.icon,
Expand Down
18 changes: 13 additions & 5 deletions core/embed/rust/src/ui/model_tt/component/page.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use crate::{
time::Instant,
ui::{
component::{paginated::PageMsg, Component, ComponentExt, Event, EventCtx, Pad, Paginate},
constant,
display::{self, Color},
geometry::{Insets, Rect},
util::animation_disabled,
Expand Down Expand Up @@ -157,6 +158,14 @@ where
self.cancel_from_any_page || !self.scrollbar.has_previous_page()
}

/// Area for drawing loader (and black rectangle behind it). Can be outside
/// bounds as we repaint entire UI tree after hiding the loader.
const fn loader_area() -> Rect {
constant::screen()
.inset(theme::borders())
.inset(Insets::bottom(theme::BUTTON_HEIGHT + theme::BUTTON_SPACING))
}

fn handle_swipe(
&mut self,
ctx: &mut EventCtx,
Expand Down Expand Up @@ -229,20 +238,20 @@ where
let now = Instant::now();

if let Some(LoaderMsg::ShrunkCompletely) = loader.event(ctx, event) {
// Clear the remnants of the loader.
self.pad.clear();
// Switch it to the initial state, so we stop painting it.
loader.reset();
// Re-draw the whole content tree.
self.content.request_complete_repaint(ctx);
// Loader overpainted our bounds, repaint entire screen from scratch.
ctx.request_repaint_root()
// This can be a result of an animation frame event, we should take
// care to not short-circuit here and deliver the event to the
// content as well.
}
match button_msg {
Some(ButtonMsg::Pressed) => {
loader.start_growing(ctx, now);
self.pad.clear(); // Clear the remnants of the content.
loader.pad.clear(); // Clear the remnants of the content.
}
Some(ButtonMsg::Released) => {
loader.start_shrinking(ctx, now);
Expand Down Expand Up @@ -316,8 +325,7 @@ where
self.scrollbar.set_count_and_active_page(page_count, 0);
self.setup_swipe();

let content_area = layout.content_single_page.union(layout.scrollbar);
self.loader.place(content_area);
self.loader.place(Self::loader_area());
bounds
}

Expand Down

0 comments on commit aa6574e

Please sign in to comment.