swift-tests/SwiftTrayDemo/ContentView.swift
Gremlin 44b59d50c9
All checks were successful
swift-macos-arm64 / swift-macos-arm64 (push) Successful in 11s
feat: make tray menu actions work and add functional demo sections
2026-03-21 17:01:43 +01:00

298 lines
11 KiB
Swift

import SwiftUI
enum DemoSection: String, CaseIterable, Identifiable, Hashable {
case overview
case windowControls
case secondaryWindow
case dialogs
var id: String { rawValue }
var title: String {
switch self {
case .overview: "Overview"
case .windowControls: "Window Controls"
case .secondaryWindow: "Secondary Window"
case .dialogs: "Dialogs"
}
}
var systemImage: String {
switch self {
case .overview: "macwindow"
case .windowControls: "slider.horizontal.3"
case .secondaryWindow: "uiwindow.split.2x1"
case .dialogs: "square.and.pencil"
}
}
}
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 selection: DemoSection? = .overview
@State private var documentTitle = "Swift Window Demo"
@State private var width: Double = 980
@State private var height: Double = 640
@State private var windowOpacity: Double = 1.0
@State private var showSheet = false
@State private var showDialog = false
@State private var showAlert = false
@State private var statusMessage = "Ready"
var body: some View {
NavigationSplitView {
List(DemoSection.allCases, selection: $selection) { section in
Label(section.title, systemImage: section.systemImage)
.tag(section)
}
.navigationTitle("Capabilities")
.listStyle(.sidebar)
} detail: {
Group {
switch selection ?? .overview {
case .overview:
overviewView
case .windowControls:
windowControlsView
case .secondaryWindow:
secondaryWindowView
case .dialogs:
dialogsView
}
}
.navigationTitle((selection ?? .overview).title)
.sheet(isPresented: $showSheet) {
SheetDemoView(statusMessage: $statusMessage)
}
.alert("Demo alert", isPresented: $showAlert) {
Button("OK") {
statusMessage = "Alert acknowledged"
}
} message: {
Text("This is a standard alert attached to the app session.")
}
.confirmationDialog("Test confirmation dialog", isPresented: $showDialog, titleVisibility: .visible) {
Button("Center Main Window") {
WindowCommandCenter.centerMainWindow()
statusMessage = "Centered the main window"
}
Button("Open Utility Window") {
openWindow(id: "inspector")
statusMessage = "Opened the utility window"
}
Button("Cancel", role: .cancel) {
statusMessage = "Confirmation cancelled"
}
} message: {
Text("Choose an action to prove the dialog actually triggers app behavior.")
}
}
}
private var overviewView: some View {
ScrollView {
VStack(alignment: .leading, spacing: 22) {
VStack(alignment: .leading, spacing: 8) {
Text("Main Window Demo")
.font(.system(size: 34, weight: .bold))
Text("A functional SwiftUI macOS app that demonstrates real window controls, dialogs, multi-window behavior, and tray integration.")
.foregroundStyle(.secondary)
}
Grid(horizontalSpacing: 16, verticalSpacing: 16) {
GridRow {
FeatureCard(title: "Resizable Window", systemImage: "arrow.up.left.and.arrow.down.right", detail: "Resize, center, retitle, and fade the main window using live controls.")
FeatureCard(title: "Working Sidebar", systemImage: "sidebar.left", detail: "Each sidebar section now drives a different detail view instead of being static decoration.")
}
GridRow {
FeatureCard(title: "Dialogs + Alerts", systemImage: "rectangle.portrait.and.arrow.right", detail: "Open a sheet, alert, and confirmation dialog that each perform visible actions.")
FeatureCard(title: "Tray Menu", systemImage: "menubar.rectangle", detail: "Tray items are explicitly enabled and can reopen or center the main window.")
}
}
GroupBox("Quick actions") {
HStack(spacing: 12) {
Button("Center Window") {
WindowCommandCenter.centerMainWindow()
statusMessage = "Centered main window"
}
Button("Open Utility Window") {
openWindow(id: "inspector")
statusMessage = "Opened utility window"
}
Button("Show Sheet") {
showSheet = true
}
}
.padding(.top, 4)
}
Label(statusMessage, systemImage: "checkmark.circle")
.foregroundStyle(.secondary)
}
.padding(24)
}
}
private var windowControlsView: some View {
Form {
Section("Window identity") {
TextField("Window title", text: $documentTitle)
Button("Apply Title") {
WindowCommandCenter.renameMainWindow(to: documentTitle)
statusMessage = "Renamed main window"
}
}
Section("Window size") {
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)
statusMessage = "Resized main window"
}
Button("Center") {
WindowCommandCenter.centerMainWindow()
statusMessage = "Centered main window"
}
Button("Toggle Full Screen") {
WindowCommandCenter.toggleFullScreen()
statusMessage = "Toggled full screen"
}
}
}
Section("Window appearance") {
VStack(alignment: .leading) {
Text("Opacity: \(windowOpacity.formatted(.number.precision(.fractionLength(2))))")
Slider(value: $windowOpacity, in: 0.35...1.0, step: 0.05)
}
Button("Apply Opacity") {
WindowCommandCenter.setMainWindowAlpha(windowOpacity)
statusMessage = "Adjusted window opacity"
}
}
}
.formStyle(.grouped)
.padding(24)
}
private var secondaryWindowView: some View {
VStack(alignment: .leading, spacing: 18) {
Text("Secondary Window Demo")
.font(.largeTitle.bold())
Text("Use this section to prove the app can open and focus a second real window, which is useful for inspectors, logs, tools, or floating utilities.")
.foregroundStyle(.secondary)
HStack(spacing: 12) {
Button("Open Utility Window") {
openWindow(id: "inspector")
statusMessage = "Opened utility window"
}
Button("Bring Main Window Forward") {
WindowCommandCenter.showMainWindow()
statusMessage = "Brought main window forward"
}
}
GroupBox("What this demonstrates") {
VStack(alignment: .leading, spacing: 10) {
Label("Multiple scenes/windows", systemImage: "macwindow.on.rectangle")
Label("Window switching from app UI", systemImage: "arrow.triangle.2.circlepath")
Label("Useful split between content and tools", systemImage: "sidebar.right")
}
.frame(maxWidth: .infinity, alignment: .leading)
.padding(.top, 4)
}
Spacer()
}
.padding(24)
}
private var dialogsView: some View {
VStack(alignment: .leading, spacing: 18) {
Text("Dialogs Demo")
.font(.largeTitle.bold())
Text("These controls trigger different interaction patterns so the app demonstrates more than a static window.")
.foregroundStyle(.secondary)
HStack(spacing: 12) {
Button("Show Sheet") {
showSheet = true
}
Button("Show Alert") {
showAlert = true
}
Button("Show Confirmation") {
showDialog = true
}
}
GroupBox("Last action") {
Text(statusMessage)
.frame(maxWidth: .infinity, alignment: .leading)
.padding(.top, 4)
}
Spacer()
}
.padding(24)
}
}
struct SheetDemoView: View {
@Binding var statusMessage: String
@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") {
statusMessage = "Closed attached sheet"
dismiss()
}
.keyboardShortcut(.defaultAction)
}
}
.padding(24)
.frame(minWidth: 420, minHeight: 180)
}
}
#Preview {
ContentView()
}