# zebra-browser-print-linux-ui

Native libadwaita UI for the [zebra-browser-print-linux](../zebra-browser-print-linux/) agent.

> Status: **0.4.0 — first working version of the Rust + libadwaita + Blueprint UI.**
> Tray icon, settings page (with autostart toggle), approved-origins
> page (revoke-per-row), printers page. Talks to the Go agent over
> session D-Bus. Flatpak manifest stub included; not yet on Flathub.

## Stack

This is the canonical 2026 GNOME-on-Fedora app stack:

- **GTK 4** + **libadwaita** (HIG widgets, adaptive layout, dark-mode aware)
- **Blueprint** (`.blp`) for declarative UI; compiled to GtkBuilder XML at build time
- **GResource** bundling of UI XML + icons (single binary, no asset paths to worry about)
- **GSettings** for window-state persistence (`com.unifiedretail.ZebraBrowserPrint` schema)
- **zbus** (sync façade) for D-Bus calls into the Go agent
- **ksni** for the StatusNotifierItem tray icon (KDE/GNOME/etc.)
- **Cargo** for Rust deps + build, **Meson** as the integration layer
- **Flatpak** target via `org.gnome.Sdk//47` + `rust-stable` SDK extension
- **AppStream metainfo** for GNOME Software / KDE Discover / Flathub

## Architecture

Two processes, one D-Bus interface:

```
┌─ zebra-browser-print-linux ─────────────────────────────┐
│ Go agent — HTTP/HTTPS listeners, USB I/O, allowlist     │
│ Exposes com.unifiedretail.ZebraBrowserPrint on session  │
│ D-Bus: ListOrigins, Approve, Revoke, ListPrinters,      │
│        GetAutostartState, SetAutostart, GetVersion      │
└───────────────────────────┬─────────────────────────────┘
                            │ session D-Bus (zbus)
                            │
┌───────────────────────────▼─────────────────────────────┐
│ zebra-browser-print-linux-ui (Rust + libadwaita)        │
│  ┌── tray icon (ksni) ──────────────────────┐           │
│  │    Open │ Quit                            │           │
│  └────────────────┬─────────────────────────┘           │
│                   │ TrayCommand mpsc::Sender             │
│                   │                                       │
│  ┌── AdwApplicationWindow ───────────────────┐           │
│  │  AdwViewStack:                             │           │
│  │   ├── Settings page (autostart toggle)     │           │
│  │   ├── Approved sites (per-row revoke)      │           │
│  │   └── Printers (read-only list)            │           │
│  └────────────────────────────────────────────┘           │
└──────────────────────────────────────────────────────────┘
```

Tray runs on its own dedicated OS thread (hosting a tokio
current-thread runtime — ksni 0.3 went async). The UI window runs
on GTK's main thread. They communicate via an `mpsc::Receiver`
that the GTK main loop drains every 100 ms via a GLib timeout.

D-Bus calls from the UI to the agent are **synchronous** — every
call is a single round-trip on loopback, well under a millisecond,
so we don't pay for an async runtime there.

## Build

### Quick (developer iteration)

```bash
sudo dnf install -y \
  rust cargo \
  gtk4-devel libadwaita-devel \
  blueprint-compiler \
  glib2-devel desktop-file-utils gettext

cargo build              # via build.rs: compiles .blp + .gresource
cargo run                # launch (needs the agent already running)
```

### Canonical (Meson + install)

```bash
sudo dnf install -y meson ninja-build appstream

meson setup _build --buildtype=release
meson compile -C _build
sudo meson install -C _build
```

After install:
- Binary at `/usr/local/bin/zebra-browser-print-linux-ui`
- `.desktop` entry at `/usr/local/share/applications/com.unifiedretail.ZebraBrowserPrint.desktop`
- Schema compiled into `/usr/local/share/glib-2.0/schemas/`
- Icons under `/usr/local/share/icons/hicolor/`
- Validates clean against `desktop-file-validate` and `appstreamcli validate`

### Flatpak

The manifest is at [`build-aux/flatpak/com.unifiedretail.ZebraBrowserPrint.json`](build-aux/flatpak/com.unifiedretail.ZebraBrowserPrint.json).

```bash
flatpak install --user flathub org.gnome.Sdk//47 \
                              org.gnome.Platform//47 \
                              org.freedesktop.Sdk.Extension.rust-stable//24.08

# One-time: vendor cargo deps for offline build (Flathub policy)
python3 build-aux/flatpak-cargo-generator.py Cargo.lock \
    > build-aux/flatpak/cargo-sources.json

flatpak-builder --user --install --force-clean build-flatpak \
    build-aux/flatpak/com.unifiedretail.ZebraBrowserPrint.json
```

## Running

The UI app expects the Go agent to be running (it talks to the
agent's D-Bus interface). The recommended setup is:

1. Install the Go agent + enable its systemd user unit
   (see [../zebra-browser-print-linux/](../zebra-browser-print-linux/)).
2. Install + launch this UI app.

Order of launch doesn't matter — if the UI starts first, it'll
show "Agent not running. Start: systemctl --user start ..." until
the agent comes up; refresh by closing/reopening the window.

The tray icon stays in your system tray after you close the
window. Right-click → Quit to exit.

## File layout

```
zebra-browser-print-linux-ui/
├── build.rs                    cargo build-script: blp → ui → gresource
├── Cargo.toml                  rust deps
├── meson.build                 top-level integration build
├── data/
│   ├── meson.build             desktop / metainfo / schema / icons install
│   ├── ui/                     .blp source for every window/page
│   ├── resources.gresource.xml manifest for the resource bundle
│   ├── *.gschema.xml           GSettings schema (window state)
│   ├── *.desktop.in.in         .desktop template (translatable)
│   ├── *.metainfo.xml.in.in    AppStream metainfo template
│   └── icons/
│       ├── scalable/apps/      full-colour app icon (SVG)
│       └── symbolic/apps/      symbolic / monochrome (SVG)
├── src/
│   ├── main.rs                 entry point
│   ├── application.rs          AdwApplication subclass
│   ├── window.rs               main window
│   ├── settings.rs             settings page
│   ├── origins.rs              approved-origins page
│   ├── printers.rs             connected-printers page
│   ├── tray.rs                 SNI tray icon
│   └── dbus.rs                 zbus client to the agent
├── po/                         (gettext stub, English-only at v0.4)
├── build-aux/flatpak/          Flathub manifest
├── LICENSE
└── README.md
```

## Roadmap

- [x] System tray + main window + 3 pages + autostart toggle
- [x] D-Bus client to Go agent
- [x] Blueprint + GResource + Meson + AppStream + Flatpak manifest
- [ ] **Native approval prompt** — replace the agent's HTML
  approval flow with a libadwaita `AdwAlertDialog` triggered by a
  D-Bus signal from the agent
- [ ] **Per-printer label-type assignment** — pair the printers
  page with the BC2 backend's `PrinterCalibration` so operators
  can map "transparency labels → printer X"
- [ ] **Toasts** — surface revoke / autostart errors via
  AdwToastOverlay instead of just stderr
- [ ] **Localisation** — wire gettext, extract strings, ship
  translations for at least en/es/fr
- [ ] **CI** — GitHub Actions matrix building Fedora + Ubuntu +
  Flathub artefacts on every PR
- [ ] **Accessibility audit** — Orca screen reader pass

## License

MIT — see [LICENSE](LICENSE).
