mirror of
https://github.com/oxen-io/session-ios.git
synced 2023-12-13 21:30:14 +01:00
Interactive/Cancelable slide left for details
// FREEBIE
This commit is contained in:
parent
ac8d59bb7d
commit
d87f000051
|
@ -147,6 +147,8 @@
|
||||||
4521C3C01F59F3BA00B4C582 /* TextFieldHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4521C3BF1F59F3BA00B4C582 /* TextFieldHelper.swift */; };
|
4521C3C01F59F3BA00B4C582 /* TextFieldHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4521C3BF1F59F3BA00B4C582 /* TextFieldHelper.swift */; };
|
||||||
4521C3C11F59F3BA00B4C582 /* TextFieldHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4521C3BF1F59F3BA00B4C582 /* TextFieldHelper.swift */; };
|
4521C3C11F59F3BA00B4C582 /* TextFieldHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4521C3BF1F59F3BA00B4C582 /* TextFieldHelper.swift */; };
|
||||||
4523149C1F7D7F81003A428C /* OWSMessagesBubbleImageFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4523149B1F7D7F81003A428C /* OWSMessagesBubbleImageFactory.swift */; };
|
4523149C1F7D7F81003A428C /* OWSMessagesBubbleImageFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4523149B1F7D7F81003A428C /* OWSMessagesBubbleImageFactory.swift */; };
|
||||||
|
4523149E1F7E916B003A428C /* SlideOffAnimatedTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4523149D1F7E916B003A428C /* SlideOffAnimatedTransition.swift */; };
|
||||||
|
452314A01F7E9E18003A428C /* DirectionalPanGestureRecognizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4523149F1F7E9E18003A428C /* DirectionalPanGestureRecognizer.swift */; };
|
||||||
452C468F1E427E200087B011 /* OutboundCallInitiator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 452C468E1E427E200087B011 /* OutboundCallInitiator.swift */; };
|
452C468F1E427E200087B011 /* OutboundCallInitiator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 452C468E1E427E200087B011 /* OutboundCallInitiator.swift */; };
|
||||||
452C46901E427E200087B011 /* OutboundCallInitiator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 452C468E1E427E200087B011 /* OutboundCallInitiator.swift */; };
|
452C46901E427E200087B011 /* OutboundCallInitiator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 452C468E1E427E200087B011 /* OutboundCallInitiator.swift */; };
|
||||||
452D1EE81DCA90D100A57EC4 /* MesssagesBubblesSizeCalculatorTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 452D1EE71DCA90D100A57EC4 /* MesssagesBubblesSizeCalculatorTest.swift */; };
|
452D1EE81DCA90D100A57EC4 /* MesssagesBubblesSizeCalculatorTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 452D1EE71DCA90D100A57EC4 /* MesssagesBubblesSizeCalculatorTest.swift */; };
|
||||||
|
@ -615,6 +617,8 @@
|
||||||
4520D8D41D417D8E00123472 /* Photos.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Photos.framework; path = System/Library/Frameworks/Photos.framework; sourceTree = SDKROOT; };
|
4520D8D41D417D8E00123472 /* Photos.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Photos.framework; path = System/Library/Frameworks/Photos.framework; sourceTree = SDKROOT; };
|
||||||
4521C3BF1F59F3BA00B4C582 /* TextFieldHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextFieldHelper.swift; sourceTree = "<group>"; };
|
4521C3BF1F59F3BA00B4C582 /* TextFieldHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextFieldHelper.swift; sourceTree = "<group>"; };
|
||||||
4523149B1F7D7F81003A428C /* OWSMessagesBubbleImageFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OWSMessagesBubbleImageFactory.swift; sourceTree = "<group>"; };
|
4523149B1F7D7F81003A428C /* OWSMessagesBubbleImageFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OWSMessagesBubbleImageFactory.swift; sourceTree = "<group>"; };
|
||||||
|
4523149D1F7E916B003A428C /* SlideOffAnimatedTransition.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SlideOffAnimatedTransition.swift; path = UserInterface/SlideOffAnimatedTransition.swift; sourceTree = "<group>"; };
|
||||||
|
4523149F1F7E9E18003A428C /* DirectionalPanGestureRecognizer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DirectionalPanGestureRecognizer.swift; sourceTree = "<group>"; };
|
||||||
452C468E1E427E200087B011 /* OutboundCallInitiator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OutboundCallInitiator.swift; sourceTree = "<group>"; };
|
452C468E1E427E200087B011 /* OutboundCallInitiator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OutboundCallInitiator.swift; sourceTree = "<group>"; };
|
||||||
452D1EE71DCA90D100A57EC4 /* MesssagesBubblesSizeCalculatorTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MesssagesBubblesSizeCalculatorTest.swift; path = Models/MesssagesBubblesSizeCalculatorTest.swift; sourceTree = "<group>"; };
|
452D1EE71DCA90D100A57EC4 /* MesssagesBubblesSizeCalculatorTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MesssagesBubblesSizeCalculatorTest.swift; path = Models/MesssagesBubblesSizeCalculatorTest.swift; sourceTree = "<group>"; };
|
||||||
452EA09D1EA7ABE00078744B /* AttachmentPointerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AttachmentPointerView.swift; sourceTree = "<group>"; };
|
452EA09D1EA7ABE00078744B /* AttachmentPointerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AttachmentPointerView.swift; sourceTree = "<group>"; };
|
||||||
|
@ -1211,6 +1215,7 @@
|
||||||
34B3F8331E8DF1700035BE1A /* ViewControllers */,
|
34B3F8331E8DF1700035BE1A /* ViewControllers */,
|
||||||
76EB052B18170B33006006FC /* Views */,
|
76EB052B18170B33006006FC /* Views */,
|
||||||
4523149B1F7D7F81003A428C /* OWSMessagesBubbleImageFactory.swift */,
|
4523149B1F7D7F81003A428C /* OWSMessagesBubbleImageFactory.swift */,
|
||||||
|
4523149D1F7E916B003A428C /* SlideOffAnimatedTransition.swift */,
|
||||||
);
|
);
|
||||||
name = UserInterface;
|
name = UserInterface;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -1519,6 +1524,7 @@
|
||||||
45A6DAD51EBBF85500893231 /* ReminderView.swift */,
|
45A6DAD51EBBF85500893231 /* ReminderView.swift */,
|
||||||
450D19111F85236600970622 /* RemoteVideoView.h */,
|
450D19111F85236600970622 /* RemoteVideoView.h */,
|
||||||
450D19121F85236600970622 /* RemoteVideoView.m */,
|
450D19121F85236600970622 /* RemoteVideoView.m */,
|
||||||
|
4523149F1F7E9E18003A428C /* DirectionalPanGestureRecognizer.swift */,
|
||||||
);
|
);
|
||||||
name = Views;
|
name = Views;
|
||||||
path = views;
|
path = views;
|
||||||
|
@ -2283,6 +2289,7 @@
|
||||||
76EB068618170B34006006FC /* ContactTableViewCell.m in Sources */,
|
76EB068618170B34006006FC /* ContactTableViewCell.m in Sources */,
|
||||||
3497DBEF1ECE2E4700DB2605 /* DomainFrontingCountryViewController.m in Sources */,
|
3497DBEF1ECE2E4700DB2605 /* DomainFrontingCountryViewController.m in Sources */,
|
||||||
34B3F8881E8DF1700035BE1A /* OversizeTextMessageViewController.swift in Sources */,
|
34B3F8881E8DF1700035BE1A /* OversizeTextMessageViewController.swift in Sources */,
|
||||||
|
452314A01F7E9E18003A428C /* DirectionalPanGestureRecognizer.swift in Sources */,
|
||||||
34330AA31E79686200DF2FB9 /* OWSProgressView.m in Sources */,
|
34330AA31E79686200DF2FB9 /* OWSProgressView.m in Sources */,
|
||||||
34B3F8A21E8EA6040035BE1A /* ViewControllerUtils.m in Sources */,
|
34B3F8A21E8EA6040035BE1A /* ViewControllerUtils.m in Sources */,
|
||||||
34CA1C271F7156F300E51C51 /* MessageMetadataViewController.swift in Sources */,
|
34CA1C271F7156F300E51C51 /* MessageMetadataViewController.swift in Sources */,
|
||||||
|
@ -2317,6 +2324,7 @@
|
||||||
34B3F8911E8DF1710035BE1A /* ShowGroupMembersViewController.m in Sources */,
|
34B3F8911E8DF1710035BE1A /* ShowGroupMembersViewController.m in Sources */,
|
||||||
4539B5861F79348F007141FF /* PushRegistrationManager.swift in Sources */,
|
4539B5861F79348F007141FF /* PushRegistrationManager.swift in Sources */,
|
||||||
45FBC5D11DF8592E00E9B410 /* SignalCall.swift in Sources */,
|
45FBC5D11DF8592E00E9B410 /* SignalCall.swift in Sources */,
|
||||||
|
4523149E1F7E916B003A428C /* SlideOffAnimatedTransition.swift in Sources */,
|
||||||
452C468F1E427E200087B011 /* OutboundCallInitiator.swift in Sources */,
|
452C468F1E427E200087B011 /* OutboundCallInitiator.swift in Sources */,
|
||||||
45F170BB1E2FC5D3003FC1F2 /* CallAudioService.swift in Sources */,
|
45F170BB1E2FC5D3003FC1F2 /* CallAudioService.swift in Sources */,
|
||||||
34B3F8711E8DF1700035BE1A /* AboutTableViewController.m in Sources */,
|
34B3F8711E8DF1700035BE1A /* AboutTableViewController.m in Sources */,
|
||||||
|
|
51
Signal/src/UserInterface/SlideOffAnimatedTransition.swift
Normal file
51
Signal/src/UserInterface/SlideOffAnimatedTransition.swift
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
@objc
|
||||||
|
class SlideOffAnimatedTransition: NSObject, UIViewControllerAnimatedTransitioning {
|
||||||
|
|
||||||
|
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
|
||||||
|
|
||||||
|
let containerView = transitionContext.containerView
|
||||||
|
guard let fromView = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from)?.view else {
|
||||||
|
owsFail("No fromView")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
guard let toView = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)?.view else {
|
||||||
|
owsFail("No toView")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let width = containerView.frame.width
|
||||||
|
let offsetLeft = fromView.frame.offsetBy(dx: -width, dy: 0)
|
||||||
|
toView.frame = fromView.frame
|
||||||
|
|
||||||
|
fromView.layer.shadowRadius = 15.0
|
||||||
|
fromView.layer.shadowOpacity = 1.0
|
||||||
|
toView.layer.opacity = 0.9
|
||||||
|
|
||||||
|
containerView.insertSubview(toView, belowSubview: fromView)
|
||||||
|
UIView.animate(withDuration: transitionDuration(using: transitionContext), delay:0, options: .curveLinear, animations: {
|
||||||
|
fromView.frame = offsetLeft
|
||||||
|
|
||||||
|
toView.layer.opacity = 1.0
|
||||||
|
fromView.layer.shadowOpacity = 0.1
|
||||||
|
}, completion: { _ in
|
||||||
|
toView.layer.opacity = 1.0
|
||||||
|
toView.layer.shadowOpacity = 0
|
||||||
|
|
||||||
|
fromView.layer.opacity = 1.0
|
||||||
|
fromView.layer.shadowOpacity = 0
|
||||||
|
|
||||||
|
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
|
||||||
|
return 0.3
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -24,6 +24,8 @@ NS_ASSUME_NONNULL_BEGIN
|
||||||
- (void)didTapFailedIncomingAttachment:(ConversationViewItem *)viewItem
|
- (void)didTapFailedIncomingAttachment:(ConversationViewItem *)viewItem
|
||||||
attachmentPointer:(TSAttachmentPointer *)attachmentPointer;
|
attachmentPointer:(TSAttachmentPointer *)attachmentPointer;
|
||||||
- (void)didTapFailedOutgoingMessage:(TSOutgoingMessage *)message;
|
- (void)didTapFailedOutgoingMessage:(TSOutgoingMessage *)message;
|
||||||
|
- (void)didPanWithGestureRecognizer:(UIPanGestureRecognizer *)gestureRecognizer
|
||||||
|
viewItem:(ConversationViewItem *)conversationItem;
|
||||||
|
|
||||||
- (void)showMetadataViewForMessage:(TSMessage *)message;
|
- (void)showMetadataViewForMessage:(TSMessage *)message;
|
||||||
|
|
||||||
|
|
|
@ -162,6 +162,12 @@ NS_ASSUME_NONNULL_BEGIN
|
||||||
UILongPressGestureRecognizer *longPress =
|
UILongPressGestureRecognizer *longPress =
|
||||||
[[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPressGesture:)];
|
[[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPressGesture:)];
|
||||||
[self addGestureRecognizer:longPress];
|
[self addGestureRecognizer:longPress];
|
||||||
|
|
||||||
|
PanDirectionGestureRecognizer *panGesture =
|
||||||
|
[[PanDirectionGestureRecognizer alloc] initWithDirection:PanDirectionHorizontal
|
||||||
|
target:self
|
||||||
|
action:@selector(handlePanGesture:)];
|
||||||
|
[self addGestureRecognizer:panGesture];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (NSString *)cellReuseIdentifier
|
+ (NSString *)cellReuseIdentifier
|
||||||
|
@ -1029,6 +1035,13 @@ NS_ASSUME_NONNULL_BEGIN
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)handlePanGesture:(UIPanGestureRecognizer *)panRecognizer
|
||||||
|
{
|
||||||
|
OWSAssert(self.delegate);
|
||||||
|
|
||||||
|
[self.delegate didPanWithGestureRecognizer:panRecognizer viewItem:self.viewItem];
|
||||||
|
}
|
||||||
|
|
||||||
#pragma mark - UIMenuController
|
#pragma mark - UIMenuController
|
||||||
|
|
||||||
- (void)showMenuController:(CGPoint)fromLocation
|
- (void)showMenuController:(CGPoint)fromLocation
|
||||||
|
|
|
@ -136,6 +136,10 @@ typedef NS_ENUM(NSInteger, MessagesRangeSizeMode) {
|
||||||
ConversationInputToolbarDelegate,
|
ConversationInputToolbarDelegate,
|
||||||
GifPickerViewControllerDelegate>
|
GifPickerViewControllerDelegate>
|
||||||
|
|
||||||
|
// Show message info animation
|
||||||
|
@property (nullable, nonatomic) UIPercentDrivenInteractiveTransition *showMessageDetailsTransition;
|
||||||
|
@property (nullable, nonatomic) UIPanGestureRecognizer *currentShowMessageDetailsPanGesture;
|
||||||
|
|
||||||
@property (nonatomic) TSThread *thread;
|
@property (nonatomic) TSThread *thread;
|
||||||
@property (nonatomic) YapDatabaseConnection *editingDatabaseConnection;
|
@property (nonatomic) YapDatabaseConnection *editingDatabaseConnection;
|
||||||
|
|
||||||
|
@ -988,9 +992,14 @@ typedef NS_ENUM(NSInteger, MessagesRangeSizeMode) {
|
||||||
|
|
||||||
[super viewWillDisappear:animated];
|
[super viewWillDisappear:animated];
|
||||||
|
|
||||||
self.isViewVisible = NO;
|
|
||||||
|
|
||||||
[self.inputToolbar viewWillDisappear:animated];
|
[self.inputToolbar viewWillDisappear:animated];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)viewDidDisappear:(BOOL)animated
|
||||||
|
{
|
||||||
|
[super viewDidDisappear:animated];
|
||||||
|
self.userHasScrolled = NO;
|
||||||
|
self.isViewVisible = NO;
|
||||||
|
|
||||||
[self.audioAttachmentPlayer stop];
|
[self.audioAttachmentPlayer stop];
|
||||||
self.audioAttachmentPlayer = nil;
|
self.audioAttachmentPlayer = nil;
|
||||||
|
@ -1005,12 +1014,6 @@ typedef NS_ENUM(NSInteger, MessagesRangeSizeMode) {
|
||||||
self.isUserScrolling = NO;
|
self.isUserScrolling = NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)viewDidDisappear:(BOOL)animated
|
|
||||||
{
|
|
||||||
[super viewDidDisappear:animated];
|
|
||||||
self.userHasScrolled = NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - Initiliazers
|
#pragma mark - Initiliazers
|
||||||
|
|
||||||
- (void)setNavigationTitle
|
- (void)setNavigationTitle
|
||||||
|
@ -4036,6 +4039,110 @@ typedef NS_ENUM(NSInteger, MessagesRangeSizeMode) {
|
||||||
return cell;
|
return cell;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma mark - swipe to show message details
|
||||||
|
|
||||||
|
- (void)didPanWithGestureRecognizer:(UIPanGestureRecognizer *)gestureRecognizer
|
||||||
|
viewItem:(ConversationViewItem *)conversationItem
|
||||||
|
{
|
||||||
|
self.currentShowMessageDetailsPanGesture = gestureRecognizer;
|
||||||
|
|
||||||
|
const CGFloat leftTranslation = -1 * [gestureRecognizer translationInView:self.view].x;
|
||||||
|
const CGFloat percent = MAX(leftTranslation, 0) / self.view.frame.size.width;
|
||||||
|
|
||||||
|
switch (gestureRecognizer.state) {
|
||||||
|
case UIGestureRecognizerStateBegan: {
|
||||||
|
TSInteraction *interaction = conversationItem.interaction;
|
||||||
|
if ([interaction isKindOfClass:[TSIncomingMessage class]] ||
|
||||||
|
[interaction isKindOfClass:[TSOutgoingMessage class]]) {
|
||||||
|
|
||||||
|
// Canary check in case we later have another reason to set navigationController.delegate - we don't
|
||||||
|
// want to inadvertently clobber it here.
|
||||||
|
OWSAssert(self.navigationController.delegate == nil) self.navigationController.delegate = self;
|
||||||
|
TSMessage *message = (TSMessage *)interaction;
|
||||||
|
MessageMetadataViewController *view = [[MessageMetadataViewController alloc] initWithMessage:message];
|
||||||
|
[self.navigationController pushViewController:view animated:YES];
|
||||||
|
} else {
|
||||||
|
OWSFail(@"%@ Can't show message metadata for message of type: %@", self.tag, [interaction class]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case UIGestureRecognizerStateChanged: {
|
||||||
|
UIPercentDrivenInteractiveTransition *transition = self.showMessageDetailsTransition;
|
||||||
|
if (!transition) {
|
||||||
|
DDLogVerbose(@"%@ transition not set up yet", self.tag);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
[transition updateInteractiveTransition:percent];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case UIGestureRecognizerStateEnded: {
|
||||||
|
const CGFloat velocity = [gestureRecognizer velocityInView:self.view].x;
|
||||||
|
|
||||||
|
UIPercentDrivenInteractiveTransition *transition = self.showMessageDetailsTransition;
|
||||||
|
if (!transition) {
|
||||||
|
DDLogVerbose(@"%@ transition not set up yet", self.tag);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Complete the transition if moved sufficiently far or fast
|
||||||
|
// Note this is trickier for incoming, since you are already on the left, and have less space.
|
||||||
|
if (percent > 0.3 || velocity < -800) {
|
||||||
|
[transition finishInteractiveTransition];
|
||||||
|
} else {
|
||||||
|
[transition cancelInteractiveTransition];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case UIGestureRecognizerStateCancelled:
|
||||||
|
case UIGestureRecognizerStateFailed: {
|
||||||
|
UIPercentDrivenInteractiveTransition *transition = self.showMessageDetailsTransition;
|
||||||
|
if (!transition) {
|
||||||
|
DDLogVerbose(@"%@ transition not set up yet", self.tag);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
[transition cancelInteractiveTransition];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (nullable id<UIViewControllerAnimatedTransitioning>)navigationController:
|
||||||
|
(UINavigationController *)navigationController
|
||||||
|
animationControllerForOperation:(UINavigationControllerOperation)operation
|
||||||
|
fromViewController:(UIViewController *)fromVC
|
||||||
|
toViewController:(UIViewController *)toVC
|
||||||
|
{
|
||||||
|
return [SlideOffAnimatedTransition new];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (nullable id<UIViewControllerInteractiveTransitioning>)
|
||||||
|
navigationController:(UINavigationController *)navigationController
|
||||||
|
interactionControllerForAnimationController:(id<UIViewControllerAnimatedTransitioning>)animationController
|
||||||
|
{
|
||||||
|
// We needed to be the navigation controller delegate to specify the interactive "slide left for message details"
|
||||||
|
// animation But we may not want to be the navigation controller delegate permanently.
|
||||||
|
self.navigationController.delegate = nil;
|
||||||
|
|
||||||
|
DDLogInfo(@"%@ >>>> in %s", self.tag, __PRETTY_FUNCTION__);
|
||||||
|
UIPanGestureRecognizer *recognizer = self.currentShowMessageDetailsPanGesture;
|
||||||
|
if (recognizer == nil) {
|
||||||
|
OWSFail(@"currentShowMessageDetailsPanGesture was unexpectedly nil");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (recognizer.state == UIGestureRecognizerStateBegan) {
|
||||||
|
self.showMessageDetailsTransition = [UIPercentDrivenInteractiveTransition new];
|
||||||
|
self.showMessageDetailsTransition.completionCurve = UIViewAnimationCurveEaseOut;
|
||||||
|
} else {
|
||||||
|
self.showMessageDetailsTransition = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
return self.showMessageDetailsTransition;
|
||||||
|
}
|
||||||
|
|
||||||
#pragma mark - UICollectionViewDelegate
|
#pragma mark - UICollectionViewDelegate
|
||||||
|
|
||||||
- (void)collectionView:(UICollectionView *)collectionView
|
- (void)collectionView:(UICollectionView *)collectionView
|
||||||
|
|
38
Signal/src/views/DirectionalPanGestureRecognizer.swift
Normal file
38
Signal/src/views/DirectionalPanGestureRecognizer.swift
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit.UIGestureRecognizerSubclass
|
||||||
|
|
||||||
|
@objc
|
||||||
|
enum PanDirection: Int {
|
||||||
|
case vertical
|
||||||
|
case horizontal
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc
|
||||||
|
class PanDirectionGestureRecognizer: UIPanGestureRecognizer {
|
||||||
|
|
||||||
|
let direction: PanDirection
|
||||||
|
|
||||||
|
init(direction: PanDirection, target: AnyObject, action: Selector) {
|
||||||
|
self.direction = direction
|
||||||
|
super.init(target: target, action: action)
|
||||||
|
}
|
||||||
|
|
||||||
|
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent) {
|
||||||
|
super.touchesMoved(touches, with: event)
|
||||||
|
|
||||||
|
if state == .began {
|
||||||
|
let vel = velocity(in: view)
|
||||||
|
switch direction {
|
||||||
|
case .horizontal where fabs(vel.y) > fabs(vel.x):
|
||||||
|
state = .cancelled
|
||||||
|
case .vertical where fabs(vel.x) > fabs(vel.y):
|
||||||
|
state = .cancelled
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue