Fonctionnalités Mobiles macOS Swift - Exemples

Exemples de fonctionnalités mobiles macOS Swift incluant informations appareil, état réseau et retour vibration

💻 Récupération Informations Appareil swift

🟢 simple ⭐⭐⭐

Obtenir informations complètes appareil incluant modèle, version OS, capacités matérielles et spécifications système

⏱️ 25 min 🏷️ swift, macos, ios, mobile, device
Prerequisites: Swift basics, Foundation framework, iOS/macOS APIs
// macOS/iOS Swift Device Information Examples
// Using Foundation, UIKit, and SystemConfiguration frameworks

#if os(iOS)
import UIKit
import UIKit.UIDevice
#endif

#if os(macOS)
import AppKit
import IOKit
import IOKit.ps
#endif

import Foundation
import SystemConfiguration

// 1. Basic Device Information
class DeviceInformation {

    #if os(iOS)
    // iOS Device Information
    static func getIOSDeviceInfo() -> DeviceInfo {
        let device = UIDevice.current
        var info = DeviceInfo()

        info.platform = "iOS"
        info.name = device.name
        info.systemName = device.systemName
        info.systemVersion = device.systemVersion
        info.model = device.model
        info.localizedModel = device.localizedModel
        info.userInterfaceIdiom = device.userInterfaceIdiom == .phone ? "iPhone" : "iPad"

        // Battery state
        info.batteryLevel = device.batteryLevel
        info.batteryState = device.batteryState.rawValue
        device.isBatteryMonitoringEnabled = true

        // Screen info
        let screen = UIScreen.main
        info.screenBounds = screen.bounds
        info.screenScale = screen.scale
        info.brightness = screen.brightness

        return info
    }
    #endif

    #if os(macOS)
    // macOS Device Information
    static func getMacOSDeviceInfo() -> DeviceInfo {
        var info = DeviceInfo()
        info.platform = "macOS"

        // Get system info using ProcessInfo
        let processInfo = ProcessInfo.processInfo
        info.systemName = "macOS"
        info.systemVersion = processInfo.operatingSystemVersionString
        info.hostName = processInfo.hostName
        info.physicalMemory = getPhysicalMemory()
        info.processorCount = processInfo.processorCount
        info.activeProcessorCount = processInfo.activeProcessorCount

        // Get hardware info
        let hardwareInfo = getHardwareInfo()
        info.model = hardwareInfo.model
        info.cpuType = hardwareInfo.cpuType
        info.cpuFrequency = hardwareInfo.cpuFrequency

        // Get serial number
        info.serialNumber = getSerialNumber()

        return info
    }

    // Get physical memory
    static func getPhysicalMemory() -> UInt64 {
        var size: UInt64 = 0
        var mib: [Int32] = [CTL_HW, HW_MEMSIZE]
        var len = MemoryLayout<UInt64>.size

        sysctl(&mib, u_int(mib.count), &size, &len, nil, 0)

        return size
    }

    // Get hardware information
    static func getHardwareInfo() -> (model: String, cpuType: String, cpuFrequency: String) {
        var size = 0
        sysctlbyname("hw.model", nil, &size, nil, 0)

        var model = [CChar](repeating: 0, count: size)
        sysctlbyname("hw.model", &model, &size, nil, 0)
        let modelString = String(cString: model)

        // Get CPU info
        var cpufamily: UInt32 = 0
        var cpufamily_size = MemoryLayout<UInt32>.size
        sysctlbyname("hw.cpufamily", &cpufamily, &cpufamily_size, nil, 0)

        var cpufrequency: Int64 = 0
        var cpufrequency_size = MemoryLayout<Int64>.size
        sysctlbyname("hw.cpufrequency", &cpufrequency, &cpufrequency_size, nil, 0)

        let cpuFreqGHz = Double(cpufrequency) / 1_000_000_000

        return (modelString, "CPU Family: \(cpufamily)", String(format: "%.2f GHz", cpuFreqGHz))
    }

    // Get serial number
    static func getSerialNumber() -> String {
        let platformExpert = IOServiceGetMatchingService(kIOMasterPortDefault,
                                                           IOServiceMatching("IOPlatformExpertDevice"))

        defer { IOObjectRelease(platformExpert) }

        guard platformExpert != 0 else { return "Unknown" }

        let serialNumberAsCFString = IORegistryEntryCreateCFProperty(platformExpert,
                                                                     kIOPlatformSerialNumberKey as CFString,
                                                                     kCFAllocatorDefault,
                                                                     0)

        guard let serialNumber = serialNumberAsCFString?.takeUnretainedValue() as? String else {
            return "Unknown"
        }

        return serialNumber
    }
    #endif

    // Get common system info
    static func getSystemInfo() -> SystemInfo {
        var sysInfo = SystemInfo()

        let processInfo = ProcessInfo.processInfo
        sysInfo.upTime = processInfo.systemUptime
        sysInfo.processorCount = processInfo.processorCount
        sysInfo.activeProcessorCount = processInfo.activeProcessorCount
        sysInfo.arguments = processInfo.arguments
        sysInfo.environment = processInfo.environment
        sysInfo.processName = processInfo.processName
        sysInfo.globalNumberOfRunningTasks = ProcessInfo.processInfo.processorCount

        return sysInfo
    }

    // Get memory usage
    static func getMemoryUsage() -> MemoryUsage {
        var stats = vm_statistics64()
        var count = UInt32(MemoryLayout<vm_statistics64>.size / MemoryLayout<integer_t>.size)

        let result = withUnsafeMutablePointer(to: &stats) {
            $0.withMemoryRebound(to: integer_t.self, capacity: Int(count)) {
                host_statistics64(mach_host_self(), HOST_VM_INFO64, $0, &count)
            }
        }

        guard result == KERN_SUCCESS else {
            return MemoryUsage()
        }

        let pageSize = vm_kernel_page_size
        let totalMemory = getPhysicalMemory()

        let usedMemory = UInt64(stats.active_count + stats.wire_count) * UInt64(pageSize)
        let freeMemory = UInt64(stats.free_count) * UInt64(pageSize)
        let cachedMemory = UInt64(stats.inactive_count + stats.speculative_count) * UInt64(pageSize)

        return MemoryUsage(
            total: totalMemory,
            used: usedMemory,
            free: freeMemory,
            cached: cachedMemory,
            active: UInt64(stats.active_count) * UInt64(pageSize),
            wired: UInt64(stats.wire_count) * UInt64(pageSize)
        )
    }
}

// 2. Network Status Monitoring
class NetworkStatus {

