mirror of
https://github.com/JohnEstropia/CoreStore.git
synced 2026-03-06 13:20:12 +01:00
WIP
This commit is contained in:
@@ -536,6 +536,22 @@
|
||||
B5AEFAB61C9962AE00AD137F /* CoreStoreBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5AEFAB41C9962AE00AD137F /* CoreStoreBridge.swift */; };
|
||||
B5AEFAB71C9962AE00AD137F /* CoreStoreBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5AEFAB41C9962AE00AD137F /* CoreStoreBridge.swift */; };
|
||||
B5AEFAB81C9962AE00AD137F /* CoreStoreBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5AEFAB41C9962AE00AD137F /* CoreStoreBridge.swift */; };
|
||||
B5BF7FAD234C41E90070E741 /* Internals.DiffableDataSourceSnapshot.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BF7FAC234C41E90070E741 /* Internals.DiffableDataSourceSnapshot.swift */; };
|
||||
B5BF7FAE234C41E90070E741 /* Internals.DiffableDataSourceSnapshot.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BF7FAC234C41E90070E741 /* Internals.DiffableDataSourceSnapshot.swift */; };
|
||||
B5BF7FAF234C41E90070E741 /* Internals.DiffableDataSourceSnapshot.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BF7FAC234C41E90070E741 /* Internals.DiffableDataSourceSnapshot.swift */; };
|
||||
B5BF7FB0234C41E90070E741 /* Internals.DiffableDataSourceSnapshot.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BF7FAC234C41E90070E741 /* Internals.DiffableDataSourceSnapshot.swift */; };
|
||||
B5BF7FB2234C97910070E741 /* DiffableDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BF7FB1234C97910070E741 /* DiffableDataSource.swift */; };
|
||||
B5BF7FB3234C97910070E741 /* DiffableDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BF7FB1234C97910070E741 /* DiffableDataSource.swift */; };
|
||||
B5BF7FB4234C97910070E741 /* DiffableDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BF7FB1234C97910070E741 /* DiffableDataSource.swift */; };
|
||||
B5BF7FB5234C97910070E741 /* DiffableDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BF7FB1234C97910070E741 /* DiffableDataSource.swift */; };
|
||||
B5BF7FB7234C97CE0070E741 /* DiffableDataSource.TableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BF7FB6234C97CE0070E741 /* DiffableDataSource.TableView.swift */; };
|
||||
B5BF7FB8234C97CE0070E741 /* DiffableDataSource.TableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BF7FB6234C97CE0070E741 /* DiffableDataSource.TableView.swift */; };
|
||||
B5BF7FB9234C97CE0070E741 /* DiffableDataSource.TableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BF7FB6234C97CE0070E741 /* DiffableDataSource.TableView.swift */; };
|
||||
B5BF7FBA234C97CE0070E741 /* DiffableDataSource.TableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BF7FB6234C97CE0070E741 /* DiffableDataSource.TableView.swift */; };
|
||||
B5BF7FBC234C99190070E741 /* Internals.FallbackDiffableDataUIDispatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BF7FBB234C99190070E741 /* Internals.FallbackDiffableDataUIDispatcher.swift */; };
|
||||
B5BF7FBD234C99190070E741 /* Internals.FallbackDiffableDataUIDispatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BF7FBB234C99190070E741 /* Internals.FallbackDiffableDataUIDispatcher.swift */; };
|
||||
B5BF7FBE234C99190070E741 /* Internals.FallbackDiffableDataUIDispatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BF7FBB234C99190070E741 /* Internals.FallbackDiffableDataUIDispatcher.swift */; };
|
||||
B5BF7FBF234C99190070E741 /* Internals.FallbackDiffableDataUIDispatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BF7FBB234C99190070E741 /* Internals.FallbackDiffableDataUIDispatcher.swift */; };
|
||||
B5C976E31C6C9F6A00B1AF90 /* UnsafeDataTransaction+Observing.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5C976E21C6C9F6A00B1AF90 /* UnsafeDataTransaction+Observing.swift */; };
|
||||
B5C976E41C6C9F9A00B1AF90 /* UnsafeDataTransaction+Observing.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5C976E21C6C9F6A00B1AF90 /* UnsafeDataTransaction+Observing.swift */; };
|
||||
B5C976E51C6C9F9B00B1AF90 /* UnsafeDataTransaction+Observing.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5C976E21C6C9F6A00B1AF90 /* UnsafeDataTransaction+Observing.swift */; };
|
||||
@@ -942,6 +958,10 @@
|
||||
B5AD60CD1C90141E00F2B2E8 /* Package.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Package.swift; sourceTree = SOURCE_ROOT; };
|
||||
B5AEFAB41C9962AE00AD137F /* CoreStoreBridge.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoreStoreBridge.swift; sourceTree = "<group>"; };
|
||||
B5BDC9271C2024F2008147CD /* .travis.yml */ = {isa = PBXFileReference; lastKnownFileType = text; path = .travis.yml; sourceTree = SOURCE_ROOT; };
|
||||
B5BF7FAC234C41E90070E741 /* Internals.DiffableDataSourceSnapshot.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Internals.DiffableDataSourceSnapshot.swift; sourceTree = "<group>"; };
|
||||
B5BF7FB1234C97910070E741 /* DiffableDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiffableDataSource.swift; sourceTree = "<group>"; };
|
||||
B5BF7FB6234C97CE0070E741 /* DiffableDataSource.TableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiffableDataSource.TableView.swift; sourceTree = "<group>"; };
|
||||
B5BF7FBB234C99190070E741 /* Internals.FallbackDiffableDataUIDispatcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Internals.FallbackDiffableDataUIDispatcher.swift; sourceTree = "<group>"; };
|
||||
B5C976E21C6C9F6A00B1AF90 /* UnsafeDataTransaction+Observing.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UnsafeDataTransaction+Observing.swift"; sourceTree = "<group>"; };
|
||||
B5C976E61C6E3A5900B1AF90 /* Internals.CoreStoreFetchedResultsController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Internals.CoreStoreFetchedResultsController.swift; sourceTree = "<group>"; };
|
||||
B5CA2B071F7E5ACA004B1936 /* WhereClauseType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WhereClauseType.swift; sourceTree = "<group>"; };
|
||||
@@ -1513,6 +1533,8 @@
|
||||
B5D8CA752346E7590055D7D1 /* DataStack+DataSources.swift */,
|
||||
B5F335572348D75D00FD649F /* LiveResult.swift */,
|
||||
B5E294DC2349F8E7003E5956 /* SnapshotResult.swift */,
|
||||
B5BF7FB1234C97910070E741 /* DiffableDataSource.swift */,
|
||||
B5BF7FB6234C97CE0070E741 /* DiffableDataSource.TableView.swift */,
|
||||
);
|
||||
name = DataSources;
|
||||
sourceTree = "<group>";
|
||||
@@ -1643,6 +1665,8 @@
|
||||
B5C976E61C6E3A5900B1AF90 /* Internals.CoreStoreFetchedResultsController.swift */,
|
||||
B5474D142227C08700B21FEC /* Internals.CoreStoreFetchRequest.swift */,
|
||||
B51260921E9B28F100402229 /* Internals.EntityIdentifier.swift */,
|
||||
B5BF7FAC234C41E90070E741 /* Internals.DiffableDataSourceSnapshot.swift */,
|
||||
B5BF7FBB234C99190070E741 /* Internals.FallbackDiffableDataUIDispatcher.swift */,
|
||||
B54A6A541BA15F2A007870FD /* Internals.FetchedResultsControllerDelegate.swift */,
|
||||
B501322F2346B76E00FC238B /* Internals.FetchedDiffableDataSourceSnapshotDelegate.swift */,
|
||||
B5FAD6AB1B51285300714891 /* Internals.MigrationManager.swift */,
|
||||
@@ -2018,6 +2042,7 @@
|
||||
B56007141B3F6C2800A9A8F9 /* SectionBy.swift in Sources */,
|
||||
B5DE522B230BD7CC00A22534 /* Internals.swift in Sources */,
|
||||
B5E84F371AFF85470064E85B /* NSManagedObjectContext+Transaction.swift in Sources */,
|
||||
B5BF7FB7234C97CE0070E741 /* DiffableDataSource.TableView.swift in Sources */,
|
||||
B5ECDC1D1CA81A2100C7F112 /* CSDataStack+Querying.swift in Sources */,
|
||||
B5C976E31C6C9F6A00B1AF90 /* UnsafeDataTransaction+Observing.swift in Sources */,
|
||||
B53FBA121CAB63CB00F0D40A /* Progress+ObjectiveC.swift in Sources */,
|
||||
@@ -2051,6 +2076,7 @@
|
||||
B51260931E9B28F100402229 /* Internals.EntityIdentifier.swift in Sources */,
|
||||
B5DAFB482203D9F8003FCCD0 /* Where.Expression.swift in Sources */,
|
||||
B5FE4DA21C8481E100FA6A91 /* StorageInterface.swift in Sources */,
|
||||
B5BF7FAD234C41E90070E741 /* Internals.DiffableDataSourceSnapshot.swift in Sources */,
|
||||
B53FB9FE1CAB2D2F00F0D40A /* CSMigrationResult.swift in Sources */,
|
||||
B5DBE2D21C991B3E00B5CEFA /* CSDataStack.swift in Sources */,
|
||||
B50392F91C478FF3009900CA /* NSManagedObject+Transaction.swift in Sources */,
|
||||
@@ -2104,6 +2130,7 @@
|
||||
B5E84F391AFF85470064E85B /* NSManagedObjectContext+Querying.swift in Sources */,
|
||||
B56923E81EB827F5007C4DC9 /* InferredSchemaMappingProvider.swift in Sources */,
|
||||
B53B275F1EE3B92E00E9B352 /* CoreStoreManagedObject.swift in Sources */,
|
||||
B5BF7FBC234C99190070E741 /* Internals.FallbackDiffableDataUIDispatcher.swift in Sources */,
|
||||
B5215CA41FA47DFD00139E3A /* FetchChainBuilder.swift in Sources */,
|
||||
B5D33A011E96012400C880DE /* Relationship.swift in Sources */,
|
||||
B5E84EE81AFF84610064E85B /* CoreStoreLogger.swift in Sources */,
|
||||
@@ -2123,6 +2150,7 @@
|
||||
B5E84EF81AFF846E0064E85B /* CoreStore+Transaction.swift in Sources */,
|
||||
B5E84F301AFF849C0064E85B /* NSManagedObjectContext+CoreStore.swift in Sources */,
|
||||
B5831B7A1F34ACBA00A9F647 /* Transformable.swift in Sources */,
|
||||
B5BF7FB2234C97910070E741 /* DiffableDataSource.swift in Sources */,
|
||||
B546F9691C9AF26D00D5AC55 /* CSInMemoryStore.swift in Sources */,
|
||||
B549F65E1E569C7400FBAB2D /* QueryableAttributeType.swift in Sources */,
|
||||
B5E84F211AFF84860064E85B /* CoreStore+Observing.swift in Sources */,
|
||||
@@ -2203,6 +2231,7 @@
|
||||
82BA18B21C4BBD3900A0916E /* ImportableObject.swift in Sources */,
|
||||
82BA18AE1C4BBD3100A0916E /* DataStack+Transaction.swift in Sources */,
|
||||
82BA18AB1C4BBD3100A0916E /* AsynchronousDataTransaction.swift in Sources */,
|
||||
B5BF7FBD234C99190070E741 /* Internals.FallbackDiffableDataUIDispatcher.swift in Sources */,
|
||||
B5D339D91E9489AB00C880DE /* CoreStoreObject.swift in Sources */,
|
||||
82BA18CE1C4BBD7100A0916E /* Internals.FetchedResultsControllerDelegate.swift in Sources */,
|
||||
B56923FB1EB82956007C4DC9 /* CSXcodeDataModelSchema.swift in Sources */,
|
||||
@@ -2230,6 +2259,7 @@
|
||||
B53FBA141CAB63CB00F0D40A /* Progress+ObjectiveC.swift in Sources */,
|
||||
B5831B761F34AC7A00A9F647 /* RelationshipProtocol.swift in Sources */,
|
||||
B5E5FA4F22D162F400330931 /* ObjectSnapshot.swift in Sources */,
|
||||
B5BF7FB3234C97910070E741 /* DiffableDataSource.swift in Sources */,
|
||||
B5E1B5AA1CAA49E2007FD580 /* CSDataStack+Migrating.swift in Sources */,
|
||||
B5D339F21E94AF5800C880DE /* CoreStoreStrings.swift in Sources */,
|
||||
B5E1B59F1CAA2568007FD580 /* CSDataStack+Observing.swift in Sources */,
|
||||
@@ -2326,6 +2356,7 @@
|
||||
82BA18B51C4BBD3F00A0916E /* BaseDataTransaction+Querying.swift in Sources */,
|
||||
B5F335592348D76300FD649F /* LiveResult.swift in Sources */,
|
||||
B501FDDF1CA8D05000BE22EF /* CSSectionBy.swift in Sources */,
|
||||
B5BF7FAE234C41E90070E741 /* Internals.DiffableDataSourceSnapshot.swift in Sources */,
|
||||
B538BA781D15B3E30003A766 /* CoreStoreBridge.m in Sources */,
|
||||
B51260801E97A18000402229 /* CoreStoreObject+Convenience.swift in Sources */,
|
||||
82BA18D31C4BBD7100A0916E /* NSManagedObjectContext+CoreStore.swift in Sources */,
|
||||
@@ -2357,6 +2388,7 @@
|
||||
B5ECDC0D1CA8161B00C7F112 /* CSGroupBy.swift in Sources */,
|
||||
B5D339E81E9493A500C880DE /* Entity.swift in Sources */,
|
||||
82BA18CC1C4BBD6400A0916E /* Progress+Convenience.swift in Sources */,
|
||||
B5BF7FB8234C97CE0070E741 /* DiffableDataSource.TableView.swift in Sources */,
|
||||
82BA18C01C4BBD5300A0916E /* DataStack+Observing.swift in Sources */,
|
||||
82BA18A61C4BBD2900A0916E /* DefaultLogger.swift in Sources */,
|
||||
);
|
||||
@@ -2411,6 +2443,7 @@
|
||||
B546F9761C9C553300D5AC55 /* SetupResult.swift in Sources */,
|
||||
B53FBA161CAB63CB00F0D40A /* Progress+ObjectiveC.swift in Sources */,
|
||||
B5ECDC271CA81A3900C7F112 /* CSCoreStore+Querying.swift in Sources */,
|
||||
B5BF7FBF234C99190070E741 /* Internals.FallbackDiffableDataUIDispatcher.swift in Sources */,
|
||||
B5D339DB1E9489AB00C880DE /* CoreStoreObject.swift in Sources */,
|
||||
B52DD1951BE1F92500949AFE /* CoreStoreError.swift in Sources */,
|
||||
B56923FD1EB82956007C4DC9 /* CSXcodeDataModelSchema.swift in Sources */,
|
||||
@@ -2438,6 +2471,7 @@
|
||||
B5831B781F34AC7A00A9F647 /* RelationshipProtocol.swift in Sources */,
|
||||
B52DD1981BE1F92500949AFE /* CoreStore+Setup.swift in Sources */,
|
||||
B5E5FA5122D162F400330931 /* ObjectSnapshot.swift in Sources */,
|
||||
B5BF7FB5234C97910070E741 /* DiffableDataSource.swift in Sources */,
|
||||
B5D339F41E94AF5800C880DE /* CoreStoreStrings.swift in Sources */,
|
||||
B5220E241D13085E009BC71E /* NSFetchedResultsController+Convenience.swift in Sources */,
|
||||
B559CD471CAA8B6300E4D58B /* CSSetupResult.swift in Sources */,
|
||||
@@ -2534,6 +2568,7 @@
|
||||
B5220E251D13088E009BC71E /* ListObserver.swift in Sources */,
|
||||
B5F3355B2348D76500FD649F /* LiveResult.swift in Sources */,
|
||||
B538BA7A1D15B3E30003A766 /* CoreStoreBridge.m in Sources */,
|
||||
B5BF7FB0234C41E90070E741 /* Internals.DiffableDataSourceSnapshot.swift in Sources */,
|
||||
B51260821E97A18000402229 /* CoreStoreObject+Convenience.swift in Sources */,
|
||||
B52DD1A01BE1F92C00949AFE /* UnsafeDataTransaction.swift in Sources */,
|
||||
B5ECDC331CA81CDC00C7F112 /* CSCoreStore+Transaction.swift in Sources */,
|
||||
@@ -2565,6 +2600,7 @@
|
||||
B598514B1C90289F00C99590 /* NSPersistentStoreCoordinator+Setup.swift in Sources */,
|
||||
B5D339EA1E9493A500C880DE /* Entity.swift in Sources */,
|
||||
B52DD1AA1BE1F93500949AFE /* TypeErasedClauses.swift in Sources */,
|
||||
B5BF7FBA234C97CE0070E741 /* DiffableDataSource.TableView.swift in Sources */,
|
||||
B53FBA021CAB2D2F00F0D40A /* CSMigrationResult.swift in Sources */,
|
||||
B51FE5AF1CD4D00300E54258 /* CoreStore+CustomDebugStringConvertible.swift in Sources */,
|
||||
);
|
||||
@@ -2619,6 +2655,7 @@
|
||||
B56321AD1BD6521C006C9394 /* Internals.MigrationManager.swift in Sources */,
|
||||
B563219D1BD65216006C9394 /* DataStack+Observing.swift in Sources */,
|
||||
B56321961BD65216006C9394 /* From.swift in Sources */,
|
||||
B5BF7FBE234C99190070E741 /* Internals.FallbackDiffableDataUIDispatcher.swift in Sources */,
|
||||
B5D339DA1E9489AB00C880DE /* CoreStoreObject.swift in Sources */,
|
||||
B5ECDC021CA80CBA00C7F112 /* CSWhere.swift in Sources */,
|
||||
B56923FC1EB82956007C4DC9 /* CSXcodeDataModelSchema.swift in Sources */,
|
||||
@@ -2646,6 +2683,7 @@
|
||||
B5E1B5AB1CAA49E2007FD580 /* CSDataStack+Migrating.swift in Sources */,
|
||||
B5831B771F34AC7A00A9F647 /* RelationshipProtocol.swift in Sources */,
|
||||
B5E5FA5022D162F400330931 /* ObjectSnapshot.swift in Sources */,
|
||||
B5BF7FB4234C97910070E741 /* DiffableDataSource.swift in Sources */,
|
||||
B5D339F31E94AF5800C880DE /* CoreStoreStrings.swift in Sources */,
|
||||
B5E1B5A01CAA2568007FD580 /* CSDataStack+Observing.swift in Sources */,
|
||||
B5ECDC261CA81A3900C7F112 /* CSCoreStore+Querying.swift in Sources */,
|
||||
@@ -2742,6 +2780,7 @@
|
||||
B56321921BD65216006C9394 /* BaseDataTransaction+Querying.swift in Sources */,
|
||||
B5F3355A2348D76500FD649F /* LiveResult.swift in Sources */,
|
||||
B501FDE01CA8D05000BE22EF /* CSSectionBy.swift in Sources */,
|
||||
B5BF7FAF234C41E90070E741 /* Internals.DiffableDataSourceSnapshot.swift in Sources */,
|
||||
B538BA791D15B3E30003A766 /* CoreStoreBridge.m in Sources */,
|
||||
B51260811E97A18000402229 /* CoreStoreObject+Convenience.swift in Sources */,
|
||||
B56321B11BD6521C006C9394 /* NSManagedObjectContext+CoreStore.swift in Sources */,
|
||||
@@ -2773,6 +2812,7 @@
|
||||
B5ECDC0E1CA8161B00C7F112 /* CSGroupBy.swift in Sources */,
|
||||
B5D339E91E9493A500C880DE /* Entity.swift in Sources */,
|
||||
B56321A41BD65216006C9394 /* CoreStore+Migration.swift in Sources */,
|
||||
B5BF7FB9234C97CE0070E741 /* DiffableDataSource.TableView.swift in Sources */,
|
||||
B56321A01BD65216006C9394 /* ObjectObserver.swift in Sources */,
|
||||
B56321951BD65216006C9394 /* TypeErasedClauses.swift in Sources */,
|
||||
);
|
||||
|
||||
@@ -26,27 +26,32 @@ struct SwiftUIView: View {
|
||||
var body: some View {
|
||||
NavigationView {
|
||||
List {
|
||||
ForEach(palettes.snapshot, id: \.self) { palette in
|
||||
NavigationLink(
|
||||
destination: DetailView(palette: palette),
|
||||
label: {
|
||||
HStack {
|
||||
Color(palette.color)
|
||||
.frame(width: 30, height: 30, alignment: .leading)
|
||||
Text(palette.colorText)
|
||||
}
|
||||
ForEach(palettes.snapshot.sectionIdentifiers, id: \.self) { (sectionID: String) in
|
||||
Section(header: Text(sectionID)) {
|
||||
ForEach(self.palettes.snapshot[section: sectionID], id: \.self) { palette in
|
||||
NavigationLink(
|
||||
destination: DetailView(palette: palette),
|
||||
label: {
|
||||
HStack {
|
||||
Color(palette.color)
|
||||
.cornerRadius(5)
|
||||
.frame(width: 30, height: 30, alignment: .leading)
|
||||
Text(palette.colorText)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
.onDelete { indices in
|
||||
let palettes = self.palettes.snapshot[indices]
|
||||
self.dataStack.perform(
|
||||
asynchronous: { transaction in
|
||||
.onDelete { itemIndices in
|
||||
let objectsToDelete = self.palettes.snapshot[section: sectionID, itemIndices: itemIndices]
|
||||
self.dataStack.perform(
|
||||
asynchronous: { transaction in
|
||||
|
||||
transaction.delete(palettes)
|
||||
},
|
||||
completion: { _ in }
|
||||
)
|
||||
transaction.delete(objectsToDelete)
|
||||
},
|
||||
completion: { _ in }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.navigationBarTitle(Text("SwiftUI"))
|
||||
@@ -90,16 +95,36 @@ struct SwiftUIView: View {
|
||||
|
||||
@available(iOS 13.0.0, *)
|
||||
struct DetailView: View {
|
||||
|
||||
@Environment(\.dataStack)
|
||||
var dataStack: DataStack
|
||||
|
||||
@ObservedObject var palette: Palette
|
||||
|
||||
@State var hue: Float = 0
|
||||
@State var saturation: Float = 0
|
||||
@State var brightness: Float = 0
|
||||
|
||||
init(palette: Palette) {
|
||||
|
||||
self.palette = palette
|
||||
self.hue = Float(palette.hue.value)
|
||||
self.saturation = palette.saturation.value
|
||||
self.brightness = palette.brightness.value
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
Color(palette.color)
|
||||
.cornerRadius(20)
|
||||
.padding(20)
|
||||
Text(palette.colorText)
|
||||
.navigationBarTitle(Text("Color"))
|
||||
VStack {
|
||||
Text(palette.colorText)
|
||||
.navigationBarTitle(Text("Color"))
|
||||
Slider(value: $hue, in: 0.0 ... 359.0 as ClosedRange<Float>)
|
||||
Slider(value: $saturation, in: 0.0 ... 1.0 as ClosedRange<Float>)
|
||||
Slider(value: $brightness, in: 0.0 ... 0.1 as ClosedRange<Float>)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
107
Sources/DiffableDataSource.TableView.swift
Normal file
107
Sources/DiffableDataSource.TableView.swift
Normal file
@@ -0,0 +1,107 @@
|
||||
//
|
||||
// DiffableDataSource.TableView.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright © 2018 John Rommel Estropia
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
|
||||
#if canImport(UIKit)
|
||||
|
||||
import UIKit
|
||||
import CoreData
|
||||
|
||||
|
||||
//// MARK: - DiffableDataSource
|
||||
//
|
||||
//extension DiffableDataSource {
|
||||
//
|
||||
// // MARK: - TableView
|
||||
//
|
||||
// public open class TableView<D: DynamicObject>: NSObject, UITableViewDataSource {
|
||||
//
|
||||
// // MARK: Public
|
||||
//
|
||||
// public typealias ObjectType = D
|
||||
//
|
||||
// public var defaultRowAnimation: UITableView.RowAnimation = .automatic
|
||||
//
|
||||
// public init(tableView: UITableView, cellProvider: @escaping (UITableView, IndexPath, ObjectType) -> UITableViewCell?) {
|
||||
//
|
||||
// self.tableView = tableView
|
||||
// self.cellProvider = cellProvider
|
||||
//
|
||||
// if #available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 15.0, *) {
|
||||
//
|
||||
// self.rawDataSource = UITableViewDiffableDataSource<String, D.ObjectID>(
|
||||
// tableView: tableView,
|
||||
// cellProvider: { (tableView, indexPath, managedObjectID) -> UITableViewCell? in
|
||||
//
|
||||
// cellProvider(
|
||||
// }
|
||||
// )
|
||||
// }
|
||||
// else {
|
||||
//
|
||||
// self.rawDataSource = nil
|
||||
// }
|
||||
//
|
||||
// super.init()
|
||||
//
|
||||
// tableView.dataSource = self
|
||||
// }
|
||||
//
|
||||
// public func apply(_ snapshot: ListSnapshot<ObjectType>, animatingDifferences: Bool = true) {
|
||||
//
|
||||
// let dataSource = UITableViewDiffableDataSource<String, D>.
|
||||
// if #available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 15.0, *) {
|
||||
//
|
||||
// self.rawDataSource! as! UITableViewDiffableDataSource<String, D>
|
||||
//
|
||||
// }
|
||||
// else {
|
||||
//
|
||||
// }
|
||||
// core.apply(
|
||||
// snapshot,
|
||||
// view: tableView,
|
||||
// animatingDifferences: animatingDifferences,
|
||||
// performUpdates: { tableView, changeset, setSections in
|
||||
// tableView.reload(using: changeset, with: self.defaultRowAnimation, setData: setSections)
|
||||
// })
|
||||
// }
|
||||
//
|
||||
//
|
||||
// // MARK: Private
|
||||
//
|
||||
// private weak var tableView: UITableView?
|
||||
// private let cellProvider: (UITableView, IndexPath, ObjectType) -> UITableViewCell?
|
||||
// private let rawDataSource: Any?
|
||||
//
|
||||
// @available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 15.0, *)
|
||||
// private var diffableDataSource: UITableViewDiffableDataSource<String, D.ObjectID> {
|
||||
//
|
||||
// return self.rawDataSource! as! UITableViewDiffableDataSource<String, D.ObjectID>
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
|
||||
#endif
|
||||
29
Sources/DiffableDataSource.swift
Normal file
29
Sources/DiffableDataSource.swift
Normal file
@@ -0,0 +1,29 @@
|
||||
//
|
||||
// File.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright © 2018 John Rommel Estropia
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
|
||||
|
||||
// MARK: - DiffableDataSource
|
||||
|
||||
public enum DiffableDataSource {}
|
||||
@@ -33,7 +33,12 @@ import CoreData
|
||||
All CoreStore's utilities are designed around `DynamicObject` instances. `NSManagedObject` and `CoreStoreObject` instances all conform to `DynamicObject`.
|
||||
*/
|
||||
public protocol DynamicObject: AnyObject {
|
||||
|
||||
|
||||
/**
|
||||
The object ID for this instance
|
||||
*/
|
||||
typealias ObjectID = NSManagedObjectID
|
||||
|
||||
/**
|
||||
Used internally by CoreStore. Do not call directly.
|
||||
*/
|
||||
@@ -52,7 +57,7 @@ public protocol DynamicObject: AnyObject {
|
||||
/**
|
||||
Used internally by CoreStore. Do not call directly.
|
||||
*/
|
||||
func cs_id() -> NSManagedObjectID
|
||||
func cs_id() -> ObjectID
|
||||
|
||||
/**
|
||||
Used internally by CoreStore. Do not call directly.
|
||||
@@ -103,7 +108,7 @@ extension NSManagedObject: DynamicObject {
|
||||
return object.isKind(of: self)
|
||||
}
|
||||
|
||||
public func cs_id() -> NSManagedObjectID {
|
||||
public func cs_id() -> ObjectID {
|
||||
|
||||
return self.objectID
|
||||
}
|
||||
@@ -166,7 +171,7 @@ extension CoreStoreObject {
|
||||
return (self as AnyClass).isSubclass(of: type as AnyClass)
|
||||
}
|
||||
|
||||
public func cs_id() -> NSManagedObjectID {
|
||||
public func cs_id() -> ObjectID {
|
||||
|
||||
return self.rawObject!.objectID
|
||||
}
|
||||
|
||||
@@ -29,9 +29,9 @@ public struct DataStackEnvironmentKey: EnvironmentKey {
|
||||
|
||||
@available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 15.0, *)
|
||||
extension EnvironmentValues {
|
||||
|
||||
|
||||
// MARK: Public
|
||||
|
||||
|
||||
public var dataStack: DataStack {
|
||||
get {
|
||||
return self[DataStackEnvironmentKey.self]
|
||||
|
||||
@@ -82,6 +82,11 @@ extension Internals {
|
||||
|
||||
try self.reapplyAffectedStores(self.typedFetchRequest, self.managedObjectContext)
|
||||
try self.performFetch()
|
||||
|
||||
if case let delegate as FetchedDiffableDataSourceSnapshotDelegate = self.delegate {
|
||||
|
||||
delegate.initialFetch()
|
||||
}
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
|
||||
606
Sources/Internals.DiffableDataSourceSnapshot.swift
Normal file
606
Sources/Internals.DiffableDataSourceSnapshot.swift
Normal file
@@ -0,0 +1,606 @@
|
||||
//
|
||||
// Internals.DiffableDataSourceSnapshot.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright © 2018 John Rommel Estropia
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
|
||||
#if canImport(UIKit) || canImport(AppKit)
|
||||
|
||||
import CoreData
|
||||
|
||||
#if canImport(UIKit)
|
||||
import UIKit
|
||||
|
||||
#elseif canImport(AppKit)
|
||||
import AppKit
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
// MARK: - Internals
|
||||
|
||||
extension Internals {
|
||||
|
||||
// MARK: Internal
|
||||
|
||||
internal typealias DiffableDataSourceSnapshot = _Internal_DiffableDataSourceSnapshot
|
||||
|
||||
|
||||
// MARK: - FallbackDiffableDataSourceSnapshot
|
||||
|
||||
// Implementation based on https://github.com/ra1028/DiffableDataSources
|
||||
internal struct FallbackDiffableDataSourceSnapshot: DiffableDataSourceSnapshot {
|
||||
|
||||
// MARK: Internal
|
||||
|
||||
init(sections: [NSFetchedResultsSectionInfo]) {
|
||||
|
||||
self.structure = .init(sections: sections)
|
||||
}
|
||||
|
||||
// MARK: DiffableDataSourceSnapshot
|
||||
|
||||
init() {
|
||||
|
||||
self.structure = .init()
|
||||
}
|
||||
|
||||
var numberOfItems: Int {
|
||||
|
||||
return self.itemIdentifiers.count
|
||||
}
|
||||
|
||||
var numberOfSections: Int {
|
||||
|
||||
return self.sectionIdentifiers.count
|
||||
}
|
||||
|
||||
var sectionIdentifiers: [NSString] {
|
||||
|
||||
return self.structure.allSectionIDs
|
||||
}
|
||||
|
||||
var itemIdentifiers: [NSManagedObjectID] {
|
||||
|
||||
self.structure.allItemIDs
|
||||
}
|
||||
|
||||
func numberOfItems(inSection identifier: NSString) -> Int {
|
||||
|
||||
return self.itemIdentifiers(inSection: identifier).count
|
||||
}
|
||||
|
||||
func itemIdentifiers(inSection identifier: NSString) -> [NSManagedObjectID] {
|
||||
|
||||
return self.structure.items(in: identifier)
|
||||
}
|
||||
|
||||
func sectionIdentifier(containingItem identifier: NSManagedObjectID) -> NSString? {
|
||||
|
||||
return self.structure.section(containing: identifier)
|
||||
}
|
||||
|
||||
func indexOfItem(_ identifier: NSManagedObjectID) -> Int? {
|
||||
|
||||
return self.itemIdentifiers.firstIndex(of: identifier)
|
||||
}
|
||||
|
||||
func indexOfSection(_ identifier: NSString) -> Int? {
|
||||
|
||||
return self.sectionIdentifiers.firstIndex(of: identifier)
|
||||
}
|
||||
|
||||
mutating func appendItems(_ identifiers: [NSManagedObjectID], toSection sectionIdentifier: NSString?) {
|
||||
|
||||
self.structure.append(itemIDs: identifiers, to: sectionIdentifier)
|
||||
}
|
||||
|
||||
mutating func insertItems(_ identifiers: [NSManagedObjectID], beforeItem beforeIdentifier: NSManagedObjectID) {
|
||||
|
||||
self.structure.insert(itemIDs: identifiers, before: beforeIdentifier)
|
||||
}
|
||||
|
||||
mutating func insertItems(_ identifiers: [NSManagedObjectID], afterItem afterIdentifier: NSManagedObjectID) {
|
||||
|
||||
self.structure.insert(itemIDs: identifiers, after: afterIdentifier)
|
||||
}
|
||||
|
||||
mutating func deleteItems(_ identifiers: [NSManagedObjectID]) {
|
||||
|
||||
self.structure.remove(itemIDs: identifiers)
|
||||
}
|
||||
|
||||
mutating func deleteAllItems() {
|
||||
|
||||
self.structure.removeAllItems()
|
||||
}
|
||||
|
||||
mutating func moveItem(_ identifier: NSManagedObjectID, beforeItem toIdentifier: NSManagedObjectID) {
|
||||
|
||||
self.structure.move(itemID: identifier, before: toIdentifier)
|
||||
}
|
||||
|
||||
mutating func moveItem(_ identifier: NSManagedObjectID, afterItem toIdentifier: NSManagedObjectID) {
|
||||
|
||||
self.structure.move(itemID: identifier, after: toIdentifier)
|
||||
}
|
||||
|
||||
mutating func reloadItems(_ identifiers: [NSManagedObjectID]) {
|
||||
|
||||
self.structure.update(itemIDs: identifiers)
|
||||
}
|
||||
|
||||
mutating func appendSections(_ identifiers: [NSString]) {
|
||||
|
||||
self.structure.append(sectionIDs: identifiers)
|
||||
}
|
||||
|
||||
mutating func insertSections(_ identifiers: [NSString], beforeSection toIdentifier: NSString) {
|
||||
|
||||
self.structure.insert(sectionIDs: identifiers, before: toIdentifier)
|
||||
}
|
||||
|
||||
mutating func insertSections(_ identifiers: [NSString], afterSection toIdentifier: NSString) {
|
||||
|
||||
self.structure.insert(sectionIDs: identifiers, after: toIdentifier)
|
||||
}
|
||||
|
||||
mutating func deleteSections(_ identifiers: [NSString]) {
|
||||
|
||||
self.structure.remove(sectionIDs: identifiers)
|
||||
}
|
||||
|
||||
mutating func moveSection(_ identifier: NSString, beforeSection toIdentifier: NSString) {
|
||||
|
||||
self.structure.move(sectionID: identifier, before: toIdentifier)
|
||||
}
|
||||
|
||||
mutating func moveSection(_ identifier: NSString, afterSection toIdentifier: NSString) {
|
||||
|
||||
self.structure.move(sectionID: identifier, after: toIdentifier)
|
||||
}
|
||||
|
||||
mutating func reloadSections(_ identifiers: [NSString]) {
|
||||
|
||||
self.structure.update(sectionIDs: identifiers)
|
||||
}
|
||||
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private var structure: BackingStructure
|
||||
|
||||
|
||||
// MARK: - BackingStructure
|
||||
|
||||
internal struct BackingStructure {
|
||||
|
||||
// MARK: Internal
|
||||
|
||||
var sections: [Section]
|
||||
|
||||
init() {
|
||||
|
||||
self.sections = []
|
||||
}
|
||||
|
||||
init(sections: [NSFetchedResultsSectionInfo]) {
|
||||
|
||||
self.sections = sections.map {
|
||||
|
||||
Section(
|
||||
id: $0.name as NSString,
|
||||
items: $0.objects?
|
||||
.compactMap({ ($0 as? NSManagedObject)?.objectID })
|
||||
.map(Item.init(id:)) ?? [],
|
||||
isReloaded: false
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
var allSectionIDs: [NSString] {
|
||||
|
||||
return self.sections.map({ $0.id })
|
||||
}
|
||||
|
||||
var allItemIDs: [NSManagedObjectID] {
|
||||
|
||||
return self.sections.lazy.flatMap({ $0.elements }).map({ $0.id })
|
||||
}
|
||||
|
||||
func items(in sectionID: NSString) -> [NSManagedObjectID] {
|
||||
|
||||
guard let sectionIndex = self.sectionIndex(of: sectionID) else {
|
||||
|
||||
Internals.abort("Section \"\(sectionID)\" does not exist")
|
||||
}
|
||||
return self.sections[sectionIndex].elements.map({ $0.id })
|
||||
}
|
||||
|
||||
func section(containing itemID: NSManagedObjectID) -> NSString? {
|
||||
|
||||
return self.itemPositionMap()[itemID]?.section.id
|
||||
}
|
||||
|
||||
mutating func append(itemIDs: [NSManagedObjectID], to sectionID: NSString?) {
|
||||
|
||||
let index: Array<Section>.Index
|
||||
if let sectionID = sectionID {
|
||||
|
||||
guard let sectionIndex = self.sectionIndex(of: sectionID) else {
|
||||
|
||||
Internals.abort("Section \"\(sectionID)\" does not exist")
|
||||
}
|
||||
index = sectionIndex
|
||||
}
|
||||
else {
|
||||
|
||||
let section = self.sections
|
||||
guard !section.isEmpty else {
|
||||
|
||||
Internals.abort("No sections exist")
|
||||
}
|
||||
index = section.index(before: section.endIndex)
|
||||
}
|
||||
|
||||
let items = itemIDs.lazy.map(Item.init)
|
||||
self.sections[index].elements.append(contentsOf: items)
|
||||
}
|
||||
|
||||
mutating func insert(itemIDs: [NSManagedObjectID], before beforeItemID: NSManagedObjectID) {
|
||||
|
||||
guard let itemPosition = self.itemPositionMap()[beforeItemID] else {
|
||||
|
||||
Internals.abort("Item \(beforeItemID) does not exist")
|
||||
}
|
||||
let items = itemIDs.lazy.map(Item.init)
|
||||
self.sections[itemPosition.sectionIndex].elements
|
||||
.insert(contentsOf: items, at: itemPosition.itemRelativeIndex)
|
||||
}
|
||||
|
||||
mutating func insert(itemIDs: [NSManagedObjectID], after afterItemID: NSManagedObjectID) {
|
||||
|
||||
guard let itemPosition = self.itemPositionMap()[afterItemID] else {
|
||||
|
||||
Internals.abort("Item \(afterItemID) does not exist")
|
||||
}
|
||||
let itemIndex = self.sections[itemPosition.sectionIndex].elements
|
||||
.index(after: itemPosition.itemRelativeIndex)
|
||||
let items = itemIDs.lazy.map(Item.init)
|
||||
self.sections[itemPosition.sectionIndex].elements
|
||||
.insert(contentsOf: items, at: itemIndex)
|
||||
}
|
||||
|
||||
mutating func remove(itemIDs: [NSManagedObjectID]) {
|
||||
|
||||
let itemPositionMap = self.itemPositionMap()
|
||||
var removeIndexSetMap: [Int: IndexSet] = [:]
|
||||
|
||||
for itemID in itemIDs {
|
||||
|
||||
guard let itemPosition = itemPositionMap[itemID] else {
|
||||
|
||||
continue
|
||||
}
|
||||
removeIndexSetMap[itemPosition.sectionIndex, default: []]
|
||||
.insert(itemPosition.itemRelativeIndex)
|
||||
}
|
||||
for (sectionIndex, removeIndexSet) in removeIndexSetMap {
|
||||
|
||||
for range in removeIndexSet.rangeView.reversed() {
|
||||
|
||||
self.sections[sectionIndex].elements.removeSubrange(range)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mutating func removeAllItems() {
|
||||
|
||||
for sectionIndex in self.sections.indices {
|
||||
|
||||
self.sections[sectionIndex].elements.removeAll()
|
||||
}
|
||||
}
|
||||
|
||||
mutating func move(itemID: NSManagedObjectID, before beforeItemID: NSManagedObjectID) {
|
||||
|
||||
guard let removed = self.remove(itemID: itemID) else {
|
||||
|
||||
Internals.abort("Item \(itemID) does not exist")
|
||||
}
|
||||
guard let itemPosition = self.itemPositionMap()[beforeItemID] else {
|
||||
|
||||
Internals.abort("Item \(beforeItemID) does not exist")
|
||||
}
|
||||
self.sections[itemPosition.sectionIndex].elements
|
||||
.insert(removed, at: itemPosition.itemRelativeIndex)
|
||||
}
|
||||
|
||||
mutating func move(itemID: NSManagedObjectID, after afterItemID: NSManagedObjectID) {
|
||||
|
||||
guard let removed = self.remove(itemID: itemID) else {
|
||||
|
||||
Internals.abort("Item \(itemID) does not exist")
|
||||
}
|
||||
guard let itemPosition = self.itemPositionMap()[afterItemID] else {
|
||||
|
||||
Internals.abort("Item \(afterItemID) does not exist")
|
||||
}
|
||||
let itemIndex = self.sections[itemPosition.sectionIndex].elements
|
||||
.index(after: itemPosition.itemRelativeIndex)
|
||||
self.sections[itemPosition.sectionIndex].elements
|
||||
.insert(removed, at: itemIndex)
|
||||
}
|
||||
|
||||
mutating func update(itemIDs: [NSManagedObjectID]) {
|
||||
|
||||
let itemPositionMap = self.itemPositionMap()
|
||||
for itemID in itemIDs {
|
||||
|
||||
guard let itemPosition = itemPositionMap[itemID] else {
|
||||
|
||||
Internals.abort("Item \(itemID) does not exist")
|
||||
}
|
||||
self.sections[itemPosition.sectionIndex].elements[itemPosition.itemRelativeIndex].isReloaded = true
|
||||
}
|
||||
}
|
||||
|
||||
mutating func append(sectionIDs: [NSString]) {
|
||||
|
||||
let newSections = sectionIDs.lazy.map(Section.init)
|
||||
self.sections.append(contentsOf: newSections)
|
||||
}
|
||||
|
||||
mutating func insert(sectionIDs: [NSString], before beforeSectionID: NSString) {
|
||||
|
||||
guard let sectionIndex = self.sectionIndex(of: beforeSectionID) else {
|
||||
|
||||
Internals.abort("Section \"\(beforeSectionID)\" does not exist")
|
||||
}
|
||||
let newSections = sectionIDs.lazy.map(Section.init)
|
||||
self.sections.insert(contentsOf: newSections, at: sectionIndex)
|
||||
}
|
||||
|
||||
mutating func insert(sectionIDs: [NSString], after afterSectionID: NSString) {
|
||||
|
||||
guard let beforeIndex = self.sectionIndex(of: afterSectionID) else {
|
||||
|
||||
Internals.abort("Section \"\(afterSectionID)\" does not exist")
|
||||
}
|
||||
let sectionIndex = self.sections.index(after: beforeIndex)
|
||||
let newSections = sectionIDs.lazy.map(Section.init)
|
||||
self.sections.insert(contentsOf: newSections, at: sectionIndex)
|
||||
}
|
||||
|
||||
mutating func remove(sectionIDs: [NSString]) {
|
||||
|
||||
for sectionID in sectionIDs {
|
||||
|
||||
self.remove(sectionID: sectionID)
|
||||
}
|
||||
}
|
||||
|
||||
mutating func move(sectionID: NSString, before beforeSectionID: NSString) {
|
||||
|
||||
guard let removed = self.remove(sectionID: sectionID) else {
|
||||
|
||||
Internals.abort("Section \"\(sectionID)\" does not exist")
|
||||
}
|
||||
guard let sectionIndex = self.sectionIndex(of: beforeSectionID) else {
|
||||
|
||||
Internals.abort("Section \"\(beforeSectionID)\" does not exist")
|
||||
}
|
||||
self.sections.insert(removed, at: sectionIndex)
|
||||
}
|
||||
|
||||
mutating func move(sectionID: NSString, after afterSectionID: NSString) {
|
||||
|
||||
guard let removed = self.remove(sectionID: sectionID) else {
|
||||
|
||||
Internals.abort("Section \"\(sectionID)\" does not exist")
|
||||
}
|
||||
guard let beforeIndex = self.sectionIndex(of: afterSectionID) else {
|
||||
|
||||
Internals.abort("Section \"\(afterSectionID)\" does not exist")
|
||||
}
|
||||
let sectionIndex = self.sections.index(after: beforeIndex)
|
||||
self.sections.insert(removed, at: sectionIndex)
|
||||
}
|
||||
|
||||
mutating func update(sectionIDs: [NSString]) {
|
||||
|
||||
for sectionID in sectionIDs {
|
||||
|
||||
guard let sectionIndex = self.sectionIndex(of: sectionID) else {
|
||||
|
||||
continue
|
||||
}
|
||||
self.sections[sectionIndex].isReloaded = true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private func sectionIndex(of sectionID: NSString) -> Array<Section>.Index? {
|
||||
|
||||
return self.sections.firstIndex(where: { $0.id == sectionID })
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
private mutating func remove(itemID: NSManagedObjectID) -> Item? {
|
||||
|
||||
guard let itemPosition = self.itemPositionMap()[itemID] else {
|
||||
|
||||
return nil
|
||||
}
|
||||
return self.sections[itemPosition.sectionIndex].elements
|
||||
.remove(at: itemPosition.itemRelativeIndex)
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
private mutating func remove(sectionID: NSString) -> Section? {
|
||||
|
||||
guard let sectionIndex = self.sectionIndex(of: sectionID) else {
|
||||
|
||||
return nil
|
||||
}
|
||||
return self.sections.remove(at: sectionIndex)
|
||||
}
|
||||
|
||||
private func itemPositionMap() -> [NSManagedObjectID: ItemPosition] {
|
||||
|
||||
return self.sections.enumerated().reduce(into: [:]) { result, section in
|
||||
|
||||
for (itemRelativeIndex, item) in section.element.elements.enumerated() {
|
||||
|
||||
result[item.id] = ItemPosition(
|
||||
item: item,
|
||||
itemRelativeIndex: itemRelativeIndex,
|
||||
section: section.element,
|
||||
sectionIndex: section.offset
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Item
|
||||
|
||||
internal struct Item: Identifiable, Equatable {
|
||||
|
||||
var isReloaded: Bool
|
||||
|
||||
init(id: NSManagedObjectID, isReloaded: Bool) {
|
||||
|
||||
self.id = id
|
||||
self.isReloaded = isReloaded
|
||||
}
|
||||
|
||||
init(id: NSManagedObjectID) {
|
||||
|
||||
self.init(id: id, isReloaded: false)
|
||||
}
|
||||
|
||||
func isContentEqual(to source: Item) -> Bool {
|
||||
|
||||
return !self.isReloaded && self.id == source.id
|
||||
}
|
||||
|
||||
// MARK: Identifiable
|
||||
|
||||
var id: NSManagedObjectID
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Section
|
||||
|
||||
internal struct Section: Identifiable, Equatable {
|
||||
|
||||
var elements: [Item] = []
|
||||
var isReloaded: Bool
|
||||
|
||||
init(id: NSString, items: [Item], isReloaded: Bool) {
|
||||
self.id = id
|
||||
self.elements = items
|
||||
self.isReloaded = isReloaded
|
||||
}
|
||||
|
||||
init(id: NSString) {
|
||||
|
||||
self.init(id: id, items: [], isReloaded: false)
|
||||
}
|
||||
|
||||
init<S: Sequence>(source: Section, elements: S) where S.Element == Item {
|
||||
|
||||
self.init(id: source.id, items: Array(elements), isReloaded: source.isReloaded)
|
||||
}
|
||||
|
||||
func isContentEqual(to source: Section) -> Bool {
|
||||
|
||||
return !self.isReloaded && self.id == source.id
|
||||
}
|
||||
|
||||
// MARK: Identifiable
|
||||
|
||||
var id: NSString
|
||||
}
|
||||
|
||||
|
||||
// MARK: - ItemPosition
|
||||
|
||||
fileprivate struct ItemPosition {
|
||||
|
||||
var item: Item
|
||||
var itemRelativeIndex: Int
|
||||
var section: Section
|
||||
var sectionIndex: Int
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - NSDiffableDataSourceSnapshot: Internals.DiffableDataSourceSnapshot
|
||||
|
||||
@available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 15.0, *)
|
||||
extension NSDiffableDataSourceSnapshot: Internals.DiffableDataSourceSnapshot where SectionIdentifierType == NSString, ItemIdentifierType == NSManagedObjectID {}
|
||||
|
||||
|
||||
// MARK: - Internals.DiffableDataSourceSnapshot
|
||||
|
||||
internal protocol _Internal_DiffableDataSourceSnapshot {
|
||||
|
||||
init()
|
||||
|
||||
var numberOfItems: Int { get }
|
||||
var numberOfSections: Int { get }
|
||||
var sectionIdentifiers: [NSString] { get }
|
||||
var itemIdentifiers: [NSManagedObjectID] { get }
|
||||
|
||||
func numberOfItems(inSection identifier: NSString) -> Int
|
||||
func itemIdentifiers(inSection identifier: NSString) -> [NSManagedObjectID]
|
||||
func sectionIdentifier(containingItem identifier: NSManagedObjectID) -> NSString?
|
||||
func indexOfItem(_ identifier: NSManagedObjectID) -> Int?
|
||||
func indexOfSection(_ identifier: NSString) -> Int?
|
||||
|
||||
mutating func appendItems(_ identifiers: [NSManagedObjectID], toSection sectionIdentifier: NSString?)
|
||||
mutating func insertItems(_ identifiers: [NSManagedObjectID], beforeItem beforeIdentifier: NSManagedObjectID)
|
||||
mutating func insertItems(_ identifiers: [NSManagedObjectID], afterItem afterIdentifier: NSManagedObjectID)
|
||||
mutating func deleteItems(_ identifiers: [NSManagedObjectID])
|
||||
mutating func deleteAllItems()
|
||||
mutating func moveItem(_ identifier: NSManagedObjectID, beforeItem toIdentifier: NSManagedObjectID)
|
||||
mutating func moveItem(_ identifier: NSManagedObjectID, afterItem toIdentifier: NSManagedObjectID)
|
||||
mutating func reloadItems(_ identifiers: [NSManagedObjectID])
|
||||
mutating func appendSections(_ identifiers: [NSString])
|
||||
mutating func insertSections(_ identifiers: [NSString], beforeSection toIdentifier: NSString)
|
||||
mutating func insertSections(_ identifiers: [NSString], afterSection toIdentifier: NSString)
|
||||
mutating func deleteSections(_ identifiers: [NSString])
|
||||
mutating func moveSection(_ identifier: NSString, beforeSection toIdentifier: NSString)
|
||||
mutating func moveSection(_ identifier: NSString, afterSection toIdentifier: NSString)
|
||||
mutating func reloadSections(_ identifiers: [NSString])
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
157
Sources/Internals.FallbackDiffableDataUIDispatcher.swift
Normal file
157
Sources/Internals.FallbackDiffableDataUIDispatcher.swift
Normal file
@@ -0,0 +1,157 @@
|
||||
//
|
||||
// Internals.FallbackDiffableDataUIDispatcher.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright © 2018 John Rommel Estropia
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
|
||||
#if canImport(UIKit) || canImport(AppKit)
|
||||
|
||||
import CoreData
|
||||
|
||||
#if canImport(QuartzCore)
|
||||
import QuartzCore
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
// MARK: - Internals
|
||||
|
||||
extension Internals {
|
||||
|
||||
// MARK: Internal
|
||||
|
||||
// // Implementation based on https://github.com/ra1028/DiffableDataSources
|
||||
// internal final class FallbackDiffableDataUIDispatcher {
|
||||
//
|
||||
// // MARK: Internal
|
||||
//
|
||||
// internal func apply() {
|
||||
//
|
||||
// }
|
||||
//
|
||||
// func snapshot() -> DiffableDataSourceSnapshot<SectionIdentifierType, ItemIdentifierType> {
|
||||
// var snapshot = DiffableDataSourceSnapshot<SectionIdentifierType, ItemIdentifierType>()
|
||||
// snapshot.structure.sections = currentSnapshot.structure.sections
|
||||
// return snapshot
|
||||
// }
|
||||
//
|
||||
// func itemIdentifier(for indexPath: IndexPath) -> ItemIdentifierType? {
|
||||
// guard 0..<sections.endIndex ~= indexPath.section else {
|
||||
// return nil
|
||||
// }
|
||||
//
|
||||
// let items = sections[indexPath.section].elements
|
||||
//
|
||||
// guard 0..<items.endIndex ~= indexPath.item else {
|
||||
// return nil
|
||||
// }
|
||||
//
|
||||
// return items[indexPath.item].differenceIdentifier
|
||||
// }
|
||||
//
|
||||
// func unsafeItemIdentifier(for indexPath: IndexPath, file: StaticString = #file, line: UInt = #line) -> ItemIdentifierType {
|
||||
// guard let itemIdentifier = itemIdentifier(for: indexPath) else {
|
||||
// universalError("Item not found at the specified index path(\(indexPath)).")
|
||||
// }
|
||||
//
|
||||
// return itemIdentifier
|
||||
// }
|
||||
//
|
||||
// func indexPath(for itemIdentifier: ItemIdentifierType) -> IndexPath? {
|
||||
// let indexPathMap: [ItemIdentifierType: IndexPath] = sections.enumerated()
|
||||
// .reduce(into: [:]) { result, section in
|
||||
// for (itemIndex, item) in section.element.elements.enumerated() {
|
||||
// result[item.differenceIdentifier] = IndexPath(
|
||||
// item: itemIndex,
|
||||
// section: section.offset
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
// return indexPathMap[itemIdentifier]
|
||||
// }
|
||||
//
|
||||
// func numberOfSections() -> Int {
|
||||
// return sections.count
|
||||
// }
|
||||
//
|
||||
// func numberOfItems(inSection section: Int) -> Int {
|
||||
// return sections[section].elements.count
|
||||
// }
|
||||
//
|
||||
//
|
||||
//
|
||||
// // MARK: Private
|
||||
//
|
||||
// private let dispatcher: MainThreadSerialDispatcher = .init()
|
||||
//
|
||||
// private var currentSnapshot: Internals.DiffableDataSourceSnapshot = FallbackDiffableDataSourceSnapshot()
|
||||
// private var sections: [FallbackDiffableDataSourceSnapshot.BackingStructure.Section] = []
|
||||
//
|
||||
//
|
||||
// // MARK: - MainThreadSerialDispatcher
|
||||
//
|
||||
// fileprivate final class MainThreadSerialDispatcher {
|
||||
//
|
||||
// // MARK: FilePrivate
|
||||
//
|
||||
// fileprivate init() {
|
||||
//
|
||||
// self.executingCount.initialize(to: 0)
|
||||
// }
|
||||
//
|
||||
// deinit {
|
||||
//
|
||||
// self.executingCount.deinitialize(count: 1)
|
||||
// self.executingCount.deallocate()
|
||||
// }
|
||||
//
|
||||
// fileprivate func dispatch(_ action: @escaping () -> Void) {
|
||||
//
|
||||
// let count = OSAtomicIncrement32(self.executingCount)
|
||||
// if Thread.isMainThread && count == 1 {
|
||||
//
|
||||
// action()
|
||||
// OSAtomicDecrement32(executingCount)
|
||||
// }
|
||||
// else {
|
||||
//
|
||||
// DispatchQueue.main.async { [weak self] in
|
||||
//
|
||||
// guard let self = self else {
|
||||
//
|
||||
// return
|
||||
// }
|
||||
// action()
|
||||
// OSAtomicDecrement32(self.executingCount)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//
|
||||
// // MARK: Private
|
||||
//
|
||||
// private let executingCount: UnsafeMutablePointer<Int32> = .allocate(capacity: 1)
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -23,8 +23,6 @@
|
||||
// SOFTWARE.
|
||||
//
|
||||
|
||||
#if canImport(UIKit) || canImport(AppKit)
|
||||
|
||||
import Foundation
|
||||
import CoreData
|
||||
|
||||
@@ -41,10 +39,9 @@ import AppKit
|
||||
|
||||
// MARK: - FetchedDiffableDataSourceSnapshot
|
||||
|
||||
@available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 15.0, *)
|
||||
internal protocol FetchedDiffableDataSourceSnapshotHandler: AnyObject {
|
||||
|
||||
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChangContentWith snapshot: NSDiffableDataSourceSnapshotReference)
|
||||
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChangContentWith snapshot: Internals.DiffableDataSourceSnapshot)
|
||||
}
|
||||
|
||||
|
||||
@@ -54,7 +51,6 @@ extension Internals {
|
||||
|
||||
// MARK: - FetchedDiffableDataSourceSnapshotDelegate
|
||||
|
||||
@available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 15.0, *)
|
||||
internal final class FetchedDiffableDataSourceSnapshotDelegate: NSObject, NSFetchedResultsControllerDelegate {
|
||||
|
||||
// MARK: Internal
|
||||
@@ -77,18 +73,71 @@ extension Internals {
|
||||
self.fetchedResultsController?.delegate = nil
|
||||
}
|
||||
|
||||
internal func initialFetch() {
|
||||
|
||||
#if canImport(UIKit) || canImport(AppKit)
|
||||
|
||||
if #available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 15.0, *) {
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
guard let fetchedResultsController = self.fetchedResultsController else {
|
||||
|
||||
return
|
||||
}
|
||||
self.controllerDidChangeContent(fetchedResultsController.dynamicCast())
|
||||
}
|
||||
|
||||
|
||||
// MARK: NSFetchedResultsControllerDelegate
|
||||
|
||||
#if canImport(UIKit) || canImport(AppKit)
|
||||
|
||||
@available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 15.0, *)
|
||||
@objc
|
||||
dynamic func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChangeContentWith snapshot: NSDiffableDataSourceSnapshotReference) {
|
||||
|
||||
self.handler?.controller(
|
||||
controller,
|
||||
didChangContentWith: snapshot
|
||||
didChangContentWith: snapshot as NSDiffableDataSourceSnapshot<NSString, NSManagedObjectID>
|
||||
)
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@objc
|
||||
dynamic func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
|
||||
|
||||
self.reloadedIDs = []
|
||||
}
|
||||
|
||||
@objc
|
||||
dynamic func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
|
||||
|
||||
self.handler?.controller(
|
||||
controller,
|
||||
didChangContentWith: FallbackDiffableDataSourceSnapshot(
|
||||
sections: controller.sections ?? []
|
||||
)
|
||||
)
|
||||
self.reloadedIDs = []
|
||||
}
|
||||
|
||||
// @objc
|
||||
// dynamic func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
|
||||
//
|
||||
//
|
||||
//// [1].difference(from: <#T##BidirectionalCollection#>)
|
||||
// let managedObject = anObject as! NSManagedObject
|
||||
// self.reloadedIDs.insert(managedObject.objectID)
|
||||
// }
|
||||
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private var reloadedIDs: Set<NSManagedObjectID> = []
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -23,8 +23,6 @@
|
||||
// SOFTWARE.
|
||||
//
|
||||
|
||||
#if canImport(UIKit) || canImport(AppKit)
|
||||
|
||||
import CoreData
|
||||
|
||||
#if canImport(UIKit)
|
||||
@@ -38,21 +36,170 @@ import AppKit
|
||||
|
||||
// MARK: - LiveList
|
||||
|
||||
@available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 15.0, *)
|
||||
public struct ListSnapshot<D: DynamicObject>: SnapshotResult, RandomAccessCollection, Hashable {
|
||||
|
||||
// MARK: Public
|
||||
|
||||
public subscript<S: Sequence>(indices: S) -> [ObjectType] where S.Element == Index {
|
||||
|
||||
|
||||
public typealias SectionID = String
|
||||
public typealias ItemID = D.ObjectID
|
||||
|
||||
public subscript<S: Sequence>(indices indices: S) -> [ObjectType] where S.Element == Index {
|
||||
|
||||
let context = self.context!
|
||||
let objectIDs = self.snapshotStruct.itemIdentifiers
|
||||
let objectIDs = self.diffableSnapshot.itemIdentifiers
|
||||
return indices.map { position in
|
||||
|
||||
|
||||
let objectID = objectIDs[position]
|
||||
return context.fetchExisting(objectID)!
|
||||
}
|
||||
}
|
||||
|
||||
public subscript(section sectionID: SectionID) -> [ObjectType] {
|
||||
|
||||
let context = self.context!
|
||||
let objectIDs = self.itemIdentifiers(inSection: sectionID)
|
||||
return objectIDs.map {
|
||||
|
||||
return context.fetchExisting($0)!
|
||||
}
|
||||
}
|
||||
|
||||
public subscript<S: Sequence>(section sectionID: SectionID, itemIndices itemIndices: S) -> [ObjectType] where S.Element == Int {
|
||||
|
||||
let context = self.context!
|
||||
let objectIDs = self.itemIdentifiers(inSection: sectionID)
|
||||
return itemIndices.map { position in
|
||||
|
||||
let objectID = objectIDs[position]
|
||||
return context.fetchExisting(objectID)!
|
||||
}
|
||||
}
|
||||
|
||||
public var numberOfItems: Int {
|
||||
|
||||
return self.diffableSnapshot.numberOfItems
|
||||
}
|
||||
|
||||
public var numberOfSections: Int {
|
||||
|
||||
return self.diffableSnapshot.numberOfSections
|
||||
}
|
||||
|
||||
public var sectionIdentifiers: [String] {
|
||||
|
||||
return self.diffableSnapshot.sectionIdentifiers as [String]
|
||||
}
|
||||
|
||||
public var itemIdentifiers: [ItemID] {
|
||||
|
||||
return self.diffableSnapshot.itemIdentifiers as [ItemID]
|
||||
}
|
||||
|
||||
public func numberOfItems(inSection identifier: SectionID) -> Int {
|
||||
|
||||
return self.diffableSnapshot.numberOfItems(inSection: identifier as NSString)
|
||||
}
|
||||
|
||||
public func itemIdentifiers(inSection identifier: SectionID) -> [ItemID] {
|
||||
|
||||
return self.diffableSnapshot.itemIdentifiers(inSection: identifier as NSString)
|
||||
}
|
||||
|
||||
public func itemIdentifiers(inSection identifier: SectionID, atIndices indices: IndexSet) -> [ItemID] {
|
||||
|
||||
let itemIDs = self.itemIdentifiers(inSection: identifier)
|
||||
return indices.map({ itemIDs[$0] })
|
||||
}
|
||||
|
||||
public func sectionIdentifier(containingItem identifier: ItemID) -> SectionID? {
|
||||
|
||||
return self.diffableSnapshot.sectionIdentifier(containingItem: identifier) as SectionID?
|
||||
}
|
||||
|
||||
public func indexOfItem(_ identifier: ItemID) -> Index? {
|
||||
|
||||
return self.diffableSnapshot.indexOfItem(identifier)
|
||||
}
|
||||
|
||||
public func indexOfSection(_ identifier: SectionID) -> Int? {
|
||||
|
||||
return self.diffableSnapshot.indexOfSection(identifier as NSString)
|
||||
}
|
||||
|
||||
public mutating func appendItems(_ identifiers: [ItemID], toSection sectionIdentifier: SectionID? = nil) {
|
||||
|
||||
self.diffableSnapshot.appendItems(identifiers, toSection: sectionIdentifier as NSString?)
|
||||
}
|
||||
|
||||
public mutating func insertItems(_ identifiers: [ItemID], beforeItem beforeIdentifier: ItemID) {
|
||||
|
||||
self.diffableSnapshot.insertItems(identifiers, beforeItem: beforeIdentifier)
|
||||
}
|
||||
|
||||
public mutating func insertItems(_ identifiers: [ItemID], afterItem afterIdentifier: ItemID) {
|
||||
|
||||
self.diffableSnapshot.insertItems(identifiers, afterItem: afterIdentifier)
|
||||
}
|
||||
|
||||
public mutating func deleteItems(_ identifiers: [ItemID]) {
|
||||
|
||||
self.diffableSnapshot.deleteItems(identifiers)
|
||||
}
|
||||
|
||||
public mutating func deleteAllItems() {
|
||||
|
||||
self.diffableSnapshot.deleteAllItems()
|
||||
}
|
||||
|
||||
public mutating func moveItem(_ identifier: ItemID, beforeItem toIdentifier: ItemID) {
|
||||
|
||||
self.diffableSnapshot.moveItem(identifier, beforeItem: toIdentifier)
|
||||
}
|
||||
|
||||
public mutating func moveItem(_ identifier: ItemID, afterItem toIdentifier: ItemID) {
|
||||
|
||||
self.diffableSnapshot.moveItem(identifier, afterItem: toIdentifier)
|
||||
}
|
||||
|
||||
public mutating func reloadItems(_ identifiers: [ItemID]) {
|
||||
|
||||
self.diffableSnapshot.reloadItems(identifiers)
|
||||
}
|
||||
|
||||
public mutating func appendSections(_ identifiers: [SectionID]) {
|
||||
|
||||
self.diffableSnapshot.appendSections(identifiers as [NSString])
|
||||
}
|
||||
|
||||
public mutating func insertSections(_ identifiers: [SectionID], beforeSection toIdentifier: SectionID) {
|
||||
|
||||
self.diffableSnapshot.insertSections(identifiers as [NSString], beforeSection: toIdentifier as NSString)
|
||||
}
|
||||
|
||||
public mutating func insertSections(_ identifiers: [SectionID], afterSection toIdentifier: SectionID) {
|
||||
|
||||
self.diffableSnapshot.insertSections(identifiers as [NSString], afterSection: toIdentifier as NSString)
|
||||
}
|
||||
|
||||
public mutating func deleteSections(_ identifiers: [SectionID]) {
|
||||
|
||||
self.diffableSnapshot.deleteSections(identifiers as [NSString])
|
||||
}
|
||||
|
||||
public mutating func moveSection(_ identifier: SectionID, beforeSection toIdentifier: SectionID) {
|
||||
|
||||
self.diffableSnapshot.moveSection(identifier as NSString, beforeSection: toIdentifier as NSString)
|
||||
}
|
||||
|
||||
public mutating func moveSection(_ identifier: SectionID, afterSection toIdentifier: SectionID) {
|
||||
|
||||
self.diffableSnapshot.moveSection(identifier as NSString, afterSection: toIdentifier as NSString)
|
||||
}
|
||||
|
||||
public mutating func reloadSections(_ identifiers: [SectionID]) {
|
||||
|
||||
self.diffableSnapshot.reloadSections(identifiers as [NSString])
|
||||
}
|
||||
|
||||
|
||||
// MARK: SnapshotResult
|
||||
@@ -64,18 +211,18 @@ public struct ListSnapshot<D: DynamicObject>: SnapshotResult, RandomAccessCollec
|
||||
|
||||
public var startIndex: Index {
|
||||
|
||||
return 0
|
||||
return self.diffableSnapshot.itemIdentifiers.startIndex
|
||||
}
|
||||
|
||||
public var endIndex: Index {
|
||||
|
||||
return self.snapshotStruct.numberOfItems
|
||||
return self.diffableSnapshot.itemIdentifiers.endIndex
|
||||
}
|
||||
|
||||
public subscript(position: Index) -> ObjectType {
|
||||
|
||||
let context = self.context!
|
||||
let objectID = self.snapshotStruct.itemIdentifiers[position]
|
||||
let objectID = self.diffableSnapshot.itemIdentifiers[position]
|
||||
return context.fetchExisting(objectID)!
|
||||
}
|
||||
|
||||
@@ -106,16 +253,14 @@ public struct ListSnapshot<D: DynamicObject>: SnapshotResult, RandomAccessCollec
|
||||
// MARK: Internal
|
||||
|
||||
internal init() {
|
||||
|
||||
self.snapshotReference = .init()
|
||||
self.snapshotStruct = self.snapshotReference as NSDiffableDataSourceSnapshot<NSString, NSManagedObjectID>
|
||||
|
||||
self.diffableSnapshot = Internals.FallbackDiffableDataSourceSnapshot()
|
||||
self.context = nil
|
||||
}
|
||||
|
||||
internal init(snapshotReference: NSDiffableDataSourceSnapshotReference, context: NSManagedObjectContext) {
|
||||
|
||||
self.snapshotReference = snapshotReference
|
||||
self.snapshotStruct = snapshotReference as NSDiffableDataSourceSnapshot<NSString, NSManagedObjectID>
|
||||
internal init(diffableSnapshot: Internals.DiffableDataSourceSnapshot, context: NSManagedObjectContext) {
|
||||
|
||||
self.diffableSnapshot = diffableSnapshot
|
||||
self.context = context
|
||||
}
|
||||
|
||||
@@ -123,9 +268,6 @@ public struct ListSnapshot<D: DynamicObject>: SnapshotResult, RandomAccessCollec
|
||||
// MARK: Private
|
||||
|
||||
private let id: UUID = .init()
|
||||
private let snapshotReference: NSDiffableDataSourceSnapshotReference
|
||||
private let snapshotStruct: NSDiffableDataSourceSnapshot<NSString, NSManagedObjectID>
|
||||
private let context: NSManagedObjectContext?
|
||||
private var diffableSnapshot: Internals.DiffableDataSourceSnapshot
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -23,18 +23,8 @@
|
||||
// SOFTWARE.
|
||||
//
|
||||
|
||||
#if canImport(UIKit) || canImport(AppKit)
|
||||
|
||||
import CoreData
|
||||
|
||||
#if canImport(UIKit)
|
||||
import UIKit
|
||||
|
||||
#elseif canImport(AppKit)
|
||||
import AppKit
|
||||
|
||||
#endif
|
||||
|
||||
#if canImport(Combine)
|
||||
import Combine
|
||||
|
||||
@@ -48,7 +38,6 @@ import SwiftUI
|
||||
|
||||
// MARK: - LiveList
|
||||
|
||||
@available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 15.0, *)
|
||||
public final class LiveList<D: DynamicObject> {
|
||||
|
||||
// MARK: Public
|
||||
@@ -57,23 +46,22 @@ public final class LiveList<D: DynamicObject> {
|
||||
|
||||
willSet {
|
||||
|
||||
#if canImport(Combine)
|
||||
|
||||
let oldValue = self.snapshot
|
||||
guard newValue != oldValue else {
|
||||
guard #available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 15.0, *) else {
|
||||
|
||||
return
|
||||
}
|
||||
#if canImport(Combine)
|
||||
|
||||
#if canImport(SwiftUI)
|
||||
withAnimation {
|
||||
self.objectWillChange.send()
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
self.objectWillChange.send()
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -182,13 +170,20 @@ public final class LiveList<D: DynamicObject> {
|
||||
applyFetchClauses: applyFetchClauses
|
||||
)
|
||||
|
||||
#if canImport(Combine)
|
||||
self.rawObjectWillChange = ObservableObjectPublisher()
|
||||
if #available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 15.0, *) {
|
||||
|
||||
#else
|
||||
self.rawObjectWillChange = nil
|
||||
#if canImport(Combine)
|
||||
self.rawObjectWillChange = ObservableObjectPublisher()
|
||||
|
||||
#endif
|
||||
#else
|
||||
self.rawObjectWillChange = nil
|
||||
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
|
||||
self.rawObjectWillChange = nil
|
||||
}
|
||||
|
||||
|
||||
// if let sectionIndexTransformer = sectionBy?.sectionIndexTransformer {
|
||||
@@ -278,14 +273,16 @@ public final class LiveList<D: DynamicObject> {
|
||||
|
||||
// MARK: - LiveList: FetchedDiffableDataSourceSnapshotHandler
|
||||
|
||||
@available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 15.0, *)
|
||||
extension LiveList: FetchedDiffableDataSourceSnapshotHandler {
|
||||
|
||||
// MARK: FetchedDiffableDataSourceSnapshotHandler
|
||||
|
||||
internal func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChangContentWith snapshot: NSDiffableDataSourceSnapshotReference) {
|
||||
internal func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChangContentWith snapshot: Internals.DiffableDataSourceSnapshot) {
|
||||
|
||||
self.snapshot = .init(snapshotReference: snapshot, context: controller.managedObjectContext)
|
||||
self.snapshot = .init(
|
||||
diffableSnapshot: snapshot,
|
||||
context: controller.managedObjectContext
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -307,5 +304,3 @@ extension LiveList: LiveResult {
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -23,143 +23,151 @@
|
||||
// SOFTWARE.
|
||||
//
|
||||
|
||||
#if canImport(SwiftUI) && canImport(Combine)
|
||||
|
||||
import CoreData
|
||||
import Combine
|
||||
import SwiftUI
|
||||
|
||||
|
||||
#warning("TODO: autoupdating doesn't work yet")
|
||||
@available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 15.0, *)
|
||||
@propertyWrapper
|
||||
public struct LiveQuery<Result: LiveResult>: DynamicProperty {
|
||||
|
||||
// MARK: Public
|
||||
|
||||
@Environment(\.dataStack)
|
||||
public var dataStack: DataStack
|
||||
|
||||
public typealias ObjectType = Result.ObjectType
|
||||
|
||||
|
||||
// MARK: @propertyWrapper
|
||||
|
||||
public fileprivate(set) var wrappedValue: Result {
|
||||
|
||||
get {
|
||||
|
||||
return self.nonMutatingWrappedValue.wrappedValue
|
||||
}
|
||||
set {
|
||||
|
||||
self.nonMutatingWrappedValue = LazyNonmutating { newValue }
|
||||
}
|
||||
}
|
||||
|
||||
public var projectedValue: Result {
|
||||
|
||||
return self.wrappedValue
|
||||
}
|
||||
|
||||
|
||||
// MARK: DynamicProperty
|
||||
|
||||
public mutating func update() {
|
||||
|
||||
SwiftUI.withAnimation {
|
||||
|
||||
let dataStack = self.dataStack
|
||||
if self.set(dataStack: dataStack) {
|
||||
|
||||
return
|
||||
}
|
||||
self.wrappedValue = self.newWrappedValue(dataStack)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: FilePrivate
|
||||
|
||||
fileprivate let newWrappedValue: (DataStack) -> Result
|
||||
|
||||
fileprivate init(newWrappedValue: @escaping (DataStack) -> Result) {
|
||||
|
||||
self.newWrappedValue = newWrappedValue
|
||||
}
|
||||
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private var nonMutatingWrappedValue: LazyNonmutating<Result> = .init { fatalError() }
|
||||
|
||||
private var currentDataStack: DataStack?
|
||||
|
||||
private mutating func set(dataStack: DataStack) -> Bool {
|
||||
|
||||
guard self.currentDataStack != dataStack else {
|
||||
|
||||
return false
|
||||
}
|
||||
self.currentDataStack = dataStack
|
||||
|
||||
let newWrappedValue = self.newWrappedValue
|
||||
self.nonMutatingWrappedValue = LazyNonmutating<Result> {
|
||||
|
||||
newWrappedValue(dataStack)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
// MARK: - LazyNonmutating
|
||||
|
||||
fileprivate final class LazyNonmutating<Value> {
|
||||
|
||||
// MARK: FilePrivate
|
||||
|
||||
lazy var wrappedValue: Value = self.initializer()
|
||||
|
||||
init(_ initializer: @escaping () -> Value) {
|
||||
|
||||
self.initializer = initializer
|
||||
}
|
||||
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private var initializer: () -> Value
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if canImport(UIKit) || canImport(AppKit)
|
||||
|
||||
@available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 15.0, *)
|
||||
extension LiveQuery {
|
||||
|
||||
public init<D: DynamicObject>(liveList: LiveList<D>) where Result == LiveList<D> {
|
||||
|
||||
self.init(
|
||||
newWrappedValue: { _ in liveList }
|
||||
)
|
||||
}
|
||||
|
||||
public init<D: DynamicObject>(_ clauseChain: FetchChainBuilder<D>) where Result == LiveList<D> {
|
||||
|
||||
self.init(
|
||||
newWrappedValue: { $0.liveList(clauseChain) }
|
||||
)
|
||||
}
|
||||
|
||||
public init<D: DynamicObject>(_ clauseChain: SectionMonitorChainBuilder<D>) where Result == LiveList<D> {
|
||||
|
||||
self.init(
|
||||
newWrappedValue: { $0.liveList(clauseChain) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
//#if canImport(SwiftUI) && canImport(Combine)
|
||||
//
|
||||
//import CoreData
|
||||
//import Combine
|
||||
//import SwiftUI
|
||||
//
|
||||
//
|
||||
//#warning("TODO: autoupdating doesn't work yet")
|
||||
//@available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 15.0, *)
|
||||
//@propertyWrapper
|
||||
//public struct LiveQuery<Result: LiveResult>: DynamicProperty {
|
||||
//
|
||||
// // MARK: Public
|
||||
//
|
||||
// @Environment(\.dataStack)
|
||||
// public var dataStack: DataStack
|
||||
//
|
||||
// public typealias ObjectType = Result.ObjectType
|
||||
//
|
||||
//
|
||||
// // MARK: @propertyWrapper
|
||||
//
|
||||
// public var wrappedValue: Result {
|
||||
//
|
||||
// get {
|
||||
//
|
||||
// return self.backingWrapper!.wrappedValue
|
||||
// }
|
||||
// set {
|
||||
//
|
||||
// self.backingWrapper!.wrappedValue = newValue
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// public var projectedValue: ObservedObject<Result>.Wrapper {
|
||||
//
|
||||
// return self.backingWrapper!.projectedValue
|
||||
// }
|
||||
//
|
||||
//
|
||||
// // MARK: DynamicProperty
|
||||
//
|
||||
// public mutating func update() {
|
||||
//
|
||||
// SwiftUI.withAnimation {
|
||||
//
|
||||
// let dataStack = self.dataStack
|
||||
//
|
||||
// if self.backingWrapper == nil {
|
||||
//
|
||||
// self.backingWrapper = ObservedObject(wrappedValue: self.newLiveResult(dataStack))
|
||||
// }
|
||||
// else {
|
||||
//
|
||||
// self.backingWrapper!.wrappedValue = self.newLiveResult(dataStack)
|
||||
// }
|
||||
// self.backingWrapper!.update()
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//
|
||||
// // MARK: FilePrivate
|
||||
//
|
||||
// fileprivate let newLiveResult: (DataStack) -> Result
|
||||
//
|
||||
// fileprivate init(newLiveResult: @escaping (DataStack) -> Result) {
|
||||
//
|
||||
// self.newLiveResult = newLiveResult
|
||||
// }
|
||||
//
|
||||
//
|
||||
// // MARK: Private
|
||||
//
|
||||
//// private var nonMutatingWrappedValue: LazyNonmutating<Result> = .init { fatalError() }
|
||||
//
|
||||
// private var currentDataStack: DataStack?
|
||||
// private var backingWrapper: ObservedObject<Result>?
|
||||
//
|
||||
// private mutating func set(dataStack: DataStack) -> Bool {
|
||||
//
|
||||
// guard self.currentDataStack != dataStack else {
|
||||
//
|
||||
// return false
|
||||
// }
|
||||
// self.currentDataStack = dataStack
|
||||
// if self.backingWrapper == nil {
|
||||
//
|
||||
// self.backingWrapper = ObservedObject(wrappedValue: self.newLiveResult(dataStack))
|
||||
// }
|
||||
// else {
|
||||
//
|
||||
// self.backingWrapper?.wrappedValue = self.newLiveResult(dataStack)
|
||||
// }
|
||||
// return true
|
||||
// }
|
||||
//
|
||||
//
|
||||
// // MARK: - LazyNonmutating
|
||||
//
|
||||
// fileprivate final class LazyNonmutating<Value> {
|
||||
//
|
||||
// // MARK: FilePrivate
|
||||
//
|
||||
// lazy var wrappedValue: Value = self.initializer()
|
||||
//
|
||||
// init(_ initializer: @escaping () -> Value) {
|
||||
//
|
||||
// self.initializer = initializer
|
||||
// }
|
||||
//
|
||||
//
|
||||
// // MARK: Private
|
||||
//
|
||||
// private var initializer: () -> Value
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//
|
||||
//#if canImport(UIKit) || canImport(AppKit)
|
||||
//
|
||||
//@available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 15.0, *)
|
||||
//extension LiveQuery {
|
||||
//
|
||||
// public init<D: DynamicObject>(liveList: LiveList<D>) where Result == LiveList<D> {
|
||||
//
|
||||
// self.init(
|
||||
// newLiveResult: { _ in liveList }
|
||||
// )
|
||||
// }
|
||||
//
|
||||
// public init<D: DynamicObject>(_ clauseChain: FetchChainBuilder<D>) where Result == LiveList<D> {
|
||||
//
|
||||
// self.init(
|
||||
// newLiveResult: { $0.liveList(clauseChain) }
|
||||
// )
|
||||
// }
|
||||
//
|
||||
// public init<D: DynamicObject>(_ clauseChain: SectionMonitorChainBuilder<D>) where Result == LiveList<D> {
|
||||
//
|
||||
// self.init(
|
||||
// newLiveResult: { $0.liveList(clauseChain) }
|
||||
// )
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//#endif
|
||||
//
|
||||
//#endif
|
||||
|
||||
Reference in New Issue
Block a user