Add custom swipe gesture for reply in chat cells.

Signed-off-by: Ivan Sein <ivan@nextcloud.com>
This commit is contained in:
Ivan Sein 2023-03-15 11:08:07 +01:00
Родитель 6f7cb89039
Коммит 7cb4f76ebb
12 изменённых файлов: 116 добавлений и 18 удалений

3
.gitmodules поставляемый
Просмотреть файл

@ -1,3 +1,6 @@
[submodule "ThirdParty/SlackTextViewController"] [submodule "ThirdParty/SlackTextViewController"]
path = ThirdParty/SlackTextViewController path = ThirdParty/SlackTextViewController
url = https://github.com/Ivansss/SlackTextViewController.git url = https://github.com/Ivansss/SlackTextViewController.git
[submodule "ThirdParty/DRCellSlideGestureRecognizer"]
path = ThirdParty/DRCellSlideGestureRecognizer
url = https://github.com/Ivansss/DRCellSlideGestureRecognizer.git

Просмотреть файл

@ -296,6 +296,9 @@
2CC007CA20E125C20096D91F /* NewRoomTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CC007C820E125C20096D91F /* NewRoomTableViewController.m */; }; 2CC007CA20E125C20096D91F /* NewRoomTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CC007C820E125C20096D91F /* NewRoomTableViewController.m */; };
2CC007CB20E125C20096D91F /* NewRoomTableViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2CC007C920E125C20096D91F /* NewRoomTableViewController.xib */; }; 2CC007CB20E125C20096D91F /* NewRoomTableViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2CC007C920E125C20096D91F /* NewRoomTableViewController.xib */; };
2CC007CE20E50B0A0096D91F /* MessageBodyTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CC007CD20E50B0A0096D91F /* MessageBodyTextView.m */; }; 2CC007CE20E50B0A0096D91F /* MessageBodyTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CC007CD20E50B0A0096D91F /* MessageBodyTextView.m */; };
2CC1C38629C0945700C8436B /* DRCellSlideGestureRecognizer.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CC1C38029C0945600C8436B /* DRCellSlideGestureRecognizer.m */; };
2CC1C38729C0945700C8436B /* DRCellSlideAction.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CC1C38429C0945700C8436B /* DRCellSlideAction.m */; };
2CC1C38829C0945700C8436B /* DRCellSlideActionView.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CC1C38529C0945700C8436B /* DRCellSlideActionView.m */; };
2CC1FF4428147F11009F7288 /* RoomSharedItemsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CC1FF4228147F10009F7288 /* RoomSharedItemsTableViewController.swift */; }; 2CC1FF4428147F11009F7288 /* RoomSharedItemsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CC1FF4228147F10009F7288 /* RoomSharedItemsTableViewController.swift */; };
2CC1FF4528147F11009F7288 /* RoomSharedItemsTableViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2CC1FF4328147F10009F7288 /* RoomSharedItemsTableViewController.xib */; }; 2CC1FF4528147F11009F7288 /* RoomSharedItemsTableViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2CC1FF4328147F10009F7288 /* RoomSharedItemsTableViewController.xib */; };
2CC1FF4828183958009F7288 /* NCDeckCardParameter.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CC1FF4728183958009F7288 /* NCDeckCardParameter.m */; }; 2CC1FF4828183958009F7288 /* NCDeckCardParameter.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CC1FF4728183958009F7288 /* NCDeckCardParameter.m */; };
@ -751,6 +754,12 @@
2CC007C920E125C20096D91F /* NewRoomTableViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = NewRoomTableViewController.xib; sourceTree = "<group>"; }; 2CC007C920E125C20096D91F /* NewRoomTableViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = NewRoomTableViewController.xib; sourceTree = "<group>"; };
2CC007CC20E50B0A0096D91F /* MessageBodyTextView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MessageBodyTextView.h; sourceTree = "<group>"; }; 2CC007CC20E50B0A0096D91F /* MessageBodyTextView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MessageBodyTextView.h; sourceTree = "<group>"; };
2CC007CD20E50B0A0096D91F /* MessageBodyTextView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MessageBodyTextView.m; sourceTree = "<group>"; }; 2CC007CD20E50B0A0096D91F /* MessageBodyTextView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MessageBodyTextView.m; sourceTree = "<group>"; };
2CC1C38029C0945600C8436B /* DRCellSlideGestureRecognizer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DRCellSlideGestureRecognizer.m; sourceTree = "<group>"; };
2CC1C38129C0945600C8436B /* DRCellSlideAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DRCellSlideAction.h; sourceTree = "<group>"; };
2CC1C38229C0945600C8436B /* DRCellSlideActionView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DRCellSlideActionView.h; sourceTree = "<group>"; };
2CC1C38329C0945600C8436B /* DRCellSlideGestureRecognizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DRCellSlideGestureRecognizer.h; sourceTree = "<group>"; };
2CC1C38429C0945700C8436B /* DRCellSlideAction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DRCellSlideAction.m; sourceTree = "<group>"; };
2CC1C38529C0945700C8436B /* DRCellSlideActionView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DRCellSlideActionView.m; sourceTree = "<group>"; };
2CC1FF4228147F10009F7288 /* RoomSharedItemsTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomSharedItemsTableViewController.swift; sourceTree = "<group>"; }; 2CC1FF4228147F10009F7288 /* RoomSharedItemsTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomSharedItemsTableViewController.swift; sourceTree = "<group>"; };
2CC1FF4328147F10009F7288 /* RoomSharedItemsTableViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = RoomSharedItemsTableViewController.xib; sourceTree = "<group>"; }; 2CC1FF4328147F10009F7288 /* RoomSharedItemsTableViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = RoomSharedItemsTableViewController.xib; sourceTree = "<group>"; };
2CC1FF4628183958009F7288 /* NCDeckCardParameter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NCDeckCardParameter.h; sourceTree = "<group>"; }; 2CC1FF4628183958009F7288 /* NCDeckCardParameter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NCDeckCardParameter.h; sourceTree = "<group>"; };
@ -957,6 +966,7 @@
2C05749C1EDDA01700D9E7F2 /* ThirdParty */ = { 2C05749C1EDDA01700D9E7F2 /* ThirdParty */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
2CC1C37F29C0945600C8436B /* DRCellSlideGestureRecognizer */,
2C20269D236832D300DFC89B /* FTPopOverMenu */, 2C20269D236832D300DFC89B /* FTPopOverMenu */,
2CB302F92264775E0053078A /* SlackTextViewController */, 2CB302F92264775E0053078A /* SlackTextViewController */,
2C4E758C214B942D003910D5 /* Firefox */, 2C4E758C214B942D003910D5 /* Firefox */,
@ -1437,6 +1447,20 @@
path = NotificationServiceExtension; path = NotificationServiceExtension;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
2CC1C37F29C0945600C8436B /* DRCellSlideGestureRecognizer */ = {
isa = PBXGroup;
children = (
2CC1C38029C0945600C8436B /* DRCellSlideGestureRecognizer.m */,
2CC1C38129C0945600C8436B /* DRCellSlideAction.h */,
2CC1C38229C0945600C8436B /* DRCellSlideActionView.h */,
2CC1C38329C0945600C8436B /* DRCellSlideGestureRecognizer.h */,
2CC1C38429C0945700C8436B /* DRCellSlideAction.m */,
2CC1C38529C0945700C8436B /* DRCellSlideActionView.m */,
);
name = DRCellSlideGestureRecognizer;
path = ThirdParty/DRCellSlideGestureRecognizer/DRCellSlideGestureRecognizer;
sourceTree = "<group>";
};
2CF0679E208A2A430070A79B /* Chat */ = { 2CF0679E208A2A430070A79B /* Chat */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@ -1887,6 +1911,7 @@
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
2C444703265D641300DF1DBC /* NCUserDefaults.m in Sources */, 2C444703265D641300DF1DBC /* NCUserDefaults.m in Sources */,
2CC1C38729C0945700C8436B /* DRCellSlideAction.m in Sources */,
1FEDE3C6257D439500853F79 /* NCChatFileController.m in Sources */, 1FEDE3C6257D439500853F79 /* NCChatFileController.m in Sources */,
1FEDE3CE257D43AB00853F79 /* NCMessageFileParameter.m in Sources */, 1FEDE3CE257D43AB00853F79 /* NCMessageFileParameter.m in Sources */,
2C4446DD2658158000DF1DBC /* NCChatBlock.m in Sources */, 2C4446DD2658158000DF1DBC /* NCChatBlock.m in Sources */,
@ -1996,11 +2021,13 @@
2CA155562099E07700CE8EF0 /* GroupedChatMessageTableViewCell.m in Sources */, 2CA155562099E07700CE8EF0 /* GroupedChatMessageTableViewCell.m in Sources */,
2CA15548208EA1EA00CE8EF0 /* ChatMessageTableViewCell.m in Sources */, 2CA15548208EA1EA00CE8EF0 /* ChatMessageTableViewCell.m in Sources */,
2CC1FF4428147F11009F7288 /* RoomSharedItemsTableViewController.swift in Sources */, 2CC1FF4428147F11009F7288 /* RoomSharedItemsTableViewController.swift in Sources */,
2CC1C38629C0945700C8436B /* DRCellSlideGestureRecognizer.m in Sources */,
1FB52E762842C75E00AC741B /* QRCodeLoginController.swift in Sources */, 1FB52E762842C75E00AC741B /* QRCodeLoginController.swift in Sources */,
2C4446D8265814D100DF1DBC /* ServerCapabilities.m in Sources */, 2C4446D8265814D100DF1DBC /* ServerCapabilities.m in Sources */,
DA66582D27B6A73800B46B11 /* UserProfileTableViewController+DelegateMethods.swift in Sources */, DA66582D27B6A73800B46B11 /* UserProfileTableViewController+DelegateMethods.swift in Sources */,
1F5CDF642584E78900B0026E /* NCChatFileStatus.m in Sources */, 1F5CDF642584E78900B0026E /* NCChatFileStatus.m in Sources */,
2CBF82C11FD5AE3F00636459 /* NCPushProxySessionManager.m in Sources */, 2CBF82C11FD5AE3F00636459 /* NCPushProxySessionManager.m in Sources */,
2CC1C38829C0945700C8436B /* DRCellSlideActionView.m in Sources */,
1FA732FC2966CBB7003D2103 /* CallFlowLayout.swift in Sources */, 1FA732FC2966CBB7003D2103 /* CallFlowLayout.swift in Sources */,
2C78EF951F7E70EB008AFA74 /* NCPeerConnection.m in Sources */, 2C78EF951F7E70EB008AFA74 /* NCPeerConnection.m in Sources */,
2C06BF6C20AEB0030031EB46 /* RoundedNumberView.m in Sources */, 2C06BF6C20AEB0030031EB46 /* RoundedNumberView.m in Sources */,

Просмотреть файл

@ -388,6 +388,14 @@
} }
}]; }];
} }
if (self.message.isReplyable && !self.message.isDeleting) {
__weak typeof(self) weakSelf = self;
[self addReplyGestureWithActionBlock:^(UITableView *tableView, NSIndexPath *indexPath) {
__strong typeof(self) strongSelf = weakSelf;
[strongSelf.delegate cellWantsToReplyToMessage:strongSelf.message];
}];
}
} }
- (void)setGuestAvatar:(NSString *)displayName - (void)setGuestAvatar:(NSString *)displayName