    // Check if network is available
    static func isNetworkAvailable() -> Bool {
        var zeroAddress = sockaddr_in()
        zeroAddress.sin_len = UInt8(MemoryLayout<sockaddr_in>.size)
        zeroAddress.sin_family = sa_family_t(AF_INET)

        guard let defaultRouteReachability = withUnsafePointer(to: &zeroAddress, {
            $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
                SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, $0)
            }
        }) else {
            return false
        }

        var flags: SCNetworkReachabilityFlags = []
        if !SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags) {
            return false
        }

        let isReachable = flags.contains(.reachable)
        let needsConnection = flags.contains(.connectionRequired)

        return isReachable && !needsConnection
    }

    // Get detailed network status
    static func getNetworkStatus() -> NetworkStatusInfo {
        var status = NetworkStatusInfo()

        // Check reachability
        status.isReachable = isNetworkAvailable()

        // Get connection type
        status.connectionType = getConnectionType()

        // Check WiFi status (iOS only)
        #if os(iOS)
        status.isWiFiEnabled = isWiFiEnabled()
        #endif

        return status
    }

    // Get connection type
    static func getConnectionType() -> String {
        var zeroAddress = sockaddr_in()
        zeroAddress.sin_len = UInt8(MemoryLayout<sockaddr_in>.size)
        zeroAddress.sin_family = sa_family_t(AF_INET)

        guard let defaultRouteReachability = withUnsafePointer(to: &zeroAddress, {
            $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
                SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, $0)
            }
        }) else {
            return "Unknown"
        }

        var flags: SCNetworkReachabilityFlags = []
        if !SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags) {
            return "Unknown"
        }

        let isWWAN = flags.contains(.isWWAN)
        let isReachable = flags.contains(.reachable)

        if isReachable && isWWAN {
            return "Cellular"
        } else if isReachable {
            return "WiFi"
        } else {
            return "No Connection"
        }
    }

    #if os(iOS)
    // Check if WiFi is enabled
    static func isWiFiEnabled() -> Bool {
        var zeroAddress = sockaddr_in()
        zeroAddress.sin_len = UInt8(MemoryLayout<sockaddr_in>.size)
        zeroAddress.sin_family = sa_family_t(AF_INET)

        guard let defaultRouteReachability = withUnsafePointer(to: &zeroAddress, {
            $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
                SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, $0)
            }
        }) else {
            return false
        }

        var flags: SCNetworkReachabilityFlags = []
        if !SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags) {
            return false
        }

        return flags.contains(.reachable) && !flags.contains(.isWWAN)
    }
    #endif

    // Monitor network changes
    static func startNetworkMonitoring(callback: @escaping (NetworkStatusInfo) -> Void) {
        var zeroAddress = sockaddr_in()
        zeroAddress.sin_len = UInt8(MemoryLayout<sockaddr_in>.size)
        zeroAddress.sin_family = sa_family_t(AF_INET)

        guard let defaultRouteReachability = withUnsafePointer(to: &zeroAddress, {
            $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
                SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, $0)
            }
        }) else {
            return
        }

        var context = NetworkCallbackContext(callback: callback)

        SCNetworkReachabilitySetCallback(
            defaultRouteReachability,
            { (_, flags, info) in
                guard let info = info else { return }

                let context = info.assumingMemoryBound(to: NetworkCallbackContext.self).pointee
                let status = NetworkStatusInfo(
                    isReachable: flags.contains(.reachable),
                    connectionType: flags.contains(.isWWAN) ? "Cellular" : "WiFi",
                    isWiFiEnabled: !flags.contains(.isWWAN) && flags.contains(.reachable)
                )
                context.callback(status)
            },
            &context
        )

        SCNetworkReachabilityScheduleWithRunLoop(defaultRouteReachability, CFRunLoopGetMain(), CFRunLoopMode.commonModes.rawValue)
    }
}

// 3. Vibration and Haptic Feedback
class VibrationController {

    #if os(iOS)
    // Basic vibration
    static func vibrate() {
        AudioServicesPlaySystemSound(kSystemSoundID_Vibrate)
    }

    // Vibrate with pattern
    static func vibrate(pattern: [VibrationPattern]) {
        for item in pattern {
            DispatchQueue.main.asyncAfter(deadline: .now() + item.delay) {
                if item.vibrate {
                    AudioServicesPlaySystemSound(kSystemSoundID_Vibrate)
                }
            }
        }
    }

    // Haptic feedback (iOS 10+)
    @available(iOS 10.0, *)
    static func haptic(style: UIImpactFeedbackGenerator.FeedbackStyle) {
        let generator = UIImpactFeedbackGenerator(style: style)
        generator.prepare()
        generator.impactOccurred()
    }

    // Notification haptic
    @available(iOS 10.0, *)
    static func notificationHaptic(type: UINotificationFeedbackGenerator.FeedbackType) {
        let generator = UINotificationFeedbackGenerator()
        generator.prepare()
        generator.notificationOccurred(type)
    }

    // Selection haptic
    @available(iOS 10.0, *)
    static func selectionHaptic() {
        let generator = UISelectionFeedbackGenerator()
        generator.prepare()
        generator.selectionChanged()
    }
    #else
    // macOS doesn't support vibration, but we can provide audio feedback
    static func vibrate() {
        print("Vibration not supported on macOS")
        // Play system sound instead
        NSSound.beep()
    }

    static func vibrate(pattern: [VibrationPattern]) {
        print("Vibration pattern not supported on macOS")
        NSSound.beep()
    }
    #endif

    // Predefined vibration patterns
    static func successVibration() {
        #if os(iOS)
        if #available(iOS 10.0, *) {
            notificationHaptic(type: .success)
        } else {
            vibrate()
        }
        #else
        NSSound.beep()
        #endif
    }

    static func errorVibration() {
        #if os(iOS)
        if #available(iOS 10.0, *) {
            notificationHaptic(type: .error)
        } else {
            vibrate(pattern: [
                VibrationPattern(vibrate: true, delay: 0),
                VibrationPattern(vibrate: false, delay: 0.1),
                VibrationPattern(vibrate: true, delay: 0.1)
            ])
        }
        #else
        NSSound.beep()
        NSSound.beep()
        #endif
    }

    static func warningVibration() {
        #if os(iOS)
        if #available(iOS 10.0, *) {
            notificationHaptic(type: .warning)
        } else {
            vibrate()
        }
        #else
        NSSound.beep()
        #endif
    }
}

