+ Weird nonisolation shit

This commit is contained in:
David Bureš 2025-08-06 15:36:32 +02:00
parent 0d3480d5b8
commit c199d071db
6 changed files with 89 additions and 32 deletions

View File

@ -10,11 +10,14 @@ import CorkNotifications
import CorkShared
import Foundation
import Observation
import Defaults
import DefaultsMacros
import Dependencies
@preconcurrency import UserNotifications
/// Class that holds the global state of the app, excluding services
@Observable @MainActor
final class AppState
@Observable
final class AppState: Sendable
{
// MARK: - Licensing
@ -71,14 +74,53 @@ final class AppState
var corruptedPackage: String = ""
// MARK: - Other
@ObservableDefault(.enableExtraAnimations) @ObservationIgnored
var enableExtraAnimations: Bool
{
return UserDefaults.standard.bool(forKey: "enableExtraAnimations")
// MARK: - Custom Initializers
nonisolated init() {
self.licensingState = .notBoughtOrHasNotActivatedDemo
self.navigationTargetId = nil
self.notificationEnabledInSystemSettings = nil
self.notificationAuthStatus = .notDetermined
self.isSearchFieldFocused = false
self.brewfileImportingStage = .importing
self.isShowingUninstallationProgressView = false
self.isShowingFatalError = false
self.fatalAlertType = nil
self.isShowingConfirmationDialog = false
self.confirmationDialogType = nil
self.sheetToShow = nil
self.packageTryingToBeUninstalledWithSudo = nil
self.isShowingRemoveTapFailedAlert = false
self.isLoadingFormulae = true
self.isLoadingCasks = true
self.isLoadingTaps = true
self.isLoadingTopPackages = false
self.failedWhileLoadingFormulae = false
self.failedWhileLoadingCasks = false
self.failedWhileLoadingTaps = false
self.failedWhileLoadingTopPackages = false
self.corruptedPackage = ""
}
}
// MARK: - Showing errors
extension AppState: DependencyKey
{
static let liveValue: AppState = .init()
}
private extension UNUserNotificationCenter
{
func authorizationStatus() async -> UNAuthorizationStatus
{
await notificationSettings().authorizationStatus
}
}
extension AppState
{
// MARK: - Alert Functions
func showAlert(errorToShow: DisplayableAlert)
{
fatalAlertType = errorToShow
@ -92,9 +134,11 @@ final class AppState
fatalAlertType = nil
}
}
// MARK: - Showing sheets
extension AppState
{
// MARK: - Sheet Functions
func showSheet(ofType sheetType: DisplayableSheet)
{
self.sheetToShow = sheetType
@ -104,9 +148,11 @@ final class AppState
{
self.sheetToShow = nil
}
}
// MARK: Showing confirmation dialogs
extension AppState
{
// MARK: - Confirmation Dialogs
func showConfirmationDialog(ofType confirmationDialogType: ConfirmationDialog)
{
self.confirmationDialogType = confirmationDialogType
@ -118,9 +164,11 @@ final class AppState
self.isShowingConfirmationDialog = false
self.confirmationDialogType = nil
}
}
// MARK: - Notification setup
extension AppState
{
// MARK: - Notifications
func setupNotifications() async
{
let notificationCenter: UNUserNotificationCenter = AppConstants.shared.notificationCenter
@ -170,7 +218,10 @@ final class AppState
notificationEnabledInSystemSettings = false
}
}
}
extension AppState
{
// MARK: - Initiating the update process from legacy contexts
@objc func startUpdateProcessForLegacySelectors(_: NSMenuItem!)
@ -180,11 +231,3 @@ final class AppState
sendNotification(title: String(localized: "notification.upgrade-process-started"))
}
}
private extension UNUserNotificationCenter
{
func authorizationStatus() async -> UNAuthorizationStatus
{
await notificationSettings().authorizationStatus
}
}

View File