Просмотреть файл

@ -24,6 +24,7 @@
#import "NextcloudTalk-Swift.h" #import "NextcloudTalk-Swift.h"
#import "DRCellSlideGestureRecognizer.h"
#import "NCChatMessage.h" #import "NCChatMessage.h"
static CGFloat kChatCellStatusViewHeight = 20.0; static CGFloat kChatCellStatusViewHeight = 20.0;
@ -41,6 +42,7 @@ typedef enum ChatMessageDeliveryState {
@protocol ChatTableViewCellDelegate <NSObject> @protocol ChatTableViewCellDelegate <NSObject>
- (void)cellDidSelectedReaction:(NCChatReaction *)reaction forMessage:(NCChatMessage *)message; - (void)cellDidSelectedReaction:(NCChatReaction *)reaction forMessage:(NCChatMessage *)message;
- (void)cellWantsToReplyToMessage:(NCChatMessage *)message;
@end @end
@ -50,5 +52,6 @@ typedef enum ChatMessageDeliveryState {
@property (nonatomic, strong) NCChatMessage *message; @property (nonatomic, strong) NCChatMessage *message;
- (UIMenu *)getDeferredUserMenuForMessage:(NCChatMessage *)message; - (UIMenu *)getDeferredUserMenuForMessage:(NCChatMessage *)message;
- (void)addReplyGestureWithActionBlock:(DRCellSlideActionBlock)block;
@end @end

Просмотреть файл

@ -25,6 +25,7 @@
typedef void (^GetMenuUserActionsForMessageCompletionBlock)(NSArray *menuItems); typedef void (^GetMenuUserActionsForMessageCompletionBlock)(NSArray *menuItems);
@interface ChatTableViewCell () <UITextFieldDelegate> @interface ChatTableViewCell () <UITextFieldDelegate>
@property (nonatomic, strong) DRCellSlideGestureRecognizer *replyGestureRecognizer;
@end @end
@implementation ChatTableViewCell @implementation ChatTableViewCell
@ -43,6 +44,34 @@ typedef void (^GetMenuUserActionsForMessageCompletionBlock)(NSArray *menuItems);
[super prepareForReuse]; [super prepareForReuse];
self.messageId = -1; self.messageId = -1;
self.message = nil; self.message = nil;
[self removeGestureRecognizer:self.replyGestureRecognizer];
}
- (void)addReplyGestureWithActionBlock:(DRCellSlideActionBlock)block
{
self.replyGestureRecognizer = [DRCellSlideGestureRecognizer new];
self.replyGestureRecognizer.leftActionStartPosition = 80;
DRCellSlideAction *action = [DRCellSlideAction actionForFraction:0.2];
action.behavior = DRCellSlideActionPullBehavior;
action.activeColor = [UIColor labelColor];
action.inactiveColor = [UIColor placeholderTextColor];
action.activeBackgroundColor = self.backgroundColor;
action.inactiveBackgroundColor = self.backgroundColor;
action.icon = [UIImage imageNamed:@"reply"];
[action setWillTriggerBlock:^(UITableView *tableView, NSIndexPath *indexPath) {
block(tableView, indexPath);
}];
[action setDidChangeStateBlock:^(DRCellSlideAction *action, BOOL active) {
if (active) {
// Actuate `Peek` feedback (weak boom)
AudioServicesPlaySystemSound(1519);
}
}];
[self.replyGestureRecognizer addActions:action];
[self addGestureRecognizer:self.replyGestureRecognizer];
} }
- (UIMenu *)getDeferredUserMenuForMessage:(NCChatMessage *)message - (UIMenu *)getDeferredUserMenuForMessage:(NCChatMessage *)message

