mirror of
https://github.com/writeas/writefreely-swiftui-multiplatform.git
synced 2024-11-15 01:11:02 +00:00
Replace Post type with WFAPost managed object
This commit is contained in:
parent
6728e20821
commit
ca8e74b2dc
@ -19,6 +19,7 @@
|
||||
<attribute name="body" attributeType="String"/>
|
||||
<attribute name="collectionAlias" optional="YES" attributeType="String"/>
|
||||
<attribute name="createdDate" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
|
||||
<attribute name="hasNewerRemoteCopy" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="language" optional="YES" attributeType="String"/>
|
||||
<attribute name="postId" optional="YES" attributeType="String"/>
|
||||
<attribute name="rtl" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
@ -34,6 +35,6 @@
|
||||
</entity>
|
||||
<elements>
|
||||
<element name="WFACollection" positionX="14.806640625" positionY="202.9156341552734" width="128" height="148"/>
|
||||
<element name="WFAPost" positionX="287.377197265625" positionY="243.2452697753906" width="128" height="194"/>
|
||||
<element name="WFAPost" positionX="287.377197265625" positionY="243.2452697753906" width="128" height="209"/>
|
||||
</elements>
|
||||
</model>
|
@ -10,7 +10,7 @@ class WriteFreelyModel: ObservableObject {
|
||||
@Published var store = PostListModel()
|
||||
@Published var collections = CollectionListModel()
|
||||
@Published var isLoggingIn: Bool = false
|
||||
@Published var selectedPost: Post?
|
||||
@Published var selectedPost: WFAPost?
|
||||
|
||||
private var client: WFClient?
|
||||
private let defaults = UserDefaults.standard
|
||||
@ -84,27 +84,41 @@ extension WriteFreelyModel {
|
||||
loggedInClient.getPosts(completion: fetchUserPostsHandler)
|
||||
}
|
||||
|
||||
func publish(post: Post) {
|
||||
func publish(post: WFAPost) {
|
||||
guard let loggedInClient = client else { return }
|
||||
|
||||
if let existingPostId = post.wfPost.postId {
|
||||
var wfPost = WFPost(
|
||||
body: post.body ?? "",
|
||||
title: post.title,
|
||||
appearance: post.appearance,
|
||||
language: post.language,
|
||||
rtl: post.rtl,
|
||||
createdDate: post.createdDate
|
||||
)
|
||||
|
||||
if let existingPostId = post.postId {
|
||||
// This is an existing post.
|
||||
wfPost.postId = post.postId
|
||||
wfPost.slug = post.slug
|
||||
wfPost.updatedDate = post.updatedDate
|
||||
wfPost.collectionAlias = post.collectionAlias
|
||||
|
||||
loggedInClient.updatePost(
|
||||
postId: existingPostId,
|
||||
updatedPost: post.wfPost,
|
||||
updatedPost: wfPost,
|
||||
completion: publishHandler
|
||||
)
|
||||
} else {
|
||||
// This is a new local draft.
|
||||
loggedInClient.createPost(
|
||||
post: post.wfPost, in: post.collection?.alias, completion: publishHandler
|
||||
post: wfPost, in: post.collectionAlias, completion: publishHandler
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func updateFromServer(post: Post) {
|
||||
func updateFromServer(post: WFAPost) {
|
||||
guard let loggedInClient = client else { return }
|
||||
guard let postId = post.wfPost.postId else { return }
|
||||
guard let postId = post.postId else { return }
|
||||
DispatchQueue.main.async {
|
||||
self.selectedPost = post
|
||||
}
|
||||
@ -212,18 +226,7 @@ private extension WriteFreelyModel {
|
||||
func fetchUserPostsHandler(result: Result<[WFPost], Error>) {
|
||||
do {
|
||||
let fetchedPosts = try result.get()
|
||||
var fetchedPostsArray: [Post] = []
|
||||
for fetchedPost in fetchedPosts {
|
||||
var post: Post
|
||||
if let matchingAlias = fetchedPost.collectionAlias {
|
||||
let matchingCachedCollection = (
|
||||
collections.userCollections.filter { $0.alias == matchingAlias }
|
||||
).first
|
||||
post = Post(wfPost: fetchedPost, in: matchingCachedCollection)
|
||||
} else {
|
||||
post = Post(wfPost: fetchedPost)
|
||||
}
|
||||
fetchedPostsArray.append(post)
|
||||
let managedPost = WFAPost(context: PersistenceManager.persistentContainer.viewContext)
|
||||
managedPost.postId = fetchedPost.postId
|
||||
managedPost.slug = fetchedPost.slug
|
||||
@ -235,10 +238,9 @@ private extension WriteFreelyModel {
|
||||
managedPost.title = fetchedPost.title
|
||||
managedPost.body = fetchedPost.body
|
||||
managedPost.collectionAlias = fetchedPost.collectionAlias
|
||||
managedPost.status = PostStatus.published.rawValue // 0 = local, 1 = edited, 2 = published
|
||||
managedPost.status = PostStatus.published.rawValue
|
||||
}
|
||||
DispatchQueue.main.async {
|
||||
self.store.updateStore(with: fetchedPostsArray)
|
||||
PersistenceManager().saveContext()
|
||||
}
|
||||
} catch {
|
||||
@ -248,13 +250,25 @@ private extension WriteFreelyModel {
|
||||
|
||||
func publishHandler(result: Result<WFPost, Error>) {
|
||||
do {
|
||||
let wfPost = try result.get()
|
||||
let fetchedPost = try result.get()
|
||||
let foundPostIndex = store.posts.firstIndex(where: {
|
||||
$0.wfPost.title == wfPost.title && $0.wfPost.body == wfPost.body
|
||||
$0.title == fetchedPost.title && $0.body == fetchedPost.body
|
||||
})
|
||||
guard let index = foundPostIndex else { return }
|
||||
let cachedPost = self.store.posts[index]
|
||||
cachedPost.appearance = fetchedPost.appearance
|
||||
cachedPost.body = fetchedPost.body
|
||||
cachedPost.collectionAlias = fetchedPost.collectionAlias
|
||||
cachedPost.createdDate = fetchedPost.createdDate
|
||||
cachedPost.language = fetchedPost.language
|
||||
cachedPost.postId = fetchedPost.postId
|
||||
cachedPost.rtl = fetchedPost.rtl ?? false
|
||||
cachedPost.slug = fetchedPost.slug
|
||||
cachedPost.status = PostStatus.published.rawValue
|
||||
cachedPost.title = fetchedPost.title
|
||||
cachedPost.updatedDate = fetchedPost.updatedDate
|
||||
DispatchQueue.main.async {
|
||||
self.store.posts[index].wfPost = wfPost
|
||||
PersistenceManager().saveContext()
|
||||
}
|
||||
} catch {
|
||||
print(error)
|
||||
@ -264,9 +278,20 @@ private extension WriteFreelyModel {
|
||||
func updateFromServerHandler(result: Result<WFPost, Error>) {
|
||||
do {
|
||||
let fetchedPost = try result.get()
|
||||
guard let cachedPost = self.selectedPost else { return }
|
||||
cachedPost.appearance = fetchedPost.appearance
|
||||
cachedPost.body = fetchedPost.body
|
||||
cachedPost.collectionAlias = fetchedPost.collectionAlias
|
||||
cachedPost.createdDate = fetchedPost.createdDate
|
||||
cachedPost.language = fetchedPost.language
|
||||
cachedPost.postId = fetchedPost.postId
|
||||
cachedPost.rtl = fetchedPost.rtl ?? false
|
||||
cachedPost.slug = fetchedPost.slug
|
||||
cachedPost.status = PostStatus.published.rawValue
|
||||
cachedPost.title = fetchedPost.title
|
||||
cachedPost.updatedDate = fetchedPost.updatedDate
|
||||
DispatchQueue.main.async {
|
||||
guard let selectedPost = self.selectedPost else { return }
|
||||
self.store.replace(post: selectedPost, with: fetchedPost)
|
||||
PersistenceManager().saveContext()
|
||||
}
|
||||
} catch {
|
||||
print(error)
|
||||
|
@ -16,23 +16,23 @@ 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()
|
||||
|
||||
for post in testPostData {
|
||||
model.store.add(post)
|
||||
}
|
||||
return ContentView()
|
||||
.environmentObject(model)
|
||||
.environment(\.managedObjectContext, PersistenceManager.persistentContainer.viewContext)
|
||||
}
|
||||
}
|
||||
//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()
|
||||
//
|
||||
// for post in testPostData {
|
||||
// model.store.add(post)
|
||||
// }
|
||||
// return ContentView()
|
||||
// .environmentObject(model)
|
||||
// .environment(\.managedObjectContext, PersistenceManager.persistentContainer.viewContext)
|
||||
// }
|
||||
//}
|
||||
|
@ -6,7 +6,7 @@ struct PostEditorStatusToolbarView: View {
|
||||
#endif
|
||||
@EnvironmentObject var model: WriteFreelyModel
|
||||
|
||||
@ObservedObject var post: Post
|
||||
@ObservedObject var post: WFAPost
|
||||
|
||||
var body: some View {
|
||||
if post.hasNewerRemoteCopy {
|
||||
@ -61,76 +61,76 @@ struct PostEditorStatusToolbarView: View {
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
let testPost = Post(
|
||||
title: "Test Post Title",
|
||||
body: """
|
||||
Here's some cool sample body text. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean ultrices \
|
||||
posuere dignissim. Vestibulum a libero tempor, lacinia nulla vitae, congue purus. Nunc ac nulla quam. Duis \
|
||||
tincidunt eros augue, et volutpat tortor pulvinar ut. Nullam sit amet maximus urna. Phasellus non dignissim lacus.\
|
||||
Nulla ac posuere ex. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec \
|
||||
non molestie mauris. Suspendisse potenti. Vivamus at erat turpis.
|
||||
|
||||
Pellentesque porttitor gravida tincidunt. Sed vitae eros non metus aliquam hendrerit. Aliquam sed risus suscipit \
|
||||
turpis dictum dictum. Duis lacus lectus, dictum vel felis in, rhoncus fringilla felis. Nunc id dolor nisl. Aliquam \
|
||||
euismod purus elit. Nullam egestas neque leo, sed aliquet ligula ultrices nec.
|
||||
""",
|
||||
createdDate: Date()
|
||||
)
|
||||
#endif
|
||||
|
||||
struct ToolbarView_LocalPreviews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
let model = WriteFreelyModel()
|
||||
let post = testPost
|
||||
return PostEditorStatusToolbarView(post: post)
|
||||
.environmentObject(model)
|
||||
}
|
||||
}
|
||||
|
||||
struct ToolbarView_RemotePreviews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
let model = WriteFreelyModel()
|
||||
let newerRemotePost = Post(
|
||||
title: testPost.wfPost.title ?? "",
|
||||
body: testPost.wfPost.body,
|
||||
createdDate: testPost.wfPost.createdDate ?? Date(),
|
||||
status: testPost.status,
|
||||
collection: testPost.collection
|
||||
)
|
||||
newerRemotePost.hasNewerRemoteCopy = true
|
||||
return PostEditorStatusToolbarView(post: newerRemotePost)
|
||||
.environmentObject(model)
|
||||
}
|
||||
}
|
||||
|
||||
#if os(iOS)
|
||||
struct ToolbarView_CompactLocalPreviews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
let model = WriteFreelyModel()
|
||||
let post = testPost
|
||||
return PostEditorStatusToolbarView(post: post)
|
||||
.environmentObject(model)
|
||||
.environment(\.horizontalSizeClass, .compact)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if os(iOS)
|
||||
struct ToolbarView_CompactRemotePreviews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
let model = WriteFreelyModel()
|
||||
let newerRemotePost = Post(
|
||||
title: testPost.wfPost.title ?? "",
|
||||
body: testPost.wfPost.body,
|
||||
createdDate: testPost.wfPost.createdDate ?? Date(),
|
||||
status: testPost.status,
|
||||
collection: testPost.collection
|
||||
)
|
||||
newerRemotePost.hasNewerRemoteCopy = true
|
||||
return PostEditorStatusToolbarView(post: newerRemotePost)
|
||||
.environmentObject(model)
|
||||
.environment(\.horizontalSizeClass, .compact)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
//#if DEBUG
|
||||
//let testPost = Post(
|
||||
// title: "Test Post Title",
|
||||
// body: """
|
||||
// Here's some cool sample body text. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean ultrices \
|
||||
// posuere dignissim. Vestibulum a libero tempor, lacinia nulla vitae, congue purus. Nunc ac nulla quam. Duis \
|
||||
// tincidunt eros augue, et volutpat tortor pulvinar ut. Nullam sit amet maximus urna. Phasellus non dignissim \
|
||||
// lacus. Nulla ac posuere ex. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus \
|
||||
// mus. Donec non molestie mauris. Suspendisse potenti. Vivamus at erat turpis.
|
||||
//
|
||||
// Pellentesque porttitor gravida tincidunt. Sed vitae eros non metus aliquam hendrerit. Aliquam sed risus suscipit \
|
||||
// turpis dictum dictum. Duis lacus lectus, dictum vel felis in, rhoncus fringilla felis. Nunc id dolor nisl. \
|
||||
// Aliquam euismod purus elit. Nullam egestas neque leo, sed aliquet ligula ultrices nec.
|
||||
// """,
|
||||
// createdDate: Date()
|
||||
//)
|
||||
//#endif
|
||||
//
|
||||
//struct ToolbarView_LocalPreviews: PreviewProvider {
|
||||
// static var previews: some View {
|
||||
// let model = WriteFreelyModel()
|
||||
// let post = testPost
|
||||
// return PostEditorStatusToolbarView(post: post)
|
||||
// .environmentObject(model)
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//struct ToolbarView_RemotePreviews: PreviewProvider {
|
||||
// static var previews: some View {
|
||||
// let model = WriteFreelyModel()
|
||||
// let newerRemotePost = Post(
|
||||
// title: testPost.wfPost.title ?? "",
|
||||
// body: testPost.wfPost.body,
|
||||
// createdDate: testPost.wfPost.createdDate ?? Date(),
|
||||
// status: testPost.status,
|
||||
// collection: testPost.collection
|
||||
// )
|
||||
// newerRemotePost.hasNewerRemoteCopy = true
|
||||
// return PostEditorStatusToolbarView(post: newerRemotePost)
|
||||
// .environmentObject(model)
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//#if os(iOS)
|
||||
//struct ToolbarView_CompactLocalPreviews: PreviewProvider {
|
||||
// static var previews: some View {
|
||||
// let model = WriteFreelyModel()
|
||||
// let post = testPost
|
||||
// return PostEditorStatusToolbarView(post: post)
|
||||
// .environmentObject(model)
|
||||
// .environment(\.horizontalSizeClass, .compact)
|
||||
// }
|
||||
//}
|
||||
//#endif
|
||||
//
|
||||
//#if os(iOS)
|
||||
//struct ToolbarView_CompactRemotePreviews: PreviewProvider {
|
||||
// static var previews: some View {
|
||||
// let model = WriteFreelyModel()
|
||||
// let newerRemotePost = Post(
|
||||
// title: testPost.wfPost.title ?? "",
|
||||
// body: testPost.wfPost.body,
|
||||
// createdDate: testPost.wfPost.createdDate ?? Date(),
|
||||
// status: testPost.status,
|
||||
// collection: testPost.collection
|
||||
// )
|
||||
// newerRemotePost.hasNewerRemoteCopy = true
|
||||
// return PostEditorStatusToolbarView(post: newerRemotePost)
|
||||
// .environmentObject(model)
|
||||
// .environment(\.horizontalSizeClass, .compact)
|
||||
// }
|
||||
//}
|
||||
//#endif
|
||||
|
@ -2,28 +2,31 @@ import SwiftUI
|
||||
|
||||
struct PostEditorView: View {
|
||||
@EnvironmentObject var model: WriteFreelyModel
|
||||
@Environment(\.managedObjectContext) var moc
|
||||
|
||||
@ObservedObject var post: Post
|
||||
@ObservedObject var post: WFAPost
|
||||
|
||||
@State private var postTitle = ""
|
||||
@State private var postBody = ""
|
||||
|
||||
@State private var isNewPost = false
|
||||
@State private var title = ""
|
||||
var body: some View {
|
||||
VStack {
|
||||
TextEditor(text: $title)
|
||||
TextEditor(text: $postTitle)
|
||||
.font(.title)
|
||||
.frame(height: 100)
|
||||
.onChange(of: title) { _ in
|
||||
if post.status == .published && post.wfPost.title != title {
|
||||
post.status = .edited
|
||||
.onChange(of: postTitle) { _ in
|
||||
if post.status == PostStatus.published.rawValue && post.title != postTitle {
|
||||
post.status = PostStatus.edited.rawValue
|
||||
}
|
||||
post.wfPost.title = title
|
||||
post.title = postTitle
|
||||
}
|
||||
TextEditor(text: $post.wfPost.body)
|
||||
TextEditor(text: $postBody)
|
||||
.font(.body)
|
||||
.onChange(of: post.wfPost.body) { _ in
|
||||
if post.status == .published {
|
||||
post.status = .edited
|
||||
.onChange(of: postBody) { _ in
|
||||
if post.status == PostStatus.published.rawValue {
|
||||
post.status = PostStatus.edited.rawValue
|
||||
}
|
||||
post.body = postBody
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
@ -34,65 +37,51 @@ struct PostEditorView: View {
|
||||
ToolbarItem(placement: .primaryAction) {
|
||||
Button(action: {
|
||||
model.publish(post: post)
|
||||
post.status = .published
|
||||
post.status = PostStatus.published.rawValue
|
||||
}, label: {
|
||||
Image(systemName: "paperplane")
|
||||
})
|
||||
}
|
||||
}
|
||||
.onAppear(perform: {
|
||||
title = post.wfPost.title ?? ""
|
||||
checkIfNewPost()
|
||||
if self.isNewPost {
|
||||
addNewPostToStore()
|
||||
}
|
||||
postTitle = post.title ?? ""
|
||||
postBody = post.body ?? ""
|
||||
})
|
||||
.onDisappear(perform: {
|
||||
if post.status == .edited {
|
||||
if post.status == PostStatus.edited.rawValue {
|
||||
DispatchQueue.main.async {
|
||||
model.store.update(post)
|
||||
PersistenceManager().saveContext()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private func checkIfNewPost() {
|
||||
self.isNewPost = !model.store.posts.contains(where: { $0.id == post.id })
|
||||
}
|
||||
|
||||
private func addNewPostToStore() {
|
||||
withAnimation {
|
||||
model.store.add(post)
|
||||
self.isNewPost = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct PostEditorView_NewLocalDraftPreviews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
PostEditorView(post: Post())
|
||||
.environmentObject(WriteFreelyModel())
|
||||
}
|
||||
}
|
||||
|
||||
struct PostEditorView_NewerLocalPostPreviews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
return PostEditorView(post: testPost)
|
||||
.environmentObject(WriteFreelyModel())
|
||||
}
|
||||
}
|
||||
|
||||
struct PostEditorView_NewerRemotePostPreviews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
let newerRemotePost = Post(
|
||||
title: testPost.wfPost.title ?? "",
|
||||
body: testPost.wfPost.body,
|
||||
createdDate: testPost.wfPost.createdDate ?? Date(),
|
||||
status: testPost.status,
|
||||
collection: testPost.collection
|
||||
)
|
||||
newerRemotePost.hasNewerRemoteCopy = true
|
||||
return PostEditorView(post: newerRemotePost)
|
||||
.environmentObject(WriteFreelyModel())
|
||||
}
|
||||
}
|
||||
//struct PostEditorView_NewLocalDraftPreviews: PreviewProvider {
|
||||
// static var previews: some View {
|
||||
// PostEditorView(post: Post())
|
||||
// .environmentObject(WriteFreelyModel())
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//struct PostEditorView_NewerLocalPostPreviews: PreviewProvider {
|
||||
// static var previews: some View {
|
||||
// return PostEditorView(post: testPost)
|
||||
// .environmentObject(WriteFreelyModel())
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//struct PostEditorView_NewerRemotePostPreviews: PreviewProvider {
|
||||
// static var previews: some View {
|
||||
// let newerRemotePost = Post(
|
||||
// title: testPost.wfPost.title ?? "",
|
||||
// body: testPost.wfPost.body,
|
||||
// createdDate: testPost.wfPost.createdDate ?? Date(),
|
||||
// status: testPost.status,
|
||||
// collection: testPost.collection
|
||||
// )
|
||||
// newerRemotePost.hasNewerRemoteCopy = true
|
||||
// return PostEditorView(post: newerRemotePost)
|
||||
// .environmentObject(WriteFreelyModel())
|
||||
// }
|
||||
//}
|
||||
|
@ -1,15 +1,15 @@
|
||||
import SwiftUI
|
||||
|
||||
struct PostCellView: View {
|
||||
@ObservedObject var post: Post
|
||||
@ObservedObject var post: WFAPost
|
||||
|
||||
var body: some View {
|
||||
HStack {
|
||||
VStack(alignment: .leading) {
|
||||
Text(post.wfPost.title ?? "")
|
||||
Text(post.title ?? "")
|
||||
.font(.headline)
|
||||
.lineLimit(1)
|
||||
Text(buildDateString(from: post.wfPost.createdDate ?? Date()))
|
||||
Text(buildDateString(from: post.createdDate ?? Date()))
|
||||
.font(.caption)
|
||||
.lineLimit(1)
|
||||
}
|
||||
@ -28,13 +28,13 @@ struct PostCellView: View {
|
||||
}
|
||||
}
|
||||
|
||||
struct PostCell_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
let testPost = Post(
|
||||
title: "Test Post Title",
|
||||
body: "Here's some cool sample body text.",
|
||||
createdDate: Date()
|
||||
)
|
||||
return PostCellView(post: testPost)
|
||||
}
|
||||
}
|
||||
//struct PostCell_Previews: PreviewProvider {
|
||||
// static var previews: some View {
|
||||
// let testPost = Post(
|
||||
// title: "Test Post Title",
|
||||
// body: "Here's some cool sample body text.",
|
||||
// createdDate: Date()
|
||||
// )
|
||||
// return PostCellView(post: testPost)
|
||||
// }
|
||||
//}
|
||||
|
@ -2,18 +2,28 @@ import Foundation
|
||||
import WriteFreely
|
||||
import CoreData
|
||||
|
||||
struct PostListModel {
|
||||
var posts: [Post]
|
||||
class PostListModel: ObservableObject {
|
||||
@Published var posts = [WFAPost]()
|
||||
|
||||
init(posts: [Post] = []) {
|
||||
self.posts = posts
|
||||
init() {
|
||||
loadCachedPosts()
|
||||
}
|
||||
|
||||
mutating func add(_ post: Post) {
|
||||
posts.append(post)
|
||||
func loadCachedPosts() {
|
||||
let request = WFAPost.createFetchRequest()
|
||||
let sort = NSSortDescriptor(key: "createdDate", ascending: false)
|
||||
request.sortDescriptors = [sort]
|
||||
|
||||
posts = []
|
||||
do {
|
||||
let cachedPosts = try PersistenceManager.persistentContainer.viewContext.fetch(request)
|
||||
posts.append(contentsOf: cachedPosts)
|
||||
} catch {
|
||||
print("Error: Failed to fetch cached posts.")
|
||||
}
|
||||
}
|
||||
|
||||
mutating func purgeAllPosts() {
|
||||
func purgeAllPosts() {
|
||||
posts = []
|
||||
let fetchRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: "WFAPost")
|
||||
let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)
|
||||
@ -27,51 +37,55 @@ struct PostListModel {
|
||||
}
|
||||
}
|
||||
|
||||
mutating func update(_ post: Post) {
|
||||
// Find the local copy in the store
|
||||
let localCopy = posts.first(where: { $0.id == post.id })
|
||||
// func add(_ post: WFAPost) {
|
||||
// posts.append(post)
|
||||
// }
|
||||
|
||||
// If there's a local copy, update the updatedDate property of its WFPost
|
||||
if let localCopy = localCopy {
|
||||
localCopy.wfPost.updatedDate = Date()
|
||||
} else {
|
||||
print("Error: Local copy not found")
|
||||
}
|
||||
}
|
||||
// func update(_ post: WFAPost) {
|
||||
// // Find the local copy in the store
|
||||
// let localCopy = posts.first(where: { $0.id == post.id })
|
||||
//
|
||||
// // If there's a local copy, update the updatedDate property of its WFPost
|
||||
// if let localCopy = localCopy {
|
||||
// localCopy.wfPost.updatedDate = Date()
|
||||
// } else {
|
||||
// print("Error: Local copy not found")
|
||||
// }
|
||||
// }
|
||||
|
||||
mutating func replace(post: Post, with fetchedPost: WFPost) {
|
||||
// Find the local copy in the store.
|
||||
let localCopy = posts.first(where: { $0.id == post.id })
|
||||
// func replace(post: Post, with fetchedPost: WFPost) {
|
||||
// // Find the local copy in the store.
|
||||
// let localCopy = posts.first(where: { $0.id == post.id })
|
||||
//
|
||||
// // Replace the local copy's wfPost property with the fetched copy.
|
||||
// if let localCopy = localCopy {
|
||||
// localCopy.wfPost = fetchedPost
|
||||
// DispatchQueue.main.async {
|
||||
// localCopy.hasNewerRemoteCopy = false
|
||||
// localCopy.status = .published
|
||||
// }
|
||||
// } else {
|
||||
// print("Error: Local copy not found")
|
||||
// }
|
||||
// }
|
||||
|
||||
// Replace the local copy's wfPost property with the fetched copy.
|
||||
if let localCopy = localCopy {
|
||||
localCopy.wfPost = fetchedPost
|
||||
DispatchQueue.main.async {
|
||||
localCopy.hasNewerRemoteCopy = false
|
||||
localCopy.status = .published
|
||||
}
|
||||
} else {
|
||||
print("Error: Local copy not found")
|
||||
}
|
||||
}
|
||||
|
||||
mutating func updateStore(with fetchedPosts: [Post]) {
|
||||
for fetchedPost in fetchedPosts {
|
||||
// Find the local copy in the store.
|
||||
let localCopy = posts.first(where: { $0.wfPost.postId == fetchedPost.wfPost.postId })
|
||||
|
||||
// If there's a local copy, check which is newer; if not, add the fetched post to the store.
|
||||
if let localCopy = localCopy {
|
||||
// We do not discard the local copy; we simply set the hasNewerRemoteCopy flag accordingly.
|
||||
if let remoteCopyUpdatedDate = fetchedPost.wfPost.updatedDate,
|
||||
let localCopyUpdatedDate = localCopy.wfPost.updatedDate {
|
||||
localCopy.hasNewerRemoteCopy = remoteCopyUpdatedDate > localCopyUpdatedDate
|
||||
} else {
|
||||
print("Error: could not determine which copy of post is newer")
|
||||
}
|
||||
} else {
|
||||
add(fetchedPost)
|
||||
}
|
||||
}
|
||||
}
|
||||
// func updateStore(with fetchedPosts: [Post]) {
|
||||
// for fetchedPost in fetchedPosts {
|
||||
// // Find the local copy in the store.
|
||||
// let localCopy = posts.first(where: { $0.wfPost.postId == fetchedPost.wfPost.postId })
|
||||
//
|
||||
// // If there's a local copy, check which is newer; if not, add the fetched post to the store.
|
||||
// if let localCopy = localCopy {
|
||||
// // We do not discard the local copy; we simply set the hasNewerRemoteCopy flag accordingly.
|
||||
// if let remoteCopyUpdatedDate = fetchedPost.wfPost.updatedDate,
|
||||
// let localCopyUpdatedDate = localCopy.wfPost.updatedDate {
|
||||
// localCopy.hasNewerRemoteCopy = remoteCopyUpdatedDate > localCopyUpdatedDate
|
||||
// } else {
|
||||
// print("Error: could not determine which copy of post is newer")
|
||||
// }
|
||||
// } else {
|
||||
// add(fetchedPost)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
@ -2,6 +2,13 @@ import SwiftUI
|
||||
|
||||
struct PostListView: View {
|
||||
@EnvironmentObject var model: WriteFreelyModel
|
||||
@Environment(\.managedObjectContext) var moc
|
||||
|
||||
@FetchRequest(
|
||||
entity: WFAPost.entity(),
|
||||
sortDescriptors: [NSSortDescriptor(keyPath: \WFAPost.createdDate, ascending: true)]
|
||||
) var posts: FetchedResults<WFAPost>
|
||||
|
||||
@State var selectedCollection: WFACollection?
|
||||
@State var showAllPosts: Bool = false
|
||||
|
||||
@ -14,12 +21,8 @@ struct PostListView: View {
|
||||
GeometryReader { geometry in
|
||||
List {
|
||||
ForEach(showPosts(for: selectedCollection)) { post in
|
||||
NavigationLink(
|
||||
destination: PostEditorView(post: post)
|
||||
) {
|
||||
PostCellView(
|
||||
post: post
|
||||
)
|
||||
NavigationLink(destination: PostEditorView(post: post)) {
|
||||
PostCellView(post: post)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -72,12 +75,8 @@ struct PostListView: View {
|
||||
#else //if os(macOS)
|
||||
List {
|
||||
ForEach(showPosts(for: selectedCollection)) { post in
|
||||
NavigationLink(
|
||||
destination: PostEditorView(post: post)
|
||||
) {
|
||||
PostCellView(
|
||||
post: post
|
||||
)
|
||||
NavigationLink(destination: PostEditorView(post: post)) {
|
||||
PostCellView(post: post)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -103,7 +102,7 @@ struct PostListView: View {
|
||||
#endif
|
||||
}
|
||||
|
||||
private func pluralizedPostCount(for posts: [Post]) -> String {
|
||||
private func pluralizedPostCount(for posts: [WFAPost]) -> String {
|
||||
if posts.count == 1 {
|
||||
return "1 post"
|
||||
} else {
|
||||
@ -111,17 +110,15 @@ struct PostListView: View {
|
||||
}
|
||||
}
|
||||
|
||||
private func showPosts(for collection: WFACollection?) -> [Post] {
|
||||
private func showPosts(for collection: WFACollection?) -> [WFAPost] {
|
||||
if showAllPosts {
|
||||
return model.store.posts
|
||||
} else {
|
||||
var posts: [Post]
|
||||
if let selectedCollection = collection {
|
||||
posts = model.store.posts.filter { $0.wfPost.collectionAlias == selectedCollection.alias }
|
||||
return model.store.posts.filter { $0.collectionAlias == selectedCollection.alias }
|
||||
} else {
|
||||
posts = model.store.posts.filter { $0.wfPost.collectionAlias == nil }
|
||||
return model.store.posts.filter { $0.collectionAlias == nil }
|
||||
}
|
||||
return posts
|
||||
}
|
||||
}
|
||||
|
||||
@ -141,69 +138,69 @@ struct PostListView: View {
|
||||
managedPost.body = post.wfPost.body
|
||||
managedPost.status = PostStatus.local.rawValue
|
||||
DispatchQueue.main.async {
|
||||
model.store.add(post)
|
||||
// model.store.add(post)
|
||||
PersistenceManager().saveContext()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct PostList_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 testPostData = [
|
||||
Post(
|
||||
title: "My First Post",
|
||||
body: "Look at me, creating a first post! That's cool.",
|
||||
createdDate: Date(timeIntervalSince1970: 1595429452),
|
||||
status: .published,
|
||||
collection: userCollection1
|
||||
),
|
||||
Post(
|
||||
title: "Post 2: The Quickening",
|
||||
body: "See, here's the rule about Highlander jokes: _there can be only one_.",
|
||||
createdDate: Date(timeIntervalSince1970: 1595514125),
|
||||
status: .edited,
|
||||
collection: userCollection1
|
||||
),
|
||||
Post(
|
||||
title: "The Post Revolutions",
|
||||
body: "I can never keep the Matrix movie order straight. Why not just call them part 2 and part 3?",
|
||||
createdDate: Date(timeIntervalSince1970: 1595600006)
|
||||
),
|
||||
Post(
|
||||
title: "Episode IV: A New Post",
|
||||
body: "How many movies does this person watch? How many movie-title jokes will they make?",
|
||||
createdDate: Date(timeIntervalSince1970: 1596219877),
|
||||
status: .published,
|
||||
collection: userCollection2
|
||||
),
|
||||
Post(
|
||||
title: "Fast (Post) Five",
|
||||
body: "Look, it was either a Fast and the Furious reference, or a Resident Evil reference."
|
||||
),
|
||||
Post(
|
||||
title: "Post: The Final Chapter",
|
||||
body: "And there you have it, a Resident Evil movie reference.",
|
||||
createdDate: Date(timeIntervalSince1970: 1596043684),
|
||||
status: .edited,
|
||||
collection: userCollection3
|
||||
)
|
||||
]
|
||||
|
||||
let model = WriteFreelyModel()
|
||||
for post in testPostData {
|
||||
model.store.add(post)
|
||||
}
|
||||
return Group {
|
||||
PostListView(selectedCollection: userCollection1)
|
||||
.environmentObject(model)
|
||||
}
|
||||
}
|
||||
}
|
||||
//struct PostList_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 testPostData = [
|
||||
// Post(
|
||||
// title: "My First Post",
|
||||
// body: "Look at me, creating a first post! That's cool.",
|
||||
// createdDate: Date(timeIntervalSince1970: 1595429452),
|
||||
// status: .published,
|
||||
// collection: userCollection1
|
||||
// ),
|
||||
// Post(
|
||||
// title: "Post 2: The Quickening",
|
||||
// body: "See, here's the rule about Highlander jokes: _there can be only one_.",
|
||||
// createdDate: Date(timeIntervalSince1970: 1595514125),
|
||||
// status: .edited,
|
||||
// collection: userCollection1
|
||||
// ),
|
||||
// Post(
|
||||
// title: "The Post Revolutions",
|
||||
// body: "I can never keep the Matrix movie order straight. Why not just call them part 2 and part 3?",
|
||||
// createdDate: Date(timeIntervalSince1970: 1595600006)
|
||||
// ),
|
||||
// Post(
|
||||
// title: "Episode IV: A New Post",
|
||||
// body: "How many movies does this person watch? How many movie-title jokes will they make?",
|
||||
// createdDate: Date(timeIntervalSince1970: 1596219877),
|
||||
// status: .published,
|
||||
// collection: userCollection2
|
||||
// ),
|
||||
// Post(
|
||||
// title: "Fast (Post) Five",
|
||||
// body: "Look, it was either a Fast and the Furious reference, or a Resident Evil reference."
|
||||
// ),
|
||||
// Post(
|
||||
// title: "Post: The Final Chapter",
|
||||
// body: "And there you have it, a Resident Evil movie reference.",
|
||||
// createdDate: Date(timeIntervalSince1970: 1596043684),
|
||||
// status: .edited,
|
||||
// collection: userCollection3
|
||||
// )
|
||||
// ]
|
||||
//
|
||||
// let model = WriteFreelyModel()
|
||||
// for post in testPostData {
|
||||
// model.store.add(post)
|
||||
// }
|
||||
// return Group {
|
||||
// PostListView(selectedCollection: userCollection1)
|
||||
// .environmentObject(model)
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
@ -1,10 +1,10 @@
|
||||
import SwiftUI
|
||||
|
||||
struct PostStatusBadgeView: View {
|
||||
@ObservedObject var post: Post
|
||||
@ObservedObject var post: WFAPost
|
||||
|
||||
var body: some View {
|
||||
let (badgeLabel, badgeColor) = setupBadgeProperties(for: post.status)
|
||||
let (badgeLabel, badgeColor) = setupBadgeProperties(for: PostStatus(rawValue: post.status)!)
|
||||
Text(badgeLabel)
|
||||
.font(.caption)
|
||||
.fontWeight(.semibold)
|
||||
@ -36,68 +36,68 @@ struct PostStatusBadgeView: View {
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
let userCollection1 = WFACollection(context: PersistenceManager.persistentContainer.viewContext)
|
||||
let userCollection2 = WFACollection(context: PersistenceManager.persistentContainer.viewContext)
|
||||
let userCollection3 = WFACollection(context: PersistenceManager.persistentContainer.viewContext)
|
||||
|
||||
let testPostData = [
|
||||
Post(
|
||||
title: "My First Post",
|
||||
body: "Look at me, creating a first post! That's cool.",
|
||||
createdDate: Date(timeIntervalSince1970: 1595429452),
|
||||
status: .published,
|
||||
collection: userCollection1
|
||||
),
|
||||
Post(
|
||||
title: "Post 2: The Quickening",
|
||||
body: "See, here's the rule about Highlander jokes: _there can be only one_.",
|
||||
createdDate: Date(timeIntervalSince1970: 1595514125),
|
||||
status: .edited,
|
||||
collection: userCollection1
|
||||
),
|
||||
Post(
|
||||
title: "The Post Revolutions",
|
||||
body: "I can never keep the Matrix movie order straight. Why not just call them part 2 and part 3?",
|
||||
createdDate: Date(timeIntervalSince1970: 1595600006)
|
||||
),
|
||||
Post(
|
||||
title: "Episode IV: A New Post",
|
||||
body: "How many movies does this person watch? How many movie-title jokes will they make?",
|
||||
createdDate: Date(timeIntervalSince1970: 1596219877),
|
||||
status: .published,
|
||||
collection: userCollection2
|
||||
),
|
||||
Post(
|
||||
title: "Fast (Post) Five",
|
||||
body: "Look, it was either a Fast and the Furious reference, or a Resident Evil reference."
|
||||
),
|
||||
Post(
|
||||
title: "Post: The Final Chapter",
|
||||
body: "And there you have it, a Resident Evil movie reference.",
|
||||
createdDate: Date(timeIntervalSince1970: 1596043684),
|
||||
status: .edited,
|
||||
collection: userCollection3
|
||||
)
|
||||
]
|
||||
#endif
|
||||
|
||||
struct PostStatusBadge_LocalDraftPreviews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
userCollection1.title = "Collection 1"
|
||||
return PostStatusBadgeView(post: testPostData[2])
|
||||
}
|
||||
}
|
||||
|
||||
struct PostStatusBadge_EditedPreviews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
userCollection1.title = "Collection 1"
|
||||
return PostStatusBadgeView(post: testPostData[1])
|
||||
}
|
||||
}
|
||||
|
||||
struct PostStatusBadge_PublishedPreviews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
PostStatusBadgeView(post: testPostData[0])
|
||||
}
|
||||
}
|
||||
//#if DEBUG
|
||||
//let userCollection1 = WFACollection(context: PersistenceManager.persistentContainer.viewContext)
|
||||
//let userCollection2 = WFACollection(context: PersistenceManager.persistentContainer.viewContext)
|
||||
//let userCollection3 = WFACollection(context: PersistenceManager.persistentContainer.viewContext)
|
||||
//
|
||||
//let testPostData = [
|
||||
// Post(
|
||||
// title: "My First Post",
|
||||
// body: "Look at me, creating a first post! That's cool.",
|
||||
// createdDate: Date(timeIntervalSince1970: 1595429452),
|
||||
// status: .published,
|
||||
// collection: userCollection1
|
||||
// ),
|
||||
// Post(
|
||||
// title: "Post 2: The Quickening",
|
||||
// body: "See, here's the rule about Highlander jokes: _there can be only one_.",
|
||||
// createdDate: Date(timeIntervalSince1970: 1595514125),
|
||||
// status: .edited,
|
||||
// collection: userCollection1
|
||||
// ),
|
||||
// Post(
|
||||
// title: "The Post Revolutions",
|
||||
// body: "I can never keep the Matrix movie order straight. Why not just call them part 2 and part 3?",
|
||||
// createdDate: Date(timeIntervalSince1970: 1595600006)
|
||||
// ),
|
||||
// Post(
|
||||
// title: "Episode IV: A New Post",
|
||||
// body: "How many movies does this person watch? How many movie-title jokes will they make?",
|
||||
// createdDate: Date(timeIntervalSince1970: 1596219877),
|
||||
// status: .published,
|
||||
// collection: userCollection2
|
||||
// ),
|
||||
// Post(
|
||||
// title: "Fast (Post) Five",
|
||||
// body: "Look, it was either a Fast and the Furious reference, or a Resident Evil reference."
|
||||
// ),
|
||||
// Post(
|
||||
// title: "Post: The Final Chapter",
|
||||
// body: "And there you have it, a Resident Evil movie reference.",
|
||||
// createdDate: Date(timeIntervalSince1970: 1596043684),
|
||||
// status: .edited,
|
||||
// collection: userCollection3
|
||||
// )
|
||||
//]
|
||||
//#endif
|
||||
//
|
||||
//struct PostStatusBadge_LocalDraftPreviews: PreviewProvider {
|
||||
// static var previews: some View {
|
||||
// userCollection1.title = "Collection 1"
|
||||
// return PostStatusBadgeView(post: testPostData[2])
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//struct PostStatusBadge_EditedPreviews: PreviewProvider {
|
||||
// static var previews: some View {
|
||||
// userCollection1.title = "Collection 1"
|
||||
// return PostStatusBadgeView(post: testPostData[1])
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//struct PostStatusBadge_PublishedPreviews: PreviewProvider {
|
||||
// static var previews: some View {
|
||||
// PostStatusBadgeView(post: testPostData[0])
|
||||
// }
|
||||
//}
|
||||
|
@ -1,3 +1,11 @@
|
||||
//
|
||||
// WFAPost+CoreDataProperties.swift
|
||||
// WriteFreely-MultiPlatform
|
||||
//
|
||||
// Created by Angelo Stavrow on 2020-09-08.
|
||||
//
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreData
|
||||
|
||||
@ -18,6 +26,7 @@ extension WFAPost {
|
||||
@NSManaged public var status: Int32
|
||||
@NSManaged public var title: String?
|
||||
@NSManaged public var updatedDate: Date?
|
||||
@NSManaged public var hasNewerRemoteCopy: Bool
|
||||
|
||||
}
|
||||
|
||||
|
@ -7,12 +7,12 @@
|
||||
<key>WriteFreely-MultiPlatform (iOS).xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>0</integer>
|
||||
<integer>1</integer>
|
||||
</dict>
|
||||
<key>WriteFreely-MultiPlatform (macOS).xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>1</integer>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
|
Loading…
Reference in New Issue
Block a user