// Data Structures
struct DeviceInfo {
    var platform: String = ""
    var name: String = ""
    var systemName: String = ""
    var systemVersion: String = ""
    var model: String = ""
    var localizedModel: String = ""
    var userInterfaceIdiom: String = ""
    var batteryLevel: Float = -1
    var batteryState: Int = 0
    var screenBounds: CGRect = .zero
    var screenScale: CGFloat = 1.0
    var brightness: CGFloat = 0.5
    var hostName: String = ""
    var physicalMemory: UInt64 = 0
    var processorCount: Int = 0
    var activeProcessorCount: Int = 0
    var cpuType: String = ""
    var cpuFrequency: String = ""
    var serialNumber: String = ""
}

struct SystemInfo {
    var upTime: TimeInterval = 0
    var processorCount: Int = 0
    var activeProcessorCount: Int = 0
    var arguments: [String] = []
    var environment: [String: String] = [:]
    var processName: String = ""
    var globalNumberOfRunningTasks: Int = 0
}

struct MemoryUsage {
    var total: UInt64 = 0
    var used: UInt64 = 0
    var free: UInt64 = 0
    var cached: UInt64 = 0
    var active: UInt64 = 0
    var wired: UInt64 = 0
}

struct NetworkStatusInfo {
    var isReachable: Bool = false
    var connectionType: String = "Unknown"
    var isWiFiEnabled: Bool = false
}

struct VibrationPattern {
    var vibrate: Bool
    var delay: TimeInterval
}

struct NetworkCallbackContext {
    var callback: (NetworkStatusInfo) -> Void
}

// Constants
let CTL_HW: Int32 = 6
let HW_MEMSIZE: Int32 = 24

// Helper function
func sysctlbyname(_ name: String, _ oldp: UnsafeMutableRawPointer?, _ oldlenp: UnsafeMutablePointer<Int>?, _ newp: UnsafeRawPointer?, _ newlen: Int) -> Int32 {
    return Darwin.sysctlbyname(name, oldp, oldlenp, newp, newlen)
}

func sysctl(_ name: UnsafeMutablePointer<Int32>, _ namelen: UInt, _ oldp: UnsafeMutableRawPointer?, _ oldlenp: UnsafeMutablePointer<Int>, _ newp: UnsafeRawPointer?, _ newlen: Int) -> Int32 {
    return Darwin.sysctl(name, namelen, oldp, oldlenp, newp, newlen)
}

// Main demonstration
func demonstrateDeviceFeatures() {
    print("=== macOS/iOS Swift Device Features ===\n")

    // 1. Device Information
    print("--- 1. Device Information ---")
    #if os(iOS)
    let deviceInfo = DeviceInformation.getIOSDeviceInfo()
    print("Platform: \(deviceInfo.platform)")
    print("Name: \(deviceInfo.name)")
    print("System: \(deviceInfo.systemName) \(deviceInfo.systemVersion)")
    print("Model: \(deviceInfo.model)")
    print("Idiom: \(deviceInfo.userInterfaceIdiom)")
    print("Battery: \(deviceInfo.batteryLevel * 100)%")
    #elseif os(macOS)
    let deviceInfo = DeviceInformation.getMacOSDeviceInfo()
    print("Platform: \(deviceInfo.platform)")
    print("System: \(deviceInfo.systemVersion)")
    print("Host Name: \(deviceInfo.hostName)")
    print("Model: \(deviceInfo.model)")
    print("CPU: \(deviceInfo.cpuType)")
    print("CPU Frequency: \(deviceInfo.cpuFrequency)")
    print("Serial Number: \(deviceInfo.serialNumber)")
    print("Processors: \(deviceInfo.processorCount)")
    print("Physical Memory: \(formatBytes(deviceInfo.physicalMemory))")
    #endif

    // 2. System Info
    print("\n--- 2. System Information ---")
    let sysInfo = DeviceInformation.getSystemInfo()
    print("Uptime: \(formatUptime(sysInfo.upTime))")
    print("Processors: \(sysInfo.processorCount)")
    print("Active Processors: \(sysInfo.activeProcessorCount)")
    print("Process Name: \(sysInfo.processName)")

    // 3. Memory Usage
    print("\n--- 3. Memory Usage ---")
    let memory = DeviceInformation.getMemoryUsage()
    print("Total: \(formatBytes(memory.total))")
    print("Used: \(formatBytes(memory.used))")
    print("Free: \(formatBytes(memory.free))")
    print("Cached: \(formatBytes(memory.cached))")
    print("Active: \(formatBytes(memory.active))")
    print("Wired: \(formatBytes(memory.wired))")

    // 4. Network Status
    print("\n--- 4. Network Status ---")
    let networkStatus = NetworkStatus.getNetworkStatus()
    print("Reachable: \(networkStatus.isReachable)")
    print("Connection Type: \(networkStatus.connectionType)")
    #if os(iOS)
    print("WiFi Enabled: \(networkStatus.isWiFiEnabled)")
    #endif

    // 5. Vibration Test
    print("\n--- 5. Vibration Test ---")
    print("Testing vibration...")
    VibrationController.vibrate()

    DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
        print("Testing success vibration...")
        VibrationController.successVibration()

        DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
            print("Testing warning vibration...")
            VibrationController.warningVibration()

            DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
                print("Testing error vibration...")
                VibrationController.errorVibration()
            }
        }
    }

    print("\n=== Device Features Demo Completed ===")
}

// Helper functions
func formatBytes(_ bytes: UInt64) -> String {
    let kb = Double(bytes) / 1024
    let mb = kb / 1024
    let gb = mb / 1024

    if gb >= 1 {
        return String(format: "%.2f GB", gb)
    } else if mb >= 1 {
        return String(format: "%.2f MB", mb)
    } else if kb >= 1 {
        return String(format: "%.2f KB", kb)
    } else {
        return "\(bytes) bytes"
    }
}

func formatUptime(_ seconds: TimeInterval) -> String {
    let days = Int(seconds) / 86400
    let hours = Int(seconds) % 86400 / 3600
    let minutes = Int(seconds) % 3600 / 60

    if days > 0 {
        return "\(days)d \(hours)h \(minutes)m"
    } else if hours > 0 {
        return "\(hours)h \(minutes)m"
    } else {
        return "\(minutes)m"
    }
}

// Run demonstration
demonstrateDeviceFeatures()

#if os(iOS)
import AVFoundation
#endif

💻 Surveillance État Réseau swift

🟡 intermediate ⭐⭐⭐

Surveiller connectivité réseau, détecter changements type de connexion et implémenter callbacks d'accessibilité