Просмотреть файл

@ -256,6 +256,14 @@
[self setDeliveryState:ChatMessageDeliveryStateSent]; [self setDeliveryState:ChatMessageDeliveryStateSent];
} }
} }
if (self.message.isReplyable && !self.message.isDeleting) {
__weak typeof(self) weakSelf = self;
[self addReplyGestureWithActionBlock:^(UITableView *tableView, NSIndexPath *indexPath) {
__strong typeof(self) strongSelf = weakSelf;
[strongSelf.delegate cellWantsToReplyToMessage:strongSelf.message];
}];
}
} }
- (void)requestPreviewForMessage:(NCChatMessage *)message withAccount:(TalkAccount *)account - (void)requestPreviewForMessage:(NCChatMessage *)message withAccount:(TalkAccount *)account

Просмотреть файл

@ -146,6 +146,14 @@
} }
}]; }];
} }
if (self.message.isReplyable && !self.message.isDeleting) {
__weak typeof(self) weakSelf = self;
[self addReplyGestureWithActionBlock:^(UITableView *tableView, NSIndexPath *indexPath) {
__strong typeof(self) strongSelf = weakSelf;
[strongSelf.delegate cellWantsToReplyToMessage:strongSelf.message];
}];
}
} }
- (void)setDeliveryState:(ChatMessageDeliveryState)state - (void)setDeliveryState:(ChatMessageDeliveryState)state

