feat: add SwiftUI app shell

Replace the command-line entry point with a windowed SwiftUI app
showing live dongle status, a controller placeholder, and a pair button.
The app runs as a regular foreground app even when launched directly
from the build directory.

Co-Authored-By: deepseek (deepseek/deepseek-v4-pro-0813): built SwiftUI app shell
This commit is contained in:
portersky
2026-08-17 15:04:59 +02:00
parent 2d4366f454
commit 0f85b59237
2 changed files with 88 additions and 10 deletions
+1 -1
View File
@@ -6,7 +6,7 @@ if(NOT CMAKE_GENERATOR MATCHES "^(Ninja|Xcode)$")
endif()
cmake_minimum_required(VERSION 3.21)
project(xone_macos VERSION 0.1.1 LANGUAGES CXX Swift)
project(xone_macos VERSION 0.1.2 LANGUAGES CXX Swift)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
+87 -9
View File
@@ -1,13 +1,91 @@
// xone_macos macOS app entry point (Swift)
// TODO(phase 5): device discovery, pairing UI, status display, menubar icon.
// xone_macos macOS app entry point (SwiftUI)
// TODO(phase 5): device discovery (IOKit notifications), pairing UI,
// status display, preferences, menubar icon.
import Foundation
import AppKit
import Combine
import SwiftUI
let version = String(cString: xone_version())
print("xone_macos \(version)")
struct XoneApp: App {
@NSApplicationDelegateAdaptor(AppDelegate.self) private var appDelegate
if xone_dongle_present() {
print("Xbox Wireless Dongle detected")
} else {
print("No Xbox Wireless Dongle detected (plug in the dongle and retry)")
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
final class AppDelegate: NSObject, NSApplicationDelegate {
func applicationDidFinishLaunching(_ notification: Notification) {
// Present as a regular app (foreground window) even when launched
// directly from the build directory instead of an .app bundle.
NSApp.setActivationPolicy(.regular)
NSApp.activate(ignoringOtherApps: true)
}
}
struct ContentView: View {
@State private var donglePresent = false
private let timer = Timer.publish(every: 1.0, on: .main, in: .common)
.autoconnect()
var body: some View {
VStack(alignment: .leading, spacing: 16) {
HStack(spacing: 8) {
Image(systemName: "gamecontroller.fill")
.font(.largeTitle)
Text("xone_macos")
.font(.title)
.bold()
}
statusView
Divider()
controllersView
HStack {
Button("Pair Controller") {
// TODO(phase 5): pairing UI (LED blink + controller press)
}
.disabled(!donglePresent)
Spacer()
Text("v\(String(cString: xone_version()))")
.foregroundStyle(.secondary)
}
}
.padding(24)
.frame(width: 420)
.frame(minHeight: 320)
.onReceive(timer) { _ in
donglePresent = xone_dongle_present()
}
}
private var statusView: some View {
HStack(spacing: 8) {
Circle()
.fill(donglePresent ? Color.green : Color.red)
.frame(width: 10, height: 10)
Text(donglePresent ? "Dongle connected" : "No dongle detected")
.font(.headline)
}
}
private var controllersView: some View {
VStack(alignment: .leading, spacing: 8) {
Text("Controllers")
.font(.headline)
Text("No controllers connected.")
.foregroundStyle(.secondary)
}
}
}
// Entry point: SwiftUI App provides a static main() (top-level code lives in
// main.swift, which CMake's Swift driver expects for executables).
XoneApp.main()