⏱️ 30 min 🏷️ swift, macos, ios, network, monitoring
Prerequisites: Swift basics, SystemConfiguration framework, Async programming
// macOS/iOS Swift Network Status Monitoring Examples
// Using SystemConfiguration and Network frameworks

import Foundation
import SystemConfiguration
#if os(iOS)
import Network
#endif

// 1. Reachability Manager
class ReachabilityManager {

    var reachability: SCNetworkReachability?
    var isMonitoring = false
    var onNetworkChange: ((Bool) -> Void)?

    // Initialize with default route
    init?() {
        var zeroAddress = sockaddr_in()
        zeroAddress.sin_len = UInt8(MemoryLayout<sockaddr_in>.size)
        zeroAddress.sin_family = sa_family_t(AF_INET)

        guard let reachability = withUnsafePointer(to: &zeroAddress, {
            $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
                SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, $0)
            }
        }) else {
            return nil
        }

        self.reachability = reachability
    }

    // Start monitoring network changes
    func startMonitoring(callback: @escaping (Bool) -> Void) {
        guard let reachability = reachability else { return }

        self.onNetworkChange = callback
        isMonitoring = true

        var context = SCNetworkReachabilityContext(
            version: 0,
            info: UnsafeMutableRawPointer(Unmanaged.passUnretained(self).toOpaque()),
            retain: nil,
            release: nil,
            copyDescription: nil
        )

        let callbackFunction: SCNetworkReachabilityCallBack = { (_, flags, info) in
            guard let info = info else { return }

            let manager = Unmanaged<ReachabilityManager>.fromOpaque(info).takeUnretainedValue()
            let isReachable = flags.contains(.reachable) && !flags.contains(.connectionRequired)

            DispatchQueue.main.async {
                manager.onNetworkChange?(isReachable)
            }
        }

        if SCNetworkReachabilitySetCallback(reachability, callbackFunction, &context) {
            SCNetworkReachabilityScheduleWithRunLoop(reachability, CFRunLoopGetMain(), CFRunLoopMode.commonModes.rawValue)
        }
    }

    // Stop monitoring
    func stopMonitoring() {
        guard let reachability = reachability, isMonitoring else { return }

        SCNetworkReachabilityUnscheduleFromRunLoop(reachability, CFRunLoopGetMain(), CFRunLoopMode.commonModes.rawValue)
        isMonitoring = false
        onNetworkChange = nil
    }

    // Check current reachability
    var isReachable: Bool {
        guard let reachability = reachability else { return false }

        var flags: SCNetworkReachabilityFlags = []
        if !SCNetworkReachabilityGetFlags(reachability, &flags) {
            return false
        }

        return flags.contains(.reachable) && !flags.contains(.connectionRequired)
    }

    // Get connection type
    var connectionType: ConnectionType {
        guard let reachability = reachability else { return .unknown }

        var flags: SCNetworkReachabilityFlags = []
        if !SCNetworkReachabilityGetFlags(reachability, &flags) {
            return .unknown
        }

        if !flags.contains(.reachable) {
            return .none
        }

        if flags.contains(.isWWAN) {
            return .cellular
        } else {
            return .wifi
        }
    }

    deinit {
        stopMonitoring()
    }
}

// Connection Type Enum
enum ConnectionType {
    case none
    case wifi
    case cellular
    case unknown

    var description: String {
        switch self {
        case .none: return "No Connection"
        case .wifi: return "WiFi"
        case .cellular: return "Cellular"
        case .unknown: return "Unknown"
        }
    }
}

// 2. Network Monitor with Detailed Info
class NetworkMonitor {

    private var reachabilityManager: ReachabilityManager?
    private var networkHistory: [NetworkEvent] = []
    private let maxHistorySize = 100

    // Start monitoring
    func startMonitoring() {
        reachabilityManager = ReachabilityManager()
        reachabilityManager?.startMonitoring { [weak self] isReachable in
            self?.handleNetworkChange(isReachable: isReachable)
        }

        logInitialStatus()
    }

    // Stop monitoring
    func stopMonitoring() {
        reachabilityManager?.stopMonitoring()
        reachabilityManager = nil
    }

    // Handle network change
    private func handleNetworkChange(isReachable: Bool) {
        let event = NetworkEvent(
            timestamp: Date(),
            isReachable: isReachable,
            connectionType: reachabilityManager?.connectionType ?? .unknown
        )

        networkHistory.append(event)

        // Trim history
        if networkHistory.count > maxHistorySize {
            networkHistory.removeFirst()
        }

        let status = isReachable ? "Connected" : "Disconnected"
        let connection = event.connectionType.description
        print("[\(formatTimestamp(event.timestamp))] Network: \(status) (\(connection))")
    }

    // Log initial status
    private func logInitialStatus() {
        let isReachable = reachabilityManager?.isReachable ?? false
        let connectionType = reachabilityManager?.connectionType ?? .unknown

        let event = NetworkEvent(
            timestamp: Date(),
            isReachable: isReachable,
            connectionType: connectionType
        )

        networkHistory.append(event)

        print("=== Network Monitor Started ===")
        print("Current Status: \(isReachable ? "Connected" : "Disconnected")")
        print("Connection Type: \(connectionType.description)")
    }

    // Get current status
    func getCurrentStatus() -> NetworkStatus {
        return NetworkStatus(
            isReachable: reachabilityManager?.isReachable ?? false,
            connectionType: reachabilityManager?.connectionType ?? .unknown,
            lastChange: networkHistory.last?.timestamp ?? Date()
        )
    }

    // Get network history
    func getNetworkHistory() -> [NetworkEvent] {
        return networkHistory
    }

    // Get statistics
    func getStatistics() -> NetworkStatistics {
        var connectedTime: TimeInterval = 0
        var disconnectedTime: TimeInterval = 0
        var connectionCount = 0
        var disconnectionCount = 0

        for i in 1..<networkHistory.count {
            let previous = networkHistory[i - 1]
            let current = networkHistory[i]
            let duration = current.timestamp.timeIntervalSince(previous.timestamp)

            if previous.isReachable {
                connectedTime += duration
                if !current.isReachable {
                    disconnectionCount += 1
                }
            } else {
                disconnectedTime += duration
                if current.isReachable {
                    connectionCount += 1
                }
            }
        }

        // Add time from last event to now
        if let last = networkHistory.last {
            let duration = Date().timeIntervalSince(last.timestamp)
            if last.isReachable {
                connectedTime += duration
            } else {
                disconnectedTime += duration
            }
        }

        let totalConnectedEvents = networkHistory.filter { $0.isReachable }.count
        let totalDisconnectedEvents = networkHistory.filter { !$0.isReachable }.count

        return NetworkStatistics(
            connectedTime: connectedTime,
            disconnectedTime: disconnectedTime,
            connectionCount: connectionCount,
            disconnectionCount: disconnectionCount,
            totalConnectedEvents: totalConnectedEvents,
            totalDisconnectedEvents: totalDisconnectedEvents
        )
    }
}

