From 94d3a95073172d4c5e4e5ac6d325fc16f7fdba5d Mon Sep 17 00:00:00 2001 From: Ryan F Date: Sun, 24 Nov 2024 19:03:48 +0000 Subject: [PATCH 1/2] =?UTF-8?q?=F0=9F=94=A6=20Control:=20Add=20Flashlight?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add toggle method on/off method with default parameter --- Sources/Control/Flashlight.swift | 65 ++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 Sources/Control/Flashlight.swift diff --git a/Sources/Control/Flashlight.swift b/Sources/Control/Flashlight.swift new file mode 100644 index 0000000..0e70bc8 --- /dev/null +++ b/Sources/Control/Flashlight.swift @@ -0,0 +1,65 @@ +// +// Flashlight.swift +// ControlKit +// + +import AVFoundation +import OSLog + +extension Control { + + /// 🔦 Control the device's flashlight. + public enum Flashlight {} +} + +extension Control.Flashlight { + + /// Indicates whether the device's flashlight is currently turned on. + /// + /// - Returns: A Boolean value indicating the flashlight state. Returns `true` if the flashlight is on, otherwise `false`. + public static var isOn: Bool { + (deviceWithFlashlight?.torchLevel ?? 0) > 0 + } + + /// Toggles the device's flashlight on/off. + /// + /// - Parameter isOn: A Boolean value to specify the desired state of the flashlight. + /// Pass `true` to turn it on or `false` to turn it off. + /// If no value is provided, the flashlight toggles its current state. + /// - Important: The flashlight can only be used while the app is in the foreground. + /// If the flashlight is on and the app is backgrounded, the flashlight will turn off. + /// - Note: If the device does not have a flashlight, this method does nothing. + public static func toggle( _ isOn: Bool = !isOn) { + guard let deviceWithFlashlight else { + return + } + do { + try deviceWithFlashlight.lockForConfiguration() + if isOn { + try deviceWithFlashlight.setTorchModeOn(level: AVCaptureDevice.maxAvailableTorchLevel) + } else { + deviceWithFlashlight.torchMode = .off + } + deviceWithFlashlight.unlockForConfiguration() + } catch { + log.error("Error toggling flashlight: \(error.localizedDescription) to \(isOn ? "on" : "off")") + } + } + + private static var deviceWithFlashlight: AVCaptureDevice? { + guard + let device = AVCaptureDevice.default(for: .video), + device.hasTorch + else { + #if targetEnvironment(simulator) + log.info("Simulator does not have a flashlight (yet)") + #else + log.info("Flashlight (torch) not available") + #endif + return nil + } + return device + } + + private static let log = Logger(subsystem: Control.subsystem, category: "Flashlight") +} From c865c704deba7cf1c5c9e9c5ff772c14e62c0187 Mon Sep 17 00:00:00 2001 From: Ryan F Date: Thu, 5 Jun 2025 21:13:59 +0100 Subject: [PATCH 2/2] =?UTF-8?q?=F0=9F=98=89=20Flashlight:=20Add=20blink?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Sources/Control/Flashlight.swift | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Sources/Control/Flashlight.swift b/Sources/Control/Flashlight.swift index 0e70bc8..03001a0 100644 --- a/Sources/Control/Flashlight.swift +++ b/Sources/Control/Flashlight.swift @@ -46,6 +46,16 @@ extension Control.Flashlight { } } + public static func blink(count: Int = 1, interval: TimeInterval = 0.1) { + Task { + for _ in 0..