diff --git a/Cork/Views/Start Page/Sub-Views/Adoptable Packages Box.swift b/Cork/Views/Start Page/Sub-Views/Adoptable Packages Box.swift index bac41d3f..b7d45293 100644 --- a/Cork/Views/Start Page/Sub-Views/Adoptable Packages Box.swift +++ b/Cork/Views/Start Page/Sub-Views/Adoptable Packages Box.swift @@ -23,29 +23,6 @@ struct AdoptablePackagesSection: View @State private var isShowingAdoptionWarning: Bool = false @Query private var excludedApps: [ExcludedAdoptableApp] - - /// Includes only apps that are **not ignored**, but still includes apps that are **not marked for adoption** - private var adoptableAppsExcludingThoseIgnored: [BrewPackagesTracker.AdoptableApp] - { - return brewPackagesTracker.adoptableApps.filter { adoptableApp in - !excludedApps.contains(where: { $0.appExecutable == adoptableApp.appExecutable }) - } - .sorted(by: { $0.caskName < $1.caskName }) - } - - /// Includes only apps that are **not ignored**, and only includes those that are **marked for adoption** - private var adoptableAppsThatWillBeAdopted: [BrewPackagesTracker.AdoptableApp] - { - return adoptableAppsExcludingThoseIgnored.filter(\.isMarkedForAdoption) - } - - private var ignoredAdoptableApps: [BrewPackagesTracker.AdoptableApp] - { - return brewPackagesTracker.adoptableApps.filter { adoptableApp in - excludedApps.contains(where: { $0.appExecutable == adoptableApp.appExecutable }) - } - .sorted(by: { $0.caskName < $1.caskName }) - } var body: some View { @@ -62,7 +39,7 @@ struct AdoptablePackagesSection: View HStack(alignment: .firstTextBaseline) { VStack(alignment: .leading, spacing: 5) { - Text("start-page.adoptable-packages.available.\(adoptableAppsExcludingThoseIgnored.count)") + Text("start-page.adoptable-packages.available.\(brewPackagesTracker.adoptableAppsNonExcluded.count)") .font(.headline) Text("start-page.adoptable-packages.excluded.\(excludedApps.count)") @@ -74,7 +51,7 @@ struct AdoptablePackagesSection: View if enableExtraAnimations { viewProxy - .animation(.bouncy, value: adoptableAppsExcludingThoseIgnored.count) + .animation(.bouncy, value: brewPackagesTracker.adoptableAppsNonExcluded.count) .animation(.bouncy, value: excludedApps.count) .contentTransition(.numericText()) } @@ -90,11 +67,11 @@ struct AdoptablePackagesSection: View { isShowingAdoptionWarning = true - AppConstants.shared.logger.info("Will adopt \(adoptableAppsThatWillBeAdopted.count, privacy: .public) apps") + AppConstants.shared.logger.info("Will adopt \(brewPackagesTracker.adoptableAppsSelectedToBeAdopted.count, privacy: .public) apps") } label: { if brewPackagesTracker.hasSelectedOnlySomeAppsToAdopt { - Text("action.adopt-some-packages.\(adoptableAppsThatWillBeAdopted.count)") + Text("action.adopt-some-packages.\(brewPackagesTracker.adoptableAppsSelectedToBeAdopted.count)") } else { @@ -109,7 +86,7 @@ struct AdoptablePackagesSection: View adoptablePackagesList } - if !ignoredAdoptableApps.isEmpty + if !brewPackagesTracker.excludedAdoptableApps.isEmpty { DisclosureGroup("adoptable-packages.excluded-label") { @@ -142,10 +119,6 @@ struct AdoptablePackagesSection: View Text("action.cancel") } - DisclosureGroup("adoptable-packages.label") - { - adoptablePackagesList - } Button(role: .cancel) { isShowingAdoptionWarning = false @@ -155,6 +128,12 @@ struct AdoptablePackagesSection: View } message: { Text("package-adoption.confirmation.message") + + List + { + Text("package-adoption.confirmation.message") + Text("package-adoption.confirmation.message") + } } .dialogSeverity(.standard) } @@ -173,7 +152,7 @@ struct AdoptablePackagesSection: View { Section { - ForEach(adoptableAppsExcludingThoseIgnored.prefix(numberOfMaxShownAdoptableApps)) + ForEach(brewPackagesTracker.adoptableAppsNonExcluded.prefix(numberOfMaxShownAdoptableApps)) { adoptableCask in HStack(alignment: .center) { @@ -222,7 +201,7 @@ struct AdoptablePackagesSection: View Label("action.show-more", systemImage: "chevron.down") } .buttonStyle(.accessoryBar) - .disabled(numberOfMaxShownAdoptableApps >= adoptableAppsExcludingThoseIgnored.count) + .disabled(numberOfMaxShownAdoptableApps >= brewPackagesTracker.adoptableAppsNonExcluded.count) Spacer() @@ -250,7 +229,7 @@ struct AdoptablePackagesSection: View { Section { - ForEach(ignoredAdoptableApps.prefix(numberOfMaxShownIgnoredAdoptableApps)) + ForEach(brewPackagesTracker.excludedAdoptableApps.prefix(numberOfMaxShownIgnoredAdoptableApps)) { ignoredApp in AdoptablePackageListItem(adoptableCask: ignoredApp, exclusionButtonType: .includeOnly) .saturation(0.3) @@ -268,7 +247,7 @@ struct AdoptablePackagesSection: View Label("action.show-more", systemImage: "chevron.down") } .buttonStyle(.accessoryBar) - .disabled(numberOfMaxShownIgnoredAdoptableApps >= ignoredAdoptableApps.count) + .disabled(numberOfMaxShownIgnoredAdoptableApps >= brewPackagesTracker.excludedAdoptableApps.count) Spacer() diff --git a/Modules/Packages/PackagesModels/Trackers/Brew Packages Tracker.swift b/Modules/Packages/PackagesModels/Trackers/Brew Packages Tracker.swift index 4bfc0680..ec3212ef 100644 --- a/Modules/Packages/PackagesModels/Trackers/Brew Packages Tracker.swift +++ b/Modules/Packages/PackagesModels/Trackers/Brew Packages Tracker.swift @@ -8,10 +8,15 @@ import Foundation import SwiftUI import Defaults +import SwiftData +import FactoryKit +import CorkShared @Observable @MainActor public class BrewPackagesTracker { + @ObservationIgnored @Injected(\.appConstants) private var appConstants: AppConstants + public init() {} public var installedFormulae: BrewPackages = .init() @@ -122,11 +127,52 @@ public class BrewPackagesTracker } } + // MARK: - App adoption + /// All adoptable apps, including those that are excluded public var adoptableApps: [AdoptableApp] = .init() + public var excludedAdoptableApps: [AdoptableApp] + { + return adoptableApps.filter { adoptableApp in + excludedAdoptableAppsInSavedFormat.contains(where: { $0.appExecutable == adoptableApp.appExecutable }) + } + .sorted(by: { $0.caskName < $1.caskName }) + } + + private static var excludedAdoptableAppsFetchDescriptor: FetchDescriptor = .init(predicate: #Predicate { _ in + return true + }) + + /// Saved excluded adoptable apps + private var excludedAdoptableAppsInSavedFormat: [ExcludedAdoptableApp] + { + do + { + let fetchedExcludedPackages = try appConstants.modelContainer.mainContext.fetch(BrewPackagesTracker.excludedAdoptableAppsFetchDescriptor) + + return fetchedExcludedPackages + } + catch let excludedPackagesFetchingError + { + appConstants.logger.error("Failed to fetch adoptable apps from database inside BrewPackagesTracker!: \(excludedPackagesFetchingError)") + + return .init() + } + } + + /// Adoptable apps, minus those that are excluded + public var adoptableAppsNonExcluded: [AdoptableApp] + { + return adoptableApps.filter { adoptableApp in + return !excludedAdoptableAppsInSavedFormat.contains(where: { $0.appExecutable == adoptableApp.appExecutable }) + } + .sorted(by: { $0.caskName < $1.caskName }) + } + + /// Adoptable apps that will get installed when clicking the `Adopt` button public var adoptableAppsSelectedToBeAdopted: [AdoptableApp] { - return self.adoptableApps.filter(\.isMarkedForAdoption) + return self.adoptableAppsNonExcluded.filter(\.isMarkedForAdoption) } public var hasSelectedOnlySomeAppsToAdopt: Bool