Skip to content

Commit

Permalink
Merge pull request betrusted-io#277 from gsora/feat/slider-widget
Browse files Browse the repository at this point in the history
feat: user interaction-enabled slider
  • Loading branch information
bunnie authored Nov 16, 2022
2 parents 08de49d + d57088a commit 1106fcf
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 3 deletions.
8 changes: 8 additions & 0 deletions services/gam/src/modal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,14 @@ impl TextEntryPayload {
}
}

#[derive(Debug, Copy, Clone, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
pub struct SliderPayload(pub u32);
impl SliderPayload {
pub fn new(value: u32) -> Self {
SliderPayload(value)
}
}

#[derive(Debug, Copy, Clone, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
pub struct RadioButtonPayload(pub ItemName); // returns the name of the item corresponding to the radio button selection
impl RadioButtonPayload {
Expand Down
12 changes: 10 additions & 2 deletions services/gam/src/modal/slider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ impl Slider {
show_legend,
}
}

pub fn set_is_progressbar(&mut self, setting: bool) {
self.is_progressbar = setting;
}

pub fn set_is_password(&mut self, setting: bool) {
// this will cause text to be inverted. Untrusted entities can try to set this,
// but the GAM should defeat this for dialog boxes outside of the trusted boot
Expand Down Expand Up @@ -194,8 +199,11 @@ impl ActionApi for Slider {
gam.relinquish_focus().unwrap();
xous::yield_slice();

send_message(self.action_conn,
xous::Message::new_scalar(self.action_opcode as usize, self.action_payload as usize, 0, 0, 0)).expect("couldn't pass on action payload");
let ret_payload = SliderPayload(self.action_payload);

let buf = Buffer::into_buf(ret_payload).expect("couldn't convert message to payload");
buf.send(self.action_conn, self.action_opcode).map(|_| ()).expect("couldn't send action message");

return None;
}
_ => {
Expand Down
4 changes: 4 additions & 0 deletions services/modals/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ pub struct ManagedProgress {
pub end_work: u32,
/// current quanta of work. Used to int the bar, updates are just a scalar with the same value.
pub current_work: u32,
/// can user interact with it?
pub user_interaction: bool,
}

/// This isn't a terribly useful notification -- it's basically read-only, no interactivity,
Expand Down Expand Up @@ -98,6 +100,8 @@ pub(crate) enum Opcode {
Bip39 = 31, // ---- note op number
Bip39Input = 32, // ----- note op number
Bip39Return = 33, // ----- note op number
SliderReturn = 34,
Slider = 35,
/// display an image
#[cfg(feature = "ditherpunk")]
Image = 3,
Expand Down
27 changes: 27 additions & 0 deletions services/modals/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -302,13 +302,40 @@ impl Modals {
start_work: start,
end_work: end,
current_work: current,
user_interaction: false,
};
let buf = Buffer::into_buf(spec).or(Err(xous::Error::InternalError))?;
buf.lend(self.conn, Opcode::StartProgress.to_u32().unwrap())
.or(Err(xous::Error::InternalError))?;
Ok(())
}

pub fn slider(
&self,
title: &str,
start: u32,
end: u32,
current: u32,
) -> Result<u32, xous::Error> {
self.lock();
let spec = ManagedProgress {
token: self.token,
title: xous_ipc::String::from_str(title),
start_work: start,
end_work: end,
current_work: current,
user_interaction: true,
};
let mut buf = Buffer::into_buf(spec).or(Err(xous::Error::InternalError))?;
buf.lend_mut(self.conn, Opcode::Slider.to_u32().unwrap())
.or(Err(xous::Error::InternalError))?;

let orig = buf.to_original::<SliderPayload, _>().unwrap();

self.unlock();
Ok(orig.0)
}

/// note that this API is not atomically token-locked, so, someone could mess with the progress bar state
/// but, progress updates are meant to be fast and frequent, and generally if a progress bar shows
/// something whacky it's not going to affect a security outcome
Expand Down
48 changes: 47 additions & 1 deletion services/modals/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ fn wrapped_main() -> ! {
let mut fixed_items = Vec::<ItemName>::new();
let mut progress_action = Slider::new(
renderer_cid,
Opcode::Gutter.to_u32().unwrap(),
Opcode::SliderReturn.to_u32().unwrap(),
0,
100,
1,
Expand Down Expand Up @@ -332,6 +332,24 @@ fn wrapped_main() -> ! {
)
.expect("couldn't initiate UX op");
}
Some(Opcode::Slider) => {
let spec = {
let buffer =
unsafe { Buffer::from_memory_message_mut(msg.body.memory_message_mut().unwrap()) };
buffer.to_original::<ManagedProgress, _>().unwrap()
};
if spec.token != token_lock.unwrap_or(default_nonce) {
log::warn!("Attempt to access modals without a mutex lock. Ignoring.");
continue;
}
op = RendererState::RunProgress(spec);
dr = Some(msg);
send_message(
renderer_cid,
Message::new_scalar(Opcode::InitiateOp.to_usize().unwrap(), 0, 0, 0, 0),
)
.expect("couldn't initiate UX op");
}
Some(Opcode::StopProgress) => msg_blocking_scalar_unpack!(msg, t0, t1, t2, t3, {
let token = [t0 as u32, t1 as u32, t2 as u32, t3 as u32];
if token != token_lock.unwrap_or(default_nonce) {
Expand Down Expand Up @@ -593,6 +611,7 @@ fn wrapped_main() -> ! {
end_work
);
progress_action.set_state(last_percentage);
progress_action.set_is_progressbar(!config.user_interaction);
#[cfg(feature = "tts")]
tts.tts_simple(config.title.as_str().unwrap()).unwrap();
renderer_modal.modify(
Expand All @@ -603,6 +622,7 @@ fn wrapped_main() -> ! {
true,
Some(DEFAULT_STYLE),
);

renderer_modal.activate();
}
RendererState::RunRadio(config) => {
Expand Down Expand Up @@ -764,6 +784,32 @@ fn wrapped_main() -> ! {
xous::return_scalar2(sender, 1, k).unwrap();
}
}),
Some(Opcode::SliderReturn) => match op {
RendererState::RunProgress(_) => {
let buffer =
unsafe { Buffer::from_memory_message(msg.body.memory_message().unwrap()) };
let item = buffer.to_original::<SliderPayload, _>().unwrap();

if let Some(mut origin) = dr.take() {
let mut response = unsafe {
Buffer::from_memory_message_mut(
origin.body.memory_message_mut().unwrap(),
)
};

response.replace(item).unwrap();
op = RendererState::None;

token_lock = next_lock(&mut work_queue);
} else {
log::error!("Ux routine returned but no origin was recorded");
panic!("Ux routine returned but no origin was recorded");
}
},
_ => {
log::warn!("got weird stuff on slider return, ignoring");
}
},
Some(Opcode::TextEntryReturn) => match op {
RendererState::RunText(_config) => {
log::trace!("validating text entry modal");
Expand Down
17 changes: 17 additions & 0 deletions services/modals/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,20 @@ pub fn spawn_test() {
}
Err(e) => log::error!("couldn't get input: {:?}", e),
}

// 6. human interaction-enabled slider
log::info!("testing human interaction-enabled slider");
let result = modals.slider(
"Human interaction-enabled slider!",
0,
100,
50,
).expect("slider test failed");

modals.show_notification(&format!("Slider value: {}", result), None)
.expect("cannot show slider result notification");

log::info!("slider test done");
}
});

Expand Down Expand Up @@ -165,6 +179,9 @@ pub fn spawn_test() {
modals.show_image(bm).expect("show image modal failed");
log::info!("image modal test done");
}

// 6. test that human-interactable slider modal
log::info!("testing human interaction-enabled modal");
}
});
}
Expand Down

0 comments on commit 1106fcf

Please sign in to comment.