feat(gui): TouchDialog modal racing EnrollOwn against EnrollmentFailed signal

Adds enroll_dialog::present which opens an adw::AlertDialog with a spinner
and races the EnrollOwn call against the EnrollmentFailed signal stream:
- Call returns Ok(_cred) -> close dialog, fire on_success refresh callback.
- Call returns Err -> swap dialog body to the user-message form.
- Signal arrives first -> swap to the signal payload (faster than waiting
  for the call's typed Err to traverse the bus).

KeysPage::start_enroll wires the activated row to present(), passing the
parent window for modal anchoring and a refresh closure as on_success.

Plan deviation: AlertDialog is libadwaita v1_5-gated, so gui/Cargo.toml
enables that feature. Targets Ubuntu 24.04+ (libadwaita 1.5).
This commit is contained in:
michael
2026-04-27 09:24:50 -07:00
parent f11047fbcb
commit 3fbd872a9c
4 changed files with 92 additions and 5 deletions

View File

@@ -11,7 +11,6 @@ use std::rc::Rc;
pub(crate) struct KeysPage {
pub root: adw::Bin,
daemon: Rc<RefCell<Option<Daemon>>>,
#[allow(dead_code)] // wired through enroll_dialog in Task 6.
parent_window: gtk::Window,
}
@@ -152,9 +151,17 @@ impl KeysPage {
}
async fn start_enroll(self: &Rc<Self>) {
// Stub until Task 6 lands the TouchDialog. Until then, surface the
// intent so manual smoke can see the click was registered.
self.show_toast("Enroll: implemented in Task 6");
let daemon = match self.daemon.borrow().clone() {
Some(d) => d,
None => return,
};
let me = self.clone();
crate::enroll_dialog::present(&self.parent_window, daemon, move || {
let me = me.clone();
glib::MainContext::default().spawn_local(async move {
me.render_connected().await;
});
});
}
fn show_toast(self: &Rc<Self>, msg: &str) {