ChatTableViewCell.m 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. /**
  2. * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors
  3. * SPDX-License-Identifier: GPL-3.0-or-later
  4. */
  5. #import "ChatTableViewCell.h"
  6. #import "NextcloudTalk-Swift.h"
  7. typedef void (^GetMenuUserActionsForMessageCompletionBlock)(NSArray *menuItems);
  8. @interface ChatTableViewCell () <UITextFieldDelegate>
  9. @property (nonatomic, strong) DRCellSlideGestureRecognizer *replyGestureRecognizer;
  10. @end
  11. @implementation ChatTableViewCell
  12. - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
  13. {
  14. self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
  15. if (self) {
  16. // Initialization
  17. }
  18. return self;
  19. }
  20. - (void)prepareForReuse
  21. {
  22. [super prepareForReuse];
  23. self.messageId = -1;
  24. self.message = nil;
  25. [self removeGestureRecognizer:self.replyGestureRecognizer];
  26. }
  27. - (void)addReplyGestureWithActionBlock:(DRCellSlideActionBlock)block
  28. {
  29. self.replyGestureRecognizer = [DRCellSlideGestureRecognizer new];
  30. self.replyGestureRecognizer.leftActionStartPosition = 80;
  31. DRCellSlideAction *action = [DRCellSlideAction actionForFraction:0.2];
  32. action.behavior = DRCellSlideActionPullBehavior;
  33. action.activeColor = [UIColor labelColor];
  34. action.inactiveColor = [UIColor placeholderTextColor];
  35. action.activeBackgroundColor = self.backgroundColor;
  36. action.inactiveBackgroundColor = self.backgroundColor;
  37. action.icon = [UIImage systemImageNamed:@"arrowshape.turn.up.left"];
  38. [action setWillTriggerBlock:^(UITableView *tableView, NSIndexPath *indexPath) {
  39. block(tableView, indexPath);
  40. }];
  41. [action setDidChangeStateBlock:^(DRCellSlideAction *action, BOOL active) {
  42. if (active) {
  43. // Actuate `Peek` feedback (weak boom)
  44. AudioServicesPlaySystemSound(1519);
  45. }
  46. }];
  47. [self.replyGestureRecognizer addActions:action];
  48. [self addGestureRecognizer:self.replyGestureRecognizer];
  49. }
  50. - (UIMenu *)getDeferredUserMenuForMessage:(NCChatMessage *)message
  51. {
  52. TalkAccount *activeAccount = [[NCDatabaseManager sharedInstance] activeAccount];
  53. if (![message.actorType isEqualToString:@"users"] || [message.actorId isEqualToString:activeAccount.userId]) {
  54. return nil;
  55. }
  56. UIDeferredMenuElement *deferredMenuElement;
  57. // Use an uncached provider so local time is not cached
  58. deferredMenuElement = [UIDeferredMenuElement elementWithUncachedProvider:^(void (^ _Nonnull completion)(NSArray<UIMenuElement *> * _Nonnull)) {
  59. [self getMenuUserActionsForMessage:message withCompletionBlock:^(NSArray *menuItems) {
  60. completion(menuItems);
  61. }];
  62. }];
  63. return [UIMenu menuWithTitle:message.actorDisplayName children:@[deferredMenuElement]];
  64. }
  65. - (void)getMenuUserActionsForMessage:(NCChatMessage *)message withCompletionBlock:(GetMenuUserActionsForMessageCompletionBlock)block
  66. {
  67. TalkAccount *activeAccount = [[NCDatabaseManager sharedInstance] activeAccount];
  68. [[NCAPIController sharedInstance] getUserActionsForUser:message.actorId usingAccount:activeAccount withCompletionBlock:^(NSDictionary *userActions, NSError *error) {
  69. if (error) {
  70. if (block) {
  71. UIAction *errorAction = [UIAction actionWithTitle:NSLocalizedString(@"No actions available", nil) image:nil identifier:nil handler:^(UIAction *action) {}];
  72. errorAction.attributes = UIMenuElementAttributesDisabled;
  73. block(@[errorAction]);
  74. }
  75. return;
  76. }
  77. NSArray *actions = [userActions objectForKey:@"actions"];
  78. if (![actions isKindOfClass:[NSArray class]]) {
  79. if (block) {
  80. UIAction *errorAction = [UIAction actionWithTitle:NSLocalizedString(@"No actions available", nil) image:nil identifier:nil handler:^(UIAction *action) {}];
  81. errorAction.attributes = UIMenuElementAttributesDisabled;
  82. block(@[errorAction]);
  83. }
  84. return;
  85. }
  86. NSMutableArray *items = [[NSMutableArray alloc] init];
  87. for (NSDictionary *action in actions) {
  88. NSString *appId = [action objectForKey:@"appId"];
  89. NSString *title = [action objectForKey:@"title"];
  90. NSString *link = [action objectForKey:@"hyperlink"];
  91. // Talk to user action
  92. if ([appId isEqualToString:@"spreed"]) {
  93. UIAction *talkAction = [UIAction actionWithTitle:title
  94. image:[[UIImage imageNamed:@"talk-20"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]
  95. identifier:nil
  96. handler:^(UIAction *action) {
  97. NSMutableDictionary *userInfo = [[NSMutableDictionary alloc] init];
  98. NSString *userId = [userActions objectForKey:@"userId"];
  99. [userInfo setObject:userId forKey:@"actorId"];
  100. [[NSNotificationCenter defaultCenter] postNotificationName:NSNotification.NCChatViewControllerTalkToUserNotification
  101. object:self
  102. userInfo:userInfo];
  103. }];
  104. [items addObject:talkAction];
  105. continue;
  106. }
  107. // Other user actions
  108. UIAction *otherAction = [UIAction actionWithTitle:title
  109. image:nil
  110. identifier:nil
  111. handler:^(UIAction *action) {
  112. NSURL *actionURL = [NSURL URLWithString:[link stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]]];
  113. [[UIApplication sharedApplication] openURL:actionURL options:@{} completionHandler:nil];
  114. }];
  115. if ([appId isEqualToString:@"profile"]) {
  116. [otherAction setImage:[UIImage systemImageNamed:@"person"]];
  117. } else if ([appId isEqualToString:@"email"]) {
  118. [otherAction setImage:[UIImage systemImageNamed:@"envelope"]];
  119. } else if ([appId isEqualToString:@"timezone"]) {
  120. [otherAction setImage:[UIImage systemImageNamed:@"clock"]];
  121. } else if ([appId isEqualToString:@"social"]) {
  122. [otherAction setImage:[UIImage systemImageNamed:@"heart"]];
  123. }
  124. [items addObject:otherAction];
  125. }
  126. if (block) {
  127. block(items);
  128. }
  129. }];
  130. }
  131. @end