diff --git a/App/Resources/Localizable.strings b/App/Resources/Localizable.strings index ae0fcac4..781cc7ca 100644 --- a/App/Resources/Localizable.strings +++ b/App/Resources/Localizable.strings @@ -8,8 +8,6 @@ "AlbumsBarButtonItem.standardAccessibilityLabel" = "Albums"; -"AlbumsViewController.navigationTitle" = "Albums"; - "AppDelegate.preferencesMenuTitle" = "Preferences"; "AppDelegate.preferencesMenuItemTitle" = "Preferences…"; "AppDelegate.saveMenuTitle" = "Save"; @@ -20,9 +18,6 @@ "BasePhotoEditingViewController.undoKeyCommandDiscoverabilityTitle" = "Undo Redaction"; "BasePhotoEditingViewController.redoKeyCommandDiscoverabilityTitle" = "Redo Redaction"; -"CollectionsDataSource.userAlbumsHeader" = "Albums"; -"CollectionsDataSource.smartAlbumsHeader" = "Library"; - "ColorPickerBarButtonItem.accessibilityLabel" = "Color Picker"; "ContactMailViewController.emailSubject" = "Hello!"; diff --git a/Modules/Capabilities/AlbumsData/Resources/en.lproj/Localizable.strings b/Modules/Capabilities/AlbumsData/Resources/en.lproj/Localizable.strings new file mode 100644 index 00000000..8d8b07d4 --- /dev/null +++ b/Modules/Capabilities/AlbumsData/Resources/en.lproj/Localizable.strings @@ -0,0 +1,13 @@ +/* + Localizable.strings + Highlighter + + Created by Geoff Pado on 7/1/24. + Copyright © 2024 Cocoatype, LLC. All rights reserved. +*/ + +// Header for the user albums section in the albums list +"PhotoCollectionsDataSource.userAlbumsHeader" = "Albums"; + +// Header for the smart albums section in the albums list +"PhotoCollectionsDataSource.smartAlbumsHeader" = "Library"; diff --git a/Modules/Legacy/Core/Sources/Photo Selection/Photo Library/Collections/Collection.swift b/Modules/Capabilities/AlbumsData/Sources/AssetCollection.swift similarity index 59% rename from Modules/Legacy/Core/Sources/Photo Selection/Photo Library/Collections/Collection.swift rename to Modules/Capabilities/AlbumsData/Sources/AssetCollection.swift index d4efb2a8..b6eaeb52 100644 --- a/Modules/Legacy/Core/Sources/Photo Selection/Photo Library/Collections/Collection.swift +++ b/Modules/Capabilities/AlbumsData/Sources/AssetCollection.swift @@ -1,30 +1,18 @@ -// Created by Geoff Pado on 5/16/20. -// Copyright © 2020 Cocoatype, LLC. All rights reserved. +// Created by Geoff Pado on 7/1/24. +// Copyright © 2024 Cocoatype, LLC. All rights reserved. import DesignSystem import Photos -import UIKit -struct CollectionSection { - let title: String - let collections: [Collection] -} - -protocol Collection { - var title: String? { get } - var icon: String { get } - var identifier: String { get } -} - -struct AssetCollection: Collection { - var assets: PHFetchResult { +public struct AssetCollection: PhotoCollection { + public var assets: PHFetchResult { let fetchOptions = PHFetchOptions() fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: true)] return PHAsset.fetchAssets(in: assetCollection, options: fetchOptions) } var assetCount: Int { return assets.count } var assetCollectionSubtype: PHAssetCollectionSubtype { assetCollection.assetCollectionSubtype } - var icon: String { + public var icon: String { switch assetCollection.assetCollectionSubtype { case .smartAlbumFavorites: return Icons.favoritesCollection case .smartAlbumRecentlyAdded, .smartAlbumUserLibrary: return Icons.recentsCollection @@ -33,8 +21,8 @@ struct AssetCollection: Collection { } } var keyAssets: PHFetchResult { return PHAsset.fetchKeyAssets(in: assetCollection, options: nil) ?? PHFetchResult() } - var identifier: String { return assetCollection.localIdentifier } - var title: String? { return assetCollection.localizedTitle } + public var identifier: String { return assetCollection.localIdentifier } + public var title: String? { return assetCollection.localizedTitle } init(_ assetCollection: PHAssetCollection) { self.assetCollection = assetCollection @@ -42,9 +30,3 @@ struct AssetCollection: Collection { private let assetCollection: PHAssetCollection } - -struct EmptyCollection: Collection { - var title: String? { nil } - var icon: String { Icons.standardCollection } - var identifier: String { "" } -} diff --git a/Modules/Capabilities/AlbumsData/Sources/EmptyCollection.swift b/Modules/Capabilities/AlbumsData/Sources/EmptyCollection.swift new file mode 100644 index 00000000..11a0f383 --- /dev/null +++ b/Modules/Capabilities/AlbumsData/Sources/EmptyCollection.swift @@ -0,0 +1,10 @@ +// Created by Geoff Pado on 7/1/24. +// Copyright © 2024 Cocoatype, LLC. All rights reserved. + +import DesignSystem + +struct EmptyCollection: PhotoCollection { + var title: String? { nil } + var icon: String { Icons.standardCollection } + var identifier: String { "" } +} diff --git a/Modules/Capabilities/AlbumsData/Sources/PhotoCollection.swift b/Modules/Capabilities/AlbumsData/Sources/PhotoCollection.swift new file mode 100644 index 00000000..985b4beb --- /dev/null +++ b/Modules/Capabilities/AlbumsData/Sources/PhotoCollection.swift @@ -0,0 +1,8 @@ +// Created by Geoff Pado on 5/16/20. +// Copyright © 2020 Cocoatype, LLC. All rights reserved. + +public protocol PhotoCollection { + var title: String? { get } + var icon: String { get } + var identifier: String { get } +} diff --git a/Modules/Capabilities/AlbumsData/Sources/PhotoCollectionSection.swift b/Modules/Capabilities/AlbumsData/Sources/PhotoCollectionSection.swift new file mode 100644 index 00000000..a62a1d38 --- /dev/null +++ b/Modules/Capabilities/AlbumsData/Sources/PhotoCollectionSection.swift @@ -0,0 +1,12 @@ +// Created by Geoff Pado on 7/1/24. +// Copyright © 2024 Cocoatype, LLC. All rights reserved. + +public struct PhotoCollectionSection { + public let title: String + public let collections: [PhotoCollection] + + public init(title: String, collections: [PhotoCollection]) { + self.title = title + self.collections = collections + } +} diff --git a/Modules/Legacy/Core/Sources/Photo Selection/Photo Library/Collections/CollectionType.swift b/Modules/Capabilities/AlbumsData/Sources/PhotoCollectionType.swift similarity index 93% rename from Modules/Legacy/Core/Sources/Photo Selection/Photo Library/Collections/CollectionType.swift rename to Modules/Capabilities/AlbumsData/Sources/PhotoCollectionType.swift index 808d47d3..736c91c4 100644 --- a/Modules/Legacy/Core/Sources/Photo Selection/Photo Library/Collections/CollectionType.swift +++ b/Modules/Capabilities/AlbumsData/Sources/PhotoCollectionType.swift @@ -3,7 +3,7 @@ import Photos -enum CollectionType { +public enum PhotoCollectionType { case favorites case library case recents @@ -31,7 +31,7 @@ enum CollectionType { return PHAssetCollection.fetchAssetCollections(with: assetCollectionType, subtype: assetCollectionSubtype, options: nil) } - var defaultCollection: Collection { + public var defaultCollection: PhotoCollection { guard let defaultCollection = fetchResult.firstObject else { assertionFailure("Did not return a default collection for type: \(self)") return AssetCollection(PHAssetCollection()) diff --git a/Modules/Capabilities/AlbumsData/Sources/PhotoCollectionsDataSource.swift b/Modules/Capabilities/AlbumsData/Sources/PhotoCollectionsDataSource.swift new file mode 100644 index 00000000..cb736195 --- /dev/null +++ b/Modules/Capabilities/AlbumsData/Sources/PhotoCollectionsDataSource.swift @@ -0,0 +1,44 @@ +// Created by Geoff Pado on 5/16/20. +// Copyright © 2020 Cocoatype, LLC. All rights reserved. + +import ErrorHandling +import Photos +import UIKit + +public class PhotoCollectionsDataSource: NSObject, ObservableObject, PHPhotoLibraryChangeObserver { + @Published public var collectionsData: [PhotoCollectionSection] + + public override init() { + collectionsData = Self.allSections() + super.init() + + PHPhotoLibrary.shared().register(self) + } + + // MARK: Change Observer + + public func photoLibraryDidChange(_ changeInstance: PHChange) { + Task { @MainActor in + collectionsData = Self.allSections() + } + } + + // MARK: Boilerplate + + private static func allSections() -> [PhotoCollectionSection] { + return [ + Self.section(title: AlbumsDataStrings.PhotoCollectionsDataSource.smartAlbumsHeader, types: [.library, .screenshots, .favorites]), + Self.section(title: AlbumsDataStrings.PhotoCollectionsDataSource.userAlbumsHeader, types: [.userAlbum]), + ] + } + + private static func section(title: String, types: [PhotoCollectionType]) -> PhotoCollectionSection { + PhotoCollectionSection( + title: title, + collections: types + .map { $0.fetchResult } + .flatMap { $0.objects(at: IndexSet(integersIn: 0..<$0.count)) } + .map(AssetCollection.init) + ) + } +} diff --git a/Modules/Capabilities/AlbumsData/Tests/AlbumsDataTests.swift b/Modules/Capabilities/AlbumsData/Tests/AlbumsDataTests.swift new file mode 100644 index 00000000..a826717d --- /dev/null +++ b/Modules/Capabilities/AlbumsData/Tests/AlbumsDataTests.swift @@ -0,0 +1,7 @@ +// +// AlbumsDataTest.swift +// Highlighter +// +// Created by Geoff Pado on 7/1/24. +// Copyright © 2024 Cocoatype, LLC. All rights reserved. +// diff --git a/Modules/Capabilities/AlbumsUI/Resources/en.lproj/Localizable.strings b/Modules/Capabilities/AlbumsUI/Resources/en.lproj/Localizable.strings new file mode 100644 index 00000000..ad4db631 --- /dev/null +++ b/Modules/Capabilities/AlbumsUI/Resources/en.lproj/Localizable.strings @@ -0,0 +1,10 @@ +/* + Localizable.strings + Highlighter + + Created by Geoff Pado on 7/1/24. + Copyright © 2024 Cocoatype, LLC. All rights reserved. +*/ + +// Navigation title for the albums list +"AlbumsViewController.navigationTitle" = "Albums"; diff --git a/Modules/Legacy/Core/Sources/Photo Selection/Albums/AlbumsHeaderLabel.swift b/Modules/Capabilities/AlbumsUI/Sources/AlbumsHeaderLabel.swift similarity index 100% rename from Modules/Legacy/Core/Sources/Photo Selection/Albums/AlbumsHeaderLabel.swift rename to Modules/Capabilities/AlbumsUI/Sources/AlbumsHeaderLabel.swift diff --git a/Modules/Legacy/Core/Sources/Photo Selection/Albums/AlbumsHeaderView.swift b/Modules/Capabilities/AlbumsUI/Sources/AlbumsHeaderView.swift similarity index 100% rename from Modules/Legacy/Core/Sources/Photo Selection/Albums/AlbumsHeaderView.swift rename to Modules/Capabilities/AlbumsUI/Sources/AlbumsHeaderView.swift diff --git a/Modules/Legacy/Core/Sources/Photo Selection/Albums/AlbumsList.swift b/Modules/Capabilities/AlbumsUI/Sources/AlbumsList.swift similarity index 64% rename from Modules/Legacy/Core/Sources/Photo Selection/Albums/AlbumsList.swift rename to Modules/Capabilities/AlbumsUI/Sources/AlbumsList.swift index b34f5379..89162557 100644 --- a/Modules/Legacy/Core/Sources/Photo Selection/Albums/AlbumsList.swift +++ b/Modules/Capabilities/AlbumsUI/Sources/AlbumsList.swift @@ -1,20 +1,22 @@ // Created by Geoff Pado on 7/15/20. // Copyright © 2020 Cocoatype, LLC. All rights reserved. +import AlbumsData +import AppNavigation import SwiftUI -struct AlbumsList: View { +public struct AlbumsList: View { @State private var selectedCollectionIdentifier: String? + @StateObject private var dataSource = PhotoCollectionsDataSource() + var navigationWrapper = NavigationWrapper.empty - let data: [CollectionSection] - init(data: [CollectionSection], selectedCollectionIdentifier: String? = CollectionType.library.defaultCollection.identifier) { - self.data = data + init(selectedCollectionIdentifier: String? = PhotoCollectionType.library.defaultCollection.identifier) { self.selectedCollectionIdentifier = selectedCollectionIdentifier } - var body: some View { - return List(selection: $selectedCollectionIdentifier) { - ForEach(data, id: \.title) { section in + public var body: some View { + List(selection: $selectedCollectionIdentifier) { + ForEach(dataSource.collectionsData, id: \.title) { section in Section(header: AlbumsSectionHeader(section.title)) { ForEach(section.collections, id: \.identifier) { collection in AlbumsRow(collection, selection: $selectedCollectionIdentifier) @@ -23,7 +25,7 @@ struct AlbumsList: View { } } .listStyle(SidebarListStyle()) - .navigationTitle("AlbumsViewController.navigationTitle") + .navigationTitle(AlbumsUIStrings.AlbumsViewController.navigationTitle) .environmentObject(navigationWrapper) .albumsListBackground() } @@ -31,21 +33,21 @@ struct AlbumsList: View { enum AlbumsList_Previews: PreviewProvider { static let fakeData = [ - CollectionSection(title: "Smart Collections", collections: [ + PhotoCollectionSection(title: "Smart Collections", collections: [ DummyCollection(title: "Recent Photos", iconName: "clock"), DummyCollection(title: "Screenshots", iconName: "camera.viewfinder"), DummyCollection(title: "Favorites", iconName: "suit.heart"), ]), - CollectionSection(title: "User Collections", collections: []), + PhotoCollectionSection(title: "User Collections", collections: []), ] static var previews: some View { - AlbumsList(data: fakeData, selectedCollectionIdentifier: nil) + AlbumsList(selectedCollectionIdentifier: nil) .preferredColorScheme(.dark) } } -struct DummyCollection: Collection { +struct DummyCollection: PhotoCollection { let title: String? let icon: String let identifier: String diff --git a/Modules/Legacy/Core/Sources/Photo Selection/Albums/AlbumsListBackgroundViewModifier.swift b/Modules/Capabilities/AlbumsUI/Sources/AlbumsListBackgroundViewModifier.swift similarity index 100% rename from Modules/Legacy/Core/Sources/Photo Selection/Albums/AlbumsListBackgroundViewModifier.swift rename to Modules/Capabilities/AlbumsUI/Sources/AlbumsListBackgroundViewModifier.swift diff --git a/Modules/Legacy/Core/Sources/Photo Selection/Albums/AlbumsRow.swift b/Modules/Capabilities/AlbumsUI/Sources/AlbumsRow.swift similarity index 86% rename from Modules/Legacy/Core/Sources/Photo Selection/Albums/AlbumsRow.swift rename to Modules/Capabilities/AlbumsUI/Sources/AlbumsRow.swift index 97773ea5..ce86b3fd 100644 --- a/Modules/Legacy/Core/Sources/Photo Selection/Albums/AlbumsRow.swift +++ b/Modules/Capabilities/AlbumsUI/Sources/AlbumsRow.swift @@ -1,12 +1,14 @@ // Created by Geoff Pado on 8/30/21. // Copyright © 2021 Cocoatype, LLC. All rights reserved. +import AlbumsData +import AppNavigation import SwiftUI struct AlbumsRow: View { @Binding var selection: String? - private let collection: Collection - init(_ collection: Collection, selection: Binding) { + private let collection: PhotoCollection + init(_ collection: PhotoCollection, selection: Binding) { self.collection = collection self._selection = selection } diff --git a/Modules/Legacy/Core/Sources/Photo Selection/Albums/AlbumsRowSelectedViewModifier.swift b/Modules/Capabilities/AlbumsUI/Sources/AlbumsRowSelectedViewModifier.swift similarity index 100% rename from Modules/Legacy/Core/Sources/Photo Selection/Albums/AlbumsRowSelectedViewModifier.swift rename to Modules/Capabilities/AlbumsUI/Sources/AlbumsRowSelectedViewModifier.swift diff --git a/Modules/Legacy/Core/Sources/Photo Selection/Albums/AlbumsSectionHeader.swift b/Modules/Capabilities/AlbumsUI/Sources/AlbumsSectionHeader.swift similarity index 100% rename from Modules/Legacy/Core/Sources/Photo Selection/Albums/AlbumsSectionHeader.swift rename to Modules/Capabilities/AlbumsUI/Sources/AlbumsSectionHeader.swift diff --git a/Modules/Legacy/Core/Sources/Photo Selection/Albums/AlbumsViewController.swift b/Modules/Capabilities/AlbumsUI/Sources/AlbumsViewController.swift similarity index 53% rename from Modules/Legacy/Core/Sources/Photo Selection/Albums/AlbumsViewController.swift rename to Modules/Capabilities/AlbumsUI/Sources/AlbumsViewController.swift index e8c3e3ca..2e26f6d7 100644 --- a/Modules/Legacy/Core/Sources/Photo Selection/Albums/AlbumsViewController.swift +++ b/Modules/Capabilities/AlbumsUI/Sources/AlbumsViewController.swift @@ -1,23 +1,21 @@ // Created by Geoff Pado on 7/15/20. // Copyright © 2020 Cocoatype, LLC. All rights reserved. -import Editing +import AlbumsData +import AppNavigation import Photos import Redactions import SwiftUI -class AlbumsViewController: UIHostingController, NavigationWrapper.NavigationObject { - init() { - let albumsDataSource = CollectionsDataSource() - self.albumsDataSource = albumsDataSource - - var albumsList = AlbumsList(data: albumsDataSource.collectionsData) +public class AlbumsViewController: UIHostingController, NavigationWrapper.NavigationObject { + public init() { + var albumsList = AlbumsList() super.init(rootView: albumsList) view.tintColor = .primaryDark - if let navigationObject = navigationObject { - navigationItem.title = Self.navigationTitle + if let navigationObject { + navigationItem.title = AlbumsUIStrings.AlbumsViewController.navigationTitle albumsList.navigationWrapper = NavigationWrapper(navigationObject: navigationObject) self.rootView = albumsList } @@ -25,36 +23,32 @@ class AlbumsViewController: UIHostingController, NavigationWrapper.N // MARK: NavigationObject - func presentSettingsViewController() { + public func presentSettingsViewController() { next?.settingsPresenter?.presentSettingsViewController() } - func presentPhotoEditingViewController(for asset: PHAsset, redactions: [Redaction]?, animated: Bool) { + public func presentPhotoEditingViewController(for asset: PHAsset, redactions: [Redaction]?, animated: Bool) { next?.photoEditorPresenter?.presentPhotoEditingViewController(for: asset, redactions: redactions, animated: animated) } - func presentPhotoEditingViewController(for image: UIImage, redactions: [Redaction]?, animated: Bool, completionHandler: ((UIImage) -> Void)?) { + public func presentPhotoEditingViewController(for image: UIImage, redactions: [Redaction]?, animated: Bool, completionHandler: ((UIImage) -> Void)?) { next?.photoEditorPresenter?.presentPhotoEditingViewController(for: image, redactions: nil, animated: true, completionHandler: completionHandler) } - func presentDocumentCameraViewController() { + public func presentDocumentCameraViewController() { next?.documentScannerPresenter?.presentDocumentCameraViewController() } - func present(_ collection: Collection) { + public func present(_ collection: PhotoCollection) { next?.collectionPresenter?.present(collection) } - func presentLimitedLibrary() { + public func presentLimitedLibrary() { next?.limitedLibraryPresenter?.presentLimitedLibrary() } // MARK: Boilerplate - private static let navigationTitle = NSLocalizedString("AlbumsViewController.navigationTitle", comment: "Navigation title for the albums list") - - private let albumsDataSource: CollectionsDataSource - @available(*, unavailable) required init(coder: NSCoder) { let typeName = NSStringFromClass(type(of: self)) diff --git a/Modules/Capabilities/AlbumsUI/Tests/AlbumsTests.swift b/Modules/Capabilities/AlbumsUI/Tests/AlbumsTests.swift new file mode 100644 index 00000000..7be769f0 --- /dev/null +++ b/Modules/Capabilities/AlbumsUI/Tests/AlbumsTests.swift @@ -0,0 +1,7 @@ +// +// AlbumsTests.swift +// Highlighter +// +// Created by Geoff Pado on 7/1/24. +// Copyright © 2024 Cocoatype, LLC. All rights reserved. +// diff --git a/Modules/Capabilities/AppNavigation/Sources/CollectionPresenting.swift b/Modules/Capabilities/AppNavigation/Sources/CollectionPresenting.swift new file mode 100644 index 00000000..104b61ac --- /dev/null +++ b/Modules/Capabilities/AppNavigation/Sources/CollectionPresenting.swift @@ -0,0 +1,19 @@ +// Created by Geoff Pado on 10/2/20. +// Copyright © 2020 Cocoatype, LLC. All rights reserved. + +import AlbumsData +import UIKit + +public protocol PhotoCollectionPresenting { + func present(_ collection: PhotoCollection) +} + +extension UIResponder { + public var collectionPresenter: PhotoCollectionPresenting? { + if let presenter = (self as? PhotoCollectionPresenting) { + return presenter + } + + return next?.collectionPresenter + } +} diff --git a/Modules/Legacy/Core/Sources/Photo Editing/DocumentScannerPresenting.swift b/Modules/Capabilities/AppNavigation/Sources/DocumentScannerPresenting.swift similarity index 75% rename from Modules/Legacy/Core/Sources/Photo Editing/DocumentScannerPresenting.swift rename to Modules/Capabilities/AppNavigation/Sources/DocumentScannerPresenting.swift index 4d25bdd7..71811bab 100644 --- a/Modules/Legacy/Core/Sources/Photo Editing/DocumentScannerPresenting.swift +++ b/Modules/Capabilities/AppNavigation/Sources/DocumentScannerPresenting.swift @@ -3,12 +3,12 @@ import UIKit -protocol DocumentScannerPresenting { +public protocol DocumentScannerPresenting { func presentDocumentCameraViewController() } extension UIResponder { - var documentScannerPresenter: DocumentScannerPresenting? { + public var documentScannerPresenter: DocumentScannerPresenting? { if let presenter = (self as? DocumentScannerPresenting) { return presenter } diff --git a/Modules/Capabilities/AppNavigation/Sources/LimitedLibraryPresenting.swift b/Modules/Capabilities/AppNavigation/Sources/LimitedLibraryPresenting.swift new file mode 100644 index 00000000..70b39bf8 --- /dev/null +++ b/Modules/Capabilities/AppNavigation/Sources/LimitedLibraryPresenting.swift @@ -0,0 +1,18 @@ +// Created by Geoff Pado on 10/16/20. +// Copyright © 2020 Cocoatype, LLC. All rights reserved. + +import SwiftUI + +public protocol LimitedLibraryPresenting { + func presentLimitedLibrary() +} + +extension UIResponder { + public var limitedLibraryPresenter: LimitedLibraryPresenting? { + if let presenter = (self as? LimitedLibraryPresenting) { + return presenter + } + + return next?.limitedLibraryPresenter + } +} diff --git a/Modules/Legacy/Core/Sources/Photo Selection/NavigationWrapper.swift b/Modules/Capabilities/AppNavigation/Sources/NavigationWrapper.swift similarity index 59% rename from Modules/Legacy/Core/Sources/Photo Selection/NavigationWrapper.swift rename to Modules/Capabilities/AppNavigation/Sources/NavigationWrapper.swift index 1d13c3b7..d88904f6 100644 --- a/Modules/Legacy/Core/Sources/Photo Selection/NavigationWrapper.swift +++ b/Modules/Capabilities/AppNavigation/Sources/NavigationWrapper.swift @@ -1,34 +1,35 @@ // Created by Geoff Pado on 5/22/21. // Copyright © 2021 Cocoatype, LLC. All rights reserved. +import AlbumsData import Photos import UIKit -class NavigationWrapper: NSObject, ObservableObject { - typealias NavigationObject = (SettingsPresenting & PhotoEditorPresenting & DocumentScannerPresenting & CollectionPresenting & LimitedLibraryPresenting) - init(navigationObject: NavigationObject) { +public class NavigationWrapper: NSObject, ObservableObject { + public typealias NavigationObject = (SettingsPresenting & PhotoEditorPresenting & DocumentScannerPresenting & PhotoCollectionPresenting & LimitedLibraryPresenting) + public init(navigationObject: NavigationObject) { self.navigationObject = navigationObject } - static let empty = NavigationWrapper() + public static let empty = NavigationWrapper() private override init() { self.navigationObject = nil } - func presentSettings() { + public func presentSettings() { navigationObject?.presentSettingsViewController() } - func presentEditor(for asset: PHAsset) { + public func presentEditor(for asset: PHAsset) { navigationObject?.presentPhotoEditingViewController(for: asset, redactions: nil, animated: true) } - func presentDocumentScanner() { + public func presentDocumentScanner() { navigationObject?.presentDocumentCameraViewController() } - func present(_ collection: Collection) { + public func present(_ collection: PhotoCollection) { navigationObject?.present(collection) } @@ -40,7 +41,7 @@ class NavigationWrapper: NSObject, ObservableObject { } extension UIResponder { - var navigationObject: NavigationWrapper.NavigationObject? { + public var navigationObject: NavigationWrapper.NavigationObject? { if let navigationObject = (self as? NavigationWrapper.NavigationObject) { return navigationObject } diff --git a/Modules/Legacy/Core/Sources/Photo Editing/PhotoEditorPresenting.swift b/Modules/Capabilities/AppNavigation/Sources/PhotoEditorPresenting.swift similarity index 84% rename from Modules/Legacy/Core/Sources/Photo Editing/PhotoEditorPresenting.swift rename to Modules/Capabilities/AppNavigation/Sources/PhotoEditorPresenting.swift index e83cfb92..c4ea40ac 100644 --- a/Modules/Legacy/Core/Sources/Photo Editing/PhotoEditorPresenting.swift +++ b/Modules/Capabilities/AppNavigation/Sources/PhotoEditorPresenting.swift @@ -1,18 +1,17 @@ // Created by Geoff Pado on 4/15/19. // Copyright © 2019 Cocoatype, LLC. All rights reserved. -import Editing import Photos import Redactions import UIKit -protocol PhotoEditorPresenting { +public protocol PhotoEditorPresenting { func presentPhotoEditingViewController(for asset: PHAsset, redactions: [Redaction]?, animated: Bool) func presentPhotoEditingViewController(for image: UIImage, redactions: [Redaction]?, animated: Bool, completionHandler: ((UIImage) -> Void)?) } extension UIResponder { - var photoEditorPresenter: PhotoEditorPresenting? { + public var photoEditorPresenter: PhotoEditorPresenting? { if let presenter = (self as? PhotoEditorPresenting) { return presenter } diff --git a/Modules/Legacy/Core/Sources/Photo Selection/Photo Library/SettingsPresenting.swift b/Modules/Capabilities/AppNavigation/Sources/SettingsPresenting.swift similarity index 78% rename from Modules/Legacy/Core/Sources/Photo Selection/Photo Library/SettingsPresenting.swift rename to Modules/Capabilities/AppNavigation/Sources/SettingsPresenting.swift index 0a84fcdd..1f966bcb 100644 --- a/Modules/Legacy/Core/Sources/Photo Selection/Photo Library/SettingsPresenting.swift +++ b/Modules/Capabilities/AppNavigation/Sources/SettingsPresenting.swift @@ -3,12 +3,12 @@ import UIKit -protocol SettingsPresenting { +public protocol SettingsPresenting { func presentSettingsViewController() } extension UIResponder { - var settingsPresenter: SettingsPresenting? { + public var settingsPresenter: SettingsPresenting? { if let settingsPresenter = (self as? SettingsPresenting) { return settingsPresenter } diff --git a/Modules/Legacy/Core/Sources/Document Scanning/DocumentScanningController.swift b/Modules/Legacy/Core/Sources/Document Scanning/DocumentScanningController.swift index 7c8dcb5c..983c635d 100644 --- a/Modules/Legacy/Core/Sources/Document Scanning/DocumentScanningController.swift +++ b/Modules/Legacy/Core/Sources/Document Scanning/DocumentScanningController.swift @@ -1,6 +1,7 @@ // Created by Geoff Pado on 2/16/22. // Copyright © 2022 Cocoatype, LLC. All rights reserved. +import AppNavigation import Editing import Purchasing import UIKit diff --git a/Modules/Legacy/Core/Sources/Library/LibrarySplitViewController.swift b/Modules/Legacy/Core/Sources/Library/LibrarySplitViewController.swift index c077f334..67da4a40 100644 --- a/Modules/Legacy/Core/Sources/Library/LibrarySplitViewController.swift +++ b/Modules/Legacy/Core/Sources/Library/LibrarySplitViewController.swift @@ -1,12 +1,15 @@ // Created by Geoff Pado on 5/18/22. // Copyright © 2022 Cocoatype, LLC. All rights reserved. +import AlbumsData +import AlbumsUI +import AppNavigation import Editing import Photos import PhotosUI import UIKit -class LibrarySplitViewController: SplitViewController, CollectionPresenting, LimitedLibraryPresenting { +class LibrarySplitViewController: SplitViewController, PhotoCollectionPresenting, LimitedLibraryPresenting { init() { let albumsNavigationController = NavigationController(rootViewController: AlbumsViewController()) let photoLibraryNavigationController = NavigationController(rootViewController: PhotoLibraryViewController()) @@ -22,7 +25,7 @@ class LibrarySplitViewController: SplitViewController, CollectionPresenting, Lim return photoLibraryViewController } - func present(_ collection: Collection) { + func present(_ collection: PhotoCollection) { photoLibraryViewController?.collection = collection show(.secondary) } diff --git a/Modules/Legacy/Core/Sources/Photo Selection/CollectionPresenting.swift b/Modules/Legacy/Core/Sources/Photo Selection/CollectionPresenting.swift deleted file mode 100644 index d2039ca1..00000000 --- a/Modules/Legacy/Core/Sources/Photo Selection/CollectionPresenting.swift +++ /dev/null @@ -1,18 +0,0 @@ -// Created by Geoff Pado on 10/2/20. -// Copyright © 2020 Cocoatype, LLC. All rights reserved. - -import UIKit - -protocol CollectionPresenting { - func present(_ collection: Collection) -} - -extension UIResponder { - var collectionPresenter: CollectionPresenting? { - if let presenter = (self as? CollectionPresenting) { - return presenter - } - - return next?.collectionPresenter - } -} diff --git a/Modules/Legacy/Core/Sources/Photo Selection/Photo Library/Collections/CollectionsDataSource.swift b/Modules/Legacy/Core/Sources/Photo Selection/Photo Library/Collections/CollectionsDataSource.swift deleted file mode 100644 index 194f30f5..00000000 --- a/Modules/Legacy/Core/Sources/Photo Selection/Photo Library/Collections/CollectionsDataSource.swift +++ /dev/null @@ -1,48 +0,0 @@ -// Created by Geoff Pado on 5/16/20. -// Copyright © 2020 Cocoatype, LLC. All rights reserved. - -import ErrorHandling -import UIKit - -class CollectionsDataSource: NSObject { - lazy var smartCollections: [Collection] = { - return allCollections(types: [CollectionType.library, .screenshots, .favorites]) - }() - - lazy var userCollections: [Collection] = { - return allCollections(types: [CollectionType.userAlbum]) - }() - - private func allCollections(types: [CollectionType]) -> [Collection] { - return types - .map { $0.fetchResult } - .flatMap { $0.objects(at: IndexSet(integersIn: 0..<$0.count)) } - .map(AssetCollection.init) - } - - // MARK: Data Access - - private func collections(forSection section: Int) -> [Collection] { - switch section { - case 0: return smartCollections - case 1: return userCollections - default: return [] - } - } - - func collection(at indexPath: IndexPath) -> Collection { - return collections(forSection: indexPath.section)[indexPath.row] - } - - // MARK: SwiftUI Data Source - - var collectionsData: [CollectionSection] {[ - CollectionSection(title: Self.smartAlbumsHeader, collections: smartCollections), - CollectionSection(title: Self.userAlbumsHeader, collections: userCollections), - ]} - - // MARK: Localizable Strings - - private static let smartAlbumsHeader = NSLocalizedString("CollectionsDataSource.smartAlbumsHeader", comment: "Header for the smart albums section in the albums list") - private static let userAlbumsHeader = NSLocalizedString("CollectionsDataSource.userAlbumsHeader", comment: "Header for the user albums section in the albums list") -} diff --git a/Modules/Legacy/Core/Sources/Photo Selection/Photo Library/Data Source/PhotoLibraryDataSource.swift b/Modules/Legacy/Core/Sources/Photo Selection/Photo Library/Data Source/PhotoLibraryDataSource.swift index 3f989808..d445891a 100644 --- a/Modules/Legacy/Core/Sources/Photo Selection/Photo Library/Data Source/PhotoLibraryDataSource.swift +++ b/Modules/Legacy/Core/Sources/Photo Selection/Photo Library/Data Source/PhotoLibraryDataSource.swift @@ -1,6 +1,7 @@ // Created by Geoff Pado on 4/8/19. // Copyright © 2019 Cocoatype, LLC. All rights reserved. +import AlbumsData import Combine import ErrorHandling import Photos @@ -9,8 +10,8 @@ import UIKit import VisionKit class PhotoLibraryDataSource: NSObject, LibraryDataSource, UICollectionViewDataSource { - let collection: Collection - init(_ collection: Collection) { + let collection: PhotoCollection + init(_ collection: PhotoCollection) { self.collection = collection self.assetsProvider = PhotoLibraryDataSourceAssetsProvider(collection: collection) self.changeCalculator = PhotoLibraryDataSourceChangeCalculator(collection: collection) diff --git a/Modules/Legacy/Core/Sources/Photo Selection/Photo Library/Data Source/PhotoLibraryDataSourceAssetsProvider.swift b/Modules/Legacy/Core/Sources/Photo Selection/Photo Library/Data Source/PhotoLibraryDataSourceAssetsProvider.swift index 8cbfc5db..288e25f4 100644 --- a/Modules/Legacy/Core/Sources/Photo Selection/Photo Library/Data Source/PhotoLibraryDataSourceAssetsProvider.swift +++ b/Modules/Legacy/Core/Sources/Photo Selection/Photo Library/Data Source/PhotoLibraryDataSourceAssetsProvider.swift @@ -1,13 +1,14 @@ // Created by Geoff Pado on 5/31/21. // Copyright © 2021 Cocoatype, LLC. All rights reserved. +import AlbumsData import ErrorHandling import Photos import UIKit class PhotoLibraryDataSourceAssetsProvider: NSObject { var photosCount: Int { allPhotos.count } - init(collection: Collection) { + init(collection: PhotoCollection) { self.collection = collection } @@ -37,5 +38,5 @@ class PhotoLibraryDataSourceAssetsProvider: NSObject { return collection.assets } - private let collection: Collection + private let collection: PhotoCollection } diff --git a/Modules/Legacy/Core/Sources/Photo Selection/Photo Library/Data Source/PhotoLibraryDataSourceChangeCalculator.swift b/Modules/Legacy/Core/Sources/Photo Selection/Photo Library/Data Source/PhotoLibraryDataSourceChangeCalculator.swift index 792b92a1..0e4f5c10 100644 --- a/Modules/Legacy/Core/Sources/Photo Selection/Photo Library/Data Source/PhotoLibraryDataSourceChangeCalculator.swift +++ b/Modules/Legacy/Core/Sources/Photo Selection/Photo Library/Data Source/PhotoLibraryDataSourceChangeCalculator.swift @@ -1,14 +1,12 @@ // Created by Geoff Pado on 5/31/21. // Copyright © 2021 Cocoatype, LLC. All rights reserved. +import AlbumsData import Photos class PhotoLibraryDataSourceChangeCalculator: NSObject { - init(collection: Collection) { - self.fetchResult = { - guard let collection = collection as? AssetCollection else { return PHFetchResult() } - return collection.assets - }() + init(collection: PhotoCollection) { + self.fetchResult = (collection as? AssetCollection)?.assets ?? PHFetchResult() } private func details(for change: PHChange) -> PHFetchResultChangeDetails? { @@ -17,8 +15,7 @@ class PhotoLibraryDataSourceChangeCalculator: NSObject { func changedResult(for change: PHChange) -> PHFetchResult { guard let changeDetails = details(for: change) else { return fetchResult } - fetchResult = changeDetails.fetchResultAfterChanges - return fetchResult + return changeDetails.fetchResultAfterChanges } func update(_ libraryView: PhotoLibraryView, from change: PHChange) { @@ -28,6 +25,8 @@ class PhotoLibraryDataSourceChangeCalculator: NSObject { return libraryView.reloadData() } + fetchResult = changedResult(for: change) + libraryView.performBatchUpdates({ [unowned libraryView, changeDetails] in if let removed = changeDetails.removedIndexes { libraryView.deleteItems(at: removed.map { IndexPath(item: $0, section: 0) }) @@ -43,7 +42,7 @@ class PhotoLibraryDataSourceChangeCalculator: NSObject { libraryView.moveItem(at: IndexPath(item: fromIndex, section: 0), to: IndexPath(item: toIndex, section: 0)) } - }, completion: nil) + }) } private(set) var fetchResult: PHFetchResult diff --git a/Modules/Legacy/Core/Sources/Photo Selection/Photo Library/Legacy/PhotoLibraryViewController.swift b/Modules/Legacy/Core/Sources/Photo Selection/Photo Library/Legacy/PhotoLibraryViewController.swift index c40a4a87..5a457def 100644 --- a/Modules/Legacy/Core/Sources/Photo Selection/Photo Library/Legacy/PhotoLibraryViewController.swift +++ b/Modules/Legacy/Core/Sources/Photo Selection/Photo Library/Legacy/PhotoLibraryViewController.swift @@ -1,13 +1,14 @@ // Created by Geoff Pado on 4/8/19. // Copyright © 2019 Cocoatype, LLC. All rights reserved. +import AlbumsData import Defaults import Editing import Photos import UIKit class PhotoLibraryViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDragDelegate, UIDropInteractionDelegate, PHPhotoLibraryChangeObserver { - init(collection: Collection = CollectionType.library.defaultCollection) { + init(collection: PhotoCollection = PhotoCollectionType.library.defaultCollection) { self.dataSource = PhotoLibraryDataSource(collection) super.init(nibName: nil, bundle: nil) @@ -51,7 +52,7 @@ class PhotoLibraryViewController: UIViewController, UICollectionViewDelegate, UI libraryView.reloadData() } - var collection: Collection { + var collection: PhotoCollection { get { return dataSource.collection } set(newCollection) { let newDataSource = PhotoLibraryDataSource(newCollection) diff --git a/Modules/Legacy/Core/Sources/Photo Selection/Photo Library/Library Items/AssetButton.swift b/Modules/Legacy/Core/Sources/Photo Selection/Photo Library/Library Items/AssetButton.swift index e636e974..69a17ae5 100644 --- a/Modules/Legacy/Core/Sources/Photo Selection/Photo Library/Library Items/AssetButton.swift +++ b/Modules/Legacy/Core/Sources/Photo Selection/Photo Library/Library Items/AssetButton.swift @@ -1,6 +1,7 @@ // Created by Geoff Pado on 7/1/20. // Copyright © 2020 Cocoatype, LLC. All rights reserved. +import AppNavigation import Photos import SwiftUI diff --git a/Modules/Legacy/Core/Sources/Photo Selection/Photo Library/Library Items/DocumentScanButton.swift b/Modules/Legacy/Core/Sources/Photo Selection/Photo Library/Library Items/DocumentScanButton.swift index f3e2a112..b159e03e 100644 --- a/Modules/Legacy/Core/Sources/Photo Selection/Photo Library/Library Items/DocumentScanButton.swift +++ b/Modules/Legacy/Core/Sources/Photo Selection/Photo Library/Library Items/DocumentScanButton.swift @@ -1,6 +1,7 @@ // Created by Geoff Pado on 7/1/20. // Copyright © 2020 Cocoatype, LLC. All rights reserved. +import AppNavigation import Editing import SwiftUI diff --git a/Modules/Legacy/Core/Sources/Photo Selection/Photo Library/Library Items/LimitedLibraryButton.swift b/Modules/Legacy/Core/Sources/Photo Selection/Photo Library/Library Items/LimitedLibraryButton.swift deleted file mode 100644 index af1912e4..00000000 --- a/Modules/Legacy/Core/Sources/Photo Selection/Photo Library/Library Items/LimitedLibraryButton.swift +++ /dev/null @@ -1,35 +0,0 @@ -// Created by Geoff Pado on 10/16/20. -// Copyright © 2020 Cocoatype, LLC. All rights reserved. - -import SwiftUI - -struct LimitedLibraryButton: View { - var body: some View { - GeometryReader { proxy in - Button { - navigationWrapper.presentLimitedLibrary() - } label: { - ZStack { - RoundedRectangle(cornerRadius: 8.0).strokeBorder(style: StrokeStyle(dash: [4, 2]), antialiased: /*@START_MENU_TOKEN@*/true/*@END_MENU_TOKEN@*/).padding(8).foregroundColor(Color.primaryLight) - Image(systemName: "rectangle.stack.badge.plus").resizable( resizingMode: /*@START_MENU_TOKEN@*/.stretch/*@END_MENU_TOKEN@*/).frame(width: proxy.size.width / 2.0, height: proxy.size.height / 2.0, alignment: /*@START_MENU_TOKEN@*/.center/*@END_MENU_TOKEN@*/).foregroundColor(Color.primaryExtraLight) - } - } - } - } - - @EnvironmentObject private var navigationWrapper: NavigationWrapper -} - -protocol LimitedLibraryPresenting { - func presentLimitedLibrary() -} - -extension UIResponder { - var limitedLibraryPresenter: LimitedLibraryPresenting? { - if let presenter = (self as? LimitedLibraryPresenting) { - return presenter - } - - return next?.limitedLibraryPresenter - } -} diff --git a/Modules/Legacy/Core/Sources/Photo Selection/Photo Library/SettingsButton.swift b/Modules/Legacy/Core/Sources/Photo Selection/Photo Library/SettingsButton.swift index 633402d9..9a03f1d9 100644 --- a/Modules/Legacy/Core/Sources/Photo Selection/Photo Library/SettingsButton.swift +++ b/Modules/Legacy/Core/Sources/Photo Selection/Photo Library/SettingsButton.swift @@ -1,6 +1,7 @@ // Created by Geoff Pado on 8/12/20. // Copyright © 2020 Cocoatype, LLC. All rights reserved. +import AppNavigation import SwiftUI struct SettingsButton: View { diff --git a/Modules/Legacy/Core/Sources/Photo Selection/PhotoSelectionNavigationController.swift b/Modules/Legacy/Core/Sources/Photo Selection/PhotoSelectionNavigationController.swift deleted file mode 100644 index bcc42f87..00000000 --- a/Modules/Legacy/Core/Sources/Photo Selection/PhotoSelectionNavigationController.swift +++ /dev/null @@ -1,45 +0,0 @@ -// Created by Geoff Pado on 4/8/19. -// Copyright © 2019 Cocoatype, LLC. All rights reserved. - -import DesignSystem -import Editing -import Introspect -import Photos -import SwiftUI -import UIKit - -struct PhotoSelection: View { - init(data: [CollectionSection]) { - self.collectionsData = data - } - - var body: some View { - NavigationView { - AlbumsList(data: collectionsData) - }.accentColor(.primaryLight).introspectNavigationController { navigationController in - let navigationBar = navigationController.navigationBar - navigationBar.standardAppearance = NavigationBarAppearance() - } - } - - static func hostingController(presenter: NavigationWrapper.NavigationObject) -> UIViewController { - let albumsDataSource = CollectionsDataSource() - let selectionView = PhotoSelection(data: albumsDataSource.collectionsData) - .environmentObject(NavigationWrapper(navigationObject: presenter)) - return UIHostingController(rootView: selectionView) - } - - private var initialCollection: Collection { - guard let firstCollection = collectionsData.first?.collections.first else { return EmptyCollection() } - return firstCollection - } - - private let collectionsData: [CollectionSection] -} - -enum PhotoSelection_Previews: PreviewProvider { - static var previews: some View { - PhotoSelection(data: AlbumsList_Previews.fakeData) - .previewDevice("iPad Pro (9.7-inch)").preferredColorScheme(.dark) - } -} diff --git a/Project.swift b/Project.swift index a515e2c8..8c5a4305 100644 --- a/Project.swift +++ b/Project.swift @@ -12,6 +12,9 @@ let project = Project( AutomatorActions.target, Photo.target, // modules + AlbumsData.target, + AlbumsUI.target, + AppNavigation.target, AppRatings.target, AutoRedactionsUI.target, Brushes.target(sdk: .catalyst), @@ -31,7 +34,6 @@ let project = Project( Geometry.target(sdk: .native), Logging.target(sdk: .catalyst), Logging.target(sdk: .native), - Navigation.target, Observations.target(sdk: .catalyst), Observations.target(sdk: .native), PurchaseMarketing.target, @@ -50,6 +52,8 @@ let project = Project( TestHelpers.target, TestHelpers.interfaceTarget, // tests + AlbumsData.testTarget, + AlbumsUI.testTarget, AppRatings.testTarget, AutoRedactionsUI.testTarget, Brushes.testTarget, diff --git a/Tuist/ProjectDescriptionHelpers/Targets/Capabilities/AlbumsData.swift b/Tuist/ProjectDescriptionHelpers/Targets/Capabilities/AlbumsData.swift new file mode 100644 index 00000000..12150cf2 --- /dev/null +++ b/Tuist/ProjectDescriptionHelpers/Targets/Capabilities/AlbumsData.swift @@ -0,0 +1,14 @@ +import ProjectDescription + +public enum AlbumsData { + public static let target = Target.capabilitiesTarget( + name: "AlbumsData", + hasResources: true, + dependencies: [ + .target(DesignSystem.target), + .target(ErrorHandling.target(sdk: .catalyst)), + ] + ) + + public static let testTarget = Target.capabilitiesTestTarget(name: "AlbumsData") +} diff --git a/Tuist/ProjectDescriptionHelpers/Targets/Capabilities/AlbumsUI.swift b/Tuist/ProjectDescriptionHelpers/Targets/Capabilities/AlbumsUI.swift new file mode 100644 index 00000000..27a5d134 --- /dev/null +++ b/Tuist/ProjectDescriptionHelpers/Targets/Capabilities/AlbumsUI.swift @@ -0,0 +1,15 @@ +import ProjectDescription + +public enum AlbumsUI { + public static let target = Target.capabilitiesTarget( + name: "AlbumsUI", + hasResources: true, + dependencies: [ + .target(AppNavigation.target), + .target(DesignSystem.target), + .target(Redactions.target(sdk: .catalyst)), + ] + ) + + public static let testTarget = Target.capabilitiesTestTarget(name: "AlbumsUI") +} diff --git a/Tuist/ProjectDescriptionHelpers/Targets/Capabilities/Navigation.swift b/Tuist/ProjectDescriptionHelpers/Targets/Capabilities/AppNavigation.swift similarity index 75% rename from Tuist/ProjectDescriptionHelpers/Targets/Capabilities/Navigation.swift rename to Tuist/ProjectDescriptionHelpers/Targets/Capabilities/AppNavigation.swift index e2ae9565..3f78fdf2 100644 --- a/Tuist/ProjectDescriptionHelpers/Targets/Capabilities/Navigation.swift +++ b/Tuist/ProjectDescriptionHelpers/Targets/Capabilities/AppNavigation.swift @@ -1,9 +1,10 @@ import ProjectDescription -public enum Navigation { +public enum AppNavigation { public static let target = Target.capabilitiesTarget( name: "AppNavigation", dependencies: [ + .target(AlbumsData.target), .target(Redactions.target(sdk: .catalyst)), ] ) diff --git a/Tuist/ProjectDescriptionHelpers/Targets/Capabilities/Shortcuts.swift b/Tuist/ProjectDescriptionHelpers/Targets/Capabilities/Shortcuts.swift index b3954b13..5c88321d 100644 --- a/Tuist/ProjectDescriptionHelpers/Targets/Capabilities/Shortcuts.swift +++ b/Tuist/ProjectDescriptionHelpers/Targets/Capabilities/Shortcuts.swift @@ -5,9 +5,9 @@ public enum Shortcuts { name: "Shortcuts", hasResources: true, dependencies: [ + .target(AppNavigation.target), .target(Detections.target(sdk: .catalyst)), .target(Exporting.target(sdk: .catalyst)), - .target(Navigation.target), .target(Observations.target(sdk: .catalyst)), .target(Purchasing.target), .target(Redactions.target(sdk: .catalyst)), diff --git a/Tuist/ProjectDescriptionHelpers/Targets/Legacy/Core.swift b/Tuist/ProjectDescriptionHelpers/Targets/Legacy/Core.swift index a31279b4..7e32e84e 100644 --- a/Tuist/ProjectDescriptionHelpers/Targets/Legacy/Core.swift +++ b/Tuist/ProjectDescriptionHelpers/Targets/Legacy/Core.swift @@ -9,12 +9,13 @@ public enum Core { sources: ["Modules/Legacy/Core/Sources/**"], headers: .headers(public: ["Modules/Legacy/Core/Headers/**"]), dependencies: [ + .target(AlbumsUI.target), + .target(AppNavigation.target), .target(AppRatings.target), .target(Defaults.target), .target(DesignSystem.target), .target(Detections.target(sdk: .catalyst)), .target(Editing.target), - .target(Navigation.target), .target(PurchaseMarketing.target), .target(Purchasing.target), .target(Purchasing.doublesTarget),