feat: add SwiftUI macOS main window demo with CI
Some checks failed
swift-macos-arm64 / swift-macos-arm64 (push) Failing after 11s
Some checks failed
swift-macos-arm64 / swift-macos-arm64 (push) Failing after 11s
This commit is contained in:
commit
cf2bfc3aa8
80
.gitea/workflows/swift-macos-arm64.yml
Normal file
80
.gitea/workflows/swift-macos-arm64.yml
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
name: swift-macos-arm64
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ main ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ main ]
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
swift-macos-arm64:
|
||||||
|
runs-on: macos-arm64
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Show toolchain versions
|
||||||
|
run: |
|
||||||
|
set -eu
|
||||||
|
sw_vers
|
||||||
|
xcodebuild -version
|
||||||
|
swift --version
|
||||||
|
|
||||||
|
- name: Install XcodeGen
|
||||||
|
run: |
|
||||||
|
set -eu
|
||||||
|
if ! command -v xcodegen >/dev/null 2>&1; then
|
||||||
|
brew install xcodegen
|
||||||
|
fi
|
||||||
|
xcodegen --version
|
||||||
|
|
||||||
|
- name: Generate Xcode project
|
||||||
|
run: |
|
||||||
|
set -eu
|
||||||
|
chmod +x ./scripts/generate-xcodeproj.sh
|
||||||
|
./scripts/generate-xcodeproj.sh
|
||||||
|
|
||||||
|
- name: Build app
|
||||||
|
run: |
|
||||||
|
set -eu
|
||||||
|
xcodebuild -project SwiftTrayDemo.xcodeproj \
|
||||||
|
-scheme SwiftTrayDemo \
|
||||||
|
-configuration Release \
|
||||||
|
-destination 'generic/platform=macOS' \
|
||||||
|
ARCHS=arm64 ONLY_ACTIVE_ARCH=YES \
|
||||||
|
-derivedDataPath build/DerivedData \
|
||||||
|
build
|
||||||
|
|
||||||
|
- name: Package app
|
||||||
|
run: |
|
||||||
|
set -eux
|
||||||
|
rm -rf artifacts bundle-out
|
||||||
|
mkdir -p artifacts
|
||||||
|
app="build/DerivedData/Build/Products/Release/SwiftTrayDemo.app"
|
||||||
|
zip_name="swift-window-demo-macos-arm64-run${{ github.run_number }}.zip"
|
||||||
|
[ -d "$app" ] || { echo 'No SwiftTrayDemo.app produced'; exit 1; }
|
||||||
|
ditto -c -k --sequesterRsrc --keepParent "$app" "artifacts/$zip_name"
|
||||||
|
cp -R "$app" bundle-out
|
||||||
|
printf '%s\n' 'SwiftTrayDemo macOS app bundle.' > artifacts/README.txt
|
||||||
|
|
||||||
|
- name: Copy latest app to runner desktop
|
||||||
|
run: |
|
||||||
|
set -eux
|
||||||
|
dest="$HOME/Desktop/Builds/swift-tests"
|
||||||
|
mkdir -p "$dest"
|
||||||
|
find "$dest" -mindepth 1 -maxdepth 1 -exec rm -rf {} +
|
||||||
|
ditto bundle-out/SwiftTrayDemo.app "$dest/SwiftTrayDemo.app"
|
||||||
|
cp artifacts/README.txt "$dest/"
|
||||||
|
printf '%s\n' \
|
||||||
|
'repo: swift-tests' \
|
||||||
|
'workflow: swift-macos-arm64.yml' \
|
||||||
|
'artifact: SwiftTrayDemo.app' \
|
||||||
|
"runner_app: $dest/SwiftTrayDemo.app" \
|
||||||
|
> "$dest/LATEST.txt"
|
||||||
|
|
||||||
|
- name: Upload artifacts
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: SwiftTrayDemo-macos-arm64-run${{ github.run_number }}
|
||||||
|
path: artifacts/
|
||||||
|
retention-days: 14
|
||||||
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
.DS_Store
|
||||||
|
build/
|
||||||
|
DerivedData/
|
||||||
|
artifacts/
|
||||||
|
bundle-out/
|
||||||
|
*.xcodeproj/
|
||||||
17
README.md
Normal file
17
README.md
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
# swift-tests
|
||||||
|
|
||||||
|
A modern macOS SwiftUI/Xcode app for exercising main application window capabilities on Apple Silicon Macs.
|
||||||
|
|
||||||
|
## What it demonstrates
|
||||||
|
- standard app window with toolbar + sidebar-style layout
|
||||||
|
- live window controls (title, size, full screen, center)
|
||||||
|
- sheets and confirmation dialogs
|
||||||
|
- secondary utility window
|
||||||
|
- simple menu-bar / tray integration
|
||||||
|
- Xcode project generation via XcodeGen for modern Xcode workflows and previews
|
||||||
|
|
||||||
|
## Layout
|
||||||
|
- `SwiftTrayDemo/` — Swift source for the macOS app
|
||||||
|
- `project.yml` — XcodeGen spec
|
||||||
|
- `scripts/generate-xcodeproj.sh` — generates `SwiftTrayDemo.xcodeproj`
|
||||||
|
- `.gitea/workflows/swift-macos-arm64.yml` — native Apple Silicon CI build
|
||||||
143
SwiftTrayDemo/ContentView.swift
Normal file
143
SwiftTrayDemo/ContentView.swift
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct FeatureCard: View {
|
||||||
|
let title: String
|
||||||
|
let systemImage: String
|
||||||
|
let detail: String
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
VStack(alignment: .leading, spacing: 10) {
|
||||||
|
Label(title, systemImage: systemImage)
|
||||||
|
.font(.headline)
|
||||||
|
Text(detail)
|
||||||
|
.font(.subheadline)
|
||||||
|
.foregroundStyle(.secondary)
|
||||||
|
}
|
||||||
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
|
.padding()
|
||||||
|
.background(.quaternary.opacity(0.45), in: RoundedRectangle(cornerRadius: 14, style: .continuous))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ContentView: View {
|
||||||
|
@Environment(\.openWindow) private var openWindow
|
||||||
|
|
||||||
|
@State private var documentTitle = "Swift Window Demo"
|
||||||
|
@State private var width: Double = 980
|
||||||
|
@State private var height: Double = 640
|
||||||
|
@State private var showSheet = false
|
||||||
|
@State private var showDialog = false
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
NavigationSplitView {
|
||||||
|
List {
|
||||||
|
Label("Overview", systemImage: "macwindow")
|
||||||
|
Label("Window Controls", systemImage: "slider.horizontal.3")
|
||||||
|
Label("Secondary Window", systemImage: "uiwindow.split.2x1")
|
||||||
|
Label("Dialogs", systemImage: "square.and.pencil")
|
||||||
|
}
|
||||||
|
.navigationTitle("Capabilities")
|
||||||
|
.listStyle(.sidebar)
|
||||||
|
} detail: {
|
||||||
|
ScrollView {
|
||||||
|
VStack(alignment: .leading, spacing: 22) {
|
||||||
|
VStack(alignment: .leading, spacing: 8) {
|
||||||
|
Text("Main Window Demo")
|
||||||
|
.font(.system(size: 34, weight: .bold))
|
||||||
|
Text("A current-style SwiftUI macOS app that exercises real desktop window behaviors instead of just rendering a static view.")
|
||||||
|
.foregroundStyle(.secondary)
|
||||||
|
}
|
||||||
|
|
||||||
|
Grid(horizontalSpacing: 16, verticalSpacing: 16) {
|
||||||
|
GridRow {
|
||||||
|
FeatureCard(title: "Resizable", systemImage: "arrow.up.left.and.arrow.down.right", detail: "Set a target content size and apply it to the frontmost app window.")
|
||||||
|
FeatureCard(title: "Secondary Window", systemImage: "macwindow.on.rectangle", detail: "Open a separate utility-style scene to prove multi-window support.")
|
||||||
|
}
|
||||||
|
GridRow {
|
||||||
|
FeatureCard(title: "Sheet + Dialog", systemImage: "rectangle.portrait.and.arrow.right", detail: "Trigger standard macOS sheets and confirmation dialogs.")
|
||||||
|
FeatureCard(title: "Tray Integration", systemImage: "menubar.rectangle", detail: "Use the menu-bar item to reopen the main window at any time.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GroupBox("Window controls") {
|
||||||
|
VStack(alignment: .leading, spacing: 14) {
|
||||||
|
TextField("Window title", text: $documentTitle)
|
||||||
|
.textFieldStyle(.roundedBorder)
|
||||||
|
|
||||||
|
HStack {
|
||||||
|
VStack(alignment: .leading) {
|
||||||
|
Text("Width: \(Int(width))")
|
||||||
|
Slider(value: $width, in: 700...1400, step: 10)
|
||||||
|
}
|
||||||
|
VStack(alignment: .leading) {
|
||||||
|
Text("Height: \(Int(height))")
|
||||||
|
Slider(value: $height, in: 480...960, step: 10)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HStack(spacing: 12) {
|
||||||
|
Button("Apply Size") {
|
||||||
|
WindowCommandCenter.resizeMainWindow(width: width, height: height)
|
||||||
|
}
|
||||||
|
Button("Center Window") {
|
||||||
|
WindowCommandCenter.centerMainWindow()
|
||||||
|
}
|
||||||
|
Button("Toggle Full Screen") {
|
||||||
|
WindowCommandCenter.toggleFullScreen()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.padding(.top, 4)
|
||||||
|
}
|
||||||
|
|
||||||
|
HStack(spacing: 12) {
|
||||||
|
Button("Open Utility Window") {
|
||||||
|
openWindow(id: "inspector")
|
||||||
|
}
|
||||||
|
Button("Show Sheet") {
|
||||||
|
showSheet = true
|
||||||
|
}
|
||||||
|
Button("Show Confirmation") {
|
||||||
|
showDialog = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.padding(24)
|
||||||
|
}
|
||||||
|
.navigationTitle(documentTitle)
|
||||||
|
.sheet(isPresented: $showSheet) {
|
||||||
|
SheetDemoView()
|
||||||
|
}
|
||||||
|
.confirmationDialog("Test confirmation dialog", isPresented: $showDialog, titleVisibility: .visible) {
|
||||||
|
Button("Acknowledge") {}
|
||||||
|
Button("Cancel", role: .cancel) {}
|
||||||
|
} message: {
|
||||||
|
Text("This validates standard app-window attached dialogs on macOS.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SheetDemoView: View {
|
||||||
|
@Environment(\.dismiss) private var dismiss
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
VStack(alignment: .leading, spacing: 16) {
|
||||||
|
Text("Attached Sheet")
|
||||||
|
.font(.title.bold())
|
||||||
|
Text("This sheet is attached to the main app window and demonstrates standard macOS document-style presentation.")
|
||||||
|
.foregroundStyle(.secondary)
|
||||||
|
HStack {
|
||||||
|
Spacer()
|
||||||
|
Button("Close") { dismiss() }
|
||||||
|
.keyboardShortcut(.defaultAction)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.padding(24)
|
||||||
|
.frame(minWidth: 420, minHeight: 180)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#Preview {
|
||||||
|
ContentView()
|
||||||
|
}
|
||||||
168
SwiftTrayDemo/SwiftTrayDemoApp.swift
Normal file
168
SwiftTrayDemo/SwiftTrayDemoApp.swift
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
import SwiftUI
|
||||||
|
import AppKit
|
||||||
|
import ObjectiveC
|
||||||
|
|
||||||
|
enum WindowCommandCenter {
|
||||||
|
static func mainWindow() -> NSWindow? {
|
||||||
|
NSApp.windows.first { $0.identifier?.rawValue == "main-window" } ?? NSApp.windows.first
|
||||||
|
}
|
||||||
|
|
||||||
|
static func resizeMainWindow(width: Double, height: Double) {
|
||||||
|
guard let window = mainWindow() else { return }
|
||||||
|
var frame = window.frame
|
||||||
|
frame.size = NSSize(width: width, height: height)
|
||||||
|
window.setFrame(frame, display: true, animate: true)
|
||||||
|
window.makeKeyAndOrderFront(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
static func centerMainWindow() {
|
||||||
|
guard let window = mainWindow() else { return }
|
||||||
|
window.center()
|
||||||
|
NSApp.activate(ignoringOtherApps: true)
|
||||||
|
window.makeKeyAndOrderFront(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
static func toggleFullScreen() {
|
||||||
|
guard let window = mainWindow() else { return }
|
||||||
|
NSApp.activate(ignoringOtherApps: true)
|
||||||
|
window.toggleFullScreen(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
static func showMainWindow() {
|
||||||
|
guard let window = mainWindow() else { return }
|
||||||
|
NSApp.activate(ignoringOtherApps: true)
|
||||||
|
window.makeKeyAndOrderFront(nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final class WindowAccessor: NSView {
|
||||||
|
var onResolve: ((NSWindow) -> Void)?
|
||||||
|
|
||||||
|
override func viewDidMoveToWindow() {
|
||||||
|
super.viewDidMoveToWindow()
|
||||||
|
if let window {
|
||||||
|
onResolve?(window)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MainWindowConfigurator: NSViewRepresentable {
|
||||||
|
func makeNSView(context: Context) -> NSView {
|
||||||
|
let view = WindowAccessor()
|
||||||
|
view.onResolve = { window in
|
||||||
|
window.identifier = NSUserInterfaceItemIdentifier("main-window")
|
||||||
|
window.title = "Swift Window Demo"
|
||||||
|
window.setContentSize(NSSize(width: 980, height: 640))
|
||||||
|
window.center()
|
||||||
|
window.styleMask.insert(.resizable)
|
||||||
|
window.styleMask.insert(.miniaturizable)
|
||||||
|
window.toolbarStyle = .unified
|
||||||
|
window.titlebarAppearsTransparent = false
|
||||||
|
}
|
||||||
|
return view
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateNSView(_ nsView: NSView, context: Context) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
final class TrayController: NSObject {
|
||||||
|
private var statusItem: NSStatusItem?
|
||||||
|
|
||||||
|
func install() {
|
||||||
|
let item = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
|
||||||
|
item.button?.image = NSImage(systemSymbolName: "menubar.rectangle", accessibilityDescription: "Swift Window Demo")
|
||||||
|
item.button?.toolTip = "Swift Window Demo"
|
||||||
|
|
||||||
|
let menu = NSMenu()
|
||||||
|
|
||||||
|
let openItem = NSMenuItem(title: "Open Main Window", action: #selector(MenuActionBox.performAction), keyEquivalent: "o")
|
||||||
|
openItem.target = MenuActionBox {
|
||||||
|
WindowCommandCenter.showMainWindow()
|
||||||
|
}
|
||||||
|
menu.addItem(openItem)
|
||||||
|
|
||||||
|
let centerItem = NSMenuItem(title: "Center Main Window", action: #selector(MenuActionBox.performAction), keyEquivalent: "c")
|
||||||
|
centerItem.target = MenuActionBox {
|
||||||
|
WindowCommandCenter.centerMainWindow()
|
||||||
|
}
|
||||||
|
menu.addItem(centerItem)
|
||||||
|
|
||||||
|
menu.addItem(.separator())
|
||||||
|
|
||||||
|
let quitItem = NSMenuItem(title: "Quit", action: #selector(MenuActionBox.performAction), keyEquivalent: "q")
|
||||||
|
quitItem.target = MenuActionBox {
|
||||||
|
NSApp.terminate(nil)
|
||||||
|
}
|
||||||
|
menu.addItem(quitItem)
|
||||||
|
|
||||||
|
objc_setAssociatedObject(openItem, UnsafeRawPointer(bitPattern: 1)!, openItem.target, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
|
||||||
|
objc_setAssociatedObject(centerItem, UnsafeRawPointer(bitPattern: 2)!, centerItem.target, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
|
||||||
|
objc_setAssociatedObject(quitItem, UnsafeRawPointer(bitPattern: 3)!, quitItem.target, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
|
||||||
|
|
||||||
|
item.menu = menu
|
||||||
|
statusItem = item
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final class MenuActionBox: NSObject {
|
||||||
|
private let action: () -> Void
|
||||||
|
|
||||||
|
init(action: @escaping () -> Void) {
|
||||||
|
self.action = action
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc func performAction() {
|
||||||
|
action()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final class AppDelegate: NSObject, NSApplicationDelegate {
|
||||||
|
private let trayController = TrayController()
|
||||||
|
|
||||||
|
func applicationDidFinishLaunching(_ notification: Notification) {
|
||||||
|
trayController.install()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct InspectorView: View {
|
||||||
|
var body: some View {
|
||||||
|
VStack(alignment: .leading, spacing: 14) {
|
||||||
|
Text("Utility Window")
|
||||||
|
.font(.title2.bold())
|
||||||
|
Text("This secondary scene proves the app supports more than one real macOS window.")
|
||||||
|
.foregroundStyle(.secondary)
|
||||||
|
Divider()
|
||||||
|
Label("Independent scene", systemImage: "macwindow.on.rectangle")
|
||||||
|
Label("Useful for inspectors, logs, or tools", systemImage: "sidebar.right")
|
||||||
|
}
|
||||||
|
.padding(20)
|
||||||
|
.frame(minWidth: 360, minHeight: 220)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@main
|
||||||
|
struct SwiftTrayDemoApp: App {
|
||||||
|
@NSApplicationDelegateAdaptor(AppDelegate.self) private var appDelegate
|
||||||
|
|
||||||
|
var body: some Scene {
|
||||||
|
WindowGroup("Swift Window Demo") {
|
||||||
|
ContentView()
|
||||||
|
.background(MainWindowConfigurator())
|
||||||
|
}
|
||||||
|
.defaultSize(width: 980, height: 640)
|
||||||
|
.commands {
|
||||||
|
CommandGroup(after: .windowArrangement) {
|
||||||
|
Button("Center Main Window") {
|
||||||
|
WindowCommandCenter.centerMainWindow()
|
||||||
|
}
|
||||||
|
.keyboardShortcut("0")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Window("Inspector", id: "inspector") {
|
||||||
|
InspectorView()
|
||||||
|
}
|
||||||
|
.defaultSize(width: 360, height: 220)
|
||||||
|
.windowResizability(.contentSize)
|
||||||
|
}
|
||||||
|
}
|
||||||
38
project.yml
Normal file
38
project.yml
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
name: SwiftTrayDemo
|
||||||
|
options:
|
||||||
|
minimumXcodeGenVersion: 2.38.0
|
||||||
|
deploymentTarget:
|
||||||
|
macOS: '14.0'
|
||||||
|
settings:
|
||||||
|
base:
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER: io.swissline.swifttraydemo
|
||||||
|
SWIFT_VERSION: 5.10
|
||||||
|
MACOSX_DEPLOYMENT_TARGET: 14.0
|
||||||
|
GENERATE_INFOPLIST_FILE: YES
|
||||||
|
INFOPLIST_KEY_NSHighResolutionCapable: YES
|
||||||
|
INFOPLIST_KEY_LSApplicationCategoryType: public.app-category.developer-tools
|
||||||
|
CODE_SIGNING_ALLOWED: NO
|
||||||
|
CODE_SIGNING_REQUIRED: NO
|
||||||
|
CODE_SIGN_IDENTITY: ''
|
||||||
|
ENABLE_DEBUG_DYLIB: YES
|
||||||
|
|
||||||
|
targets:
|
||||||
|
SwiftTrayDemo:
|
||||||
|
type: application
|
||||||
|
platform: macOS
|
||||||
|
sources:
|
||||||
|
- SwiftTrayDemo
|
||||||
|
settings:
|
||||||
|
base:
|
||||||
|
PRODUCT_NAME: SwiftTrayDemo
|
||||||
|
PRODUCT_MODULE_NAME: SwiftTrayDemo
|
||||||
|
INFOPLIST_KEY_CFBundleDisplayName: SwiftTrayDemo
|
||||||
|
INFOPLIST_KEY_CFBundleName: SwiftTrayDemo
|
||||||
|
INFOPLIST_KEY_CFBundleExecutable: SwiftTrayDemo
|
||||||
|
INFOPLIST_KEY_CFBundleIdentifier: io.swissline.swifttraydemo
|
||||||
|
INFOPLIST_KEY_CFBundleShortVersionString: '1.0'
|
||||||
|
INFOPLIST_KEY_CFBundleVersion: '1'
|
||||||
|
INFOPLIST_KEY_LSMinimumSystemVersion: '14.0'
|
||||||
|
scheme:
|
||||||
|
testTargets: []
|
||||||
|
gatherCoverageData: false
|
||||||
8
scripts/generate-xcodeproj.sh
Executable file
8
scripts/generate-xcodeproj.sh
Executable file
@ -0,0 +1,8 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
if ! command -v xcodegen >/dev/null 2>&1; then
|
||||||
|
echo "xcodegen not found. Install with: brew install xcodegen" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
cd "$(dirname "$0")/.."
|
||||||
|
xcodegen generate
|
||||||
14
swift-tests-docs.md
Normal file
14
swift-tests-docs.md
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
# swift-tests-docs
|
||||||
|
|
||||||
|
Clean restart as a normal macOS SwiftUI app.
|
||||||
|
|
||||||
|
## Shape
|
||||||
|
- one app target only
|
||||||
|
- no Swift package layout
|
||||||
|
- one window
|
||||||
|
- one tray icon
|
||||||
|
- real `.app` output
|
||||||
|
|
||||||
|
## Build output
|
||||||
|
Latest app is copied to:
|
||||||
|
- `/Users/m1/Desktop/Builds/swift-tests/SwiftTrayDemo.app`
|
||||||
3
swift-tests-report.md
Normal file
3
swift-tests-report.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# swift-tests-report
|
||||||
|
|
||||||
|
Project restarted from scratch as a minimal normal SwiftUI macOS app with one target, one window, and one tray icon.
|
||||||
Loading…
x
Reference in New Issue
Block a user