Skip to content

Commit 888de9e

Browse files
Merge pull request #47 from writeas/set-collection-for-post
Set collection for post
2 parents c6f108c + 8afa5fe commit 888de9e

File tree

10 files changed

+71
-32
lines changed

10 files changed

+71
-32
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import CoreData
2+
3+
extension NSManagedObjectContext {
4+
/// Executes the given `NSBatchDeleteRequest` and directly merges the changes to bring the given
5+
/// managed object context up to date.
6+
///
7+
/// Credit: https://www.avanderlee.com/swift/nsbatchdeleterequest-core-data/
8+
///
9+
/// - Parameter batchDeleteRequest: The `NSBatchDeleteRequest` to execute.
10+
/// - Throws: An error if anything went wrong executing the batch deletion.
11+
public func executeAndMergeChanges(using batchDeleteRequest: NSBatchDeleteRequest) throws {
12+
batchDeleteRequest.resultType = .resultTypeObjectIDs
13+
let result = try execute(batchDeleteRequest) as? NSBatchDeleteResult
14+
let changes: [AnyHashable: Any] = [NSDeletedObjectsKey: result?.result as? [NSManagedObjectID] ?? []]
15+
NSManagedObjectContext.mergeChanges(fromRemoteContextSave: changes, into: [self])
16+
}
17+
}

Shared/LocalStorageManager.swift

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,7 @@ class LocalStorageManager {
5050
let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)
5151

5252
do {
53-
try LocalStorageManager.persistentContainer.persistentStoreCoordinator.execute(
54-
deleteRequest, with: LocalStorageManager.persistentContainer.viewContext
55-
)
53+
try LocalStorageManager.persistentContainer.viewContext.executeAndMergeChanges(using: deleteRequest)
5654
} catch {
5755
print("Error: Failed to purge cached collections.")
5856
}

Shared/Models/WriteFreelyModel.swift

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ class WriteFreelyModel: ObservableObject {
1111
@Published var isLoggingIn: Bool = false
1212
@Published var selectedPost: WFAPost?
1313

14+
#if os(iOS)
15+
@Published var isPresentingSettingsView: Bool = false
16+
#endif
17+
1418
private var client: WFClient?
1519
private let defaults = UserDefaults.standard
1620

@@ -112,7 +116,12 @@ extension WriteFreelyModel {
112116
DispatchQueue.main.async {
113117
self.selectedPost = post
114118
}
115-
loggedInClient.getPost(byId: postId, completion: updateFromServerHandler)
119+
if let postCollectionAlias = post.collectionAlias,
120+
let postSlug = post.slug {
121+
loggedInClient.getPost(bySlug: postSlug, from: postCollectionAlias, completion: updateFromServerHandler)
122+
} else {
123+
loggedInClient.getPost(byId: postId, completion: updateFromServerHandler)
124+
}
116125
}
117126
}
118127

@@ -169,8 +178,8 @@ private extension WriteFreelyModel {
169178
try purgeTokenFromKeychain(username: account.user?.username, server: account.server)
170179
client = nil
171180
DispatchQueue.main.async {
172-
LocalStorageManager().purgeUserCollections()
173181
self.account.logout()
182+
LocalStorageManager().purgeUserCollections()
174183
self.posts.purgeAllPosts()
175184
}
176185
} catch {
@@ -280,12 +289,15 @@ private extension WriteFreelyModel {
280289
}
281290

282291
func updateFromServerHandler(result: Result<WFPost, Error>) {
292+
// ⚠️ NOTE:
293+
// The API does not return a collection alias, so we take care not to overwrite the
294+
// cached post's collection alias with the 'nil' value from the fetched post.
295+
// See: https://github.com/writeas/writefreely-swift/issues/20
283296
do {
284297
let fetchedPost = try result.get()
285298
guard let cachedPost = self.selectedPost else { return }
286299
cachedPost.appearance = fetchedPost.appearance
287300
cachedPost.body = fetchedPost.body
288-
cachedPost.collectionAlias = fetchedPost.collectionAlias
289301
cachedPost.createdDate = fetchedPost.createdDate
290302
cachedPost.language = fetchedPost.language
291303
cachedPost.postId = fetchedPost.postId

Shared/Navigation/ContentView.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,18 @@ struct ContentView: View {
1313
.foregroundColor(.secondary)
1414
}
1515
.environmentObject(model)
16+
17+
#if os(iOS)
18+
EmptyView()
19+
.sheet(
20+
isPresented: $model.isPresentingSettingsView,
21+
onDismiss: { model.isPresentingSettingsView = false },
22+
content: {
23+
SettingsView()
24+
.environmentObject(model)
25+
}
26+
)
27+
#endif
1628
}
1729
}
1830

Shared/PostEditor/PostEditorView.swift

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,7 @@ struct PostEditorView: View {
3030
}
3131
ToolbarItem(placement: .primaryAction) {
3232
Button(action: {
33-
model.publish(post: post)
34-
post.status = PostStatus.published.rawValue
33+
publishPost()
3534
}, label: {
3635
Image(systemName: "paperplane")
3736
})
@@ -50,6 +49,14 @@ struct PostEditorView: View {
5049
}
5150
})
5251
}
52+
53+
private func publishPost() {
54+
DispatchQueue.main.async {
55+
LocalStorageManager().saveContext()
56+
model.posts.loadCachedPosts()
57+
model.publish(post: post)
58+
}
59+
}
5360
}
5461

