feat(apple): wake-until-up overlay + host edit with MAC prefill
apple / swift (push) Successful in 1m10s
arch / build-publish (push) Successful in 5m17s
android / android (push) Successful in 7m30s
ci / web (push) Successful in 1m7s
ci / docs-site (push) Successful in 1m11s
release / apple (push) Successful in 8m39s
ci / rust (push) Successful in 4m53s
deb / build-publish (push) Successful in 2m58s
decky / build-publish (push) Successful in 16s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 6s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 4s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 4s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 4s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 5s
ci / bench (push) Successful in 4m50s
apple / screenshots (push) Successful in 5m44s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 10m9s
docker / deploy-docs (push) Successful in 18s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 9m52s
apple / swift (push) Successful in 1m10s
arch / build-publish (push) Successful in 5m17s
android / android (push) Successful in 7m30s
ci / web (push) Successful in 1m7s
ci / docs-site (push) Successful in 1m11s
release / apple (push) Successful in 8m39s
ci / rust (push) Successful in 4m53s
deb / build-publish (push) Successful in 2m58s
decky / build-publish (push) Successful in 16s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 6s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 4s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 4s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 4s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 5s
ci / bench (push) Successful in 4m50s
apple / screenshots (push) Successful in 5m44s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 10m9s
docker / deploy-docs (push) Successful in 18s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 9m52s
- HostWaker + WakeOverlay: after sending the Wake-on-LAN packet, wait until the host is really back (resend + mDNS poll, timeout, cancel/retry) before connecting. macOS-only in practice — WoL stays gated off on iOS/tvOS pending the multicast entitlement. - Add/Edit host sheet gains a Wake-on-LAN MAC field, prefilled from the stored MAC or the live mDNS advert; parseMacs validates aa:bb:cc:dd:ee:ff. - Gamepad chrome/home and glass-style polish. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
// The "Waking <host>…" modal shown while HostWaker brings a sleeping host back — a spinner + a
|
||||
// live elapsed counter, escalating to a retry/cancel prompt on timeout. Presented over BOTH the
|
||||
// touch and gamepad home (a wake only ever starts on macOS today, where WoL is ungated), and it
|
||||
// drives from either a pointer (the buttons) or a controller (B cancels, A retries once timed out).
|
||||
|
||||
import PunktfunkKit
|
||||
import SwiftUI
|
||||
|
||||
struct WakeOverlay: View {
|
||||
@ObservedObject var waker: HostWaker
|
||||
|
||||
var body: some View {
|
||||
if let w = waker.waking {
|
||||
ZStack {
|
||||
// Dim + swallow input to the home behind it.
|
||||
Rectangle().fill(.black.opacity(0.6)).ignoresSafeArea()
|
||||
.contentShape(Rectangle())
|
||||
.onTapGesture {}
|
||||
card(w)
|
||||
.frame(maxWidth: 380)
|
||||
.padding(28)
|
||||
.consoleGlass(RoundedRectangle(cornerRadius: 22, style: .continuous))
|
||||
.overlay(
|
||||
RoundedRectangle(cornerRadius: 22, style: .continuous)
|
||||
.strokeBorder(.white.opacity(0.12), lineWidth: 1))
|
||||
.padding(40)
|
||||
}
|
||||
.environment(\.colorScheme, .dark)
|
||||
.transition(.opacity)
|
||||
#if os(iOS) || os(macOS)
|
||||
.background { WakeControllerInput(waker: waker) }
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder private func card(_ w: HostWaker.Waking) -> some View {
|
||||
VStack(spacing: 14) {
|
||||
if w.timedOut {
|
||||
Image(systemName: "moon.zzz.fill")
|
||||
.font(.system(size: 34)).foregroundStyle(.white.opacity(0.85))
|
||||
Text("\(w.hostName) didn't wake")
|
||||
.font(.geist(19, .bold, relativeTo: .title3)).foregroundStyle(.white)
|
||||
Text("It may still be booting, or it's powered off / off this network.")
|
||||
.font(.geist(13, relativeTo: .caption)).foregroundStyle(.white.opacity(0.6))
|
||||
.multilineTextAlignment(.center)
|
||||
HStack(spacing: 12) {
|
||||
Button("Cancel") { waker.cancel() }.buttonStyle(.bordered)
|
||||
Button("Try Again") { waker.retry() }.glassProminentButtonStyle()
|
||||
}
|
||||
.padding(.top, 6)
|
||||
} else {
|
||||
ProgressView().controlSize(.large).tint(.white)
|
||||
Text("Waking \(w.hostName)…")
|
||||
.font(.geist(19, .bold, relativeTo: .title3)).foregroundStyle(.white)
|
||||
Text("Waiting for it to come online · \(w.seconds)s")
|
||||
.font(.geistFixed(13)).foregroundStyle(.white.opacity(0.6))
|
||||
.monospacedDigit()
|
||||
Button(w.connectsAfter ? "Cancel" : "Stop Waiting") { waker.cancel() }
|
||||
.buttonStyle(.bordered)
|
||||
.padding(.top, 6)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if os(iOS) || os(macOS)
|
||||
/// Controller binding for the overlay: B cancels; A retries once it has timed out. A zero-size
|
||||
/// backing view owning a `GamepadMenuInput` for the overlay's lifetime (the home carousel/list is
|
||||
/// gated inactive while a wake is up, so nothing else is consuming the pad).
|
||||
private struct WakeControllerInput: View {
|
||||
@ObservedObject var waker: HostWaker
|
||||
@State private var input = GamepadMenuInput(manager: .shared)
|
||||
|
||||
var body: some View {
|
||||
Color.clear
|
||||
.onAppear {
|
||||
input.onBack = { waker.cancel() }
|
||||
input.onConfirm = { if waker.waking?.timedOut == true { waker.retry() } }
|
||||
input.start()
|
||||
}
|
||||
.onDisappear { input.stop() }
|
||||
}
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user