From 8e035a43cb17ffc88df0669314da3d4a4f0d8e8d Mon Sep 17 00:00:00 2001 From: Angelo Stavrow Date: Thu, 3 Sep 2020 15:22:13 -0400 Subject: [PATCH] Fetch user collections into CoreData and list from ManagedObjectContext --- Shared/Models/Post.swift | 12 ++++--- Shared/Models/PostCollection.swift | 17 ++++------ Shared/Models/WriteFreelyModel.swift | 28 ++++++++++----- Shared/Navigation/ContentView.swift | 13 +++++-- Shared/Navigation/SidebarView.swift | 11 +++++- Shared/PersistenceManager.swift | 11 +++--- .../PostCollection/CollectionListModel.swift | 23 ++++++++----- .../PostCollection/CollectionListView.swift | 34 +++++++++++++++---- Shared/PostList/PostListView.swift | 14 ++++---- Shared/WriteFreely_MultiPlatformApp.swift | 1 + WFACollection+CoreDataProperties.swift | 4 +-- 11 files changed, 115 insertions(+), 53 deletions(-) diff --git a/Shared/Models/Post.swift b/Shared/Models/Post.swift index 57e1d12..9f42d9f 100644 --- a/Shared/Models/Post.swift +++ b/Shared/Models/Post.swift @@ -10,7 +10,7 @@ enum PostStatus { class Post: Identifiable, ObservableObject, Hashable { @Published var wfPost: WFPost @Published var status: PostStatus - @Published var collection: PostCollection + @Published var collection: PostCollection? @Published var hasNewerRemoteCopy: Bool = false let id = UUID() @@ -19,15 +19,15 @@ class Post: Identifiable, ObservableObject, Hashable { title: String = "Title", body: String = "Write your post here...", createdDate: Date = Date(), - status: PostStatus = .local, - collection: PostCollection = draftsCollection + status: PostStatus = .draft, + collection: PostCollection? = nil ) { self.wfPost = WFPost(body: body, title: title, createdDate: createdDate) self.status = status self.collection = collection } - convenience init(wfPost: WFPost, in collection: PostCollection = draftsCollection) { + convenience init(wfPost: WFPost, in collection: PostCollection? = nil) { self.init( title: wfPost.title ?? "", body: wfPost.body, @@ -50,6 +50,10 @@ extension Post { } #if DEBUG +let userCollection1 = PostCollection(title: "Collection 1") +let userCollection2 = PostCollection(title: "Collection 2") +let userCollection3 = PostCollection(title: "Collection 3") + let testPost = Post( title: "Test Post Title", body: """ diff --git a/Shared/Models/PostCollection.swift b/Shared/Models/PostCollection.swift index 8801cff..c4a5d5b 100644 --- a/Shared/Models/PostCollection.swift +++ b/Shared/Models/PostCollection.swift @@ -1,10 +1,14 @@ import Foundation import WriteFreely -struct PostCollection: Identifiable { +class PostCollection: Identifiable { let id = UUID() - let title: String + var title: String var wfCollection: WFCollection? + + init(title: String) { + self.title = title + } } extension PostCollection { @@ -12,12 +16,3 @@ extension PostCollection { return lhs.id == rhs.id } } - -let allPostsCollection = PostCollection(title: "All Posts") -let draftsCollection = PostCollection(title: "Drafts") - -#if DEBUG -let userCollection1 = PostCollection(title: "Collection 1") -let userCollection2 = PostCollection(title: "Collection 2") -let userCollection3 = PostCollection(title: "Collection 3") -#endif diff --git a/Shared/Models/WriteFreelyModel.swift b/Shared/Models/WriteFreelyModel.swift index 9e6e8b8..4096de8 100644 --- a/Shared/Models/WriteFreelyModel.swift +++ b/Shared/Models/WriteFreelyModel.swift @@ -8,7 +8,7 @@ class WriteFreelyModel: ObservableObject { @Published var account = AccountModel() @Published var preferences = PreferencesModel() @Published var store = PostStore() - @Published var collections = CollectionListModel(with: []) + @Published var collections = CollectionListModel() @Published var isLoggingIn: Bool = false @Published var selectedPost: Post? @@ -96,7 +96,7 @@ extension WriteFreelyModel { } else { // This is a new local draft. loggedInClient.createPost( - post: post.wfPost, in: post.collection.wfCollection?.alias, completion: publishHandler + post: post.wfPost, in: post.collection?.wfCollection?.alias, completion: publishHandler ) } } @@ -190,12 +190,24 @@ private extension WriteFreelyModel { let fetchedCollections = try result.get() var fetchedCollectionsArray: [PostCollection] = [] for fetchedCollection in fetchedCollections { - var postCollection = PostCollection(title: fetchedCollection.title) + let postCollection = PostCollection(title: fetchedCollection.title) postCollection.wfCollection = fetchedCollection fetchedCollectionsArray.append(postCollection) + + DispatchQueue.main.async { + let localCollection = WFACollection(context: PersistenceManager.persistentContainer.viewContext) + localCollection.alias = fetchedCollection.alias + localCollection.blogDescription = fetchedCollection.description + localCollection.email = fetchedCollection.email + localCollection.isPublic = fetchedCollection.isPublic ?? false + localCollection.styleSheet = fetchedCollection.styleSheet + localCollection.title = fetchedCollection.title + localCollection.url = fetchedCollection.url + } } DispatchQueue.main.async { - self.collections = CollectionListModel(with: fetchedCollectionsArray) +// self.collections = CollectionListModel(with: fetchedCollectionsArray) + PersistenceManager().saveContext() } } catch { print(error) @@ -209,10 +221,10 @@ private extension WriteFreelyModel { for fetchedPost in fetchedPosts { var post: Post if let matchingAlias = fetchedPost.collectionAlias { - let postCollection = ( - collections.userCollections.filter { $0.wfCollection?.alias == matchingAlias } - ).first - post = Post(wfPost: fetchedPost, in: postCollection ?? draftsCollection) + let postCollection = PostCollection(title: ( + collections.userCollections.filter { $0.alias == matchingAlias } + ).first?.title ?? "NO TITLE") + post = Post(wfPost: fetchedPost, in: postCollection) } else { post = Post(wfPost: fetchedPost) } diff --git a/Shared/Navigation/ContentView.swift b/Shared/Navigation/ContentView.swift index efdeef3..1213f1e 100644 --- a/Shared/Navigation/ContentView.swift +++ b/Shared/Navigation/ContentView.swift @@ -7,7 +7,7 @@ struct ContentView: View { NavigationView { SidebarView() - PostListView(selectedCollection: allPostsCollection) + PostListView(selectedCollection: CollectionListModel.allPostsCollection) Text("Select a post, or create a new local draft.") .foregroundColor(.secondary) @@ -18,12 +18,21 @@ struct ContentView: View { struct ContentView_Previews: PreviewProvider { static var previews: some View { + let userCollection1 = WFACollection(context: PersistenceManager.persistentContainer.viewContext) + let userCollection2 = WFACollection(context: PersistenceManager.persistentContainer.viewContext) + let userCollection3 = WFACollection(context: PersistenceManager.persistentContainer.viewContext) + userCollection1.title = "Collection 1" + userCollection2.title = "Collection 2" + userCollection3.title = "Collection 3" + let model = WriteFreelyModel() - model.collections = CollectionListModel(with: [userCollection1, userCollection2, userCollection3]) + model.collections = CollectionListModel() + for post in testPostData { model.store.add(post) } return ContentView() .environmentObject(model) + .environment(\.managedObjectContext, PersistenceManager.persistentContainer.viewContext) } } diff --git a/Shared/Navigation/SidebarView.swift b/Shared/Navigation/SidebarView.swift index a95ee08..7175fa4 100644 --- a/Shared/Navigation/SidebarView.swift +++ b/Shared/Navigation/SidebarView.swift @@ -8,9 +8,18 @@ struct SidebarView: View { struct SidebarView_Previews: PreviewProvider { static var previews: some View { + let userCollection1 = WFACollection(context: PersistenceManager.persistentContainer.viewContext) + let userCollection2 = WFACollection(context: PersistenceManager.persistentContainer.viewContext) + let userCollection3 = WFACollection(context: PersistenceManager.persistentContainer.viewContext) + userCollection1.title = "Collection 1" + userCollection2.title = "Collection 2" + userCollection3.title = "Collection 3" + let model = WriteFreelyModel() - model.collections = CollectionListModel(with: [userCollection1, userCollection2, userCollection3]) + model.collections = CollectionListModel() + return SidebarView() .environmentObject(model) + .environment(\.managedObjectContext, PersistenceManager.persistentContainer.viewContext) } } diff --git a/Shared/PersistenceManager.swift b/Shared/PersistenceManager.swift index c5ea6ea..e7d22f4 100644 --- a/Shared/PersistenceManager.swift +++ b/Shared/PersistenceManager.swift @@ -7,13 +7,14 @@ import AppKit #endif class PersistenceManager { - let persistentContainer: NSPersistentContainer = { + static let persistentContainer: NSPersistentContainer = { let container = NSPersistentContainer(name: "LocalStorageModel") - container.loadPersistentStores(completionHandler: { (_, error) in + container.loadPersistentStores { _, error in + container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy if let error = error { fatalError("Unresolved error loading persistent store: \(error)") } - }) + } return container }() @@ -38,9 +39,9 @@ class PersistenceManager { } func saveContext() { - if persistentContainer.viewContext.hasChanges { + if PersistenceManager.persistentContainer.viewContext.hasChanges { do { - try persistentContainer.viewContext.save() + try PersistenceManager.persistentContainer.viewContext.save() } catch { print("Error saving context: \(error)") } diff --git a/Shared/PostCollection/CollectionListModel.swift b/Shared/PostCollection/CollectionListModel.swift index 64c7c54..4cd21cc 100644 --- a/Shared/PostCollection/CollectionListModel.swift +++ b/Shared/PostCollection/CollectionListModel.swift @@ -1,18 +1,25 @@ import SwiftUI +import CoreData class CollectionListModel: ObservableObject { - private(set) var userCollections: [PostCollection] = [] - @Published private(set) var collectionsList: [PostCollection] = [ allPostsCollection, draftsCollection ] + @Published var userCollections = [WFACollection]() - init(with userCollections: [PostCollection]) { - for userCollection in userCollections { - self.userCollections.append(userCollection) - } - collectionsList.append(contentsOf: self.userCollections) + static let allPostsCollection = PostCollection(title: "All Posts") + static let draftsCollection = PostCollection(title: "Drafts") + + init() { +// let request = WFACollection.createFetchRequest() +// request.sortDescriptors = [] +// do { +// userCollections = try PersistenceManager.persistentContainer.viewContext.fetch(request) +// } catch { +// print("Error: Failed to fetch user collections from local store") +// userCollections = [] +// } } func clearUserCollection() { userCollections = [] - collectionsList = [ allPostsCollection, draftsCollection ] + // Clear collections from CoreData store. } } diff --git a/Shared/PostCollection/CollectionListView.swift b/Shared/PostCollection/CollectionListView.swift index 1e06865..6c71177 100644 --- a/Shared/PostCollection/CollectionListView.swift +++ b/Shared/PostCollection/CollectionListView.swift @@ -2,14 +2,25 @@ import SwiftUI struct CollectionListView: View { @EnvironmentObject var model: WriteFreelyModel + @Environment(\.managedObjectContext) var moc + + @FetchRequest(entity: WFACollection.entity(), sortDescriptors: []) var collections: FetchedResults var body: some View { List { - ForEach(model.collections.collectionsList) { collection in - NavigationLink( - destination: PostListView(selectedCollection: collection) - ) { - Text(collection.title) + NavigationLink(destination: PostListView(selectedCollection: CollectionListModel.allPostsCollection)) { + Text(CollectionListModel.allPostsCollection.title) + } + NavigationLink(destination: PostListView(selectedCollection: CollectionListModel.draftsCollection)) { + Text(CollectionListModel.draftsCollection.title) + } + Section(header: Text("Your Blogs")) { + ForEach(collections, id: \.alias) { collection in + NavigationLink( + destination: PostListView(selectedCollection: PostCollection(title: collection.title)) + ) { + Text(collection.title) + } } } } @@ -19,10 +30,21 @@ struct CollectionListView: View { } struct CollectionSidebar_Previews: PreviewProvider { + @Environment(\.managedObjectContext) var moc + static var previews: some View { + let userCollection1 = WFACollection(context: PersistenceManager.persistentContainer.viewContext) + let userCollection2 = WFACollection(context: PersistenceManager.persistentContainer.viewContext) + let userCollection3 = WFACollection(context: PersistenceManager.persistentContainer.viewContext) + userCollection1.title = "Collection 1" + userCollection2.title = "Collection 2" + userCollection3.title = "Collection 3" + let model = WriteFreelyModel() - model.collections = CollectionListModel(with: [userCollection1, userCollection2, userCollection3]) + model.collections = CollectionListModel() + return CollectionListView() .environmentObject(model) + .environment(\.managedObjectContext, PersistenceManager.persistentContainer.viewContext) } } diff --git a/Shared/PostList/PostListView.swift b/Shared/PostList/PostListView.swift index 4d79bc7..bffd1f8 100644 --- a/Shared/PostList/PostListView.swift +++ b/Shared/PostList/PostListView.swift @@ -105,13 +105,15 @@ struct PostListView: View { } private func showPosts(for collection: PostCollection) -> [Post] { - if collection == allPostsCollection { - return model.store.posts + var posts: [Post] + if collection == CollectionListModel.allPostsCollection { + posts = model.store.posts + } else if collection == CollectionListModel.draftsCollection { + posts = model.store.posts.filter { $0.collection == nil } } else { - return model.store.posts.filter { - $0.collection.title == collection.title - } + posts = model.store.posts.filter { $0.collection?.title == collection.title } } + return posts } private func reloadFromServer() { @@ -130,7 +132,7 @@ struct PostList_Previews: PreviewProvider { model.store.add(post) } return Group { - PostListView(selectedCollection: allPostsCollection) + PostListView(selectedCollection: CollectionListModel.allPostsCollection) .environmentObject(model) } } diff --git a/Shared/WriteFreely_MultiPlatformApp.swift b/Shared/WriteFreely_MultiPlatformApp.swift index 63c1182..3865a58 100644 --- a/Shared/WriteFreely_MultiPlatformApp.swift +++ b/Shared/WriteFreely_MultiPlatformApp.swift @@ -12,6 +12,7 @@ struct WriteFreely_MultiPlatformApp: App { WindowGroup { ContentView() .environmentObject(model) + .environment(\.managedObjectContext, PersistenceManager.persistentContainer.viewContext) // .preferredColorScheme(preferences.selectedColorScheme) // See PreferencesModel for info. } diff --git a/WFACollection+CoreDataProperties.swift b/WFACollection+CoreDataProperties.swift index 7aceb40..8c8ca02 100644 --- a/WFACollection+CoreDataProperties.swift +++ b/WFACollection+CoreDataProperties.swift @@ -3,7 +3,7 @@ import CoreData extension WFACollection { - @nonobjc public class func fetchRequest() -> NSFetchRequest { + @nonobjc public class func createFetchRequest() -> NSFetchRequest { return NSFetchRequest(entityName: "WFACollection") } @@ -12,7 +12,7 @@ extension WFACollection { @NSManaged public var email: String? @NSManaged public var isPublic: Bool @NSManaged public var styleSheet: String? - @NSManaged public var title: String? + @NSManaged public var title: String @NSManaged public var url: String? }