// Data Structures
struct NetworkEvent {
    let timestamp: Date
    let isReachable: Bool
    let connectionType: ConnectionType
}

struct NetworkStatus {
    let isReachable: Bool
    let connectionType: ConnectionType
    let lastChange: Date
}

struct NetworkStatistics {
    let connectedTime: TimeInterval
    let disconnectedTime: TimeInterval
    let connectionCount: Int
    let disconnectionCount: Int
    let totalConnectedEvents: Int
    let totalDisconnectedEvents: Int

    var uptimePercentage: Double {
        let total = connectedTime + disconnectedTime
        guard total > 0 else { return 0 }
        return (connectedTime / total) * 100
    }
}

// 3. Bandwidth Monitor (Simplified)
class BandwidthMonitor {

    private var startTime: Date?
    private var startBytes: UInt64 = 0
    private var currentBytes: UInt64 = 0

    // Start monitoring bandwidth
    func startMonitoring() {
        startTime = Date()
        startBytes = getCurrentBytesReceived()
        print("Bandwidth monitoring started")
    }

    // Stop monitoring and get results
    func stopMonitoring() -> BandwidthResult {
        guard let start = startTime else {
            return BandwidthResult(duration: 0, bytesReceived: 0, averageSpeed: 0)
        }

        currentBytes = getCurrentBytesReceived()
        let duration = Date().timeIntervalSince(start)
        let bytesReceived = currentBytes - startBytes
        let averageSpeed = bytesReceived / UInt64(duration)

        startTime = nil
        startBytes = 0

        let result = BandwidthResult(
            duration: duration,
            bytesReceived: bytesReceived,
            averageSpeed: averageSpeed
        )

        print("Bandwidth monitoring stopped:")
        print("  Duration: \(String(format: "%.1f", duration))s")
        print("  Bytes Received: \(formatBytes(bytesReceived))")
        print("  Average Speed: \(formatBytes(averageSpeed))/s")

        return result
    }

    // Get current bytes received (simplified)
    private func getCurrentBytesReceived() -> UInt64 {
        // In a real implementation, you'd use network interface statistics
        // This is a placeholder
        return UInt64.random(in: 1000000...10000000)
    }
}

struct BandwidthResult {
    let duration: TimeInterval
    let bytesReceived: UInt64
    let averageSpeed: UInt64
}

// 4. Connectivity Test
class ConnectivityTest {

    // Test connectivity to a host
    static func testConnection(to host: String, timeout: TimeInterval = 5.0) -> Bool {
        guard let reachability = SCNetworkReachabilityCreateWithName(nil, host) else {
            return false
        }

        var flags: SCNetworkReachabilityFlags = []
        if !SCNetworkReachabilityGetFlags(reachability, &flags) {
            return false
        }

        let isReachable = flags.contains(.reachable)
        let needsConnection = flags.contains(.connectionRequired)
        let canConnectAutomatically = flags.contains(.connectionOnDemand) || flags.contains(.connectionOnTraffic)

        return isReachable && (!needsConnection || canConnectAutomatically)
    }

    // Test multiple hosts
    static func testMultipleHosts(_ hosts: [String]) -> [String: Bool] {
        var results: [String: Bool] = [:]

        for host in hosts {
            results[host] = testConnection(to: host)
        }

        return results
    }

    // Ping test (simplified)
    static func ping(_ host: String, count: Int = 4) -> PingResult {
        print("Pinging \(host)...")

        var successfulPings = 0
        var totalLatency: TimeInterval = 0

        for _ in 0..<count {
            let start = Date()

            if testConnection(to: host, timeout: 1.0) {
                let latency = Date().timeIntervalSince(start)
                totalLatency += latency
                successfulPings += 1
            }

            Thread.sleep(forTimeInterval: 0.5)
        }

        let averageLatency = successfulPings > 0 ? totalLatency / Double(successfulPings) : 0
        let packetLoss = ((count - successfulPings) / count) * 100

        let result = PingResult(
            host: host,
            packetsSent: count,
            packetsReceived: successfulPings,
            packetLoss: packetLoss,
            averageLatency: averageLatency
        )

        print("Ping statistics for \(host):")
        print("  Packets: Sent = \(count), Received = \(successfulPings), Lost = \(count - successfulPings)")
        print("  Packet Loss: \(packetLoss)%")
        if successfulPings > 0 {
            print("  Average Latency: \(String(format: "%.2f", averageLatency * 1000))ms")
        }

        return result
    }
}

struct PingResult {
    let host: String
    let packetsSent: Int
    let packetsReceived: Int
    let packetLoss: Int
    let averageLatency: TimeInterval
}

// Helper functions
func formatTimestamp(_ date: Date) -> String {
    let formatter = DateFormatter()
    formatter.dateFormat = "HH:mm:ss"
    return formatter.string(from: date)
}

func formatBytes(_ bytes: UInt64) -> String {
    let kb = Double(bytes) / 1024
    let mb = kb / 1024
    let gb = mb / 1024

    if gb >= 1 {
        return String(format: "%.2f GB", gb)
    } else if mb >= 1 {
        return String(format: "%.2f MB", mb)
    } else if kb >= 1 {
        return String(format: "%.2f KB", kb)
    } else {
        return "\(bytes) B"
    }
}

