feat(gui): KeysPage scaffold + tokio runtime in main, gtk::Box layout

KeysPage::new spawns the connect-and-render flow on glib::MainContext::
spawn_local. On success it shows a placeholder PreferencesPage (Task 5
fills in the list); on failure it shows StatusPage with a Retry button
that re-runs the connect attempt.

main.rs installs the multi-thread tokio runtime guard before app.run()
so zbus's tokio futures execute correctly when polled by glib.

Layout deviation from plan: ToolbarView is libadwaita v1_4-gated; the
project sticks with gtk::Box vertical for portability (commit c6a5e94
established this pattern).
This commit is contained in:
michael
2026-04-27 09:20:31 -07:00
parent d07d3469fe
commit 5d6b7ceeb0
2 changed files with 109 additions and 6 deletions

View File

@@ -3,24 +3,48 @@ use gtk::glib;
mod bus;
mod error;
mod keys_page;
const APP_ID: &str = "io.dangerousthings.AuthForge";
fn main() -> glib::ExitCode {
// Multi-thread tokio runtime hosts zbus's tokio-flavored futures. The
// `_guard` keeps the runtime context active on this thread so calls like
// `zbus::Connection::system().await` from within `glib::MainContext::
// spawn_local` closures don't panic with "no current reactor".
let runtime = tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build()
.expect("build tokio runtime");
let _guard = runtime.enter();
let app = adw::Application::builder().application_id(APP_ID).build();
app.connect_activate(|app| {
let status = adw::StatusPage::builder()
.icon_name("dialog-password-symbolic")
.title("Authentication setup")
.description("Phase 0 placeholder. Real UI in Phase 8.")
.build();
let win = adw::ApplicationWindow::builder()
.application(app)
.default_width(720)
.default_height(540)
.title("Authentication")
.content(&status)
.build();
let header = adw::HeaderBar::new();
let stack = adw::ViewStack::new();
let switcher = adw::ViewSwitcher::builder()
.stack(&stack)
.policy(adw::ViewSwitcherPolicy::Wide)
.build();
header.set_title_widget(Some(&switcher));
let keys = keys_page::KeysPage::new(win.clone().upcast());
stack.add_titled(&keys.root, Some("keys"), "Keys");
// ToolbarView is libadwaita v1_4-gated; the project sticks with the
// simpler Box layout for portability (see commit c6a5e94).
let layout = gtk::Box::new(gtk::Orientation::Vertical, 0);
layout.append(&header);
layout.append(&stack);
stack.set_vexpand(true);
win.set_content(Some(&layout));
win.present();
});
app.run()