Exemplos de Recursos de Área de Trabalho macOS Swift

Exemplos de recursos específicos de desktop macOS Swift incluindo diálogos de arquivo, caixas de mensagem e bandeja do sistema

💻 Caixas de Mensagem swift

🟢 simple ⭐⭐

Exibir diálogos de alerta, diálogos de confirmação e caixas de mensagem personalizadas usando NSAlert

⏱️ 25 min 🏷️ swift, macos, desktop, gui
Prerequisites: Basic Swift, Cocoa/AppKit
// macOS Swift Message Boxes Examples
// Using NSAlert for various dialog types

import Cocoa
import Foundation

// 1. Simple Alert Dialog
class SimpleAlertDialog {

    func showAlert(title: String, message: String) {
        print("\n--- Simple Alert ---")
        print("Title: \(title)")
        print("Message: \(message)")

        let alert = NSAlert()
        alert.messageText = title
        alert.informativeText = message
        alert.alertStyle = .informational
        alert.addButton(withTitle: "OK")

        let response = alert.runModal()
        print("Response: \(response.rawValue)")
    }

    func showError(title: String, message: String) {
        print("\n--- Error Alert ---")
        print("Title: \(title)")
        print("Message: \(message)")

        let alert = NSAlert()
        alert.messageText = title
        alert.informativeText = message
        alert.alertStyle = .critical
        alert.addButton(withTitle: "OK")

        alert.runModal()
    }

    func showWarning(title: String, message: String) {
        print("\n--- Warning Alert ---")
        print("Title: \(title)")
        print("Message: \(message)")

        let alert = NSAlert()
        alert.messageText = title
        alert.informativeText = message
        alert.alertStyle = .warning
        alert.addButton(withTitle: "OK")

        alert.runModal()
    }
}

// 2. Confirmation Dialog
class ConfirmationDialog {

    enum Response {
        case yes
        case no
        case cancelled

        init(_ modalResponse: NSApplication.ModalResponse) {
            switch modalResponse {
            case .alertFirstButtonReturn:
                self = .yes
            case .alertSecondButtonReturn:
                self = .no
            default:
                self = .cancelled
            }
        }
    }

    func confirm(title: String, message: String) -> Response {
        print("\n--- Confirmation Dialog ---")
        print("Question: \(message)")

        let alert = NSAlert()
        alert.messageText = title
        alert.informativeText = message
        alert.alertStyle = .informational
        alert.addButton(withTitle: "Yes")
        alert.addButton(withTitle: "No")

        let response = Response(alert.runModal())
        print("User response: \(response)")

        return response
    }

    func confirmDestructive(title: String, message: String, item: String) -> Response {
        print("\n--- Destructive Confirmation ---")
        print("Warning: This action cannot be undone")

        let alert = NSAlert()
        alert.messageText = title
        alert.informativeText = message + "\n\nAre you sure you want to delete '\(item)'?"
        alert.alertStyle = .critical
        alert.addButton(withTitle: "Delete")
        alert.addButton(withTitle: "Cancel")

        let response = Response(alert.runModal())
        return response
    }

    func confirmWithThirdOption(title: String, message: String) -> Int {
        print("\n--- Three-Option Confirmation ---")

        let alert = NSAlert()
        alert.messageText = title
        alert.informativeText = message
        alert.alertStyle = .informational
        alert.addButton(withTitle: "Yes")
        alert.addButton(withTitle: "No")
        alert.addButton(withTitle: "Cancel")

        let response = alert.runModal()
        print("Response button: \(response.rawValue - NSApplication.ModalResponse.alertFirstButtonReturn.rawValue)")

        return response.rawValue - NSApplication.ModalResponse.alertFirstButtonReturn.rawValue
    }
}

// 3. Custom Alert with Icon
class CustomIconAlert {

    func showWithIcon(title: String, message: String, icon: NSImage?) {
        print("\n--- Custom Icon Alert ---")

        let alert = NSAlert()
        alert.messageText = title
        alert.informativeText = message
        alert.alertStyle = .informational

        if let icon = icon {
            alert.icon = icon
            print("Custom icon set: \(icon.size)")
        }

        alert.addButton(withTitle: "OK")
        alert.runModal()
    }

    func showWithSystemIcon(title: String, message: String, iconName: String) {
        print("\n--- System Icon Alert ---")

        let alert = NSAlert()
        alert.messageText = title
        alert.informativeText = message

        if let icon = NSImage(systemSymbolName: iconName, accessibilityDescription: nil) {
            alert.icon = icon
            print("Using system icon: \(iconName)")
        }

        alert.alertStyle = .informational
        alert.addButton(withTitle: "OK")
        alert.runModal()
    }
}

// 4. Input Dialog
class InputDialog {

    func showTextInput(title: String, message: String, defaultValue: String = "") -> String? {
        print("\n--- Text Input Dialog ---")

        let alert = NSAlert()
        alert.messageText = title
        alert.informativeText = message
        alert.alertStyle = .informational
        alert.addButton(withTitle: "OK")
        alert.addButton(withTitle: "Cancel")

        let input = NSTextField(frame: NSRect(x: 0, y: 0, width: 300, height: 24))
        input.stringValue = defaultValue
        alert.accessoryView = input

        alert.window.initialFirstResponder = input

        let response = alert.runModal()

        if response == .alertFirstButtonReturn {
            let value = input.stringValue
            print("Input: \(value)")
            return value
        }

        print("Input cancelled")
        return nil
    }

    func showPasswordInput(title: String, message: String) -> String? {
        print("\n--- Password Input Dialog ---")

        let alert = NSAlert()
        alert.messageText = title
        alert.informativeText = message
        alert.alertStyle = .informational
        alert.addButton(withTitle: "OK")
        alert.addButton(withTitle: "Cancel")

        let input = NSSecureTextField(frame: NSRect(x: 0, y: 0, width: 300, height: 24))
        alert.accessoryView = input

        alert.window.initialFirstResponder = input

        let response = alert.runModal()

        if response == .alertFirstButtonReturn {
            let password = input.stringValue
            print("Password received: \(password.count) characters")
            return password
        }

        return nil
    }

    func showMultiLineInput(title: String, message: String, defaultValue: String = "") -> String? {
        print("\n--- Multi-line Input Dialog ---")

        let alert = NSAlert()
        alert.messageText = title
        alert.informativeText = message
        alert.alertStyle = .informational
        alert.addButton(withTitle: "OK")
        alert.addButton(withTitle: "Cancel")

        let scrollView = NSScrollView(frame: NSRect(x: 0, y: 0, width: 400, height: 100))
        let textView = NSTextView()
        textView.textContainer?.containerSize = NSSize(width: 400, height: 100)
        textView.textContainer?.widthTracksTextView = true
        textView.isHorizontallyResizable = false
        textView.isVerticallyResizable = true
        textView.autoresizingMask = .height
        textView.string = defaultValue

        scrollView.documentView = textView
        scrollView.hasVerticalScroller = true
        alert.accessoryView = scrollView

        alert.window.initialFirstResponder = textView

        let response = alert.runModal()

        if response == .alertFirstButtonReturn {
            let value = textView.string
            print("Multi-line input: \(value.count) characters")
            return value
        }

        return nil
    }
}

