Skip to content

Commit 372fc10

Browse files
authored
Comments: Fix "Trash" trailing action not updating the status of the comments cached on the device (#25485)
* Fix an issue with Trash button not updating the comment status * Remove usages of onAvailableInternetConnectionDo * Add missing alert * Update release notes * Update unit tests
1 parent 8b51f6d commit 372fc10

6 files changed

Lines changed: 66 additions & 15 deletions

File tree

RELEASE-NOTES.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
26.9
22
-----
33
* [*] All self-hosted sites now sign in using application passwords [#25424]
4+
* [*] Comments: Fix "Trash" trailing action not updating the status of the comments cached on the device [#25485]
45
* [*] Stats: Add a confirmation dialog when marking referrers as spam [#25475]
56
* [*] Reader: Fix an issue with Article screen not updating comments if comment is posted from inline section [#25483]
67
* [*] Reader: Fix button style [#25447]

Tests/KeystoneTests/Tests/Services/CommentService+MorderationTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ final class CommentService_MorderationTests: CoreDataTestCase {
183183
wait(for: [exp], timeout: 5)
184184

185185
// The local comment should not be changed
186-
XCTAssertEqual(self.comment.status, CommentStatusType.pending.description)
186+
XCTAssertEqual(self.comment.status, "trash")
187187
}
188188

189189
}

WordPress/Classes/Services/CommentService.m

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -528,8 +528,28 @@ - (void)deleteComment:(Comment *)comment
528528
id<CommentServiceRemote> remote = [self remoteForBlog:comment.blog];
529529

530530
// If the Comment is not permanently deleted, don't remove it from the local cache as it can still be displayed.
531+
// Optimistically update the status so the comment is immediately removed from filtered views.
531532
if (!comment.deleteWillBePermanent) {
532-
[remote trashComment:remoteComment success:success failure:failure];
533+
NSString *prevStatus = comment.status;
534+
NSString *trashStatus = [Comment descriptionFor:CommentStatusTypeUnapproved];
535+
536+
[self.coreDataStack performAndSaveUsingBlock:^(NSManagedObjectContext *context) {
537+
Comment *commentInContext = [context existingObjectWithID:comment.objectID error:nil];
538+
commentInContext.status = trashStatus;
539+
}];
540+
comment.status = trashStatus;
541+
542+
[remote trashComment:remoteComment success:success failure:^(NSError *error) {
543+
// Revert status on failure.
544+
[self.coreDataStack performAndSaveUsingBlock:^(NSManagedObjectContext *context) {
545+
Comment *commentInContext = [context existingObjectWithID:comment.objectID error:nil];
546+
commentInContext.status = prevStatus;
547+
} completion:^{
548+
if (failure) {
549+
failure(error);
550+
}
551+
} onQueue:dispatch_get_main_queue()];
552+
}];
533553
return;
534554
}
535555

WordPress/Classes/Utility/Reachability/ReachabilityUtils+OnlineActions.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ extension ReachabilityUtils {
1616
/// - warning: Do not use it as it can't reliably identify as the connection
1717
/// is reachable or not and can significantly lag behind the actual
1818
/// connectivity status.
19-
@objc public class func onAvailableInternetConnectionDo(_ action: () -> Void) {
19+
public class func onAvailableInternetConnectionDo(_ action: () -> Void) {
2020
guard ReachabilityUtils.isInternetReachable() else {
2121
WPError.showAlert(withTitle: DefaultNoConnectionMessage.title, message: DefaultNoConnectionMessage.message)
2222
return

WordPress/Classes/ViewRelated/Comments/Controllers/CommentsViewController+Swift.swift

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,4 +75,34 @@ extension CommentsViewController {
7575
}
7676
return item == CommentFilter.unreplied
7777
}
78+
79+
@objc public func showApproveCommentErrorNotice(_ error: NSError) {
80+
Notice(error: error, title: Strings.approveError).post()
81+
}
82+
83+
@objc public func showUnapproveCommentErrorNotice(_ error: NSError) {
84+
Notice(error: error, title: Strings.unapproveError).post()
85+
}
86+
87+
@objc public func showTrashCommentErrorNotice(_ error: NSError) {
88+
Notice(error: error, title: Strings.trashError).post()
89+
}
90+
}
91+
92+
private enum Strings {
93+
static let approveError = NSLocalizedString(
94+
"comments.approve.error.title",
95+
value: "Error approving comment",
96+
comment: "Title for the error notice shown when approving a comment fails."
97+
)
98+
static let unapproveError = NSLocalizedString(
99+
"comments.unapprove.error.title",
100+
value: "Error unapproving comment",
101+
comment: "Title for the error notice shown when unapproving a comment fails."
102+
)
103+
static let trashError = NSLocalizedString(
104+
"comments.trash.error.title",
105+
value: "Error trashing comment",
106+
comment: "Title for the error notice shown when trashing a comment fails."
107+
)
78108
}

WordPress/Classes/ViewRelated/Comments/Controllers/CommentsViewController.m

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -318,9 +318,7 @@ - (UISwipeActionsConfiguration *)tableView:(UITableView *)tableView trailingSwip
318318

319319
// Trash Action
320320
UIContextualAction *trash = [UIContextualAction contextualActionWithStyle:UIContextualActionStyleDestructive title:NSLocalizedString(@"Trash", @"Trashes a comment") handler:^(UIContextualAction * _Nonnull __unused action, __kindof UIView * _Nonnull __unused sourceView, void (^ _Nonnull completionHandler)(BOOL)) {
321-
[ReachabilityUtils onAvailableInternetConnectionDo:^{
322-
[weakSelf deleteComment:comment];
323-
}];
321+
[weakSelf deleteComment:comment];
324322
completionHandler(YES);
325323
}];
326324

@@ -331,9 +329,7 @@ - (UISwipeActionsConfiguration *)tableView:(UITableView *)tableView trailingSwip
331329

332330
// Unapprove Action
333331
UIContextualAction *unapprove = [UIContextualAction contextualActionWithStyle:UIContextualActionStyleNormal title:NSLocalizedString(@"Unapprove", @"Unapproves a Comment") handler:^(UIContextualAction * _Nonnull __unused action, __kindof UIView * _Nonnull __unused sourceView, void (^ _Nonnull completionHandler)(BOOL)) {
334-
[ReachabilityUtils onAvailableInternetConnectionDo:^{
335-
[weakSelf unapproveComment:comment];
336-
}];
332+
[weakSelf unapproveComment:comment];
337333
completionHandler(YES);
338334
}];
339335

@@ -342,9 +338,7 @@ - (UISwipeActionsConfiguration *)tableView:(UITableView *)tableView trailingSwip
342338
} else {
343339
// Approve Action
344340
UIContextualAction *approve = [UIContextualAction contextualActionWithStyle:UIContextualActionStyleNormal title:NSLocalizedString(@"Approve", @"Approves a Comment") handler:^(UIContextualAction * _Nonnull __unused action, __kindof UIView * _Nonnull __unused sourceView, void (^ _Nonnull completionHandler)(BOOL)) {
345-
[ReachabilityUtils onAvailableInternetConnectionDo:^{
346-
[weakSelf approveComment:comment];
347-
}];
341+
[weakSelf approveComment:comment];
348342
completionHandler(YES);
349343
}];
350344

@@ -362,31 +356,37 @@ - (void)approveComment:(Comment *)comment
362356
[CommentAnalytics trackCommentUnApprovedWithComment:comment];
363357
CommentService *service = [[CommentService alloc] initWithCoreDataStack:[ContextManager sharedInstance]];;
364358

359+
__typeof(self) __weak weakSelf = self;
365360
[self.tableView setEditing:NO animated:YES];
366361
[service approveComment:comment success:nil failure:^(NSError *error) {
367362
DDLogError(@"Error approving comment: %@", error);
363+
[weakSelf showApproveCommentErrorNotice:error];
368364
}];
369365
}
370366

371367
- (void)unapproveComment:(Comment *)comment
372368
{
373369
[CommentAnalytics trackCommentUnApprovedWithComment:comment];
374370
CommentService *service = [[CommentService alloc] initWithCoreDataStack:[ContextManager sharedInstance]];
375-
371+
372+
__typeof(self) __weak weakSelf = self;
376373
[self.tableView setEditing:NO animated:YES];
377374
[service unapproveComment:comment success:nil failure:^(NSError *error) {
378375
DDLogError(@"Error unapproving comment: %@", error);
376+
[weakSelf showUnapproveCommentErrorNotice:error];
379377
}];
380378
}
381379

382380
- (void)deleteComment:(Comment *)comment
383381
{
384382
[CommentAnalytics trackCommentTrashedWithComment:comment];
385383
CommentService *service = [[CommentService alloc] initWithCoreDataStack:[ContextManager sharedInstance]];
386-
384+
385+
__typeof(self) __weak weakSelf = self;
387386
[self.tableView setEditing:NO animated:YES];
388387
[service deleteComment:comment success:nil failure:^(NSError *error) {
389388
DDLogError(@"Error deleting comment: %@", error);
389+
[weakSelf showTrashCommentErrorNotice:error];
390390
}];
391391
}
392392

@@ -488,7 +488,7 @@ - (NSPredicate *)predicateForFetchRequest:(CommentStatusFilter)statusFilter
488488
{
489489
NSPredicate *predicate;
490490
if (statusFilter == CommentStatusFilterAll && ![self isUnrepliedFilterSelected:self.filterTabBar]) {
491-
predicate = [NSPredicate predicateWithFormat:@"(blog == %@)", self.blog];
491+
predicate = [NSPredicate predicateWithFormat:@"(blog == %@) AND NOT (status IN %@)", self.blog, @[@"trash", @"spam"]];
492492
} else {
493493
// Exclude any local replies from all filters except all.
494494
predicate = [NSPredicate predicateWithFormat:@"(blog == %@) AND commentID != nil", self.blog];

0 commit comments

Comments
 (0)