// Main demonstration
func demonstrateNetworkMonitoring() {
    print("=== macOS/iOS Swift Network Status Monitoring ===\n")

    // 1. Basic reachability check
    print("--- 1. Basic Reachability Check ---")
    if let manager = ReachabilityManager() {
        print("Is Reachable: \(manager.isReachable)")
        print("Connection Type: \(manager.connectionType.description)")
    }

    // 2. Start monitoring
    print("\n--- 2. Network Monitoring ---")
    let monitor = NetworkMonitor()
    monitor.startMonitoring()

    // Keep monitoring for a few seconds
    print("Monitoring network changes for 10 seconds...")
    Thread.sleep(forTimeInterval: 10)

    // 3. Get current status
    print("\n--- 3. Current Status ---")
    let status = monitor.getCurrentStatus()
    print("Reachable: \(status.isReachable)")
    print("Connection: \(status.connectionType.description)")
    print("Last Change: \(formatTimestamp(status.lastChange))")

    // 4. Get statistics
    print("\n--- 4. Network Statistics ---")
    let stats = monitor.getStatistics()
    print("Connected Time: \(String(format: "%.1f", stats.connectedTime))s")
    print("Disconnected Time: \(String(format: "%.1f", stats.disconnectedTime))s")
    print("Connection Count: \(stats.connectionCount)")
    print("Disconnection Count: \(stats.disconnectionCount)")
    print("Uptime: \(String(format: "%.1f", stats.uptimePercentage))%")

    // 5. Test multiple hosts
    print("\n--- 5. Host Connectivity Tests ---")
    let hosts = ["apple.com", "google.com", "github.com", "localhost"]
    let results = ConnectivityTest.testMultipleHosts(hosts)

    for (host, reachable) in results {
        print("\(host): \(reachable ? "✓ Reachable" : "✗ Unreachable")")
    }

    // 6. Ping test
    print("\n--- 6. Ping Test ---")
    let pingResult = ConnectivityTest.ping("apple.com", count: 4)

    // 7. Bandwidth monitoring
    print("\n--- 7. Bandwidth Monitoring ---")
    let bandwidthMonitor = BandwidthMonitor()
    bandwidthMonitor.startMonitoring()
    print("Monitoring bandwidth for 5 seconds...")
    Thread.sleep(forTimeInterval: 5)
    bandwidthMonitor.stopMonitoring()

    // Stop monitoring
    monitor.stopMonitoring()

    print("\n=== Network Monitoring Demo Completed ===")
}

// Run demonstration
demonstrateNetworkMonitoring()

💻 Vibration et Retour Haptique swift

🔴 complex ⭐⭐⭐⭐

Implémenter patterns vibration appareil et retour haptique pour notifications utilisateur

⏱️ 30 min 🏷️ swift, macos, ios, haptic, vibration
Prerequisites: Swift basics, CoreHaptics framework, iOS 13+ APIs
// macOS/iOS Swift Vibration and Haptic Feedback Examples
// Using CoreHaptics (iOS 13+) and AudioToolbox

#if os(iOS)
import UIKit
import CoreHaptics
import AudioToolbox
#endif

#if os(macOS)
import AppKit
#endif

import Foundation

// 1. Haptic Engine Manager
class HapticEngineManager {

    #if os(iOS)
    @available(iOS 13.0, *)
    private var hapticEngine: CHHapticEngine?

    // Initialize haptic engine
    @available(iOS 13.0, *)
    func initializeHapticEngine() -> Bool {
        guard CHHapticEngine.capabilitiesForHardware().supportsHaptics else {
            print("Haptics not supported on this device")
            return false
        }

        do {
            hapticEngine = try CHHapticEngine()

            // Handle engine stopped
            hapticEngine?.stoppedHandler = { reason in
                print("Haptic engine stopped: \(reason.rawValue)")
            }

            // Handle engine reset
            hapticEngine?.resetHandler = {
                print("Haptic engine reset")
                do {
                    try self.hapticEngine?.start()
                } catch {
                    print("Error starting haptic engine after reset: \(error)")
                }
            }

            try hapticEngine?.start()
            print("Haptic engine initialized successfully")
            return true

        } catch {
            print("Error creating haptic engine: \(error)")
            return false
        }
    }

    // Stop haptic engine
    @available(iOS 13.0, *)
    func stopHapticEngine() {
        hapticEngine?.stop(completionHandler: { error in
            if let error = error {
                print("Error stopping haptic engine: \(error)")
            }
        })
    }
    #else
    func initializeHapticEngine() -> Bool {
        print("Haptics not supported on macOS")
        return false
    }

    func stopHapticEngine() {
        print("Haptics not supported on macOS")
    }
    #endif
}

// 2. Vibration Patterns
class VibrationPatternManager {

    #if os(iOS)
    // Play vibration pattern using AudioToolbox
    static func playVibrationPattern(_ pattern: VibrationPattern) {
        for item in pattern.items {
            DispatchQueue.main.asyncAfter(deadline: .now() + item.delay) {
                if item.intensity > 0 {
                    AudioServicesPlaySystemSound(kSystemSoundID_Vibrate)
                }
            }
        }
    }

    // Predefined patterns
    static func notificationPattern() -> VibrationPattern {
        VibrationPattern(items: [
            VibrationItem(intensity: 1, delay: 0),
            VibrationItem(intensity: 0, delay: 0.1),
            VibrationItem(intensity: 1, delay: 0.1)
        ])
    }

    static func alertPattern() -> VibrationPattern {
        VibrationPattern(items: [
            VibrationItem(intensity: 1, delay: 0),
            VibrationItem(intensity: 0, delay: 0.15),
            VibrationItem(intensity: 1, delay: 0.15),
            VibrationItem(intensity: 0, delay: 0.15),
            VibrationItem(intensity: 1, delay: 0.15)
        ])
    }

    static func successPattern() -> VibrationPattern {
        VibrationPattern(items: [
            VibrationItem(intensity: 1, delay: 0),
            VibrationItem(intensity: 0, delay: 0.05),
            VibrationItem(intensity: 1, delay: 0.05)
        ])
    }

    static func errorPattern() -> VibrationPattern {
        VibrationPattern(items: [
            VibrationItem(intensity: 1, delay: 0),
            VibrationItem(intensity: 0, delay: 0.1),
            VibrationItem(intensity: 1, delay: 0.1),
            VibrationItem(intensity: 0, delay: 0.1),
            VibrationItem(intensity: 1, delay: 0.1),
            VibrationItem(intensity: 0, delay: 0.1),
            VibrationItem(intensity: 1, delay: 0.1)
        ])
    }

    static func heartbeatPattern() -> VibrationPattern {
        VibrationPattern(items: [
            VibrationItem(intensity: 1, delay: 0),
            VibrationItem(intensity: 0, delay: 0.15),
            VibrationItem(intensity: 1, delay: 0.15),
            VibrationItem(intensity: 0, delay: 0.3),
            VibrationItem(intensity: 1, delay: 0.3),
            VibrationItem(intensity: 0, delay: 0.15),
            VibrationItem(intensity: 1, delay: 0.15)
        ])
    }
    #else
    static func playVibrationPattern(_ pattern: VibrationPattern) {
        print("Vibration not supported on macOS")
        NSSound.beep()
    }

    static func notificationPattern() -> VibrationPattern {
        VibrationPattern(items: [])
    }

