Show the iOS version and guest address as the window subtitle

Once vphoned connects, the VM window's subtitle reads
`iOS <version> - <address>`, and it is empty while vphoned is away.

vphoned's health report took the first en* address, which sorts to en0's
fe80:: link-local address. It now picks a 192.x IPv4 address first, then
any other IPv4 that is not loopback or 169.254, then a routable IPv6.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Lakr
2026-09-29 22:43:59 +09:00
co-authored by Claude Opus 5.5
parent fa8913499c
commit 2b253b6eeb
2 changed files with 31 additions and 4 deletions
+12 -3
View File
@@ -40,10 +40,19 @@ enum GuestAPI {
SHA256.hash(data: data).map { String(format: "%02x", $0) }.joined()
}
/// The address the host shows for the guest, from icli's
/// `"<interface> <address>"` strings: a 192.x IPv4 address (the NAT
/// network), then any other routable IPv4, then a routable IPv6. Loopback
/// and link-local addresses, which sort first, never qualify.
static func preferredAddress(_ addresses: [String]) -> String? {
let hosts = addresses.compactMap { $0.split(separator: " ", maxSplits: 1).last.map(String.init) }
let ipv4 = hosts.filter { !$0.contains(":") && !$0.hasPrefix("127.") && !$0.hasPrefix("169.254.") }
let ipv6 = hosts.filter { $0.contains(":") && $0 != "::1" && !$0.contains("%") && !$0.hasPrefix("fe80:") }
return ipv4.first { $0.hasPrefix("192.") } ?? ipv4.first ?? ipv6.first
}
static func health() -> [String: Any] {
let addresses = networkInfo()["addresses"] as? [String] ?? []
let ip = addresses.first(where: { $0.hasPrefix("en") && !$0.contains("127.0.0.1") })?
.split(separator: " ").last.map(String.init)
let ip = preferredAddress(networkInfo()["addresses"] as? [String] ?? [])
let version = ProcessInfo.processInfo.operatingSystemVersion
return [
"name": "vphoned",
@@ -99,15 +99,33 @@ class VPhoneVirtualMachineWindowController: NSObject {
monitor.start(control: control, window: window)
touchIDMonitor = monitor
// Poll vphoned status for the Home button
// Poll vphoned status for the Home button and the subtitle
_ = Timer.scheduledTimer(withTimeInterval: 2, repeats: true) { [weak self] _ in
Task { @MainActor in
guard let self, let control = self.control else { return }
self.updateHomeButton(connected: control.isConnected)
self.updateSubtitle(control: control)
}
}
}
// MARK: - Subtitle
/// `iOS <version> - <address>` from vphoned's health report, which picks
/// the IPv4 address first and falls back to IPv6; empty until it connects.
private func updateSubtitle(control: VPhoneGuestControl) {
guard let window = windowController?.window else { return }
var parts: [String] = []
if control.isConnected {
if let version = control.guestIOSVersion, !version.isEmpty { parts.append("iOS \(version)") }
if let address = control.guestIPAddress, !address.isEmpty { parts.append(address) }
}
let subtitle = parts.joined(separator: " - ")
if window.subtitle != subtitle {
window.subtitle = subtitle
}
}
// MARK: - Home Button
private static let homeImage = NSImage(