// 5. Selection Dialog
class SelectionDialog {

    func showChoice(title: String, message: String, options: [String]) -> Int? {
        print("\n--- Selection Dialog ---")
        print("Options: \(options)")

        let alert = NSAlert()
        alert.messageText = title
        alert.informativeText = message
        alert.alertStyle = .informational

        for option in options {
            alert.addButton(withTitle: option)
        }

        let response = alert.runModal()
        let selectedIndex = Int(response.rawValue - NSApplication.ModalResponse.alertFirstButtonReturn.rawValue)

        if selectedIndex >= 0 && selectedIndex < options.count {
            print("Selected: \(options[selectedIndex]) (index: \(selectedIndex))")
            return selectedIndex
        }

        return nil
    }

    func showRadioGroup(title: String, message: String, options: [(label: String, tag: Int)]) -> Int? {
        print("\n--- Radio Group Dialog ---")

        let alert = NSAlert()
        alert.messageText = title
        alert.informativeText = message
        alert.alertStyle = .informational
        alert.addButton(withTitle: "OK")
        alert.addButton(withTitle: "Cancel")

        let radioGroup = NSStackView()
        radioGroup.orientation = .vertical
        radioGroup.spacing = 8

        var buttons: [NSButton] = []

        for (index, option) in options.enumerated() {
            let button = NSButton(radioButtonWithTitle: option.label, target: nil, action: nil)
            button.tag = option.tag
            if index == 0 { button.state = .on }
            buttons.append(button)
            radioGroup.addArrangedSubview(button)
        }

        alert.accessoryView = radioGroup

        let response = alert.runModal()

        if response == .alertFirstButtonReturn,
           let selected = buttons.first(where: { $0.state == .on }) {
            print("Selected: \(selected.title) (tag: \(selected.tag))")
            return selected.tag
        }

        return nil
    }
}

// 6. Progress Dialog
class ProgressDialog {

    func showProgress(title: String, message: String, maxValue: Double = 100) {
        print("\n--- Progress Dialog ---")

        let alert = NSAlert()
        alert.messageText = title
        alert.informativeText = message
        alert.alertStyle = .informational

        let progress = NSProgressIndicator(frame: NSRect(x: 0, y: 0, width: 300, height: 20))
        progress.minValue = 0
        progress.maxValue = maxValue
        progress.isIndeterminate = false
        alert.accessoryView = progress

        progress.startAnimation(nil)

        // Show as sheet or non-modal
        alert.window.level = .floating
        alert.runModal()

        progress.stopAnimation(nil)
    }

    func showIndeterminateProgress(title: String, message: String) {
        print("\n--- Indeterminate Progress Dialog ---")

        let alert = NSAlert()
        alert.messageText = title
        alert.informativeText = message
        alert.alertStyle = .informational

        let progress = NSProgressIndicator(frame: NSRect(x: 0, y: 0, width: 300, height: 20))
        progress.style = .spinning
        progress.isIndeterminate = true
        alert.accessoryView = progress

        progress.startAnimation(nil)
        alert.runModal()
        progress.stopAnimation(nil)
    }
}

// 7. Sheet Dialog (Attached to Window)
class SheetDialog {

    func showSheet(window: NSWindow, title: String, message: String) {
        print("\n--- Sheet Dialog ---")

        let alert = NSAlert()
        alert.messageText = title
        alert.informativeText = message
        alert.alertStyle = .informational
        alert.addButton(withTitle: "OK")

        alert.beginSheetModal(for: window) { response in
            print("Sheet closed with response: \(response.rawValue)")
        }
    }

    func showSheetConfirm(window: NSWindow, title: String, message: String, completion: @escaping (Bool) -> Void) {
        print("\n--- Sheet Confirmation ---")

        let alert = NSAlert()
        alert.messageText = title
        alert.informativeText = message
        alert.alertStyle = .warning
        alert.addButton(withTitle: "Yes")
        alert.addButton(withTitle: "No")

        alert.beginSheetModal(for: window) { response in
            let confirmed = response == .alertFirstButtonReturn
            print("Sheet confirm: \(confirmed)")
            completion(confirmed)
        }
    }
}

// 8. Toast Notification
class ToastNotification {

    func show(message: String, duration: TimeInterval = 3) {
        print("\n--- Toast Notification ---")
        print("Message: \(message)")

        let alert = NSAlert()
        alert.messageText = ""
        alert.informativeText = message
        alert.alertStyle = .informational
        alert.showsSuppressionButton = true
        alert.suppressionButton.title = ""

        // Auto-dismiss after duration
        DispatchQueue.main.asyncAfter(deadline: .now() + duration) {
            alert.window.close()
        }

        alert.runModal()
    }

    func showInWindow(window: NSWindow, message: String, position: NSRect) {
        print("\n--- Toast in Window ---")

        let toast = NSPanel(
            contentRect: NSRect(x: 0, y: 0, width: 300, height: 50),
            styleMask: [.borderless],
            backing: .buffered,
            defer: false
        )

        let label = NSTextField(labelWithString: message)
        label.frame = NSRect(x: 10, y: 10, width: 280, height: 30)
        label.alignment = .center
        toast.contentView?.addSubview(label)

        toast.level = .floating
        toast.alphaValue = 0.9

        window.addChildWindow(toast, ordered: .above)

        DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
            window.removeChildWindow(toast)
            toast.close()
        }
    }
}

// 9. Login Dialog
class LoginDialog {

    func showLogin() -> (username: String, password: String)? {
        print("\n--- Login Dialog ---")

        let alert = NSAlert()
        alert.messageText = "Login"
        alert.informativeText = "Enter your credentials"
        alert.alertStyle = .informational
        alert.addButton(withTitle: "Login")
        alert.addButton(withTitle: "Cancel")

        let view = NSView(frame: NSRect(x: 0, y: 0, width: 250, height: 70))

        let usernameLabel = NSTextField(labelWithString: "Username:")
        usernameLabel.frame = NSRect(x: 0, y: 45, width: 80, height: 20)
        view.addSubview(usernameLabel)

        let usernameField = NSTextField(frame: NSRect(x: 90, y: 45, width: 150, height: 20))
        view.addSubview(usernameField)

        let passwordLabel = NSTextField(labelWithString: "Password:")
        passwordLabel.frame = NSRect(x: 0, y: 15, width: 80, height: 20)
        view.addSubview(passwordLabel)

        let passwordField = NSSecureTextField(frame: NSRect(x: 90, y: 15, width: 150, height: 20))
        view.addSubview(passwordField)

        alert.accessoryView = view
        alert.window.initialFirstResponder = usernameField

        let response = alert.runModal()

        if response == .alertFirstButtonReturn {
            let username = usernameField.stringValue
            let password = passwordField.stringValue
            print("Login attempt for: \(username)")
            return (username, password)
        }

        return nil
    }
}