Просмотреть файл

@ -207,6 +207,14 @@
[self setDeliveryState:ChatMessageDeliveryStateSent]; [self setDeliveryState:ChatMessageDeliveryStateSent];
} }
} }
if (self.message.isReplyable && !self.message.isDeleting) {
__weak typeof(self) weakSelf = self;
[self addReplyGestureWithActionBlock:^(UITableView *tableView, NSIndexPath *indexPath) {
__strong typeof(self) strongSelf = weakSelf;
[strongSelf.delegate cellWantsToReplyToMessage:strongSelf.message];
}];
}
} }
- (void)createLocationPreview - (void)createLocationPreview

Просмотреть файл

@ -3863,24 +3863,6 @@ NSString * const NCChatViewControllerTalkToUserNotification = @"NCChatViewContro
return previewController; return previewController;
} }
//Swipe to reply option
- (UISwipeActionsConfiguration *)tableView:(UITableView *)tableView leadingSwipeActionsConfigurationForRowAtIndexPath:(nonnull NSIndexPath *)indexPath
{
NSDate *sectionDate = [_dateSections objectAtIndex:indexPath.section];
NCChatMessage *message = [[_messages objectForKey:sectionDate] objectAtIndex:indexPath.row];
if (message.isReplyable && !message.isDeleting) {
UIContextualAction *replyAction = [UIContextualAction contextualActionWithStyle:UIContextualActionStyleNormal title:nil handler:^(UIContextualAction * _Nonnull action, __kindof UIView * _Nonnull sourceView, void (^ _Nonnull completionHandler)(BOOL)) {
[self didPressReply:message];
completionHandler(true);
}];
replyAction.image = [UIImage imageNamed:@"reply-settings"];
replyAction.backgroundColor = self.tableView.backgroundColor;
return [UISwipeActionsConfiguration configurationWithActions:@[replyAction]];
} else {
return nil;
}
}
#pragma mark - FileMessageTableViewCellDelegate #pragma mark - FileMessageTableViewCellDelegate
- (void)cellWantsToDownloadFile:(NCMessageFileParameter *)fileParameter - (void)cellWantsToDownloadFile:(NCMessageFileParameter *)fileParameter
@ -4012,6 +3994,11 @@ NSString * const NCChatViewControllerTalkToUserNotification = @"NCChatViewContro
[self addOrRemoveReaction:reaction inChatMessage:message]; [self addOrRemoveReaction:reaction inChatMessage:message];
} }
- (void)cellWantsToReplyToMessage:(NCChatMessage *)message
{
[self didPressReply:message];
}
#pragma mark - NCChatFileControllerDelegate #pragma mark - NCChatFileControllerDelegate
- (void)fileControllerDidLoadFile:(NCChatFileController *)fileController withFileStatus:(NCChatFileStatus *)fileStatus - (void)fileControllerDidLoadFile:(NCChatFileController *)fileController withFileStatus:(NCChatFileStatus *)fileStatus