5562
struct PostEditorView_Previews: PreviewProvider {

Shared/PostList/PostListModel.swift

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,7 @@ class PostListModel: ObservableObject {
2828
let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)
2929

3030
do {
31-
try LocalStorageManager.persistentContainer.persistentStoreCoordinator.execute(
32-
deleteRequest, with: LocalStorageManager.persistentContainer.viewContext
33-
)
31+
try LocalStorageManager.persistentContainer.viewContext.executeAndMergeChanges(using: deleteRequest)
3432
} catch {
3533
print("Error: Failed to purge cached posts.")
3634
}

Shared/PostList/PostListView.swift

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,6 @@ struct PostListView: View {
77
@State var selectedCollection: WFACollection?
88
@State var showAllPosts: Bool = false
99

10-
#if os(iOS)
11-
@State private var isPresentingSettings = false
12-
#endif
13-
1410
var body: some View {
1511
#if os(iOS)
1612
GeometryReader { geometry in
@@ -31,18 +27,10 @@ struct PostListView: View {
3127
ToolbarItem(placement: .bottomBar) {
3228
HStack {
3329
Button(action: {
34-
isPresentingSettings = true
30+
model.isPresentingSettingsView = true
3531
}, label: {
3632
Image(systemName: "gear")
37-
}).sheet(
38-
isPresented: $isPresentingSettings,
39-
onDismiss: {
40-
isPresentingSettings = false
41-
},
42-
content: {
43-
SettingsView(isPresented: $isPresentingSettings)
44-
}
45-
)
33+
})
4634
.padding(.leading)
4735
Spacer()
4836
Text(pluralizedPostCount(for: showPosts(for: selectedCollection)))
@@ -117,6 +105,9 @@ struct PostListView: View {
117105
managedPost.title = ""
118106
managedPost.body = ""
119107
managedPost.status = PostStatus.local.rawValue
108+
if let selectedCollectionAlias = selectedCollection?.alias {
109+
managedPost.collectionAlias = selectedCollectionAlias
110+
}
120111
DispatchQueue.main.async {
121112
LocalStorageManager().saveContext()
122113
}

WriteFreely-MultiPlatform.xcodeproj/project.pbxproj

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@
5454
17C42E632507D8E600072984 /* PostStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17C42E612507D8E600072984 /* PostStatus.swift */; };
5555
17C42E652509237800072984 /* PostListFilteredView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17C42E642509237800072984 /* PostListFilteredView.swift */; };
5656
17C42E662509237800072984 /* PostListFilteredView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17C42E642509237800072984 /* PostListFilteredView.swift */; };
57+
17C42E70250AA12300072984 /* NSManagedObjectContext+ExecuteAndMergeChanges.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17C42E6F250AA12200072984 /* NSManagedObjectContext+ExecuteAndMergeChanges.swift */; };
58+
17C42E71250AAFD500072984 /* NSManagedObjectContext+ExecuteAndMergeChanges.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17C42E6F250AA12200072984 /* NSManagedObjectContext+ExecuteAndMergeChanges.swift */; };
5759
17D435E824E3128F0036B539 /* PreferencesModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17D435E724E3128F0036B539 /* PreferencesModel.swift */; };
5860
17D435E924E3128F0036B539 /* PreferencesModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17D435E724E3128F0036B539 /* PreferencesModel.swift */; };
5961
17DF329D24C87D3500BCE2E3 /* Tests_iOS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17DF329C24C87D3500BCE2E3 /* Tests_iOS.swift */; };
@@ -114,6 +116,7 @@
114116
17B996D72502D23E0017B536 /* WFAPost+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WFAPost+CoreDataProperties.swift"; sourceTree = SOURCE_ROOT; };
115117
17C42E612507D8E600072984 /* PostStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostStatus.swift; sourceTree = "<group>"; };
116118
17C42E642509237800072984 /* PostListFilteredView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostListFilteredView.swift; sourceTree = "<group>"; };
119+
17C42E6F250AA12200072984 /* NSManagedObjectContext+ExecuteAndMergeChanges.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSManagedObjectContext+ExecuteAndMergeChanges.swift"; sourceTree = "<group>"; };
117120
17D435E724E3128F0036B539 /* PreferencesModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesModel.swift; sourceTree = "<group>"; };
118121
17DF328124C87D3300BCE2E3 /* WriteFreely_MultiPlatformApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WriteFreely_MultiPlatformApp.swift; sourceTree = "<group>"; };
119122
17DF328224C87D3300BCE2E3 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
@@ -193,6 +196,7 @@
193196
isa = PBXGroup;
194197
children = (
195198
1756AE8024CB844500FD7257 /* View+Keyboard.swift */,
199+
17C42E6F250AA12200072984 /* NSManagedObjectContext+ExecuteAndMergeChanges.swift */,
196200
);
197201
path = Extensions;
198202
sourceTree = "<group>";
@@ -591,6 +595,7 @@
591595
17120DA324E19A42002B9F6C /* PreferencesView.swift in Sources */,
592596
1756AE6E24CB255B00FD7257 /* PostListModel.swift in Sources */,
593597
174D313224EC2831006CA9EE /* WriteFreelyModel.swift in Sources */,
598+
17C42E70250AA12300072984 /* NSManagedObjectContext+ExecuteAndMergeChanges.swift in Sources */,
594599
17120DA124E19839002B9F6C /* AccountView.swift in Sources */,
595600
1756AE7424CB26FA00FD7257 /* PostCellView.swift in Sources */,
596601
);
@@ -610,6 +615,7 @@
610615
17DF32D624C8CA3400BCE2E3 /* PostStatusBadgeView.swift in Sources */,
611616
17C42E662509237800072984 /* PostListFilteredView.swift in Sources */,
612617
17120DAD24E1B99F002B9F6C /* AccountLoginView.swift in Sources */,
618+
17C42E71250AAFD500072984 /* NSManagedObjectContext+ExecuteAndMergeChanges.swift in Sources */,
613619
1756AE7B24CB65DF00FD7257 /* PostListView.swift in Sources */,
614620
1753F6AC24E431CC00309365 /* MacPreferencesView.swift in Sources */,
615621
1756DC0424FEE18400207AB8 /* WFACollection+CoreDataProperties.swift in Sources */,

iOS/Settings/SettingsHeaderView.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import SwiftUI
22

33
struct SettingsHeaderView: View {
4-
@Binding var isPresented: Bool
4+
@Environment(\.presentationMode) var presentationMode
55

66
var body: some View {
77
HStack {
@@ -10,7 +10,7 @@ struct SettingsHeaderView: View {
1010
.fontWeight(.bold)
1111
Spacer()
1212
Button(action: {
13-
isPresented = false
13+
presentationMode.wrappedValue.dismiss()
1414
}, label: {
1515
Image(systemName: "xmark.circle")
1616
})
@@ -21,6 +21,6 @@ struct SettingsHeaderView: View {
2121

2222
struct SettingsHeaderView_Previews: PreviewProvider {
2323
static var previews: some View {
24-
SettingsHeaderView(isPresented: .constant(true))
24+
SettingsHeaderView()
2525
}
2626
}

iOS/Settings/SettingsView.swift

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,9 @@ import SwiftUI
33
struct SettingsView: View {
44
@EnvironmentObject var model: WriteFreelyModel
55

6-
@Binding var isPresented: Bool
7-
86
var body: some View {
97
VStack {
10-
SettingsHeaderView(isPresented: $isPresented)
8+
SettingsHeaderView()
119
Form {
1210
Section(header: Text("Login Details")) {
1311
AccountView()
@@ -23,7 +21,7 @@ struct SettingsView: View {
2321

2422
struct SettingsView_Previews: PreviewProvider {
2523
static var previews: some View {
26-
SettingsView(isPresented: .constant(true))
24+
SettingsView()
2725
.environmentObject(WriteFreelyModel())
2826
}
2927
}

0 commit comments

Comments
 (0)