// 10. Complex Dialog with Multiple Controls
class ComplexDialog {

    func showPreferences() -> [String: Any]? {
        print("\n--- Complex Preferences Dialog ---")

        let alert = NSAlert()
        alert.messageText = "Preferences"
        alert.alertStyle = .informational
        alert.addButton(withTitle: "Save")
        alert.addButton(withTitle: "Cancel")

        let view = NSView(frame: NSRect(x: 0, y: 0, width: 300, height: 180))

        // Checkbox 1
        let checkbox1 = NSButton(checkboxWithTitle: "Enable notifications", target: nil, action: nil)
        checkbox1.state = .on
        checkbox1.frame = NSRect(x: 10, y: 150, width: 280, height: 20)
        view.addSubview(checkbox1)

        // Checkbox 2
        let checkbox2 = NSButton(checkboxWithTitle: "Auto-save documents", target: nil, action: nil)
        checkbox2.state = .on
        checkbox2.frame = NSRect(x: 10, y: 120, width: 280, height: 20)
        view.addSubview(checkbox2)

        // Popup button
        let popupLabel = NSTextField(labelWithString: "Theme:")
        popupLabel.frame = NSRect(x: 10, y: 95, width: 80, height: 17)
        view.addSubview(popupLabel)

        let popup = NSPopUpButton(frame: NSRect(x: 100, y: 90, width: 190, height: 25))
        popup.addItem(withTitle: "Light")
        popup.addItem(withTitle: "Dark")
        popup.addItem(withTitle: "Auto")
        view.addSubview(popup)

        // Slider
        let sliderLabel = NSTextField(labelWithString: "Font size:")
        sliderLabel.frame = NSRect(x: 10, y: 65, width: 80, height: 17)
        view.addSubview(sliderLabel)

        let slider = NSSlider(frame: NSRect(x: 100, y: 60, width: 190, height: 20))
        slider.minValue = 10
        slider.maxValue = 24
        slider.integerValue = 13
        view.addSubview(slider)

        // Text field
        let textFieldLabel = NSTextField(labelWithString: "Name:")
        textFieldLabel.frame = NSRect(x: 10, y: 35, width: 80, height: 17)
        view.addSubview(textFieldLabel)

        let nameField = NSTextField(frame: NSRect(x: 100, y: 32, width: 190, height: 22))
        view.addSubview(nameField)

        alert.accessoryView = view

        let response = alert.runModal()

        if response == .alertFirstButtonReturn {
            let preferences: [String: Any] = [
                "notifications": checkbox1.state == .on,
                "autoSave": checkbox2.state == .on,
                "theme": popup.titleOfSelectedItem ?? "",
                "fontSize": slider.integerValue,
                "name": nameField.stringValue
            ]
            print("Preferences saved: \(preferences)")
            return preferences
        }

        return nil
    }
}

// 11. Alert with Checkbox
class CheckboxAlert {

    func showAlertWithCheckbox(title: String, message: String, checkboxText: String, completion: @escaping (Bool, Bool) -> Void) {
        print("\n--- Alert with Checkbox ---")

        let alert = NSAlert()
        alert.messageText = title
        alert.informativeText = message
        alert.alertStyle = .informational
        alert.addButton(withTitle: "OK")

        alert.showsSuppressionButton = true
        alert.suppressionButton.title = checkboxText

        let response = alert.runModal()
        let checked = alert.suppressionButton.state == .on
        let okPressed = response == .alertFirstButtonReturn

        print("OK pressed: \(okPressed), Checkbox: \(checked)")
        completion(okPressed, checked)
    }

    func showDontAskAgain(title: String, message: String) {
        showAlertWithCheckbox(title: title, message: message, checkboxText: "Don't ask again") { _, dontAsk in
            if dontAsk {
                print("User chose not to be asked again")
                // Save preference to UserDefaults
                UserDefaults.standard.set(true, forKey: "dontAskAgain")
            }
        }
    }
}

// 12. Modal Window Dialog
class ModalWindowDialog {

    func showModalWindow(title: String, content: String) {
        print("\n--- Modal Window Dialog ---")

        let window = NSWindow(
            contentRect: NSRect(x: 0, y: 0, width: 400, height: 300),
            styleMask: [.titled, .closable],
            backing: .buffered,
            defer: false
        )

        window.title = title

        let contentView = NSView(frame: NSRect(x: 0, y: 0, width: 400, height: 300))

        let textField = NSTextField(labelWithString: content)
        textField.frame = NSRect(x: 20, y: 150, width: 360, height: 100)
        textField.alignment = .center
        contentView.addSubview(textField)

        let closeButton = NSButton(frame: NSRect(x: 150, y: 20, width: 100, height: 30))
        closeButton.title = "Close"
        closeButton.target = window
        closeButton.action = #selector(NSWindow.close)
        contentView.addSubview(closeButton)

        window.contentView = contentView
        window.isReleasedWhenClosed = false

        let app = NSApplication.shared
        app.runModal(for: window)
        window.close()
    }
}

// Main demonstration
func demonstrateMessageBoxes() {
    print("=== macOS Swift Message Boxes Examples ===")

    // Note: These dialogs require GUI context
    print("\nNote: Message boxes require NSApplication context")
    print("The following examples show the implementation pattern")

    print("\n--- Example Alert Types ---")

    let simpleAlert = SimpleAlertDialog()
    print("Simple alert: title='Information', message='This is a message'")

    let confirmation = ConfirmationDialog()
    print("Confirmation: title='Confirm', message='Are you sure?'")

    let inputDialog = InputDialog()
    print("Text input: title='Enter Name', message='Please enter your name:'")

    let loginDialog = LoginDialog()
    print("Login dialog: requesting username and password")

    let complex = ComplexDialog()
    print("Complex dialog: multiple controls (checkboxes, popup, slider, text field)")

    print("\n=== All Message Box Examples Completed ===")
}

// Run demonstration
demonstrateMessageBoxes()

💻 Diálogos de Arquivo swift

🟡 intermediate ⭐⭐⭐

