mirror of
https://github.com/writeas/writefreely-swiftui-multiplatform.git
synced 2024-11-15 01:11:02 +00:00
Load user collections from cache on launch, wipe from database on logout
This commit is contained in:
parent
8e035a43cb
commit
0887638841
@ -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: WFACollection?
|
||||
@Published var hasNewerRemoteCopy: Bool = false
|
||||
|
||||
let id = UUID()
|
||||
@ -20,14 +20,14 @@ class Post: Identifiable, ObservableObject, Hashable {
|
||||
body: String = "Write your post here...",
|
||||
createdDate: Date = Date(),
|
||||
status: PostStatus = .draft,
|
||||
collection: PostCollection? = nil
|
||||
collection: WFACollection? = nil
|
||||
) {
|
||||
self.wfPost = WFPost(body: body, title: title, createdDate: createdDate)
|
||||
self.status = status
|
||||
self.collection = collection
|
||||
}
|
||||
|
||||
convenience init(wfPost: WFPost, in collection: PostCollection? = nil) {
|
||||
convenience init(wfPost: WFPost, in collection: WFACollection? = nil) {
|
||||
self.init(
|
||||
title: wfPost.title ?? "",
|
||||
body: wfPost.body,
|
||||
@ -48,65 +48,3 @@ extension Post {
|
||||
hasher.combine(id)
|
||||
}
|
||||
}
|
||||
|
||||
#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: """
|
||||
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()
|
||||
)
|
||||
|
||||
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
|
||||
|
@ -42,8 +42,9 @@ class WriteFreelyModel: ObservableObject {
|
||||
self.account.login(WFUser(token: token, username: self.account.username))
|
||||
self.client = WFClient(for: serverURL)
|
||||
self.client?.user = self.account.user
|
||||
self.collections.clearUserCollection()
|
||||
self.fetchUserCollections()
|
||||
if self.collections.userCollections.count == 0 {
|
||||
self.fetchUserCollections()
|
||||
}
|
||||
self.fetchUserPosts()
|
||||
}
|
||||
}
|
||||
@ -96,7 +97,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?.alias, completion: publishHandler
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -164,8 +165,8 @@ private extension WriteFreelyModel {
|
||||
try purgeTokenFromKeychain(username: account.user?.username, server: account.server)
|
||||
client = nil
|
||||
DispatchQueue.main.async {
|
||||
self.account.logout()
|
||||
self.collections.clearUserCollection()
|
||||
self.account.logout()
|
||||
self.store.purgeAllPosts()
|
||||
}
|
||||
} catch {
|
||||
@ -186,14 +187,12 @@ private extension WriteFreelyModel {
|
||||
}
|
||||
|
||||
func fetchUserCollectionsHandler(result: Result<[WFCollection], Error>) {
|
||||
DispatchQueue.main.async {
|
||||
self.collections.loadCachedUserCollections()
|
||||
}
|
||||
do {
|
||||
let fetchedCollections = try result.get()
|
||||
var fetchedCollectionsArray: [PostCollection] = []
|
||||
for fetchedCollection in fetchedCollections {
|
||||
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
|
||||
@ -206,7 +205,6 @@ private extension WriteFreelyModel {
|
||||
}
|
||||
}
|
||||
DispatchQueue.main.async {
|
||||
// self.collections = CollectionListModel(with: fetchedCollectionsArray)
|
||||
PersistenceManager().saveContext()
|
||||
}
|
||||
} catch {
|
||||
@ -221,10 +219,10 @@ private extension WriteFreelyModel {
|
||||
for fetchedPost in fetchedPosts {
|
||||
var post: Post
|
||||
if let matchingAlias = fetchedPost.collectionAlias {
|
||||
let postCollection = PostCollection(title: (
|
||||
let matchingCachedCollection = (
|
||||
collections.userCollections.filter { $0.alias == matchingAlias }
|
||||
).first?.title ?? "NO TITLE")
|
||||
post = Post(wfPost: fetchedPost, in: postCollection)
|
||||
).first
|
||||
post = Post(wfPost: fetchedPost, in: matchingCachedCollection)
|
||||
} else {
|
||||
post = Post(wfPost: fetchedPost)
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ struct ContentView: View {
|
||||
NavigationView {
|
||||
SidebarView()
|
||||
|
||||
PostListView(selectedCollection: CollectionListModel.allPostsCollection)
|
||||
PostListView(selectedCollection: nil)
|
||||
|
||||
Text("Select a post, or create a new local draft.")
|
||||
.foregroundColor(.secondary)
|
||||
|
@ -4,22 +4,34 @@ import CoreData
|
||||
class CollectionListModel: ObservableObject {
|
||||
@Published var userCollections = [WFACollection]()
|
||||
|
||||
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 = []
|
||||
// }
|
||||
loadCachedUserCollections()
|
||||
}
|
||||
|
||||
func loadCachedUserCollections() {
|
||||
let request = WFACollection.createFetchRequest()
|
||||
let sort = NSSortDescriptor(key: "title", ascending: true)
|
||||
request.sortDescriptors = [sort]
|
||||
|
||||
userCollections = []
|
||||
do {
|
||||
let cachedCollections = try PersistenceManager.persistentContainer.viewContext.fetch(request)
|
||||
userCollections.append(contentsOf: cachedCollections)
|
||||
} catch {
|
||||
print("Error: Failed to fetch cached user collections.")
|
||||
}
|
||||
}
|
||||
|
||||
func clearUserCollection() {
|
||||
// Make sure the userCollections property is properly populated.
|
||||
// FIXME: Without this, sometimes the userCollections array is empty.
|
||||
loadCachedUserCollections()
|
||||
|
||||
for userCollection in userCollections {
|
||||
PersistenceManager.persistentContainer.viewContext.delete(userCollection)
|
||||
}
|
||||
PersistenceManager().saveContext()
|
||||
|
||||
userCollections = []
|
||||
// Clear collections from CoreData store.
|
||||
}
|
||||
}
|
||||
|
@ -4,20 +4,23 @@ struct CollectionListView: View {
|
||||
@EnvironmentObject var model: WriteFreelyModel
|
||||
@Environment(\.managedObjectContext) var moc
|
||||
|
||||
@FetchRequest(entity: WFACollection.entity(), sortDescriptors: []) var collections: FetchedResults<WFACollection>
|
||||
@FetchRequest(
|
||||
entity: WFACollection.entity(),
|
||||
sortDescriptors: [NSSortDescriptor(keyPath: \WFACollection.title, ascending: true)]
|
||||
) var collections: FetchedResults<WFACollection>
|
||||
|
||||
var body: some View {
|
||||
List {
|
||||
NavigationLink(destination: PostListView(selectedCollection: CollectionListModel.allPostsCollection)) {
|
||||
Text(CollectionListModel.allPostsCollection.title)
|
||||
}
|
||||
NavigationLink(destination: PostListView(selectedCollection: CollectionListModel.draftsCollection)) {
|
||||
Text(CollectionListModel.draftsCollection.title)
|
||||
// NavigationLink(destination: PostListView(selectedCollection: CollectionListModel.allPostsCollection)) {
|
||||
// Text(CollectionListModel.allPostsCollection.title)
|
||||
// }
|
||||
NavigationLink(destination: PostListView(selectedCollection: nil)) {
|
||||
Text(model.account.server == "https://write.as" ? "Anonymous" : "Drafts")
|
||||
}
|
||||
Section(header: Text("Your Blogs")) {
|
||||
ForEach(collections, id: \.alias) { collection in
|
||||
NavigationLink(
|
||||
destination: PostListView(selectedCollection: PostCollection(title: collection.title))
|
||||
destination: PostListView(selectedCollection: collection)
|
||||
) {
|
||||
Text(collection.title)
|
||||
}
|
||||
|
@ -61,6 +61,24 @@ 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()
|
||||
|
@ -30,6 +30,11 @@ struct PostCellView: View {
|
||||
|
||||
struct PostCell_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
PostCellView(post: testPost)
|
||||
let testPost = Post(
|
||||
title: "Test Post Title",
|
||||
body: "Here's some cool sample body text.",
|
||||
createdDate: Date()
|
||||
)
|
||||
return PostCellView(post: testPost)
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ import SwiftUI
|
||||
|
||||
struct PostListView: View {
|
||||
@EnvironmentObject var model: WriteFreelyModel
|
||||
@State var selectedCollection: PostCollection
|
||||
@State var selectedCollection: WFACollection?
|
||||
|
||||
#if os(iOS)
|
||||
@State private var isPresentingSettings = false
|
||||
@ -23,7 +23,9 @@ struct PostListView: View {
|
||||
}
|
||||
}
|
||||
.environmentObject(model)
|
||||
.navigationTitle(selectedCollection.title)
|
||||
.navigationTitle(
|
||||
selectedCollection?.title ?? (model.account.server == "https://write.as" ? "Anonymous" : "Drafts")
|
||||
)
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .primaryAction) {
|
||||
Button(action: {
|
||||
@ -77,7 +79,9 @@ struct PostListView: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
.navigationTitle(selectedCollection.title)
|
||||
.navigationTitle(
|
||||
selectedCollection?.title ?? (model.account.server == "https://write.as" ? "Anonymous" : "Drafts")
|
||||
)
|
||||
.navigationSubtitle(pluralizedPostCount(for: showPosts(for: selectedCollection)))
|
||||
.toolbar {
|
||||
Button(action: {
|
||||
@ -104,15 +108,26 @@ struct PostListView: View {
|
||||
}
|
||||
}
|
||||
|
||||
private func showPosts(for collection: PostCollection) -> [Post] {
|
||||
private func showPosts(for collection: WFACollection?) -> [Post] {
|
||||
var posts: [Post]
|
||||
if collection == CollectionListModel.allPostsCollection {
|
||||
posts = model.store.posts
|
||||
} else if collection == CollectionListModel.draftsCollection {
|
||||
posts = model.store.posts.filter { $0.collection == nil }
|
||||
|
||||
if let selectedCollection = collection {
|
||||
posts = model.store.posts.filter { $0.wfPost.collectionAlias == selectedCollection.alias }
|
||||
} else {
|
||||
posts = model.store.posts.filter { $0.collection?.title == collection.title }
|
||||
posts = model.store.posts.filter { $0.wfPost.collectionAlias == nil }
|
||||
}
|
||||
|
||||
// for post in model.store.posts {
|
||||
// print("Post '\(post.wfPost.title ?? "Untitled")' in \(post.collection?.title ?? "No collection")")
|
||||
// }
|
||||
// if collection == CollectionListModel.allPostsCollection {
|
||||
// posts = model.store.posts
|
||||
// } else if collection == CollectionListModel.draftsCollection {
|
||||
// posts = model.store.posts.filter { $0.collection == nil }
|
||||
// } else {
|
||||
// posts = model.store.posts.filter { $0.collection == collection }
|
||||
// }
|
||||
|
||||
return posts
|
||||
}
|
||||
|
||||
@ -127,12 +142,60 @@ struct PostListView: View {
|
||||
|
||||
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: CollectionListModel.allPostsCollection)
|
||||
PostListView(selectedCollection: userCollection1)
|
||||
.environmentObject(model)
|
||||
}
|
||||
}
|
||||
|
@ -36,17 +36,63 @@ 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"
|
||||
PostStatusBadgeView(post: testPostData[2])
|
||||
}
|
||||
}
|
||||
|
||||
struct PostStatusBadge_EditedPreviews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
Group {
|
||||
PostStatusBadgeView(post: testPostData[1])
|
||||
}
|
||||
userCollection1.title = "Collection 1"
|
||||
return PostStatusBadgeView(post: testPostData[1])
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user