From c74a857dbc29ec6b268d5d7b7dafba3ec8f76b64 Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 3 Jan 2025 10:54:37 -0500 Subject: [PATCH 1/4] Remove preflight connection check when sending replies (can be lagging behind) --- .../Notifications/ReplyTextView/ReplyTextView.swift | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Notifications/ReplyTextView/ReplyTextView.swift b/WordPress/Classes/ViewRelated/Notifications/ReplyTextView/ReplyTextView.swift index 003e65a7ff59..3659cc60322e 100644 --- a/WordPress/Classes/ViewRelated/Notifications/ReplyTextView/ReplyTextView.swift +++ b/WordPress/Classes/ViewRelated/Notifications/ReplyTextView/ReplyTextView.swift @@ -147,17 +147,6 @@ import Gridicons return } - // We can't reply without an internet connection - let appDelegate = WordPressAppDelegate.shared - guard appDelegate!.connectionAvailable 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) - textView.resignFirstResponder() - return - } - // Load the new text let newText = textView.text textView.resignFirstResponder() From b1709b74ee89def9673597b7331b5fe12ce50631 Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 3 Jan 2025 11:19:11 -0500 Subject: [PATCH 2/4] Fix an issue with comments disppearing if request fails --- .../ReplyTextView/ReplyTextView.swift | 27 ++++++++++++------- .../ReplyTextView/ReplyTextView.xib | 5 ++-- .../Comments/ReaderCommentsViewController.m | 10 ++++++- 3 files changed, 29 insertions(+), 13 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Notifications/ReplyTextView/ReplyTextView.swift b/WordPress/Classes/ViewRelated/Notifications/ReplyTextView/ReplyTextView.swift index 3659cc60322e..924ddcb1c32a 100644 --- a/WordPress/Classes/ViewRelated/Notifications/ReplyTextView/ReplyTextView.swift +++ b/WordPress/Classes/ViewRelated/Notifications/ReplyTextView/ReplyTextView.swift @@ -143,19 +143,14 @@ import Gridicons // MARK: - IBActions @IBAction fileprivate func btnReplyPressed() { - guard let handler = onReply else { - return - } + guard let onReply else { return } // Load the new text let newText = textView.text textView.resignFirstResponder() - // Cleanup + Shrink - text = String() - // Hit the handler - handler(newText!) + onReply(newText ?? "") } @IBAction fileprivate func btnEnterFullscreenPressed(_ sender: Any) { @@ -275,8 +270,12 @@ import Gridicons comment: "Accessibility Label for the enter full screen button on the comment reply text view") // Reply button - replyButton.setTitleColor(UIAppColor.brand, for: .normal) - replyButton.titleLabel?.text = NSLocalizedString("Reply", comment: "Reply to a comment.") + replyButton.configuration = { + var configuration = UIButton.Configuration.plain() + configuration.baseForegroundColor = UIAppColor.brand + configuration.title = NSLocalizedString("Reply", comment: "Reply to a comment.") + return configuration + }() replyButton.accessibilityIdentifier = "reply-button" replyButton.accessibilityLabel = NSLocalizedString("Reply", comment: "Accessibility label for the reply button") refreshReplyButton() @@ -297,6 +296,16 @@ import Gridicons frame.size.height = minimumHeight } + @objc func setShowingLoadingIndicator(_ isLoading: Bool) { + isUserInteractionEnabled = !isLoading + + textView.alpha = isLoading ? 0.33 : 1.0 + + replyButton.isEnabled = !isLoading + replyButton.configuration?.title = isLoading ? nil : NSLocalizedString("Reply", comment: "Reply to a comment.") + replyButton.configuration?.showsActivityIndicator = isLoading + } + // MARK: - Refresh Helpers fileprivate func refreshInterface() { refreshPlaceholder() diff --git a/WordPress/Classes/ViewRelated/Notifications/ReplyTextView/ReplyTextView.xib b/WordPress/Classes/ViewRelated/Notifications/ReplyTextView/ReplyTextView.xib index bff11aee058d..873787813b75 100644 --- a/WordPress/Classes/ViewRelated/Notifications/ReplyTextView/ReplyTextView.xib +++ b/WordPress/Classes/ViewRelated/Notifications/ReplyTextView/ReplyTextView.xib @@ -1,9 +1,9 @@ - + - + @@ -102,7 +102,6 @@ - diff --git a/WordPress/Classes/ViewRelated/Reader/Comments/ReaderCommentsViewController.m b/WordPress/Classes/ViewRelated/Reader/Comments/ReaderCommentsViewController.m index 2caa6da68a6d..e0610eaedf52 100644 --- a/WordPress/Classes/ViewRelated/Reader/Comments/ReaderCommentsViewController.m +++ b/WordPress/Classes/ViewRelated/Reader/Comments/ReaderCommentsViewController.m @@ -916,6 +916,9 @@ - (void)sendReplyWithNewContent:(NSString *)content NSString *successMessage = NSLocalizedString(@"Reply Sent!", @"The app successfully sent a comment"); [weakSelf displayNoticeWithTitle:successMessage message:nil]; + [weakSelf.replyTextView setShowingLoadingIndicator:NO]; + weakSelf.replyTextView.text = @""; + [weakSelf trackReplyTo:replyToComment]; [weakSelf.tableView deselectSelectedRowWithAnimation:YES]; [weakSelf refreshReplyTextViewPlaceholder]; @@ -931,11 +934,16 @@ - (void)sendReplyWithNewContent:(NSString *)content DDLogError(@"Error sending reply: %@", error); [generator notificationOccurred:UINotificationFeedbackTypeError]; NSString *message = NSLocalizedString(@"There has been an unexpected error while sending your reply", "Reply Failure Message"); - [weakSelf displayNoticeWithTitle:message message:nil]; + [weakSelf.replyTextView setShowingLoadingIndicator:NO]; + [weakSelf displayNoticeWithTitle:message message:[error localizedDescription]]; + + [weakSelf.replyTextView becomeFirstResponder]; [weakSelf refreshTableViewAndNoResultsView:NO]; }; + [self.replyTextView setShowingLoadingIndicator:YES]; + CommentService *service = [[CommentService alloc] initWithCoreDataStack:[ContextManager sharedInstance]]; if (replyToComment) { From d847e8a0d2b424a3f26d5096da5248e81b0d504d Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 3 Jan 2025 11:32:21 -0500 Subject: [PATCH 3/4] Update other screens using TextView --- .../CommentDetailViewController.swift | 23 ++++++++++++++----- .../NotificationDetailsViewController.swift | 17 ++++++++++---- 2 files changed, 29 insertions(+), 11 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Comments/Controllers/CommentDetailViewController.swift b/WordPress/Classes/ViewRelated/Comments/Controllers/CommentDetailViewController.swift index 7b0a4c918050..679cfb7551e6 100644 --- a/WordPress/Classes/ViewRelated/Comments/Controllers/CommentDetailViewController.swift +++ b/WordPress/Classes/ViewRelated/Comments/Controllers/CommentDetailViewController.swift @@ -1068,13 +1068,15 @@ private extension CommentDetailViewController { return } + replyTextView?.setShowingLoadingIndicator(true) + commentService.createReply(for: comment, content: content) { reply in self.commentService.uploadComment(reply, success: { [weak self] in - self?.displayReplyNotice(success: true) + self?.didSendReply(success: true) self?.refreshCommentReplyIfNeeded() }, failure: { [weak self] error in DDLogError("Failed uploading comment reply: \(String(describing: error))") - self?.displayReplyNotice(success: false) + self?.didSendReply(success: false, error: error) }) } } @@ -1084,21 +1086,30 @@ private extension CommentDetailViewController { return } + replyTextView?.setShowingLoadingIndicator(true) + commentService.replyToHierarchicalComment(withID: NSNumber(value: comment.commentID), post: post, content: content, success: { [weak self] in - self?.displayReplyNotice(success: true) + self?.didSendReply(success: true) self?.refreshCommentReplyIfNeeded() }, failure: { [weak self] error in DDLogError("Failed creating post comment reply: \(String(describing: error))") - self?.displayReplyNotice(success: false) + self?.didSendReply(success: false, error: error) }) } - func displayReplyNotice(success: Bool) { + func didSendReply(success: Bool, error: Error? = nil) { + replyTextView?.setShowingLoadingIndicator(false) + if success { + replyTextView?.text = "" + } else { + replyTextView?.becomeFirstResponder() + } + let message = success ? ReplyMessages.successMessage : ReplyMessages.failureMessage - displayNotice(title: message) + displayNotice(title: message, message: error?.localizedDescription) } func configureSuggestionsView() { diff --git a/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationDetailsViewController.swift b/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationDetailsViewController.swift index 27a99751b05b..006525b144ff 100644 --- a/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationDetailsViewController.swift +++ b/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationDetailsViewController.swift @@ -417,12 +417,15 @@ extension NotificationDetailsViewController { replyTextView.accessibilityIdentifier = .replyTextViewAccessibilityId replyTextView.accessibilityLabel = NSLocalizedString("Reply Text", comment: "Notifications Reply Accessibility Identifier") replyTextView.delegate = self - replyTextView.onReply = { [weak self] content in - let group = self?.note.contentGroup(ofKind: .comment) + replyTextView.onReply = { [weak self, weak replyTextView] content in + guard let self, let replyTextView else { + return + } + let group = self.note.contentGroup(ofKind: .comment) guard let block: FormattableCommentContent = group?.blockOfKind(.comment) else { return } - self?.replyCommentWithBlock(block, content: content) + self.replyCommentWithBlock(block, content: content, textView: replyTextView) } replyTextView.setContentCompressionResistancePriority(.required, for: .vertical) @@ -1085,26 +1088,30 @@ private extension NotificationDetailsViewController { _ = navigationController?.popToRootViewController(animated: true) } - func replyCommentWithBlock(_ block: FormattableCommentContent, content: String) { + func replyCommentWithBlock(_ block: FormattableCommentContent, content: String, textView: ReplyTextView) { guard let replyAction = block.action(id: ReplyToCommentAction.actionIdentifier()) else { return } let generator = UINotificationFeedbackGenerator() generator.prepare() - generator.notificationOccurred(.success) let actionContext = ActionContext(block: block, content: content) { [weak self] (request, success) in + textView.setShowingLoadingIndicator(false) if success { + generator.notificationOccurred(.success) WPAppAnalytics.track(.notificationsCommentRepliedTo) + textView.text = "" let message = NSLocalizedString("Reply Sent!", comment: "The app successfully sent a comment") self?.displayNotice(title: message) } else { generator.notificationOccurred(.error) + textView.becomeFirstResponder() self?.displayReplyError(with: block, content: content) } } + textView.setShowingLoadingIndicator(true) replyAction.execute(context: actionContext) } From cb47b04e2310678152c90998be1b725071bc70e0 Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 3 Jan 2025 12:05:16 -0500 Subject: [PATCH 4/4] Update release notes --- RELEASE-NOTES.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt index 0be968bb772f..d099e643848f 100644 --- a/RELEASE-NOTES.txt +++ b/RELEASE-NOTES.txt @@ -11,6 +11,7 @@ * [*] Fix layout issues in Privacy Settings section of App Settings [#23936] * [*] Fix incorrect chevron icons direction in RTL languages [#23940] * [*] Fix an issue with clear navigation bar background in revision browser [#23941] +* [*] Fix an issue with comments being lost on request failure [#23942] 25.6 -----