Abrir e salvar diálogos de arquivo com filtros e opções personalizadas usando NSOpenPanel e NSSavePanel

⏱️ 30 min 🏷️ swift, macos, desktop, gui
Prerequisites: Intermediate Swift, Cocoa/AppKit
// macOS Swift File Dialogs Examples
// Using NSOpenPanel and NSSavePanel for file selection

import Cocoa
import Foundation

// 1. Basic Open File Dialog
class BasicFileDialog {

    @discardableResult
    func openFile() -> String? {
        print("\n--- Basic Open File Dialog ---")

        let panel = NSOpenPanel()
        panel.title = "Select a file"
        panel.showsResizeIndicator = true
        panel.canChooseFiles = true
        panel.canChooseDirectories = false
        panel.allowsMultipleSelection = false

        let response = panel.runModal()

        if response == .OK {
            if let url = panel.url {
                print("Selected file: \(url.path)")
                return url.path
            }
        }

        print("No file selected")
        return nil
    }
}

// 2. Open File with Filters
class FileDialogWithFilters {

    enum FileFilter {
        case images
        case text
        case pdf
        case all
        case custom(types: [String])

        var extensions: [String] {
            switch self {
            case .images:
                return ["jpg", "jpeg", "png", "gif", "bmp", "tiff"]
            case .text:
                return ["txt", "md", "rtf"]
            case .pdf:
                return ["pdf"]
            case .all:
                return ["*"]
            case .custom(let types):
                return types
            }
        }

        var description: String {
            switch self {
            case .images:
                return "Image Files"
            case .text:
                return "Text Files"
            case .pdf:
                return "PDF Documents"
            case .all:
                return "All Files"
            case .custom(let types):
                return types.joined(separator: ", ")
            }
        }
    }

    func openFile(allowedTypes: [FileFilter]) -> [URL]? {
        print("\n--- Open File with Filters ---")

        let panel = NSOpenPanel()
        panel.title = "Select a file"
        panel.canChooseFiles = true
        panel.canChooseDirectories = false
        panel.allowsMultipleSelection = true

        // Set allowed file types
        let allTypes = allowedTypes.flatMap { $0.extensions }
        panel.allowedFileTypes = allTypes.contains("*") ? nil : allTypes

        // Display filters in title
        let filterDescriptions = allowedTypes.map { $0.description }.joined(separator: ", ")
        print("Allowed types: \(filterDescriptions)")

        let response = panel.runModal()

        if response == .OK {
            let urls = panel.urls
            print("Selected \(urls.count) file(s):")
            urls.forEach { print("  - \($0.lastPathComponent)") }
            return urls
        }

        return nil
    }
}

// 3. Save File Dialog
class SaveFileDialog {

    @discardableResult
    func saveFile(defaultName: String = "untitled.txt") -> URL? {
        print("\n--- Save File Dialog ---")

        let panel = NSSavePanel()
        panel.title = "Save File"
        panel.nameFieldStringValue = defaultName
        panel.canCreateDirectories = true
        panel.isExtensionHidden = false

        let response = panel.runModal()

        if response == .OK {
            if let url = panel.url {
                print("Save to: \(url.path)")

                // Create empty file
                if let content = "Sample content\n".data(using: .utf8) {
                    try? content.write(to: url)
                    print("File created successfully")
                }

                return url
            }
        }

        print("Save cancelled")
        return nil
    }

    func saveFileWithExtension(defaultName: String, allowedExtensions: [String]) -> URL? {
        print("\n--- Save File with Extension Validation ---")

        let panel = NSSavePanel()
        panel.title = "Save File"
        panel.nameFieldStringValue = defaultName
        panel.allowedFileTypes = allowedExtensions
        panel.allowsOtherFileTypes = false

        let response = panel.runModal()

        if response == .OK {
            if let url = panel.url {
                print("Saved to: \(url.path)")
                print("Extension: \(url.pathExtension)")
                return url
            }
        }

        return nil
    }
}

// 4. Open Directory Dialog
class DirectoryDialog {

    func selectDirectory() -> URL? {
        print("\n--- Open Directory Dialog ---")

        let panel = NSOpenPanel()
        panel.title = "Select a folder"
        panel.canChooseFiles = false
        panel.canChooseDirectories = true
        panel.allowsMultipleSelection = false

        let response = panel.runModal()

        if response == .OK {
            if let url = panel.url {
                print("Selected directory: \(url.path)")

                // List directory contents
                if let files = try? FileManager.default.contentsOfDirectory(atPath: url.path) {
                    print("Contents (\(files.count) items):")
                    files.forEach { print("  - \($0)") }
                }

                return url
            }
        }

        return nil
    }

    func selectMultipleDirectories() -> [URL]? {
        print("\n--- Select Multiple Directories ---")

        let panel = NSOpenPanel()
        panel.title = "Select folders"
        panel.canChooseFiles = false
        panel.canChooseDirectories = true
        panel.allowsMultipleSelection = true

        let response = panel.runModal()

        if response == .OK {
            let urls = panel.urls
            print("Selected \(urls.count) director(y/ies):")
            urls.forEach { print("  - \($0.path)") }
            return urls
        }

        return nil
    }
}

// 5. Open Panel with Custom Options
class CustomFileDialog {

    func openWithCustomOptions() -> [URL]? {
        print("\n--- Open Panel with Custom Options ---")

        let panel = NSOpenPanel()
        panel.title = "Select files to import"
        panel.prompt = "Import"
        panel.message = "Choose one or more files to import into the application"

        // Configure options
        panel.canChooseFiles = true
        panel.canChooseDirectories = false
        panel.allowsMultipleSelection = true

        // Set starting directory
        if let downloadsURL = FileManager.default.urls(for: .downloadsDirectory, in: .userDomainMask).first {
            panel.directoryURL = downloadsURL
            print("Starting in Downloads folder")
        }

        // Show hidden files
        panel.showsHiddenFiles = false

        let response = panel.runModal()

        if response == .OK {
            let urls = panel.urls
            print("Selected \(urls.count) file(s) for import")
            return urls
        }

        return nil
    }

    func saveWithAccessoryView() -> URL? {
        print("\n--- Save Panel with Accessory View ---")

        let panel = NSSavePanel()
        panel.title = "Export Settings"

        // Create accessory view
        let accessoryView = NSView(frame: NSRect(x: 0, y: 0, width: 300, height: 50))

        let checkbox = NSButton(checkboxWithTitle: "Include user preferences", target: nil, action: nil)
        checkbox.state = .on
        checkbox.frame = NSRect(x: 20, y: 25, width: 260, height: 20)
        accessoryView.addSubview(checkbox)

        let label = NSTextField(labelWithString: "Export options:")
        label.frame = NSRect(x: 20, y: 5, width: 260, height: 15)
        accessoryView.addSubview(label)

        panel.accessoryView = accessoryView

        let response = panel.runModal()

        if response == .OK, let url = panel.url {
            let includePrefs = checkbox.state == .on
            print("Exported to: \(url.path)")
            print("Include preferences: \(includePrefs)")
            return url
        }

        return nil
    }
}

