Skip to content

Commit

Permalink
Merge branch 'trunk' into task/add-actions-to-post-settings
Browse files Browse the repository at this point in the history
  • Loading branch information
kean authored May 7, 2024
2 parents 0fbecc9 + ee8e09a commit badd1a5
Show file tree
Hide file tree
Showing 22 changed files with 320 additions and 206 deletions.
2 changes: 2 additions & 0 deletions RELEASE-NOTES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
* [*] Make it easier to "Share" and "Blaze" a published post with an updated success view [##23128]
* [*] Add support for viewing trashed posts and pages and restoring them from the editor [#23142]
* [*] Impove the "Post Settings" screen groups/ordering to better align with Gutenberg [#23164]
* [*] Update the "More" menu in the Editor to use modern iOS design and update copy to match Gutenberg [#23145]
* [*] Update the "Revisions" list design and fix an issue with the footer displaying incorrect "Date Created" for drafts [#23145]

24.8
-----
Expand Down
10 changes: 8 additions & 2 deletions WordPress/Classes/Models/AbstractPost+TitleForVisibility.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,15 @@ extension AbstractPost {
static let publicLabel = NSLocalizedString("Public", comment: "Privacy setting for posts set to 'Public' (default). Should be the same as in core WP.")

/// A title describing the status. Ie.: "Public" or "Private" or "Password protected"
///
/// - warning: deprecated (kahu-offline-mode) (use ``PostVisibility``)
@objc var titleForVisibility: String {
guard FeatureFlag.syncPublishing.enabled else {
return _titleForVisibility
}
return PostVisibility(post: self).localizedTitle
}

/// - warning: deprecated (kahu-offline-mode) (use ``PostVisibility``)
@objc private var _titleForVisibility: String {
if password != nil {
return AbstractPost.passwordProtectedLabel
} else if status == .publishPrivate {
Expand Down
24 changes: 15 additions & 9 deletions WordPress/Classes/Services/PostCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,9 @@ class PostCoordinator: NSObject {
retryDelay = min(32, retryDelay * 1.5)
return retryDelay
}
func setLongerDelay() {
retryDelay = max(retryDelay, 20)
}
var retryDelay: TimeInterval
weak var retryTimer: Timer?

Expand Down Expand Up @@ -509,10 +512,11 @@ class PostCoordinator: NSObject {
}

private func startSync(for post: AbstractPost) {
guard let revision = post.getLatestRevisionNeedingSync() else {
let worker = getWorker(for: post)
if let worker = workers[post.objectID], worker.error != nil {
worker.error = nil
postDidUpdateNotification(for: post)
}
guard let revision = post.getLatestRevisionNeedingSync() else {
return DDLogInfo("sync: \(post.objectID.shortDescription) is already up to date")
}
startSync(for: post, revision: revision)
Expand Down Expand Up @@ -610,14 +614,16 @@ class PostCoordinator: NSObject {
worker.error = error
postDidUpdateNotification(for: operation.post)

if !PostCoordinator.isTerminalError(error) {
let delay = worker.nextRetryDelay
worker.retryTimer = Timer.scheduledTimer(withTimeInterval: delay, repeats: false) { [weak self, weak worker] _ in
guard let self, let worker else { return }
self.didRetryTimerFire(for: worker)
}
worker.log("scheduled retry with delay: \(delay)s.")
if PostCoordinator.isTerminalError(error) {
worker.setLongerDelay()
}

let delay = worker.nextRetryDelay
worker.retryTimer = Timer.scheduledTimer(withTimeInterval: delay, repeats: false) { [weak self, weak worker] _ in
guard let self, let worker else { return }
self.didRetryTimerFire(for: worker)
}
worker.log("scheduled retry with delay: \(delay)s.")

if let error = error as? PostRepository.PostSaveError, case .deleted = error {
operation.log("post was permanently deleted")
Expand Down
3 changes: 3 additions & 0 deletions WordPress/Classes/Utility/Analytics/WPAnalyticsEvent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import Foundation
case editorPostSlugChanged
case editorPostExcerptChanged
case editorPostSiteChanged
case editorPostLegacyMoreMenuShown

// Resolve post version conflict
case resolveConflictScreenShown
Expand Down Expand Up @@ -666,6 +667,8 @@ import Foundation
return "editor_post_excerpt_changed"
case .editorPostSiteChanged:
return "editor_post_site_changed"
case .editorPostLegacyMoreMenuShown:
return "editor_post_legacy_more_menu_shown"
case .resolveConflictScreenShown:
return "resolve_conflict_screen_shown"
case .resolveConflictSaveTapped:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1197,7 +1197,7 @@ private extension AztecPostViewController {

if (post.revisions ?? []).count > 0 {
alert.addDefaultActionWithTitle(MoreSheetAlert.historyTitle) { [unowned self] _ in
self.displayHistory()
self.displayRevisionsList()
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@ extension GutenbergViewController {
case managedObjectContextMissing = 2
}

// - warning: deprecated (kahu-offline-mode)
// TODO: Remove when/if confirmed that this is never invoked by Gutenberg.
func displayMoreSheet() {
WPAnalytics.track(.editorPostLegacyMoreMenuShown)

// Dismisses and locks the Notices Store from displaying any new notices.
ActionDispatcher.dispatch(NoticeAction.lock)
let alert = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
Expand Down Expand Up @@ -52,7 +56,7 @@ extension GutenbergViewController {

if (post.revisions ?? []).count > 0 {
alert.addDefaultActionWithTitle(MoreSheetAlert.historyTitle) { [weak self] _ in
self?.displayHistory()
self?.displayRevisionsList()
ActionDispatcher.dispatch(NoticeAction.unlock)
}
}
Expand Down Expand Up @@ -86,11 +90,68 @@ extension GutenbergViewController {

present(alert, animated: true)
}

func makeMoreMenu() -> UIMenu {
UIMenu(title: "", image: nil, identifier: nil, options: [], children: [
UIDeferredMenuElement.uncached { [weak self] in
$0(self?.makeMoreMenuSections() ?? [])
}
])
}

private func makeMoreMenuSections() -> [UIMenuElement] {
var sections: [UIMenuElement] = [
UIMenu(title: "", subtitle: "", options: .displayInline, children: makeMoreMenuActions())
]
if let string = makeContextStructureString() {
sections.append(UIAction(subtitle: string, attributes: [.disabled], handler: { _ in }))
}
return sections
}

private func makeMoreMenuActions() -> [UIAction] {
var actions: [UIAction] = []

let toggleModeTitle = mode == .richText ? Strings.codeEditor : Strings.visualEditor
let toggleModeIconName = mode == .richText ? "curlybraces" : "doc.richtext"
actions.append(UIAction(title: toggleModeTitle, image: UIImage(systemName: toggleModeIconName)) { [weak self] _ in
self?.toggleEditingMode()
})

actions.append(UIAction(title: Strings.preview, image: UIImage(systemName: "safari")) { [weak self] _ in
self?.displayPreview()
})

let revisionCount = (post.revisions ?? []).count
if revisionCount > 0 {
actions.append(UIAction(title: Strings.revisions + " (\(revisionCount))", image: UIImage(systemName: "clock.arrow.circlepath")) { [weak self] _ in
self?.displayRevisionsList()
})
}

let settingsTitle = self.post is Page ? Strings.pageSettings : Strings.postSettings
actions.append(UIAction(title: settingsTitle, image: UIImage(systemName: "gearshape")) { [weak self] _ in
self?.displayPostSettings()
})
let helpTitle = JetpackFeaturesRemovalCoordinator.jetpackFeaturesEnabled() ? Strings.helpAndSupport : Strings.help
actions.append(UIAction(title: helpTitle, image: UIImage(systemName: "questionmark.circle")) { [weak self] _ in
self?.showEditorHelp()
})
return actions
}

private func makeContextStructureString() -> String? {
guard mode == .richText, let contentInfo = contentInfo else {
return nil
}
return String(format: Strings.contentStructure, contentInfo.blockCount, contentInfo.wordCount, contentInfo.characterCount)
}
}

// MARK: - Constants

extension GutenbergViewController {
// - warning: deprecated (kahu-offline-mode)
struct MoreSheetAlert {
static let htmlTitle = NSLocalizedString("Switch to HTML Mode", comment: "Switches the Editor to HTML Mode")
static let richTitle = NSLocalizedString("Switch to Visual Mode", comment: "Switches the Editor to Rich Text Mode")
Expand All @@ -104,3 +165,15 @@ extension GutenbergViewController {
static let editorHelpTitle = NSLocalizedString("Help", comment: "Open editor help options")
}
}

private enum Strings {
static let codeEditor = NSLocalizedString("postEditor.moreMenu.codeEditor", value: "Code Editor", comment: "Post Editor / Button in the 'More' menu")
static let visualEditor = NSLocalizedString("postEditor.moreMenu.visualEditor", value: "Visual Editor", comment: "Post Editor / Button in the 'More' menu")
static let preview = NSLocalizedString("postEditor.moreMenu.preview", value: "Preview", comment: "Post Editor / Button in the 'More' menu")
static let revisions = NSLocalizedString("postEditor.moreMenu.revisions", value: "Revisions", comment: "Post Editor / Button in the 'More' menu")
static let pageSettings = NSLocalizedString("postEditor.moreMenu.pageSettings", value: "Page Settings", comment: "Post Editor / Button in the 'More' menu")
static let postSettings = NSLocalizedString("postEditor.moreMenu.postSettings", value: "Post Settings", comment: "Post Editor / Button in the 'More' menu")
static let helpAndSupport = NSLocalizedString("postEditor.moreMenu.helpAndSupport", value: "Help & Support", comment: "Post Editor / Button in the 'More' menu")
static let help = NSLocalizedString("postEditor.moreMenu.help", value: "Help", comment: "Post Editor / Button in the 'More' menu")
static let contentStructure = NSLocalizedString("postEditor.moreMenu.contentStructure", value: "Blocks: %li, Words: %li, Characters: %li", comment: "Post Editor / 'More' menu details labels with 'Blocks', 'Words' and 'Characters' counts as parameters (in that order)")
}
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,15 @@ class GutenbergViewController: UIViewController, PostEditor, FeaturedImageDelega
borderBottom.frame = CGRect(x: 0, y: navigationController?.navigationBar.frame.size.height ?? 0 - borderWidth, width: navigationController?.navigationBar.frame.size.width ?? 0, height: borderWidth)
borderBottom.autoresizingMask = [.flexibleWidth, .flexibleTopMargin]
navigationController?.navigationBar.addSubview(borderBottom)

if FeatureFlag.syncPublishing.enabled {
navigationBarManager.moreButton.menu = makeMoreMenu()
navigationBarManager.moreButton.showsMenuAsPrimaryAction = true
}
}

@objc private func buttonMoreTapped() {
displayMoreSheet()
}

private func reloadBlogIconView() {
Expand Down

This file was deleted.

67 changes: 0 additions & 67 deletions WordPress/Classes/ViewRelated/Pages/PageListSectionHeaderView.xib

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -758,7 +758,9 @@ class AbstractPostListViewController: UIViewController,
SiteStatsInformation.sharedInstance.oauth2Token = blog.authToken
SiteStatsInformation.sharedInstance.siteID = blog.dotComID

let postURL = URL(string: post.permaLink! as String)
guard let postURL = post.permaLink.flatMap(URL.init) else {
return wpAssertionFailure("permalink missing or invalid")
}
let postStatsTableViewController = PostStatsTableViewController.withJPBannerForBlog(postID: postID,
postTitle: post.titleForDisplay(),
postURL: postURL)
Expand Down
17 changes: 11 additions & 6 deletions WordPress/Classes/ViewRelated/Post/PostCardStatusViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -97,14 +97,10 @@ class PostCardStatusViewModel: NSObject, AbstractPostMenuViewModel {
return .warning
}
switch post.status ?? .draft {
case .pending:
return .success
case .scheduled:
return .primary(.shade40)
case .trash:
return .error
default:
return .neutral(.shade70)
return .secondaryLabel
}
}

Expand Down Expand Up @@ -277,9 +273,18 @@ class PostCardStatusViewModel: NSObject, AbstractPostMenuViewModel {
func statusAndBadges(separatedBy separator: String) -> String {
let sticky = post.isStickyPost ? Constants.stickyLabel : ""
let pending = (post.status == .pending && isSyncPublishingEnabled) ? Constants.pendingReview : ""
let visibility: String = {
let visibility = PostVisibility(post: post)
switch visibility {
case .public:
return ""
case .private, .protected:
return visibility.localizedTitle
}
}()
let status = self.status ?? ""

return [status, pending, sticky].filter { !$0.isEmpty }.joined(separator: separator)
return [status, visibility, pending, sticky].filter { !$0.isEmpty }.joined(separator: separator)
}

/// Determine what the failed status message should be and return it.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ extension PostEditor {
}
}

func displayHistory() {
func displayRevisionsList() {
guard FeatureFlag.syncPublishing.enabled else {
_displayHistory()
return
Expand All @@ -174,7 +174,7 @@ extension PostEditor {
self.post.mt_excerpt = revision.postExcerpt

// It's important to clear the pending uploads associated with the
    // post. The assumption is that if the revision on the remote,
// post. The assumption is that if the revision on the remote,
// its associated media has to be also uploaded.
MediaCoordinator.shared.cancelUploadOfAllMedia(for: self.post)
self.post.media = []
Expand Down
Loading

0 comments on commit badd1a5

Please sign in to comment.