feat(client/linux): settings revamp on the Apple category map + parity pieces
apple / swift (push) Successful in 1m19s
apple / screenshots (push) Successful in 6m23s
ci / web (push) Successful in 45s
ci / docs-site (push) Successful in 50s
ci / bench (push) Successful in 7m5s
decky / build-publish (push) Successful in 20s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 10s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 10s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 11s
docker / build-push (ci, ci/rust-ci-noble.Dockerfile, punktfunk-rust-ci-noble) (push) Successful in 10s
arch / build-publish (push) Successful in 12m23s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 11s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 1m4s
android / android (push) Successful in 17m51s
deb / build-publish (push) Successful in 12m9s
flatpak / build-publish (push) Successful in 7m3s
deb / build-publish-host (push) Successful in 12m19s
windows-msix / package (arm64, C:\Users\Public\ffmpeg-arm64, --no-default-features, aarch64-pc-windows-msvc, C:\t-a64) (push) Failing after 5m18s
ci / rust (push) Successful in 26m40s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 16m3s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 15m49s
windows-msix / package (x64, C:\Users\Public\ffmpeg, , x86_64-pc-windows-msvc, C:\t) (push) Failing after 6m11s
docker / deploy-docs (push) Successful in 25s
windows / build (aarch64-pc-windows-msvc) (push) Failing after 5m34s
windows / build (x86_64-pc-windows-msvc) (push) Successful in 8m58s
apple / swift (push) Successful in 1m19s
apple / screenshots (push) Successful in 6m23s
ci / web (push) Successful in 45s
ci / docs-site (push) Successful in 50s
ci / bench (push) Successful in 7m5s
decky / build-publish (push) Successful in 20s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 10s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 10s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 11s
docker / build-push (ci, ci/rust-ci-noble.Dockerfile, punktfunk-rust-ci-noble) (push) Successful in 10s
arch / build-publish (push) Successful in 12m23s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 11s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 1m4s
android / android (push) Successful in 17m51s
deb / build-publish (push) Successful in 12m9s
flatpak / build-publish (push) Successful in 7m3s
deb / build-publish-host (push) Successful in 12m19s
windows-msix / package (arm64, C:\Users\Public\ffmpeg-arm64, --no-default-features, aarch64-pc-windows-msvc, C:\t-a64) (push) Failing after 5m18s
ci / rust (push) Successful in 26m40s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 16m3s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 15m49s
windows-msix / package (x64, C:\Users\Public\ffmpeg, , x86_64-pc-windows-msvc, C:\t) (push) Failing after 6m11s
docker / deploy-docs (push) Successful in 25s
windows / build (aarch64-pc-windows-msvc) (push) Failing after 5m34s
windows / build (x86_64-pc-windows-msvc) (push) Successful in 8m58s
One page of everything becomes the cross-client map (the Apple 2026-07 revamp, same shape the Windows client just adopted): General / Display / Input / Audio / Controllers pages with per-field captions, dynamic where the meaning depends on the selection (touch mode, resolution, codec). About stays in the primary menu per GNOME convention; settings search is on. Combo-row captions are deliberately ONE line — a wrapped subtitle's natural width crushes the selected-value label into an ellipsis. New controls, all with existing plumbing: 10-bit HDR (hdr_enabled was advertised but had no UI), PyroWave in the codec picker (preference-only, Linux decodes it), a detected-controllers list, auto-wake on connect — gated at the AppMsg::WakeConnect entry (off: no packet, no wake-and-wait fallback; the card menu's explicit Wake stays), invert scroll (session plumbing landed with the Windows parity series), and the GPU + audio endpoint pickers, fed by a startup worker-thread probe (AppModel::probes) and hidden while empty. The screenshot harness gains PUNKTFUNK_SHOT_SETTINGS_PAGE to open the capture on a specific page. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -55,6 +55,11 @@ pub struct AppModel {
|
||||
/// App-lifetime SDL gamepad service (Settings' controller list + pinning). Streams
|
||||
/// run in the session binary, which has its own.
|
||||
pub gamepad: crate::gamepad::GamepadService,
|
||||
/// Device lists for the settings pickers (GPUs via `punktfunk-session
|
||||
/// --list-adapters` — the shell deliberately links no Vulkan itself — and audio
|
||||
/// endpoints via the PipeWire registry), probed once at startup on a worker thread.
|
||||
/// Empty until the probe lands — empty lists simply hide their pickers.
|
||||
pub probes: Rc<RefCell<crate::ui_settings::DeviceProbes>>,
|
||||
hosts: Controller<HostsPage>,
|
||||
/// One session child at a time — connects while one runs are ignored.
|
||||
busy: bool,
|
||||
@@ -160,6 +165,42 @@ impl SimpleComponent for AppModel {
|
||||
}
|
||||
|
||||
let settings = Rc::new(RefCell::new(Settings::load()));
|
||||
// Device lists for the settings pickers: probe in the background, ready long
|
||||
// before the dialog opens. A missing session binary or absent PipeWire just
|
||||
// leaves the corresponding list empty (and its picker hidden).
|
||||
let probes: Rc<RefCell<crate::ui_settings::DeviceProbes>> = Rc::default();
|
||||
{
|
||||
let (tx, rx) = async_channel::bounded::<crate::ui_settings::DeviceProbes>(1);
|
||||
std::thread::spawn(move || {
|
||||
let adapters: Vec<String> =
|
||||
std::process::Command::new(crate::spawn::session_binary())
|
||||
.arg("--list-adapters")
|
||||
.output()
|
||||
.ok()
|
||||
.filter(|o| o.status.success())
|
||||
.map(|o| {
|
||||
String::from_utf8_lossy(&o.stdout)
|
||||
.lines()
|
||||
.map(str::trim)
|
||||
.filter(|l| !l.is_empty())
|
||||
.map(str::to_string)
|
||||
.collect()
|
||||
})
|
||||
.unwrap_or_default();
|
||||
let (speakers, mics) = pf_client_core::audio::devices().unwrap_or_default();
|
||||
let _ = tx.send_blocking(crate::ui_settings::DeviceProbes {
|
||||
adapters,
|
||||
speakers,
|
||||
mics,
|
||||
});
|
||||
});
|
||||
let probes = probes.clone();
|
||||
glib::spawn_future_local(async move {
|
||||
if let Ok(found) = rx.recv().await {
|
||||
*probes.borrow_mut() = found;
|
||||
}
|
||||
});
|
||||
}
|
||||
// Re-apply the persisted forwarded-controller pin (stable key; the service
|
||||
// matches it whenever such a pad connects).
|
||||
{
|
||||
@@ -197,6 +238,7 @@ impl SimpleComponent for AppModel {
|
||||
settings,
|
||||
identity,
|
||||
gamepad: init.gamepad,
|
||||
probes,
|
||||
hosts,
|
||||
busy: false,
|
||||
wake_fallback: None,
|
||||
@@ -307,8 +349,15 @@ impl SimpleComponent for AppModel {
|
||||
// packet now (fire-and-forget — harmless if it's awake) so a genuinely-asleep
|
||||
// box is already booting while the dial times out, arm the wake-wait fallback
|
||||
// for THIS request, and connect immediately.
|
||||
crate::wol::wake(&req.mac, req.addr.parse().ok());
|
||||
self.wake_fallback = Some(req.clone());
|
||||
//
|
||||
// Auto-wake OFF (the Settings toggle, for VPN hosts that look offline when
|
||||
// they aren't): no packet and no wake-and-wait fallback — the dial either
|
||||
// succeeds or fails with the normal error. The host-card menu's explicit
|
||||
// "Wake host" is deliberately not gated.
|
||||
if self.settings.borrow().auto_wake {
|
||||
crate::wol::wake(&req.mac, req.addr.parse().ok());
|
||||
self.wake_fallback = Some(req.clone());
|
||||
}
|
||||
sender.input(AppMsg::Connect(req));
|
||||
}
|
||||
}
|
||||
@@ -435,6 +484,7 @@ impl SimpleComponent for AppModel {
|
||||
&self.window,
|
||||
self.settings.clone(),
|
||||
&self.gamepad,
|
||||
&self.probes.borrow(),
|
||||
move || {
|
||||
// The library toggle changes the saved cards' menu — re-render.
|
||||
let _ = hosts.send(HostsMsg::Refresh);
|
||||
|
||||
Reference in New Issue
Block a user