Fetch user collections into CoreData and list from ManagedObjectContext

This commit is contained in:
Angelo Stavrow 2020-09-03 15:22:13 -04:00
parent bac7d9bfb0
commit 8e035a43cb
No known key found for this signature in database
GPG Key ID: 1A49C7064E060EEE
11 changed files with 115 additions and 53 deletions

View File

@ -10,7 +10,7 @@ enum PostStatus {
class Post: Identifiable, ObservableObject, Hashable { class Post: Identifiable, ObservableObject, Hashable {
@Published var wfPost: WFPost @Published var wfPost: WFPost
@Published var status: PostStatus @Published var status: PostStatus
@Published var collection: PostCollection @Published var collection: PostCollection?
@Published var hasNewerRemoteCopy: Bool = false @Published var hasNewerRemoteCopy: Bool = false
let id = UUID() let id = UUID()
@ -19,15 +19,15 @@ class Post: Identifiable, ObservableObject, Hashable {
title: String = "Title", title: String = "Title",
body: String = "Write your post here...", body: String = "Write your post here...",
createdDate: Date = Date(), createdDate: Date = Date(),
status: PostStatus = .local, status: PostStatus = .draft,
collection: PostCollection = draftsCollection collection: PostCollection? = nil
) { ) {
self.wfPost = WFPost(body: body, title: title, createdDate: createdDate) self.wfPost = WFPost(body: body, title: title, createdDate: createdDate)
self.status = status self.status = status
self.collection = collection self.collection = collection
} }
convenience init(wfPost: WFPost, in collection: PostCollection = draftsCollection) { convenience init(wfPost: WFPost, in collection: PostCollection? = nil) {
self.init( self.init(
title: wfPost.title ?? "", title: wfPost.title ?? "",
body: wfPost.body, body: wfPost.body,
@ -50,6 +50,10 @@ extension Post {
} }
#if DEBUG #if DEBUG
let userCollection1 = PostCollection(title: "Collection 1")
let userCollection2 = PostCollection(title: "Collection 2")
let userCollection3 = PostCollection(title: "Collection 3")
let testPost = Post( let testPost = Post(
title: "Test Post Title", title: "Test Post Title",
body: """ body: """

View File

@ -1,10 +1,14 @@
import Foundation import Foundation
import WriteFreely import WriteFreely
struct PostCollection: Identifiable { class PostCollection: Identifiable {
let id = UUID() let id = UUID()
let title: String var title: String
var wfCollection: WFCollection? var wfCollection: WFCollection?
init(title: String) {
self.title = title
}
} }
extension PostCollection { extension PostCollection {
@ -12,12 +16,3 @@ extension PostCollection {
return lhs.id == rhs.id 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

View File

@ -8,7 +8,7 @@ class WriteFreelyModel: ObservableObject {
@Published var account = AccountModel() @Published var account = AccountModel()
@Published var preferences = PreferencesModel() @Published var preferences = PreferencesModel()
@Published var store = PostStore() @Published var store = PostStore()
@Published var collections = CollectionListModel(with: []) @Published var collections = CollectionListModel()
@Published var isLoggingIn: Bool = false @Published var isLoggingIn: Bool = false
@Published var selectedPost: Post? @Published var selectedPost: Post?
@ -96,7 +96,7 @@ extension WriteFreelyModel {
} else { } else {
// This is a new local draft. // This is a new local draft.
loggedInClient.createPost( 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() let fetchedCollections = try result.get()
var fetchedCollectionsArray: [PostCollection] = [] var fetchedCollectionsArray: [PostCollection] = []
for fetchedCollection in fetchedCollections { for fetchedCollection in fetchedCollections {
var postCollection = PostCollection(title: fetchedCollection.title) let postCollection = PostCollection(title: fetchedCollection.title)
postCollection.wfCollection = fetchedCollection postCollection.wfCollection = fetchedCollection
fetchedCollectionsArray.append(postCollection) 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 { DispatchQueue.main.async {
self.collections = CollectionListModel(with: fetchedCollectionsArray) // self.collections = CollectionListModel(with: fetchedCollectionsArray)
PersistenceManager().saveContext()
} }
} catch { } catch {
print(error) print(error)
@ -209,10 +221,10 @@ private extension WriteFreelyModel {
for fetchedPost in fetchedPosts { for fetchedPost in fetchedPosts {
var post: Post var post: Post
if let matchingAlias = fetchedPost.collectionAlias { if let matchingAlias = fetchedPost.collectionAlias {
let postCollection = ( let postCollection = PostCollection(title: (
collections.userCollections.filter { $0.wfCollection?.alias == matchingAlias } collections.userCollections.filter { $0.alias == matchingAlias }
).first ).first?.title ?? "NO TITLE")
post = Post(wfPost: fetchedPost, in: postCollection ?? draftsCollection) post = Post(wfPost: fetchedPost, in: postCollection)
} else { } else {
post = Post(wfPost: fetchedPost) post = Post(wfPost: fetchedPost)
} }

View File

@ -7,7 +7,7 @@ struct ContentView: View {
NavigationView { NavigationView {
SidebarView() SidebarView()
PostListView(selectedCollection: allPostsCollection) PostListView(selectedCollection: CollectionListModel.allPostsCollection)
Text("Select a post, or create a new local draft.") Text("Select a post, or create a new local draft.")
.foregroundColor(.secondary) .foregroundColor(.secondary)
@ -18,12 +18,21 @@ struct ContentView: View {
struct ContentView_Previews: PreviewProvider { struct ContentView_Previews: PreviewProvider {
static var previews: some View { 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() let model = WriteFreelyModel()
model.collections = CollectionListModel(with: [userCollection1, userCollection2, userCollection3]) model.collections = CollectionListModel()
for post in testPostData { for post in testPostData {
model.store.add(post) model.store.add(post)
} }
return ContentView() return ContentView()
.environmentObject(model) .environmentObject(model)
.environment(\.managedObjectContext, PersistenceManager.persistentContainer.viewContext)
} }
} }

View File

@ -8,9 +8,18 @@ struct SidebarView: View {
struct SidebarView_Previews: PreviewProvider { struct SidebarView_Previews: PreviewProvider {
static var previews: some View { 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() let model = WriteFreelyModel()
model.collections = CollectionListModel(with: [userCollection1, userCollection2, userCollection3]) model.collections = CollectionListModel()
return SidebarView() return SidebarView()
.environmentObject(model) .environmentObject(model)
.environment(\.managedObjectContext, PersistenceManager.persistentContainer.viewContext)
} }
} }

View File

@ -7,13 +7,14 @@ import AppKit
#endif #endif
class PersistenceManager { class PersistenceManager {
let persistentContainer: NSPersistentContainer = { static let persistentContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: "LocalStorageModel") let container = NSPersistentContainer(name: "LocalStorageModel")
container.loadPersistentStores(completionHandler: { (_, error) in container.loadPersistentStores { _, error in
container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
if let error = error { if let error = error {
fatalError("Unresolved error loading persistent store: \(error)") fatalError("Unresolved error loading persistent store: \(error)")
} }
}) }
return container return container
}() }()
@ -38,9 +39,9 @@ class PersistenceManager {
} }
func saveContext() { func saveContext() {
if persistentContainer.viewContext.hasChanges { if PersistenceManager.persistentContainer.viewContext.hasChanges {
do { do {
try persistentContainer.viewContext.save() try PersistenceManager.persistentContainer.viewContext.save()
} catch { } catch {
print("Error saving context: \(error)") print("Error saving context: \(error)")
} }

View File

@ -1,18 +1,25 @@
import SwiftUI import SwiftUI
import CoreData
class CollectionListModel: ObservableObject { class CollectionListModel: ObservableObject {
private(set) var userCollections: [PostCollection] = [] @Published var userCollections = [WFACollection]()
@Published private(set) var collectionsList: [PostCollection] = [ allPostsCollection, draftsCollection ]
init(with userCollections: [PostCollection]) { static let allPostsCollection = PostCollection(title: "All Posts")
for userCollection in userCollections { static let draftsCollection = PostCollection(title: "Drafts")
self.userCollections.append(userCollection)
} init() {
collectionsList.append(contentsOf: self.userCollections) // 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() { func clearUserCollection() {
userCollections = [] userCollections = []
collectionsList = [ allPostsCollection, draftsCollection ] // Clear collections from CoreData store.
} }
} }

View File

@ -2,14 +2,25 @@ import SwiftUI
struct CollectionListView: View { struct CollectionListView: View {
@EnvironmentObject var model: WriteFreelyModel @EnvironmentObject var model: WriteFreelyModel
@Environment(\.managedObjectContext) var moc
@FetchRequest(entity: WFACollection.entity(), sortDescriptors: []) var collections: FetchedResults<WFACollection>
var body: some View { var body: some View {
List { List {
ForEach(model.collections.collectionsList) { collection in NavigationLink(destination: PostListView(selectedCollection: CollectionListModel.allPostsCollection)) {
NavigationLink( Text(CollectionListModel.allPostsCollection.title)
destination: PostListView(selectedCollection: collection) }
) { NavigationLink(destination: PostListView(selectedCollection: CollectionListModel.draftsCollection)) {
Text(collection.title) 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 { struct CollectionSidebar_Previews: PreviewProvider {
@Environment(\.managedObjectContext) var moc
static var previews: some View { 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() let model = WriteFreelyModel()
model.collections = CollectionListModel(with: [userCollection1, userCollection2, userCollection3]) model.collections = CollectionListModel()
return CollectionListView() return CollectionListView()
.environmentObject(model) .environmentObject(model)
.environment(\.managedObjectContext, PersistenceManager.persistentContainer.viewContext)
} }
} }

View File

@ -105,13 +105,15 @@ struct PostListView: View {
} }
private func showPosts(for collection: PostCollection) -> [Post] { private func showPosts(for collection: PostCollection) -> [Post] {
if collection == allPostsCollection { var posts: [Post]
return model.store.posts if collection == CollectionListModel.allPostsCollection {
posts = model.store.posts
} else if collection == CollectionListModel.draftsCollection {
posts = model.store.posts.filter { $0.collection == nil }
} else { } else {
return model.store.posts.filter { posts = model.store.posts.filter { $0.collection?.title == collection.title }
$0.collection.title == collection.title
}
} }
return posts
} }
private func reloadFromServer() { private func reloadFromServer() {
@ -130,7 +132,7 @@ struct PostList_Previews: PreviewProvider {
model.store.add(post) model.store.add(post)
} }
return Group { return Group {
PostListView(selectedCollection: allPostsCollection) PostListView(selectedCollection: CollectionListModel.allPostsCollection)
.environmentObject(model) .environmentObject(model)
} }
} }

View File

@ -12,6 +12,7 @@ struct WriteFreely_MultiPlatformApp: App {
WindowGroup { WindowGroup {
ContentView() ContentView()
.environmentObject(model) .environmentObject(model)
.environment(\.managedObjectContext, PersistenceManager.persistentContainer.viewContext)
// .preferredColorScheme(preferences.selectedColorScheme) // See PreferencesModel for info. // .preferredColorScheme(preferences.selectedColorScheme) // See PreferencesModel for info.
} }

View File

@ -3,7 +3,7 @@ import CoreData
extension WFACollection { extension WFACollection {
@nonobjc public class func fetchRequest() -> NSFetchRequest<WFACollection> { @nonobjc public class func createFetchRequest() -> NSFetchRequest<WFACollection> {
return NSFetchRequest<WFACollection>(entityName: "WFACollection") return NSFetchRequest<WFACollection>(entityName: "WFACollection")
} }
@ -12,7 +12,7 @@ extension WFACollection {
@NSManaged public var email: String? @NSManaged public var email: String?
@NSManaged public var isPublic: Bool @NSManaged public var isPublic: Bool
@NSManaged public var styleSheet: String? @NSManaged public var styleSheet: String?
@NSManaged public var title: String? @NSManaged public var title: String
@NSManaged public var url: String? @NSManaged public var url: String?
} }