// 6. Async File Dialog
class AsyncFileDialog {

    func openFileAsync(completion: @escaping (URL?) -> Void) {
        print("\n--- Async File Dialog ---")

        DispatchQueue.main.async {
            let panel = NSOpenPanel()
            panel.title = "Select a file"
            panel.canChooseFiles = true
            panel.canChooseDirectories = false

            panel.begin { response in
                if response == .OK {
                    if let url = panel.url {
                        print("File selected asynchronously: \(url.path)")
                        completion(url)
                        return
                    }
                }
                print("No file selected")
                completion(nil)
            }
        }
    }
}

// 7. Recent Files Dialog
class RecentFilesDialog {

    func showRecentDocuments() -> [URL]? {
        print("\n--- Recent Documents ---")

        let panel = NSOpenPanel()
        panel.title = "Recent Documents"

        // Use the shared document controller
        let documentController = NSDocumentController.shared

        if let recentURLs = documentController.recentDocumentURLs, !recentURLs.isEmpty {
            print("Found \(recentURLs.count) recent document(s):")
            recentURLs.prefix(10).forEach { url in
                print("  - \(url.lastPathComponent)")
            }

            // Show panel in directory of most recent
            if let mostRecent = recentURLs.first,
               let parentURL = mostRecent.deletingLastPathComponent() as URL? {
                panel.directoryURL = parentURL
            }

            let response = panel.runModal()
            if response == .OK, let url = panel.url {
                return [url]
            }
        } else {
            print("No recent documents found")

            // Show regular dialog
            let response = panel.runModal()
            if response == .OK, let url = panel.url {
                return [url]
            }
        }

        return nil
    }
}

// 8. File Dialog with Preview
class FileDialogWithPreview {

    func openWithPreview() -> URL? {
        print("\n--- File Dialog with Preview ---")

        let panel = NSOpenPanel()
        panel.title = "Select an image"
        panel.canChooseFiles = true
        panel.canChooseDirectories = false
        panel.allowedFileTypes = ["jpg", "jpeg", "png", "gif", "pdf"]

        // Enable preview
        panel.canDownloadItems = true

        // Create custom preview accessory view
        let previewView = NSImageView()
        previewView.frame = NSRect(x: 0, y: 0, width: 200, height: 200)
        previewView.imageScaling = .scaleProportionallyUpOrDown
        previewView.wantsLayer = true
        previewView.layer?.borderWidth = 1
        previewView.layer?.borderColor = NSColor.separatorColor.cgColor

        panel.accessoryView = previewView

        // Note: In a real app, you would implement a delegate to update preview
        // when selection changes

        let response = panel.runModal()

        if response == .OK, let url = panel.url {
            print("Selected: \(url.lastPathComponent)")

            // Load and display preview
            if let image = NSImage(contentsOf: url) {
                previewView.image = image
                print("Image size: \(image.size)")
            }

            return url
        }

        return nil
    }
}

// 9. File Dialog with Validation
class ValidatedFileDialog {

    func openWithValidation(minFileSize: Int = 0, maxFileSize: Int = Int.max) -> URL? {
        print("\n--- File Dialog with Validation ---")

        let panel = NSOpenPanel()
        panel.title = "Select a file"
        panel.canChooseFiles = true
        panel.canChooseDirectories = false
        panel.message = "File size must be between \(minFileSize) and \(maxFileSize) bytes"

        let response = panel.runModal()

        if response == .OK, let url = panel.url {
            // Validate file size
            if let attributes = try? FileManager.default.attributesOfItem(atPath: url.path),
               let fileSize = attributes[.size] as? UInt64 {

                print("File: \(url.lastPathComponent)")
                print("Size: \(fileSize) bytes")

                if fileSize < UInt64(minFileSize) {
                    let alert = NSAlert()
                    alert.messageText = "File too small"
                    alert.informativeText = "Selected file is smaller than minimum required size (\(minFileSize) bytes)"
                    alert.alertStyle = .warning
                    alert.runModal()
                    return nil
                }

                if fileSize > UInt64(maxFileSize) {
                    let alert = NSAlert()
                    alert.messageText = "File too large"
                    alert.informativeText = "Selected file exceeds maximum allowed size (\(maxFileSize) bytes)"
                    alert.alertStyle = .warning
                    alert.runModal()
                    return nil
                }

                return url
            }
        }

        return nil
    }
}

// 10. Comprehensive File Dialog Manager
class FileDialogManager {

    enum DialogMode {
        case open
        case save
        case selectFolder
        case selectMultiple
    }

    struct DialogConfig {
        var title: String = "Select File"
        var message: String? = nil
        var defaultName: String = "untitled"
        var allowedTypes: [String]? = nil
        var allowsMultiple: Bool = false
        var canSelectFolders: Bool = false
        var startDirectory: URL? = nil
        var prompt: String? = nil

        static func openDialog(title: String = "Open",
                               message: String? = nil,
                               types: [String]? = nil,
                               multiple: Bool = false) -> DialogConfig {
            var config = DialogConfig()
            config.title = title
            config.message = message
            config.allowedTypes = types
            config.allowsMultiple = multiple
            return config
        }

        static func saveDialog(title: String = "Save",
                               defaultName: String = "untitled",
                               types: [String]? = nil) -> DialogConfig {
            var config = DialogConfig()
            config.title = title
            config.defaultName = defaultName
            config.allowedTypes = types
            return config
        }
    }

    func show(mode: DialogMode, config: DialogConfig) -> [URL]? {
        print("\n--- File Dialog Manager ---")
        print("Mode: \(mode), Title: \(config.title)")

        switch mode {
        case .open, .selectMultiple:
            let panel = NSOpenPanel()
            panel.title = config.title
            panel.message = config.message
            panel.canChooseFiles = !config.canSelectFolders
            panel.canChooseDirectories = config.canSelectFolders
            panel.allowsMultipleSelection = config.allowsMultiple
            panel.allowedFileTypes = config.allowedTypes
            if let prompt = config.prompt {
                panel.prompt = prompt
            }
            panel.directoryURL = config.startDirectory

            let response = panel.runModal()
            if response == .OK {
                return panel.urls.isEmpty ? nil : panel.urls
            }

        case .save:
            let panel = NSSavePanel()
            panel.title = config.title
            panel.message = config.message
            panel.nameFieldStringValue = config.defaultName
            panel.allowedFileTypes = config.allowedTypes
            panel.directoryURL = config.startDirectory
            if let prompt = config.prompt {
                panel.prompt = prompt
            }

            let response = panel.runModal()
            if response == .OK, let url = panel.url {
                return [url]
            }

        case .selectFolder:
            let panel = NSOpenPanel()
            panel.title = config.title
            panel.canChooseFiles = false
            panel.canChooseDirectories = true
            panel.allowsMultipleSelection = config.allowsMultiple
            panel.directoryURL = config.startDirectory

            let response = panel.runModal()
            if response == .OK {
                return panel.urls.isEmpty ? nil : panel.urls
            }
        }

        return nil
    }
}