    static func alertPattern() -> VibrationPattern {
        VibrationPattern(items: [])
    }

    static func successPattern() -> VibrationPattern {
        VibrationPattern(items: [])
    }

    static func errorPattern() -> VibrationPattern {
        VibrationPattern(items: [])
    }

    static func heartbeatPattern() -> VibrationPattern {
        VibrationPattern(items: [])
    }
    #endif
}

// 3. Haptic Feedback Manager
class HapticFeedbackManager {

    #if os(iOS)
    // Impact feedback
    @available(iOS 10.0, *)
    static func impact(style: UIImpactFeedbackGenerator.FeedbackStyle) {
        let generator = UIImpactFeedbackGenerator(style: style)
        generator.prepare()
        generator.impactOccurred()
    }

    // Light impact
    @available(iOS 10.0, *)
    static func lightImpact() {
        impact(style: .light)
    }

    // Medium impact
    @available(iOS 10.0, *)
    static func mediumImpact() {
        impact(style: .medium)
    }

    // Heavy impact
    @available(iOS 10.0, *)
    static func heavyImpact() {
        impact(style: .heavy)
    }

    // Soft impact (iOS 13+)
    @available(iOS 13.0, *)
    static func softImpact() {
        impact(style: .soft)
    }

    // Rigid impact (iOS 13+)
    @available(iOS 13.0, *)
    static func rigidImpact() {
        impact(style: .rigid)
    }

    // Notification feedback
    @available(iOS 10.0, *)
    static func notification(_ type: UINotificationFeedbackGenerator.FeedbackType) {
        let generator = UINotificationFeedbackGenerator()
        generator.prepare()
        generator.notificationOccurred(type)
    }

    // Success notification
    @available(iOS 10.0, *)
    static func successNotification() {
        notification(.success)
    }

    // Warning notification
    @available(iOS 10.0, *)
    static func warningNotification() {
        notification(.warning)
    }

    // Error notification
    @available(iOS 10.0, *)
    static func errorNotification() {
        notification(.error)
    }

    // Selection feedback
    @available(iOS 10.0, *)
    static func selectionChanged() {
        let generator = UISelectionFeedbackGenerator()
        generator.prepare()
        generator.selectionChanged()
    }
    #else
    static func impact(style: Int) {
        print("Haptic impact not supported on macOS")
        NSSound.beep()
    }

    static func lightImpact() {
        NSSound.beep()
    }

    static func mediumImpact() {
        NSSound.beep()
    }

    static func heavyImpact() {
        NSSound.beep()
    }

    static func notification(_ type: Int) {
        NSSound.beep()
    }

    static func successNotification() {
        NSSound.beep()
    }

    static func warningNotification() {
        NSSound.beep()
        NSSound.beep()
    }

    static func errorNotification() {
        NSSound.beep()
        NSSound.beep()
        NSSound.beep()
    }

    static func selectionChanged() {
        NSSound.beep()
    }
    #endif
}

// 4. Custom Haptic Patterns
class CustomHapticPatterns {

    #if os(iOS)
    @available(iOS 13.0, *)
    static func playCustomHapticPattern(intensity: Float, sharpness: Float, duration: TimeInterval) {
        guard CHHapticEngine.capabilitiesForHardware().supportsHaptics else {
            print("Haptics not supported")
            return
        }

        do {
            let pattern = try CHHapticPattern(
                events: [
                    CHHapticEvent(eventType: .hapticTransient, parameters: [
                        CHHapticEventParameter(parameterID: .hapticIntensity, value: intensity),
                        CHHapticEventParameter(parameterID: .hapticSharpness, value: sharpness)
                    ], relativeTime: 0)
                ],
                parameters: []
            )

            let engine = try CHHapticEngine()
            try engine.start()

            let player = try engine.makePlayer(with: pattern)
            try player.start(atTime: 0)

            print("Playing custom haptic pattern")

        } catch {
            print("Error playing custom pattern: \(error)")
        }
    }

    @available(iOS 13.0, *)
    static func playContinuousHaptic(intensity: Float, sharpness: Float, duration: TimeInterval) {
        guard CHHapticEngine.capabilitiesForHardware().supportsHaptics else {
            print("Haptics not supported")
            return
        }

        do {
            let pattern = try CHHapticPattern(
                events: [
                    CHHapticEvent(eventType: .hapticContinuous, parameters: [
                        CHHapticEventParameter(parameterID: .hapticIntensity, value: intensity),
                        CHHapticEventParameter(parameterID: .hapticSharpness, value: sharpness)
                    ], relativeTime: 0, duration: duration)
                ],
                parameters: []
            )

            let engine = try CHHapticEngine()
            try engine.start()

            let player = try engine.makePlayer(with: pattern)
            try player.start(atTime: 0)

            print("Playing continuous haptic for \(duration)s")

        } catch {
            print("Error playing continuous haptic: \(error)")
        }
    }

    @available(iOS 13.0, *)
    static func playComplexPattern() {
        guard CHHapticEngine.capabilitiesForHardware().supportsHaptics else {
            print("Haptics not supported")
            return
        }

        do {
            // Create a complex pattern with multiple events
            let pattern = try CHHapticPattern(
                events: [
                    // Tap
                    CHHapticEvent(eventType: .hapticTransient, parameters: [
                        CHHapticEventParameter(parameterID: .hapticIntensity, value: 1.0),
                        CHHapticEventParameter(parameterID: .hapticSharpness, value: 0.5)
                    ], relativeTime: 0),

                    // Hold
                    CHHapticEvent(eventType: .hapticContinuous, parameters: [
                        CHHapticEventParameter(parameterID: .hapticIntensity, value: 0.8),
                        CHHapticEventParameter(parameterID: .hapticSharpness, value: 0.3)
                    ], relativeTime: 0.1, duration: 0.2),

                    // Release
                    CHHapticEvent(eventType: .hapticTransient, parameters: [
                        CHHapticEventParameter(parameterID: .hapticIntensity, value: 0.6),
                        CHHapticEventParameter(parameterID: .hapticSharpness, value: 0.8)
                    ], relativeTime: 0.4)
                ],
                parameters: []
            )

            let engine = try CHHapticEngine()
            try engine.start()

            let player = try engine.makePlayer(with: pattern)
            try player.start(atTime: 0)

            print("Playing complex haptic pattern")

        } catch {
            print("Error playing complex pattern: \(error)")
        }
    }
    #else
    @available(iOS 13.0, *)
    static func playCustomHapticPattern(intensity: Float, sharpness: Float, duration: TimeInterval) {
        print("Custom haptics not supported on macOS")
    }

