cleaning up concurrency warnings
This commit is contained in:
@@ -13,3 +13,5 @@ enum PauseReason: Codable, Equatable, Hashable {
|
|||||||
case idle
|
case idle
|
||||||
case system
|
case system
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension PauseReason: Sendable {}
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import Combine
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
/// Protocol that defines the interface for enforce mode functionality.
|
/// Protocol that defines the interface for enforce mode functionality.
|
||||||
@MainActor
|
|
||||||
protocol EnforceModeProviding: AnyObject, ObservableObject {
|
protocol EnforceModeProviding: AnyObject, ObservableObject {
|
||||||
/// Whether enforce mode is currently enabled
|
/// Whether enforce mode is currently enabled
|
||||||
var isEnforceModeEnabled: Bool { get }
|
var isEnforceModeEnabled: Bool { get }
|
||||||
|
|||||||
@@ -6,14 +6,12 @@
|
|||||||
import Combine
|
import Combine
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
@MainActor
|
|
||||||
protocol TimerSettingsProviding {
|
protocol TimerSettingsProviding {
|
||||||
func allTimerSettings() -> [TimerType: (enabled: Bool, intervalMinutes: Int)]
|
func allTimerSettings() -> [TimerType: (enabled: Bool, intervalMinutes: Int)]
|
||||||
func isTimerEnabled(for type: TimerType) -> Bool
|
func isTimerEnabled(for type: TimerType) -> Bool
|
||||||
func timerIntervalMinutes(for type: TimerType) -> Int
|
func timerIntervalMinutes(for type: TimerType) -> Int
|
||||||
}
|
}
|
||||||
|
|
||||||
@MainActor
|
|
||||||
protocol SettingsProviding: AnyObject, Observable, TimerSettingsProviding {
|
protocol SettingsProviding: AnyObject, Observable, TimerSettingsProviding {
|
||||||
var settings: AppSettings { get set }
|
var settings: AppSettings { get set }
|
||||||
var settingsPublisher: AnyPublisher<AppSettings, Never> { get }
|
var settingsPublisher: AnyPublisher<AppSettings, Never> { get }
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import Combine
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
/// Protocol for fullscreen detection functionality
|
/// Protocol for fullscreen detection functionality
|
||||||
@MainActor
|
|
||||||
protocol FullscreenDetectionProviding: AnyObject, ObservableObject {
|
protocol FullscreenDetectionProviding: AnyObject, ObservableObject {
|
||||||
/// Whether a fullscreen app is currently active
|
/// Whether a fullscreen app is currently active
|
||||||
var isFullscreenActive: Bool { get }
|
var isFullscreenActive: Bool { get }
|
||||||
@@ -22,7 +21,6 @@ protocol FullscreenDetectionProviding: AnyObject, ObservableObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Protocol for idle monitoring functionality
|
/// Protocol for idle monitoring functionality
|
||||||
@MainActor
|
|
||||||
protocol IdleMonitoringProviding: AnyObject, ObservableObject {
|
protocol IdleMonitoringProviding: AnyObject, ObservableObject {
|
||||||
/// Whether the user is currently idle
|
/// Whether the user is currently idle
|
||||||
var isIdle: Bool { get }
|
var isIdle: Bool { get }
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import Foundation
|
|||||||
|
|
||||||
/// Protocol that defines the interface for timer engine functionality.
|
/// Protocol that defines the interface for timer engine functionality.
|
||||||
/// This abstraction allows for dependency injection and easy mocking in tests.
|
/// This abstraction allows for dependency injection and easy mocking in tests.
|
||||||
@MainActor
|
|
||||||
protocol TimerEngineProviding: AnyObject, ObservableObject {
|
protocol TimerEngineProviding: AnyObject, ObservableObject {
|
||||||
/// Current timer states for all active timers
|
/// Current timer states for all active timers
|
||||||
var timerStates: [TimerIdentifier: TimerState] { get }
|
var timerStates: [TimerIdentifier: TimerState] { get }
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
import Combine
|
import Combine
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
@MainActor
|
|
||||||
final class CalibrationFlowController: ObservableObject {
|
final class CalibrationFlowController: ObservableObject {
|
||||||
@Published private(set) var currentStep: CalibrationStep?
|
@Published private(set) var currentStep: CalibrationStep?
|
||||||
@Published private(set) var currentStepIndex = 0
|
@Published private(set) var currentStepIndex = 0
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import Foundation
|
|||||||
import AppKit
|
import AppKit
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
@MainActor
|
|
||||||
final class CalibratorService: ObservableObject {
|
final class CalibratorService: ObservableObject {
|
||||||
static let shared = CalibratorService()
|
static let shared = CalibratorService()
|
||||||
|
|
||||||
@@ -280,8 +279,8 @@ final class CalibratorService: ObservableObject {
|
|||||||
rightVertical: Double? = nil,
|
rightVertical: Double? = nil,
|
||||||
faceWidthRatio: Double = 0
|
faceWidthRatio: Double = 0
|
||||||
) {
|
) {
|
||||||
Task { @MainActor in
|
Task { [weak self] in
|
||||||
collectSample(
|
self?.collectSample(
|
||||||
leftRatio: leftRatio,
|
leftRatio: leftRatio,
|
||||||
rightRatio: rightRatio,
|
rightRatio: rightRatio,
|
||||||
leftVertical: leftVertical,
|
leftVertical: leftVertical,
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ enum ComplianceResult {
|
|||||||
case faceNotDetected
|
case faceNotDetected
|
||||||
}
|
}
|
||||||
|
|
||||||
@MainActor
|
|
||||||
class EnforceModeService: ObservableObject {
|
class EnforceModeService: ObservableObject {
|
||||||
static let shared = EnforceModeService()
|
static let shared = EnforceModeService()
|
||||||
|
|
||||||
@@ -224,12 +223,10 @@ class EnforceModeService: ObservableObject {
|
|||||||
private func startFaceDetectionTimer() {
|
private func startFaceDetectionTimer() {
|
||||||
stopFaceDetectionTimer()
|
stopFaceDetectionTimer()
|
||||||
|
|
||||||
faceDetectionTimer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { _ in
|
faceDetectionTimer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] _ in
|
||||||
Task { @MainActor [weak self] in
|
|
||||||
self?.checkFaceDetectionTimeout()
|
self?.checkFaceDetectionTimeout()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private func stopFaceDetectionTimer() {
|
private func stopFaceDetectionTimer() {
|
||||||
faceDetectionTimer?.invalidate()
|
faceDetectionTimer?.invalidate()
|
||||||
|
|||||||
@@ -45,7 +45,6 @@ final class CameraSessionManager: NSObject, ObservableObject {
|
|||||||
return layer
|
return layer
|
||||||
}
|
}
|
||||||
|
|
||||||
@MainActor
|
|
||||||
func start() async throws {
|
func start() async throws {
|
||||||
guard !isRunning else { return }
|
guard !isRunning else { return }
|
||||||
|
|
||||||
@@ -63,7 +62,6 @@ final class CameraSessionManager: NSObject, ObservableObject {
|
|||||||
isRunning = true
|
isRunning = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@MainActor
|
|
||||||
func stop() {
|
func stop() {
|
||||||
captureSession?.stopRunning()
|
captureSession?.stopRunning()
|
||||||
captureSession = nil
|
captureSession = nil
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import AVFoundation
|
|||||||
import Combine
|
import Combine
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
@MainActor
|
|
||||||
class EyeTrackingService: NSObject, ObservableObject {
|
class EyeTrackingService: NSObject, ObservableObject {
|
||||||
static let shared = EyeTrackingService()
|
static let shared = EyeTrackingService()
|
||||||
|
|
||||||
@@ -100,12 +99,15 @@ class EyeTrackingService: NSObject, ObservableObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try await cameraManager.start()
|
try await cameraManager.start()
|
||||||
isEyeTrackingActive = true
|
await MainActor.run {
|
||||||
|
self.isEyeTrackingActive = true
|
||||||
|
}
|
||||||
print("✓ Eye tracking active")
|
print("✓ Eye tracking active")
|
||||||
}
|
}
|
||||||
|
|
||||||
func stopEyeTracking() {
|
func stopEyeTracking() {
|
||||||
cameraManager.stop()
|
cameraManager.stop()
|
||||||
|
Task { @MainActor in
|
||||||
isEyeTrackingActive = false
|
isEyeTrackingActive = false
|
||||||
isEyesClosed = false
|
isEyesClosed = false
|
||||||
userLookingAtScreen = true
|
userLookingAtScreen = true
|
||||||
@@ -113,6 +115,7 @@ class EyeTrackingService: NSObject, ObservableObject {
|
|||||||
debugAdapter.clear()
|
debugAdapter.clear()
|
||||||
syncDebugState()
|
syncDebugState()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private func syncDebugState() {
|
private func syncDebugState() {
|
||||||
debugLeftPupilRatio = debugAdapter.leftPupilRatio
|
debugLeftPupilRatio = debugAdapter.leftPupilRatio
|
||||||
@@ -134,7 +137,6 @@ class EyeTrackingService: NSObject, ObservableObject {
|
|||||||
debugImageSize = debugAdapter.imageSize
|
debugImageSize = debugAdapter.imageSize
|
||||||
}
|
}
|
||||||
|
|
||||||
@MainActor
|
|
||||||
private func updateGazeConfiguration() {
|
private func updateGazeConfiguration() {
|
||||||
let configuration = GazeDetector.Configuration(
|
let configuration = GazeDetector.Configuration(
|
||||||
thresholds: CalibrationState.shared.thresholds,
|
thresholds: CalibrationState.shared.thresholds,
|
||||||
@@ -184,7 +186,8 @@ extension EyeTrackingService: CameraSessionDelegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Task { @MainActor in
|
Task { @MainActor [weak self] in
|
||||||
|
guard let self else { return }
|
||||||
self.faceDetected = result.faceDetected
|
self.faceDetected = result.faceDetected
|
||||||
self.isEyesClosed = result.isEyesClosed
|
self.isEyesClosed = result.isEyesClosed
|
||||||
self.userLookingAtScreen = result.userLookingAtScreen
|
self.userLookingAtScreen = result.userLookingAtScreen
|
||||||
@@ -220,7 +223,6 @@ enum EyeTrackingError: Error, LocalizedError {
|
|||||||
|
|
||||||
// MARK: - Debug State Adapter
|
// MARK: - Debug State Adapter
|
||||||
|
|
||||||
@MainActor
|
|
||||||
final class EyeDebugStateAdapter {
|
final class EyeDebugStateAdapter {
|
||||||
var leftPupilRatio: Double?
|
var leftPupilRatio: Double?
|
||||||
var rightPupilRatio: Double?
|
var rightPupilRatio: Double?
|
||||||
|
|||||||
@@ -92,19 +92,19 @@ enum GazeDirection: String, Sendable, CaseIterable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Calibration state for adaptive thresholding (matches Python Calibration class)
|
/// Calibration state for adaptive thresholding (matches Python Calibration class)
|
||||||
final class PupilCalibration: @unchecked Sendable {
|
final class PupilCalibration: Sendable {
|
||||||
private let lock = NSLock()
|
private let lock = NSLock()
|
||||||
private let targetFrames = 20
|
private let targetFrames = 20
|
||||||
private var thresholdsLeft: [Int] = []
|
private var thresholdsLeft: [Int] = []
|
||||||
private var thresholdsRight: [Int] = []
|
private var thresholdsRight: [Int] = []
|
||||||
|
|
||||||
nonisolated var isComplete: Bool {
|
var isComplete: Bool {
|
||||||
lock.lock()
|
lock.lock()
|
||||||
defer { lock.unlock() }
|
defer { lock.unlock() }
|
||||||
return thresholdsLeft.count >= targetFrames && thresholdsRight.count >= targetFrames
|
return thresholdsLeft.count >= targetFrames && thresholdsRight.count >= targetFrames
|
||||||
}
|
}
|
||||||
|
|
||||||
nonisolated func threshold(forSide side: Int) -> Int {
|
func threshold(forSide side: Int) -> Int {
|
||||||
lock.lock()
|
lock.lock()
|
||||||
defer { lock.unlock() }
|
defer { lock.unlock() }
|
||||||
let thresholds = side == 0 ? thresholdsLeft : thresholdsRight
|
let thresholds = side == 0 ? thresholdsLeft : thresholdsRight
|
||||||
@@ -113,7 +113,7 @@ final class PupilCalibration: @unchecked Sendable {
|
|||||||
return thresholds.reduce(0, +) / thresholds.count
|
return thresholds.reduce(0, +) / thresholds.count
|
||||||
}
|
}
|
||||||
|
|
||||||
nonisolated func evaluate(eyeData: UnsafePointer<UInt8>, width: Int, height: Int, side: Int) {
|
func evaluate(eyeData: UnsafePointer<UInt8>, width: Int, height: Int, side: Int) {
|
||||||
let bestThreshold = findBestThreshold(eyeData: eyeData, width: width, height: height)
|
let bestThreshold = findBestThreshold(eyeData: eyeData, width: width, height: height)
|
||||||
lock.lock()
|
lock.lock()
|
||||||
defer { lock.unlock() }
|
defer { lock.unlock() }
|
||||||
@@ -124,7 +124,7 @@ final class PupilCalibration: @unchecked Sendable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private nonisolated func findBestThreshold(
|
private func findBestThreshold(
|
||||||
eyeData: UnsafePointer<UInt8>, width: Int, height: Int
|
eyeData: UnsafePointer<UInt8>, width: Int, height: Int
|
||||||
) -> Int {
|
) -> Int {
|
||||||
let averageIrisSize = 0.48
|
let averageIrisSize = 0.48
|
||||||
@@ -154,7 +154,7 @@ final class PupilCalibration: @unchecked Sendable {
|
|||||||
return bestThreshold
|
return bestThreshold
|
||||||
}
|
}
|
||||||
|
|
||||||
private nonisolated static func irisSize(data: UnsafePointer<UInt8>, width: Int, height: Int)
|
private static func irisSize(data: UnsafePointer<UInt8>, width: Int, height: Int)
|
||||||
-> Double
|
-> Double
|
||||||
{
|
{
|
||||||
let margin = 5
|
let margin = 5
|
||||||
@@ -177,7 +177,7 @@ final class PupilCalibration: @unchecked Sendable {
|
|||||||
return totalCount > 0 ? Double(blackCount) / Double(totalCount) : 0
|
return totalCount > 0 ? Double(blackCount) / Double(totalCount) : 0
|
||||||
}
|
}
|
||||||
|
|
||||||
nonisolated func reset() {
|
func reset() {
|
||||||
lock.lock()
|
lock.lock()
|
||||||
defer { lock.unlock() }
|
defer { lock.unlock() }
|
||||||
thresholdsLeft.removeAll()
|
thresholdsLeft.removeAll()
|
||||||
@@ -245,34 +245,34 @@ final class PupilDetector: @unchecked Sendable {
|
|||||||
nonisolated(unsafe) static var debugRightEyeRegion: EyeRegion?
|
nonisolated(unsafe) static var debugRightEyeRegion: EyeRegion?
|
||||||
nonisolated(unsafe) static var debugImageSize: CGSize?
|
nonisolated(unsafe) static var debugImageSize: CGSize?
|
||||||
|
|
||||||
nonisolated(unsafe) static let calibration = PupilCalibration()
|
nonisolated static let calibration = PupilCalibration()
|
||||||
|
|
||||||
// MARK: - Convenience Properties
|
// MARK: - Convenience Properties
|
||||||
|
|
||||||
private nonisolated static var debugImageCounter: Int {
|
private nonisolated(unsafe) static var debugImageCounter: Int {
|
||||||
get { _debugImageCounter }
|
get { _debugImageCounter }
|
||||||
set { _debugImageCounter = newValue }
|
set { _debugImageCounter = newValue }
|
||||||
}
|
}
|
||||||
|
|
||||||
private nonisolated static var frameCounter: Int {
|
private nonisolated(unsafe) static var frameCounter: Int {
|
||||||
get { _frameCounter }
|
get { _frameCounter }
|
||||||
set { _frameCounter = newValue }
|
set { _frameCounter = newValue }
|
||||||
}
|
}
|
||||||
|
|
||||||
private nonisolated static var lastPupilPositions: (left: PupilPosition?, right: PupilPosition?)
|
private nonisolated(unsafe) static var lastPupilPositions: (left: PupilPosition?, right: PupilPosition?)
|
||||||
{
|
{
|
||||||
get { _lastPupilPositions }
|
get { _lastPupilPositions }
|
||||||
set { _lastPupilPositions = newValue }
|
set { _lastPupilPositions = newValue }
|
||||||
}
|
}
|
||||||
|
|
||||||
private nonisolated static var metrics: PupilDetectorMetrics {
|
private nonisolated(unsafe) static var metrics: PupilDetectorMetrics {
|
||||||
get { _metrics }
|
get { _metrics }
|
||||||
set { _metrics = newValue }
|
set { _metrics = newValue }
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Precomputed Tables
|
// MARK: - Precomputed Tables
|
||||||
|
|
||||||
private nonisolated(unsafe) static let spatialWeightsLUT: [[Float]] = {
|
private nonisolated static let spatialWeightsLUT: [[Float]] = {
|
||||||
let d = 10
|
let d = 10
|
||||||
let radius = d / 2
|
let radius = d / 2
|
||||||
let sigmaSpace: Float = 15.0
|
let sigmaSpace: Float = 15.0
|
||||||
@@ -287,7 +287,7 @@ final class PupilDetector: @unchecked Sendable {
|
|||||||
return weights
|
return weights
|
||||||
}()
|
}()
|
||||||
|
|
||||||
private nonisolated(unsafe) static let colorWeightsLUT: [Float] = {
|
private nonisolated static let colorWeightsLUT: [Float] = {
|
||||||
let sigmaColor: Float = 15.0
|
let sigmaColor: Float = 15.0
|
||||||
var lut = [Float](repeating: 0, count: 256)
|
var lut = [Float](repeating: 0, count: 256)
|
||||||
for diff in 0..<256 {
|
for diff in 0..<256 {
|
||||||
|
|||||||
@@ -8,20 +8,23 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
import os.log
|
import os.log
|
||||||
|
|
||||||
|
nonisolated private let loggingSubsystem = "com.mikefreno.Gaze"
|
||||||
|
nonisolated private let isLoggingEnabled: Bool = {
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
let isLoggingEnabled = true
|
return true
|
||||||
#else
|
#else
|
||||||
let isLoggingEnabled = false
|
return false
|
||||||
#endif
|
#endif
|
||||||
|
}()
|
||||||
|
|
||||||
/// A centralized logging manager that provides structured, subsystem-aware logging
|
/// A centralized logging manager that provides structured, subsystem-aware logging
|
||||||
/// for the Gaze application to ensure logs are captured by the run script.
|
/// for the Gaze application to ensure logs are captured by the run script.
|
||||||
final class LoggingManager {
|
final class LoggingManager: @unchecked Sendable {
|
||||||
static let shared = LoggingManager()
|
static let shared = LoggingManager()
|
||||||
|
|
||||||
// MARK: - Private Properties
|
// MARK: - Private Properties
|
||||||
|
|
||||||
private let subsystem = "com.mikefreno.Gaze"
|
private let subsystem = loggingSubsystem
|
||||||
|
|
||||||
// MARK: - Public Loggers
|
// MARK: - Public Loggers
|
||||||
|
|
||||||
@@ -84,30 +87,39 @@ final class LoggingManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Log an info message using the shared LoggingManager
|
/// Log an info message using the shared LoggingManager
|
||||||
public func logInfo(_ message: String, category: String = "General") {
|
nonisolated public func logInfo(_ message: String, category: String = "General") {
|
||||||
LoggingManager.shared.info(message, category: category)
|
guard isLoggingEnabled else { return }
|
||||||
|
let logger = Logger(subsystem: loggingSubsystem, category: category)
|
||||||
|
logger.info("\(message, privacy: .public)")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Log a debug message using the shared LoggingManager
|
/// Log a debug message using the shared LoggingManager
|
||||||
public func logDebug(_ message: String, category: String = "General") {
|
nonisolated public func logDebug(_ message: String, category: String = "General") {
|
||||||
LoggingManager.shared.debug(message, category: category)
|
guard isLoggingEnabled else { return }
|
||||||
|
let logger = Logger(subsystem: loggingSubsystem, category: category)
|
||||||
|
logger.debug("\(message, privacy: .public)")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Log an error message using the shared LoggingManager
|
/// Log an error message using the shared LoggingManager
|
||||||
public func logError(_ message: String, category: String = "General") {
|
nonisolated public func logError(_ message: String, category: String = "General") {
|
||||||
LoggingManager.shared.error(message, category: category)
|
guard isLoggingEnabled else { return }
|
||||||
|
let logger = Logger(subsystem: loggingSubsystem, category: category)
|
||||||
|
logger.error("\(message, privacy: .public)")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Log a warning message using the shared LoggingManager
|
/// Log a warning message using the shared LoggingManager
|
||||||
public func logWarning(_ message: String, category: String = "General") {
|
nonisolated public func logWarning(_ message: String, category: String = "General") {
|
||||||
LoggingManager.shared.warning(message, category: category)
|
guard isLoggingEnabled else { return }
|
||||||
|
let logger = Logger(subsystem: loggingSubsystem, category: category)
|
||||||
|
logger.warning("\(message, privacy: .public)")
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Additional Helper Functions
|
// MARK: - Additional Helper Functions
|
||||||
|
|
||||||
/// Log a verbose message (only enabled in DEBUG builds)
|
/// Log a verbose message (only enabled in DEBUG builds)
|
||||||
public func logVerbose(_ message: String, category: String = "General") {
|
nonisolated public func logVerbose(_ message: String, category: String = "General") {
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
LoggingManager.shared.debug(message, category: category)
|
let logger = Logger(subsystem: loggingSubsystem, category: category)
|
||||||
|
logger.debug("\(message, privacy: .public)")
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ struct MenuBarLocationResult {
|
|||||||
let frame: CGRect
|
let frame: CGRect
|
||||||
}
|
}
|
||||||
|
|
||||||
@MainActor
|
|
||||||
final class MenuBarItemLocator {
|
final class MenuBarItemLocator {
|
||||||
static let shared = MenuBarItemLocator()
|
static let shared = MenuBarItemLocator()
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ public enum ScreenCaptureAuthorizationStatus: Equatable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@MainActor
|
|
||||||
protocol ScreenCapturePermissionManaging: AnyObject {
|
protocol ScreenCapturePermissionManaging: AnyObject {
|
||||||
var authorizationStatus: ScreenCaptureAuthorizationStatus { get }
|
var authorizationStatus: ScreenCaptureAuthorizationStatus { get }
|
||||||
var authorizationStatusPublisher: AnyPublisher<ScreenCaptureAuthorizationStatus, Never> { get }
|
var authorizationStatusPublisher: AnyPublisher<ScreenCaptureAuthorizationStatus, Never> { get }
|
||||||
@@ -31,7 +30,6 @@ protocol ScreenCapturePermissionManaging: AnyObject {
|
|||||||
func openSystemSettings()
|
func openSystemSettings()
|
||||||
}
|
}
|
||||||
|
|
||||||
@MainActor
|
|
||||||
final class ScreenCapturePermissionManager: ObservableObject, ScreenCapturePermissionManaging {
|
final class ScreenCapturePermissionManager: ObservableObject, ScreenCapturePermissionManaging {
|
||||||
static let shared = ScreenCapturePermissionManager()
|
static let shared = ScreenCapturePermissionManager()
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
/// A simple dependency injection container for managing service instances.
|
/// A simple dependency injection container for managing service instances.
|
||||||
@MainActor
|
|
||||||
final class ServiceContainer {
|
final class ServiceContainer {
|
||||||
|
|
||||||
/// Shared instance for production use
|
/// Shared instance for production use
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
import AVFoundation
|
import AVFoundation
|
||||||
import Combine
|
import Combine
|
||||||
|
|
||||||
@MainActor
|
|
||||||
class CameraAccessService: ObservableObject {
|
class CameraAccessService: ObservableObject {
|
||||||
static let shared = CameraAccessService()
|
static let shared = CameraAccessService()
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import Combine
|
|||||||
import Foundation
|
import Foundation
|
||||||
import Observation
|
import Observation
|
||||||
|
|
||||||
@MainActor
|
|
||||||
@Observable
|
@Observable
|
||||||
final class SettingsManager {
|
final class SettingsManager {
|
||||||
static let shared = SettingsManager()
|
static let shared = SettingsManager()
|
||||||
|
|||||||
@@ -62,7 +62,6 @@ struct SystemFullscreenEnvironmentProvider: FullscreenEnvironmentProviding {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@MainActor
|
|
||||||
final class FullscreenDetectionService: ObservableObject {
|
final class FullscreenDetectionService: ObservableObject {
|
||||||
@Published private(set) var isFullscreenActive = false
|
@Published private(set) var isFullscreenActive = false
|
||||||
|
|
||||||
@@ -113,10 +112,8 @@ final class FullscreenDetectionService: ObservableObject {
|
|||||||
let notificationCenter = workspace.notificationCenter
|
let notificationCenter = workspace.notificationCenter
|
||||||
|
|
||||||
let stateChangeHandler: (Notification) -> Void = { [weak self] _ in
|
let stateChangeHandler: (Notification) -> Void = { [weak self] _ in
|
||||||
Task { @MainActor in
|
|
||||||
self?.checkFullscreenState()
|
self?.checkFullscreenState()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let notifications: [(NSNotification.Name, Any?)] = [
|
let notifications: [(NSNotification.Name, Any?)] = [
|
||||||
(NSWorkspace.activeSpaceDidChangeNotification, workspace),
|
(NSWorkspace.activeSpaceDidChangeNotification, workspace),
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import AppKit
|
|||||||
import Combine
|
import Combine
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
@MainActor
|
|
||||||
class IdleMonitoringService: ObservableObject {
|
class IdleMonitoringService: ObservableObject {
|
||||||
@Published private(set) var isIdle = false
|
@Published private(set) var isIdle = false
|
||||||
@Published private(set) var idleTimeSeconds: TimeInterval = 0
|
@Published private(set) var idleTimeSeconds: TimeInterval = 0
|
||||||
@@ -34,11 +33,9 @@ class IdleMonitoringService: ObservableObject {
|
|||||||
private func startMonitoring() {
|
private func startMonitoring() {
|
||||||
timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] _ in
|
timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] _ in
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
Task { @MainActor in
|
|
||||||
self.checkIdleState()
|
self.checkIdleState()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private func checkIdleState() {
|
private func checkIdleState() {
|
||||||
idleTimeSeconds = CGEventSource.secondsSinceLastEventType(
|
idleTimeSeconds = CGEventSource.secondsSinceLastEventType(
|
||||||
@@ -82,7 +79,6 @@ struct UsageStatistics: Codable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@MainActor
|
|
||||||
class UsageTrackingService: ObservableObject {
|
class UsageTrackingService: ObservableObject {
|
||||||
@Published private(set) var statistics: UsageStatistics
|
@Published private(set) var statistics: UsageStatistics
|
||||||
|
|
||||||
@@ -120,10 +116,8 @@ class UsageTrackingService: ObservableObject {
|
|||||||
|
|
||||||
idleService.$isIdle
|
idleService.$isIdle
|
||||||
.sink { [weak self] isIdle in
|
.sink { [weak self] isIdle in
|
||||||
Task { @MainActor in
|
|
||||||
self?.updateTracking(isIdle: isIdle)
|
self?.updateTracking(isIdle: isIdle)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,11 +129,9 @@ class UsageTrackingService: ObservableObject {
|
|||||||
private func startTracking() {
|
private func startTracking() {
|
||||||
Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] _ in
|
Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] _ in
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
Task { @MainActor in
|
|
||||||
self.tick()
|
self.tick()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private func tick() {
|
private func tick() {
|
||||||
let now = Date()
|
let now = Date()
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
import AppKit
|
import AppKit
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
@MainActor
|
|
||||||
final class SystemSleepManager {
|
final class SystemSleepManager {
|
||||||
private let settingsManager: any SettingsProviding
|
private let settingsManager: any SettingsProviding
|
||||||
private weak var timerEngine: (any TimerEngineProviding)?
|
private weak var timerEngine: (any TimerEngineProviding)?
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
@MainActor
|
|
||||||
final class ReminderTriggerService {
|
final class ReminderTriggerService {
|
||||||
private let settingsProvider: any SettingsProviding
|
private let settingsProvider: any SettingsProviding
|
||||||
private let enforceModeService: EnforceModeService?
|
private let enforceModeService: EnforceModeService?
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ protocol SmartModeCoordinatorDelegate: AnyObject {
|
|||||||
func smartModeDidRequestResumeAll(_ coordinator: SmartModeCoordinator, reason: PauseReason)
|
func smartModeDidRequestResumeAll(_ coordinator: SmartModeCoordinator, reason: PauseReason)
|
||||||
}
|
}
|
||||||
|
|
||||||
@MainActor
|
|
||||||
final class SmartModeCoordinator {
|
final class SmartModeCoordinator {
|
||||||
weak var delegate: SmartModeCoordinatorDelegate?
|
weak var delegate: SmartModeCoordinatorDelegate?
|
||||||
|
|
||||||
@@ -35,18 +34,14 @@ final class SmartModeCoordinator {
|
|||||||
|
|
||||||
fullscreenService?.$isFullscreenActive
|
fullscreenService?.$isFullscreenActive
|
||||||
.sink { [weak self] isFullscreen in
|
.sink { [weak self] isFullscreen in
|
||||||
Task { @MainActor in
|
|
||||||
self?.handleFullscreenChange(isFullscreen: isFullscreen)
|
self?.handleFullscreenChange(isFullscreen: isFullscreen)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
|
|
||||||
idleService?.$isIdle
|
idleService?.$isIdle
|
||||||
.sink { [weak self] isIdle in
|
.sink { [weak self] isIdle in
|
||||||
Task { @MainActor in
|
|
||||||
self?.handleIdleChange(isIdle: isIdle)
|
self?.handleIdleChange(isIdle: isIdle)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
import Combine
|
import Combine
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
@MainActor
|
|
||||||
class TimerEngine: ObservableObject {
|
class TimerEngine: ObservableObject {
|
||||||
@Published var timerStates: [TimerIdentifier: TimerState] = [:]
|
@Published var timerStates: [TimerIdentifier: TimerState] = [:]
|
||||||
@Published var activeReminder: ReminderEvent?
|
@Published var activeReminder: ReminderEvent?
|
||||||
@@ -47,9 +46,7 @@ class TimerEngine: ObservableObject {
|
|||||||
)
|
)
|
||||||
self.configurationHelper = TimerConfigurationHelper(settingsProvider: settingsManager)
|
self.configurationHelper = TimerConfigurationHelper(settingsProvider: settingsManager)
|
||||||
|
|
||||||
Task { @MainActor in
|
|
||||||
enforceModeService?.setTimerEngine(self)
|
enforceModeService?.setTimerEngine(self)
|
||||||
}
|
|
||||||
|
|
||||||
scheduler.delegate = self
|
scheduler.delegate = self
|
||||||
smartModeCoordinator.delegate = self
|
smartModeCoordinator.delegate = self
|
||||||
@@ -175,7 +172,7 @@ class TimerEngine: ObservableObject {
|
|||||||
for: identifier,
|
for: identifier,
|
||||||
secondsRemaining: updatedState.remainingSeconds
|
secondsRemaining: updatedState.remainingSeconds
|
||||||
) {
|
) {
|
||||||
Task { @MainActor in
|
Task {
|
||||||
await reminderService.prepareEnforceMode(
|
await reminderService.prepareEnforceMode(
|
||||||
secondsRemaining: updatedState.remainingSeconds)
|
secondsRemaining: updatedState.remainingSeconds)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ protocol TimerSchedulerDelegate: AnyObject {
|
|||||||
func schedulerDidTick(_ scheduler: TimerScheduler)
|
func schedulerDidTick(_ scheduler: TimerScheduler)
|
||||||
}
|
}
|
||||||
|
|
||||||
@MainActor
|
|
||||||
final class TimerScheduler {
|
final class TimerScheduler {
|
||||||
weak var delegate: TimerSchedulerDelegate?
|
weak var delegate: TimerSchedulerDelegate?
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
import Combine
|
import Combine
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
@MainActor
|
|
||||||
final class TimerStateManager: ObservableObject {
|
final class TimerStateManager: ObservableObject {
|
||||||
@Published private(set) var timerStates: [TimerIdentifier: TimerState] = [:]
|
@Published private(set) var timerStates: [TimerIdentifier: TimerState] = [:]
|
||||||
@Published private(set) var activeReminder: ReminderEvent?
|
@Published private(set) var activeReminder: ReminderEvent?
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import Foundation
|
|||||||
import Sparkle
|
import Sparkle
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@MainActor
|
|
||||||
class UpdateManager: NSObject, ObservableObject {
|
class UpdateManager: NSObject, ObservableObject {
|
||||||
static let shared = UpdateManager()
|
static let shared = UpdateManager()
|
||||||
|
|
||||||
@@ -49,21 +48,17 @@ class UpdateManager: NSObject, ObservableObject {
|
|||||||
options: [.new, .initial]
|
options: [.new, .initial]
|
||||||
) { [weak self] _, change in
|
) { [weak self] _, change in
|
||||||
guard let self = self, let newValue = change.newValue else { return }
|
guard let self = self, let newValue = change.newValue else { return }
|
||||||
Task { @MainActor in
|
|
||||||
self.automaticallyChecksForUpdates = newValue
|
self.automaticallyChecksForUpdates = newValue
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
lastCheckDateObservation = updater.observe(
|
lastCheckDateObservation = updater.observe(
|
||||||
\.lastUpdateCheckDate,
|
\.lastUpdateCheckDate,
|
||||||
options: [.new, .initial]
|
options: [.new, .initial]
|
||||||
) { [weak self] _, change in
|
) { [weak self] _, change in
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
Task { @MainActor in
|
|
||||||
self.lastUpdateCheckDate = change.newValue ?? nil
|
self.lastUpdateCheckDate = change.newValue ?? nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
func checkForUpdates() {
|
func checkForUpdates() {
|
||||||
|
|||||||
Reference in New Issue
Block a user