From 00a1d0e2c581fb6080a847951426493d56cf7930 Mon Sep 17 00:00:00 2001 From: Shiki Date: Thu, 28 Feb 2019 09:03:08 -0700 Subject: [PATCH 01/12] Add showNoInternetConnectionNotice --- .../ReachabilityUtils+OnlineActions.swift | 21 ++++++++++++++----- WordPress/Classes/Utility/ReachabilityUtils.m | 3 ++- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/WordPress/Classes/Utility/ReachabilityUtils+OnlineActions.swift b/WordPress/Classes/Utility/ReachabilityUtils+OnlineActions.swift index 8bc5efc3c02d..b1f30038ae99 100644 --- a/WordPress/Classes/Utility/ReachabilityUtils+OnlineActions.swift +++ b/WordPress/Classes/Utility/ReachabilityUtils+OnlineActions.swift @@ -1,17 +1,19 @@ import Foundation +import WordPressFlux extension ReachabilityUtils { + private enum NoConnectionMessages { + static let title = NSLocalizedString("No Connection", + comment: "Title of error prompt when no internet connection is available.") + static let message = noConnectionMessage() + } /// Performs the action when an internet connection is available /// If no internet connection is available an error message is displayed /// @objc class func onAvailableInternetConnectionDo(_ action: () -> Void) { guard ReachabilityUtils.isInternetReachable() else { - let title = NSLocalizedString("No Connection", - comment: "Title of error prompt when no internet connection is available.") - let message = NSLocalizedString("The Internet connection appears to be offline", - comment: "Message of error prompt shown when a user tries to perform an action without an internet connection.") - WPError.showAlert(withTitle: title, message: message) + WPError.showAlert(withTitle: NoConnectionMessages.title, message: NoConnectionMessages.message) return } action() @@ -35,4 +37,13 @@ extension ReachabilityUtils { return notification.userInfo?[Foundation.Notification.reachabilityKey] as? Bool == true }) } + + /// Shows a generic non-blocking "No Connection" error message to the user. + /// + /// We use a Snackbar instead of a literal Alert because, for internet connection errors, + /// Alerts can be disruptive. + @objc class func showNoInternetConnectionNotice() { + let notice = Notice(title: NoConnectionMessages.title, message: NoConnectionMessages.message) + ActionDispatcher.dispatch(NoticeAction.post(notice)) + } } diff --git a/WordPress/Classes/Utility/ReachabilityUtils.m b/WordPress/Classes/Utility/ReachabilityUtils.m index 7e4b6223c4ff..5232a3d753a7 100644 --- a/WordPress/Classes/Utility/ReachabilityUtils.m +++ b/WordPress/Classes/Utility/ReachabilityUtils.m @@ -80,7 +80,8 @@ + (void)showAlertNoInternetConnectionWithRetryBlock:(void (^)(void))retryBlock + (NSString *)noConnectionMessage { - return NSLocalizedString(@"The Internet connection appears to be offline.", @""); + return NSLocalizedString(@"The Internet connection appears to be offline.", + @"Message of error prompt shown when a user tries to perform an action without an internet connection."); } + (BOOL)alertIsShowing From e36ec4f6384a59043fec2e235d74e7299c2a5e6f Mon Sep 17 00:00:00 2001 From: Shiki Date: Thu, 28 Feb 2019 09:30:06 -0700 Subject: [PATCH 02/12] Use Notice in NetworkAware.presentNoNetworkAlert --- WordPress/Classes/ViewRelated/System/NetworkAware.swift | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/WordPress/Classes/ViewRelated/System/NetworkAware.swift b/WordPress/Classes/ViewRelated/System/NetworkAware.swift index 2a15b3b88d9f..9d11ea367e65 100644 --- a/WordPress/Classes/ViewRelated/System/NetworkAware.swift +++ b/WordPress/Classes/ViewRelated/System/NetworkAware.swift @@ -31,9 +31,7 @@ extension NetworkAwareUI { } func presentNoNetworkAlert() { - let title = NSLocalizedString("Unable to Sync", comment: "Title of error prompt shown when a sync the user initiated fails.") - let message = NSLocalizedString("The Internet connection appears to be offline.", comment: "Message of error prompt shown when a sync the user initiated fails.") - WPError.showAlert(withTitle: title, message: message) + ReachabilityUtils.showNoInternetConnectionNotice() } func noConnectionMessage() -> String { From 7325be673f18a6b7097fdc653bfbc77e53172812 Mon Sep 17 00:00:00 2001 From: Shiki Date: Thu, 28 Feb 2019 09:56:39 -0700 Subject: [PATCH 03/12] Reader: Prevent duplicate offline error Notices --- .../Reader/ReaderStreamViewController.swift | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift b/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift index 486441a92bae..516f80feccf3 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift @@ -248,7 +248,9 @@ import WordPressFlux didSetupView = true if readerTopic != nil { - configureControllerForTopic() + // Do not perform a sync since a sync will be executed in viewWillAppear anyway. This + // prevents a possible internet connection error being shown twice. + configureControllerForTopic(synchronize: false) } else if (siteID != nil || tagSlug != nil) && isShowingResultStatusView == false { displayLoadingStream() } @@ -450,7 +452,7 @@ import WordPressFlux /// Configures the controller for the `readerTopic`. This should only be called /// once when the topic is set. - private func configureControllerForTopic() { + private func configureControllerForTopic(synchronize: Bool = true) { assert(readerTopic != nil, "A reader topic is required") assert(isViewLoaded, "The controller's view must be loaded before displaying the topic") @@ -479,7 +481,10 @@ import WordPressFlux tableView.setContentOffset(CGPoint.zero, animated: false) content.refresh() refreshTableViewHeaderLayout() - syncIfAppropriate() + + if synchronize { + syncIfAppropriate() + } bumpStats() From a7ba9136ea6fafd3772898941e5163ea169b6da8 Mon Sep 17 00:00:00 2001 From: Shiki Date: Thu, 28 Feb 2019 10:02:07 -0700 Subject: [PATCH 04/12] Comments: Prevent duplicate offline error Notices The handleConnectionError() call is unnecessary because the refreshAndSyncIfNeeded() will cause handleConnectionError() to be called later if there is no internet connection. --- WordPress/Classes/ViewRelated/Comments/CommentsViewController.m | 1 - 1 file changed, 1 deletion(-) diff --git a/WordPress/Classes/ViewRelated/Comments/CommentsViewController.m b/WordPress/Classes/ViewRelated/Comments/CommentsViewController.m index cd1e8fadc274..e1cd9ad3c603 100644 --- a/WordPress/Classes/ViewRelated/Comments/CommentsViewController.m +++ b/WordPress/Classes/ViewRelated/Comments/CommentsViewController.m @@ -74,7 +74,6 @@ - (void)viewWillAppear:(BOOL)animated // Refresh the UI [self refreshNoResultsView]; - [self handleConnectionError]; [self refreshAndSyncIfNeeded]; } From a0fa905eeff436e9a02ce54463642357168f4b60 Mon Sep 17 00:00:00 2001 From: Shiki Date: Thu, 28 Feb 2019 10:28:54 -0700 Subject: [PATCH 05/12] Post List: Prevent duplicate Alert + Notice MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `forcingNetworkAlerts` argument does not seem necessary because we’ll just end up showing both an Alert and a Notice if there is a network problem. --- .../Post/AbstractPostListViewController.swift | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Post/AbstractPostListViewController.swift b/WordPress/Classes/ViewRelated/Post/AbstractPostListViewController.swift index a29b97129592..7af5f852ba0d 100644 --- a/WordPress/Classes/ViewRelated/Post/AbstractPostListViewController.swift +++ b/WordPress/Classes/ViewRelated/Post/AbstractPostListViewController.swift @@ -302,7 +302,7 @@ class AbstractPostListViewController: UIViewController, WPContentSyncHelperDeleg tableView.register(UITableViewCell.self, forCellReuseIdentifier: abstractPostWindowlessCellIdenfitier) } - fileprivate func refreshResults(forcingNetworkAlerts: Bool = false) { + private func refreshResults() { guard isViewLoaded == true else { return } @@ -312,11 +312,7 @@ class AbstractPostListViewController: UIViewController, WPContentSyncHelperDeleg } hideNoResultsView() - if tableViewHandler.resultsController.fetchedObjects?.count > 0 { - if forcingNetworkAlerts { - presentNoNetworkAlert() - } - } else { + if tableViewHandler.resultsController.fetchedObjects?.count == 0 { showNoResultsView() } } @@ -621,21 +617,13 @@ class AbstractPostListViewController: UIViewController, WPContentSyncHelperDeleg } } - func presentNoNetworkAlert() { - if shouldPresentAlert() { - let title = NSLocalizedString("Unable to Sync", comment: "Title of error prompt shown when a sync the user initiated fails.") - let message = NSLocalizedString("The Internet connection appears to be offline.", comment: "Message of error prompt shown when a sync the user initiated fails.") - WPError.showAlert(withTitle: title, message: message) - } - } - func shouldPresentAlert() -> Bool { return !connectionAvailable() && !contentIsEmpty() && isViewOnScreen() } @objc func syncItemsWithUserInteraction(_ userInteraction: Bool) { syncHelper.syncContentWithUserInteraction(userInteraction) - refreshResults(forcingNetworkAlerts: userInteraction) + refreshResults() } @objc func updateFilter(_ filter: PostListFilter, withSyncedPosts posts: [AbstractPost], syncOptions options: PostServiceSyncOptions) { From 1c4bf9f72fd253d8f65b194d0b7e001be42d4df8 Mon Sep 17 00:00:00 2001 From: Shiki Date: Thu, 28 Feb 2019 11:33:48 -0700 Subject: [PATCH 06/12] Post List: Use Notice on pull to refresh errors --- WordPress/Classes/Utility/WPError.h | 21 ++++ WordPress/Classes/Utility/WPError.m | 103 +++++++++++------- WordPress/Classes/Utility/WPError.swift | 22 ++++ .../Post/AbstractPostListViewController.swift | 5 +- WordPress/WordPress.xcodeproj/project.pbxproj | 4 + 5 files changed, 111 insertions(+), 44 deletions(-) create mode 100644 WordPress/Classes/Utility/WPError.swift diff --git a/WordPress/Classes/Utility/WPError.h b/WordPress/Classes/Utility/WPError.h index a11f3e5e4e8e..bb2aa34c0381 100644 --- a/WordPress/Classes/Utility/WPError.h +++ b/WordPress/Classes/Utility/WPError.h @@ -28,6 +28,27 @@ */ + (void)showXMLRPCErrorAlert:(NSError *)error; +/** + * Create a suggested title and message based on the given `error` + * + * @param error Assumed to be an error from a networking call + * @param desiredTitle If given, this will be the title that will be returned. + * + * @return A dictionary with keys "title" and "message". Both values are not null. + */ ++ (nonnull NSDictionary *)titleAndMessageFromNetworkingError:(nonnull NSError *)error + desiredTitle:(nullable NSString *)desiredTitle; + +/** + * Shows a sign-in page if the `error`'s cause requires an authentication or authorization. + * + * This is meant to be a helper method for the other methods in this class and is only publicly + * exposed so it can be accessed in WPError.swift. + * + * @param error Assumed to be an error from a networking call. + * @returns YES if a sign-in page was shown. + */ ++ (BOOL)showWPComSigninIfErrorIsInvalidAuth:(nonnull NSError *)error; ///--------------------- /// @name General alerts diff --git a/WordPress/Classes/Utility/WPError.m b/WordPress/Classes/Utility/WPError.m index e3643d5ac423..6835fae49370 100644 --- a/WordPress/Classes/Utility/WPError.m +++ b/WordPress/Classes/Utility/WPError.m @@ -32,12 +32,48 @@ + (void)showNetworkingAlertWithError:(NSError *)error } + (void)showNetworkingAlertWithError:(NSError *)error title:(NSString *)title +{ + if ([self showWPComSigninIfErrorIsInvalidAuth:error]) { + return; + } + + NSDictionary *titleAndMessage = [self titleAndMessageFromNetworkingError:error desiredTitle:title]; + + [self showAlertWithTitle:titleAndMessage[@"title"] + message:titleAndMessage[@"message"] + withSupportButton:YES + okPressedBlock:nil]; +} + ++ (void)showXMLRPCErrorAlert:(NSError *)error +{ + NSString *cleanedErrorMsg = [error localizedDescription]; + + if ([error.domain isEqualToString:WPXMLRPCFaultErrorDomain] && error.code == 401) { + cleanedErrorMsg = NSLocalizedString(@"Sorry, you cannot access this feature. Please check your User Role on this site.", @""); + } + + // ignore HTTP auth canceled errors + if ([error.domain isEqual:NSURLErrorDomain] && error.code == NSURLErrorUserCancelledAuthentication) { + [WPError internalInstance].alertShowing = NO; + return; + } + + if ([cleanedErrorMsg rangeOfString:@"NSXMLParserErrorDomain"].location != NSNotFound) { + cleanedErrorMsg = NSLocalizedString(@"The app can't recognize the server response. Please, check the configuration of your site.", @""); + } + + [self showAlertWithTitle:NSLocalizedString(@"Error", @"Generic popup title for any type of error.") message:cleanedErrorMsg]; +} + ++ (NSDictionary *)titleAndMessageFromNetworkingError:(NSError *)error + desiredTitle:(NSString *)desiredTitle { NSString *message = nil; - NSString *customTitle = nil; + NSString *title = nil; if ([error.domain isEqual:AFURLRequestSerializationErrorDomain] || - [error.domain isEqual:AFURLResponseSerializationErrorDomain]) + [error.domain isEqual:AFURLResponseSerializationErrorDomain]) { NSHTTPURLResponse *response = (NSHTTPURLResponse *)[error.userInfo objectForKey:AFNetworkingOperationFailingURLResponseErrorKey]; switch (error.code) { @@ -54,22 +90,22 @@ + (void)showNetworkingAlertWithError:(NSError *)error title:(NSString *)title case 415: case 416: case 417: - customTitle = NSLocalizedString(@"Incompatible site", @"Error message shown in the set up process if the WP install was unable to be added to the app due to an error being returned from the site."); + title = NSLocalizedString(@"Incompatible site", @"Error message shown in the set up process if the WP install was unable to be added to the app due to an error being returned from the site."); message = [NSString stringWithFormat:NSLocalizedString(@"Your site returned a %d error.\nThis is usually due to an incompatible server configuration.\nPlease contact your hosting provider, or reach out to us using our in-app support.", @"Error message shown in the set up process if the WP install was unable to be added to the app due to an error being returned from the site."), response.statusCode]; break; case 403: - customTitle = NSLocalizedString(@"Forbidden Access", @"Error message shown in the set up process if the WP install was unable to be added to the app due to an error accessing the site."); + title = NSLocalizedString(@"Forbidden Access", @"Error message shown in the set up process if the WP install was unable to be added to the app due to an error accessing the site."); message = NSLocalizedString(@"Received 'Forbidden Access'.\nIt seems there is a problem with your WordPress site", @"Error message shown in the set up process if the WP install was unable to be added to the app due to an error accessing the site."); break; case 500: case 501: - customTitle = NSLocalizedString(@"Internal Server Error", @"Error message shown in the set up process if the WP install was unable to be added to the app due to an error accessing the site, most likely due to an error with the server hosting the WP install."); + title = NSLocalizedString(@"Internal Server Error", @"Error message shown in the set up process if the WP install was unable to be added to the app due to an error accessing the site, most likely due to an error with the server hosting the WP install."); message = NSLocalizedString(@"Received 'Internal Server Error'.\nIt seems there is a problem with your WordPress site", @"Error message shown in the set up process if the WP install was unable to be added to the app due to an error accessing the site, most likely due to an error with the server hosting the WP install."); break; case 502: case 503: case 504: - customTitle = NSLocalizedString(@"Temporary Server Error", @"Error message shown in the set up process if the WP install was unable to be added to the app due to an error accessing the site, most likely due to an error with the server hosting the WP install, but may be a temporary issue."); + title = NSLocalizedString(@"Temporary Server Error", @"Error message shown in the set up process if the WP install was unable to be added to the app due to an error accessing the site, most likely due to an error with the server hosting the WP install, but may be a temporary issue."); message = NSLocalizedString(@"It seems your WordPress site is not accessible at this time, please try again later", @"Error message shown in the set up process if the WP install was unable to be added to the app due to an error accessing the site, most likely due to an error with the server hosting the WP install, but may be a temporary issue."); break; default: @@ -81,50 +117,33 @@ + (void)showNetworkingAlertWithError:(NSError *)error title:(NSString *)title default: break; } - } else if ([error.domain isEqualToString:WordPressComRestApiErrorDomain]) { - DDLogError(@"wp.com API error: %@: %@", error.userInfo[WordPressComRestApi.ErrorKeyErrorCode], - [error localizedDescription]); - if (error.code == WordPressComRestApiErrorInvalidToken || error.code == WordPressComRestApiErrorAuthorizationRequired) { - [WordPressAuthenticationManager showSigninForWPComFixingAuthToken]; - return; - } } - + + if (desiredTitle != nil) { + title = desiredTitle; + } else if (title == nil) { + title = NSLocalizedString(@"Error", @"Generic error alert title"); + } + if (message == nil) { message = [error localizedDescription]; message = [NSString decodeXMLCharactersIn:message]; } - - if (title == nil) { - if (customTitle == nil) { - title = NSLocalizedString(@"Error", @"Generic error alert title"); - } else { - title = customTitle; - } - } - - [self showAlertWithTitle:title message:message withSupportButton:YES okPressedBlock:nil]; + + return @{@"title": title, @"message": message}; } -+ (void)showXMLRPCErrorAlert:(NSError *)error -{ - NSString *cleanedErrorMsg = [error localizedDescription]; - - if ([error.domain isEqualToString:WPXMLRPCFaultErrorDomain] && error.code == 401) { - cleanedErrorMsg = NSLocalizedString(@"Sorry, you cannot access this feature. Please check your User Role on this site.", @""); - } - - // ignore HTTP auth canceled errors - if ([error.domain isEqual:NSURLErrorDomain] && error.code == NSURLErrorUserCancelledAuthentication) { - [WPError internalInstance].alertShowing = NO; - return; - } - - if ([cleanedErrorMsg rangeOfString:@"NSXMLParserErrorDomain"].location != NSNotFound) { - cleanedErrorMsg = NSLocalizedString(@"The app can't recognize the server response. Please, check the configuration of your site.", @""); ++ (BOOL)showWPComSigninIfErrorIsInvalidAuth:(nonnull NSError *)error { + if ([error.domain isEqualToString:WordPressComRestApiErrorDomain]) { + DDLogError(@"wp.com API error: %@: %@", error.userInfo[WordPressComRestApi.ErrorKeyErrorCode], + [error localizedDescription]); + if (error.code == WordPressComRestApiErrorInvalidToken || error.code == WordPressComRestApiErrorAuthorizationRequired) { + [WordPressAuthenticationManager showSigninForWPComFixingAuthToken]; + return YES; + } } - - [self showAlertWithTitle:NSLocalizedString(@"Error", @"Generic popup title for any type of error.") message:cleanedErrorMsg]; + + return NO; } + (void)showAlertWithTitle:(NSString *)title message:(NSString *)message diff --git a/WordPress/Classes/Utility/WPError.swift b/WordPress/Classes/Utility/WPError.swift new file mode 100644 index 000000000000..7c1f7c664aac --- /dev/null +++ b/WordPress/Classes/Utility/WPError.swift @@ -0,0 +1,22 @@ + +import Foundation +import WordPressFlux + +extension WPError { + /// Show a Notice with the message taken from the given `error` + /// + /// This is similar to `showNetworkingAlertWithError` except this uses a Notice instead of + /// an Alert. + /// + /// - parameter error: Assumed to be an error from a networking call + static func showNetworkingNotice(title: String, error: NSError) { + if showWPComSigninIfErrorIsInvalidAuth(error) { + return + } + + let titleAndMessage = self.titleAndMessage(fromNetworkingError: error, desiredTitle: title) + + let notice = Notice(title: titleAndMessage["title"] ?? "", message: titleAndMessage["message"]) + ActionDispatcher.dispatch(NoticeAction.post(notice)) + } +} diff --git a/WordPress/Classes/ViewRelated/Post/AbstractPostListViewController.swift b/WordPress/Classes/ViewRelated/Post/AbstractPostListViewController.swift index 7af5f852ba0d..6109e0e0ae6b 100644 --- a/WordPress/Classes/ViewRelated/Post/AbstractPostListViewController.swift +++ b/WordPress/Classes/ViewRelated/Post/AbstractPostListViewController.swift @@ -779,8 +779,9 @@ class AbstractPostListViewController: UIViewController, WPContentSyncHelperDeleg promptForPassword() return } - - WPError.showNetworkingAlertWithError(error, title: NSLocalizedString("Unable to Sync", comment: "Title of error prompt shown when a sync the user initiated fails.")) + + let title = NSLocalizedString("Unable to Sync", comment: "Title of error prompt shown when a sync the user initiated fails.") + WPError.showNetworkingNotice(title: title, error: error) } @objc func promptForPassword() { diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index 833c4331347a..d76ae34262dc 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -336,6 +336,7 @@ 462F4E0A18369F0B0028D2F8 /* BlogDetailsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 462F4E0718369F0B0028D2F8 /* BlogDetailsViewController.m */; }; 4645AFC51961E1FB005F7509 /* AppImages.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4645AFC41961E1FB005F7509 /* AppImages.xcassets */; }; 4C8A715EBCE7E73AEE216293 /* Pods_WordPressShareExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F47DB4A8EC2E6844E213A3FA /* Pods_WordPressShareExtension.framework */; }; + 57D5812D2228526C002BAAD7 /* WPError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57D5812C2228526C002BAAD7 /* WPError.swift */; }; 5903AE1B19B60A98009D5354 /* WPButtonForNavigationBar.m in Sources */ = {isa = PBXBuildFile; fileRef = 5903AE1A19B60A98009D5354 /* WPButtonForNavigationBar.m */; }; 590E873B1CB8205700D1B734 /* PostListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 590E873A1CB8205700D1B734 /* PostListViewController.swift */; }; 591232691CCEAA5100B86207 /* AbstractPostListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 591232681CCEAA5100B86207 /* AbstractPostListViewController.swift */; }; @@ -2176,6 +2177,7 @@ 4F943DB9A7237917709622D5 /* Pods-WordPressNotificationContentExtension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WordPressNotificationContentExtension.debug.xcconfig"; path = "../Pods/Target Support Files/Pods-WordPressNotificationContentExtension/Pods-WordPressNotificationContentExtension.debug.xcconfig"; sourceTree = ""; }; 51A5F017948878F7E26979A0 /* Pods-WordPress.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WordPress.release.xcconfig"; path = "../Pods/Target Support Files/Pods-WordPress/Pods-WordPress.release.xcconfig"; sourceTree = ""; }; 556E3A9C1600564F6A3CADF6 /* Pods_WordPress.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_WordPress.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 57D5812C2228526C002BAAD7 /* WPError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WPError.swift; sourceTree = ""; }; 5903AE1A19B60A98009D5354 /* WPButtonForNavigationBar.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WPButtonForNavigationBar.m; sourceTree = ""; usesTabs = 0; }; 5903AE1C19B60AB9009D5354 /* WPButtonForNavigationBar.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WPButtonForNavigationBar.h; sourceTree = ""; usesTabs = 0; }; 590E873A1CB8205700D1B734 /* PostListViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PostListViewController.swift; sourceTree = ""; }; @@ -5890,6 +5892,7 @@ 5D6C4B051B603E03005E3C43 /* WPContentSyncHelper.swift */, E114D798153D85A800984182 /* WPError.h */, E114D799153D85A800984182 /* WPError.m */, + 57D5812C2228526C002BAAD7 /* WPError.swift */, 5D6C4B061B603E03005E3C43 /* WPTableViewHandler.h */, 5D6C4B071B603E03005E3C43 /* WPTableViewHandler.m */, E1F5A1BA1771C90A00E0495F /* WPTableImageSource.h */, @@ -9632,6 +9635,7 @@ 740516892087B73400252FD0 /* SearchableActivityConvertable.swift in Sources */, B5F641B31E37C36700B7819F /* AdaptiveNavigationController.swift in Sources */, 74BC35B820499EEB00AC1525 /* RemotePostCategory+Extensions.swift in Sources */, + 57D5812D2228526C002BAAD7 /* WPError.swift in Sources */, 825327581FBF7CD600B8B7D2 /* ActivityUtils.swift in Sources */, 080AAA691E7C63C3004DCD11 /* Media+HTML.m in Sources */, 59DD94341AC479ED0032DD6B /* WPLogger.m in Sources */, From b7e1a5d4fe16b0775a0520b47fba6130d38fd542 Mon Sep 17 00:00:00 2001 From: Shiki Date: Thu, 28 Feb 2019 13:19:38 -0700 Subject: [PATCH 07/12] Manually dismiss offline error Notices --- WordPress/Classes/Stores/NoticeStore.swift | 9 +++++++- .../ReachabilityUtils+OnlineActions.swift | 22 +++++++++++++++---- WordPress/Classes/Utility/WPError.swift | 17 +++++++++++++- .../CommentsViewController+NetworkAware.swift | 4 ++++ .../Comments/CommentsViewController.m | 5 +++++ .../NotificationsViewController.swift | 2 ++ .../Post/AbstractPostListViewController.swift | 10 +++++++++ .../Reader/ReaderStreamViewController.swift | 2 ++ .../ViewRelated/System/NetworkAware.swift | 5 +++++ 9 files changed, 70 insertions(+), 6 deletions(-) diff --git a/WordPress/Classes/Stores/NoticeStore.swift b/WordPress/Classes/Stores/NoticeStore.swift index ed3e09e7f5eb..312e57234b51 100644 --- a/WordPress/Classes/Stores/NoticeStore.swift +++ b/WordPress/Classes/Stores/NoticeStore.swift @@ -33,6 +33,11 @@ struct Notice { /// A title for an optional cancel button that can be displayed as part of a notice /// let cancelTitle: String? + + /// An optional value that can be used as a reference by consumers. + /// + /// This is not used in the Notice system at all. + let tag: String? /// An optional handler closure that will be called when the action button /// is tapped, if you've provided an action title @@ -45,6 +50,7 @@ struct Notice { style: NoticeStyle = NormalNoticeStyle(), actionTitle: String? = nil, cancelTitle: String? = nil, + tag: String? = nil, actionHandler: ActionHandlerFunction? = nil) { self.title = title self.message = message @@ -52,6 +58,7 @@ struct Notice { self.notificationInfo = notificationInfo self.actionTitle = actionTitle self.cancelTitle = cancelTitle + self.tag = tag self.actionHandler = actionHandler self.style = style } @@ -98,7 +105,7 @@ enum NoticeAction: Action { struct NoticeStoreState { - fileprivate var notice: Notice? + fileprivate(set) var notice: Notice? } /// NoticeStore queues notices for display to the user. diff --git a/WordPress/Classes/Utility/ReachabilityUtils+OnlineActions.swift b/WordPress/Classes/Utility/ReachabilityUtils+OnlineActions.swift index b1f30038ae99..afb021fc1932 100644 --- a/WordPress/Classes/Utility/ReachabilityUtils+OnlineActions.swift +++ b/WordPress/Classes/Utility/ReachabilityUtils+OnlineActions.swift @@ -2,10 +2,11 @@ import Foundation import WordPressFlux extension ReachabilityUtils { - private enum NoConnectionMessages { + private enum NoConnectionMessage { static let title = NSLocalizedString("No Connection", comment: "Title of error prompt when no internet connection is available.") static let message = noConnectionMessage() + static let tag = "ReachabilityUtils.NoConnection" } /// Performs the action when an internet connection is available @@ -13,7 +14,7 @@ extension ReachabilityUtils { /// @objc class func onAvailableInternetConnectionDo(_ action: () -> Void) { guard ReachabilityUtils.isInternetReachable() else { - WPError.showAlert(withTitle: NoConnectionMessages.title, message: NoConnectionMessages.message) + WPError.showAlert(withTitle: NoConnectionMessage.title, message: NoConnectionMessage.message) return } action() @@ -42,8 +43,21 @@ extension ReachabilityUtils { /// /// We use a Snackbar instead of a literal Alert because, for internet connection errors, /// Alerts can be disruptive. - @objc class func showNoInternetConnectionNotice() { - let notice = Notice(title: NoConnectionMessages.title, message: NoConnectionMessages.message) + @objc static func showNoInternetConnectionNotice() { + let notice = Notice(title: NoConnectionMessage.title, + message: NoConnectionMessage.message, + tag: NoConnectionMessage.tag) ActionDispatcher.dispatch(NoticeAction.post(notice)) } + + /// Dismiss the currently shown Notice if it was created using showNoInternetConnectionNotice() + @objc static func dismissNoInternetConnectionNotice() { + if StoreContainer.shared.notice.state.notice?.tag == NoConnectionMessage.tag { + noticePresenter?.dismissCurrentNotice() + } + } + + private static var noticePresenter: NoticePresenter? { + return (UIApplication.shared.delegate as? WordPressAppDelegate)?.noticePresenter + } } diff --git a/WordPress/Classes/Utility/WPError.swift b/WordPress/Classes/Utility/WPError.swift index 7c1f7c664aac..49a5688a9ddb 100644 --- a/WordPress/Classes/Utility/WPError.swift +++ b/WordPress/Classes/Utility/WPError.swift @@ -3,6 +3,8 @@ import Foundation import WordPressFlux extension WPError { + private static let noticeTag = "WPError.Networking" + /// Show a Notice with the message taken from the given `error` /// /// This is similar to `showNetworkingAlertWithError` except this uses a Notice instead of @@ -16,7 +18,20 @@ extension WPError { let titleAndMessage = self.titleAndMessage(fromNetworkingError: error, desiredTitle: title) - let notice = Notice(title: titleAndMessage["title"] ?? "", message: titleAndMessage["message"]) + let notice = Notice(title: titleAndMessage["title"] ?? "", + message: titleAndMessage["message"], + tag: noticeTag) ActionDispatcher.dispatch(NoticeAction.post(notice)) } + + /// Dismiss the currently shown Notice if it was created using showNetworkingNotice() + static func dismissNetworkingNotice() { + if StoreContainer.shared.notice.state.notice?.tag == noticeTag { + noticePresenter?.dismissCurrentNotice() + } + } + + private static var noticePresenter: NoticePresenter? { + return (UIApplication.shared.delegate as? WordPressAppDelegate)?.noticePresenter + } } diff --git a/WordPress/Classes/ViewRelated/Comments/CommentsViewController+NetworkAware.swift b/WordPress/Classes/ViewRelated/Comments/CommentsViewController+NetworkAware.swift index 958558a559b5..566c736ae1eb 100644 --- a/WordPress/Classes/ViewRelated/Comments/CommentsViewController+NetworkAware.swift +++ b/WordPress/Classes/ViewRelated/Comments/CommentsViewController+NetworkAware.swift @@ -18,6 +18,10 @@ extension CommentsViewController: NetworkAwareUI { presentNoNetworkAlert() } } + + @objc func dismissConnectionErrorNotice() { + dismissNoNetworkAlert() + } } extension CommentsViewController: NetworkStatusDelegate { diff --git a/WordPress/Classes/ViewRelated/Comments/CommentsViewController.m b/WordPress/Classes/ViewRelated/Comments/CommentsViewController.m index e1cd9ad3c603..480fc3490d84 100644 --- a/WordPress/Classes/ViewRelated/Comments/CommentsViewController.m +++ b/WordPress/Classes/ViewRelated/Comments/CommentsViewController.m @@ -78,6 +78,11 @@ - (void)viewWillAppear:(BOOL)animated [self refreshAndSyncIfNeeded]; } +- (void)viewWillDisappear:(BOOL)animated { + [super viewWillDisappear:animated]; + [self dismissConnectionErrorNotice]; +} + - (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id)coordinator { [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator]; diff --git a/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationsViewController.swift b/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationsViewController.swift index 0e8185924a7e..3275fa96c6b9 100644 --- a/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationsViewController.swift +++ b/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationsViewController.swift @@ -167,6 +167,8 @@ class NotificationsViewController: UITableViewController, UIViewControllerRestor override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) stopListeningToNotifications() + + dismissNoNetworkAlert() // If we're not onscreen, don't use row animations. Otherwise the fade animation might get animated incrementally tableViewHandler.updateRowAnimation = .none diff --git a/WordPress/Classes/ViewRelated/Post/AbstractPostListViewController.swift b/WordPress/Classes/ViewRelated/Post/AbstractPostListViewController.swift index 6109e0e0ae6b..7b0934ff6f50 100644 --- a/WordPress/Classes/ViewRelated/Post/AbstractPostListViewController.swift +++ b/WordPress/Classes/ViewRelated/Post/AbstractPostListViewController.swift @@ -239,6 +239,8 @@ class AbstractPostListViewController: UIViewController, WPContentSyncHelperDeleg if searchController.isActive { searchController.isActive = false } + + dismissAllNetworkErrorNotices() NotificationCenter.default.removeObserver(self, name: UIApplication.didBecomeActiveNotification, object: nil) unregisterForKeyboardNotifications() @@ -604,6 +606,7 @@ class AbstractPostListViewController: UIViewController, WPContentSyncHelperDeleg if appDelegate?.connectionAvailable == false { refreshResults() + dismissAllNetworkErrorNotices() presentNoNetworkAlert() return } @@ -780,6 +783,8 @@ class AbstractPostListViewController: UIViewController, WPContentSyncHelperDeleg return } + dismissAllNetworkErrorNotices() + let title = NSLocalizedString("Unable to Sync", comment: "Title of error prompt shown when a sync the user initiated fails.") WPError.showNetworkingNotice(title: title, error: error) } @@ -1045,6 +1050,11 @@ class AbstractPostListViewController: UIViewController, WPContentSyncHelperDeleg @objc func promptThatPostRestoredToFilter(_ filter: PostListFilter) { assert(false, "You should implement this method in the subclass") } + + private func dismissAllNetworkErrorNotices() { + dismissNoNetworkAlert() + WPError.dismissNetworkingNotice() + } // MARK: - Post Actions diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift b/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift index 516f80feccf3..c41f60554b4d 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift @@ -275,6 +275,8 @@ import WordPressFlux override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) + + dismissNoNetworkAlert() // We want to listen for any changes (following, liked) in a post detail so we can refresh the child context. let mainContext = ContextManager.sharedInstance().mainContext diff --git a/WordPress/Classes/ViewRelated/System/NetworkAware.swift b/WordPress/Classes/ViewRelated/System/NetworkAware.swift index 9d11ea367e65..df014e5ebe6c 100644 --- a/WordPress/Classes/ViewRelated/System/NetworkAware.swift +++ b/WordPress/Classes/ViewRelated/System/NetworkAware.swift @@ -10,6 +10,7 @@ protocol NetworkAwareUI: NetworkAware { func shouldPresentAlert() -> Bool func contentIsEmpty() -> Bool func presentNoNetworkAlert() + func dismissNoNetworkAlert() func noConnectionMessage() -> String } @@ -33,6 +34,10 @@ extension NetworkAwareUI { func presentNoNetworkAlert() { ReachabilityUtils.showNoInternetConnectionNotice() } + + func dismissNoNetworkAlert() { + ReachabilityUtils.dismissNoInternetConnectionNotice() + } func noConnectionMessage() -> String { return ReachabilityUtils.noConnectionMessage() From efa3ce4b6305687c5a43457fde53d8328b01a097 Mon Sep 17 00:00:00 2001 From: Shiki Date: Thu, 28 Feb 2019 14:24:07 -0700 Subject: [PATCH 08/12] Fix lint errors --- WordPress/Classes/Stores/NoticeStore.swift | 2 +- .../Classes/Utility/ReachabilityUtils+OnlineActions.swift | 4 ++-- WordPress/Classes/Utility/WPError.swift | 8 ++++---- .../Comments/CommentsViewController+NetworkAware.swift | 2 +- .../Controllers/NotificationsViewController.swift | 2 +- .../ViewRelated/Post/AbstractPostListViewController.swift | 8 ++++---- .../ViewRelated/Reader/ReaderStreamViewController.swift | 2 +- WordPress/Classes/ViewRelated/System/NetworkAware.swift | 2 +- 8 files changed, 15 insertions(+), 15 deletions(-) diff --git a/WordPress/Classes/Stores/NoticeStore.swift b/WordPress/Classes/Stores/NoticeStore.swift index 312e57234b51..422b03eadd64 100644 --- a/WordPress/Classes/Stores/NoticeStore.swift +++ b/WordPress/Classes/Stores/NoticeStore.swift @@ -33,7 +33,7 @@ struct Notice { /// A title for an optional cancel button that can be displayed as part of a notice /// let cancelTitle: String? - + /// An optional value that can be used as a reference by consumers. /// /// This is not used in the Notice system at all. diff --git a/WordPress/Classes/Utility/ReachabilityUtils+OnlineActions.swift b/WordPress/Classes/Utility/ReachabilityUtils+OnlineActions.swift index afb021fc1932..87c4e6938b2f 100644 --- a/WordPress/Classes/Utility/ReachabilityUtils+OnlineActions.swift +++ b/WordPress/Classes/Utility/ReachabilityUtils+OnlineActions.swift @@ -49,14 +49,14 @@ extension ReachabilityUtils { tag: NoConnectionMessage.tag) ActionDispatcher.dispatch(NoticeAction.post(notice)) } - + /// Dismiss the currently shown Notice if it was created using showNoInternetConnectionNotice() @objc static func dismissNoInternetConnectionNotice() { if StoreContainer.shared.notice.state.notice?.tag == NoConnectionMessage.tag { noticePresenter?.dismissCurrentNotice() } } - + private static var noticePresenter: NoticePresenter? { return (UIApplication.shared.delegate as? WordPressAppDelegate)?.noticePresenter } diff --git a/WordPress/Classes/Utility/WPError.swift b/WordPress/Classes/Utility/WPError.swift index 49a5688a9ddb..21b7c56c909c 100644 --- a/WordPress/Classes/Utility/WPError.swift +++ b/WordPress/Classes/Utility/WPError.swift @@ -4,7 +4,7 @@ import WordPressFlux extension WPError { private static let noticeTag = "WPError.Networking" - + /// Show a Notice with the message taken from the given `error` /// /// This is similar to `showNetworkingAlertWithError` except this uses a Notice instead of @@ -15,7 +15,7 @@ extension WPError { if showWPComSigninIfErrorIsInvalidAuth(error) { return } - + let titleAndMessage = self.titleAndMessage(fromNetworkingError: error, desiredTitle: title) let notice = Notice(title: titleAndMessage["title"] ?? "", @@ -23,14 +23,14 @@ extension WPError { tag: noticeTag) ActionDispatcher.dispatch(NoticeAction.post(notice)) } - + /// Dismiss the currently shown Notice if it was created using showNetworkingNotice() static func dismissNetworkingNotice() { if StoreContainer.shared.notice.state.notice?.tag == noticeTag { noticePresenter?.dismissCurrentNotice() } } - + private static var noticePresenter: NoticePresenter? { return (UIApplication.shared.delegate as? WordPressAppDelegate)?.noticePresenter } diff --git a/WordPress/Classes/ViewRelated/Comments/CommentsViewController+NetworkAware.swift b/WordPress/Classes/ViewRelated/Comments/CommentsViewController+NetworkAware.swift index 566c736ae1eb..d3555eb27b64 100644 --- a/WordPress/Classes/ViewRelated/Comments/CommentsViewController+NetworkAware.swift +++ b/WordPress/Classes/ViewRelated/Comments/CommentsViewController+NetworkAware.swift @@ -18,7 +18,7 @@ extension CommentsViewController: NetworkAwareUI { presentNoNetworkAlert() } } - + @objc func dismissConnectionErrorNotice() { dismissNoNetworkAlert() } diff --git a/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationsViewController.swift b/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationsViewController.swift index 3275fa96c6b9..3771d3127a45 100644 --- a/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationsViewController.swift +++ b/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationsViewController.swift @@ -167,7 +167,7 @@ class NotificationsViewController: UITableViewController, UIViewControllerRestor override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) stopListeningToNotifications() - + dismissNoNetworkAlert() // If we're not onscreen, don't use row animations. Otherwise the fade animation might get animated incrementally diff --git a/WordPress/Classes/ViewRelated/Post/AbstractPostListViewController.swift b/WordPress/Classes/ViewRelated/Post/AbstractPostListViewController.swift index 7b0934ff6f50..841b589a5d77 100644 --- a/WordPress/Classes/ViewRelated/Post/AbstractPostListViewController.swift +++ b/WordPress/Classes/ViewRelated/Post/AbstractPostListViewController.swift @@ -239,7 +239,7 @@ class AbstractPostListViewController: UIViewController, WPContentSyncHelperDeleg if searchController.isActive { searchController.isActive = false } - + dismissAllNetworkErrorNotices() NotificationCenter.default.removeObserver(self, name: UIApplication.didBecomeActiveNotification, object: nil) @@ -782,9 +782,9 @@ class AbstractPostListViewController: UIViewController, WPContentSyncHelperDeleg promptForPassword() return } - + dismissAllNetworkErrorNotices() - + let title = NSLocalizedString("Unable to Sync", comment: "Title of error prompt shown when a sync the user initiated fails.") WPError.showNetworkingNotice(title: title, error: error) } @@ -1050,7 +1050,7 @@ class AbstractPostListViewController: UIViewController, WPContentSyncHelperDeleg @objc func promptThatPostRestoredToFilter(_ filter: PostListFilter) { assert(false, "You should implement this method in the subclass") } - + private func dismissAllNetworkErrorNotices() { dismissNoNetworkAlert() WPError.dismissNetworkingNotice() diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift b/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift index c41f60554b4d..4cfd3d10fbf7 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift @@ -275,7 +275,7 @@ import WordPressFlux override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) - + dismissNoNetworkAlert() // We want to listen for any changes (following, liked) in a post detail so we can refresh the child context. diff --git a/WordPress/Classes/ViewRelated/System/NetworkAware.swift b/WordPress/Classes/ViewRelated/System/NetworkAware.swift index df014e5ebe6c..c49f6bc700d0 100644 --- a/WordPress/Classes/ViewRelated/System/NetworkAware.swift +++ b/WordPress/Classes/ViewRelated/System/NetworkAware.swift @@ -34,7 +34,7 @@ extension NetworkAwareUI { func presentNoNetworkAlert() { ReachabilityUtils.showNoInternetConnectionNotice() } - + func dismissNoNetworkAlert() { ReachabilityUtils.dismissNoInternetConnectionNotice() } From a91fb59fcac636658bdb4ccab3c1dba9fd7517fa Mon Sep 17 00:00:00 2001 From: Shiki Date: Thu, 28 Feb 2019 16:37:01 -0700 Subject: [PATCH 09/12] Move tag-based dismissal to NoticePresenter --- WordPress/Classes/Stores/NoticeStore.swift | 2 +- .../Classes/Utility/ReachabilityUtils+OnlineActions.swift | 4 +--- WordPress/Classes/Utility/WPError.swift | 4 +--- .../ViewRelated/System/Notices/NoticePresenter.swift | 8 ++++++++ 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/WordPress/Classes/Stores/NoticeStore.swift b/WordPress/Classes/Stores/NoticeStore.swift index 422b03eadd64..b95adea7d8d6 100644 --- a/WordPress/Classes/Stores/NoticeStore.swift +++ b/WordPress/Classes/Stores/NoticeStore.swift @@ -105,7 +105,7 @@ enum NoticeAction: Action { struct NoticeStoreState { - fileprivate(set) var notice: Notice? + fileprivate var notice: Notice? } /// NoticeStore queues notices for display to the user. diff --git a/WordPress/Classes/Utility/ReachabilityUtils+OnlineActions.swift b/WordPress/Classes/Utility/ReachabilityUtils+OnlineActions.swift index 87c4e6938b2f..37ed9abc1c0a 100644 --- a/WordPress/Classes/Utility/ReachabilityUtils+OnlineActions.swift +++ b/WordPress/Classes/Utility/ReachabilityUtils+OnlineActions.swift @@ -52,9 +52,7 @@ extension ReachabilityUtils { /// Dismiss the currently shown Notice if it was created using showNoInternetConnectionNotice() @objc static func dismissNoInternetConnectionNotice() { - if StoreContainer.shared.notice.state.notice?.tag == NoConnectionMessage.tag { - noticePresenter?.dismissCurrentNotice() - } + noticePresenter?.dismissCurrentNotice(tagged: NoConnectionMessage.tag) } private static var noticePresenter: NoticePresenter? { diff --git a/WordPress/Classes/Utility/WPError.swift b/WordPress/Classes/Utility/WPError.swift index 21b7c56c909c..3aee1878eb85 100644 --- a/WordPress/Classes/Utility/WPError.swift +++ b/WordPress/Classes/Utility/WPError.swift @@ -26,9 +26,7 @@ extension WPError { /// Dismiss the currently shown Notice if it was created using showNetworkingNotice() static func dismissNetworkingNotice() { - if StoreContainer.shared.notice.state.notice?.tag == noticeTag { - noticePresenter?.dismissCurrentNotice() - } + noticePresenter?.dismissCurrentNotice(tagged: noticeTag) } private static var noticePresenter: NoticePresenter? { diff --git a/WordPress/Classes/ViewRelated/System/Notices/NoticePresenter.swift b/WordPress/Classes/ViewRelated/System/Notices/NoticePresenter.swift index e773a5522451..47823ace65bd 100644 --- a/WordPress/Classes/ViewRelated/System/Notices/NoticePresenter.swift +++ b/WordPress/Classes/ViewRelated/System/Notices/NoticePresenter.swift @@ -189,6 +189,14 @@ class NoticePresenter: NSObject { dismiss(container: container) } + /// Dismiss the currently shown `Notice` if its `tag` is equal to the given `tag`. + public func dismissCurrentNotice(tagged tag: String) { + // It's named _nextNotice_ but it really is the _current_ Notice in NoticeStore.state + if store.nextNotice?.tag == tag { + dismissCurrentNotice() + } + } + private func dismiss(container: NoticeContainerView) { guard container.superview != nil else { return From 334e0ef76a025f40f6ec2a20188fd12a390951cf Mon Sep 17 00:00:00 2001 From: Shiki Date: Thu, 28 Feb 2019 16:38:06 -0700 Subject: [PATCH 10/12] Rename WPError.swift to WPError+Swift.swift This follows the current convention. --- .../Utility/{WPError.swift => WPError+Swift.swift} | 0 WordPress/WordPress.xcodeproj/project.pbxproj | 8 ++++---- 2 files changed, 4 insertions(+), 4 deletions(-) rename WordPress/Classes/Utility/{WPError.swift => WPError+Swift.swift} (100%) diff --git a/WordPress/Classes/Utility/WPError.swift b/WordPress/Classes/Utility/WPError+Swift.swift similarity index 100% rename from WordPress/Classes/Utility/WPError.swift rename to WordPress/Classes/Utility/WPError+Swift.swift diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index d76ae34262dc..44a0a95cdb11 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -336,7 +336,7 @@ 462F4E0A18369F0B0028D2F8 /* BlogDetailsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 462F4E0718369F0B0028D2F8 /* BlogDetailsViewController.m */; }; 4645AFC51961E1FB005F7509 /* AppImages.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4645AFC41961E1FB005F7509 /* AppImages.xcassets */; }; 4C8A715EBCE7E73AEE216293 /* Pods_WordPressShareExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F47DB4A8EC2E6844E213A3FA /* Pods_WordPressShareExtension.framework */; }; - 57D5812D2228526C002BAAD7 /* WPError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57D5812C2228526C002BAAD7 /* WPError.swift */; }; + 57D5812D2228526C002BAAD7 /* WPError+Swift.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57D5812C2228526C002BAAD7 /* WPError+Swift.swift */; }; 5903AE1B19B60A98009D5354 /* WPButtonForNavigationBar.m in Sources */ = {isa = PBXBuildFile; fileRef = 5903AE1A19B60A98009D5354 /* WPButtonForNavigationBar.m */; }; 590E873B1CB8205700D1B734 /* PostListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 590E873A1CB8205700D1B734 /* PostListViewController.swift */; }; 591232691CCEAA5100B86207 /* AbstractPostListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 591232681CCEAA5100B86207 /* AbstractPostListViewController.swift */; }; @@ -2177,7 +2177,7 @@ 4F943DB9A7237917709622D5 /* Pods-WordPressNotificationContentExtension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WordPressNotificationContentExtension.debug.xcconfig"; path = "../Pods/Target Support Files/Pods-WordPressNotificationContentExtension/Pods-WordPressNotificationContentExtension.debug.xcconfig"; sourceTree = ""; }; 51A5F017948878F7E26979A0 /* Pods-WordPress.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WordPress.release.xcconfig"; path = "../Pods/Target Support Files/Pods-WordPress/Pods-WordPress.release.xcconfig"; sourceTree = ""; }; 556E3A9C1600564F6A3CADF6 /* Pods_WordPress.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_WordPress.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 57D5812C2228526C002BAAD7 /* WPError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WPError.swift; sourceTree = ""; }; + 57D5812C2228526C002BAAD7 /* WPError+Swift.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WPError+Swift.swift"; sourceTree = ""; }; 5903AE1A19B60A98009D5354 /* WPButtonForNavigationBar.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WPButtonForNavigationBar.m; sourceTree = ""; usesTabs = 0; }; 5903AE1C19B60AB9009D5354 /* WPButtonForNavigationBar.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WPButtonForNavigationBar.h; sourceTree = ""; usesTabs = 0; }; 590E873A1CB8205700D1B734 /* PostListViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PostListViewController.swift; sourceTree = ""; }; @@ -5892,7 +5892,7 @@ 5D6C4B051B603E03005E3C43 /* WPContentSyncHelper.swift */, E114D798153D85A800984182 /* WPError.h */, E114D799153D85A800984182 /* WPError.m */, - 57D5812C2228526C002BAAD7 /* WPError.swift */, + 57D5812C2228526C002BAAD7 /* WPError+Swift.swift */, 5D6C4B061B603E03005E3C43 /* WPTableViewHandler.h */, 5D6C4B071B603E03005E3C43 /* WPTableViewHandler.m */, E1F5A1BA1771C90A00E0495F /* WPTableImageSource.h */, @@ -9635,7 +9635,7 @@ 740516892087B73400252FD0 /* SearchableActivityConvertable.swift in Sources */, B5F641B31E37C36700B7819F /* AdaptiveNavigationController.swift in Sources */, 74BC35B820499EEB00AC1525 /* RemotePostCategory+Extensions.swift in Sources */, - 57D5812D2228526C002BAAD7 /* WPError.swift in Sources */, + 57D5812D2228526C002BAAD7 /* WPError+Swift.swift in Sources */, 825327581FBF7CD600B8B7D2 /* ActivityUtils.swift in Sources */, 080AAA691E7C63C3004DCD11 /* Media+HTML.m in Sources */, 59DD94341AC479ED0032DD6B /* WPLogger.m in Sources */, From 3b758b473213eb93fdc34885e304cd975e5f417e Mon Sep 17 00:00:00 2001 From: Shiki Date: Thu, 28 Feb 2019 16:43:17 -0700 Subject: [PATCH 11/12] Remove unnecessary @objc annotations --- .../Classes/Utility/ReachabilityUtils+OnlineActions.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/WordPress/Classes/Utility/ReachabilityUtils+OnlineActions.swift b/WordPress/Classes/Utility/ReachabilityUtils+OnlineActions.swift index 37ed9abc1c0a..16e098993ce9 100644 --- a/WordPress/Classes/Utility/ReachabilityUtils+OnlineActions.swift +++ b/WordPress/Classes/Utility/ReachabilityUtils+OnlineActions.swift @@ -43,7 +43,7 @@ extension ReachabilityUtils { /// /// We use a Snackbar instead of a literal Alert because, for internet connection errors, /// Alerts can be disruptive. - @objc static func showNoInternetConnectionNotice() { + static func showNoInternetConnectionNotice() { let notice = Notice(title: NoConnectionMessage.title, message: NoConnectionMessage.message, tag: NoConnectionMessage.tag) @@ -51,7 +51,7 @@ extension ReachabilityUtils { } /// Dismiss the currently shown Notice if it was created using showNoInternetConnectionNotice() - @objc static func dismissNoInternetConnectionNotice() { + static func dismissNoInternetConnectionNotice() { noticePresenter?.dismissCurrentNotice(tagged: NoConnectionMessage.tag) } From 11c929e7855342aafe730c85bc5af3b1baa5b597 Mon Sep 17 00:00:00 2001 From: Shiki Date: Tue, 5 Mar 2019 08:29:49 -0800 Subject: [PATCH 12/12] Updated RELEASE-NOTES.txt --- RELEASE-NOTES.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt index 4408be53d0fe..8975d405567d 100644 --- a/RELEASE-NOTES.txt +++ b/RELEASE-NOTES.txt @@ -1,6 +1,7 @@ 12.0 ----- * Redesigned Notices +* Changed offline error messages to be less disruptive. 11.9 ------