Browse Source

Handle undo of edited posts (#251)

pull/253/head
Angelo Stavrow 9 months ago
committed by GitHub
parent
commit
73d219d0ec
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 68 additions and 12 deletions
  1. +2
    -0
      CHANGELOG.md
  2. +1
    -1
      Shared/Extensions/WriteFreelyModel+APIHandlers.swift
  3. +18
    -0
      Shared/PostEditor/PostEditorModel.swift
  4. +4
    -4
      WriteFreely-MultiPlatform.xcodeproj/project.pbxproj
  5. +11
    -3
      iOS/PostEditor/PostEditorView.swift
  6. +9
    -2
      iOS/PostEditor/PostTextEditingView.swift
  7. +12
    -0
      macOS/Navigation/ActivePostToolbarView.swift
  8. +1
    -0
      macOS/PostEditor/PostEditorView.swift
  9. +10
    -2
      macOS/PostEditor/PostTextEditingView.swift

+ 2
- 0
CHANGELOG.md View File

@@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- [Mac] Added a context-menu item to delete local posts from the post list.
- [Mac] Added methods to fetch device logs.
- [iOS, Mac] Added a way to search for text across all posts.
- [iOS, Mac] Added a way to refresh an edited post from the server copy.

### Changed

@@ -25,6 +26,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- [Mac] Updated the URL and minimum version of the WriteFreely Swift package.
- [Mac] Upgraded the Sparkle package to v2.
- [Mac] The app now prompts you to reach out to our user forums if it detects a crash.
- [iOS, Mac] The app now reverts a post from edited to published status if you undo your changes.

### Fixed



+ 1
- 1
Shared/Extensions/WriteFreelyModel+APIHandlers.swift View File

@@ -244,6 +244,7 @@ extension WriteFreelyModel {
#if os(macOS)
self.selectedPost = cachedPost
#endif
cachedPost.status = PostStatus.published.rawValue
}
} catch {
self.currentError = AppError.genericError(error.localizedDescription)
@@ -280,7 +281,6 @@ extension WriteFreelyModel {
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
}


+ 18
- 0
Shared/PostEditor/PostEditorModel.swift View File

@@ -12,6 +12,9 @@ struct PostEditorModel {
@AppStorage(WFDefaults.selectedCollectionURL, store: UserDefaults.shared) var selectedCollectionURL: URL?
@AppStorage(WFDefaults.lastDraftURL, store: UserDefaults.shared) var lastDraftURL: URL?

private(set) var initialPostTitle: String?
private(set) var initialPostBody: String?

#if os(macOS)
var postToUpdate: WFAPost?
#endif
@@ -58,6 +61,21 @@ struct PostEditorModel {
return collection
}

/// Sets the initial values for title and body on a published post.
///
/// Used to detect if the title and body have changed back to their initial values. If the passed `WFAPost` isn't
/// published, any title and post values already stored are reset to `nil`.
/// - Parameter post: The `WFAPost` for which we're setting initial title/body values.
mutating func setInitialValues(for post: WFAPost) {
if post.status != PostStatus.published.rawValue {
initialPostTitle = nil
initialPostBody = nil
return
}
initialPostTitle = post.title
initialPostBody = post.body
}

private func fetchManagedObject(from objectURL: URL) -> NSManagedObject? {
let coordinator = LocalStorageManager.standard.container.persistentStoreCoordinator
guard let managedObjectID = coordinator.managedObjectID(forURIRepresentation: objectURL) else { return nil }


+ 4
- 4
WriteFreely-MultiPlatform.xcodeproj/project.pbxproj View File

@@ -1063,7 +1063,7 @@
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
CODE_SIGN_ENTITLEMENTS = "ActionExtension-iOS/ActionExtension-iOS.entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 701;
CURRENT_PROJECT_VERSION = 702;
DEVELOPMENT_TEAM = TPPAB4YBA6;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = "ActionExtension-iOS/Info.plist";
@@ -1094,7 +1094,7 @@
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
CODE_SIGN_ENTITLEMENTS = "ActionExtension-iOS/ActionExtension-iOS.entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 701;
CURRENT_PROJECT_VERSION = 702;
DEVELOPMENT_TEAM = TPPAB4YBA6;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = "ActionExtension-iOS/Info.plist";
@@ -1237,7 +1237,7 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = "WriteFreely-MultiPlatform (iOS).entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 701;
CURRENT_PROJECT_VERSION = 702;
DEVELOPMENT_TEAM = TPPAB4YBA6;
ENABLE_PREVIEWS = YES;
INFOPLIST_FILE = iOS/Info.plist;
@@ -1263,7 +1263,7 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = "WriteFreely-MultiPlatform (iOS).entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 701;
CURRENT_PROJECT_VERSION = 702;
DEVELOPMENT_TEAM = TPPAB4YBA6;
ENABLE_PREVIEWS = YES;
INFOPLIST_FILE = iOS/Info.plist;


+ 11
- 3
iOS/PostEditor/PostEditorView.swift View File

@@ -84,7 +84,7 @@ struct PostEditorView: View {
})
.accessibilityHint(Text("Choose the blog you want to publish this post to"))
.disabled(post.body.count == 0)
} else {
} else if post.status == PostStatus.edited.rawValue {
Button(action: {
if model.account.isLoggedIn {
publishPost()
@@ -95,6 +95,14 @@ struct PostEditorView: View {
Label("Publish", systemImage: "paperplane")
})
.disabled(post.status == PostStatus.published.rawValue || post.body.count == 0)

Button(action: {
model.updateFromServer(post: post)
}, label: {
Label("Revert", systemImage: "clock.arrow.circlepath")
})
.accessibilityHint(Text("Replace the edited post with the published version from the server"))
.disabled(post.status != PostStatus.edited.rawValue)
}
Button(action: {
sharePost()
@@ -160,6 +168,7 @@ struct PostEditorView: View {
})
.onAppear(perform: {
self.selectedCollection = collections.first { $0.alias == post.collectionAlias }
model.editor.setInitialValues(for: post)
if post.status != PostStatus.published.rawValue {
DispatchQueue.main.async {
self.model.editor.saveLastDraft(post)
@@ -201,9 +210,8 @@ struct PostEditorView: View {
LocalStorageManager.standard.saveContext()
model.publish(post: post)
}
#if os(iOS)
model.editor.setInitialValues(for: post)
self.hideKeyboard()
#endif
}

private func sharePost() {


+ 9
- 2
iOS/PostEditor/PostTextEditingView.swift View File

@@ -2,6 +2,7 @@ import SwiftUI

struct PostTextEditingView: View {
@Environment(\.horizontalSizeClass) var horizontalSizeClass
@EnvironmentObject var model: WriteFreelyModel
@ObservedObject var post: WFAPost
@Binding var updatingTitleFromServer: Bool
@Binding var updatingBodyFromServer: Bool
@@ -35,13 +36,16 @@ struct PostTextEditingView: View {
)
.accessibilityLabel(Text("Title (optional)"))
.accessibilityHint(Text("Add or edit the title for your post; use the Return key to skip to the body"))
.onChange(of: post.title) { _ in
.onChange(of: post.title) { value in
if post.status == PostStatus.published.rawValue && !updatingTitleFromServer {
post.status = PostStatus.edited.rawValue
}
if updatingTitleFromServer {
updatingTitleFromServer = false
}
if post.status == PostStatus.edited.rawValue && value == model.editor.initialPostTitle {
post.status = PostStatus.published.rawValue
}
}
MultilineTextField(
"Write...",
@@ -51,13 +55,16 @@ struct PostTextEditingView: View {
)
.accessibilityLabel(Text("Body"))
.accessibilityHint(Text("Add or edit the body of your post"))
.onChange(of: post.body) { _ in
.onChange(of: post.body) { value in
if post.status == PostStatus.published.rawValue && !updatingBodyFromServer {
post.status = PostStatus.edited.rawValue
}
if updatingBodyFromServer {
updatingBodyFromServer = false
}
if post.status == PostStatus.edited.rawValue && value == model.editor.initialPostBody {
post.status = PostStatus.published.rawValue
}
}
}
.onChange(of: titleIsFirstResponder, perform: { value in


+ 12
- 0
macOS/Navigation/ActivePostToolbarView.swift View File

@@ -31,6 +31,17 @@ struct ActivePostToolbarView: View {
.frame(minWidth: 50, alignment: .center)
.layoutPriority(1)
.padding(.horizontal)
if activePost.status == PostStatus.edited.rawValue {
Button(action: {
model.editor.postToUpdate = activePost
model.updateFromServer(post: activePost)
model.selectedPost = nil
}, label: {
Image(systemName: "clock.arrow.circlepath")
.accessibilityLabel(Text("Revert post"))
.accessibilityHint(Text("Replace the edited post with the published version from the server"))
})
}
if activePost.status == PostStatus.local.rawValue {
Menu(content: {
Label("Publish To:", systemImage: "paperplane")
@@ -131,6 +142,7 @@ struct ActivePostToolbarView: View {
LocalStorageManager.standard.saveContext()
model.publish(post: post)
}
model.editor.setInitialValues(for: post)
}

private func openSettingsWindow() {


+ 1
- 0
macOS/PostEditor/PostEditorView.swift View File

@@ -16,6 +16,7 @@ struct PostEditorView: View {
.padding()
.background(Color(NSColor.controlBackgroundColor))
.onAppear(perform: {
model.editor.setInitialValues(for: post)
if post.status != PostStatus.published.rawValue {
DispatchQueue.main.async {
self.model.editor.saveLastDraft(post)


+ 10
- 2
macOS/PostEditor/PostTextEditingView.swift View File

@@ -1,6 +1,7 @@
import SwiftUI

struct PostTextEditingView: View {
@EnvironmentObject var model: WriteFreelyModel
@ObservedObject var post: WFAPost
@Binding var updatingFromServer: Bool
@State private var appearance: PostAppearance = .serif
@@ -74,8 +75,15 @@ struct PostTextEditingView: View {
private func onTextChange(_ text: String) {
extractTitle(text)

if post.status == PostStatus.published.rawValue && !updatingFromServer {
post.status = PostStatus.edited.rawValue
if !updatingFromServer {
if post.status == PostStatus.published.rawValue {
post.status = PostStatus.edited.rawValue
}
if post.status == PostStatus.edited.rawValue,
post.title == model.editor.initialPostTitle,
post.body == model.editor.initialPostBody {
post.status = PostStatus.published.rawValue
}
}

if updatingFromServer {


Loading…
Cancel
Save