@ -25,7 +25,7 @@ struct GetInstalledCasksIntent: AppIntent
{
let dummyBrewData: BrewPackagesTracker = await .init()
guard let installedCasks: BrewPackages = await dummyBrewData.loadInstalledPackages(packageTypeToLoad: .cask, appState: AppState()) else
guard let installedCasks: BrewPackages = await dummyBrewData.loadInstalledPackages(packageTypeToLoad: .cask) else
{
throw IntentError.failedWhilePerformingIntent
}

View File

@ -42,7 +42,7 @@ struct GetInstalledFormulaeIntent: AppIntent
{
let dummyBrewData: BrewPackagesTracker = await .init()
guard let installedFormulae: BrewPackages = await dummyBrewData.loadInstalledPackages(packageTypeToLoad: .formula, appState: AppState()) else
guard let installedFormulae: BrewPackages = await dummyBrewData.loadInstalledPackages(packageTypeToLoad: .formula) else
{
throw IntentError.failedWhilePerformingIntent
}

View File

@ -16,8 +16,8 @@ extension BrewPackagesTracker
{
AppConstants.shared.logger.debug("Will start synchronization process")
async let updatedFormulaeTracker: BrewPackages? = await self.loadInstalledPackages(packageTypeToLoad: .formula, appState: AppState())
async let updatedCasksTracker: BrewPackages? = await self.loadInstalledPackages(packageTypeToLoad: .cask, appState: AppState())
async let updatedFormulaeTracker: BrewPackages? = await self.loadInstalledPackages(packageTypeToLoad: .formula)
async let updatedCasksTracker: BrewPackages? = await self.loadInstalledPackages(packageTypeToLoad: .cask)
guard let safeUpdatedFormulaeTracker = await updatedFormulaeTracker, let safeUpdatedCasksTracker = await updatedCasksTracker else
{

View File

@ -7,6 +7,7 @@
import CorkShared
import Foundation
import Dependencies
/// A representation of the loaded ``BrewPackage``s
/// Includes packages that were loaded properly, along those whose loading failed
@ -21,9 +22,11 @@ extension BrewPackagesTracker
/// - appState: ``AppState`` used to display loading errors
/// - Returns: A set of loaded ``BrewPackage``s for the specified ``PackageType``
func loadInstalledPackages(
packageTypeToLoad: PackageType, appState: AppState
packageTypeToLoad: PackageType
) async -> BrewPackages?
{
@Dependency(AppState.self) var appState: AppState
/// Start tracking when loading started
let timeLoadingStarted: Date = .now
AppConstants.shared.logger.debug(
@ -47,23 +50,23 @@ extension BrewPackagesTracker
{
case .couldNotReadContentsOfParentFolder(let loadingError, let folderURL):
AppConstants.shared.logger.error("Failed while loading packages: Could not read contents of parent folder (\(folderURL.path()): \(loadingError)")
appState.showAlert(errorToShow: .couldNotGetContentsOfPackageFolder(loadingError))
await appState.showAlert(errorToShow: .couldNotGetContentsOfPackageFolder(loadingError))
case .packageDoesNotHaveAnyVersionsInstalled(let packageURL):
AppConstants.shared.logger.error("Failed while loading packages: Package \(packageURL.packageNameFromURL()) does not have any versions installed")
appState.showAlert(
await appState.showAlert(
errorToShow: .installedPackageHasNoVersions(
corruptedPackageName: packageURL.packageNameFromURL()))
case .packageIsNotAFolder(let offendingFile, let offendingFileURL):
AppConstants.shared.logger.error("Failed while loading packages: Package \(offendingFileURL.path()) is not a folder")
appState.showAlert(
await appState.showAlert(
errorToShow: .installedPackageIsNotAFolder(
itemName: offendingFile, itemURL: offendingFileURL
))
case .numberOLoadedPackagesDosNotMatchNumberOfPackageFolders:
AppConstants.shared.logger.error("Failed while loading packages: Number of loaded packages does not match the number of URLs in package folder")
appState.showAlert(errorToShow: .numberOfLoadedPackagesDoesNotMatchNumberOfPackageFolders)
await appState.showAlert(errorToShow: .numberOfLoadedPackagesDoesNotMatchNumberOfPackageFolders)
case .triedToThreatFolderContainingPackagesAsPackage(let packageType):
appState.showAlert(errorToShow: .triedToThreatFolderContainingPackagesAsPackage(packageType: packageType))
await appState.showAlert(errorToShow: .triedToThreatFolderContainingPackagesAsPackage(packageType: packageType))
case .failedWhileReadingContentsOfPackageFolder(let folderURL, let reportedError):
AppConstants.shared.logger.error("Failed while loading packages: Couldn't read contents of package folder \(folderURL) with this error: \(reportedError)")
case .failedWhileTryingToDetermineIntentionalInstallation(let folderURL, let associatedIntentionalDiscoveryError):

View File

@ -7,9 +7,10 @@
import Foundation
import SwiftUI
import Dependencies
@Observable @MainActor
class BrewPackagesTracker
@Observable
final class BrewPackagesTracker: Sendable
{
var installedFormulae: BrewPackages = .init()
var installedCasks: BrewPackages = .init()
@ -89,6 +90,11 @@ class BrewPackagesTracker
installedCasks.insert(.success(package))
}
}
nonisolated init() {
self.installedFormulae = .init()
self.installedCasks = .init()
}
}
extension BrewPackagesTracker
@ -117,3 +123,8 @@ extension BrewPackagesTracker
return self.numberOfInstalledFormulae + self.numberOfInstalledCasks
}
}
extension BrewPackagesTracker: DependencyKey
{
static let liveValue: BrewPackagesTracker = .init()
}