diff --git a/WordPress/Classes/Categories/NSMutableArray+NullableObjects.h b/WordPress/Classes/Categories/NSMutableArray+NullableObjects.h deleted file mode 100644 index 4541021d079a..000000000000 --- a/WordPress/Classes/Categories/NSMutableArray+NullableObjects.h +++ /dev/null @@ -1,7 +0,0 @@ -#import - -@interface NSMutableArray (NullableObjects) - -- (void)addNullableObject:(nullable ObjectType)anObject; - -@end diff --git a/WordPress/Classes/Categories/NSMutableArray+NullableObjects.m b/WordPress/Classes/Categories/NSMutableArray+NullableObjects.m deleted file mode 100644 index cc946714e9a9..000000000000 --- a/WordPress/Classes/Categories/NSMutableArray+NullableObjects.m +++ /dev/null @@ -1,11 +0,0 @@ -#import "NSMutableArray+NullableObjects.h" - -@implementation NSMutableArray (NullableObjects) - -- (void)addNullableObject:(nullable id)anObject { - if (anObject != nil) { - [self addObject:anObject]; - } -} - -@end diff --git a/WordPress/Classes/Extensions/Colors and Styles/WPStyleGuide+ApplicationStyles.swift b/WordPress/Classes/Extensions/Colors and Styles/WPStyleGuide+ApplicationStyles.swift index 1b5b6159a574..48089988fffe 100644 --- a/WordPress/Classes/Extensions/Colors and Styles/WPStyleGuide+ApplicationStyles.swift +++ b/WordPress/Classes/Extensions/Colors and Styles/WPStyleGuide+ApplicationStyles.swift @@ -64,7 +64,7 @@ extension WPStyleGuide { viewController.navigationItem.compactScrollEdgeAppearance = standardAppearance } - @objc class func configureTabBar(_ tabBar: UITabBar) { + @objc public class func configureTabBar(_ tabBar: UITabBar) { tabBar.tintColor = UIAppColor.tint tabBar.unselectedItemTintColor = UIColor(named: "TabUnselected") } diff --git a/WordPress/Classes/Extensions/Comment+Interface.swift b/WordPress/Classes/Extensions/Comment+Interface.swift index 094df3675a78..3420d236a9d1 100644 --- a/WordPress/Classes/Extensions/Comment+Interface.swift +++ b/WordPress/Classes/Extensions/Comment+Interface.swift @@ -11,7 +11,7 @@ extension Comment { /// readable, and you should use the *descriptionForSectionIdentifier* method /// as well! /// - @objc func relativeDateSectionIdentifier() -> String? { + @objc public func relativeDateSectionIdentifier() -> String? { guard let dateCreated else { return nil } @@ -46,7 +46,7 @@ extension Comment { /// Translates a relative date section identifier into a human-readable string. /// - @objc static func descriptionForSectionIdentifier(_ identifier: String) -> String { + @objc public static func descriptionForSectionIdentifier(_ identifier: String) -> String { guard let section = Sections(rawValue: identifier) else { return String() } diff --git a/WordPress/Classes/Extensions/NSFetchedResultsController+Helpers.swift b/WordPress/Classes/Extensions/NSFetchedResultsController+Helpers.swift index 2eea7d8ff3b5..eee36cd8f806 100644 --- a/WordPress/Classes/Extensions/NSFetchedResultsController+Helpers.swift +++ b/WordPress/Classes/Extensions/NSFetchedResultsController+Helpers.swift @@ -4,7 +4,7 @@ import CoreData extension NSFetchedResultsController { /// Returns whether an indexPath represents the last row in it's section, or not /// - @objc func isLastIndexPathInSection(_ indexPath: IndexPath) -> Bool { + @objc public func isLastIndexPathInSection(_ indexPath: IndexPath) -> Bool { guard let sections else { return false } @@ -19,7 +19,7 @@ extension NSFetchedResultsController { /// Returns the NSManagedObject at the specified indexPath, if the Row + Section are still valid. /// Otherwise, null will be returned. /// - @objc func managedObject(atUnsafe indexPath: IndexPath) -> NSManagedObject? { + @objc public func managedObject(atUnsafe indexPath: IndexPath) -> NSManagedObject? { guard let sections else { return nil } @@ -37,7 +37,7 @@ extension NSFetchedResultsController { /// Returns whether an NSFetchedResultsController is empty /// - @objc func isEmpty() -> Bool { + @objc public func isEmpty() -> Bool { // We can not return fetchedObjects.count == 0 because of a Swift compiler error: // Extension of a generic Objective-C class cannot access the class's generic parameters at runtime return sections?.first(where: { $0.numberOfObjects > 0 }) == nil diff --git a/WordPress/Classes/Extensions/Notifications/Notification+Interface.swift b/WordPress/Classes/Extensions/Notifications/Notification+Interface.swift index 6eb24595fd2b..8aa561b57a71 100644 --- a/WordPress/Classes/Extensions/Notifications/Notification+Interface.swift +++ b/WordPress/Classes/Extensions/Notifications/Notification+Interface.swift @@ -6,7 +6,7 @@ extension Notification { /// Returns a Section Identifier that can be sorted. Note that this string is not human readable, and /// you should use the *descriptionForSectionIdentifier* method as well!. /// - @objc func sectionIdentifier() -> String { + @objc public func sectionIdentifier() -> String { // Normalize Dates: Time must not be considered. Just the raw dates let fromDate = timestampAsDate.normalizedDate() let toDate = Date().normalizedDate() @@ -37,7 +37,7 @@ extension Notification { /// Translates a Section Identifier into a Human-Readable String. /// - @objc class func descriptionForSectionIdentifier(_ identifier: String) -> String { + @objc public class func descriptionForSectionIdentifier(_ identifier: String) -> String { guard let section = Sections(rawValue: identifier) else { return String() } diff --git a/WordPress/Classes/Extensions/UIBarButtonItem+Extensions.swift b/WordPress/Classes/Extensions/UIBarButtonItem+Extensions.swift index 2c9ce55ec8d6..f6a0bb7db0fe 100644 --- a/WordPress/Classes/Extensions/UIBarButtonItem+Extensions.swift +++ b/WordPress/Classes/Extensions/UIBarButtonItem+Extensions.swift @@ -2,7 +2,7 @@ import UIKit extension UIBarButtonItem { /// Returns a bar button item with a spinner activity indicator. - @objc class var activityIndicator: UIBarButtonItem { + @objc public class var activityIndicator: UIBarButtonItem { let activityIndicator = UIActivityIndicatorView(style: .medium) activityIndicator.sizeToFit() activityIndicator.startAnimating() diff --git a/WordPress/Classes/Extensions/UINavigationController+Helpers.swift b/WordPress/Classes/Extensions/UINavigationController+Helpers.swift index bbb1b44fb2c7..93a85f060533 100644 --- a/WordPress/Classes/Extensions/UINavigationController+Helpers.swift +++ b/WordPress/Classes/Extensions/UINavigationController+Helpers.swift @@ -1,7 +1,7 @@ import UIKit extension UINavigationController { - @objc func scrollContentToTopAnimated(_ animated: Bool) { + @objc public func scrollContentToTopAnimated(_ animated: Bool) { guard viewControllers.count == 1 else { return } if let topViewController = topViewController as? ScrollableViewController { diff --git a/WordPress/Classes/Jetpack/JetpackMigration/SuccessCard/TableView/MigrationSuccessCell.swift b/WordPress/Classes/Jetpack/JetpackMigration/SuccessCard/TableView/MigrationSuccessCell.swift index df4fe2454708..63999bae6d16 100644 --- a/WordPress/Classes/Jetpack/JetpackMigration/SuccessCard/TableView/MigrationSuccessCell.swift +++ b/WordPress/Classes/Jetpack/JetpackMigration/SuccessCard/TableView/MigrationSuccessCell.swift @@ -1,17 +1,17 @@ import UIKit @objc -class MigrationSuccessCell: UITableViewCell { +public class MigrationSuccessCell: UITableViewCell { var onTap: (() -> Void)? var cardView: MigrationSuccessCardView? - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) setup() } - required init?(coder: NSCoder) { + public required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -25,12 +25,12 @@ class MigrationSuccessCell: UITableViewCell { cardView = view } - @objc func configureForSidebarMode() { + @objc public func configureForSidebarMode() { cardView?.backgroundColor = .clear } @objc(configureWithViewController:) - func configure(with viewController: UIViewController) { + public func configure(with viewController: UIViewController) { self.onTap = { [weak viewController] in guard let viewController else { return @@ -40,17 +40,3 @@ class MigrationSuccessCell: UITableViewCell { } } } - -extension BlogDetailsViewController { - - @objc func migrationSuccessSectionViewModel() -> BlogDetailsSection { - let row = BlogDetailsRow() - row.callback = {} - - let section = BlogDetailsSection(title: nil, - rows: [row], - footerTitle: nil, - category: .migrationSuccess) - return section - } -} diff --git a/WordPress/Classes/Models/Blog/Blog+Editor.swift b/WordPress/Classes/Models/Blog/Blog+Editor.swift index 8dc1481e8d0a..26ed1ebe3a94 100644 --- a/WordPress/Classes/Models/Blog/Blog+Editor.swift +++ b/WordPress/Classes/Models/Blog/Blog+Editor.swift @@ -42,7 +42,7 @@ extension Blog { return mobileEditor ?? GutenbergSettings().getDefaultEditor(for: self) } - @objc var isGutenbergEnabled: Bool { + @objc public var isGutenbergEnabled: Bool { return editor == .gutenberg } } diff --git a/WordPress/Classes/Models/PublicizeService+Lookup.swift b/WordPress/Classes/Models/PublicizeService+Lookup.swift index 59f09b3de4a0..0f6a47799bf5 100644 --- a/WordPress/Classes/Models/PublicizeService+Lookup.swift +++ b/WordPress/Classes/Models/PublicizeService+Lookup.swift @@ -12,7 +12,7 @@ extension PublicizeService { } @objc(lookupPublicizeServiceNamed:inContext:) - static func objc_lookupPublicizeServiceNamed(_ name: String, in context: NSManagedObjectContext) -> PublicizeService? { + public static func objc_lookupPublicizeServiceNamed(_ name: String, in context: NSManagedObjectContext) -> PublicizeService? { try? lookupPublicizeServiceNamed(name, in: context) } @@ -21,7 +21,7 @@ extension PublicizeService { /// - Returns: An array of `PublicizeService`. The array is empty if no objects are cached. /// @objc(allPublicizeServicesInContext:error:) - static func allPublicizeServices(in context: NSManagedObjectContext) throws -> [PublicizeService] { + public static func allPublicizeServices(in context: NSManagedObjectContext) throws -> [PublicizeService] { let request = NSFetchRequest(entityName: PublicizeService.classNameWithoutNamespaces()) let sortDescriptor = NSSortDescriptor(key: "order", ascending: true) request.sortDescriptors = [sortDescriptor] diff --git a/WordPress/Classes/Services/AccountService+Swift.swift b/WordPress/Classes/Services/AccountService+Swift.swift index f0a0dba44eb8..4b1e5cd0f364 100644 --- a/WordPress/Classes/Services/AccountService+Swift.swift +++ b/WordPress/Classes/Services/AccountService+Swift.swift @@ -13,7 +13,7 @@ extension AccountService { } } - @objc func setupAppExtensions(defaultAccount: WPAccount) { + @objc public func setupAppExtensions(defaultAccount: WPAccount) { let shareExtensionService = ShareExtensionService() let notificationSupportService = NotificationSupportService() diff --git a/WordPress/Classes/Services/BlogService+Domains.swift b/WordPress/Classes/Services/BlogService+Domains.swift index 06326fc3fe4c..ca1271494b21 100644 --- a/WordPress/Classes/Services/BlogService+Domains.swift +++ b/WordPress/Classes/Services/BlogService+Domains.swift @@ -12,7 +12,7 @@ extension BlogService { /// Convenience method to be able to refresh the blogs from ObjC. /// @objc - func refreshDomains(for blog: Blog, success: (() -> Void)?, failure: ((Error) -> Void)?) { + public func refreshDomains(for blog: Blog, success: (() -> Void)?, failure: ((Error) -> Void)?) { guard let account = blog.account else { failure?(BlogServiceDomainError.noAccountForSpecifiedBlog(blog: blog)) return diff --git a/WordPress/Classes/Stores/StatsWidgetsStore.swift b/WordPress/Classes/Stores/StatsWidgetsStore.swift index 4dfd77c361f0..2c1c17d0cf9e 100644 --- a/WordPress/Classes/Stores/StatsWidgetsStore.swift +++ b/WordPress/Classes/Stores/StatsWidgetsStore.swift @@ -416,7 +416,7 @@ private extension StatsWidgetsStore { } extension StatsViewController { - @objc func initializeStatsWidgetsIfNeeded() { + @objc public func initializeStatsWidgetsIfNeeded() { StoreContainer.shared.statsWidgets.initializeStatsWidgetsIfNeeded() } } diff --git a/WordPress/Classes/System/Root View/ReaderPresenter.swift b/WordPress/Classes/System/Root View/ReaderPresenter.swift index c22503e788cb..32c1e22aadd1 100644 --- a/WordPress/Classes/System/Root View/ReaderPresenter.swift +++ b/WordPress/Classes/System/Root View/ReaderPresenter.swift @@ -6,7 +6,7 @@ import WordPressData import WordPressUI /// Manages top-level Reader navigation. -final class ReaderPresenter: NSObject, SplitViewDisplayable { +public final class ReaderPresenter: NSObject, SplitViewDisplayable { private let sidebarViewModel = ReaderSidebarViewModel() // The view controllers used during split view presentation. @@ -23,7 +23,7 @@ final class ReaderPresenter: NSObject, SplitViewDisplayable { private var selectionObserver: AnyCancellable? - override init() { + public override init() { secondary = UINavigationController() sidebar = ReaderSidebarViewController(viewModel: sidebarViewModel) sidebar.navigationItem.largeTitleDisplayMode = .automatic @@ -36,7 +36,7 @@ final class ReaderPresenter: NSObject, SplitViewDisplayable { } // TODO: (reader) update to allow seamless transitions between split view and tabs - @objc func prepareForTabBarPresentation() -> UINavigationController { + @objc public func prepareForTabBarPresentation() -> UINavigationController { guard AccountHelper.isDotcomAvailable() else { return UINavigationController(rootViewController: ReaderLoggedOutViewController()) } diff --git a/WordPress/Classes/Utility/AccountHelper.swift b/WordPress/Classes/Utility/AccountHelper.swift index 33171101a859..809c6b2ab849 100644 --- a/WordPress/Classes/Utility/AccountHelper.swift +++ b/WordPress/Classes/Utility/AccountHelper.swift @@ -90,7 +90,7 @@ import Foundation deleteAccountData() } - @objc static func deleteAccountData() { + static func deleteAccountData() { // Delete saved dashboard states BlogDashboardState.resetAllStates() diff --git a/WordPress/Classes/Utility/Analytics/WPAppAnalytics.m b/WordPress/Classes/Utility/Analytics/WPAppAnalytics.m index e9b571516838..20e9be24220c 100644 --- a/WordPress/Classes/Utility/Analytics/WPAppAnalytics.m +++ b/WordPress/Classes/Utility/Analytics/WPAppAnalytics.m @@ -1,3 +1,4 @@ +@import WordPressShared; @import NSObject_SafeExpectations; #import "WPAppAnalytics.h" diff --git a/WordPress/Classes/Utility/App Configuration/AppConfiguration.swift b/WordPress/Classes/Utility/App Configuration/AppConfiguration.swift index a6876347e5a7..bdb8b1f35026 100644 --- a/WordPress/Classes/Utility/App Configuration/AppConfiguration.swift +++ b/WordPress/Classes/Utility/App Configuration/AppConfiguration.swift @@ -2,12 +2,12 @@ import Foundation import BuildSettingsKit /// - warning: Soft-deprecated. Use `BuildSettings` directly. -@objc class AppConfiguration: NSObject { - @objc static var isJetpack: Bool { +struct AppConfiguration { + static var isJetpack: Bool { BuildSettings.current.brand == .jetpack } - @objc static var isWordPress: Bool { + static var isWordPress: Bool { BuildSettings.current.brand == .wordpress } } diff --git a/WordPress/Classes/Utility/Editor/GutenbergSettings.swift b/WordPress/Classes/Utility/Editor/GutenbergSettings.swift index e4fad5eb2530..5a0b35ff812e 100644 --- a/WordPress/Classes/Utility/Editor/GutenbergSettings.swift +++ b/WordPress/Classes/Utility/Editor/GutenbergSettings.swift @@ -215,19 +215,19 @@ class GutenbergSettings { } @objc(GutenbergSettings) -class GutenbergSettingsBridge: NSObject { +public class GutenbergSettingsBridge: NSObject { @objc(setGutenbergEnabled:forBlog:) - static func setGutenbergEnabled(_ isEnabled: Bool, for blog: Blog) { + public static func setGutenbergEnabled(_ isEnabled: Bool, for blog: Blog) { GutenbergSettings().setGutenbergEnabled(isEnabled, for: blog, source: .viaSiteSettings) } @objc(postSettingsToRemoteForBlog:) - static func postSettingsToRemote(for blog: Blog) { + public static func postSettingsToRemote(for blog: Blog) { GutenbergSettings().postSettingsToRemote(for: blog) } @objc(isSimpleWPComSite:) - static func isSimpleWPComSite(_ blog: Blog) -> Bool { + public static func isSimpleWPComSite(_ blog: Blog) -> Bool { return GutenbergSettings().isSimpleWPComSite(blog) } } diff --git a/WordPress/Classes/Utility/In-App Feedback/AppRatingsUtility.swift b/WordPress/Classes/Utility/In-App Feedback/AppRatingsUtility.swift index a33edc01e87d..8093b217fe9c 100644 --- a/WordPress/Classes/Utility/In-App Feedback/AppRatingsUtility.swift +++ b/WordPress/Classes/Utility/In-App Feedback/AppRatingsUtility.swift @@ -5,24 +5,24 @@ import BuildSettingsKit /// app review. This class is loosely based on /// [Appirater](https://github.com/arashpayan/appirater) /// -class AppRatingUtility: NSObject { +class AppRatingUtility { /// Sets the number of system wide significant events are required when /// calling `shouldPromptForAppReview`. Ideally this number should be a /// number less than the total of all the significant event counts for each /// section so as to trigger the review prompt for a fairly active user who /// uses the app in a broad fashion. /// - @objc var systemWideSignificantEventCountRequiredForPrompt: Int = 1 + var systemWideSignificantEventCountRequiredForPrompt: Int = 1 /// The App Review URL that we send off to UIApplication to open up the app /// store review page. /// - @objc var appReviewUrl: URL { Constants.defaultAppReviewURL } + var appReviewUrl: URL { Constants.defaultAppReviewURL } /// Sets the number of days that have to pass between AppReview prompts /// Apple only allows 3 prompts per year. We're trying to be a bit more conservative and are doing /// up to 2 times a year (183 = round(365/2)). - @objc var numberOfDaysToWaitBetweenPrompts: Int = 183 + var numberOfDaysToWaitBetweenPrompts: Int = 183 /// A value to indicate whether this launch was an upgrade from a previous version var didUpgradeVersion: Bool = false @@ -49,10 +49,10 @@ class AppRatingUtility: NSObject { return promptingDisabledRemote || promptingDisabledLocal } - @objc static let shared = AppRatingUtility(defaults: UserDefaults.standard) + static let shared = AppRatingUtility(defaults: UserDefaults.standard) init(defaults: UserDefaults, - featureFlagStore: RemoteFeatureFlagStore = RemoteFeatureFlagStore()) { + featureFlagStore: RemoteFeatureFlagStore = RemoteFeatureFlagStore()) { self.defaults = defaults self.featureFlagStore = featureFlagStore } @@ -63,7 +63,7 @@ class AppRatingUtility: NSObject { /// - Parameters: /// - version: version number of the app, e.g. CFBundleShortVersionString /// - @objc func setVersion(_ version: String) { + func setVersion(_ version: String) { let trackingVersion = defaults.string(forKey: Key.currentVersion) ?? version defaults.set(version, forKey: Key.currentVersion) @@ -85,20 +85,18 @@ class AppRatingUtility: NSObject { /// - section: Section name, e.g. "Notifications" /// - significantEventCount: The number of significant events required to trigger an app rating prompt for this particular section. /// - @objc(registerSection:withSignificantEventCount:) func register(section: String, significantEventCount count: Int) { sections[section] = Section(significantEventCount: count) } /// Increments significant events app wide. /// - @objc func incrementSignificantEvent() { + func incrementSignificantEvent() { incrementStoredValue(key: Key.significantEventCount) } /// Increments significant events for just this particular section. /// - @objc(incrementSignificantEventForSection:) func incrementSignificantEvent(section: String) { guard sections[section] != nil else { assertionFailure("Invalid section \(section)") @@ -111,26 +109,26 @@ class AppRatingUtility: NSObject { /// Indicates that the user didn't want to review the app or leave feedback /// for this version. /// - @objc func declinedToRateCurrentVersion() { + func declinedToRateCurrentVersion() { defaults.set(true, forKey: Key.declinedToRateCurrentVersion) defaults.set(2, forKey: Key.numberOfVersionsToSkipPrompting) } /// Indicates that the user decided to give feedback for this version. /// - @objc func gaveFeedbackForCurrentVersion() { + func gaveFeedbackForCurrentVersion() { defaults.set(true, forKey: Key.gaveFeedbackForCurrentVersion) } /// Indicates that the use rated the current version of the app. /// - @objc func ratedCurrentVersion() { + func ratedCurrentVersion() { defaults.set(true, forKey: Key.ratedCurrentVersion) } /// Indicates that the user didn't like the current version of the app. /// - @objc func dislikedCurrentVersion() { + func dislikedCurrentVersion() { incrementStoredValue(key: Key.userDislikeCount) defaults.set(true, forKey: Key.dislikedCurrentVersion) defaults.set(2, forKey: Key.numberOfVersionsToSkipPrompting) @@ -138,7 +136,7 @@ class AppRatingUtility: NSObject { /// Indicates the user did like the current version of the app. /// - @objc func likedCurrentVersion() { + func likedCurrentVersion() { incrementStoredValue(key: Key.userLikeCount) defaults.set(true, forKey: Key.likedCurrentVersion) defaults.set(1, forKey: Key.numberOfVersionsToSkipPrompting) @@ -146,7 +144,7 @@ class AppRatingUtility: NSObject { /// Indicates whether enough time has passed since we last prompted the user for their opinion. /// - @objc func enoughTimePassedSinceLastPrompt()-> Bool { + func enoughTimePassedSinceLastPrompt()-> Bool { if let lastPromptDate = defaults.value(forKeyPath: Key.lastPromptToRateDate), let date = lastPromptDate as? Date, let days = Calendar.current.dateComponents([.day], from: date, to: Date()).day { @@ -162,7 +160,7 @@ class AppRatingUtility: NSObject { /// Note that this method will check to see if app review prompts on a /// global basis have been shut off. /// - @objc func shouldPromptForAppReview() -> Bool { + func shouldPromptForAppReview() -> Bool { if !enoughTimePassedSinceLastPrompt() || shouldSkipRatingForCurrentVersion() || promptingDisabled { @@ -182,7 +180,6 @@ class AppRatingUtility: NSObject { /// Note that this method will check to see if prompts for this section have /// been shut off entirely. /// - @objc(shouldPromptForAppReviewForSection:) func shouldPromptForAppReview(section name: String) -> Bool { guard let section = sections[name] else { assertionFailure("Invalid section \(name)") @@ -203,19 +200,19 @@ class AppRatingUtility: NSObject { /// Records a prompt for a review /// - @objc func userWasPromptedToReview() { + func userWasPromptedToReview() { defaults.set(Date(), forKey: Key.lastPromptToRateDate) } /// Checks if the user has ever indicated that they like the app. /// - @objc func hasUserEverLikedApp() -> Bool { + func hasUserEverLikedApp() -> Bool { return defaults.integer(forKey: Key.userLikeCount) > 0 } /// Checks if the user has ever indicated they dislike the app. /// - @objc func hasUserEverDislikedApp() -> Bool { + func hasUserEverDislikedApp() -> Bool { return defaults.integer(forKey: Key.userDislikeCount) > 0 } @@ -283,7 +280,7 @@ class AppRatingUtility: NSObject { // MARK: - Debug - override var debugDescription: String { + var debugDescription: String { var state = [String: Any]() defaults.dictionaryRepresentation() .filter({ key, _ in key.hasPrefix("AppRating") }) @@ -301,13 +298,13 @@ class AppRatingUtility: NSObject { // Overrides promptingDisabledLocal. For testing purposes only. // - @objc func _overridePromptingDisabledLocal(_ disabled: Bool) { + func _overridePromptingDisabledLocal(_ disabled: Bool) { promptingDisabledLocal = disabled } // Overrides lastPromptToRateDate. For testing purposes only. // - @objc func _overrideLastPromptToRateDate(_ date: Date) { + func _overrideLastPromptToRateDate(_ date: Date) { defaults.set(date, forKey: Key.lastPromptToRateDate) } diff --git a/WordPress/Classes/Utility/Logging/WPLogger.m b/WordPress/Classes/Utility/Logging/WPLogger.m index 4ecd396f358f..2c71c10c4131 100644 --- a/WordPress/Classes/Utility/Logging/WPLogger.m +++ b/WordPress/Classes/Utility/Logging/WPLogger.m @@ -1,3 +1,6 @@ +@import CocoaLumberjack; +@import WordPressShared; + #import "WPLogger.h" #ifdef KEYSTONE #import "Keystone-Swift.h" @@ -5,8 +8,6 @@ #import "WordPress-Swift.h" #endif -@import CocoaLumberjack; - DDLogLevel ddLogLevel = DDLogLevelInfo; void SetCocoaLumberjackObjCLogLevel(NSUInteger ddLogLevelRawValue) diff --git a/WordPress/Classes/Utility/Migration/ContentMigrationCoordinator.swift b/WordPress/Classes/Utility/Migration/ContentMigrationCoordinator.swift index add6a99f9acf..db8d84ff12a3 100644 --- a/WordPress/Classes/Utility/Migration/ContentMigrationCoordinator.swift +++ b/WordPress/Classes/Utility/Migration/ContentMigrationCoordinator.swift @@ -4,9 +4,9 @@ import BuildSettingsKit /// Encapsulates logic related to content migration from WordPress to Jetpack. /// -@objc class ContentMigrationCoordinator: NSObject { +class ContentMigrationCoordinator { - @objc static var shared: ContentMigrationCoordinator = { + static var shared: ContentMigrationCoordinator = { .init() }() @@ -43,8 +43,6 @@ import BuildSettingsKit self.eligibilityProvider = eligibilityProvider self.tracker = tracker - super.init() - // register for account change notification. ensureBackupDataDeletedOnLogout() } @@ -106,7 +104,7 @@ import BuildSettingsKit /// Attempts to clean up the exported data by re-exporting user content if they're still eligible, or deleting them otherwise. /// Re-exporting user content ensures that the exported data will match the latest state of Account and Blogs. /// - @objc func cleanupExportedDataIfNeeded() { + func cleanupExportedDataIfNeeded() { // try to re-export the user content if they're still eligible. startAndDo { [weak self] result in switch result { diff --git a/WordPress/Classes/Utility/ObjCBridge.swift b/WordPress/Classes/Utility/ObjCBridge.swift new file mode 100644 index 000000000000..01804448cf71 --- /dev/null +++ b/WordPress/Classes/Utility/ObjCBridge.swift @@ -0,0 +1,39 @@ +import Foundation + +/// This class is a temporary bridge between Swift-only APIs in Keystone +/// and the remaining Objective-C classes that weren't replaced yet. +/// +/// FIXME: Remove when remaining Objective-C usages are gone. +@objc public final class ObjCBridge: NSObject { + @objc public class func showSigninForWPComFixingAuthToken() { + WordPressAuthenticationManager.showSigninForWPComFixingAuthToken() + } + + @objc public class func showSupportTableViewController() { + SupportTableViewController().showFromTabBar() + } + + @objc public class func makeSharingAuthorizationViewController(publicizer: PublicizeService, url: URL, blog: Blog, delegate: SharingAuthorizationDelegate) -> UIViewController { + SharingAuthorizationWebViewController(with: publicizer, url: url, for: blog, delegate: delegate) + } + + @objc public class func makeSharingButtonsViewController(blog: Blog) -> UIViewController { + SharingButtonsViewController(blog: blog) + } + + @objc public class func trackBlazeEntryPointDisplayed(source: BlazeSource) { + BlazeEventsTracker.trackEntryPointDisplayed(for: source) + } + + @objc public class var isWordPress: Bool { + AppConfiguration.isWordPress + } + + @objc public class func incrementSignificantEvent() { + AppRatingUtility.shared.incrementSignificantEvent() + } + + @objc public class var unreadNotificationsCount: Int { + ZendeskUtils.unreadNotificationsCount + } +} diff --git a/WordPress/Classes/Utility/Reachability/ReachabilityUtils+OnlineActions.swift b/WordPress/Classes/Utility/Reachability/ReachabilityUtils+OnlineActions.swift index 51081d0ea0e5..838084a48389 100644 --- a/WordPress/Classes/Utility/Reachability/ReachabilityUtils+OnlineActions.swift +++ b/WordPress/Classes/Utility/Reachability/ReachabilityUtils+OnlineActions.swift @@ -16,7 +16,7 @@ extension ReachabilityUtils { /// - warning: Do not use it as it can't reliably identify as the connection /// is reachable or not and can significantly lag behind the actual /// connectivity status. - @objc class func onAvailableInternetConnectionDo(_ action: () -> Void) { + @objc public class func onAvailableInternetConnectionDo(_ action: () -> Void) { guard ReachabilityUtils.isInternetReachable() else { WPError.showAlert(withTitle: DefaultNoConnectionMessage.title, message: DefaultNoConnectionMessage.message) return @@ -32,7 +32,7 @@ extension ReachabilityUtils { /// calling NotificationCenter.removeObserver(_:) /// @discardableResult - @objc class func observeOnceInternetAvailable(action: @escaping () -> Void) -> NSObjectProtocol { + @objc public class func observeOnceInternetAvailable(action: @escaping () -> Void) -> NSObjectProtocol { return NotificationCenter.default.observeOnce( forName: .reachabilityUpdated, object: nil, @@ -47,14 +47,14 @@ extension ReachabilityUtils { /// /// We use a Snackbar instead of a literal Alert because, for internet connection errors, /// Alerts can be disruptive. - @objc static func showNoInternetConnectionNotice(message: String = noConnectionMessage()) { + @objc public static func showNoInternetConnectionNotice(message: String = noConnectionMessage()) { // An empty title is intentional to only show a single regular font message. let notice = Notice(title: "", message: message, tag: DefaultNoConnectionMessage.tag) ActionDispatcher.dispatch(NoticeAction.post(notice)) } /// Dismiss the currently shown Notice if it was created using showNoInternetConnectionNotice() - @objc static func dismissNoInternetConnectionNotice() { + @objc public static func dismissNoInternetConnectionNotice() { ActionDispatcher.dispatch(NoticeAction.clearWithTag(DefaultNoConnectionMessage.tag)) } } diff --git a/WordPress/Classes/Utility/UIAlertControllerProxy.m b/WordPress/Classes/Utility/UIAlertControllerProxy.m index 889ca17beda3..a30c598e55ad 100644 --- a/WordPress/Classes/Utility/UIAlertControllerProxy.m +++ b/WordPress/Classes/Utility/UIAlertControllerProxy.m @@ -1,3 +1,5 @@ +@import WordPressShared; + #import "UIAlertControllerProxy.h" #ifdef KEYSTONE #import "Keystone-Swift.h" diff --git a/WordPress/Classes/Utility/WPContentSyncHelper.swift b/WordPress/Classes/Utility/WPContentSyncHelper.swift index e4e80316632a..e7de5852d1d9 100644 --- a/WordPress/Classes/Utility/WPContentSyncHelper.swift +++ b/WordPress/Classes/Utility/WPContentSyncHelper.swift @@ -1,6 +1,6 @@ import UIKit -@objc protocol WPContentSyncHelperDelegate: NSObjectProtocol { +@objc public protocol WPContentSyncHelperDelegate: NSObjectProtocol { func syncHelper(_ syncHelper: WPContentSyncHelper, syncContentWithUserInteraction userInteraction: Bool, success: ((_ hasMore: Bool) -> Void)?, failure: ((_ error: NSError) -> Void)?) func syncHelper(_ syncHelper: WPContentSyncHelper, syncMoreWithSuccess success: ((_ hasMore: Bool) -> Void)?, failure: ((_ error: NSError) -> Void)?) @objc optional func syncContentStart(_ syncHelper: WPContentSyncHelper) @@ -9,18 +9,18 @@ import UIKit @objc optional func hasNoMoreContent(_ syncHelper: WPContentSyncHelper) } -class WPContentSyncHelper: NSObject { +public class WPContentSyncHelper: NSObject { - @objc weak var delegate: WPContentSyncHelperDelegate? - @objc var isSyncing: Bool = false { + @objc public weak var delegate: WPContentSyncHelperDelegate? + @objc public var isSyncing: Bool = false { didSet { if isSyncing { delegate?.syncContentStart?(self) } } } - @objc var isLoadingMore: Bool = false - @objc var hasMoreContent: Bool = true { + @objc public var isLoadingMore: Bool = false + @objc public var hasMoreContent: Bool = true { didSet { if hasMoreContent == oldValue { return @@ -33,15 +33,18 @@ class WPContentSyncHelper: NSObject { // MARK: - Syncing - @objc @discardableResult func syncContent() -> Bool { + @objc @discardableResult + public func syncContent() -> Bool { return syncContentWithUserInteraction(false) } - @objc @discardableResult func syncContentWithUserInteraction() -> Bool { + @objc @discardableResult + public func syncContentWithUserInteraction() -> Bool { return syncContentWithUserInteraction(true) } - @objc @discardableResult func syncContentWithUserInteraction(_ userInteraction: Bool) -> Bool { + @objc @discardableResult + public func syncContentWithUserInteraction(_ userInteraction: Bool) -> Bool { guard !isSyncing else { return false } @@ -60,7 +63,8 @@ class WPContentSyncHelper: NSObject { return true } - @objc @discardableResult func syncMoreContent() -> Bool { + @objc @discardableResult + public func syncMoreContent() -> Bool { guard !isSyncing else { return false } @@ -81,7 +85,7 @@ class WPContentSyncHelper: NSObject { return true } - @objc func backgroundSync(success: (() -> Void)?, failure: ((_ error: NSError?) -> Void)?) { + @objc public func backgroundSync(success: (() -> Void)?, failure: ((_ error: NSError?) -> Void)?) { guard !isSyncing else { success?() return @@ -101,7 +105,7 @@ class WPContentSyncHelper: NSObject { }) } - @objc func syncContentEnded(error: Bool = false) { + @objc public func syncContentEnded(error: Bool = false) { isSyncing = false isLoadingMore = false diff --git a/WordPress/Classes/Utility/WPError.m b/WordPress/Classes/Utility/WPError.m index 64bb50a91723..fb0c7ef287a4 100644 --- a/WordPress/Classes/Utility/WPError.m +++ b/WordPress/Classes/Utility/WPError.m @@ -94,7 +94,7 @@ + (BOOL)showWPComSigninIfErrorIsInvalidAuth:(nonnull NSError *)error { DDLogError(@"wp.com API error: %@: %@", error.userInfo[WordPressComRestApi.ErrorKeyErrorCode], [error localizedDescription]); if (error.code == WordPressComRestApiErrorCodeInvalidToken || error.code == WordPressComRestApiErrorCodeAuthorizationRequired) { - [WordPressAuthenticationManager showSigninForWPComFixingAuthToken]; + [ObjCBridge showSigninForWPComFixingAuthToken]; return YES; } } @@ -138,8 +138,7 @@ + (void)showAlertWithTitle:(NSString *)title message:(NSString *)message withSup if (showSupport) { NSString *supportText = NSLocalizedString(@"Need Help?", @"'Need help?' button label, links off to the WP for iOS FAQ."); UIAlertAction *action = [UIAlertAction actionWithTitle:supportText style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull __unused action) { - SupportTableViewController *supportVC = [[SupportTableViewController alloc] init]; - [supportVC showFromTabBar]; + [ObjCBridge showSupportTableViewController]; [WPError internalInstance].alertShowing = NO; }]; [alertController addAction:action]; diff --git a/WordPress/Classes/Utility/WebViewController/WebViewControllerFactory.swift b/WordPress/Classes/Utility/WebViewController/WebViewControllerFactory.swift index 654bb0323d96..a139afa321bc 100644 --- a/WordPress/Classes/Utility/WebViewController/WebViewControllerFactory.swift +++ b/WordPress/Classes/Utility/WebViewController/WebViewControllerFactory.swift @@ -1,31 +1,32 @@ import UIKit import WebKit -class WebViewControllerFactory: NSObject { - @available(*, unavailable) - override init() { - } - - @objc static func controller(configuration: WebViewControllerConfiguration, source: String) -> WebKitViewController { +enum WebViewControllerFactory { + static func controller(configuration: WebViewControllerConfiguration, source: String) -> WebKitViewController { configuration.analyticsSource = source let controller = WebKitViewController(configuration: configuration) return controller } - @objc static func controller(url: URL, source: String) -> UIViewController { + static func controller(url: URL, source: String) -> UIViewController { let configuration = WebViewControllerConfiguration(url: url) return controller(configuration: configuration, source: source) } - @objc static func controller(url: URL, title: String, source: String) -> UIViewController { + static func controller(url: URL, title: String, source: String) -> UIViewController { let configuration = WebViewControllerConfiguration(url: url) configuration.customTitle = title return controller(configuration: configuration, source: source) } - @objc static func controller(url: URL, blog: Blog, source: String, withDeviceModes: Bool = false, - onClose: (() -> Void)? = nil) -> UIViewController { + static func controller( + url: URL, + blog: Blog, + source: String, + withDeviceModes: Bool = false, + onClose: (() -> Void)? = nil + ) -> UIViewController { let configuration = WebViewControllerConfiguration(url: url) configuration.analyticsSource = source configuration.authenticate(blog: blog) @@ -33,21 +34,23 @@ class WebViewControllerFactory: NSObject { return withDeviceModes ? PreviewWebKitViewController(configuration: configuration) : controller(configuration: configuration, source: source) } - @objc static func controller(url: URL, account: WPAccount, source: String) -> UIViewController { + static func controller(url: URL, account: WPAccount, source: String) -> UIViewController { let configuration = WebViewControllerConfiguration(url: url) configuration.authenticate(account: account) return controller(configuration: configuration, source: source) } - @objc static func controllerAuthenticatedWithDefaultAccount(url: URL, source: String) -> UIViewController { + static func controllerAuthenticatedWithDefaultAccount(url: URL, source: String) -> UIViewController { let configuration = WebViewControllerConfiguration(url: url) configuration.authenticateWithDefaultAccount() return controller(configuration: configuration, source: source) } - static func controllerWithDefaultAccountAndSecureInteraction(url: URL, - source: String, - title: String? = nil) -> WebKitViewController { + static func controllerWithDefaultAccountAndSecureInteraction( + url: URL, + source: String, + title: String? = nil + ) -> WebKitViewController { let configuration = WebViewControllerConfiguration(url: url) configuration.authenticateWithDefaultAccount() configuration.secureInteraction = true diff --git a/WordPress/Classes/Utility/ZendeskUtils.swift b/WordPress/Classes/Utility/ZendeskUtils.swift index f92efe1406c3..c7971c3a38e0 100644 --- a/WordPress/Classes/Utility/ZendeskUtils.swift +++ b/WordPress/Classes/Utility/ZendeskUtils.swift @@ -42,14 +42,14 @@ protocol ZendeskUtilsProtocol { /// This class provides the functionality to communicate with Zendesk for Help Center and support ticket interaction, /// as well as displaying views for the Help Center, new tickets, and ticket list. /// -@objc class ZendeskUtils: NSObject, ZendeskUtilsProtocol { +class ZendeskUtils: NSObject, ZendeskUtilsProtocol { // MARK: - Public Properties static var sharedInstance: ZendeskUtils = ZendeskUtils(contextManager: ContextManager.shared) static var zendeskEnabled = false - @objc static var unreadNotificationsCount = 0 + static var unreadNotificationsCount = 0 - @objc static var showSupportNotificationIndicator: Bool { + static var showSupportNotificationIndicator: Bool { return unreadNotificationsCount > 0 } @@ -100,7 +100,7 @@ protocol ZendeskUtilsProtocol { self.contextManager = contextManager } - @objc static func setup() { + static func setup() { guard getZendeskCredentials() else { return } diff --git a/WordPress/Classes/ViewRelated/Blaze/Helpers/BlazeEventsTracker.swift b/WordPress/Classes/ViewRelated/Blaze/Helpers/BlazeEventsTracker.swift index 7bd971af05bb..672a53f950db 100644 --- a/WordPress/Classes/ViewRelated/Blaze/Helpers/BlazeEventsTracker.swift +++ b/WordPress/Classes/ViewRelated/Blaze/Helpers/BlazeEventsTracker.swift @@ -1,7 +1,7 @@ import Foundation import WordPressShared -@objcMembers class BlazeEventsTracker: NSObject { +struct BlazeEventsTracker { private static let currentStepPropertyKey = "current_step" private static let errorPropertyKey = "error" diff --git a/WordPress/Classes/ViewRelated/Blaze/Helpers/BlazeHelper.swift b/WordPress/Classes/ViewRelated/Blaze/Helpers/BlazeHelper.swift index d09246e0a48c..19dfbe8b6be2 100644 --- a/WordPress/Classes/ViewRelated/Blaze/Helpers/BlazeHelper.swift +++ b/WordPress/Classes/ViewRelated/Blaze/Helpers/BlazeHelper.swift @@ -1,7 +1,6 @@ import Foundation -@objcMembers final class BlazeHelper: NSObject { - +enum BlazeHelper { static func isBlazeFlagEnabled() -> Bool { guard AppConfiguration.isJetpack else { return false diff --git a/WordPress/Classes/ViewRelated/Blaze/Webview/BlazeFlowCoordinator.swift b/WordPress/Classes/ViewRelated/Blaze/Webview/BlazeFlowCoordinator.swift index 3a8084c38493..6e7047846e9a 100644 --- a/WordPress/Classes/ViewRelated/Blaze/Webview/BlazeFlowCoordinator.swift +++ b/WordPress/Classes/ViewRelated/Blaze/Webview/BlazeFlowCoordinator.swift @@ -1,7 +1,7 @@ import Foundation import UIKit -@objc enum BlazeSource: Int, OverlaySource { +@objc public enum BlazeSource: Int, OverlaySource { case dashboardCard case menuItem case postsList diff --git a/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsSectionFooterView.swift b/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsSectionFooterView.swift index 97146b271e82..5beb13937bab 100644 --- a/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsSectionFooterView.swift +++ b/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsSectionFooterView.swift @@ -1,7 +1,7 @@ import UIKit import WordPressUI -class BlogDetailsSectionFooterView: UITableViewHeaderFooterView { +public class BlogDetailsSectionFooterView: UITableViewHeaderFooterView { private let titleLabel: UILabel = { let titleLabel = UILabel() titleLabel.translatesAutoresizingMaskIntoConstraints = false @@ -12,12 +12,12 @@ class BlogDetailsSectionFooterView: UITableViewHeaderFooterView { }() private let spacerView = UIView(frame: .zero) - override public init(reuseIdentifier: String?) { + public override init(reuseIdentifier: String?) { super.init(reuseIdentifier: reuseIdentifier) setupSubviews() } - required public init?(coder aDecoder: NSCoder) { + public required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) setupSubviews() } @@ -39,7 +39,7 @@ class BlogDetailsSectionFooterView: UITableViewHeaderFooterView { updateUI(title: nil, shouldShowExtraSpacing: false) } - @objc func updateUI(title: String?, shouldShowExtraSpacing: Bool) { + @objc public func updateUI(title: String?, shouldShowExtraSpacing: Bool) { titleLabel.text = title spacerView.isHidden = !shouldShowExtraSpacing } diff --git a/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController+Activity.swift b/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController+Activity.swift index b8f8c7ecde5c..c0250238c3d6 100644 --- a/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController+Activity.swift +++ b/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController+Activity.swift @@ -70,7 +70,7 @@ extension BlogDetailsViewController: SearchableActivityConvertable { return displayURL } - @objc func createUserActivity() { + @objc public func createUserActivity() { registerUserActivity() } } diff --git a/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController+FancyAlerts.swift b/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController+FancyAlerts.swift deleted file mode 100644 index 4bd401408f27..000000000000 --- a/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController+FancyAlerts.swift +++ /dev/null @@ -1,7 +0,0 @@ -import UIKit - -extension BlogDetailsViewController { - @objc func shouldShowDashboard() -> Bool { - isDashboardEnabled() - } -} diff --git a/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController+Me.swift b/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController+Me.swift index af86d97d5858..6c58ba656488 100644 --- a/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController+Me.swift +++ b/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController+Me.swift @@ -5,7 +5,7 @@ import Gravatar extension BlogDetailsViewController { - @objc func downloadGravatarImage(for row: BlogDetailsRow, forceRefresh: Bool = false) { + @objc public func downloadGravatarImage(for row: BlogDetailsRow, forceRefresh: Bool = false) { guard let email = blog.account?.email else { return } @@ -21,7 +21,7 @@ extension BlogDetailsViewController { } } - @objc func observeGravatarImageUpdate() { + @objc public func observeGravatarImageUpdate() { NotificationCenter.default.addObserver(self, selector: #selector(refreshAvatar(_:)), name: .GravatarQEAvatarUpdateNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(updateGravatarImage(_:)), name: .GravatarImageUpdateNotification, object: nil) } diff --git a/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController+SectionHelpers.swift b/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController+SectionHelpers.swift index 1e7330210293..5c95aa4398ec 100644 --- a/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController+SectionHelpers.swift +++ b/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController+SectionHelpers.swift @@ -37,77 +37,77 @@ extension BlogDetailsSubsection { } extension BlogDetailsViewController { - @objc func findSectionIndex(sections: [BlogDetailsSection], category: BlogDetailsSectionCategory) -> Int { + @objc public func findSectionIndex(sections: [BlogDetailsSection], category: BlogDetailsSectionCategory) -> Int { return sections.findSectionIndex(of: category) ?? NSNotFound } - @objc func sectionCategory(subsection: BlogDetailsSubsection, blog: Blog) -> BlogDetailsSectionCategory { + @objc public func sectionCategory(subsection: BlogDetailsSubsection, blog: Blog) -> BlogDetailsSectionCategory { return subsection.sectionCategory(for: blog) } - @objc func defaultSubsection() -> BlogDetailsSubsection { + @objc public func defaultSubsection() -> BlogDetailsSubsection { if !JetpackFeaturesRemovalCoordinator.jetpackFeaturesEnabled() { return .posts } - if shouldShowDashboard() { + if isDashboardEnabled() { return .home } return .stats } - @objc func shouldAddJetpackSection() -> Bool { + @objc public func shouldAddJetpackSection() -> Bool { guard JetpackFeaturesRemovalCoordinator.shouldShowJetpackFeatures() else { return false } return blog.shouldShowJetpackSection } - @objc func shouldAddGeneralSection() -> Bool { + @objc public func shouldAddGeneralSection() -> Bool { guard JetpackFeaturesRemovalCoordinator.shouldShowJetpackFeatures() else { return false } return blog.shouldShowJetpackSection == false } - @objc func shouldAddPersonalizeSection() -> Bool { + @objc public func shouldAddPersonalizeSection() -> Bool { guard JetpackFeaturesRemovalCoordinator.shouldShowJetpackFeatures() else { return false } return blog.supports(.themeBrowsing) || blog.supports(.menus) } - @objc func shouldAddMeRow() -> Bool { + @objc public func shouldAddMeRow() -> Bool { JetpackFeaturesRemovalCoordinator.currentAppUIType == .simplified && !isSidebarModeEnabled } - @objc func shouldAddSharingRow() -> Bool { + @objc public func shouldAddSharingRow() -> Bool { guard JetpackFeaturesRemovalCoordinator.shouldShowJetpackFeatures() else { return false } return blog.supports(.sharing) } - @objc func shouldAddPeopleRow() -> Bool { + @objc public func shouldAddPeopleRow() -> Bool { guard JetpackFeaturesRemovalCoordinator.shouldShowJetpackFeatures() else { return false } return blog.supports(.people) } - @objc func shouldAddUsersRow() -> Bool { + @objc public func shouldAddUsersRow() -> Bool { // Only admin users can list users. FeatureFlag.selfHostedSiteUserManagement.enabled && blog.isSelfHosted && blog.isAdmin } - @objc func shouldAddPluginsRow() -> Bool { + @objc public func shouldAddPluginsRow() -> Bool { return blog.supports(.pluginManagement) } - @objc func shouldAddDomainRegistrationRow() -> Bool { + @objc public func shouldAddDomainRegistrationRow() -> Bool { return FeatureFlag.domainRegistration.enabled && blog.supports(.domains) } - @objc func showUsers() { + @objc public func showUsers() { guard let presentationDelegate, let userId = self.blog.userID?.intValue else { return } @@ -121,7 +121,7 @@ extension BlogDetailsViewController { presentationDelegate.presentBlogDetailsViewController(UIHostingController(rootView: rootView)) } - @objc func showManagePluginsScreen() { + @objc public func showManagePluginsScreen() { guard blog.supports(.pluginManagement), let site = JetpackSiteRef(blog: blog) else { return diff --git a/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController+SiteMonitoring.swift b/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController+SiteMonitoring.swift deleted file mode 100644 index 260ddfbbba63..000000000000 --- a/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController+SiteMonitoring.swift +++ /dev/null @@ -1,14 +0,0 @@ -import UIKit - -extension BlogDetailsViewController { - - @objc func showSiteMonitoring() { - showSiteMonitoring(selectedTab: nil) - } - - @objc func showSiteMonitoring(selectedTab: NSNumber?) { - let selectedTab = selectedTab.flatMap { SiteMonitoringTab(rawValue: $0.intValue) } - let controller = SiteMonitoringViewController(blog: blog, selectedTab: selectedTab) - presentationDelegate?.presentBlogDetailsViewController(controller) - } -} diff --git a/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController+Strings.swift b/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController+Strings.swift index 86c37650a389..c38bb7a6a09d 100644 --- a/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController+Strings.swift +++ b/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController+Strings.swift @@ -36,11 +36,11 @@ extension BlogDetailsViewController { // MARK: - Objective-C Interface @objc(BlogDetailsViewControllerStrings) -class objc_BlogDetailsViewController_Strings: NSObject { +public class objc_BlogDetailsViewController_Strings: NSObject { - @objc class func contentSectionTitle() -> String { BlogDetailsViewController.Strings.contentSectionTitle } - @objc class func trafficSectionTitle() -> String { BlogDetailsViewController.Strings.trafficSectionTitle } - @objc class func maintenanceSectionTitle() -> String { BlogDetailsViewController.Strings.maintenanceSectionTitle } - @objc class func socialRowTitle() -> String { BlogDetailsViewController.Strings.socialRowTitle } - @objc class func siteMonitoringRowTitle() -> String { BlogDetailsViewController.Strings.siteMonitoringRowTitle } + @objc public class func contentSectionTitle() -> String { BlogDetailsViewController.Strings.contentSectionTitle } + @objc public class func trafficSectionTitle() -> String { BlogDetailsViewController.Strings.trafficSectionTitle } + @objc public class func maintenanceSectionTitle() -> String { BlogDetailsViewController.Strings.maintenanceSectionTitle } + @objc public class func socialRowTitle() -> String { BlogDetailsViewController.Strings.socialRowTitle } + @objc public class func siteMonitoringRowTitle() -> String { BlogDetailsViewController.Strings.siteMonitoringRowTitle } } diff --git a/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController+Swift.swift b/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController+Swift.swift index 23147d2118b1..c2ea032d6e82 100644 --- a/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController+Swift.swift +++ b/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController+Swift.swift @@ -7,6 +7,32 @@ extension BlogDetailsViewController { @objc public func isDashboardEnabled() -> Bool { return JetpackFeaturesRemovalCoordinator.jetpackFeaturesEnabled() && blog.isAccessibleThroughWPCom() } + + @objc public func confirmRemoveSite() { + let blogService = BlogService(coreDataStack: ContextManager.shared) + blogService.remove(blog) + + WordPressAppDelegate.shared?.trackLogoutIfNeeded() + + if AppConfiguration.isWordPress { + ContentMigrationCoordinator.shared.cleanupExportedDataIfNeeded() + } + + // Delete local data after removing the last site + if !AccountHelper.isLoggedIn { + AccountHelper.deleteAccountData() + } + + navigationController?.popToRootViewController(animated: true) + } + + @objc public func shouldShowJetpackInstallCard() -> Bool { + !WPDeviceIdentification.isiPad() && JetpackInstallPluginHelper.shouldShowCard(for: blog) + } + + @objc public func shouldShowBlaze() -> Bool { + BlazeHelper.isBlazeFlagEnabled() && self.blog.supports(.blaze) + } } // MARK: - BlogDetailsViewController (Navigation) @@ -25,7 +51,7 @@ extension BlogDetailsViewController { } @objc(showPostListFromSource:) - func showPostList(from source: BlogDetailsNavigationSource) { + public func showPostList(from source: BlogDetailsNavigationSource) { trackEvent(.openedPosts, from: source) let controller = PostListViewController.controllerWithBlog(blog) controller.navigationItem.largeTitleDisplayMode = .never @@ -33,7 +59,7 @@ extension BlogDetailsViewController { } @objc(showPageListFromSource:) - func showPageList(from source: BlogDetailsNavigationSource) { + public func showPageList(from source: BlogDetailsNavigationSource) { trackEvent(.openedPages, from: source) let controller = PageListViewController.controllerWithBlog(blog) controller.navigationItem.largeTitleDisplayMode = .never @@ -41,19 +67,19 @@ extension BlogDetailsViewController { } @objc(showMediaLibraryFromSource:) - func showMediaLibrary(from source: BlogDetailsNavigationSource) { + public func showMediaLibrary(from source: BlogDetailsNavigationSource) { showMediaLibrary(from: source, showPicker: false) } @objc(showMediaLibraryFromSource:showPicker:) - func showMediaLibrary(from source: BlogDetailsNavigationSource, showPicker: Bool) { + public func showMediaLibrary(from source: BlogDetailsNavigationSource, showPicker: Bool) { trackEvent(.openedMediaLibrary, from: source) let controller = SiteMediaViewController(blog: blog, showPicker: showPicker) presentationDelegate?.presentBlogDetailsViewController(controller) } @objc(showSettingsFromSource:) - func showSettings(from source: BlogDetailsNavigationSource) { + public func showSettings(from source: BlogDetailsNavigationSource) { trackEvent(.openedSiteSettings, from: source) guard let settingsVC = SiteSettingsViewController(blog: blog) else { @@ -80,8 +106,8 @@ extension BlogDetailsViewController { } } - @objc - @discardableResult func showMe() -> MeViewController { + @objc @discardableResult + public func showMe() -> MeViewController { let controller = MeViewController() presentationDelegate?.presentBlogDetailsViewController(controller) return controller @@ -142,7 +168,7 @@ extension BlogDetailsViewController { } @objc(showCommentsFromSource:) - func showComments(from source: BlogDetailsNavigationSource) { + public func showComments(from source: BlogDetailsNavigationSource) { trackEvent(.openedComments, from: source) guard let commentsVC = CommentsViewController(blog: blog) else { @@ -188,7 +214,7 @@ extension BlogDetailsViewController { } @objc(showStatsFromSource:) - func showStats(from source: BlogDetailsNavigationSource) { + public func showStats(from source: BlogDetailsNavigationSource) { trackEvent(.statsAccessed, from: source) let statsVC = makeStatsVC() @@ -218,7 +244,7 @@ extension BlogDetailsViewController { } @objc(showDomainsFromSource:) - func showDomains(from source: BlogDetailsNavigationSource) { + public func showDomains(from source: BlogDetailsNavigationSource) { guard let presentationDelegate else { return wpAssertionFailure("presentationDelegate mising") } @@ -232,7 +258,7 @@ extension BlogDetailsViewController { } @objc(showSharingFromSource:) - func showSharing(from source: BlogDetailsNavigationSource) { + public func showSharing(from source: BlogDetailsNavigationSource) { let sharingVC: UIViewController if !blog.supportsPublicize() { @@ -248,7 +274,7 @@ extension BlogDetailsViewController { } @objc(showViewSiteFromSource:) - func showViewSite(from source: BlogDetailsNavigationSource) { + public func showViewSite(from source: BlogDetailsNavigationSource) { trackEvent(.openedViewSite, from: source) guard let string = blog.homeURL, let homeURL = URL(string: string as String) else { @@ -283,6 +309,16 @@ extension BlogDetailsViewController { guard let url = URL(string: dashboardPath) else { return } UIApplication.shared.open(url, options: [:], completionHandler: nil) } + + @objc public func showSiteMonitoring() { + showSiteMonitoring(selectedTab: nil) + } + + @objc public func showSiteMonitoring(selectedTab: NSNumber?) { + let selectedTab = selectedTab.flatMap { SiteMonitoringTab(rawValue: $0.intValue) } + let controller = SiteMonitoringViewController(blog: blog, selectedTab: selectedTab) + presentationDelegate?.presentBlogDetailsViewController(controller) + } } // MARK: - BlogDetailsViewController (Tracking) diff --git a/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController.m b/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController.m index 849339b33b90..cfc07ea94753 100644 --- a/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController.m +++ b/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController.m @@ -14,7 +14,6 @@ #import "WordPress-Swift.h" #endif #import "MenusViewController.h" -#import "NSMutableArray+NullableObjects.h" @import Gridicons; @import Reachability; @@ -43,6 +42,16 @@ #pragma mark - Helper Classes for Blog Details view model. +@implementation NSMutableArray (NullableObjects) + +- (void)addNullableObject:(nullable id)anObject { + if (anObject != nil) { + [self addObject:anObject]; + } +} + +@end + @implementation BlogDetailsRow - (instancetype)initWithTitle:(NSString * __nonnull)title @@ -232,7 +241,6 @@ @interface BlogDetailsViewController () *tableSections; @property (nonatomic, strong) BlogService *blogService; -@property (nonatomic, strong) SiteIconPickerPresenter *siteIconPickerPresenter; /// Used to restore the tableview selection during state restoration, and /// also when switching between a collapsed and expanded split view controller presentation @@ -352,7 +360,7 @@ - (void)viewDidAppear:(BOOL)animated } if ([self shouldShowBlaze]) { - [BlazeEventsTracker trackEntryPointDisplayedFor:BlazeSourceMenuItem]; + [ObjCBridge trackBlazeEntryPointDisplayedWithSource:BlazeSourceMenuItem]; } } @@ -635,14 +643,6 @@ - (void)setRestorableSelectedIndexPath:(NSIndexPath *)restorableSelectedIndexPat _restorableSelectedIndexPath = nil; } -- (SiteIconPickerPresenter *)siteIconPickerPresenter -{ - if (!_siteIconPickerPresenter) { - _siteIconPickerPresenter = [[SiteIconPickerPresenter alloc]initWithBlog:self.blog]; - } - return _siteIconPickerPresenter; -} - #pragma mark - iOS 10 bottom padding - (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)sectionNum { @@ -764,7 +764,7 @@ - (BlogDetailsRow *)socialRow { __weak __typeof(self) weakSelf = self; - NSString *title = [AppConfiguration isWordPress] + NSString *title = ObjCBridge.isWordPress ? NSLocalizedString(@"Sharing", @"Noun. Title. Links to a blog's sharing options.") : [BlogDetailsViewControllerStrings socialRowTitle]; @@ -999,7 +999,7 @@ - (void)configureTableViewData [marr addNullableObject:[self homeSectionViewModel]]; } - if ([AppConfiguration isWordPress]) { + if (ObjCBridge.isWordPress) { if ([self shouldAddJetpackSection]) { [marr addNullableObject:[self jetpackSectionViewModel]]; } @@ -1660,16 +1660,6 @@ - (void)preloadDomains failure:nil]; } -- (BOOL)shouldShowJetpackInstallCard -{ - return ![WPDeviceIdentification isiPad] && [JetpackInstallPluginHelper shouldShowCardFor:self.blog]; -} - -- (BOOL)shouldShowBlaze -{ - return [BlazeHelper isBlazeFlagEnabled] && [self.blog supports:BlogFeatureBlaze]; -} - #pragma mark - Remove Site - (void)showRemoveSiteAlert @@ -1692,24 +1682,6 @@ - (void)showRemoveSiteAlert [self presentViewController:alertController animated:YES completion:nil]; } -- (void)confirmRemoveSite -{ - BlogService *blogService = [[BlogService alloc] initWithCoreDataStack:[ContextManager sharedInstance]]; - [blogService removeBlog:self.blog]; - [[WordPressAppDelegate shared] trackLogoutIfNeeded]; - - if ([AppConfiguration isWordPress]) { - [ContentMigrationCoordinator.shared cleanupExportedDataIfNeeded]; - } - - // Delete local data after removing the last site - if (!AccountHelper.isLoggedIn) { - [AccountHelper deleteAccountData]; - } - - [self.navigationController popToRootViewControllerAnimated:YES]; -} - #pragma mark - Notification handlers - (void)handleDataModelChange:(NSNotification *)note diff --git a/WordPress/Classes/ViewRelated/Blog/Blog Details/SoTW 2023/SOTWCardView.swift b/WordPress/Classes/ViewRelated/Blog/Blog Details/SoTW 2023/SOTWCardView.swift index 229ab84f43e1..b4ba2ec7fccd 100644 --- a/WordPress/Classes/ViewRelated/Blog/Blog Details/SoTW 2023/SOTWCardView.swift +++ b/WordPress/Classes/ViewRelated/Blog/Blog Details/SoTW 2023/SOTWCardView.swift @@ -101,7 +101,7 @@ private struct SotWConstants { // MARK: - UITableViewCell Wrapper -class SotWTableViewCell: UITableViewCell { +public class SotWTableViewCell: UITableViewCell { private lazy var cardView: SotWCardView = { let cardView = SotWCardView() @@ -117,12 +117,12 @@ class SotWTableViewCell: UITableViewCell { return cardView }() - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) setupView() } - required init?(coder: NSCoder) { + public required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -132,7 +132,7 @@ class SotWTableViewCell: UITableViewCell { WPAnalytics.track(.sotw2023NudgePostEventCardShown) } - @objc func configure(onCardHidden: (() -> Void)?) { + @objc public func configure(onCardHidden: (() -> Void)?) { cardView.didHideCard = onCardHidden } } @@ -141,7 +141,7 @@ class SotWTableViewCell: UITableViewCell { extension BlogDetailsViewController { - @objc func sotw2023SectionViewModel() -> BlogDetailsSection { + @objc public func sotw2023SectionViewModel() -> BlogDetailsSection { let row = BlogDetailsRow() row.callback = {} let section = BlogDetailsSection(title: nil, @@ -151,7 +151,7 @@ extension BlogDetailsViewController { return section } - @objc func shouldShowSotW2023Card() -> Bool { + @objc public func shouldShowSotW2023Card() -> Bool { guard AppConfiguration.isWordPress && RemoteFeatureFlag.wordPressSotWCard.enabled() else { return false } diff --git a/WordPress/Classes/ViewRelated/Blog/Sharing/KeyringAccountHelper.swift b/WordPress/Classes/ViewRelated/Blog/Sharing/KeyringAccountHelper.swift index a68d0bdf80b7..7da98d1e3027 100644 --- a/WordPress/Classes/ViewRelated/Blog/Sharing/KeyringAccountHelper.swift +++ b/WordPress/Classes/ViewRelated/Blog/Sharing/KeyringAccountHelper.swift @@ -11,15 +11,15 @@ struct KeyringAccount { var keyringConnection: KeyringConnection } -@objc class KeyringAccountHelper: NSObject { +@objc public class KeyringAccountHelper: NSObject { - @objc class ValidationError: NSObject { - @objc let header: String - @objc let body: String - @objc let continueTitle: String - @objc let cancelTitle: String + @objc public class ValidationError: NSObject { + @objc public let header: String + @objc public let body: String + @objc public let continueTitle: String + @objc public let cancelTitle: String - @objc let continueURL: URL? + @objc public let continueURL: URL? init(header: String, body: String, continueTitle: String, cancelTitle: String, continueURL: URL? = nil) { self.header = header @@ -38,7 +38,7 @@ struct KeyringAccount { /// /// - Returns: An instance of `ValidationError` object, this is a plain object just with the information for an alert. /// - @objc func validateConnections(_ connections: [KeyringConnection], with publicizeService: PublicizeService) -> ValidationError? { + @objc public func validateConnections(_ connections: [KeyringConnection], with publicizeService: PublicizeService) -> ValidationError? { let accounts = accountsFromKeyringConnections(connections, with: publicizeService) if publicizeService.serviceID == PublicizeService.facebookServiceID, accounts.isEmpty { diff --git a/WordPress/Classes/ViewRelated/Blog/Sharing/SharingAuthorizationHelper.m b/WordPress/Classes/ViewRelated/Blog/Sharing/SharingAuthorizationHelper.m index e310ad3f4ba1..54bbb664a4f7 100644 --- a/WordPress/Classes/ViewRelated/Blog/Sharing/SharingAuthorizationHelper.m +++ b/WordPress/Classes/ViewRelated/Blog/Sharing/SharingAuthorizationHelper.m @@ -1,5 +1,6 @@ -#import "SharingAuthorizationHelper.h" +@import WordPressShared; +#import "SharingAuthorizationHelper.h" #import "Blog.h" #import "BlogService.h" @@ -92,7 +93,7 @@ - (void)reconnectPublicizeConnection:(PublicizeConnection *)publicizeConnection */ - (void)authorizeWithConnectionURL:(NSURL *)connectionURL { - SharingAuthorizationWebViewController *webViewController = [[SharingAuthorizationWebViewController alloc] initWith:self.publicizeService url:connectionURL for:self.blog delegate:self]; + UIViewController *webViewController = [ObjCBridge makeSharingAuthorizationViewControllerWithPublicizer:self.publicizeService url:connectionURL blog:self.blog delegate:self]; self.navController = [[UINavigationController alloc] initWithRootViewController:webViewController]; self.navController.modalPresentationStyle = UIModalPresentationFormSheet; diff --git a/WordPress/Classes/ViewRelated/Blog/Sharing/SharingAuthorizationWebViewController.swift b/WordPress/Classes/ViewRelated/Blog/Sharing/SharingAuthorizationWebViewController.swift index 0c9bfc4048de..3ecc3f678beb 100644 --- a/WordPress/Classes/ViewRelated/Blog/Sharing/SharingAuthorizationWebViewController.swift +++ b/WordPress/Classes/ViewRelated/Blog/Sharing/SharingAuthorizationWebViewController.swift @@ -13,7 +13,6 @@ public protocol SharingAuthorizationDelegate: NSObjectProtocol { func authorizeDidCancel(_ publicizer: PublicizeService) } -@objc class SharingAuthorizationWebViewController: WebKitViewController { private static let loginURL = "https://wordpress.com/wp-login.php" @@ -29,7 +28,6 @@ class SharingAuthorizationWebViewController: WebKitViewController { private weak var delegate: SharingAuthorizationDelegate? - @objc init(with publicizer: PublicizeService, url: URL, for blog: Blog, delegate: SharingAuthorizationDelegate) { self.delegate = delegate self.publicizer = publicizer diff --git a/WordPress/Classes/ViewRelated/Blog/Sharing/SharingButtonsViewController.swift b/WordPress/Classes/ViewRelated/Blog/Sharing/SharingButtonsViewController.swift index 93193a13575b..3dcc37482b83 100644 --- a/WordPress/Classes/ViewRelated/Blog/Sharing/SharingButtonsViewController.swift +++ b/WordPress/Classes/ViewRelated/Blog/Sharing/SharingButtonsViewController.swift @@ -5,7 +5,7 @@ import WordPressShared /// Manages which sharing button are displayed, their order, and other settings /// related to sharing. /// -@objc class SharingButtonsViewController: UITableViewController { +class SharingButtonsViewController: UITableViewController { typealias SharingButtonsRowAction = () -> Void typealias SharingButtonsCellConfig = (UITableViewCell) -> Void @@ -55,7 +55,7 @@ import WordPressShared // MARK: - LifeCycle Methods - @objc init(blog: Blog) { + init(blog: Blog) { self.blog = blog super.init(style: .insetGrouped) diff --git a/WordPress/Classes/ViewRelated/Blog/Sharing/SharingViewController.m b/WordPress/Classes/ViewRelated/Blog/Sharing/SharingViewController.m index 8101d7b27173..905b730e0333 100644 --- a/WordPress/Classes/ViewRelated/Blog/Sharing/SharingViewController.m +++ b/WordPress/Classes/ViewRelated/Blog/Sharing/SharingViewController.m @@ -314,7 +314,7 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath } case SharingSectionSharingButtons: - controller = [[SharingButtonsViewController alloc] initWithBlog:self.blog]; + controller = [ObjCBridge makeSharingButtonsViewControllerWithBlog:self.blog]; [WPAppAnalytics track:WPAnalyticsStatSharingOpenedSharingButtonSettings withBlog:self.blog]; break; diff --git a/WordPress/Classes/ViewRelated/Blog/Sharing/SharingViewController.swift b/WordPress/Classes/ViewRelated/Blog/Sharing/SharingViewController.swift index 1248004d3882..f4f6c5a29bea 100644 --- a/WordPress/Classes/ViewRelated/Blog/Sharing/SharingViewController.swift +++ b/WordPress/Classes/ViewRelated/Blog/Sharing/SharingViewController.swift @@ -5,12 +5,12 @@ extension SharingViewController { static let jetpackBadgePadding: CGFloat = 30 @objc - static func jetpackBrandingVisibile() -> Bool { + public static func jetpackBrandingVisibile() -> Bool { return JetpackBrandingVisibility.all.enabled } @objc - func makeJetpackBadge() -> UIView { + public func makeJetpackBadge() -> UIView { let textProvider = JetpackBrandingTextProvider(screen: JetpackBadgeScreen.sharing) let badge = JetpackButton.makeBadgeView(title: textProvider.brandingText(), topPadding: Self.jetpackBadgePadding, @@ -21,7 +21,7 @@ extension SharingViewController { } @objc - func presentJetpackOverlay() { + public func presentJetpackOverlay() { JetpackBrandingCoordinator.presentOverlay(from: self) JetpackBrandingAnalyticsHelper.trackJetpackPoweredBadgeTapped(screen: .sharing) } @@ -29,7 +29,7 @@ extension SharingViewController { // MARK: Twitter Deprecation @objc - func makeTwitterDeprecationFooterView() -> TwitterDeprecationTableFooterView { + public func makeTwitterDeprecationFooterView() -> TwitterDeprecationTableFooterView { let footerView = TwitterDeprecationTableFooterView() footerView.presentingViewController = self footerView.source = "social_connection_list" diff --git a/WordPress/Classes/ViewRelated/Blog/Sharing/TwitterDeprecationTableFooterView.swift b/WordPress/Classes/ViewRelated/Blog/Sharing/TwitterDeprecationTableFooterView.swift index 70d944122da4..2c619b1f54b5 100644 --- a/WordPress/Classes/ViewRelated/Blog/Sharing/TwitterDeprecationTableFooterView.swift +++ b/WordPress/Classes/ViewRelated/Blog/Sharing/TwitterDeprecationTableFooterView.swift @@ -4,13 +4,13 @@ import WordPressUI /// A subclass implementation of `UITableViewHeaderFooterView` that displays a text with a tappable link. /// Specifically used for Twitter deprecation purposes. /// -@objc class TwitterDeprecationTableFooterView: UITableViewHeaderFooterView { +@objc public class TwitterDeprecationTableFooterView: UITableViewHeaderFooterView { // The view controller that will present the web view. - @objc weak var presentingViewController: UIViewController? = nil + @objc public weak var presentingViewController: UIViewController? = nil // For tracking purposes. See https://wp.me/pctCYC-OI#tracks - @objc var source: String? = nil + @objc public var source: String? = nil private let label: UILabel = { let label = UILabel() @@ -43,12 +43,12 @@ import WordPressUI // MARK: Methods - override public init(reuseIdentifier: String?) { + public override init(reuseIdentifier: String?) { super.init(reuseIdentifier: reuseIdentifier) setupSubviews() } - required public init?(coder aDecoder: NSCoder) { + public required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) setupSubviews() } @@ -66,7 +66,7 @@ private extension TwitterDeprecationTableFooterView { contentView.pinSubviewToAllEdgeMargins(label) } - @objc public func labelTapped(_ sender: UITapGestureRecognizer) { + @objc func labelTapped(_ sender: UITapGestureRecognizer) { guard let presentingViewController, let source, let attributedText = label.attributedText else { diff --git a/WordPress/Classes/ViewRelated/Blog/Site Management/SiteTagsViewController.swift b/WordPress/Classes/ViewRelated/Blog/Site Management/SiteTagsViewController.swift index 78cb73412736..f70218824bc7 100644 --- a/WordPress/Classes/ViewRelated/Blog/Site Management/SiteTagsViewController.swift +++ b/WordPress/Classes/ViewRelated/Blog/Site Management/SiteTagsViewController.swift @@ -56,7 +56,7 @@ final class SiteTagsViewController: UITableViewController { private var isPerformingInitialSync = false - @objc public init(blog: Blog) { + init(blog: Blog) { self.blog = blog super.init(style: .plain) } diff --git a/WordPress/Classes/ViewRelated/Blog/Site Management/StartOverViewController.swift b/WordPress/Classes/ViewRelated/Blog/Site Management/StartOverViewController.swift index b23741bed905..db30fd798b10 100644 --- a/WordPress/Classes/ViewRelated/Blog/Site Management/StartOverViewController.swift +++ b/WordPress/Classes/ViewRelated/Blog/Site Management/StartOverViewController.swift @@ -5,16 +5,16 @@ import WordPressUI /// StartOverViewController allows user to trigger help session to remove site content. /// -open class StartOverViewController: UITableViewController, MFMailComposeViewControllerDelegate { +class StartOverViewController: UITableViewController, MFMailComposeViewControllerDelegate { // MARK: - Properties: must be set by creator /// The blog whose content we want to remove /// - @objc var blog: Blog! + var blog: Blog! // MARK: - Properties: table content - @objc let headerView: TableViewHeaderDetailView = { + let headerView: TableViewHeaderDetailView = { let header = NSLocalizedString("Let Us Help", comment: "Heading for instructions on Start Over settings page") /// GlotPress breaks if iOS keys are longer than 256 characters. /// So lets split it to keep GlotPress happy :) GH: #15353 @@ -31,7 +31,7 @@ open class StartOverViewController: UITableViewController, MFMailComposeViewCont return TableViewHeaderDetailView(title: header, detail: detail) }() - @objc let contactCell: UITableViewCell = { + let contactCell: UITableViewCell = { let contactTitle = NSLocalizedString("Contact Support", comment: "Button to contact support on Start Over settings page") let actionCell = WPTableViewCellDefault(style: .value1, reuseIdentifier: nil) @@ -48,7 +48,7 @@ open class StartOverViewController: UITableViewController, MFMailComposeViewCont /// /// - Parameter blog: The Blog currently at the site /// - @objc convenience init(blog: Blog) { + convenience init(blog: Blog) { self.init(style: .insetGrouped) self.blog = blog } @@ -107,29 +107,29 @@ open class StartOverViewController: UITableViewController, MFMailComposeViewCont // Mark - Email handling - @objc let mailRecipient = "help@wordpress.com" + let mailRecipient = "help@wordpress.com" - @objc var mailSubject: String { + var mailSubject: String { guard let displayURL = self.blog.displayURL else { return "Start over" } return "Start over with site \(displayURL)" } - @objc var mailBody: String { + var mailBody: String { guard let siteURL = self.blog.url else { return "I want to start over" } return "I want to start over with the site \(siteURL)" } - @objc var googleMailURL: URL? { + var googleMailURL: URL? { let googleMailString = "googlegmail:///co?to=\(mailRecipient)" + "&subject=\(mailSubject)&body=\(mailBody)" return URL(string: googleMailString.addingPercentEncoding(withAllowedCharacters: NSCharacterSet.urlQueryAllowed)!) } - @objc func showAppleMailComposer() { + func showAppleMailComposer() { let mailComposeController = MFMailComposeViewController() mailComposeController.mailComposeDelegate = self mailComposeController.setToRecipients([mailRecipient]) @@ -138,11 +138,11 @@ open class StartOverViewController: UITableViewController, MFMailComposeViewCont present(mailComposeController, animated: true) } - @objc func showGoogleMailComposerForURL(_ url: URL ) { + func showGoogleMailComposerForURL(_ url: URL ) { UIApplication.shared.open(url) } - @objc func showAlertToSendEmail() { + func showAlertToSendEmail() { let title = String(format: NSLocalizedString("Contact us at %@", comment: "Alert title for contact us alert, placeholder for help email address, inserted at run time."), mailRecipient) let message = NSLocalizedString("\nPlease send us an email to have your content cleared out.", comment: "Message to ask the user to send us an email to clear their content.") diff --git a/WordPress/Classes/ViewRelated/Blog/Site Settings/LanguageViewController.swift b/WordPress/Classes/ViewRelated/Blog/Site Settings/LanguageViewController.swift index 046a4ca2517b..8a56f6d65a17 100644 --- a/WordPress/Classes/ViewRelated/Blog/Site Settings/LanguageViewController.swift +++ b/WordPress/Classes/ViewRelated/Blog/Site Settings/LanguageViewController.swift @@ -7,7 +7,7 @@ import WordPressShared open class LanguageViewController: UITableViewController, LanguageSelectorDelegate { /// Callback to be executed whenever the Blog's selected language changes. /// - @objc var onChange: ((NSNumber) -> Void)? + @objc public var onChange: ((NSNumber) -> Void)? /// Designated Initializer /// diff --git a/WordPress/Classes/ViewRelated/Blog/Site Settings/SiteSettingsViewController+Blogging.swift b/WordPress/Classes/ViewRelated/Blog/Site Settings/SiteSettingsViewController+Blogging.swift index 18ecd2bde70b..74683b6ea51d 100644 --- a/WordPress/Classes/ViewRelated/Blog/Site Settings/SiteSettingsViewController+Blogging.swift +++ b/WordPress/Classes/ViewRelated/Blog/Site Settings/SiteSettingsViewController+Blogging.swift @@ -2,18 +2,18 @@ import UIKit extension SiteSettingsViewController { - @objc var bloggingSettingsRowCount: Int { + @objc public var bloggingSettingsRowCount: Int { bloggingSettingsRows.count } - @objc func tableView(_ tableView: UITableView, cellForBloggingSettingsInRow row: Int) -> UITableViewCell { + @objc public func tableView(_ tableView: UITableView, cellForBloggingSettingsInRow row: Int) -> UITableViewCell { switch bloggingSettingsRows[row] { case .reminders: return remindersTableViewCell } } - @objc func tableView(_ tableView: UITableView, didSelectInBloggingSettingsAt indexPath: IndexPath) { + @objc public func tableView(_ tableView: UITableView, didSelectInBloggingSettingsAt indexPath: IndexPath) { switch bloggingSettingsRows[indexPath.row] { case .reminders: presentBloggingRemindersFlow(indexPath: indexPath) diff --git a/WordPress/Classes/ViewRelated/Blog/Site Settings/SiteSettingsViewController+Swift.swift b/WordPress/Classes/ViewRelated/Blog/Site Settings/SiteSettingsViewController+Swift.swift index 6b4ab39bf059..63aa07cea892 100644 --- a/WordPress/Classes/ViewRelated/Blog/Site Settings/SiteSettingsViewController+Swift.swift +++ b/WordPress/Classes/ViewRelated/Blog/Site Settings/SiteSettingsViewController+Swift.swift @@ -19,7 +19,7 @@ import WordPressShared extension SiteSettingsViewController { // MARK: - General - @objc func showPrivacySelector() { + @objc public func showPrivacySelector() { struct SiteSettingsPrivacyPicker: View { let blog: Blog @State var selection: SiteVisibility @@ -41,9 +41,32 @@ extension SiteSettingsViewController { navigationController?.pushViewController(viewController, animated: true) } + @objc(showStartOverForBlog:) + public func showStartOver(for blog: Blog) { + wpAssert(blog.supportsSiteManagementServices()) + + WPAppAnalytics.track(.siteSettingsStartOverAccessed, blog: blog) + + if SupportConfiguration.isStartOverSupportEnabled && blog.hasPaidPlan { + let startOverVC = StartOverViewController(blog: blog) + navigationController?.pushViewController(startOverVC, animated: true) + } else { + guard let targetURL = Constants.emptySiteSupportURL else { return } + + let webVC = WebViewControllerFactory.controller(url: targetURL, source: "site_settings_start_over") + let navigationVC = UINavigationController(rootViewController: webVC) + present(navigationVC, animated: true, completion: nil) + } + } + + @objc public func showTagList() { + let tagsVC = SiteTagsViewController(blog: blog) + navigationController?.pushViewController(tagsVC, animated: true) + } + // MARK: - Timezone - @objc func observeTimeZoneStore() { + @objc public func observeTimeZoneStore() { timeZoneObserver = TimeZoneObserver() { [weak self] (oldState, newState) in guard let controller = self else { return @@ -61,7 +84,7 @@ extension SiteSettingsViewController { } } - @objc func timezoneLabel() -> String? { + @objc public func timezoneLabel() -> String? { return timezoneLabel(state: StoreContainer.shared.timezone.state) } @@ -88,7 +111,7 @@ extension SiteSettingsViewController { // MARK: - Homepage Settings - @objc var homepageSettingsCell: SettingTableViewCell? { + @objc public var homepageSettingsCell: SettingTableViewCell? { let cell = SettingTableViewCell(label: NSLocalizedString("Homepage Settings", comment: "Label for Homepage Settings site settings section"), editable: true, reuseIdentifier: nil) cell?.textValue = blog.homepageType?.title return cell @@ -96,12 +119,13 @@ extension SiteSettingsViewController { // MARK: - Navigation - @objc(showHomepageSettingsForBlog:) func showHomepageSettings(for blog: Blog) { + @objc(showHomepageSettingsForBlog:) + public func showHomepageSettings(for blog: Blog) { let settingsViewController = HomepageSettingsViewController(blog: blog) navigationController?.pushViewController(settingsViewController, animated: true) } - @objc func showTimezoneSelector() { + @objc public func showTimezoneSelector() { let controller = TimeZoneSelectorViewController(selectedValue: timezoneValue) { [weak self] (newValue) in self?.navigationController?.popViewController(animated: true) self?.blog.settings?.gmtOffset = newValue.gmtOffset as NSNumber? @@ -113,12 +137,12 @@ extension SiteSettingsViewController { navigationController?.pushViewController(controller, animated: true) } - @objc func showDateAndTimeFormatSettings() { + @objc public func showDateAndTimeFormatSettings() { let dateAndTimeFormatViewController = DateAndTimeFormatSettingsViewController(blog: blog) navigationController?.pushViewController(dateAndTimeFormatViewController, animated: true) } - @objc func showPostPerPageSetting() { + @objc public func showPostPerPageSetting() { let pickerViewController = SettingsPickerViewController(style: .insetGrouped) pickerViewController.title = NSLocalizedString("Posts per Page", comment: "Posts per Page Title") pickerViewController.switchVisible = false @@ -141,12 +165,12 @@ extension SiteSettingsViewController { navigationController?.pushViewController(pickerViewController, animated: true) } - @objc func showSpeedUpYourSiteSettings() { + @objc public func showSpeedUpYourSiteSettings() { let speedUpSiteSettingsViewController = JetpackSpeedUpSiteSettingsViewController(blog: blog) navigationController?.pushViewController(speedUpSiteSettingsViewController, animated: true) } - @objc func showRelatedPostsSettings() { + @objc public func showRelatedPostsSettings() { let view = RelatedPostsSettingsView(blog: blog) let host = UIHostingController(rootView: view) host.title = view.title // Make sure title is available before push @@ -156,7 +180,7 @@ extension SiteSettingsViewController { // MARK: Footers @objc(getTrafficSettingsSectionFooterView) - func trafficSettingsSectionFooterView() -> UIView { + public func trafficSettingsSectionFooterView() -> UIView { let footer = makeFooterView() footer.textLabel?.text = NSLocalizedString("Your WordPress.com site supports the use of Accelerated Mobile Pages, a Google-led initiative that dramatically speeds up loading times on mobile devices.", comment: "Footer for AMP Traffic Site Setting, should match Calypso.") @@ -168,7 +192,7 @@ extension SiteSettingsViewController { } @objc(getEditorSettingsSectionFooterView) - func editorSettingsSectionFooterView() -> UIView { + public func editorSettingsSectionFooterView() -> UIView { let footer = makeFooterView() footer.textLabel?.text = NSLocalizedString("Edit new posts and pages with the block editor.", comment: "Explanation for the option to enable the block editor") return footer @@ -235,12 +259,12 @@ extension SiteSettingsViewController { } @objc - var generalSettingsRowCount: Int { + public var generalSettingsRowCount: Int { generalSettingsRows.count } @objc - func tableView(_ tableView: UITableView, cellForGeneralSettingsInRow row: Int) -> UITableViewCell { + public func tableView(_ tableView: UITableView, cellForGeneralSettingsInRow row: Int) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: SettingsTableViewCellReuseIdentifier) as! SettingTableViewCell switch generalSettingsRows[row] { @@ -262,7 +286,7 @@ extension SiteSettingsViewController { } @objc - func tableView(_ tableView: UITableView, didSelectInGeneralSettingsAt indexPath: IndexPath) { + public func tableView(_ tableView: UITableView, didSelectInGeneralSettingsAt indexPath: IndexPath) { switch generalSettingsRows[indexPath.row] { case .title where blog.isAdmin: showEditSiteTitleController(indexPath: indexPath) @@ -417,3 +441,7 @@ private extension SiteSettingsViewController { static let privacyTitle = NSLocalizedString("siteSettings.privacy.title", value: "Privacy", comment: "Title for screen to select the privacy options for a blog") } } + +private enum Constants { + static let emptySiteSupportURL = URL(string: "https://en.support.wordpress.com/empty-site") +} diff --git a/WordPress/Classes/ViewRelated/Blog/Site Settings/SiteSettingsViewController.m b/WordPress/Classes/ViewRelated/Blog/Site Settings/SiteSettingsViewController.m index b08bb25a7776..b7e51654c46d 100644 --- a/WordPress/Classes/ViewRelated/Blog/Site Settings/SiteSettingsViewController.m +++ b/WordPress/Classes/ViewRelated/Blog/Site Settings/SiteSettingsViewController.m @@ -59,8 +59,6 @@ SiteSettingsJetpackCount, }; -static NSString *const EmptySiteSupportURL = @"https://en.support.wordpress.com/empty-site"; - @interface SiteSettingsViewController () #pragma mark - Account Section @@ -816,12 +814,6 @@ - (void)showDefaultCategorySelector [self.navigationController pushViewController:postCategoriesViewController animated:YES]; } -- (void)showTagList -{ - SiteTagsViewController *tagsAdmin = [[SiteTagsViewController alloc] initWithBlog:self.blog]; - [self.navigationController pushViewController:tagsAdmin animated:YES]; -} - - (void)showPostFormatSelector { NSArray *titles = self.blog.sortedPostFormatNames; @@ -908,23 +900,6 @@ - (void)tableView:(UITableView *)tableView didSelectInJetpackSectionRow:(NSInteg } } -- (void)showStartOverForBlog:(Blog *)blog -{ - NSParameterAssert([blog supportsSiteManagementServices]); - - [WPAppAnalytics track:WPAnalyticsStatSiteSettingsStartOverAccessed withBlog:self.blog]; - if ([SupportConfigurationObjC isStartOverSupportEnabled] && self.blog.hasPaidPlan) { - StartOverViewController *viewController = [[StartOverViewController alloc] initWithBlog:blog]; - [self.navigationController pushViewController:viewController animated:YES]; - } else { - NSURL *targetURL = [NSURL URLWithString:EmptySiteSupportURL]; - - UIViewController *webViewController = [WebViewControllerFactory controllerWithUrl:targetURL source:@"site_settings_start_over"]; - UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:webViewController]; - [self presentViewController:navController animated:YES completion:nil]; - } -} - - (void)tableView:(UITableView *)tableView didSelectInAdvancedSectionRow:(NSInteger)row { switch (row) { diff --git a/WordPress/Classes/ViewRelated/Comments/Analytics/CommentAnalytics.swift b/WordPress/Classes/ViewRelated/Comments/Analytics/CommentAnalytics.swift index e4739435d614..5c3134c457b6 100644 --- a/WordPress/Classes/ViewRelated/Comments/Analytics/CommentAnalytics.swift +++ b/WordPress/Classes/ViewRelated/Comments/Analytics/CommentAnalytics.swift @@ -2,7 +2,7 @@ import Foundation import FormattableContentKit import WordPressShared -@objc class CommentAnalytics: NSObject { +@objc public class CommentAnalytics: NSObject { struct Constants { static let sites = "sites" @@ -34,43 +34,43 @@ import WordPressShared ] } - @objc static func trackCommentViewed(comment: Comment) { + @objc public static func trackCommentViewed(comment: Comment) { trackCommentEvent(comment: comment, event: .commentViewed) } - @objc static func trackCommentEditorOpened(comment: Comment) { + @objc public static func trackCommentEditorOpened(comment: Comment) { trackCommentEvent(comment: comment, event: .commentEditorOpened) } - @objc static func trackCommentEdited(comment: Comment) { + @objc public static func trackCommentEdited(comment: Comment) { trackCommentEvent(comment: comment, event: .commentEdited) } - @objc static func trackCommentApproved(comment: Comment) { + @objc public static func trackCommentApproved(comment: Comment) { trackCommentEvent(comment: comment, event: .commentApproved) } - @objc static func trackCommentUnApproved(comment: Comment) { + @objc public static func trackCommentUnApproved(comment: Comment) { trackCommentEvent(comment: comment, event: .commentUnApproved) } - @objc static func trackCommentTrashed(comment: Comment) { + @objc public static func trackCommentTrashed(comment: Comment) { trackCommentEvent(comment: comment, event: .commentTrashed) } - @objc static func trackCommentSpammed(comment: Comment) { + @objc public static func trackCommentSpammed(comment: Comment) { trackCommentEvent(comment: comment, event: .commentSpammed) } - @objc static func trackCommentLiked(comment: Comment) { + @objc public static func trackCommentLiked(comment: Comment) { trackCommentEvent(comment: comment, event: .commentLiked) } - @objc static func trackCommentUnLiked(comment: Comment) { + @objc public static func trackCommentUnLiked(comment: Comment) { trackCommentEvent(comment: comment, event: .commentUnliked) } - @objc static func trackCommentRepliedTo(comment: Comment) { + @objc public static func trackCommentRepliedTo(comment: Comment) { trackCommentEvent(comment: comment, event: .commentRepliedTo) } diff --git a/WordPress/Classes/ViewRelated/Comments/Controllers/CommentDetailViewController.swift b/WordPress/Classes/ViewRelated/Comments/Controllers/CommentDetailViewController.swift index 694227acc036..46e0a356b94d 100644 --- a/WordPress/Classes/ViewRelated/Comments/Controllers/CommentDetailViewController.swift +++ b/WordPress/Classes/ViewRelated/Comments/Controllers/CommentDetailViewController.swift @@ -9,11 +9,11 @@ extension NSNotification.Name { } let userInfoCommentIdKey = "commentID" -@objc protocol CommentDetailsDelegate: AnyObject { +@objc public protocol CommentDetailsDelegate: AnyObject { func nextCommentSelected() } -class CommentDetailViewController: UIViewController, NoResultsViewHost { +public class CommentDetailViewController: UIViewController, NoResultsViewHost { // MARK: Properties @@ -23,7 +23,7 @@ class CommentDetailViewController: UIViewController, NoResultsViewHost { // Reply properties private var addCommentButton: CommentLargeButton? - @objc weak var commentDelegate: CommentDetailsDelegate? + @objc public weak var commentDelegate: CommentDetailsDelegate? private weak var notificationDelegate: CommentDetailsNotificationDelegate? private var comment: Comment @@ -202,13 +202,15 @@ class CommentDetailViewController: UIViewController, NoResultsViewHost { return button }() - @objc var isSidebarModeEnabled = false + @objc public var isSidebarModeEnabled = false // MARK: Initialization - @objc init(comment: Comment, - isLastInList: Bool, - managedObjectContext: NSManagedObjectContext = ContextManager.shared.mainContext) { + @objc public init( + comment: Comment, + isLastInList: Bool, + managedObjectContext: NSManagedObjectContext = ContextManager.shared.mainContext + ) { self.comment = comment self.commentStatus = CommentStatusType.typeForStatus(comment.status) self.isLastInList = isLastInList @@ -230,13 +232,13 @@ class CommentDetailViewController: UIViewController, NoResultsViewHost { super.init(nibName: nil, bundle: nil) } - required init?(coder: NSCoder) { + public required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } // MARK: View lifecycle - override func viewDidLoad() { + public override func viewDidLoad() { super.viewDidLoad() configureView() @@ -247,7 +249,7 @@ class CommentDetailViewController: UIViewController, NoResultsViewHost { refreshCommentReplyIfNeeded() } - override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { + public override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) // when an orientation change is triggered, recalculate the content cell's height. @@ -258,7 +260,7 @@ class CommentDetailViewController: UIViewController, NoResultsViewHost { } // Update the Comment being displayed. - @objc func displayComment(_ comment: Comment, isLastInList: Bool = true) { + @objc public func displayComment(_ comment: Comment, isLastInList: Bool = true) { self.comment = comment self.isLastInList = isLastInList addCommentButton?.placeholder = String(format: .replyPlaceholderFormat, comment.authorForDisplay()) @@ -857,11 +859,11 @@ private extension CommentDetailViewController { extension CommentDetailViewController: UITableViewDelegate, UITableViewDataSource { - func numberOfSections(in tableView: UITableView) -> Int { + public func numberOfSections(in tableView: UITableView) -> Int { return sections.count } - func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { switch sections[section] { case .content(let rows): return rows.count @@ -870,11 +872,11 @@ extension CommentDetailViewController: UITableViewDelegate, UITableViewDataSourc } } - func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { + public func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { return UITableView.automaticDimension } - func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell: UITableViewCell = { let rows: [RowType] switch sections[indexPath.section] { @@ -913,7 +915,7 @@ extension CommentDetailViewController: UITableViewDelegate, UITableViewDataSourc return cell } - func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { + public func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { switch sections[section] { case .content: return nil @@ -922,18 +924,18 @@ extension CommentDetailViewController: UITableViewDelegate, UITableViewDataSourc } } - func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) { + public func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) { let header = view as! UITableViewHeaderFooterView header.textLabel?.font = Style.tertiaryTextFont header.textLabel?.textColor = UIColor.secondaryLabel } - func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { + public func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { // Hide cell separator if it's positioned before the delete button cell. cell.separatorInset = self.shouldHideCellSeparator(for: indexPath) ? self.insetsForHiddenCellSeparator : .zero } - func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { tableView.deselectRow(at: indexPath, animated: true) switch sections[indexPath.section] { diff --git a/WordPress/Classes/ViewRelated/Comments/Controllers/CommentsViewController+Filters.swift b/WordPress/Classes/ViewRelated/Comments/Controllers/CommentsViewController+Swift.swift similarity index 88% rename from WordPress/Classes/ViewRelated/Comments/Controllers/CommentsViewController+Filters.swift rename to WordPress/Classes/ViewRelated/Comments/Controllers/CommentsViewController+Swift.swift index 33260b226ebc..bddf010b172f 100644 --- a/WordPress/Classes/ViewRelated/Comments/Controllers/CommentsViewController+Filters.swift +++ b/WordPress/Classes/ViewRelated/Comments/Controllers/CommentsViewController+Swift.swift @@ -44,7 +44,7 @@ extension CommentsViewController { } } - @objc func configureFilterTabBar(_ filterTabBar: FilterTabBar) { + @objc public func configureFilterTabBar(_ filterTabBar: FilterTabBar) { WPStyleGuide.configureFilterTabBar(filterTabBar) filterTabBar.items = CommentFilter.allCases filterTabBar.addTarget(self, action: #selector(selectedFilterDidChange(_:)), for: .valueChanged) @@ -59,16 +59,16 @@ extension CommentsViewController { refresh(with: filter.statusFilter) } - @objc func getSelectedIndex(_ filterTabBar: FilterTabBar) -> Int { + @objc public func getSelectedIndex(_ filterTabBar: FilterTabBar) -> Int { return filterTabBar.selectedIndex } - @objc func setSeletedIndex(_ selectedIndex: Int, filterTabBar: FilterTabBar) { + @objc public func setSeletedIndex(_ selectedIndex: Int, filterTabBar: FilterTabBar) { filterTabBar.setSelectedIndex(selectedIndex, animated: false) selectedFilterDidChange(filterTabBar) } - @objc func isUnrepliedFilterSelected(_ filterTabBar: FilterTabBar) -> Bool { + @objc public func isUnrepliedFilterSelected(_ filterTabBar: FilterTabBar) -> Bool { guard let item = filterTabBar.currentlySelectedItem as? CommentFilter else { return false } diff --git a/WordPress/Classes/ViewRelated/Comments/Views/ListTableViewCell+Comments.swift b/WordPress/Classes/ViewRelated/Comments/Views/ListTableViewCell+Comments.swift index d10dcb9fbd66..8dbd716ec77d 100644 --- a/WordPress/Classes/ViewRelated/Comments/Views/ListTableViewCell+Comments.swift +++ b/WordPress/Classes/ViewRelated/Comments/Views/ListTableViewCell+Comments.swift @@ -4,7 +4,7 @@ import WordPressShared /// extension ListTableViewCell { /// Configures the cell based on the provided `Comment` object. - @objc func configureWithComment(_ comment: Comment) { + @objc public func configureWithComment(_ comment: Comment) { // indicator view indicatorColor = Style.pendingIndicatorColor showsIndicator = (comment.status == CommentStatusType.pending.description) diff --git a/WordPress/Classes/ViewRelated/Jetpack/Branding/Menu Card/BlogDetailsViewController+JetpackBrandingMenuCard.swift b/WordPress/Classes/ViewRelated/Jetpack/Branding/Menu Card/BlogDetailsViewController+JetpackBrandingMenuCard.swift index 4fdf7ff0142d..fcab690b498a 100644 --- a/WordPress/Classes/ViewRelated/Jetpack/Branding/Menu Card/BlogDetailsViewController+JetpackBrandingMenuCard.swift +++ b/WordPress/Classes/ViewRelated/Jetpack/Branding/Menu Card/BlogDetailsViewController+JetpackBrandingMenuCard.swift @@ -2,17 +2,17 @@ import Foundation extension BlogDetailsViewController { - @objc var shouldShowTopJetpackBrandingMenuCard: Bool { + @objc public var shouldShowTopJetpackBrandingMenuCard: Bool { let presenter = JetpackBrandingMenuCardPresenter(blog: self.blog) return presenter.shouldShowTopCard() } - @objc var shouldShowBottomJetpackBrandingMenuCard: Bool { + @objc public var shouldShowBottomJetpackBrandingMenuCard: Bool { let presenter = JetpackBrandingMenuCardPresenter(blog: self.blog) return presenter.shouldShowBottomCard() } - @objc func jetpackCardSectionViewModel() -> BlogDetailsSection { + @objc public func jetpackCardSectionViewModel() -> BlogDetailsSection { let row = BlogDetailsRow() row.callback = { let presenter = JetpackBrandingMenuCardPresenter(blog: self.blog) diff --git a/WordPress/Classes/ViewRelated/Jetpack/Branding/Menu Card/JetpackBrandingMenuCardCell.swift b/WordPress/Classes/ViewRelated/Jetpack/Branding/Menu Card/JetpackBrandingMenuCardCell.swift index 296a172e65ee..f130ac235153 100644 --- a/WordPress/Classes/ViewRelated/Jetpack/Branding/Menu Card/JetpackBrandingMenuCardCell.swift +++ b/WordPress/Classes/ViewRelated/Jetpack/Branding/Menu Card/JetpackBrandingMenuCardCell.swift @@ -2,7 +2,7 @@ import UIKit import Lottie import WordPressUI -class JetpackBrandingMenuCardCell: UITableViewCell { +public class JetpackBrandingMenuCardCell: UITableViewCell { // MARK: Private Variables @@ -135,12 +135,12 @@ class JetpackBrandingMenuCardCell: UITableViewCell { // MARK: Initializers - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) commonInit() } - required init?(coder: NSCoder) { + public required init?(coder: NSCoder) { super.init(coder: coder) commonInit() } @@ -151,7 +151,7 @@ class JetpackBrandingMenuCardCell: UITableViewCell { // MARK: Cell Lifecycle - override func prepareForReuse() { + public override func prepareForReuse() { super.prepareForReuse() containerStackView.removeAllSubviews() @@ -414,7 +414,7 @@ private extension JetpackBrandingMenuCardCell { extension JetpackBrandingMenuCardCell { @objc(configureWithViewController:) - func configure(with viewController: BlogDetailsViewController) { + public func configure(with viewController: BlogDetailsViewController) { self.viewController = viewController presenter = JetpackBrandingMenuCardPresenter(blog: viewController.blog) config = presenter?.cardConfig() diff --git a/WordPress/Classes/ViewRelated/Jetpack/Install/JetpackInstallPluginHelper.swift b/WordPress/Classes/ViewRelated/Jetpack/Install/JetpackInstallPluginHelper.swift index af7d2a88871d..05051649a904 100644 --- a/WordPress/Classes/ViewRelated/Jetpack/Install/JetpackInstallPluginHelper.swift +++ b/WordPress/Classes/ViewRelated/Jetpack/Install/JetpackInstallPluginHelper.swift @@ -1,6 +1,5 @@ import WordPressShared -@objc class JetpackInstallPluginHelper: NSObject { // MARK: Dependencies @@ -33,7 +32,7 @@ class JetpackInstallPluginHelper: NSObject { /// /// - Parameter blog: The `Blog` to show the install cards for, /// - Returns: True if the install cards should be shown for this blog. - @objc static func shouldShowCard(for blog: Blog?) -> Bool { + static func shouldShowCard(for blog: Blog?) -> Bool { // cards are only shown in Jetpack. guard AppConfiguration.isJetpack, let helper = JetpackInstallPluginHelper(blog) else { diff --git a/WordPress/Classes/ViewRelated/Jetpack/Install/View/JetpackRemoteInstallTableViewCell.swift b/WordPress/Classes/ViewRelated/Jetpack/Install/View/JetpackRemoteInstallTableViewCell.swift index 827f8b773b44..bce13b727e8d 100644 --- a/WordPress/Classes/ViewRelated/Jetpack/Install/View/JetpackRemoteInstallTableViewCell.swift +++ b/WordPress/Classes/ViewRelated/Jetpack/Install/View/JetpackRemoteInstallTableViewCell.swift @@ -2,7 +2,7 @@ import UIKit import WordPressShared @objcMembers -class JetpackRemoteInstallTableViewCell: UITableViewCell { +public class JetpackRemoteInstallTableViewCell: UITableViewCell { // MARK: Properties @@ -52,7 +52,7 @@ class JetpackRemoteInstallTableViewCell: UITableViewCell { // MARK: Functions - func configure(blog: Blog, viewController: BlogDetailsViewController?) { + public func configure(blog: Blog, viewController: BlogDetailsViewController?) { self.blog = blog self.presenterViewController = viewController cardView.updatePlugin(JetpackPlugin(from: blog.jetpackConnectionActivePlugins)) @@ -69,7 +69,7 @@ class JetpackRemoteInstallTableViewCell: UITableViewCell { extension BlogDetailsViewController: JetpackRemoteInstallDelegate { - @objc func jetpackInstallSectionViewModel() -> BlogDetailsSection { + @objc public func jetpackInstallSectionViewModel() -> BlogDetailsSection { let row = BlogDetailsRow() row.callback = {} let section = BlogDetailsSection(title: nil, diff --git a/WordPress/Classes/ViewRelated/Jetpack/Jetpack Settings/JetpackConnectionViewController.swift b/WordPress/Classes/ViewRelated/Jetpack/Jetpack Settings/JetpackConnectionViewController.swift index 0d9948e6b5ba..49448a66e72f 100644 --- a/WordPress/Classes/ViewRelated/Jetpack/Jetpack Settings/JetpackConnectionViewController.swift +++ b/WordPress/Classes/ViewRelated/Jetpack/Jetpack Settings/JetpackConnectionViewController.swift @@ -2,7 +2,7 @@ import UIKit import WordPressShared @objc -protocol JetpackConnectionDelegate { +public protocol JetpackConnectionDelegate { func jetpackDisconnectedForBlog(_ blog: Blog) } @@ -30,7 +30,7 @@ open class JetpackConnectionViewController: UITableViewController { // MARK: - Public Properties - @objc weak var delegate: JetpackConnectionDelegate? + @objc public weak var delegate: JetpackConnectionDelegate? // MARK: - Initializer diff --git a/WordPress/Classes/ViewRelated/Jetpack/Jetpack Settings/JetpackSettingsViewController.swift b/WordPress/Classes/ViewRelated/Jetpack/Jetpack Settings/JetpackSettingsViewController.swift index 530a3fa40706..6d2392ee3c4a 100644 --- a/WordPress/Classes/ViewRelated/Jetpack/Jetpack Settings/JetpackSettingsViewController.swift +++ b/WordPress/Classes/ViewRelated/Jetpack/Jetpack Settings/JetpackSettingsViewController.swift @@ -358,7 +358,7 @@ open class JetpackSettingsViewController: UITableViewController { } extension JetpackSettingsViewController: JetpackConnectionDelegate { - func jetpackDisconnectedForBlog(_ blog: Blog) { + public func jetpackDisconnectedForBlog(_ blog: Blog) { if blog == self.blog { navigationController?.popToRootViewController(animated: true) } diff --git a/WordPress/Classes/ViewRelated/Jetpack/Login/JetpackLoginViewController.swift b/WordPress/Classes/ViewRelated/Jetpack/Login/JetpackLoginViewController.swift index 4f3863af6d21..78e80b027935 100644 --- a/WordPress/Classes/ViewRelated/Jetpack/Login/JetpackLoginViewController.swift +++ b/WordPress/Classes/ViewRelated/Jetpack/Login/JetpackLoginViewController.swift @@ -6,7 +6,7 @@ import WordPressUI /// A view controller that presents a Jetpack login form. /// -class JetpackLoginViewController: UIViewController { +public class JetpackLoginViewController: UIViewController { // MARK: - Constants @@ -25,7 +25,7 @@ class JetpackLoginViewController: UIViewController { // Defaulting to stats because since that one is written in ObcC we don't have access to the enum there. var promptType: JetpackLoginPromptType = .stats - typealias CompletionBlock = () -> Void + public typealias CompletionBlock = () -> Void /// This completion handler closure is executed when the authentication process handled /// by this VC is completed. /// @@ -45,24 +45,24 @@ class JetpackLoginViewController: UIViewController { /// /// - Parameter blog: The current blog /// - @objc init(blog: Blog) { + @objc public init(blog: Blog) { self.blog = blog super.init(nibName: nil, bundle: nil) } - required init?(coder aDecoder: NSCoder) { + public required init?(coder aDecoder: NSCoder) { preconditionFailure("Jetpack Login View Controller must be initialized by code") } // MARK: - LifeCycle Methods - override func viewDidLoad() { + public override func viewDidLoad() { super.viewDidLoad() WPStyleGuide.configureColors(view: view, tableView: nil) setupControls() } - override func willTransition(to newCollection: UITraitCollection, with coordinator: UIViewControllerTransitionCoordinator) { + public override func willTransition(to newCollection: UITraitCollection, with coordinator: UIViewControllerTransitionCoordinator) { super.willTransition(to: newCollection, with: coordinator) toggleHidingImageView(for: newCollection) } diff --git a/WordPress/Classes/ViewRelated/Me/Me Main/MeViewController.swift b/WordPress/Classes/ViewRelated/Me/Me Main/MeViewController.swift index bc2e67f327db..c25247a5c235 100644 --- a/WordPress/Classes/ViewRelated/Me/Me Main/MeViewController.swift +++ b/WordPress/Classes/ViewRelated/Me/Me Main/MeViewController.swift @@ -3,7 +3,7 @@ import BuildSettingsKit import WordPressShared import AutomatticAbout -class MeViewController: UITableViewController { +public class MeViewController: UITableViewController { var handler: ImmuTableViewHandler! var isSidebarModeEnabled = false @@ -11,24 +11,24 @@ class MeViewController: UITableViewController { // MARK: - Table View Controller - override init(style: UITableView.Style) { + public override init(style: UITableView.Style) { super.init(style: style) navigationItem.title = NSLocalizedString("Me", comment: "Me page title") clearsSelectionOnViewWillAppear = false } - required convenience init() { + public required convenience init() { self.init(style: .insetGrouped) let notificationCenter = NotificationCenter.default notificationCenter.addObserver(self, selector: #selector(refreshModelWithNotification(_:)), name: .ZendeskPushNotificationReceivedNotification, object: nil) notificationCenter.addObserver(self, selector: #selector(refreshModelWithNotification(_:)), name: .ZendeskPushNotificationClearedNotification, object: nil) } - required init?(coder aDecoder: NSCoder) { + public required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } - override func viewDidLoad() { + public override func viewDidLoad() { super.viewDidLoad() if isSidebarModeEnabled { @@ -57,26 +57,26 @@ class MeViewController: UITableViewController { reloadViewModel() } - override func viewDidLayoutSubviews() { + public override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() tableView.layoutHeaderView() } - override func viewWillAppear(_ animated: Bool) { + public override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) refreshAccountDetailsAndSettings() animateDeselectionInteractively() } - override func viewDidAppear(_ animated: Bool) { + public override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) registerUserActivity() } - override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + public override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) // Required to update the tableview cell disclosure indicators @@ -238,7 +238,7 @@ class MeViewController: UITableViewController { // MARK: - UITableViewDelegate - override func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? { + public override func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? { let isNewSelection = (indexPath != tableView.indexPathForSelectedRow) if isNewSelection { @@ -347,15 +347,9 @@ class MeViewController: UITableViewController { } } - /// Selects the My Profile row and pushes the Support view controller - /// - @objc public func navigateToMyProfile() { - navigateToTarget(for: RowTitles.myProfile) - } - /// Selects the Account Settings row and pushes the Account Settings view controller /// - @objc public func navigateToAccountSettings() { + func navigateToAccountSettings() { navigateToTarget(for: RowTitles.accountSettings) } @@ -367,7 +361,7 @@ class MeViewController: UITableViewController { /// Selects the App Settings row and pushes the App Settings view controller /// - @objc public func navigateToAppSettings(completion: ((AppSettingsViewController) -> Void)? = nil) { + func navigateToAppSettings(completion: ((AppSettingsViewController) -> Void)? = nil) { self.selectRowForTitle(appSettingsRow.title) WPAppAnalytics.track(.openedAppSettings) let destination = AppSettingsViewController() @@ -378,7 +372,7 @@ class MeViewController: UITableViewController { /// Selects the Help & Support row and pushes the Support view controller /// - @objc public func navigateToHelpAndSupport() { + func navigateToHelpAndSupport() { navigateToTarget(for: RowTitles.support) } @@ -533,15 +527,15 @@ class MeViewController: UITableViewController { // MARK: - SearchableActivity Conformance extension MeViewController: SearchableActivityConvertable { - var activityType: String { + public var activityType: String { return WPActivityType.me.rawValue } - var activityTitle: String { + public var activityTitle: String { return NSLocalizedString("Me", comment: "Title of the 'Me' tab - used for spotlight indexing on iOS.") } - var activityKeywords: Set? { + public var activityKeywords: Set? { let keyWordString = NSLocalizedString("wordpress, me, settings, account, notification log out, logout, log in, login, help, support", comment: "This is a comma separated list of keywords used for spotlight indexing of the 'Me' tab.") let keywordArray = keyWordString.arrayOfTags() @@ -618,7 +612,7 @@ extension MeViewController: ShareAppContentPresenterDelegate { // MARK: - Jetpack powered badge extension MeViewController { - override func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? { + public override func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? { guard section == handler.viewModel.sections.count - 1, JetpackBrandingVisibility.all.enabled else { return nil diff --git a/WordPress/Classes/ViewRelated/Menus/Controllers/MenusViewController.swift b/WordPress/Classes/ViewRelated/Menus/Controllers/MenusViewController.swift index a96d3d08dae6..3168543a7717 100644 --- a/WordPress/Classes/ViewRelated/Menus/Controllers/MenusViewController.swift +++ b/WordPress/Classes/ViewRelated/Menus/Controllers/MenusViewController.swift @@ -5,7 +5,7 @@ extension MenusViewController { /// Fetch all pages from the site. /// /// - Returns: A block that can be used to cancel the fetching. - @objc func fetchAllPages(success: @escaping ([MenuItem]) -> Void, failure: @escaping (Error) -> Void) -> () -> Void { + @objc public func fetchAllPages(success: @escaping ([MenuItem]) -> Void, failure: @escaping (Error) -> Void) -> () -> Void { let coreDataStack = ContextManager.shared let repository = PostRepository(coreDataStack: coreDataStack) let fetchAllPagesTask = repository.fetchAllPages(statuses: [.publish], in: TaggedManagedObjectID(blog)) diff --git a/WordPress/Classes/ViewRelated/NUX/Helpers/WordPressAuthenticationManager.swift b/WordPress/Classes/ViewRelated/NUX/Helpers/WordPressAuthenticationManager.swift index 79717ca66580..6710ccaac9f4 100644 --- a/WordPress/Classes/ViewRelated/NUX/Helpers/WordPressAuthenticationManager.swift +++ b/WordPress/Classes/ViewRelated/NUX/Helpers/WordPressAuthenticationManager.swift @@ -8,7 +8,6 @@ import Gridicons // MARK: - WordPressAuthenticationManager // -@objc class WordPressAuthenticationManager: NSObject { static let WPSigninDidFinishNotification = WordPressAuthenticator.WPSigninDidFinishNotification @@ -196,8 +195,7 @@ extension WordPressAuthenticationManager { /// /// - Parameter onDismissed: Closure to be executed whenever the returned ViewController is dismissed. /// - @objc - class func signinForWPComFixingAuthToken(_ onDismissed: ((_ cancelled: Bool) -> Void)? = nil) -> UIViewController { + static func signinForWPComFixingAuthToken(_ onDismissed: ((_ cancelled: Bool) -> Void)? = nil) -> UIViewController { let context = ContextManager.shared.mainContext let account = try? WPAccount.lookupDefaultWordPressComAccount(in: context) @@ -207,8 +205,7 @@ extension WordPressAuthenticationManager { /// Presents the WordPress Authentication UI from the rootViewController (configured to allow only WordPress.com). /// This method pre-populates the Email + Username with the values returned by the default WordPress.com account (if any). /// - @objc - class func showSigninForWPComFixingAuthToken() { + static func showSigninForWPComFixingAuthToken() { guard let presenter = UIApplication.shared.mainWindow?.rootViewController else { assertionFailure() return diff --git a/WordPress/Classes/ViewRelated/Post/Categories/PostCategoriesViewController.swift b/WordPress/Classes/ViewRelated/Post/Categories/PostCategoriesViewController.swift index a4d517762612..57b92c76fdc2 100644 --- a/WordPress/Classes/ViewRelated/Post/Categories/PostCategoriesViewController.swift +++ b/WordPress/Classes/ViewRelated/Post/Categories/PostCategoriesViewController.swift @@ -2,19 +2,19 @@ import UIKit import SwiftUI import WordPressShared -@objc protocol PostCategoriesViewControllerDelegate { +@objc public protocol PostCategoriesViewControllerDelegate { @objc optional func postCategoriesViewController(_ controller: PostCategoriesViewController, didSelectCategory category: PostCategory) @objc optional func postCategoriesViewController(_ controller: PostCategoriesViewController, didUpdateSelectedCategories categories: NSSet) } -@objc enum CategoriesSelectionMode: Int { +@objc public enum CategoriesSelectionMode: Int { case post case parent case blogDefault } -@objc class PostCategoriesViewController: UITableViewController { - @objc weak var delegate: PostCategoriesViewControllerDelegate? +@objc public class PostCategoriesViewController: UITableViewController { + @objc public weak var delegate: PostCategoriesViewControllerDelegate? var onCategoriesChanged: (() -> Void)? @@ -28,24 +28,24 @@ import WordPressShared private var hasSyncedCategories = false - @objc init(blog: Blog, currentSelection: [PostCategory]?, selectionMode: CategoriesSelectionMode) { + @objc public init(blog: Blog, currentSelection: [PostCategory]?, selectionMode: CategoriesSelectionMode) { self.blog = blog self.selectionMode = selectionMode self.originalSelection = currentSelection super.init(style: .insetGrouped) } - required init?(coder: NSCoder) { + public required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } - override func viewDidLoad() { + public override func viewDidLoad() { super.viewDidLoad() configureTableView() configureView() } - override func viewWillAppear(_ animated: Bool) { + public override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) reloadCategories() if !hasSyncedCategories { @@ -53,7 +53,7 @@ import WordPressShared } } - override func viewWillDisappear(_ animated: Bool) { + public override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) onCategoriesChanged?() } @@ -191,11 +191,11 @@ import WordPressShared //tableView - override func numberOfSections(in tableView: UITableView) -> Int { + public override func numberOfSections(in tableView: UITableView) -> Int { return 1 } - override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + public override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { var result = categories.count if selectionMode == .parent { result = result + 1 @@ -203,7 +203,7 @@ import WordPressShared return result } - override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + public override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { guard let cell = tableView.dequeueReusableCell(withIdentifier: Constants.categoryCellIdentifier, for: indexPath) as? WPTableViewCell else { return UITableViewCell() } @@ -226,7 +226,7 @@ import WordPressShared return cell } - override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + public override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { if let currentSelectedIndexPath = tableView.indexPathForSelectedRow { tableView.deselectRow(at: currentSelectedIndexPath, animated: true) } diff --git a/WordPress/Classes/ViewRelated/Post/Categories/WPCategoryTree.swift b/WordPress/Classes/ViewRelated/Post/Categories/WPCategoryTree.swift index 274d11fca3eb..e651308c90ab 100644 --- a/WordPress/Classes/ViewRelated/Post/Categories/WPCategoryTree.swift +++ b/WordPress/Classes/ViewRelated/Post/Categories/WPCategoryTree.swift @@ -1,14 +1,14 @@ import Foundation -class WPCategoryTree: NSObject { +public class WPCategoryTree: NSObject { var parent: PostCategory? var children = [WPCategoryTree]() - @objc init(parent: PostCategory?) { + @objc public init(parent: PostCategory?) { self.parent = parent } - @objc func getChildrenFromObjects(_ collection: [Any]) { + @objc public func getChildrenFromObjects(_ collection: [Any]) { collection.forEach { guard let category = $0 as? PostCategory else { return @@ -22,7 +22,7 @@ class WPCategoryTree: NSObject { } } - @objc func getAllObjects() -> [PostCategory] { + @objc public func getAllObjects() -> [PostCategory] { var allObjects = [PostCategory]() if let parent { allObjects.append(parent) diff --git a/WordPress/Classes/ViewRelated/Post/PostAuthorSelectorViewController.swift b/WordPress/Classes/ViewRelated/Post/PostAuthorSelectorViewController.swift index 4d3145cb88c3..2f77f3183e90 100644 --- a/WordPress/Classes/ViewRelated/Post/PostAuthorSelectorViewController.swift +++ b/WordPress/Classes/ViewRelated/Post/PostAuthorSelectorViewController.swift @@ -1,15 +1,15 @@ import UIKit -@objc class PostAuthorSelectorViewController: SettingsSelectionViewController { +class PostAuthorSelectorViewController: SettingsSelectionViewController { /// A completion block that is called after the user selects an option. - @objc var completion: (() -> Void)? + var completion: (() -> Void)? /// Representation of an Author used by the view. private typealias Author = (displayName: String, userID: NSNumber, avatarURL: String?) // MARK: - Constructors - @objc init(_ post: AbstractPost) { + init(post: AbstractPost) { let authors = PostAuthorSelectorViewController.sortedActiveAuthors(for: post.blog) guard !authors.isEmpty, let currentAuthorID = post.authorID else { diff --git a/WordPress/Classes/ViewRelated/Post/PostSettingsViewController+JetpackSocial.swift b/WordPress/Classes/ViewRelated/Post/PostSettingsViewController+JetpackSocial.swift index 5dc4a84811fa..03a7df163f49 100644 --- a/WordPress/Classes/ViewRelated/Post/PostSettingsViewController+JetpackSocial.swift +++ b/WordPress/Classes/ViewRelated/Post/PostSettingsViewController+JetpackSocial.swift @@ -6,7 +6,7 @@ extension PostSettingsViewController { // MARK: - No connection view - @objc func showNoConnection() -> Bool { + @objc public func showNoConnection() -> Bool { let isJetpackSocialEnabled = RemoteFeatureFlag.jetpackSocialImprovements.enabled() let isNoConnectionViewHidden = UserPersistentStoreFactory.instance().bool(forKey: hideNoConnectionViewKey()) let blogSupportsPublicize = apost.blog.supportsPublicize() @@ -21,7 +21,7 @@ extension PostSettingsViewController { && !isPostPrivate } - @objc func createNoConnectionView() -> UIView { + @objc public func createNoConnectionView() -> UIView { WPAnalytics.track(.jetpackSocialNoConnectionCardDisplayed, properties: ["source": Constants.trackingSource]) let services = availableServices() @@ -37,7 +37,7 @@ extension PostSettingsViewController { // MARK: - Remaining shares view - @objc func showRemainingShares() -> Bool { + @objc public func showRemainingShares() -> Bool { let isJetpackSocialEnabled = RemoteFeatureFlag.jetpackSocialImprovements.enabled() let blogSupportsPublicize = apost.blog.supportsPublicize() let blogHasConnections = publicizeConnections.count > 0 @@ -50,7 +50,7 @@ extension PostSettingsViewController { && !isPostPrivate } - @objc func createRemainingSharesView() -> UIView { + @objc public func createRemainingSharesView() -> UIView { guard let sharingLimit = apost.blog.sharingLimit else { // This scenario *shouldn't* happen since we check that the publicize info is not nil before // showing this view @@ -74,7 +74,7 @@ extension PostSettingsViewController { // MARK: - Social share cells - @objc func userCanEditSharing() -> Bool { + @objc public func userCanEditSharing() -> Bool { guard let post = self.apost as? Post else { return false } @@ -85,7 +85,7 @@ extension PostSettingsViewController { return post.canEditPublicizeSettings() && remainingSocialShares() > 0 } - @objc func remainingSocialShares() -> Int { + @objc public func remainingSocialShares() -> Int { self.apost.blog.sharingLimit?.remaining ?? .max } diff --git a/WordPress/Classes/ViewRelated/Post/PostSettingsViewController+Swift.swift b/WordPress/Classes/ViewRelated/Post/PostSettingsViewController+Swift.swift index ca4003dea48d..a95b7afcf3af 100644 --- a/WordPress/Classes/ViewRelated/Post/PostSettingsViewController+Swift.swift +++ b/WordPress/Classes/ViewRelated/Post/PostSettingsViewController+Swift.swift @@ -25,11 +25,11 @@ extension PostSettingsViewController { presentingViewController.present(navigation, animated: true) } - @objc var isDraftOrPending: Bool { + @objc public var isDraftOrPending: Bool { apost.original().isStatus(in: [.draft, .pending]) } - @objc func onViewDidLoad() { + @objc public func onViewDidLoad() { if isStandalone { setupStandaloneEditor() } @@ -146,7 +146,7 @@ extension PostSettingsViewController: UIAdaptivePresentationControllerDelegate { // MARK: - PostSettingsViewController (Visibility) extension PostSettingsViewController { - @objc func showPostVisibilitySelector() { + @objc public func showPostVisibilitySelector() { let view = PostVisibilityPicker(selection: .init(post: apost)) { [weak self] selection in guard let self else { return } @@ -186,7 +186,7 @@ extension PostSettingsViewController { // MARK: - PostSettingsViewController (Publish Date) extension PostSettingsViewController { - @objc func showPublishDatePicker() { + @objc public func showPublishDatePicker() { var viewModel = PublishSettingsViewModel(post: self.apost) let viewController = PublishDatePickerViewController.make(viewModel: viewModel) { date in WPAnalytics.track(.editorPostScheduledChanged, properties: ["via": "settings"]) @@ -199,7 +199,7 @@ extension PostSettingsViewController { // MARK: - PostSettingsViewController (Page Attributes) extension PostSettingsViewController { - @objc func showParentPageController() { + @objc public func showParentPageController() { guard let page = (self.apost as? Page) else { wpAssertionFailure("post has to be a page") return @@ -234,7 +234,7 @@ extension PostSettingsViewController { } } - @objc func getParentPageTitle() -> String? { + @objc public func getParentPageTitle() -> String? { guard let page = (self.apost as? Page) else { wpAssertionFailure("post has to be a page") return nil @@ -252,10 +252,10 @@ extension PostSettingsViewController { } } -// MARK: - PostSettingsViewController (Featued Image) +// MARK: - PostSettingsViewController (Misc) extension PostSettingsViewController { - @objc func configureFeaturedImageCell(cell: UITableViewCell, viewModel: PostSettingsFeaturedImageViewModel) { + @objc public func configureFeaturedImageCell(cell: UITableViewCell, viewModel: PostSettingsFeaturedImageViewModel) { var configuration = UIHostingConfiguration { PostSettingsFeaturedImageCell(post: apost, viewModel: viewModel) { [weak self] in self?.showFeaturedImageSelector(cell: cell) @@ -276,6 +276,29 @@ extension PostSettingsViewController { lightboxVC.configureZoomTransition(sourceView: cell.contentView) present(lightboxVC, animated: true) } + + @objc public func showPostAuthorSelector() { + let authorVC = PostAuthorSelectorViewController(post: apost) + authorVC.completion = { [weak authorVC] in + WPAnalytics.track(.editorPostAuthorChanged, properties: ["via": "settings"]) + authorVC?.dismiss() // It pops VC + self.tableView.reloadData() + } + navigationController?.pushViewController(authorVC, animated: true) + } + + @objc public func showTagsPicker() { + guard let post = apost as? Post else { + return wpAssertionFailure("expected post type") + } + let tagsPickerVC = PostTagPickerViewController(tags: post.tags ?? "", blog: post.blog) + tagsPickerVC.onValueChanged = { value in + WPAnalytics.track(.editorPostTagsChanged, properties: ["via": "settings"]) + post.tags = value + } + WPAnalytics.track(.postSettingsAddTagsShown) + navigationController?.pushViewController(tagsPickerVC, animated: true) + } } private enum Strings { diff --git a/WordPress/Classes/ViewRelated/Post/PostSettingsViewController.m b/WordPress/Classes/ViewRelated/Post/PostSettingsViewController.m index 08c9e796bc8a..c18167d0cde4 100644 --- a/WordPress/Classes/ViewRelated/Post/PostSettingsViewController.m +++ b/WordPress/Classes/ViewRelated/Post/PostSettingsViewController.m @@ -770,18 +770,6 @@ - (WPTableViewCell *)getWPTableViewImageAndAccessoryCell return cell; } -- (void)showPostAuthorSelector -{ - PostAuthorSelectorViewController *vc = [[PostAuthorSelectorViewController alloc] init:self.apost]; - __weak PostAuthorSelectorViewController *weakVc = vc; - vc.completion = ^{ - [WPAnalytics trackEvent:WPAnalyticsEventEditorPostAuthorChanged properties:@{@"via": @"settings"}]; - [weakVc dismiss]; - [self.tableView reloadData]; - }; - [self.navigationController pushViewController:vc animated:YES]; -} - - (void)showPostFormatSelector { Post *post = self.post; @@ -962,22 +950,6 @@ - (void)showCategoriesSelection [self.navigationController pushViewController:controller animated:YES]; } - -- (void)showTagsPicker -{ - PostTagPickerViewController *tagsPicker = [[PostTagPickerViewController alloc] initWithTags:self.post.tags blog:self.post.blog]; - - tagsPicker.onValueChanged = ^(NSString * _Nonnull value) { - [WPAnalytics trackEvent:WPAnalyticsEventEditorPostTagsChanged properties:@{@"via": @"settings"}]; - - self.post.tags = value; - }; - - [WPAnalytics track:WPAnalyticsStatPostSettingsAddTagsShown]; - - [self.navigationController pushViewController:tagsPicker animated:YES]; -} - #pragma mark - Jetpack Social - (UITableViewCell *)configureGenericCellWith:(UIView *)view { diff --git a/WordPress/Classes/ViewRelated/Post/PostTagPickerViewController.swift b/WordPress/Classes/ViewRelated/Post/PostTagPickerViewController.swift index b827b8630b5b..f3ce14395318 100644 --- a/WordPress/Classes/ViewRelated/Post/PostTagPickerViewController.swift +++ b/WordPress/Classes/ViewRelated/Post/PostTagPickerViewController.swift @@ -3,12 +3,13 @@ import WordPressShared import WordPressUI class PostTagPickerViewController: UIViewController { + var onValueChanged: ((String) -> Void)? + let blog: Blog + private let originalTags: [String] - @objc var onValueChanged: ((String) -> Void)? - @objc let blog: Blog private let keyboardObserver = TableViewKeyboardObserver() - @objc init(tags: String, blog: Blog) { + init(tags: String, blog: Blog) { originalTags = PostTagPickerViewController.extractTags(from: tags) self.blog = blog @@ -26,6 +27,7 @@ class PostTagPickerViewController: UIViewController { private let textViewContainer = UIView() fileprivate let tableView = UITableView(frame: .zero, style: .grouped) private let descriptionLabel = UILabel() + fileprivate var dataSource: PostTagPickerDataSource = LoadingDataSource() { didSet { tableView.dataSource = dataSource diff --git a/WordPress/Classes/ViewRelated/Post/Views/PostSettingsFeaturedImageCell.swift b/WordPress/Classes/ViewRelated/Post/Views/PostSettingsFeaturedImageCell.swift index fb905a64c741..f2890f13382b 100644 --- a/WordPress/Classes/ViewRelated/Post/Views/PostSettingsFeaturedImageCell.swift +++ b/WordPress/Classes/ViewRelated/Post/Views/PostSettingsFeaturedImageCell.swift @@ -110,7 +110,7 @@ struct PostSettingsFeaturedImageCell: View { } } -final class PostSettingsFeaturedImageViewModel: NSObject, ObservableObject { +public final class PostSettingsFeaturedImageViewModel: NSObject, ObservableObject { @Published private(set) var upload: Media? let post: AbstractPost @@ -118,10 +118,10 @@ final class PostSettingsFeaturedImageViewModel: NSObject, ObservableObject { private var receipt: UUID? private let coordinator = MediaCoordinator.shared - @objc weak var tableView: UITableView? - @objc weak var delegate: FeaturedImageDelegate? + @objc public weak var tableView: UITableView? + @objc public weak var delegate: FeaturedImageDelegate? - @objc init(post: AbstractPost) { + @objc public init(post: AbstractPost) { self.post = post } diff --git a/WordPress/Classes/ViewRelated/Site Creation/Shared/UITableView+Header.swift b/WordPress/Classes/ViewRelated/Site Creation/Shared/UITableView+Header.swift index 74f5d135bb7a..fc0c8fc5f3b9 100644 --- a/WordPress/Classes/ViewRelated/Site Creation/Shared/UITableView+Header.swift +++ b/WordPress/Classes/ViewRelated/Site Creation/Shared/UITableView+Header.swift @@ -58,7 +58,7 @@ extension UITableView { /// /// Source: https://gist.github.com/smileyborg/50de5da1c921b73bbccf7f76b3694f6a /// - @objc func sizeToFitFooterView() { + @objc public func sizeToFitFooterView() { guard let tableFooterView else { return } diff --git a/WordPress/Classes/ViewRelated/Stats/Extensions/NoResultsViewController+StatsModule.swift b/WordPress/Classes/ViewRelated/Stats/Extensions/NoResultsViewController+StatsModule.swift index 514000f8d337..c25a6b546ade 100644 --- a/WordPress/Classes/ViewRelated/Stats/Extensions/NoResultsViewController+StatsModule.swift +++ b/WordPress/Classes/ViewRelated/Stats/Extensions/NoResultsViewController+StatsModule.swift @@ -5,14 +5,14 @@ import WordPressUI extension NoResultsViewController { - @objc func configureForStatsModuleDisabled() { + @objc public func configureForStatsModuleDisabled() { configure(title: Strings.statsModuleDisabled.title, buttonTitle: Strings.statsModuleDisabled.buttonTitle, subtitle: Strings.statsModuleDisabled.subtitle, image: Constants.statsImageName) } - @objc func configureForActivatingStatsModule() { + @objc public func configureForActivatingStatsModule() { configure(title: Strings.activatingStatsModule.title, accessoryView: NoResultsViewController.loadingAccessoryView()) view.layoutIfNeeded() } diff --git a/WordPress/Classes/ViewRelated/Stats/Extensions/StatsViewController+JetpackSettings.swift b/WordPress/Classes/ViewRelated/Stats/Extensions/StatsViewController+JetpackSettings.swift index 7aa8f1611f4c..16fd3e41d520 100644 --- a/WordPress/Classes/ViewRelated/Stats/Extensions/StatsViewController+JetpackSettings.swift +++ b/WordPress/Classes/ViewRelated/Stats/Extensions/StatsViewController+JetpackSettings.swift @@ -3,7 +3,7 @@ import UIKit extension StatsViewController { - @objc func activateStatsModule(success: @escaping () -> Void, failure: @escaping (Error?) -> Void) { + @objc public func activateStatsModule(success: @escaping () -> Void, failure: @escaping (Error?) -> Void) { guard let blog else { return } diff --git a/WordPress/Classes/ViewRelated/Stats/Helpers/SiteStatsInformation.swift b/WordPress/Classes/ViewRelated/Stats/Helpers/SiteStatsInformation.swift index 3b797ea91ead..65a14fd4ba9f 100644 --- a/WordPress/Classes/ViewRelated/Stats/Helpers/SiteStatsInformation.swift +++ b/WordPress/Classes/ViewRelated/Stats/Helpers/SiteStatsInformation.swift @@ -3,18 +3,18 @@ import WordPressShared /// Singleton class to contain site related information for Stats. /// -@objc class SiteStatsInformation: NSObject { +@objc public class SiteStatsInformation: NSObject { // MARK: - Properties typealias SiteInsights = [String: [Int]] private let userDefaultsInsightTypesKey = "StatsInsightTypes" - @objc static var sharedInstance: SiteStatsInformation = SiteStatsInformation() + @objc public static var sharedInstance: SiteStatsInformation = SiteStatsInformation() private override init() {} - @objc var siteID: NSNumber? - @objc var siteTimeZone: TimeZone? - @objc var oauth2Token: String? - @objc var supportsFileDownloads: Bool = true + @objc public var siteID: NSNumber? + @objc public var siteTimeZone: TimeZone? + @objc public var oauth2Token: String? + @objc public var supportsFileDownloads: Bool = true func updateTimeZone() { let context = ContextManager.shared.mainContext diff --git a/WordPress/Classes/ViewRelated/Stats/SiteStatsDashboardViewController.swift b/WordPress/Classes/ViewRelated/Stats/SiteStatsDashboardViewController.swift index d662747117fb..a709208c5ccb 100644 --- a/WordPress/Classes/ViewRelated/Stats/SiteStatsDashboardViewController.swift +++ b/WordPress/Classes/ViewRelated/Stats/SiteStatsDashboardViewController.swift @@ -43,7 +43,7 @@ fileprivate extension StatsTabType { } } -class SiteStatsDashboardViewController: UIViewController { +public class SiteStatsDashboardViewController: UIViewController { static let lastSelectedStatsDateKey = "LastSelectedStatsDate" // MARK: - Properties @@ -54,7 +54,7 @@ class SiteStatsDashboardViewController: UIViewController { private var pageViewController: UIPageViewController? private lazy var displayedTabs: [StatsTabType] = StatsTabType.displayedTabs - @objc lazy var manageInsightsButton: UIBarButtonItem = { + @objc public lazy var manageInsightsButton: UIBarButtonItem = { let button = UIBarButtonItem( image: UIImage(systemName: "gearshape"), style: .plain, @@ -95,7 +95,7 @@ class SiteStatsDashboardViewController: UIViewController { // MARK: - View - override func viewDidLoad() { + public override func viewDidLoad() { super.viewDidLoad() // Important to make navigation bar match the filter bar @@ -109,7 +109,7 @@ class SiteStatsDashboardViewController: UIViewController { view.accessibilityIdentifier = "stats-dashboard" } - override func viewWillAppear(_ animated: Bool) { + public override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) addWillEnterForegroundObserver() JetpackFeaturesRemovalCoordinator.presentOverlayIfNeeded(in: self, source: .stats) @@ -131,16 +131,16 @@ class SiteStatsDashboardViewController: UIViewController { } } - @objc func manageInsightsButtonTapped() { + @objc public func manageInsightsButtonTapped() { insightsTableViewController.showAddInsightView(source: "nav_bar") } - override func viewWillDisappear(_ animated: Bool) { + public override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) removeWillEnterForegroundObserver() } - override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + public override func prepare(for segue: UIStoryboardSegue, sender: Any?) { switch segue.destination { case let pageViewController as UIPageViewController: self.pageViewController = pageViewController @@ -149,7 +149,7 @@ class SiteStatsDashboardViewController: UIViewController { } } - override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { + public override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { if traitCollection.verticalSizeClass == .regular, traitCollection.horizontalSizeClass == .compact { updatePeriodView(oldSelectedTab: currentSelectedTab) } diff --git a/WordPress/Classes/ViewRelated/Stats/StatsViewController.m b/WordPress/Classes/ViewRelated/Stats/StatsViewController.m index fc2393fb552b..229e587245f7 100644 --- a/WordPress/Classes/ViewRelated/Stats/StatsViewController.m +++ b/WordPress/Classes/ViewRelated/Stats/StatsViewController.m @@ -74,8 +74,9 @@ - (void)viewDidLoad - (void)viewDidAppear:(BOOL)animated { - // Track as significant event for App Rating calculations - [[AppRatingUtility shared] incrementSignificantEvent]; + [super viewDidAppear:animated]; + + [ObjCBridge incrementSignificantEvent]; } - (void)setBlog:(Blog *)blog diff --git a/WordPress/Classes/ViewRelated/Suggestions/SuggestionViewModel.swift b/WordPress/Classes/ViewRelated/Suggestions/SuggestionViewModel.swift index d9c16eae5882..0c48f01d6a79 100644 --- a/WordPress/Classes/ViewRelated/Suggestions/SuggestionViewModel.swift +++ b/WordPress/Classes/ViewRelated/Suggestions/SuggestionViewModel.swift @@ -1,11 +1,11 @@ import Foundation -@objc final class SuggestionViewModel: NSObject { +@objc public final class SuggestionViewModel: NSObject { - @objc private(set) var title: String? + @objc public private(set) var title: String? - @objc let subtitle: String? - @objc let imageURL: URL? + @objc public let subtitle: String? + @objc public let imageURL: URL? init(suggestion: UserSuggestion) { if let username = suggestion.username { diff --git a/WordPress/Classes/ViewRelated/Suggestions/SuggestionsListViewModel.swift b/WordPress/Classes/ViewRelated/Suggestions/SuggestionsListViewModel.swift index 0e2b79cb9992..16a2960a8326 100644 --- a/WordPress/Classes/ViewRelated/Suggestions/SuggestionsListViewModel.swift +++ b/WordPress/Classes/ViewRelated/Suggestions/SuggestionsListViewModel.swift @@ -1,12 +1,12 @@ import Foundation import CoreData -@objc final class SuggestionsListSection: NSObject { - @objc var title: String? - @objc var rows: [SuggestionViewModel] = [] +@objc public final class SuggestionsListSection: NSObject { + @objc public var title: String? + @objc public var rows: [SuggestionViewModel] = [] } -@objc final class SuggestionsListViewModel: NSObject, SuggestionsListViewModelType { +@objc public final class SuggestionsListViewModel: NSObject, SuggestionsListViewModelType { // MARK: - Dependencies @@ -16,13 +16,13 @@ import CoreData // MARK: - Configuration - @objc var suggestionType: SuggestionType = .mention { + @objc public var suggestionType: SuggestionType = .mention { didSet { self.searchSuggestions(withWord: searchText) } } - @objc var prominentSuggestionsIds: [NSNumber]? { + @objc public var prominentSuggestionsIds: [NSNumber]? { didSet { self.searchSuggestions(withWord: searchText) } @@ -34,8 +34,8 @@ import CoreData // MARK: - State - @objc private(set) var isLoading = false - @objc private(set) var sections = [SuggestionsListSection]() + @objc public private(set) var isLoading = false + @objc public private(set) var sections = [SuggestionsListSection]() private(set) var suggestions = Suggestions.users([]) @@ -45,12 +45,12 @@ import CoreData return suggestionType.trigger } - @objc private(set) var searchText: String = "" + @objc public private(set) var searchText: String = "" // MARK: - Callback /// Called when the search result is updated. - @objc var searchResultUpdated: StateUpdatedHandler? + @objc public var searchResultUpdated: StateUpdatedHandler? // MARK: - Init @@ -58,7 +58,7 @@ import CoreData self.blog = blog } - @objc convenience init(siteID: NSNumber, context: NSManagedObjectContext = ContextManager.shared.mainContext) { + @objc public convenience init(siteID: NSNumber, context: NSManagedObjectContext = ContextManager.shared.mainContext) { let blog = Blog.lookup(withID: siteID, in: context) self.init(blog: blog) self.context = context @@ -84,7 +84,7 @@ import CoreData // MARK: - Load Data - @objc func reloadData() { + @objc public func reloadData() { guard let blog = self.blog else { return } self.isLoading = true switch suggestionType { @@ -110,7 +110,7 @@ import CoreData /// Searches suggestions for the given word. /// - Parameter word: The suggestions that contain this word. /// - Returns: True when there is at least one suggestion. - @discardableResult @objc func searchSuggestions(withWord word: String) -> Bool { + @discardableResult @objc public func searchSuggestions(withWord word: String) -> Bool { if word.hasPrefix(suggestionTrigger) { let searchQuery = NSString(string: word).substring(from: suggestionTrigger.count) self.searchText = word @@ -238,7 +238,7 @@ import CoreData // MARK: - Types - typealias StateUpdatedHandler = (SuggestionsListViewModelType) -> Void + public typealias StateUpdatedHandler = (SuggestionsListViewModelType) -> Void } diff --git a/WordPress/Classes/ViewRelated/Suggestions/SuggestionsTableView.m b/WordPress/Classes/ViewRelated/Suggestions/SuggestionsTableView.m index 5bc95ce95250..ba13c6b78770 100644 --- a/WordPress/Classes/ViewRelated/Suggestions/SuggestionsTableView.m +++ b/WordPress/Classes/ViewRelated/Suggestions/SuggestionsTableView.m @@ -235,11 +235,9 @@ - (void)updateConstraints [self.tableView setNeedsLayout]; [self.tableView layoutIfNeeded]; if (maxRows) { - self.heightConstraint.constant = [SuggestionsTableView maximumHeightForTableView:self.tableView - maxNumberOfRowsToDisplay:maxRows]; + self.heightConstraint.constant = [SuggestionsTableView maximumHeightForTableView:self.tableView maxNumberOfRowsToDisplay:maxRows]; } else { - self.heightConstraint.constant = [SuggestionsTableView heightForTableView:self.tableView - maximumHeight:self.bounds.size.height - minimumHeaderHeight]; + self.heightConstraint.constant = [SuggestionsTableView heightForTableView:self.tableView maximumHeight:self.bounds.size.height - minimumHeaderHeight]; } [super updateConstraints]; } diff --git a/WordPress/Classes/ViewRelated/Suggestions/SuggestionsTableView.swift b/WordPress/Classes/ViewRelated/Suggestions/SuggestionsTableView.swift index a6482ca7a5aa..90f001f6b6b7 100644 --- a/WordPress/Classes/ViewRelated/Suggestions/SuggestionsTableView.swift +++ b/WordPress/Classes/ViewRelated/Suggestions/SuggestionsTableView.swift @@ -80,13 +80,13 @@ extension SuggestionType { /// Returns the ideal height for the table view that displays all sections and rows as long as this height doesn't exceed the given `maximumHeight`. /// - static func height(forTableView tableView: UITableView, maximumHeight height: CGFloat) -> CGFloat { + public static func height(forTableView tableView: UITableView, maximumHeight height: CGFloat) -> CGFloat { return min(height, tableView.contentSize.height) } /// Returns the ideal height for the table view to display the given number of rows. /// - static func maximumHeight(forTableView tableView: UITableView, maxNumberOfRowsToDisplay maxRows: NSNumber) -> CGFloat { + public static func maximumHeight(forTableView tableView: UITableView, maxNumberOfRowsToDisplay maxRows: NSNumber) -> CGFloat { guard let maxRowIndexPath = indexPath(forRowAtPosition: maxRows.intValue, in: tableView) else { return 0 } diff --git a/WordPress/Classes/ViewRelated/Suggestions/SuggestionsViewModelType.swift b/WordPress/Classes/ViewRelated/Suggestions/SuggestionsViewModelType.swift index 81e742c4afcd..a407fd5e0a0e 100644 --- a/WordPress/Classes/ViewRelated/Suggestions/SuggestionsViewModelType.swift +++ b/WordPress/Classes/ViewRelated/Suggestions/SuggestionsViewModelType.swift @@ -1,6 +1,6 @@ import Foundation -@objc protocol SuggestionsListViewModelType: AnyObject { +@objc public protocol SuggestionsListViewModelType: AnyObject { var suggestionType: SuggestionType { get set } var prominentSuggestionsIds: [NSNumber]? { get set } diff --git a/WordPress/Classes/ViewRelated/Support/SupportConfiguration.swift b/WordPress/Classes/ViewRelated/Support/SupportConfiguration.swift index 5076dfb3edb5..7cb76d986993 100644 --- a/WordPress/Classes/ViewRelated/Support/SupportConfiguration.swift +++ b/WordPress/Classes/ViewRelated/Support/SupportConfiguration.swift @@ -25,10 +25,8 @@ enum SupportConfiguration { ) -> Bool { return isJetpack && migrationState == .completed } -} -@objc class SupportConfigurationObjC: NSObject { - @objc static var isStartOverSupportEnabled: Bool { - return SupportConfiguration.current() == .zendesk + static var isStartOverSupportEnabled: Bool { + SupportConfiguration.current() == .zendesk } } diff --git a/WordPress/Classes/ViewRelated/Support/SupportTableViewController.swift b/WordPress/Classes/ViewRelated/Support/SupportTableViewController.swift index 8464697a3f89..5315c70f0440 100644 --- a/WordPress/Classes/ViewRelated/Support/SupportTableViewController.swift +++ b/WordPress/Classes/ViewRelated/Support/SupportTableViewController.swift @@ -44,10 +44,6 @@ class SupportTableViewController: UITableViewController { self.dismissTapped = dismissTapped } - @objc public convenience init() { - self.init(configuration: .init(), style: .insetGrouped) - } - // MARK: - View override func viewDidLoad() { @@ -94,7 +90,7 @@ class SupportTableViewController: UITableViewController { } // TODO: Refactor this method to use the general `show(from:)` method - @objc func showFromTabBar() { + func showFromTabBar() { let navigationController = UINavigationController.init(rootViewController: self) if WPDeviceIdentification.isiPad() { diff --git a/WordPress/Classes/ViewRelated/System/FilterTabBar.swift b/WordPress/Classes/ViewRelated/System/FilterTabBar.swift index bb0376166c77..f2191c3cb8c3 100644 --- a/WordPress/Classes/ViewRelated/System/FilterTabBar.swift +++ b/WordPress/Classes/ViewRelated/System/FilterTabBar.swift @@ -28,7 +28,7 @@ extension FilterTabBarItem where Self: RawRepresentable { } } -class FilterTabBar: UIControl { +public class FilterTabBar: UIControl { private let scrollView: UIScrollView = { let scrollView = UIScrollView() scrollView.translatesAutoresizingMaskIntoConstraints = false @@ -107,7 +107,7 @@ class FilterTabBar: UIControl { /// If selectedTitleColor is not provided, tint color will also be applied to /// titles of selected tabs. /// - override var tintColor: UIColor! { + public override var tintColor: UIColor! { didSet { tabs.forEach({ $0.tintColor = tintColor @@ -229,13 +229,13 @@ class FilterTabBar: UIControl { var tabSeparatorPadding: CGFloat = AppearanceMetrics.buttonPadding // MARK: - Initialization - required init?(coder aDecoder: NSCoder) { + public required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) commonInit() } - init() { + public init() { super.init(frame: .zero) translatesAutoresizingMaskIntoConstraints = false commonInit() @@ -284,7 +284,7 @@ class FilterTabBar: UIControl { activateTabSeparatorPlacementConstraints() } - override func layoutSubviews() { + public override func layoutSubviews() { super.layoutSubviews() updateForCurrentEnvironment() @@ -555,7 +555,7 @@ class FilterTabBar: UIControl { static let initialVelocity: CGFloat = -0.5 } - override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + public override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) if isAutomaticTabSizingStyleEnabled { diff --git a/WordPress/Classes/ViewRelated/System/WPTabBarController+MeTab.swift b/WordPress/Classes/ViewRelated/System/WPTabBarController+MeTab.swift index 8429125f5e49..27f8f9fc8ef0 100644 --- a/WordPress/Classes/ViewRelated/System/WPTabBarController+MeTab.swift +++ b/WordPress/Classes/ViewRelated/System/WPTabBarController+MeTab.swift @@ -9,7 +9,7 @@ extension WPTabBarController { try? WPAccount.lookupDefaultWordPressComAccount(in: ContextManager.shared.mainContext) } - @objc func observeGravatarImageUpdate() { + @objc public func observeGravatarImageUpdate() { NotificationCenter.default.addObserver(self, selector: #selector(refreshAvatar(_:)), name: .GravatarQEAvatarUpdateNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(updateGravatarImage(_:)), name: .GravatarImageUpdateNotification, object: nil) @@ -19,7 +19,7 @@ extension WPTabBarController { NotificationCenter.default.addObserver(self, selector: #selector(accountDidChange), name: .WPAccountEmailAndDefaultBlogUpdated, object: nil) } - @objc func configureMeTabImage(placeholderImage: UIImage?) { + @objc public func configureMeTabImage(placeholderImage: UIImage?) { meNavigationController.tabBarItem.image = placeholderImage downloadImage() } diff --git a/WordPress/Classes/ViewRelated/System/WPTabBarController+Swift.swift b/WordPress/Classes/ViewRelated/System/WPTabBarController+Swift.swift index 1c1d4b6c4c3a..9992eb43c43a 100644 --- a/WordPress/Classes/ViewRelated/System/WPTabBarController+Swift.swift +++ b/WordPress/Classes/ViewRelated/System/WPTabBarController+Swift.swift @@ -23,7 +23,7 @@ import WordPressShared } extension WPTabBarController { - @objc class func readerLocalizedTitle() -> String { + @objc public class func readerLocalizedTitle() -> String { SharedStrings.Reader.title } @@ -57,7 +57,7 @@ extension WPTabBarController { } } - @objc func startObserversForTabAccessTracking() { + @objc public func startObserversForTabAccessTracking() { let nc = NotificationCenter.default nc.addObserver(self, selector: #selector(trackTabAccessOnAppDidBecomeActive), @@ -69,14 +69,14 @@ extension WPTabBarController { object: nil) } - @objc func trackTabAccessOnAppDidBecomeActive() { + @objc public func trackTabAccessOnAppDidBecomeActive() { trackTabAccessForTabIndex(selectedIndex) } /// Reset `shouldTrackTabAccessOnViewDidAppear` if the user has logged out. /// /// This allows us to track tab access on `-viewDidAppear` when the user logs back in again. - @objc func resetViewDidAppearFlagOnWPComAccountChange(_ notification: NSNotification) { + @objc public func resetViewDidAppearFlagOnWPComAccountChange(_ notification: NSNotification) { guard notification.object == nil else { return } @@ -87,7 +87,7 @@ extension WPTabBarController { /// Track tab access on viewDidAppear but only once. /// /// This covers the scenario when the user has just logged in. - @objc func trackTabAccessOnViewDidAppear() { + @objc public func trackTabAccessOnViewDidAppear() { guard shouldTrackTabAccessOnViewDidAppear else { return } @@ -163,6 +163,12 @@ extension WPTabBarController { bounceAnimation.calculationMode = CAAnimationCalculationMode.cubic imageView.layer.add(bounceAnimation, forKey: nil) } + + @objc public func switchNotificationsTabToNotificationSettings() { + showNotificationsTab() + notificationsNavigationController?.popToRootViewController(animated: false) + notificationsViewController?.showNotificationSettings() + } } private extension UIView { diff --git a/WordPress/Classes/ViewRelated/System/WPTabBarController.h b/WordPress/Classes/ViewRelated/System/WPTabBarController.h index 92f353ef70dc..8d73e46e7e7b 100644 --- a/WordPress/Classes/ViewRelated/System/WPTabBarController.h +++ b/WordPress/Classes/ViewRelated/System/WPTabBarController.h @@ -21,6 +21,7 @@ extern NSNotificationName const WPTabBarHeightChangedNotification; @interface WPTabBarController : UITabBarController @property (nonatomic, strong, readonly, nullable) NotificationsViewController *notificationsViewController; +@property (nonatomic, strong, readonly, nullable) UINavigationController *notificationsNavigationController; @property (nonatomic, strong, readonly, nullable) UINavigationController *readerNavigationController; @property (nonatomic, strong, readonly, nonnull) MeViewController *meViewController; @property (nonatomic, strong, readonly, nonnull) UINavigationController *meNavigationController; diff --git a/WordPress/Classes/ViewRelated/System/WPTabBarController.m b/WordPress/Classes/ViewRelated/System/WPTabBarController.m index 5c745c04dfd1..142b5a4defe2 100644 --- a/WordPress/Classes/ViewRelated/System/WPTabBarController.m +++ b/WordPress/Classes/ViewRelated/System/WPTabBarController.m @@ -270,14 +270,6 @@ - (void)popNotificationsTabToRoot [self.notificationsNavigationController popToRootViewControllerAnimated:NO]; } -- (void)switchNotificationsTabToNotificationSettings -{ - [self showNotificationsTab]; - [self.notificationsNavigationController popToRootViewControllerAnimated:NO]; - - [self.notificationsViewController showNotificationSettings]; -} - - (NSString *)currentlySelectedScreen { // Check which tab is currently selected @@ -365,7 +357,7 @@ - (void)updateNotificationBadgeVisibility } // Discount Zendesk unread notifications when determining if we need to show the notificationsTabBarImageUnread. - NSInteger count = [[UIApplication sharedApplication] applicationIconBadgeNumber] - [ZendeskUtils unreadNotificationsCount]; + NSInteger count = [[UIApplication sharedApplication] applicationIconBadgeNumber] - ObjCBridge.unreadNotificationsCount; if (count > 0 || ![self welcomeNotificationSeen]) { notificationsTabBarItem.image = self.notificationsTabBarImageUnread; notificationsTabBarItem.accessibilityLabel = NSLocalizedString(@"Notifications Unread", @"Notifications tab bar item accessibility label, unread notifications state"); diff --git a/WordPress/Classes/ViewRelated/Themes/ThemeBrowserViewController.swift b/WordPress/Classes/ViewRelated/Themes/ThemeBrowserViewController.swift index 6c1b64163a49..fce40b5c9ac5 100644 --- a/WordPress/Classes/ViewRelated/Themes/ThemeBrowserViewController.swift +++ b/WordPress/Classes/ViewRelated/Themes/ThemeBrowserViewController.swift @@ -508,7 +508,7 @@ public protocol ThemePresenter: AnyObject { // MARK: - WPContentSyncHelperDelegate - func syncHelper(_ syncHelper: WPContentSyncHelper, syncContentWithUserInteraction userInteraction: Bool, success: ((_ hasMore: Bool) -> Void)?, failure: ((_ error: NSError) -> Void)?) { + public func syncHelper(_ syncHelper: WPContentSyncHelper, syncContentWithUserInteraction userInteraction: Bool, success: ((_ hasMore: Bool) -> Void)?, failure: ((_ error: NSError) -> Void)?) { if syncHelper == themesSyncHelper { syncThemePage(1, search: searchName, success: success, failure: failure) } else if syncHelper == customThemesSyncHelper { @@ -516,14 +516,14 @@ public protocol ThemePresenter: AnyObject { } } - func syncHelper(_ syncHelper: WPContentSyncHelper, syncMoreWithSuccess success: ((_ hasMore: Bool) -> Void)?, failure: ((_ error: NSError) -> Void)?) { + public func syncHelper(_ syncHelper: WPContentSyncHelper, syncMoreWithSuccess success: ((_ hasMore: Bool) -> Void)?, failure: ((_ error: NSError) -> Void)?) { if syncHelper == themesSyncHelper { let nextPage = themesSyncingPage + 1 syncThemePage(nextPage, search: searchName, success: success, failure: failure) } } - func syncContentEnded(_ syncHelper: WPContentSyncHelper) { + public func syncContentEnded(_ syncHelper: WPContentSyncHelper) { updateResults() let lastVisibleTheme = collectionView?.indexPathsForVisibleItems.last ?? IndexPath(item: 0, section: 0) if syncHelper == themesSyncHelper { @@ -531,7 +531,7 @@ public protocol ThemePresenter: AnyObject { } } - func hasNoMoreContent(_ syncHelper: WPContentSyncHelper) { + public func hasNoMoreContent(_ syncHelper: WPContentSyncHelper) { if syncHelper == themesSyncHelper { themesSyncingPage = 0 } diff --git a/WordPress/Classes/ViewRelated/Views/List/ListTableHeaderView.swift b/WordPress/Classes/ViewRelated/Views/List/ListTableHeaderView.swift index c5929d532ac0..309c569e98de 100644 --- a/WordPress/Classes/ViewRelated/Views/List/ListTableHeaderView.swift +++ b/WordPress/Classes/ViewRelated/Views/List/ListTableHeaderView.swift @@ -7,7 +7,7 @@ import WordPressShared /// This is used in Comments and Notifications as part of the Comments /// Unification project. /// -class ListTableHeaderView: UITableViewHeaderFooterView, NibReusable { +public class ListTableHeaderView: UITableViewHeaderFooterView, NibReusable { // MARK: IBOutlets @IBOutlet private weak var separatorsView: SeparatorsView! @@ -17,11 +17,11 @@ class ListTableHeaderView: UITableViewHeaderFooterView, NibReusable { /// Added to provide objc support, since NibReusable protocol methods aren't accessible from objc. /// This should be removed when the caller is rewritten in Swift. - @objc static let reuseIdentifier = defaultReuseID + @objc public static let reuseIdentifier = defaultReuseID - @objc static let estimatedRowHeight = 26 + @objc public static let estimatedRowHeight = 26 - @objc var title: String? { + @objc public var title: String? { get { titleLabel.text } @@ -33,7 +33,7 @@ class ListTableHeaderView: UITableViewHeaderFooterView, NibReusable { // MARK: Initialization - override func awakeFromNib() { + public override func awakeFromNib() { super.awakeFromNib() // Hide text label to prevent values being shown due to interaction with diff --git a/WordPress/Classes/ViewRelated/Views/List/ListTableViewCell.swift b/WordPress/Classes/ViewRelated/Views/List/ListTableViewCell.swift index 070ef96703ba..ebc322040962 100644 --- a/WordPress/Classes/ViewRelated/Views/List/ListTableViewCell.swift +++ b/WordPress/Classes/ViewRelated/Views/List/ListTableViewCell.swift @@ -8,7 +8,7 @@ import WordPressShared /// This is used in Comments and Notifications as part of the Comments /// Unification project. /// -class ListTableViewCell: UITableViewCell, NibReusable { +public class ListTableViewCell: UITableViewCell, NibReusable { // MARK: IBOutlets @IBOutlet private weak var indicatorView: UIView! @@ -25,30 +25,30 @@ class ListTableViewCell: UITableViewCell, NibReusable { /// Added to provide objc support, since NibReusable protocol methods aren't accessible from objc. /// This should be removed when the caller is rewritten in Swift. - @objc static let reuseIdentifier = defaultReuseID + @objc public static let reuseIdentifier = defaultReuseID - @objc static let estimatedRowHeight = 68 + @objc public static let estimatedRowHeight = 68 /// The color of the indicator circle. - @objc var indicatorColor: UIColor = .clear { + @objc public var indicatorColor: UIColor = .clear { didSet { updateIndicatorColor() } } /// Toggle variable to determine whether the indicator circle should be shown. - @objc var showsIndicator: Bool = false { + @objc public var showsIndicator: Bool = false { didSet { updateIndicatorColor() } } /// The default placeholder image. - @objc var placeholderImage: UIImage = Style.placeholderImage + @objc public var placeholderImage: UIImage = Style.placeholderImage /// The attributed string to be displayed in titleLabel. /// To keep the styles uniform between List components, refer to regular and bold styles in `WPStyleGuide+List`. - @objc var attributedTitleText: NSAttributedString? { + @objc public var attributedTitleText: NSAttributedString? { get { titleLabel.attributedText } @@ -59,7 +59,7 @@ class ListTableViewCell: UITableViewCell, NibReusable { /// The snippet text, displayed in snippetLabel. /// Note that new values are trimmed of whitespaces and newlines. - @objc var snippetText: String? { + @objc public var snippetText: String? { get { snippetLabel.text } @@ -76,7 +76,7 @@ class ListTableViewCell: UITableViewCell, NibReusable { // MARK: Initialization - override func awakeFromNib() { + public override func awakeFromNib() { super.awakeFromNib() configureSubviews() }