Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
6a35a45
Add empty PublishPostViewController
kean Sep 17, 2025
60fe6f6
Extract PostSettingsFormContentView
kean Sep 17, 2025
3e66947
Show PostSettingsFormContentView
kean Sep 17, 2025
3444865
Add initial header view
kean Sep 17, 2025
82566d0
Add temporary cancel and publish options
kean Sep 17, 2025
b99cca2
Move general section below
kean Sep 17, 2025
d11b2f7
Update PostSettigns to support .publishing context
kean Sep 17, 2025
a00f718
Use primary style
kean Sep 17, 2025
0c394ff
Add publishing section directly to PostSettingsView
kean Sep 17, 2025
91ee556
Improve the publishing sheet design
kean Sep 17, 2025
63fd4c7
Increase SiteIcon corner radius
kean Sep 17, 2025
bd140e8
Add preview button (empty)
kean Sep 17, 2025
3aad454
Add top icons
kean Sep 17, 2025
5158a32
Implement publishing
kean Sep 17, 2025
c33eea5
Add PrepublishingSheetResult support
kean Sep 17, 2025
c77cc82
Make it possible to keep changes to the post
kean Sep 17, 2025
6c05fec
Fix confirmation dialog savings
kean Sep 17, 2025
8957da2
Fix save not showing
kean Sep 17, 2025
1a0e244
Show spinner loading separately
kean Sep 17, 2025
fea38bf
Fix navigation for tags and categories
kean Sep 17, 2025
e26d8c3
Update publish button title dynamically
kean Sep 17, 2025
b48cd96
Remove extra navigation view
kean Sep 17, 2025
ac21b47
Add initial social sharing
kean Sep 21, 2025
957d1bc
Show social section separately
kean Sep 22, 2025
02a9b8f
Implement setup view
kean Sep 22, 2025
21a503f
Add initil support for auto sharing view
kean Sep 22, 2025
bed2444
Rename to PostSocialSharingSettings
kean Sep 22, 2025
35bd98b
Move social sharing settings to PostSettings (struct
kean Sep 22, 2025
ce85c78
Initial integration with sharing settings
kean Sep 22, 2025
df872d4
Implement apply of sharing settings
kean Sep 22, 2025
5f5a0d6
Remove preview post
kean Sep 22, 2025
bca323b
Update based on comments
kean Sep 22, 2025
1bcae82
Extract isPostEligibleForSocialSharing
kean Sep 23, 2025
258f4b8
Fix publish date being non-optional
kean Sep 23, 2025
5eee225
Further simplify publishing
kean Sep 23, 2025
accc2e5
Add PostSettingsPublishDatePicker
kean Sep 23, 2025
bd02f28
Improve header design
kean Sep 23, 2025
c855e06
Add shouldPublishImmediatelly support
kean Sep 23, 2025
ead649d
Move info section
kean Sep 23, 2025
1e79d33
Integrate upload view snackbar
kean Sep 23, 2025
9b1648d
Revert unwanted changes
kean Sep 23, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion Modules/Sources/WordPressUI/Views/SiteIconView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@ public struct SiteIconView: View {

public var body: some View {
contents
.clipShape(RoundedRectangle(cornerRadius: 6))
.clipShape(RoundedRectangle(cornerRadius: cornerRadius))
}

private var cornerRadius: CGFloat {
if #available(iOS 26, *) { 10 } else { 6 }
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A small change to make the corner radius work better with the larger radius on iOS 26.

}

@ViewBuilder
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public class PublicizeInfo: NSManagedObject {
}

/// A value-type representation for Publicize auto-sharing usage.
public struct SharingLimit {
public struct SharingLimit: Hashable {
/// The remaining shares available for use.
public let remaining: Int

Expand Down
37 changes: 37 additions & 0 deletions WordPress/Classes/Services/PostCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,43 @@ class PostCoordinator: NSObject {
}
}

/// Publishes the post according to the current settings and user capabilities.
///
/// - warning: Before publishing, ensure that the media for the post got
/// uploaded. Managing media is not the responsibility of `PostRepository.`
///
/// - parameter changes: The set of changes apply to the post together
/// with the publishing options.
@MainActor
func publish_v2(_ post: AbstractPost, parameters: RemotePostUpdateParameters) async throws {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I plan to remove the previous version in the next PR where the legacy screen is removed.

wpAssert(post.isOriginal())
wpAssert(post.isStatus(in: [.draft, .pending]))

await pauseSyncing(for: post)
defer { resumeSyncing(for: post) }

var parameters = parameters
if parameters.status == nil {
parameters.status = Post.Status.publish.rawValue
}
if parameters.date == nil {
// If the post was previously scheduled for a different date,
// the app has to send a new value to override it.
parameters.date = post.shouldPublishImmediately() ? nil : Date()
}

do {
let repository = PostRepository(coreDataStack: coreDataStack)
try await repository.save(post, changes: parameters)
didPublish(post)
show(PostCoordinator.makeUploadSuccessNotice(for: post))
} catch {
trackError(error, operation: "post-publish", post: post)
handleError(error, for: post)
throw error
}
}

@MainActor
private func didPublish(_ post: AbstractPost) {
if post.status == .scheduled {
Expand Down
4 changes: 4 additions & 0 deletions WordPress/Classes/Utility/BuildInformation/FeatureFlag.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public enum FeatureFlag: Int, CaseIterable {
case pluginManagementOverhaul
case newsletterSubscribers
case newStats
case newPublishingSheet

/// Returns a boolean indicating if the feature is enabled.
///
Expand Down Expand Up @@ -82,6 +83,8 @@ public enum FeatureFlag: Int, CaseIterable {
return true
case .newStats:
return false
case .newPublishingSheet:
return false
}
}

Expand Down Expand Up @@ -125,6 +128,7 @@ extension FeatureFlag {
case .readerGutenbergCommentComposer: "Gutenberg Comment Composer"
case .newsletterSubscribers: "Newsletter Subscribers"
case .newStats: "New Stats"
case .newPublishingSheet: "New Publishing Sheet"
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import WordPressUI

struct JetpackSocialNoConnectionView: View {

private let viewModel: JetpackSocialNoConnectionViewModel
let viewModel: JetpackSocialNoConnectionViewModel

var body: some View {
VStack(alignment: .leading, spacing: 12.0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ struct PostSettings: Hashable {
// MARK: - Post-specific
var postFormat: String?
var isStickyPost = false
var sharing: PostSocialSharingSettings?

// MARK: - Page-specific
var parentPageID: Int?
Expand All @@ -36,7 +37,7 @@ struct PostSettings: Hashable {
excerpt = post.mt_excerpt ?? ""
slug = post.wp_slug ?? ""
status = post.status ?? .draft
publishDate = post.dateCreated
publishDate = post.shouldPublishImmediately() ? nil : post.dateCreated
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

password = post.password

if let authorID = post.authorID?.intValue, authorID > 0 {
Expand All @@ -57,6 +58,7 @@ struct PostSettings: Hashable {
categoryIDs = Set((post.categories ?? []).compactMap {
$0.categoryID?.intValue
})
sharing = PostSocialSharingSettings.make(for: post)
case let page as Page:
parentPageID = page.parentID?.intValue
default:
Expand Down Expand Up @@ -129,6 +131,22 @@ struct PostSettings: Hashable {
if post.isStickyPost != isStickyPost {
post.isStickyPost = isStickyPost
}

if let sharing {
for connection in sharing.services.flatMap(\.connections) {
let keyringID = NSNumber(value: connection.keyringID)
if !post.publicizeConnectionDisabledForKeyringID(keyringID) != connection.enabled {
if connection.enabled {
post.enablePublicizeConnectionWithKeyringID(keyringID)
} else {
post.disablePublicizeConnectionWithKeyringID(keyringID)
}
}
}
if post.publicizeMessage != sharing.message {
post.publicizeMessage = sharing.message
}
}
case let page as Page:
if page.parentID?.intValue != parentPageID {
page.parentID = parentPageID.map { NSNumber(value: $0) }
Expand Down Expand Up @@ -186,3 +204,70 @@ extension PostSettings {
.map { $0.stringByDecodingXMLCharacters() }
}
}

/// A value-type representation of `PublicizeService` for the current blog that's simplified for the auto-sharing flow.
struct PostSocialSharingSettings: Hashable {
var services: [Service]
var message: String
var sharingLimit: PublicizeInfo.SharingLimit?

struct Service: Hashable {
let name: PublicizeService.ServiceName
var connections: [Connection]
}

struct Connection: Hashable {
let account: String
let keyringID: Int
var enabled: Bool
}

static func make(for post: Post) -> PostSocialSharingSettings? {
guard let context = post.managedObjectContext else {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I copied most of the social-sharing code from the existing PrepublishingViewController with minimum changes to the implementation or the architecture. I do not plan to rework it in the scope of this project.

wpAssertionFailure("missing moc")
return nil
}

let connections = post.blog.sortedConnections

// first, build a dictionary to categorize the connections.
var connectionsMap = [PublicizeService.ServiceName: [PublicizeConnection]]()
connections.filter { !$0.requiresUserAction() }.forEach { connection in
let name = PublicizeService.ServiceName(rawValue: connection.service) ?? .unknown
var serviceConnections = connectionsMap[name] ?? []
serviceConnections.append(connection)
connectionsMap[name] = serviceConnections
}

let publicizeServices: [PublicizeService]
do {
publicizeServices = try PublicizeService.allPublicizeServices(in: context)
} catch {
wpAssertionFailure("failed to fetch services", userInfo: ["error": error.localizedDescription])
return nil
}

let services = publicizeServices.compactMap { service -> PostSocialSharingSettings.Service? in
// skip services without connections.
guard let serviceConnections = connectionsMap[service.name],
!serviceConnections.isEmpty else {
return nil
}

return PostSocialSharingSettings.Service(
name: service.name,
connections: serviceConnections.map {
.init(account: $0.externalDisplay,
keyringID: $0.keyringConnectionID.intValue,
enabled: !post.publicizeConnectionDisabledForKeyringID($0.keyringConnectionID))
}
)
}

return PostSocialSharingSettings(
services: services,
message: post.publicizeMessage ?? post.titleForDisplay(),
sharingLimit: post.blog.sharingLimit
)
}
}
Loading