// Main demonstration
func demonstrateFileDialogs() {
    print("=== macOS Swift File Dialogs Examples ===")

    let manager = FileDialogManager()

    // Note: These dialogs require GUI context
    print("\nNote: Dialogs require NSApplication context")
    print("The following examples show the implementation pattern")

    // Example configurations
    print("\n--- Example Configurations ---")

    let openConfig = FileDialogManager.DialogConfig.openDialog(
        title: "Open Image",
        message: "Select an image file",
        types: ["jpg", "jpeg", "png", "gif"],
        multiple: true
    )
    print("Open config: \(openConfig.title), types: \(openConfig.allowedTypes ?? [])")

    let saveConfig = FileDialogManager.DialogConfig.saveDialog(
        title: "Save Document",
        defaultName: "document.txt",
        types: ["txt", "md"]
    )
    print("Save config: \(saveConfig.title), default: \(saveConfig.defaultName)")

    print("\n=== All File Dialog Examples Completed ===")
}

// Run demonstration
demonstrateFileDialogs()

💻 Bandeja do Sistema swift

🟡 intermediate ⭐⭐⭐

Criar e gerenciar aplicações de barra de menu com NSStatusItem

⏱️ 35 min 🏷️ swift, macos, desktop, gui
Prerequisites: Intermediate Swift, Cocoa/AppKit
// macOS Swift System Tray Examples
// Creating and managing menu bar applications with NSStatusItem

import Cocoa
import Foundation

// 1. Basic Status Item
class BasicStatusItem {

    private var statusItem: NSStatusItem?

    func createStatusItem() {
        print("\n--- Basic Status Item ---")

        statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)

        if let button = statusItem?.button {
            button.title = "🔔"
            print("Status item created with icon")
        }
    }

    func removeStatusItem() {
        print("\n--- Removing Status Item ---")

        if let statusItem = statusItem {
            NSStatusBar.system.removeStatusItem(statusItem)
            self.statusItem = nil
            print("Status item removed")
        }
    }
}

// 2. Status Item with Menu
class StatusItemWithMenu {

    private var statusItem: NSStatusItem?

    func createWithMenu() {
        print("\n--- Status Item with Menu ---")

        statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)

        if let button = statusItem?.button {
            button.title = "⚙️"
        }

        let menu = NSMenu()