Просмотреть файл

@ -216,6 +216,14 @@
[self setDeliveryState:ChatMessageDeliveryStateSent]; [self setDeliveryState:ChatMessageDeliveryStateSent];
} }
} }
if (self.message.isReplyable && !self.message.isDeleting) {
__weak typeof(self) weakSelf = self;
[self addReplyGestureWithActionBlock:^(UITableView *tableView, NSIndexPath *indexPath) {
__strong typeof(self) strongSelf = weakSelf;
[strongSelf.delegate cellWantsToReplyToMessage:strongSelf.message];
}];
}
} }
- (void)setDeliveryState:(ChatMessageDeliveryState)state - (void)setDeliveryState:(ChatMessageDeliveryState)state

Просмотреть файл

@ -243,6 +243,14 @@
[self setDeliveryState:ChatMessageDeliveryStateSent]; [self setDeliveryState:ChatMessageDeliveryStateSent];
} }
} }
if (self.message.isReplyable && !self.message.isDeleting) {
__weak typeof(self) weakSelf = self;
[self addReplyGestureWithActionBlock:^(UITableView *tableView, NSIndexPath *indexPath) {
__strong typeof(self) strongSelf = weakSelf;
[strongSelf.delegate cellWantsToReplyToMessage:strongSelf.message];
}];
}
} }
- (void)setDeliveryState:(ChatMessageDeliveryState)state - (void)setDeliveryState:(ChatMessageDeliveryState)state

1
ThirdParty/DRCellSlideGestureRecognizer поставляемый Submodule

@ -0,0 +1 @@
Subproject commit 1939fd516708f3938cc5efccba5f944352a41e5e