cleaning up concurrency warnings

This commit is contained in:
Michael Freno
2026-01-30 01:09:08 -05:00
parent 10b93978e4
commit 44a8f40a27
26 changed files with 72 additions and 103 deletions

View File

@@ -13,3 +13,5 @@ enum PauseReason: Codable, Equatable, Hashable {
case idle case idle
case system case system
} }
extension PauseReason: Sendable {}

View File

@@ -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 }

View File

@@ -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 }

View File

@@ -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 }

View File

@@ -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 }

View File

@@ -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

View File

@@ -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,

View File

@@ -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()

View File

@@ -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

View File

@@ -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?

View File

@@ -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 {

View File

@@ -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
} }

View File

@@ -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()

View File

@@ -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()

View File

@@ -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

View File

@@ -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()

View File

@@ -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()

View File

@@ -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),

View File

@@ -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()

View File

@@ -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)?

View File

@@ -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?

View File

@@ -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)
} }

View File

@@ -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)
} }

View File

@@ -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?

View File

@@ -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?

View File

@@ -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() {