        menu.addItem(NSMenuItem(title: "About", action: #selector(showAbout), keyEquivalent: ""))
        menu.addItem(NSMenuItem.separator())
        menu.addItem(NSMenuItem(title: "Preferences", action: #selector(showPreferences), keyEquivalent: ","))
        menu.addItem(NSMenuItem.separator())
        menu.addItem(NSMenuItem(title: "Quit", action: #selector(quitApplication), keyEquivalent: "q"))

        statusItem?.menu = menu

        print("Menu created with 4 items")
    }

    @objc private func showAbout() {
        print("Menu action: About")
        showAlert(message: "About this application")
    }

    @objc private func showPreferences() {
        print("Menu action: Preferences")
        showAlert(message: "Open preferences")
    }

    @objc private func quitApplication() {
        print("Menu action: Quit")
        NSApplication.shared.terminate(nil)
    }

    private func showAlert(message: String) {
        let alert = NSAlert()
        alert.messageText = message
        alert.alertStyle = .informational
        alert.runModal()
    }

    func cleanup() {
        if let statusItem = statusItem {
            NSStatusBar.system.removeStatusItem(statusItem)
        }
    }
}

// 3. Status Item with Custom View
class StatusItemWithCustomView {

    private var statusItem: NSStatusItem?
    private var clickCount = 0

    func createWithCustomView() {
        print("\n--- Status Item with Custom View ---")

        statusItem = NSStatusBar.system.statusItem(withLength: 60)

        guard let button = statusItem?.button else {
            print("Failed to get status item button")
            return
        }

        button.title = ""
        button.action = #selector(statusItemClicked)
        button.target = self

        // Create custom view
        let customView = NSView(frame: NSRect(x: 0, y: 0, width: 60, height: 20))
        customView.wantsLayer = true
        customView.layer?.backgroundColor = NSColor.controlBackgroundColor.cgColor
        customView.layer?.cornerRadius = 5

        let label = NSTextField(labelWithString: "Menu")
        label.frame = NSRect(x: 10, y: 2, width: 40, height: 16)
        label.alignment = .center
        customView.addSubview(label)

        button.addSubview(customView)

        print("Custom view status item created")
    }

    @objc private func statusItemClicked() {
        clickCount += 1
        print("Status item clicked (count: \(clickCount))")

        let menu = NSMenu()
        menu.addItem(NSMenuItem(title: "Clicked \(clickCount) times", action: nil, keyEquivalent: ""))
        menu.addItem(NSMenuItem.separator())
        menu.addItem(NSMenuItem(title: "Reset", action: #selector(resetCounter), keyEquivalent: ""))

        statusItem?.menu = menu
        statusItem?.button?.performClick(nil)
    }

    @objc private func resetCounter() {
        clickCount = 0
        print("Counter reset")
    }

    func cleanup() {
        if let statusItem = statusItem {
            NSStatusBar.system.removeStatusItem(statusItem)
        }
    }
}

// 4. Dynamic Menu
class DynamicStatusMenu {

    private var statusItem: NSStatusItem?

    func createDynamicMenu() {
        print("\n--- Dynamic Status Menu ---")

        statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)

        if let button = statusItem?.button {
            button.title = "📊"
        }

        refreshMenu()
    }

    func refreshMenu() {
        let menu = NSMenu()

        // Dynamic timestamp
        let dateFormatter = DateFormatter()
        dateFormatter.timeStyle = .medium
        let timeString = dateFormatter.string(from: Date())

        menu.addItem(NSMenuItem(title: "Time: \(timeString)", action: nil, keyEquivalent: ""))
        menu.addItem(NSMenuItem.separator())

        // Dynamic system info
        let memoryUsage = getMemoryUsage()
        menu.addItem(NSMenuItem(title: "Memory: \(memoryUsage)", action: nil, keyEquivalent: ""))

        menu.addItem(NSMenuItem.separator())
        menu.addItem(NSMenuItem(title: "Refresh", action: #selector(refreshClicked), keyEquivalent: "r"))
        menu.addItem(NSMenuItem.separator())
        menu.addItem(NSMenuItem(title: "Quit", action: #selector(quitApplication), keyEquivalent: "q"))

        statusItem?.menu = menu
    }

    private func getMemoryUsage() -> String {
        let task = ProcessInfo.processInfo
        let used = UInt64(task.physicalMemory)
        let formatted = ByteCountFormatter.string(fromByteCount: Int64(used), countStyle: .memory)
        return formatted
    }

    @objc private func refreshClicked() {
        print("Refreshing menu...")
        refreshMenu()
    }

    @objc private func quitApplication() {
        NSApplication.shared.terminate(nil)
    }

    func cleanup() {
        if let statusItem = statusItem {
            NSStatusBar.system.removeStatusItem(statusItem)
        }
    }
}

// 5. Status Item with Toggle
class ToggleStatusItem {

    private var statusItem: NSStatusItem?
    private var isEnabled = false

    func createToggleItem() {
        print("\n--- Toggle Status Item ---")

        statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
        updateIcon()

        let menu = NSMenu()
        let toggleItem = NSMenuItem(
            title: "Enable",
            action: #selector(toggleEnabled),
            keyEquivalent: ""
        )
        toggleItem.tag = 1
        menu.addItem(toggleItem)
        menu.addItem(NSMenuItem.separator())
        menu.addItem(NSMenuItem(title: "Quit", action: #selector(quitApplication), keyEquivalent: "q"))

        statusItem?.menu = menu
    }

    @objc private func toggleEnabled() {
        isEnabled.toggle()
        updateIcon()
        updateMenuItem()

        print("Toggled: \(isEnabled ? "Enabled" : "Disabled")")
    }

    private func updateIcon() {
        statusItem?.button?.title = isEnabled ? "🟢" : "🔴"
    }

    private func updateMenuItem() {
        guard let menu = statusItem?.menu,
              let item = menu.item(withTag: 1) else { return }

        item.title = isEnabled ? "Disable" : "Enable"
    }

    @objc private func quitApplication() {
        NSApplication.shared.terminate(nil)
    }

    func cleanup() {
        if let statusItem = statusItem {
            NSStatusBar.system.removeStatusItem(statusItem)
        }
    }
}

// 6. Status Item with Popover
class PopoverStatusItem {

    private var statusItem: NSStatusItem?
    private var popover: NSPopover?

    func createWithPopover() {
        print("\n--- Status Item with Popover ---")

        statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)

        if let button = statusItem?.button {
            button.title = "ℹ️"
            button.action = #selector(togglePopover)
            button.target = self
        }

        // Create popover
        popover = NSPopover()
        popover?.contentSize = NSSize(width: 300, height: 200)
        popover?.behavior = .transient
        popover?.contentViewController = PopoverViewController()
    }

    @objc private func togglePopover() {
        guard let button = statusItem?.button else { return }

        if let popover = popover, popover.isShown {
            popover.performClose(nil)
        } else {
            popover?.show(relativeTo: button.bounds, of: button, preferredEdge: .minY)
        }
    }

    func cleanup() {
        popover?.close()
        if let statusItem = statusItem {
            NSStatusBar.system.removeStatusItem(statusItem)
        }
    }
}

// Popover View Controller
class PopoverViewController: NSViewController {
    override func loadView() {
        view = NSView(frame: NSRect(x: 0, y: 0, width: 300, height: 200))

        let label = NSTextField(labelWithString: "Popover Content")
        label.frame = NSRect(x: 20, y: 150, width: 260, height: 30)
        label.alignment = .center
        label.font = NSFont.boldSystemFont(ofSize: 16)
        view.addSubview(label)

        let info = NSTextField(labelWithString: "This is a popover window.")
        info.frame = NSRect(x: 20, y: 100, width: 260, height: 20)
        info.alignment = .center
        view.addSubview(info)

        let closeButton = NSButton(frame: NSRect(x: 100, y: 20, width: 100, height: 30))
        closeButton.title = "Close"
        closeButton.target = self
        closeButton.action = #selector(closePopover)
        view.addSubview(closeButton)
    }

    @objc private func closePopover() {
        if let popover = presentingViewController as? NSPopover {
            popover.performClose(nil)
        }
    }
}

// 7. Status Item with Badge
class BadgedStatusItem {

    private var statusItem: NSStatusItem?
    private var badgeCount = 0

    func createBadgedItem() {
        print("\n--- Badged Status Item ---")

        statusItem = NSStatusBar.system.statusItem(withLength: 40)

        updateBadge()

        let menu = NSMenu()
        menu.addItem(NSMenuItem(title: "Increment", action: #selector(incrementBadge), keyEquivalent: "+"))
        menu.addItem(NSMenuItem(title: "Decrement", action: #selector(decrementBadge), keyEquivalent: "-"))
        menu.addItem(NSMenuItem.separator())
        menu.addItem(NSMenuItem(title: "Clear", action: #selector(clearBadge), keyEquivalent: "0"))
        menu.addItem(NSMenuItem.separator())
        menu.addItem(NSMenuItem(title: "Quit", action: #selector(quitApplication), keyEquivalent: "q"))

        statusItem?.menu = menu
    }

    private func updateBadge() {
        guard let button = statusItem?.button else { return }

        if badgeCount > 0 {
            button.title = "\(badgeCount)"
            // Add red circle effect
            button.wantsLayer = true
            button.layer?.backgroundColor = NSColor.red.cgColor
            button.layer?.cornerRadius = 10
        } else {
            button.title = "📬"
            button.layer?.backgroundColor = nil
        }

        print("Badge count: \(badgeCount)")
    }

    @objc private func incrementBadge() {
        badgeCount += 1
        updateBadge()
    }

    @objc private func decrementBadge() {
        badgeCount = max(0, badgeCount - 1)
        updateBadge()
    }

    @objc private func clearBadge() {
        badgeCount = 0
        updateBadge()
    }

    @objc private func quitApplication() {
        NSApplication.shared.terminate(nil)
    }

    func cleanup() {
        if let statusItem = statusItem {
            NSStatusBar.system.removeStatusItem(statusItem)
        }
    }
}

// 8. Status Item with Tooltip
class TooltipStatusItem {

    private var statusItem: NSStatusItem?

    func createWithTooltip() {
        print("\n--- Status Item with Tooltip ---")

        statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)

        if let button = statusItem?.button {
            button.title = "💡"
            button.toolTip = "Click for options"
        }

        let menu = NSMenu()

        let infoItem = NSMenuItem(title: "System Information", action: nil, keyEquivalent: "")
        infoItem.toolTip = "View detailed system info"
        menu.addItem(infoItem)

        let prefItem = NSMenuItem(title: "Settings", action: nil, keyEquivalent: "")
        prefItem.toolTip = "Open application settings"
        menu.addItem(prefItem)

        menu.addItem(NSMenuItem.separator())
        menu.addItem(NSMenuItem(title: "Quit", action: #selector(quitApplication), keyEquivalent: "q"))

        statusItem?.menu = menu

        print("Tooltip status item created")
    }

    @objc private func quitApplication() {
        NSApplication.shared.terminate(nil)
    }

    func updateTooltip(_ tooltip: String) {
        statusItem?.button?.toolTip = tooltip
        print("Tooltip updated: \(tooltip)")
    }

    func cleanup() {
        if let statusItem = statusItem {
            NSStatusBar.system.removeStatusItem(statusItem)
        }
    }
}

// 9. Animated Status Item
class AnimatedStatusItem {

    private var statusItem: NSStatusItem?
    private var frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]
    private var currentFrame = 0
    private var timer: Timer?
    private var isAnimating = false

    func createAnimatedItem() {
        print("\n--- Animated Status Item ---")

        statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)

        if let button = statusItem?.button {
            button.title = frames[0]
        }

        let menu = NSMenu()
        menu.addItem(NSMenuItem(title: "Start Animation", action: #selector(startAnimation), keyEquivalent: "s"))
        menu.addItem(NSMenuItem(title: "Stop Animation", action: #selector(stopAnimation), keyEquivalent: "x"))
        menu.addItem(NSMenuItem.separator())
        menu.addItem(NSMenuItem(title: "Quit", action: #selector(quitApplication), keyEquivalent: "q"))

        statusItem?.menu = menu
    }

    @objc private func startAnimation() {
        guard !isAnimating else { return }

        isAnimating = true
        timer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { [weak self] _ in
            self?.updateFrame()
        }

        print("Animation started")
    }

    @objc private func stopAnimation() {
        isAnimating = false
        timer?.invalidate()
        timer = nil

        statusItem?.button?.title = "⏸"
        print("Animation stopped")
    }

    private func updateFrame() {
        currentFrame = (currentFrame + 1) % frames.count
        statusItem?.button?.title = frames[currentFrame]
    }

    @objc private func quitApplication() {
        stopAnimation()
        NSApplication.shared.terminate(nil)
    }

    func cleanup() {
        stopAnimation()
        if let statusItem = statusItem {
            NSStatusBar.system.removeStatusItem(statusItem)
        }
    }
}

// 10. Complete Menu Bar Application
class MenuBarApplication {

    private var statusItem: NSStatusItem?
    private var appState: AppState = AppState()

    func create() {
        print("\n--- Complete Menu Bar Application ---")

        statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)

        if let button = statusItem?.button {
            button.title = "🚀"
        }

        buildMenu()
        setupNotifications()
    }

    private func buildMenu() {
        let menu = NSMenu()

        // App section
        menu.addItem(NSMenuItem(title: "About", action: #selector(showAbout), keyEquivalent: ""))
        menu.addItem(NSMenuItem.separator())

        // Features section
        menu.addItem(NSMenuItem(title: "Connect", action: #selector(toggleConnection), keyEquivalent: "c"))
        menu.addItem(NSMenuItem(title: "Sync", action: #selector(syncData), keyEquivalent: "s"))
        menu.addItem(NSMenuItem.separator())

        // Status section
        menu.addItem(NSMenuItem(title: "Status: \(appState.status)", action: nil, keyEquivalent: ""))
        menu.addItem(NSMenuItem.separator())

        // Preferences
        menu.addItem(NSMenuItem(title: "Preferences...", action: #selector(showPreferences), keyEquivalent: ","))

        // Quit
        menu.addItem(NSMenuItem.separator())
        menu.addItem(NSMenuItem(title: "Quit", action: #selector(quitApplication), keyEquivalent: "q"))

        statusItem?.menu = menu
    }

    private func setupNotifications() {
        NotificationCenter.default.addObserver(
            self,
            selector: #selector(statusChanged),
            name: .statusDidChange,
            object: nil
        )
    }

    @objc private func showAbout() {
        print("Menu: About")
        showAlert(message: "Menu Bar Application v1.0")
    }

    @objc private func toggleConnection() {
        appState.isConnected.toggle()
        print("Toggled connection: \(appState.isConnected)")

        updateStatusIcon()
        buildMenu()
    }

    @objc private func syncData() {
        print("Syncing data...")
        showAlert(message: "Sync completed")
    }

    @objc private func showPreferences() {
        print("Menu: Preferences")
        showAlert(message: "Open preferences window")
    }

    @objc private func quitApplication() {
        NSApplication.shared.terminate(nil)
    }

    @objc private func statusChanged() {
        print("Status changed: \(appState.status)")
        buildMenu()
    }

    private func updateStatusIcon() {
        statusItem?.button?.title = appState.isConnected ? "🟢" : "🔴"
    }

    private func showAlert(message: String) {
        let alert = NSAlert()
        alert.messageText = message
        alert.alertStyle = .informational
        alert.runModal()
    }

    func cleanup() {
        NotificationCenter.default.removeObserver(self)
        if let statusItem = statusItem {
            NSStatusBar.system.removeStatusItem(statusItem)
        }
    }
}

// Application State
class AppState {
    var isConnected = false
    var status: String {
        return isConnected ? "Connected" : "Disconnected"
    }
}

extension Notification.Name {
    static let statusDidChange = Notification.Name("statusDidChange")
}

// Main demonstration
func demonstrateSystemTray() {
    print("=== macOS Swift System Tray Examples ===")

    // Note: System tray items require NSApplication context
    print("\nNote: Status items require NSApplication context")
    print("The following examples show the implementation pattern")

    print("\n--- Example Configurations ---")

    print("1. Basic Status Item - Simple icon in menu bar")
    print("2. Status Item with Menu - Dropdown menu with actions")
    print("3. Custom View - Custom view with click handling")
    print("4. Dynamic Menu - Menu that updates dynamically")
    print("5. Toggle Status Item - Toggle between states")
    print("6. Popover - Show popover window on click")
    print("7. Badge - Show notification badge count")
    print("8. Tooltip - Show tooltip on hover")
    print("9. Animated Item - Animated status icon")
    print("10. Complete App - Full menu bar application")

    print("\n=== All System Tray Examples Completed ===")
}

// Run demonstration
demonstrateSystemTray()