@@ -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, | |||||
collection: PostCollection = draftsCollection | |||||
status: PostStatus = .draft, | |||||
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: """ | ||||
@@ -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 |
@@ -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 = ( | |||||
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 { | } else { | ||||
post = Post(wfPost: fetchedPost) | post = Post(wfPost: fetchedPost) | ||||
} | } | ||||
@@ -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) | |||||
} | } | ||||
} | } |
@@ -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) | |||||
} | } | ||||
} | } |
@@ -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)") | ||||
} | } | ||||
@@ -1,18 +1,25 @@ | |||||
import SwiftUI | import SwiftUI | ||||
import CoreData | |||||
class CollectionListModel: ObservableObject { | 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() { | func clearUserCollection() { | ||||
userCollections = [] | userCollections = [] | ||||
collectionsList = [ allPostsCollection, draftsCollection ] | |||||
// Clear collections from CoreData store. | |||||
} | } | ||||
} | } |
@@ -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: 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 { | 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) | |||||
} | } | ||||
} | } |
@@ -105,13 +105,15 @@ struct PostListView: View { | |||||
} | } | ||||
private func showPosts(for collection: PostCollection) -> [Post] { | 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 { | } 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() { | 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) | ||||
} | } | ||||
} | } | ||||
@@ -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. | ||||
} | } | ||||
@@ -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? | ||||
} | } | ||||