    @available(iOS 13.0, *)
    static func playContinuousHaptic(intensity: Float, sharpness: Float, duration: TimeInterval) {
        print("Continuous haptics not supported on macOS")
    }

    @available(iOS 13.0, *)
    static func playComplexPattern() {
        print("Complex haptics not supported on macOS")
    }
    #endif
}

// 5. Haptic Notification Manager
class HapticNotificationManager {

    // Complete notification with visual, audio, and haptic feedback
    static func showNotification(type: NotificationType) {
        print("\n=== \(type.title) ===")

        switch type {
        case .success:
            #if os(iOS)
            if #available(iOS 10.0, *) {
                HapticFeedbackManager.successNotification()
            } else {
                VibrationPatternManager.playVibrationPattern(VibrationPatternManager.successPattern())
            }
            #else
            NSSound.beep()
            #endif

        case .warning:
            #if os(iOS)
            if #available(iOS 10.0, *) {
                HapticFeedbackManager.warningNotification()
            } else {
                VibrationPatternManager.playVibrationPattern(VibrationPatternManager.alertPattern())
            }
            #else
            NSSound.beep()
            NSSound.beep()
            #endif

        case .error:
            #if os(iOS)
            if #available(iOS 10.0, *) {
                HapticFeedbackManager.errorNotification()
            } else {
                VibrationPatternManager.playVibrationPattern(VibrationPatternManager.errorPattern())
            }
            #else
            NSSound.beep()
            NSSound.beep()
            NSSound.beep()
            #endif

        case .message:
            #if os(iOS)
            VibrationPatternManager.playVibrationPattern(VibrationPatternManager.notificationPattern())
            #else
            NSSound.beep()
            #endif

        case .reminder:
            #if os(iOS)
            if #available(iOS 10.0, *) {
                HapticFeedbackManager.mediumImpact()
            }
            #else
            NSSound.beep()
            #endif
        }
    }

    // Show progress haptic
    static func showProgressHaptic(progress: Float) {
        #if os(iOS)
        if #available(iOS 10.0, *) {
            let intensity = CHHapticEventParameter.ParameterID.hapticIntensity
            // Gradually increase haptic based on progress
            if progress >= 1.0 {
                HapticFeedbackManager.successNotification()
            } else if progress > 0.75 {
                HapticFeedbackManager.lightImpact()
            }
        }
        #endif
    }
}

// Data Structures
struct VibrationPattern {
    let items: [VibrationItem]
}

struct VibrationItem {
    let intensity: Int
    let delay: TimeInterval
}

enum NotificationType {
    case success
    case warning
    case error
    case message
    case reminder

    var title: String {
        switch self {
        case .success: return "Success"
        case .warning: return "Warning"
        case .error: return "Error"
        case .message: return "Message"
        case .reminder: return "Reminder"
        }
    }
}

// Main demonstration
func demonstrateHapticFeedback() {
    print("=== macOS/iOS Swift Vibration & Haptic Feedback ===\n")

    // Initialize haptic engine
    #if os(iOS)
    if #available(iOS 13.0, *) {
        let engineManager = HapticEngineManager()
        _ = engineManager.initializeHapticEngine()
    }
    #endif

    // 1. Basic impact feedback
    print("--- 1. Impact Feedback ---")
    print("Light impact...")
    HapticFeedbackManager.lightImpact()
    Thread.sleep(forTimeInterval: 0.5)

    print("Medium impact...")
    HapticFeedbackManager.mediumImpact()
    Thread.sleep(forTimeInterval: 0.5)

    print("Heavy impact...")
    HapticFeedbackManager.heavyImpact()
    Thread.sleep(forTimeInterval: 0.5)

    // 2. Selection feedback
    print("\n--- 2. Selection Feedback ---")
    print("Selection changed (3 times)...")
    HapticFeedbackManager.selectionChanged()
    Thread.sleep(forTimeInterval: 0.2)
    HapticFeedbackManager.selectionChanged()
    Thread.sleep(forTimeInterval: 0.2)
    HapticFeedbackManager.selectionChanged()

    // 3. Notification feedback
    print("\n--- 3. Notification Feedback ---")
    print("Success notification...")
    HapticNotificationManager.showNotification(type: .success)
    Thread.sleep(forTimeInterval: 1.0)

    print("Warning notification...")
    HapticNotificationManager.showNotification(type: .warning)
    Thread.sleep(forTimeInterval: 1.0)

    print("Error notification...")
    HapticNotificationManager.showNotification(type: .error)
    Thread.sleep(forTimeInterval: 1.0)

    // 4. Vibration patterns
    print("\n--- 4. Vibration Patterns ---")
    print("Notification pattern...")
    VibrationPatternManager.playVibrationPattern(VibrationPatternManager.notificationPattern())
    Thread.sleep(forTimeInterval: 1.0)

    print("Alert pattern...")
    VibrationPatternManager.playVibrationPattern(VibrationPatternManager.alertPattern())
    Thread.sleep(forTimeInterval: 1.0)

    print("Heartbeat pattern...")
    VibrationPatternManager.playVibrationPattern(VibrationPatternManager.heartbeatPattern())

    // 5. Custom haptics (iOS 13+)
    #if os(iOS)
    if #available(iOS 13.0, *) {
        print("\n--- 5. Custom Haptics ---")
        Thread.sleep(forTimeInterval: 1.0)

        print("Custom pattern (intensity: 0.8, sharpness: 0.5)...")
        CustomHapticPatterns.playCustomHapticPattern(intensity: 0.8, sharpness: 0.5, duration: 0.3)
        Thread.sleep(forTimeInterval: 0.5)

        print("Continuous haptic (0.5s)...")
        CustomHapticPatterns.playContinuousHaptic(intensity: 0.7, sharpness: 0.4, duration: 0.5)
        Thread.sleep(forTimeInterval: 0.6)

        print("Complex pattern...")
        CustomHapticPatterns.playComplexPattern()
    }
    #endif

    // 6. Progress haptics
    print("\n--- 6. Progress Haptics ---")
    print("Simulating progress...")
    for i in 1...5 {
        let progress = Float(i) / 5.0
        print("Progress: \(Int(progress * 100))%")
        HapticNotificationManager.showProgressHaptic(progress: progress)
        Thread.sleep(forTimeInterval: 0.3)
    }

    print("\n=== Haptic Feedback Demo Completed ===")
}

// Run demonstration
demonstrateHapticFeedback()