Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge beta 21.9.0.2 #20321

Merged
merged 25 commits into from
Mar 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
839959d
Fix: update blaze status on pull to refresh
Mar 9, 2023
bc82b26
Allow audio upload to premium users after Jetpack features removal
fluiddot Mar 9, 2023
dfd7c01
Update: remove dependency on `RootViewCoordinator` in `JetpackFeature…
hassaanelgarem Mar 10, 2023
9164867
Tests: fix tests build errors
hassaanelgarem Mar 10, 2023
177cbde
Update: always initialize currentAppUIType
hassaanelgarem Mar 10, 2023
82b6e0d
Remove canHandle usage
dvdchr Mar 10, 2023
2ff0a02
Refactor: get blaze status when syncing the blog metadata
Mar 10, 2023
644b458
Fix: whitepace violation
Mar 10, 2023
8bbc0d5
Merge pull request #20291 from wordpress-mobile/gutenberg/fix/enable-…
fluiddot Mar 10, 2023
ee0162d
Merge pull request #20300 from wordpress-mobile/fix/20297-rootviewcoo…
hassaanelgarem Mar 12, 2023
8c65896
Update: set objectID var after creating the comment
hassaanelgarem Mar 12, 2023
e267389
Bump version number
mokagio Mar 13, 2023
8cbd8b3
Fix WP.com post deeplink not opening in app (#20304)
mokagio Mar 13, 2023
e290c13
Fix a crash when replying to a post from a comment (#20308)
mokagio Mar 13, 2023
38afa94
Merge 'origin/release/21.9' into merge/hotfix-21.8.2-into-21.9
mokagio Mar 13, 2023
e87fff7
Merge hotfix 21.8.2 into release 21.9 (#20311)
mokagio Mar 13, 2023
98a29a8
Fix: update isBlazeApproved for all paths
Mar 13, 2023
265f0a9
Fix: show blaze in general section if available
Mar 13, 2023
10e18e7
Refactor: extract blaze row creation
Mar 13, 2023
5fda63a
Merge pull request #20290 from wordpress-mobile/fix/blaze-pull-to-ref…
momo-ozawa Mar 13, 2023
7c27e5a
Merge pull request #20314 from wordpress-mobile/fix/show-blaze-in-gen…
momo-ozawa Mar 13, 2023
86b1f43
Update app translations – `Localizable.strings`
mokagio Mar 14, 2023
c346dc6
Update WordPress metadata translations
mokagio Mar 14, 2023
9cc3aae
Update Jetpack metadata translations
mokagio Mar 14, 2023
05f143c
Bump version number
mokagio Mar 14, 2023
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
48 changes: 26 additions & 22 deletions WordPress/Classes/Services/BlazeService.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Foundation
import WordPressKit

final class BlazeService {
@objc final class BlazeService: NSObject {

private let contextManager: CoreDataStack
private let remote: BlazeServiceRemote
Expand All @@ -18,44 +18,48 @@ final class BlazeService {
self.remote = remote ?? .init(wordPressComRestApi: account.wordPressComRestV2Api)
}

@objc class func createService() -> BlazeService? {
self.init()
}

// MARK: - Methods

/// Fetches and updates blaze status from the server.
/// Fetches a site's blaze status from the server, and updates the blog's isBlazeApproved property.
///
/// - Parameters:
/// - blog: A blog
/// - completion: Closure to be called on success
func updateStatus(for blog: Blog,
completion: (() -> Void)? = nil) {
@objc func getStatus(for blog: Blog,
completion: (() -> Void)? = nil) {

guard BlazeHelper.isBlazeFlagEnabled() else {
updateBlog(blog, isBlazeApproved: false, completion: completion)
return
}

guard let siteId = blog.dotComID?.intValue else {
DDLogError("Invalid site ID for Blaze")
completion?()
updateBlog(blog, isBlazeApproved: false, completion: completion)
return
}

remote.getStatus(forSiteId: siteId) { result in
switch result {
case .success(let approved):

self.contextManager.performAndSave({ context in

guard let blog = Blog.lookup(withObjectID: blog.objectID, in: context) else {
DDLogError("Unable to update isBlazeApproved value for blog")
completion?()
return
}

blog.isBlazeApproved = approved
DDLogInfo("Successfully updated isBlazeApproved value for blog: \(approved)")

}, completion: {
completion?()
}, on: .main)

self.updateBlog(blog, isBlazeApproved: approved, completion: completion)
case .failure(let error):
DDLogError("Unable to fetch isBlazeApproved value from remote: \(error.localizedDescription)")
completion?()
self.updateBlog(blog, isBlazeApproved: false, completion: completion)
}
}
}

private func updateBlog(_ blog: Blog, isBlazeApproved: Bool, completion: (() -> Void)? = nil) {
contextManager.performAndSave({ context in
blog.isBlazeApproved = isBlazeApproved
DDLogInfo("Successfully updated isBlazeApproved value for blog: \(isBlazeApproved)")
}, completion: {
completion?()
}, on: .main)
}
}
6 changes: 6 additions & 0 deletions WordPress/Classes/Services/BlogService.m
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,12 @@ - (void)syncBlogAndAllMetadata:(Blog *)blog completionHandler:(void (^)(void))co
DDLogError(@"Failed to sync Editor settings");
dispatch_group_leave(syncGroup);
}];

BlazeService *blazeService = [BlazeService createService];
dispatch_group_enter(syncGroup);
[blazeService getStatusFor:blog completion:^{
dispatch_group_leave(syncGroup);
}];

// When everything has left the syncGroup (all calls have ended with success
// or failure) perform the completionHandler
Expand Down
1 change: 1 addition & 0 deletions WordPress/Classes/Services/CommentService.m
Original file line number Diff line number Diff line change
Expand Up @@ -1048,6 +1048,7 @@ - (void)createHierarchicalCommentWithContent:(NSString *)content
[self.coreDataStack performAndSaveUsingBlock:^(NSManagedObjectContext *context) {
ReaderPost *post = [context existingObjectWithID:postObjectID error:nil];
Comment *comment = [self createHierarchicalCommentWithContent:content withParent:parentID postID:post.postID siteID:siteID inContext:context];
objectID = comment.objectID;
// This fixes an issue where the comment may not appear for some posts after a successful posting
// More information: https://github.com/wordpress-mobile/WordPress-iOS/issues/13259
comment.post = post;
Expand Down
11 changes: 10 additions & 1 deletion WordPress/Classes/System/RootViewCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,11 @@ class RootViewCoordinator {
// MARK: Private instance variables

private(set) var rootViewPresenter: RootViewPresenter
private(set) var currentAppUIType: AppUIType
private var currentAppUIType: AppUIType {
didSet {
updateJetpackFeaturesRemovalCoordinatorState()
}
}
private var featureFlagStore: RemoteFeatureFlagStore
private var windowManager: WindowManager?

Expand All @@ -53,6 +57,7 @@ class RootViewCoordinator {
let meScenePresenter = MeScenePresenter()
self.rootViewPresenter = MySitesCoordinator(meScenePresenter: meScenePresenter, onBecomeActiveTab: {})
}
updateJetpackFeaturesRemovalCoordinatorState()
updatePromptsIfNeeded()
}

Expand All @@ -69,6 +74,10 @@ class RootViewCoordinator {
}
}

private func updateJetpackFeaturesRemovalCoordinatorState() {
JetpackFeaturesRemovalCoordinator.currentAppUIType = currentAppUIType
}

// MARK: UI Reload

/// Reload the UI if needed after the app has already been launched.
Expand Down
27 changes: 13 additions & 14 deletions WordPress/Classes/System/WordPressAppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -516,20 +516,19 @@ extension WordPressAppDelegate {
return
}

// When a counterpart WordPress/Jetpack app is detected, ensure that the router can handle the URL.
// Passing a URL that the router can't handle results in opening the URL in Safari, which will
// cause the other app to "catch" the intent — and leads to a navigation loop between the two apps.
//
// TODO: Remove this after the Universal Link routes for the WordPress app are removed.
//
// Read more: https://github.com/wordpress-mobile/WordPress-iOS/issues/19755
if MigrationAppDetection.isCounterpartAppInstalled {
// If we can handle the URL, then let the UniversalLinkRouter do it.
guard UniversalLinkRouter.shared.canHandle(url: url) else {
// Otherwise, try to convert the URL to a WP Admin link and open it in Safari.
WPAdminConvertibleRouter.shared.handle(url: url)
return
}
/// If the counterpart WordPress/Jetpack app is installed, and the URL has a wp-admin link equivalent,
/// bounce the wp-admin link to Safari instead.
///
/// Passing a URL that the router couldn't handle results in opening the URL in Safari, which will
/// cause the other app to "catch" the intent — and leads to a navigation loop between the two apps.
///
/// TODO: Remove this after the Universal Link routes for the WordPress app are removed.
///
/// Read more: https://github.com/wordpress-mobile/WordPress-iOS/issues/19755
if MigrationAppDetection.isCounterpartAppInstalled,
WPAdminConvertibleRouter.shared.canHandle(url: url) {
WPAdminConvertibleRouter.shared.handle(url: url)
return
}

trackDeepLink(for: url) { url in
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -873,6 +873,10 @@ - (BlogDetailsSection *)generalSectionViewModel
[weakSelf showActivity];
}]];
}

if ([self shouldShowBlaze]) {
[rows addObject:[self blazeRow]];
}

// Temporarily disabled
// if ([self.blog supports:BlogFeaturePlans] && ![self.blog isWPForTeams]) {
Expand Down Expand Up @@ -946,18 +950,7 @@ - (BlogDetailsSection *)jetpackSectionViewModel
}

if ([self shouldShowBlaze]) {
CGSize iconSize = CGSizeMake(BlogDetailGridiconSize, BlogDetailGridiconSize);
UIImage *blazeIcon = [[UIImage imageNamed:@"icon-blaze"] resizedImage:iconSize interpolationQuality:kCGInterpolationHigh];
BlogDetailsRow *blazeRow = [[BlogDetailsRow alloc] initWithTitle:NSLocalizedString(@"Blaze", @"Noun. Links to a blog's Blaze screen.")
accessibilityIdentifier:@"Blaze Row"
image:[blazeIcon imageFlippedForRightToLeftLayoutDirection]
imageColor:nil
renderingMode:UIImageRenderingModeAlwaysOriginal
callback:^{
[weakSelf showBlaze];
}];
blazeRow.showsSelectionState = NO;
[rows addObject:blazeRow];
[rows addObject:[self blazeRow]];
}
NSString *title = @"";

Expand All @@ -968,6 +961,22 @@ - (BlogDetailsSection *)jetpackSectionViewModel
return [[BlogDetailsSection alloc] initWithTitle:title andRows:rows category:BlogDetailsSectionCategoryJetpack];
}

- (BlogDetailsRow *)blazeRow
{
__weak __typeof(self) weakSelf = self;
CGSize iconSize = CGSizeMake(BlogDetailGridiconSize, BlogDetailGridiconSize);
UIImage *blazeIcon = [[UIImage imageNamed:@"icon-blaze"] resizedImage:iconSize interpolationQuality:kCGInterpolationHigh];
BlogDetailsRow *blazeRow = [[BlogDetailsRow alloc] initWithTitle:NSLocalizedString(@"Blaze", @"Noun. Links to a blog's Blaze screen.")
accessibilityIdentifier:@"Blaze Row"
image:[blazeIcon imageFlippedForRightToLeftLayoutDirection]
imageColor:nil
renderingMode:UIImageRenderingModeAlwaysOriginal
callback:^{
[weakSelf showBlaze];
}];
blazeRow.showsSelectionState = NO;
return blazeRow;
}

- (BlogDetailsSection *)publishTypeSectionViewModel
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,6 @@ class MySiteViewController: UIViewController, NoResultsViewHost {
createFABIfNeeded()
updateSegmentedControl(for: newBlog, switchTabsIfNeeded: true)
fetchPrompt(for: newBlog)
updateBlazeStatus(for: newBlog)
}

get {
Expand Down Expand Up @@ -167,7 +166,6 @@ class MySiteViewController: UIViewController, NoResultsViewHost {
startObservingQuickStart()
startObservingOnboardingPrompt()
subscribeToWillEnterForeground()
subscribeToSiteSettingsUpdated()
}

override func viewWillAppear(_ animated: Bool) {
Expand Down Expand Up @@ -272,15 +270,6 @@ class MySiteViewController: UIViewController, NoResultsViewHost {
NotificationCenter.default.addObserver(self, selector: #selector(handlePostPublished), name: .newPostPublished, object: nil)
}

private func subscribeToSiteSettingsUpdated() {
NotificationCenter.default.addObserver(forName: NSNotification.Name.WPBlogSettingsUpdated, object: nil, queue: nil) { [weak self] _ in
guard let blog = self?.blog else {
return
}
self?.updateBlazeStatus(for: blog)
}
}

private func subscribeToWillEnterForeground() {
NotificationCenter.default.addObserver(self,
selector: #selector(displayOverlayIfNeeded),
Expand Down Expand Up @@ -440,7 +429,6 @@ class MySiteViewController: UIViewController, NoResultsViewHost {
showSitePicker(for: mainBlog)
updateNavigationTitle(for: mainBlog)
updateSegmentedControl(for: mainBlog, switchTabsIfNeeded: true)
updateBlazeStatus(for: mainBlog)
}

@objc
Expand Down Expand Up @@ -470,15 +458,17 @@ class MySiteViewController: UIViewController, NoResultsViewHost {

switch section {
case .siteMenu:

blogDetailsViewController?.pulledToRefresh(with: refreshControl) { [weak self] in
guard let self = self else {
return
}

self.updateNavigationTitle(for: blog)
self.sitePickerViewController?.blogDetailHeaderView.blog = blog
self.updateBlazeStatus(for: blog)
}


case .dashboard:

/// The dashboard’s refresh control is intentionally not tied to blog syncing in order to keep
Expand All @@ -494,7 +484,7 @@ class MySiteViewController: UIViewController, NoResultsViewHost {

self.updateNavigationTitle(for: blog)
self.sitePickerViewController?.blogDetailHeaderView.blog = blog
self.updateBlazeStatus(for: blog)
self.blogDashboardViewController?.reloadCardsLocally()
}
}

Expand Down Expand Up @@ -830,9 +820,9 @@ class MySiteViewController: UIViewController, NoResultsViewHost {
self.switchTab(to: .siteMenu)
}

self.updateBlazeStatus(for: blog)
self.updateNavigationTitle(for: blog)
self.updateSegmentedControl(for: blog)
self.updateChildViewController(for: blog)
self.createFABIfNeeded()
self.fetchPrompt(for: blog)

Expand Down Expand Up @@ -959,20 +949,6 @@ class MySiteViewController: UIViewController, NoResultsViewHost {
self.blog = blog
}

// MARK: - Blaze

private func updateBlazeStatus(for blog: Blog) {
guard BlazeHelper.isBlazeFlagEnabled(),
let blazeService = BlazeService() else {
updateChildViewController(for: blog)
return
}

blazeService.updateStatus(for: blog) { [weak self] in
self?.updateChildViewController(for: blog)
}
}

// MARK: - Blogging Prompts

@objc func handlePostPublished() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1200,7 +1200,7 @@ extension GutenbergViewController: GutenbergBridgeDataSource {
.videoPressBlock: false,
.unsupportedBlockEditor: false,
.canEnableUnsupportedBlockEditor: false,
.isAudioBlockMediaUploadEnabled: false,
.isAudioBlockMediaUploadEnabled: !isFreeWPCom,
.mediaFilesCollectionBlock: false,
.reusableBlock: false,
.shouldUseFastImage: !post.blog.isPrivate(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ class JetpackFeaturesRemovalCoordinator: NSObject {
}
}

static var currentAppUIType: RootViewCoordinator.AppUIType?

static func generalPhase(featureFlagStore: RemoteFeatureFlagStore = RemoteFeatureFlagStore()) -> GeneralPhase {
if AppConfiguration.isJetpack {
return .normal // Always return normal for Jetpack
Expand Down Expand Up @@ -139,34 +141,30 @@ class JetpackFeaturesRemovalCoordinator: NSObject {

/// Used to determine if the Jetpack features are enabled based on the current app UI type.
/// This way we ensure features are not removed before reloading the UI.
/// But if this function is called from a background thread, we determine if the Jetpack Features
/// But if the current app UI type is not set, we determine if the Jetpack Features
/// are enabled based on the removal phase regardless of the app UI state.
/// Default root view coordinator is used.
@objc
static func jetpackFeaturesEnabled() -> Bool {
guard Thread.isMainThread else {
return shouldEnableJetpackFeatures()
}
return jetpackFeaturesEnabled(rootViewCoordinator: .shared)
return jetpackFeaturesEnabled(featureFlagStore: RemoteFeatureFlagStore())
}

/// Used to determine if the Jetpack features are enabled based on the current app UI type.
/// This way we ensure features are not removed before reloading the UI.
/// But if this function is called from a background thread, we determine if the Jetpack Features
/// But if the current app UI type is not set, we determine if the Jetpack Features
/// are enabled based on the removal phase regardless of the app UI state.
/// Using two separate methods (rather than one method with a default argument) because Obj-C.
/// - Returns: `true` if UI type is normal, and `false` if UI type is simplified.
static func jetpackFeaturesEnabled(rootViewCoordinator: RootViewCoordinator) -> Bool {
guard Thread.isMainThread else {
return shouldEnableJetpackFeatures()
static func jetpackFeaturesEnabled(featureFlagStore: RemoteFeatureFlagStore) -> Bool {
guard let currentAppUIType else {
return shouldEnableJetpackFeatures(featureFlagStore: featureFlagStore)
}
return rootViewCoordinator.currentAppUIType == .normal
return currentAppUIType == .normal
}


/// Used to determine if the Jetpack features are enabled based on the removal phase regardless of the app UI state.
private static func shouldEnableJetpackFeatures(featureFlagStore: RemoteFeatureFlagStore = RemoteFeatureFlagStore()) -> Bool {
let phase = generalPhase()
private static func shouldEnableJetpackFeatures(featureFlagStore: RemoteFeatureFlagStore) -> Bool {
let phase = generalPhase(featureFlagStore: featureFlagStore)
switch phase {
case .four, .newUsers, .selfHosted:
return false
Expand Down
Loading