From d4ca97f1de3a896bd0fa4e0ea96182d194f4271b Mon Sep 17 00:00:00 2001 From: Diego Rey Mendez Date: Wed, 8 May 2019 17:42:03 -0300 Subject: [PATCH 1/6] Adds ClosureGroup to the project. --- .../Utility/ClosureGroup/ClosureGroup.swift | 49 +++++++++++++++++++ WordPress/WordPress.xcodeproj/project.pbxproj | 12 +++++ 2 files changed, 61 insertions(+) create mode 100644 WordPress/Classes/Utility/ClosureGroup/ClosureGroup.swift diff --git a/WordPress/Classes/Utility/ClosureGroup/ClosureGroup.swift b/WordPress/Classes/Utility/ClosureGroup/ClosureGroup.swift new file mode 100644 index 000000000000..45d787d34af6 --- /dev/null +++ b/WordPress/Classes/Utility/ClosureGroup/ClosureGroup.swift @@ -0,0 +1,49 @@ +import Foundation + +/// This class offers a generic mechanism to group closures and execute them. +/// This can be very useful to group together logic that needs to be executed +/// as a result of events. +/// +/// As an example: you can have an instance of this class to run code +/// whenever Reachability detects the App is online and whenever the App +/// comes to the foreground. +/// +class ClosureGroup { + + /// Just a typealias for readability. + /// + typealias Closure = () -> () + + /// The closures that have been registered. + /// + private var closures = [String: Closure]() + + // MARK: - Running the closure group + + /// Runs all registered closures. + /// + func run() { + for (_, closure) in closures { + closure() + } + } + + // MARK: - Registering and Unregistering closures. + + /// Registers a closure for running in this group. + /// + func register(identifier: String, closure: @escaping Closure) { + guard closures[identifier] == nil else { + assertionFailure("We shouldn't be adding two closures with the same identifier to the same group.") + return + } + + closures[identifier] = closure + } + + /// Unregisters a closure from this group. + /// + func unregister(identifier: String) { + closures.removeValue(forKey: identifier) + } +} diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index a9350ddc2b97..95eb0018df48 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -1698,6 +1698,7 @@ E8DEE110E4BC3FA1974AB1BB /* Pods_WordPressTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B921F5DD9A1F257C792EC225 /* Pods_WordPressTest.framework */; }; F10E655021B0613A007AB2EE /* GutenbergViewController+MoreActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F10E654F21B06139007AB2EE /* GutenbergViewController+MoreActions.swift */; }; F115308121B17E66002F1D65 /* EditorFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = F115308021B17E65002F1D65 /* EditorFactory.swift */; }; + F125314D22836B93007D4F2C /* ClosureGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = F125314C22836B93007D4F2C /* ClosureGroup.swift */; }; F126FE0020A33BDB0010EB6E /* VideoUploadProcessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = F126FDFD20A33BDB0010EB6E /* VideoUploadProcessor.swift */; }; F126FE0220A33BDB0010EB6E /* DocumentUploadProcessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = F126FDFF20A33BDB0010EB6E /* DocumentUploadProcessor.swift */; }; F128C31C1AFCC95B008C2404 /* WPNavigationMediaPickerViewController+StatusBarStyle.m in Sources */ = {isa = PBXBuildFile; fileRef = F128C31B1AFCC95B008C2404 /* WPNavigationMediaPickerViewController+StatusBarStyle.m */; }; @@ -3893,6 +3894,7 @@ F10E654F21B06139007AB2EE /* GutenbergViewController+MoreActions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "GutenbergViewController+MoreActions.swift"; sourceTree = ""; }; F115308021B17E65002F1D65 /* EditorFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EditorFactory.swift; sourceTree = ""; }; F117E5841F7AA8BF003D9ACB /* WordPress 67.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "WordPress 67.xcdatamodel"; sourceTree = ""; }; + F125314C22836B93007D4F2C /* ClosureGroup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClosureGroup.swift; sourceTree = ""; }; F126FDFD20A33BDB0010EB6E /* VideoUploadProcessor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VideoUploadProcessor.swift; sourceTree = ""; }; F126FDFE20A33BDB0010EB6E /* ImgUploadProcessor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImgUploadProcessor.swift; sourceTree = ""; }; F126FDFF20A33BDB0010EB6E /* DocumentUploadProcessor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DocumentUploadProcessor.swift; sourceTree = ""; }; @@ -6109,6 +6111,7 @@ isa = PBXGroup; children = ( 40247E002120FE2300AE1C3C /* Automated Transfer */, + F125314B22836AC6007D4F2C /* ClosureGroup */, F198533821ADAA4E00DCDAE7 /* Editor */, 7E58879820FE8D8300DB6F80 /* Environment */, 7E4123AB20F4096200DF8486 /* FormattableContent */, @@ -8444,6 +8447,14 @@ path = Pages; sourceTree = ""; }; + F125314B22836AC6007D4F2C /* ClosureGroup */ = { + isa = PBXGroup; + children = ( + F125314C22836B93007D4F2C /* ClosureGroup.swift */, + ); + path = ClosureGroup; + sourceTree = ""; + }; F126FDFC20A33BDB0010EB6E /* Processors */ = { isa = PBXGroup; children = ( @@ -10269,6 +10280,7 @@ 5DF8D26119E82B1000A2CD95 /* ReaderCommentsViewController.m in Sources */, 43B27968216809AC00ECC046 /* QuickStartNavigationWatcher.swift in Sources */, 7E3E7A6020E44E490075D159 /* FooterContentGroup.swift in Sources */, + F125314D22836B93007D4F2C /* ClosureGroup.swift in Sources */, 59A3CADD1CD2FF0C009BFA1B /* BasePageListCell.m in Sources */, 436D56202117312700CEAA33 /* RegisterDomainSuggestionsTableViewController.swift in Sources */, E114D79A153D85A800984182 /* WPError.m in Sources */, From 8a52352c7fdfe3884e7ba537b1980366a881a34e Mon Sep 17 00:00:00 2001 From: Diego Rey Mendez Date: Sat, 25 May 2019 16:55:38 -0300 Subject: [PATCH 2/6] Implements UploadsManager and the Uploader protocol. Wires some things for future use. --- .../Classes/Services/MediaCoordinator.swift | 5 +- .../Classes/Services/PostCoordinator.swift | 9 ++++ .../System/WordPressAppDelegate+Swift.swift | 13 +++++ .../Classes/System/WordPressAppDelegate.h | 2 + .../Classes/System/WordPressAppDelegate.m | 3 ++ WordPress/Classes/Uploads/Uploader.swift | 6 +++ .../Classes/Uploads/UploadsManager.swift | 17 +++++++ .../Utility/ClosureGroup/ClosureGroup.swift | 49 ------------------- WordPress/WordPress.xcodeproj/project.pbxproj | 28 ++++++----- 9 files changed, 70 insertions(+), 62 deletions(-) create mode 100644 WordPress/Classes/Uploads/Uploader.swift create mode 100644 WordPress/Classes/Uploads/UploadsManager.swift delete mode 100644 WordPress/Classes/Utility/ClosureGroup/ClosureGroup.swift diff --git a/WordPress/Classes/Services/MediaCoordinator.swift b/WordPress/Classes/Services/MediaCoordinator.swift index 2743deeb62bf..51fb39421019 100644 --- a/WordPress/Classes/Services/MediaCoordinator.swift +++ b/WordPress/Classes/Services/MediaCoordinator.swift @@ -5,7 +5,10 @@ import WordPressFlux /// items, independently of a specific view controller. It should be accessed /// via the `shared` singleton. /// -class MediaCoordinator: NSObject { +class MediaCoordinator: NSObject, Uploader { + func resume() { + } + @objc static let shared = MediaCoordinator() diff --git a/WordPress/Classes/Services/PostCoordinator.swift b/WordPress/Classes/Services/PostCoordinator.swift index 3a89f9efb7d3..ce4ee82ac89a 100644 --- a/WordPress/Classes/Services/PostCoordinator.swift +++ b/WordPress/Classes/Services/PostCoordinator.swift @@ -228,3 +228,12 @@ class PostCoordinator: NSObject { } } } + +extension PostCoordinator: Uploader { + func resume() { + // Resume the upload of all posts that are not synched. + // + // 1. Query posts with status == .failed + // 2. Call retrySave() for each post + } +} diff --git a/WordPress/Classes/System/WordPressAppDelegate+Swift.swift b/WordPress/Classes/System/WordPressAppDelegate+Swift.swift index 9c233cae30b5..bbf95b1609dc 100644 --- a/WordPress/Classes/System/WordPressAppDelegate+Swift.swift +++ b/WordPress/Classes/System/WordPressAppDelegate+Swift.swift @@ -92,6 +92,19 @@ extension WordPressAppDelegate { } } + @objc func configureUploadsManager() { + // It's not great that we're using singletons here. This change is a good opportunity to + // revisit if we can make the coordinators children to another owning object. + // + // We're leaving as-is for now to avoid digressing. + let uploaders: [Uploader] = [ + MediaCoordinator.shared, + PostCoordinator.shared + ] + + uploadsManager = UploadsManager(uploaders: uploaders) + } + @objc func configureWordPressAuthenticator() { authManager = WordPressAuthenticationManager() diff --git a/WordPress/Classes/System/WordPressAppDelegate.h b/WordPress/Classes/System/WordPressAppDelegate.h index 21fe8259da4f..4fa2b6ba0950 100644 --- a/WordPress/Classes/System/WordPressAppDelegate.h +++ b/WordPress/Classes/System/WordPressAppDelegate.h @@ -6,6 +6,7 @@ @class HockeyManager; @class NoticePresenter; @class Reachability; +@class UploadsManager; @class WPUserAgent; @class WPAppAnalytics; @class WPLogger; @@ -24,6 +25,7 @@ @property (nonatomic, strong, readwrite) Reachability *internetReachability; @property (nonatomic, strong, readwrite) WordPressAuthenticationManager *authManager; @property (nonatomic, assign, readwrite) BOOL connectionAvailable; +@property (nonatomic, strong, readwrite, nonnull) UploadsManager *uploadsManager; + (WordPressAppDelegate *)sharedInstance; diff --git a/WordPress/Classes/System/WordPressAppDelegate.m b/WordPress/Classes/System/WordPressAppDelegate.m index 63fefcdef0de..106ac40a4841 100644 --- a/WordPress/Classes/System/WordPressAppDelegate.m +++ b/WordPress/Classes/System/WordPressAppDelegate.m @@ -274,6 +274,9 @@ - (void)runStartupSequenceWithLaunchOptions:(NSDictionary *)launchOptions // Networking setup [self setupNetworkActivityIndicator]; [WPUserAgent useWordPressUserAgentInUIWebViews]; + + // Uploading + [self configureUploadsManager]; // WORKAROUND: Preload the Noto regular font to ensure it is not overridden // by any of the Noto varients. Size is arbitrary. diff --git a/WordPress/Classes/Uploads/Uploader.swift b/WordPress/Classes/Uploads/Uploader.swift new file mode 100644 index 000000000000..4f21cbd4b9b1 --- /dev/null +++ b/WordPress/Classes/Uploads/Uploader.swift @@ -0,0 +1,6 @@ +import Foundation + +protocol Uploader { + /// Starts all pending uploads + func resume() +} diff --git a/WordPress/Classes/Uploads/UploadsManager.swift b/WordPress/Classes/Uploads/UploadsManager.swift new file mode 100644 index 000000000000..f3120842221b --- /dev/null +++ b/WordPress/Classes/Uploads/UploadsManager.swift @@ -0,0 +1,17 @@ +import Foundation + +/// Takes care of coordinating all Uploaders used by the app. +@objc +class UploadsManager: NSObject { + private let uploaders: [Uploader] + + init(uploaders: [Uploader]) { + self.uploaders = uploaders + } + + func resume() { + for uploader in uploaders { + uploader.resume() + } + } +} diff --git a/WordPress/Classes/Utility/ClosureGroup/ClosureGroup.swift b/WordPress/Classes/Utility/ClosureGroup/ClosureGroup.swift deleted file mode 100644 index 45d787d34af6..000000000000 --- a/WordPress/Classes/Utility/ClosureGroup/ClosureGroup.swift +++ /dev/null @@ -1,49 +0,0 @@ -import Foundation - -/// This class offers a generic mechanism to group closures and execute them. -/// This can be very useful to group together logic that needs to be executed -/// as a result of events. -/// -/// As an example: you can have an instance of this class to run code -/// whenever Reachability detects the App is online and whenever the App -/// comes to the foreground. -/// -class ClosureGroup { - - /// Just a typealias for readability. - /// - typealias Closure = () -> () - - /// The closures that have been registered. - /// - private var closures = [String: Closure]() - - // MARK: - Running the closure group - - /// Runs all registered closures. - /// - func run() { - for (_, closure) in closures { - closure() - } - } - - // MARK: - Registering and Unregistering closures. - - /// Registers a closure for running in this group. - /// - func register(identifier: String, closure: @escaping Closure) { - guard closures[identifier] == nil else { - assertionFailure("We shouldn't be adding two closures with the same identifier to the same group.") - return - } - - closures[identifier] = closure - } - - /// Unregisters a closure from this group. - /// - func unregister(identifier: String) { - closures.removeValue(forKey: identifier) - } -} diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index 95eb0018df48..a3984625da17 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -1698,7 +1698,6 @@ E8DEE110E4BC3FA1974AB1BB /* Pods_WordPressTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B921F5DD9A1F257C792EC225 /* Pods_WordPressTest.framework */; }; F10E655021B0613A007AB2EE /* GutenbergViewController+MoreActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F10E654F21B06139007AB2EE /* GutenbergViewController+MoreActions.swift */; }; F115308121B17E66002F1D65 /* EditorFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = F115308021B17E65002F1D65 /* EditorFactory.swift */; }; - F125314D22836B93007D4F2C /* ClosureGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = F125314C22836B93007D4F2C /* ClosureGroup.swift */; }; F126FE0020A33BDB0010EB6E /* VideoUploadProcessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = F126FDFD20A33BDB0010EB6E /* VideoUploadProcessor.swift */; }; F126FE0220A33BDB0010EB6E /* DocumentUploadProcessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = F126FDFF20A33BDB0010EB6E /* DocumentUploadProcessor.swift */; }; F128C31C1AFCC95B008C2404 /* WPNavigationMediaPickerViewController+StatusBarStyle.m in Sources */ = {isa = PBXBuildFile; fileRef = F128C31B1AFCC95B008C2404 /* WPNavigationMediaPickerViewController+StatusBarStyle.m */; }; @@ -1707,6 +1706,8 @@ F18B43781F849F580089B817 /* PostAttachmentTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F18B43771F849F580089B817 /* PostAttachmentTests.swift */; }; F1D690161F82913F00200E30 /* FeatureFlag.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1D690151F828FF000200E30 /* FeatureFlag.swift */; }; F1D690171F82914200200E30 /* BuildConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1D690141F828FF000200E30 /* BuildConfiguration.swift */; }; + F1DB8D292288C14400906E2F /* Uploader.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1DB8D282288C14400906E2F /* Uploader.swift */; }; + F1DB8D2B2288C24500906E2F /* UploadsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1DB8D2A2288C24500906E2F /* UploadsManager.swift */; }; F928EDA3226140620030D451 /* WPCrashLogging.swift in Sources */ = {isa = PBXBuildFile; fileRef = F928EDA2226140620030D451 /* WPCrashLogging.swift */; }; F9463A7321C05EE90081F11E /* ScreenshotCredentials.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9463A7221C05EE90081F11E /* ScreenshotCredentials.swift */; }; F98C58192228849E0073D752 /* XCTest+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF2716A01CABC7D40006E2D4 /* XCTest+Extensions.swift */; }; @@ -3894,7 +3895,6 @@ F10E654F21B06139007AB2EE /* GutenbergViewController+MoreActions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "GutenbergViewController+MoreActions.swift"; sourceTree = ""; }; F115308021B17E65002F1D65 /* EditorFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EditorFactory.swift; sourceTree = ""; }; F117E5841F7AA8BF003D9ACB /* WordPress 67.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "WordPress 67.xcdatamodel"; sourceTree = ""; }; - F125314C22836B93007D4F2C /* ClosureGroup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClosureGroup.swift; sourceTree = ""; }; F126FDFD20A33BDB0010EB6E /* VideoUploadProcessor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VideoUploadProcessor.swift; sourceTree = ""; }; F126FDFE20A33BDB0010EB6E /* ImgUploadProcessor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImgUploadProcessor.swift; sourceTree = ""; }; F126FDFF20A33BDB0010EB6E /* DocumentUploadProcessor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DocumentUploadProcessor.swift; sourceTree = ""; }; @@ -3909,6 +3909,8 @@ F18B43771F849F580089B817 /* PostAttachmentTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = PostAttachmentTests.swift; path = Posts/PostAttachmentTests.swift; sourceTree = ""; }; F1D690141F828FF000200E30 /* BuildConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BuildConfiguration.swift; sourceTree = ""; }; F1D690151F828FF000200E30 /* FeatureFlag.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeatureFlag.swift; sourceTree = ""; }; + F1DB8D282288C14400906E2F /* Uploader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Uploader.swift; sourceTree = ""; }; + F1DB8D2A2288C24500906E2F /* UploadsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UploadsManager.swift; sourceTree = ""; }; F262DFCA1F94418CE76D1D78 /* Pods-WordPressNotificationContentExtension.release-internal.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WordPressNotificationContentExtension.release-internal.xcconfig"; path = "../Pods/Target Support Files/Pods-WordPressNotificationContentExtension/Pods-WordPressNotificationContentExtension.release-internal.xcconfig"; sourceTree = ""; }; F373612EEEEF10E500093FF3 /* Pods-WordPress.release-alpha.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WordPress.release-alpha.xcconfig"; path = "../Pods/Target Support Files/Pods-WordPress/Pods-WordPress.release-alpha.xcconfig"; sourceTree = ""; }; F47DB4A8EC2E6844E213A3FA /* Pods_WordPressShareExtension.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_WordPressShareExtension.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -4211,6 +4213,7 @@ E1CA0A6A1FA73039004C4BBE /* Stores */, 8584FDB719243E550019C02E /* System */, 8584FDB4192437160019C02E /* Utility */, + F1DB8D272288C12A00906E2F /* Uploads */, 8584FDB31923EF4F0019C02E /* ViewRelated */, ); path = Classes; @@ -6111,7 +6114,6 @@ isa = PBXGroup; children = ( 40247E002120FE2300AE1C3C /* Automated Transfer */, - F125314B22836AC6007D4F2C /* ClosureGroup */, F198533821ADAA4E00DCDAE7 /* Editor */, 7E58879820FE8D8300DB6F80 /* Environment */, 7E4123AB20F4096200DF8486 /* FormattableContent */, @@ -8447,14 +8449,6 @@ path = Pages; sourceTree = ""; }; - F125314B22836AC6007D4F2C /* ClosureGroup */ = { - isa = PBXGroup; - children = ( - F125314C22836B93007D4F2C /* ClosureGroup.swift */, - ); - path = ClosureGroup; - sourceTree = ""; - }; F126FDFC20A33BDB0010EB6E /* Processors */ = { isa = PBXGroup; children = ( @@ -8505,6 +8499,15 @@ path = BuildInformation; sourceTree = ""; }; + F1DB8D272288C12A00906E2F /* Uploads */ = { + isa = PBXGroup; + children = ( + F1DB8D282288C14400906E2F /* Uploader.swift */, + F1DB8D2A2288C24500906E2F /* UploadsManager.swift */, + ); + path = Uploads; + sourceTree = ""; + }; F928EDA1226140430030D451 /* Sentry */ = { isa = PBXGroup; children = ( @@ -10280,7 +10283,6 @@ 5DF8D26119E82B1000A2CD95 /* ReaderCommentsViewController.m in Sources */, 43B27968216809AC00ECC046 /* QuickStartNavigationWatcher.swift in Sources */, 7E3E7A6020E44E490075D159 /* FooterContentGroup.swift in Sources */, - F125314D22836B93007D4F2C /* ClosureGroup.swift in Sources */, 59A3CADD1CD2FF0C009BFA1B /* BasePageListCell.m in Sources */, 436D56202117312700CEAA33 /* RegisterDomainSuggestionsTableViewController.swift in Sources */, E114D79A153D85A800984182 /* WPError.m in Sources */, @@ -10405,6 +10407,7 @@ D858F30120E20106007E8A1C /* LikePost.swift in Sources */, 1703D04C20ECD93800D292E9 /* Routes+Post.swift in Sources */, E11C4B702010930B00A6619C /* Blog+Jetpack.swift in Sources */, + F1DB8D292288C14400906E2F /* Uploader.swift in Sources */, 821738091FE04A9E00BEC94C /* DateAndTimeFormatSettingsViewController.swift in Sources */, 5D6C4B081B603E03005E3C43 /* WPContentSyncHelper.swift in Sources */, E6A2158E1D10627500DE5270 /* ReaderMenuViewModel.swift in Sources */, @@ -10733,6 +10736,7 @@ 738B9A5221B85CF20005062B /* SiteCreationWizardLauncher.swift in Sources */, D865722E2186F96D0023A99C /* SiteSegmentsWizardContent.swift in Sources */, E66969E01B9E648100EC9C00 /* ReaderTopicToReaderDefaultTopic37to38.swift in Sources */, + F1DB8D2B2288C24500906E2F /* UploadsManager.swift in Sources */, 9822AFA021EECB8E007D922D /* AnnualSiteStatsCell.swift in Sources */, 82A062DE2017BCBA0084CE7C /* ActivityListSectionHeaderView.swift in Sources */, 73FEC871220B358500CEF791 /* WPAccount+RestApi.swift in Sources */, From 03d4fca656a250c4f588333bdbdffbee5408073d Mon Sep 17 00:00:00 2001 From: Diego Rey Mendez Date: Sat, 25 May 2019 17:37:08 -0300 Subject: [PATCH 3/6] Wires UploadsManager to the events that should trigger it. --- .../Classes/System/WordPressAppDelegate.m | 5 +++ .../Classes/Uploads/UploadsManager.swift | 37 ++++++++++++++++++- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/WordPress/Classes/System/WordPressAppDelegate.m b/WordPress/Classes/System/WordPressAppDelegate.m index 106ac40a4841..162ad1640417 100644 --- a/WordPress/Classes/System/WordPressAppDelegate.m +++ b/WordPress/Classes/System/WordPressAppDelegate.m @@ -95,6 +95,8 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( [self setupComponentsAppearance]; [self disableAnimationsForUITests:application]; [[PushNotificationsManager shared] deletePendingLocalNotifications]; + + return YES; } @@ -171,6 +173,8 @@ - (void)applicationDidEnterBackground:(UIApplication *)application - (void)applicationWillEnterForeground:(UIApplication *)application { DDLogInfo(@"%@ %@", self, NSStringFromSelector(_cmd)); + + [self.uploadsManager resume]; } - (void)applicationWillResignActive:(UIApplication *)application @@ -296,6 +300,7 @@ - (void)runStartupSequenceWithLaunchOptions:(NSDictionary *)launchOptions [MediaCoordinator.shared refreshMediaStatus]; [PostCoordinator.shared refreshPostStatus]; [MediaFileManager clearUnusedMediaUploadFilesOnCompletion:nil onError:nil]; + [self.uploadsManager resume]; }); // Configure Extensions diff --git a/WordPress/Classes/Uploads/UploadsManager.swift b/WordPress/Classes/Uploads/UploadsManager.swift index f3120842221b..58d8ed713e9d 100644 --- a/WordPress/Classes/Uploads/UploadsManager.swift +++ b/WordPress/Classes/Uploads/UploadsManager.swift @@ -1,14 +1,47 @@ import Foundation -/// Takes care of coordinating all Uploaders used by the app. +/// Takes care of coordinating all uploaders used by the app. +/// @objc class UploadsManager: NSObject { private let uploaders: [Uploader] + private lazy var reachabilityObserver: NSObjectProtocol = { + return NotificationCenter.default.addObserver(forName: .reachabilityChanged, object: nil, queue: nil) { [weak self] notification in + + guard let self = self else { + return + } + + let internetIsReachable = notification.userInfo?[Foundation.Notification.reachabilityKey] as? Bool ?? false + + if internetIsReachable { + self.resume() + } + } + }() - init(uploaders: [Uploader]) { + // MARK: Initialization & Finalization + + /// Default initializer. + /// + /// - Parameters: + /// - uploaders: the uploaders that this object will be handling. + /// + required init(uploaders: [Uploader]) { self.uploaders = uploaders + + super.init() + } + + deinit { + NotificationCenter.default.removeObserver(reachabilityObserver) } + + // MARK: Interacting with Uploads + /// Resumes all uploads handled by the uploaders. + /// + @objc func resume() { for uploader in uploaders { uploader.resume() From 9585b9a0cc7b3b77c23b398df7c76982743d58bc Mon Sep 17 00:00:00 2001 From: Diego Rey Mendez Date: Sat, 25 May 2019 17:37:49 -0300 Subject: [PATCH 4/6] rake lint:autocorrect --- WordPress/Classes/Uploads/UploadsManager.swift | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/WordPress/Classes/Uploads/UploadsManager.swift b/WordPress/Classes/Uploads/UploadsManager.swift index 58d8ed713e9d..646ca2c6865e 100644 --- a/WordPress/Classes/Uploads/UploadsManager.swift +++ b/WordPress/Classes/Uploads/UploadsManager.swift @@ -7,13 +7,13 @@ class UploadsManager: NSObject { private let uploaders: [Uploader] private lazy var reachabilityObserver: NSObjectProtocol = { return NotificationCenter.default.addObserver(forName: .reachabilityChanged, object: nil, queue: nil) { [weak self] notification in - + guard let self = self else { return } - + let internetIsReachable = notification.userInfo?[Foundation.Notification.reachabilityKey] as? Bool ?? false - + if internetIsReachable { self.resume() } @@ -21,7 +21,7 @@ class UploadsManager: NSObject { }() // MARK: Initialization & Finalization - + /// Default initializer. /// /// - Parameters: @@ -29,14 +29,14 @@ class UploadsManager: NSObject { /// required init(uploaders: [Uploader]) { self.uploaders = uploaders - + super.init() } - + deinit { NotificationCenter.default.removeObserver(reachabilityObserver) } - + // MARK: Interacting with Uploads /// Resumes all uploads handled by the uploaders. From ad589295507e0cb35dec2c9ae764c0b756d0afc0 Mon Sep 17 00:00:00 2001 From: Diego Rey Mendez Date: Sat, 1 Jun 2019 01:01:07 -0300 Subject: [PATCH 5/6] Removing again two files which were added back by mistake. --- .../Classes/System/WordPressAppDelegate.h | 32 -- .../Classes/System/WordPressAppDelegate.m | 354 ------------------ 2 files changed, 386 deletions(-) delete mode 100644 WordPress/Classes/System/WordPressAppDelegate.h delete mode 100644 WordPress/Classes/System/WordPressAppDelegate.m diff --git a/WordPress/Classes/System/WordPressAppDelegate.h b/WordPress/Classes/System/WordPressAppDelegate.h deleted file mode 100644 index 4fa2b6ba0950..000000000000 --- a/WordPress/Classes/System/WordPressAppDelegate.h +++ /dev/null @@ -1,32 +0,0 @@ -@class AbstractPost; -@class Blog; -@class BlogListViewController; -@class NotificationsViewController; -@class WordPressAuthenticationManager; -@class HockeyManager; -@class NoticePresenter; -@class Reachability; -@class UploadsManager; -@class WPUserAgent; -@class WPAppAnalytics; -@class WPLogger; - -@import CocoaLumberjack; - -@interface WordPressAppDelegate : NSObject - -@property (strong, nonatomic) UIWindow *window; -@property (nonatomic, strong, readonly) WPLogger *logger; -@property (nonatomic, assign, readonly) BOOL runningInBackground; -@property (nonatomic, strong, readonly) WPUserAgent *userAgent; - -@property (nonatomic, strong, readwrite) WPAppAnalytics *analytics; -@property (nonatomic, strong, readwrite) HockeyManager *hockey; -@property (nonatomic, strong, readwrite) Reachability *internetReachability; -@property (nonatomic, strong, readwrite) WordPressAuthenticationManager *authManager; -@property (nonatomic, assign, readwrite) BOOL connectionAvailable; -@property (nonatomic, strong, readwrite, nonnull) UploadsManager *uploadsManager; - -+ (WordPressAppDelegate *)sharedInstance; - -@end diff --git a/WordPress/Classes/System/WordPressAppDelegate.m b/WordPress/Classes/System/WordPressAppDelegate.m deleted file mode 100644 index 162ad1640417..000000000000 --- a/WordPress/Classes/System/WordPressAppDelegate.m +++ /dev/null @@ -1,354 +0,0 @@ -#import "WordPressAppDelegate.h" - -// Constants -#import "Constants.h" - -// Pods -#import -#import - -// Data model -#import "Blog.h" - -// Data services -#import "BlogService.h" -#import "MediaService.h" - -// Logging -#import "WPLogger.h" - -// Misc managers, helpers, utilities -#import "ContextManager.h" -#import "TodayExtensionService.h" -#import "WPAuthTokenIssueSolver.h" -#import - -// Networking -#import "WPUserAgent.h" -#import "ApiCredentials.h" - -// Swift support -#import "WordPress-Swift.h" - -// View controllers -#import "StatsViewController.h" -#import "WPTabBarController.h" -#import - - -@interface WordPressAppDelegate () - -@property (nonatomic, strong, readwrite) WPLogger *logger; -@property (nonatomic, assign, readwrite) UIBackgroundTaskIdentifier bgTask; -@property (nonatomic, assign, readwrite) BOOL shouldRestoreApplicationState; -@property (nonatomic, strong, readwrite) PingHubManager *pinghubManager; -@property (nonatomic, strong, readwrite) WP3DTouchShortcutCreator *shortcutCreator; -@property (nonatomic, strong, readwrite) NoticePresenter *noticePresenter; - -@end - -@implementation WordPressAppDelegate - -+ (WordPressAppDelegate *)sharedInstance -{ - return (WordPressAppDelegate *)[[UIApplication sharedApplication] delegate]; -} - -#pragma mark - UIApplicationDelegate - -- (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions -{ - self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; - - // Authentication Framework - [self configureWordPressAuthenticator]; - - // Basic networking setup - [self configureReachability]; - [self configureSelfHostedChallengeHandler]; - - // Set the main window up - [self.window makeKeyAndVisible]; - - WPAuthTokenIssueSolver *authTokenIssueSolver = [[WPAuthTokenIssueSolver alloc] init]; - - __weak __typeof(self) weakSelf = self; - - BOOL isFixingAuthTokenIssue = [authTokenIssueSolver fixAuthTokenIssueAndDo:^{ - [weakSelf runStartupSequenceWithLaunchOptions:launchOptions]; - }]; - - self.shouldRestoreApplicationState = !isFixingAuthTokenIssue; - - return YES; -} - -- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions -{ - DDLogInfo(@"didFinishLaunchingWithOptions state: %d", application.applicationState); - - [[InteractiveNotificationsManager shared] registerForUserNotifications]; - [self showWelcomeScreenIfNeededAnimated:NO]; - [self setupPingHub]; - [self setupShortcutCreator]; - [self setupBackgroundRefresh:application]; - [self setupComponentsAppearance]; - [self disableAnimationsForUITests:application]; - [[PushNotificationsManager shared] deletePendingLocalNotifications]; - - - - return YES; -} - -- (void)setupPingHub -{ - self.pinghubManager = [PingHubManager new]; -} - -- (void)setupShortcutCreator -{ - self.shortcutCreator = [WP3DTouchShortcutCreator new]; -} - -/** - This method will disable animations and speed-up keyboad input if command-line arguments includes "NoAnimations" - It was designed to be used in UI test suites. To enable it just pass a launch argument into XCUIApplicaton: - - XCUIApplication().launchArguments = ["NoAnimations"] -*/ -- (void)disableAnimationsForUITests:(UIApplication *)application { - NSArray *args = [NSProcessInfo processInfo].arguments; - - for (NSString *arg in args){ - if ([arg isEqualToString:@"NoAnimations"]){ - [UIView setAnimationsEnabled:false]; - application.windows.firstObject.layer.speed = MAXFLOAT; - application.keyWindow.layer.speed = MAXFLOAT; - } - }} - -- (void)setupBackgroundRefresh:(UIApplication *)application { - [application setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum]; -} - -- (void)configureNoticePresenter -{ - self.noticePresenter = [[NoticePresenter alloc] init]; -} - -- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary *)options -{ - return [self application:app open:url options:options]; -} - -- (void)applicationWillTerminate:(UIApplication *)application -{ - DDLogInfo(@"%@ %@", self, NSStringFromSelector(_cmd)); -} - -- (void)applicationDidEnterBackground:(UIApplication *)application -{ - DDLogInfo(@"%@ %@", self, NSStringFromSelector(_cmd)); - - // Let the app finish any uploads that are in progress - UIApplication *app = [UIApplication sharedApplication]; - if (_bgTask != UIBackgroundTaskInvalid) { - [app endBackgroundTask:_bgTask]; - _bgTask = UIBackgroundTaskInvalid; - } - - _bgTask = [app beginBackgroundTaskWithExpirationHandler:^{ - // Synchronize the cleanup call on the main thread in case - // the task actually finishes at around the same time. - dispatch_async(dispatch_get_main_queue(), ^{ - if (self.bgTask != UIBackgroundTaskInvalid) { - [app endBackgroundTask:self.bgTask]; - self.bgTask = UIBackgroundTaskInvalid; - } - }); - }]; -} - -- (void)applicationWillEnterForeground:(UIApplication *)application -{ - DDLogInfo(@"%@ %@", self, NSStringFromSelector(_cmd)); - - [self.uploadsManager resume]; -} - -- (void)applicationWillResignActive:(UIApplication *)application -{ - DDLogInfo(@"%@ %@", self, NSStringFromSelector(_cmd)); -} - -- (void)applicationDidBecomeActive:(UIApplication *)application -{ - DDLogInfo(@"%@ %@", self, NSStringFromSelector(_cmd)); -} - -- (BOOL)application:(UIApplication *)application shouldSaveApplicationState:(NSCoder *)coder -{ - return YES; -} - -- (BOOL)application:(UIApplication *)application shouldRestoreApplicationState:(NSCoder *)coder -{ - NSUserDefaults* standardUserDefaults = [NSUserDefaults standardUserDefaults]; - - NSString* const lastSavedStateVersionKey = @"lastSavedStateVersionKey"; - NSString* lastSavedStateVersion = [standardUserDefaults objectForKey:lastSavedStateVersionKey]; - NSString* currentVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey: @"CFBundleShortVersionString"]; - BOOL shouldRestoreApplicationState = NO; - - if (lastSavedStateVersion && [lastSavedStateVersion length] > 0 && [lastSavedStateVersion isEqualToString:currentVersion]) { - shouldRestoreApplicationState = self.shouldRestoreApplicationState;; - } - - [standardUserDefaults setObject:currentVersion forKey:lastSavedStateVersionKey]; - - return shouldRestoreApplicationState; -} - -- (void)application: (UIApplication *)application performActionForShortcutItem:(nonnull UIApplicationShortcutItem *)shortcutItem completionHandler:(nonnull void (^)(BOOL))completionHandler -{ - WP3DTouchShortcutHandler *shortcutHandler = [[WP3DTouchShortcutHandler alloc] init]; - completionHandler([shortcutHandler handleShortcutItem:shortcutItem]); -} - -- (UIViewController *)application:(UIApplication *)application viewControllerWithRestorationIdentifierPath:(NSArray *)identifierComponents coder:(NSCoder *)coder -{ - NSString *restoreID = [identifierComponents lastObject]; - return [[Restorer new] viewControllerWithIdentifier:restoreID]; -} - -- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)(void))completionHandler { - - // 21-Oct-2017: We are only handling background URLSessions initiated by the share extension so there - // is no need to inspect the identifier beyond the simple check here. - if ([identifier containsString:WPAppGroupName]) { - ShareExtensionSessionManager *sessionManager = [[ShareExtensionSessionManager alloc] initWithAppGroup:WPAppGroupName backgroundSessionIdentifier:identifier]; - sessionManager.backgroundSessionCompletionBlock = completionHandler; - [sessionManager startBackgroundSession]; - } -} - -#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 120000 -- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray> * _Nullable))restorationHandler { -#else -- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray * _Nullable))restorationHandler { -#endif - if ([userActivity.activityType isEqualToString:NSUserActivityTypeBrowsingWeb]) { - [self handleWebActivity:userActivity]; - } else { - // Spotlight search - [SearchManager.shared handleWithActivity: userActivity]; - } - - return YES; -} - -#pragma mark - Application startup - -- (void)runStartupSequenceWithLaunchOptions:(NSDictionary *)launchOptions -{ - // Local Notifications - [self addNotificationObservers]; - - // Crash reporting, logging - self.logger = [[WPLogger alloc] init]; - [self configureHockeySDK]; - [self configureCrashLogging]; - [self configureAppRatingUtility]; - - // Analytics - [self configureAnalytics]; - - // Debugging - [self printDebugLaunchInfoWithLaunchOptions:launchOptions]; - [self toggleExtraDebuggingIfNeeded]; -#if DEBUG - [KeychainTools processKeychainDebugArguments]; - [ZDKCoreLogger setEnabled:YES]; - [ZDKCoreLogger setLogLevel:ZDKLogLevelDebug]; -#endif - - [ZendeskUtils setup]; - - // Networking setup - [self setupNetworkActivityIndicator]; - [WPUserAgent useWordPressUserAgentInUIWebViews]; - - // Uploading - [self configureUploadsManager]; - - // WORKAROUND: Preload the Noto regular font to ensure it is not overridden - // by any of the Noto varients. Size is arbitrary. - // See: https://github.com/wordpress-mobile/WordPress-Shared-iOS/issues/79 - // Remove this when #79 is resolved. - [WPFontManager notoRegularFontOfSize:16.0]; - - [self customizeAppearance]; - - // Push notifications - // This is silent (the user isn't prompted) so we can do it on launch. - // We'll ask for user notification permission after signin. - [[PushNotificationsManager shared] registerForRemoteNotifications]; - - // Deferred tasks to speed up app launch - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{ - [MediaCoordinator.shared refreshMediaStatus]; - [PostCoordinator.shared refreshPostStatus]; - [MediaFileManager clearUnusedMediaUploadFilesOnCompletion:nil onError:nil]; - [self.uploadsManager resume]; - }); - - // Configure Extensions - [self setupWordPressExtensions]; - - [self.shortcutCreator createShortcutsIf3DTouchAvailable:[AccountHelper isLoggedIn]]; - - self.window.rootViewController = [WPTabBarController sharedInstance]; - - [self configureNoticePresenter]; -} - -#pragma mark - Push Notification delegate - -- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken -{ - [[PushNotificationsManager shared] registerDeviceToken:deviceToken]; -} - -- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error -{ - [[PushNotificationsManager shared] registrationDidFail:error]; -} - -- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler -{ - DDLogMethod(); - - [[PushNotificationsManager shared] handleNotification:userInfo completionHandler:completionHandler]; -} - -#pragma mark - Background Refresh - -- (void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler -{ - WPTabBarController *tabBarController = [WPTabBarController sharedInstance]; - ReaderMenuViewController *readerMenuVC = tabBarController.readerMenuViewController; - if (readerMenuVC.currentReaderStream) { - [readerMenuVC.currentReaderStream backgroundFetch:completionHandler]; - } else { - completionHandler(UIBackgroundFetchResultNoData); - } -} - -- (BOOL)runningInBackground -{ - UIApplicationState state = [UIApplication sharedApplication].applicationState; - return state == UIApplicationStateBackground; -} - -@end From 55ece5f27982958ffb5cc4b2a1578e2fcbd9e0bf Mon Sep 17 00:00:00 2001 From: Diego Rey Mendez Date: Sat, 1 Jun 2019 01:09:20 -0300 Subject: [PATCH 6/6] Fixes an compilation issue. --- WordPress/Classes/System/WordPressAppDelegate.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/WordPress/Classes/System/WordPressAppDelegate.swift b/WordPress/Classes/System/WordPressAppDelegate.swift index 0d4fa3d2f445..bad22397cb8b 100644 --- a/WordPress/Classes/System/WordPressAppDelegate.swift +++ b/WordPress/Classes/System/WordPressAppDelegate.swift @@ -224,11 +224,11 @@ class WordPressAppDelegate: UIResponder, UIApplicationDelegate { PushNotificationsManager.shared.registerForRemoteNotifications() // Deferred tasks to speed up app launch - DispatchQueue.global(qos: .background).async { + DispatchQueue.global(qos: .background).async { [weak self] in MediaCoordinator.shared.refreshMediaStatus() PostCoordinator.shared.refreshPostStatus() MediaFileManager.clearUnusedMediaUploadFiles(onCompletion: nil, onError: nil) - uploadsManager.resume() + self?.uploadsManager.resume() } setupWordPressExtensions()