Full Code of joseria/JASwipeCell for AI

master 438e60bc14a4 cached
32 files
180.8 KB
44.7k tokens
1 symbols
1 requests
Download .txt
Repository: joseria/JASwipeCell
Branch: master
Commit: 438e60bc14a4
Files: 32
Total size: 180.8 KB

Directory structure:
gitextract_ndxeqazj/

├── .gitignore
├── .travis.yml
├── JASwipeCell/
│   ├── JAActionButton.h
│   ├── JAActionButton.m
│   ├── JASwipeCell.h
│   └── JASwipeCell.m
├── JASwipeCell.podspec
├── JASwipeCellExample/
│   ├── ALView+PureLayout.h
│   ├── ALView+PureLayout.m
│   ├── AppDelegate.h
│   ├── AppDelegate.m
│   ├── Base.lproj/
│   │   └── Main.storyboard
│   ├── Images.xcassets/
│   │   ├── AppIcon.appiconset/
│   │   │   └── Contents.json
│   │   └── LaunchImage.launchimage/
│   │       └── Contents.json
│   ├── Info.plist
│   ├── JATableViewCell.h
│   ├── JATableViewCell.m
│   ├── JATableViewController.h
│   ├── JATableViewController.m
│   ├── NSArray+PureLayout.h
│   ├── NSArray+PureLayout.m
│   ├── NSLayoutConstraint+PureLayout.h
│   ├── NSLayoutConstraint+PureLayout.m
│   ├── PureLayout+Internal.h
│   ├── PureLayout.h
│   ├── PureLayoutDefines.h
│   └── main.m
├── JASwipeCellExample.xcodeproj/
│   ├── project.pbxproj
│   ├── project.xcworkspace/
│   │   └── contents.xcworkspacedata
│   └── xcshareddata/
│       └── xcschemes/
│           └── JASwipeCellExample.xcscheme
├── LICENSE
└── README.md

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
# Xcode
#
.DS_Store
build/
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata
*.xccheckout
*.moved-aside
DerivedData
*.hmap
*.ipa
*.xcuserstate

# CocoaPods
#
# We recommend against adding the Pods directory to your .gitignore. However
# you should judge for yourself, the pros and cons are mentioned at:
# http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control
#
# Pods/


================================================
FILE: .travis.yml
================================================
language: objective-c
script:
  - xctool -project JASwipeCellExample.xcodeproj -scheme JASwipeCellExample -sdk iphonesimulator clean build


================================================
FILE: JASwipeCell/JAActionButton.h
================================================
//
//  JAActionButton.h
//  JASwipeCell
//
//  Created by Jose Alvarez on 10/8/14.
//  Copyright (c) 2014 Jose Alvarez. All rights reserved.
//
//  Permission is hereby granted, free of charge, to any person obtaining a copy
//  of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//  copies of the Software, and to permit persons to whom the Software is
//  furnished to do so, subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be included in all
//  copies or substantial portions of the Software.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//  SOFTWARE.

#import <UIKit/UIKit.h>

@class JASwipeCell;

// A block that will be executed when the user taps on any of the buttons.
typedef void (^JAActionButtonHandler)(UIButton *actionButton, JASwipeCell *cell);

@interface JAActionButton : UIButton

// Block handler that belongs to this button.
@property (nonatomic, copy, readonly) JAActionButtonHandler handler;

- (instancetype)initActionButtonWithTitle:(NSString *)title color:(UIColor *)color handler:(JAActionButtonHandler)handler;

+ (instancetype)actionButtonWithTitle:(NSString *)title color:(UIColor *)color handler:(JAActionButtonHandler)handler;

@end


================================================
FILE: JASwipeCell/JAActionButton.m
================================================
//
//  JAActionButton.m
//  JASwipeCell
//
//  Created by Jose Alvarez on 10/8/14.
//  Copyright (c) 2014 Jose Alvarez. All rights reserved.
//
//  Permission is hereby granted, free of charge, to any person obtaining a copy
//  of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//  copies of the Software, and to permit persons to whom the Software is
//  furnished to do so, subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be included in all
//  copies or substantial portions of the Software.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//  SOFTWARE.

#import "JAActionButton.h"

@interface JAActionButton ()
@property (nonatomic, strong) NSString *title;
@property (nonatomic, strong) UIColor *color;
@property (nonatomic, copy, readwrite) JAActionButtonHandler handler;
@end

@implementation JAActionButton

- (instancetype)initActionButtonWithTitle:(NSString *)title color:(UIColor *)color handler:(JAActionButtonHandler)handler
{
    self = [super init];
    if (self) {
        _title = title;
        _color = color;
        _handler = handler;
        
        [self setTitle:title forState:UIControlStateNormal];
        self.titleLabel.font = [UIFont fontWithName:@"HelveticaNeue" size:14.0f];
        [self.titleLabel setTextAlignment:NSTextAlignmentCenter];
        [self.titleLabel setNumberOfLines:2];
        self.backgroundColor = color;
    }
    return self;
}

+ (instancetype)actionButtonWithTitle:(NSString *)title color:(UIColor *)color handler:(JAActionButtonHandler)handler
{
    JAActionButton *button = [[JAActionButton alloc] initActionButtonWithTitle:title color:color handler:handler];
    return button;
}

@end

================================================
FILE: JASwipeCell/JASwipeCell.h
================================================
//
//  JASwipeCell.h
//  JASwipeCell
//
//  Created by Jose Alvarez on 10/8/14.
//  Copyright (c) 2014 Jose Alvarez. All rights reserved.
//
//  Permission is hereby granted, free of charge, to any person obtaining a copy
//  of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//  copies of the Software, and to permit persons to whom the Software is
//  furnished to do so, subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be included in all
//  copies or substantial portions of the Software.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//  SOFTWARE.

#import <UIKit/UIKit.h>

// Default button width for buttons.
static CGFloat const kJAButtonWidth = 60;

typedef NS_OPTIONS(NSUInteger, JAButtonLocation) {
    // Buttons are located on the left side.
    JAButtonLocationLeft,
    // Buttons are located on the right side.
    JAButtonLocationRight
};

@class JASwipeCell;

@protocol JASwipeCellDelegate <NSObject>
// Called when the left most button has swiped all the way to the right.
- (void)leftMostButtonSwipeCompleted:(JASwipeCell *)cell;
// Called when the right most button has swiped all the way to the left.
- (void)rightMostButtonSwipeCompleted:(JASwipeCell *)cell;
@optional
// Called when the user begins swiping right on the cell.
- (void)swipingRightForCell:(JASwipeCell *)cell;
// Called when the user begins swiping left on the cell.
- (void)swipingLeftForCell:(JASwipeCell *)cell;
@end

/**
 This cell class provides a mechanism for rendering JAActionButtons behind a top container
 view. These buttons can be added to the left and/or right side of the cell. This is a similar
 implementation to IOS 8's mail application. As you swipe the cell, the buttons underneath are 
 revealed up to their max width. If the user swipes past a threshold, the left/right most button will
 pin to the container view and that button's action will fire once the swipe completes.
 */
@interface JASwipeCell : UITableViewCell
// Top view that will contain all subviews displayed on the cell.
@property (nonatomic, strong) UIView *topContentView;
// Delegate that will respond to cell swipes and button actions.
@property (nonatomic, weak) id <JASwipeCellDelegate> delegate;

/**
 Adds action buttons to the cell at the specified location with default widths.
 
 @param actionButtons The action buttons that will be located underneath the top view.
 @param buttonPosition Where the buttons will be located (JAButtonLocationLeft or JAButtonLocationRight).
 */
- (void)addActionButtons:(NSArray *)actionButtons withButtonPosition:(JAButtonLocation)buttonPosition;

/**
 Adds action buttons to the cell at the specified location.
 
 @param actionButtons The action buttons that will be located underneath the top view.
 @param width Width of the buttons.
 @param buttonLocation Where the buttons will be located (JAButtonLocationLeft or JAButtonLocationRight).
 */
- (void)addActionButtons:(NSArray *)actionButtons withButtonWidth:(CGFloat)width withButtonPosition:(JAButtonLocation)buttonPosition;

/**
 Resets the top container view and buttons back to their original state.
 */
- (void)resetContainerView;

/**
 Completes the pin to the top view.
 */
- (void)completePinToTopViewAnimation;

@end


================================================
FILE: JASwipeCell/JASwipeCell.m
================================================
//
//  JASwipeCell.m
//  JASwipeCell
//
//  Created by Jose Alvarez on 10/8/14.
//  Copyright (c) 2014 Jose Alvarez. All rights reserved.
//
//  Permission is hereby granted, free of charge, to any person obtaining a copy
//  of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//  copies of the Software, and to permit persons to whom the Software is
//  furnished to do so, subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be included in all
//  copies or substantial portions of the Software.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//  SOFTWARE.

#import "JASwipeCell.h"
#import "JAActionButton.h"

#define kButtonTitlePadding     5.0

// Determines the direction that the user is swiping
typedef NS_ENUM(NSUInteger, JASwipeDirection) {
    JASwipeDirectionLeft,
    JASwipeDirectionRight
};

@interface JASwipeCell () <UIGestureRecognizerDelegate>

// Holds the width of a left button
@property (nonatomic) CGFloat leftButtonWidth;
// Holds the width of a right button
@property (nonatomic) CGFloat rightButtonWidth;
// Holds the left action buttons
@property (nonatomic, strong) NSArray *leftButtons;
// Holds the right action buttons
@property (nonatomic, strong) NSArray *rightButtons;
// Holds the starting x position for the left buttons
@property (nonatomic, strong) NSMutableArray *leftButtonsStartingX;
// Holds the starting x position for the right buttons
@property (nonatomic, strong) NSMutableArray *rightButtonsStartingX;
// Determines if the layout has already been applied on this cell
@property (nonatomic) BOOL isLayoutApplied;
// The starting point for the swipe
@property (nonatomic) CGPoint startingPoint;
// Currently swiping to the left
@property (nonatomic) BOOL swipingLeft;
// Currently swiping to the right
@property (nonatomic) BOOL swipingRight;
// Determines of the left most button is currently pinned to the top view.
@property (nonatomic) BOOL leftMostButtonPinned;
// Determines of the right most button is currently pinned to the top view.
@property (nonatomic) BOOL rightMostButtonPinned;
// Determines if the left buttons are revealed.
@property (nonatomic) BOOL leftButtonsRevealed;
// Determines if the right buttons are revealed.
@property (nonatomic) BOOL rightButtonsRevealed;

// Holds the pan gesture recognizer applied to the cell
@property (nonatomic, strong) UIPanGestureRecognizer *panGestureRecognizer;

@end

@implementation JASwipeCell

- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        [self initialize];
    }
    return self;
}

- (void)initialize
{
    [self addSubview:self.topContentView];
    _panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panHandler:)];
    _panGestureRecognizer.delegate = self;
    [self.topContentView addGestureRecognizer:_panGestureRecognizer];
}

- (UIView *)topContentView
{
    if (!_topContentView) {
        _topContentView = [[UIView alloc] init];
        _topContentView.backgroundColor = [UIColor whiteColor];
    }
    return _topContentView;
}

- (void)setLeftButtons:(NSArray *)leftButtons
{
    // Remove any existing left button from the superView before adding new ones
    if (_leftButtons) {
        for (UIButton *button in _leftButtons) {
            [button removeFromSuperview];
        }
        self.isLayoutApplied = NO;
    }
    _leftButtons = leftButtons;
    
    // The first button should be the top button on the z-axis
    for (UIButton *button in _leftButtons.reverseObjectEnumerator) {
        NSAssert([button isMemberOfClass:[JAActionButton class]], @"This cell expects JAActionButton class buttons");
        [button addTarget:self action:@selector(buttonTapped:) forControlEvents:UIControlEventTouchUpInside];
	// Make sure the buttons will not be visible before their frames are set...
	button.frame = CGRectMake( 5000, 0, button.frame.size.width, button.frame.size.height );
        [self.contentView addSubview:button];
    }
}

- (void)setRightButtons:(NSArray *)rightButtons
{
    // Remove any existing right button from the superView before adding new ones
    if (_rightButtons) {
        for (UIButton *button in _rightButtons) {
            [button removeFromSuperview];
        }
        self.isLayoutApplied = NO;
    }
    _rightButtons = rightButtons;
    
    // The first button should be the top button on the z-axis
    for (UIButton *button in _rightButtons.reverseObjectEnumerator) {
        NSAssert([button isMemberOfClass:[JAActionButton class]], @"This cell expects JAActionButton class buttons");
        [button addTarget:self action:@selector(buttonTapped:) forControlEvents:UIControlEventTouchUpInside];
	// Make sure the buttons will not be visible before their frames are set...
	button.frame = CGRectMake( 5000, 0, button.frame.size.width, button.frame.size.height );
        [self.contentView addSubview:button];
    }
}

- (void)buttonTapped:(JAActionButton *)button
{
    if (button.handler) {
        button.handler(button, self);
    }
}

- (void)layoutSubviews
{
    [super layoutSubviews];
    
    if (!self.isLayoutApplied) {
        self.topContentView.frame = self.contentView.frame;
        // Layout left buttons
        for (int i = 0; i < self.leftButtons.count; i++) {
            UIButton *lButton = self.leftButtons[i];
            // The first button's width is the same as the contentView. This will be the cell that will
            // pin to the topView.
            if (i == 0) {
                CGRect button1Frame = self.contentView.frame;
                button1Frame.size.width = self.frame.size.width;
		button1Frame.origin.x = - self.frame.size.width;
                lButton.frame = button1Frame;
                [lButton setContentHorizontalAlignment:UIControlContentHorizontalAlignmentRight];
                // Add right padding to the button title
                [lButton setTitleEdgeInsets:UIEdgeInsetsMake(0, 0, 0, kButtonTitlePadding)];
            } else {
                lButton.frame = CGRectMake(-self.leftButtonWidth, 0, self.leftButtonWidth, self.contentView.frame.size.height);
            }
        }
        
        // Layout right buttons
        for (int i = 0; i < self.rightButtons.count; i++) {
            UIButton *rButton = self.rightButtons[i];
            // The first button's width is the same as the contentView. This will be the cell that will
            // pin to the topView.
            if (i == 0) {
                CGRect button1Frame = self.contentView.frame;
		button1Frame.size.width = self.frame.size.width;
		button1Frame.origin.x = self.frame.size.width;
                rButton.frame = button1Frame;
                [rButton setContentHorizontalAlignment:UIControlContentHorizontalAlignmentLeft];
                // Add right padding to the button title
                [rButton setTitleEdgeInsets:UIEdgeInsetsMake(0, kButtonTitlePadding, 0, 0)];
            } else {
		rButton.frame = CGRectMake(self.frame.size.width, 0, self.rightButtonWidth, self.contentView.frame.size.height);
            }
        }
        
        // Need to remember the original frames for when we are swiping the buttons.
        self.leftButtonsStartingX = [[NSMutableArray alloc] initWithCapacity:self.leftButtons.count];
        self.rightButtonsStartingX = [[NSMutableArray alloc] initWithCapacity:self.rightButtons.count];
        for (UIButton *lButton in self.leftButtons) {
            [self.leftButtonsStartingX addObject:[NSNumber numberWithFloat:lButton.frame.origin.x]];
        }
        for (UIButton *rButton in self.rightButtons) {
            [self.rightButtonsStartingX addObject:[NSNumber numberWithFloat:rButton.frame.origin.x]];
        }
        
        self.isLayoutApplied = YES;
    }
}

- (void)addActionButtons:(NSArray *)actionButtons withButtonPosition:(JAButtonLocation)buttonPosition
{
    [self addActionButtons:actionButtons withButtonWidth:kJAButtonWidth withButtonPosition:buttonPosition];
}

- (void)addActionButtons:(NSArray *)actionButtons withButtonWidth:(CGFloat)width withButtonPosition:(JAButtonLocation)buttonPosition
{
    if (buttonPosition == JAButtonLocationLeft) {
        self.leftButtons = actionButtons;
        self.leftButtonWidth = (width > 0) ? width : kJAButtonWidth;
    } else {
        self.rightButtons = actionButtons;
        self.rightButtonWidth = (width > 0) ? width: kJAButtonWidth;
    }
}

#pragma -mark Helper Methods

- (CGFloat)leftButtonsTotalWidth
{
    return self.leftButtons.count * self.leftButtonWidth;
}

- (CGFloat)rightButtonsTotalWidth
{
    return self.rightButtons.count * self.rightButtonWidth;
}

- (void)hideLeftButtons
{
    for (UIButton *button in self.leftButtons){
        button.hidden = YES;
    }
}

- (void)showLeftButtons
{
    for (UIButton *button in self.leftButtons){
        button.hidden = NO;
    }
}

- (void)hideRightButtons
{
    for (UIButton *button in self.rightButtons){
        button.hidden = YES;
    }
}

- (void)showRightButtons
{
    for (UIButton *button in self.rightButtons){
        button.hidden = NO;
    }
}

/**
 Resets the top container view and buttons to their original states.
 */
- (void)resetContainerView
{
    if (self.topContentView.frame.origin.x > 0) {
        [UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
            CGRect frame = self.topContentView.frame;
            frame.origin.x = 0;
            self.topContentView.frame = frame;
            [self revealButtonsWithTopViewWithOffset:0 swipeDirection:JASwipeDirectionRight];
        } completion:nil];
    } else {
        [UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
            CGRect frame = self.topContentView.frame;
            frame.origin.x = 0;
            self.topContentView.frame = frame;
            [self revealButtonsWithTopViewWithOffset:0 swipeDirection:JASwipeDirectionLeft];
        } completion:nil];

    }

}

- (void)completePinToTopViewAnimation
{
    CGFloat newXOffset = self.rightButtonsRevealed ? -self.frame.size.width : self.frame.size.width;
    [UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
        [self pinButtonToTopViewWithOffset:newXOffset swipeDirection:self.rightButtonsRevealed ? JASwipeDirectionLeft : JASwipeDirectionRight];
        self.topContentView.frame = CGRectMake(newXOffset, self.topContentView.frame.origin.y, CGRectGetWidth(self.topContentView.frame), CGRectGetHeight(self.topContentView.frame));
    } completion:nil];
}

/**
 Pins the left most or right most button to the top view.
 @param xOffset The x offset where this button needs to pin to
 @param panDirection The swipe direction.
 */
- (void)pinButtonToTopViewWithOffset:(CGFloat)xOffset swipeDirection:(JASwipeDirection)swipeDirection
{
    UIButton *pinButton = nil;
    CGFloat pinButtonStartingX;
    if (swipeDirection == JASwipeDirectionLeft) {
        pinButton = self.rightButtons[0];
        pinButtonStartingX = [(NSNumber *)self.rightButtonsStartingX[0] floatValue];
    } else {
        pinButton = self.leftButtons[0];
        pinButtonStartingX = [(NSNumber *)self.leftButtonsStartingX[0] floatValue];
    }
    pinButton.frame = CGRectMake(pinButtonStartingX + xOffset, pinButton.frame.origin.y, pinButton.frame.size.width, pinButton.frame.size.height);
}

/**
 Reveals the buttons as the top view pans. The buttons are offset from each other.
 
 @param xOffset The current x offset of the top view.
 @param panDirection The swipe direction.
 */
- (void)revealButtonsWithTopViewWithOffset:(CGFloat)xOffset swipeDirection:(JASwipeDirection)swipeDirection
{
    NSArray *buttons = (swipeDirection == JASwipeDirectionRight) ? self.leftButtons : self.rightButtons;
    NSUInteger buttonCount = buttons.count;
    for (int i = 0; i < buttonCount; i++) {
        JAActionButton *button = buttons[i];
        CGFloat buttonStartingX = (swipeDirection == JASwipeDirectionRight) ?  [(NSNumber *)self.leftButtonsStartingX[i] floatValue] : [(NSNumber *)self.rightButtonsStartingX[i] floatValue];
        if (i == buttonCount - 1) {
            // Last button (closest to the top view) will be offset by the same amount as the top view.
            button.frame = CGRectMake(buttonStartingX + xOffset, button.frame.origin.y, button.frame.size.width, button.frame.size.height);
        } else {
            // The rest of the buttons will be offset from each other.
            button.frame = CGRectMake(buttonStartingX + (xOffset/buttonCount) * (i + 1), button.frame.origin.y, button.frame.size.width, button.frame.size.height);
        }
    }
}

#pragma  -mark UIPanGestureRecognizer delegate methods

- (void)panHandler:(UIPanGestureRecognizer *)recognizer
{
    switch (recognizer.state) {
        case UIGestureRecognizerStateBegan:
            self.startingPoint = self.topContentView.frame.origin;
            break;
        case UIGestureRecognizerStateChanged: {
            CGFloat currentX = [recognizer translationInView:self].x;
            CGFloat newXOffset = self.startingPoint.x + currentX;
	    CGFloat deltaWidth = 0.0;
            
            // When starting from a closed state.
            if (self.startingPoint.x == 0) {
                self.swipingLeft = currentX < self.startingPoint.x;
                self.swipingRight = currentX > self.startingPoint.x;
            } else {
                // Starting on an open state.
                self.swipingLeft = currentX > self.startingPoint.x;
                self.swipingRight = currentX < self.startingPoint.x;
            }
            
            if (self.swipingLeft) {
                // Exit if we don't have any right buttons
                if (self.rightButtons.count == 0 ){
                    return;
                }
                [self hideLeftButtons];
                [self showRightButtons];
                
                if ([self.delegate respondsToSelector:@selector(swipingLeftForCell:)]) {
                    [self.delegate swipingLeftForCell:self];
                }
                
                // Starting in a closed state
                if (self.startingPoint.x == 0) {
                    // Handle panning and revealing the right buttons
                    [self handlePanningButtons:newXOffset swipeDirection:JASwipeDirectionLeft];
                }
                // Top view is open revealing the right buttons
                else {
                    // Starting open with right buttons revealed
                    if (fabs(self.startingPoint.x) == [self rightButtonsTotalWidth]) {
                        // Handle panning and revealing the right buttons
                        [self handlePanningButtons:newXOffset swipeDirection:JASwipeDirectionLeft];
                    }
                }
		// Calculate the top view width adjustment because of accessory buttons
		if( self.contentView.frame.size.width < self.frame.size.width ) {
		    deltaWidth = self.frame.size.width - self.contentView.frame.size.width;
		    if( -newXOffset < deltaWidth )
			deltaWidth = -newXOffset;
		}
            }
            // Swiping to the right
            else if (self.swipingRight) {
                // Exit if we don't have any left buttons
                if (self.leftButtons.count == 0) {
                    return;
                }
                [self hideRightButtons];
                [self showLeftButtons];
                if ([self.delegate respondsToSelector:@selector(swipingRightForCell:)]) {
                    [self.delegate swipingRightForCell:self];
                }
                
                // Starting in a closed state
                if (self.startingPoint.x == 0) {
                    // Handle panning and revealing the left buttons
                    [self handlePanningButtons:newXOffset swipeDirection:JASwipeDirectionRight];
                }
                // Top view is open revealing the left buttons
                else {
                    // Started open with right buttons revealed
                    if (self.startingPoint.x == [self leftButtonsTotalWidth]) {
                        // Handle panning and revealing the left buttons
                        [self handlePanningButtons:newXOffset swipeDirection:JASwipeDirectionRight];
                    }
                }
            }
            
            self.topContentView.frame = CGRectMake(newXOffset, self.startingPoint.y, CGRectGetWidth(self.contentView.frame)+deltaWidth, CGRectGetHeight(self.topContentView.frame));
        }
            break;
        case UIGestureRecognizerStateEnded:
        {
            CGFloat currentX = self.topContentView.frame.origin.x;
            CGFloat newXOffset = 0.0;
	    CGFloat deltaWidth = 0.0;
            
            if (self.swipingLeft) {
                // Exit if we don't have any right buttons
                if (self.rightButtons.count == 0) {
                    return;
                }
                // Complete the swipe to the left
                if (fabs(currentX) > [self rightButtonsTotalWidth]) {
                    newXOffset = -self.frame.size.width;
                    [UIView animateWithDuration:0.1 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
                        [self pinButtonToTopViewWithOffset:newXOffset swipeDirection:JASwipeDirectionLeft];
                    } completion:^(BOOL finished) {
                        [self.delegate rightMostButtonSwipeCompleted:self];
                    }];
                    self.rightButtonsRevealed = NO;
                }
                // Open to reveal right buttons
                else if (fabs(currentX) == [self rightButtonsTotalWidth] || fabs(currentX) > [self rightButtonsTotalWidth]/2) {
                    newXOffset = -[self rightButtonsTotalWidth];
		    // Set the top view width adjustment because of accessory buttons
		    if( self.contentView.frame.size.width < self.frame.size.width ) {
			deltaWidth = self.frame.size.width - self.contentView.frame.size.width;
		    }
                    [UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
                        [self revealButtonsWithTopViewWithOffset:newXOffset swipeDirection:JASwipeDirectionLeft];
                    } completion:nil];
                    self.rightButtonsRevealed = YES;
                }
                // Move top view to closed state
                else {
                    newXOffset = 0;
                    [UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
                        [self revealButtonsWithTopViewWithOffset:newXOffset swipeDirection:JASwipeDirectionLeft];
                    } completion:nil];
                    self.rightButtonsRevealed = NO;
                }
            }
            // Swiping right
            else if (self.swipingRight) {
                // Exit if we don't have any left buttons
                if (self.leftButtons.count == 0) {
                    return;
                }
                // Complete the pan to the right
                if (currentX > [self leftButtonsTotalWidth]) {
                    newXOffset = self.frame.size.width;
                    [UIView animateWithDuration:0.1 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
                        [self pinButtonToTopViewWithOffset:newXOffset swipeDirection:JASwipeDirectionRight];
                    } completion:^(BOOL finished) {
                        [self.delegate leftMostButtonSwipeCompleted:self];
                    }];
                    self.leftButtonsRevealed = NO;
                }
                // Open to reveal left buttons
                else if (currentX == [self leftButtonsTotalWidth] || fabs(currentX) > [self leftButtonsTotalWidth]/2) {
                    newXOffset = [self leftButtonsTotalWidth];
                    [UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
                        [self revealButtonsWithTopViewWithOffset:newXOffset swipeDirection:JASwipeDirectionRight];
                    } completion:nil];
                    self.leftButtonsRevealed = YES;
                }
                // Move top view to closed state
                else {
                    newXOffset = 0;
                    [UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
                        [self revealButtonsWithTopViewWithOffset:newXOffset swipeDirection:JASwipeDirectionRight];
                    } completion:nil];
                    self.leftButtonsRevealed = NO;
                }
            }
           
            [UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
                self.topContentView.frame = CGRectMake(newXOffset, self.topContentView.frame.origin.y, CGRectGetWidth(self.contentView.frame)+deltaWidth, CGRectGetHeight(self.topContentView.frame));
            } completion:nil];
            
            break;
        }
        default:
            break;
    }
}

/**
 Helper method that handles pinning the left/right most button to the top view and also the panning of all the buttons.
 */
- (void)handlePanningButtons:(CGFloat)xOffset swipeDirection:(JASwipeDirection)swipeDirection
{
    CGFloat newXOffset = (swipeDirection == JASwipeDirectionLeft) ? fabs(xOffset) : xOffset;
    CGFloat totalButtonsWidth = (swipeDirection == JASwipeDirectionLeft) ? [self rightButtonsTotalWidth] : [self leftButtonsTotalWidth];
    BOOL buttonPinned = (swipeDirection == JASwipeDirectionLeft) ? self.rightMostButtonPinned : self.leftMostButtonPinned;
    
    // Pin the furthest left/right button to the top view
    if (newXOffset > totalButtonsWidth) {
        // Animate the pinning of the edge-most button
        if (!buttonPinned) {
            [UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
                [self pinButtonToTopViewWithOffset:xOffset swipeDirection:swipeDirection];
            } completion:nil];
        } else {
            [self pinButtonToTopViewWithOffset:xOffset swipeDirection:swipeDirection];
        }
        if (swipeDirection == JASwipeDirectionLeft) {
            self.rightMostButtonPinned = YES;
        } else {
            self.leftMostButtonPinned = YES;
        }
        
    } else {
        // Move the buttons along with the top view
        if (buttonPinned) {
            [UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
                [self revealButtonsWithTopViewWithOffset:xOffset swipeDirection:swipeDirection];
            } completion:nil];
        } else {
            [self revealButtonsWithTopViewWithOffset:xOffset swipeDirection:swipeDirection];
        }
        if (swipeDirection == JASwipeDirectionLeft) {
            self.rightMostButtonPinned = NO;
        } else {
            self.leftMostButtonPinned = NO;
        }
    }
}

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
    if ([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) {
        
        // Find the current vertical scrolling velocity
        CGFloat velocity = [(UIPanGestureRecognizer *)gestureRecognizer velocityInView:gestureRecognizer.view].y;
        
        // Return YES if no scrolling up
        return fabs(velocity) <= 0.2;
        
    }
    return YES;
}

- (BOOL)gestureRecognizerShouldBegin:(UIPanGestureRecognizer *)gestureRecognizer {
    if ( gestureRecognizer == self.panGestureRecognizer ) {
        CGPoint translation = [gestureRecognizer translationInView:self.superview];
        return fabs(translation.y) <= fabs(translation.x);
    }
    else {
        return YES;
    }
}

@end


================================================
FILE: JASwipeCell.podspec
================================================
#
#  Be sure to run `pod spec lint JASwipeCell.podspec' to ensure this is a
#  valid spec and to remove all comments including this before submitting the spec.
#
#  To learn more about Podspec attributes see http://docs.cocoapods.org/specification.html
#  To see working Podspecs in the CocoaPods repo see https://github.com/CocoaPods/Specs/
#

Pod::Spec.new do |s|
  s.name         = "JASwipeCell"
  s.version      = "1.0.1"
  s.summary      = "A UITableViewCell subclass that simulates IOS 8 mail's swipe cells."

  s.description  = <<-DESC
                   A UITableViewCell subclass that displays customizable left or right buttons that are revealed as the user swipes the cell in either direction. The edge-most buttons will pin to the container view and will execute an event similar to how the delete/archive button work in IOS 8 mail. A great way to simulate IOS 8 mail's behavior.
                   DESC

  s.homepage     = "https://github.com/joseria/JASwipeCell"
  s.license      = 'MIT'
  s.author             = { "Jose Alvarez" => "jose.a.alvarez@gmail.com" }
  s.social_media_url   = "http://twitter.com/joseaalvarez"
  s.platform     = :ios, "7.0"
  s.source       = { :git => "https://github.com/joseria/JASwipeCell.git", :tag => "1.0.1" }
  s.source_files  = 'JASwipeCell'
  s.requires_arc = true
end


================================================
FILE: JASwipeCellExample/ALView+PureLayout.h
================================================
//
//  ALView+PureLayout.h
//  v1.1.0
//  https://github.com/smileyborg/PureLayout
//
//  Copyright (c) 2012 Richard Turton
//  Copyright (c) 2013-2014 Tyler Fox
//
//  This code is distributed under the terms and conditions of the MIT license.
//
//  Permission is hereby granted, free of charge, to any person obtaining a copy
//  of this software and associated documentation files (the "Software"), to
//  deal in the Software without restriction, including without limitation the
//  rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
//  sell copies of the Software, and to permit persons to whom the Software is
//  furnished to do so, subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be included in
//  all copies or substantial portions of the Software.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
//  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
//  IN THE SOFTWARE.
//

#import "PureLayoutDefines.h"


#pragma mark - ALView+PureLayout

/**
 A category on UIView/NSView that provides a simple yet powerful interface for creating Auto Layout constraints.
 */
@interface ALView (PureLayout)


#pragma mark Factory & Initializer Methods

/** Creates and returns a new view that does not convert the autoresizing mask into constraints. */
+ (instancetype)newAutoLayoutView;

/** Initializes and returns a new view that does not convert the autoresizing mask into constraints. */
- (instancetype)initForAutoLayout;


#pragma mark Set Constraint Priority

/** Sets the constraint priority to the given value for all constraints created using the PureLayout API within the given constraints block.
    NOTE: This method will have no effect (and will NOT set the priority) on constraints created or added using the SDK directly within the block! */
+ (void)autoSetPriority:(ALLayoutPriority)priority forConstraints:(ALConstraintsBlock)block;


#pragma mark Remove Constraints

/** Removes the given constraint from the view it has been added to. */
+ (void)autoRemoveConstraint:(NSLayoutConstraint *)constraint;

/** Removes the given constraints from the views they have been added to. */
+ (void)autoRemoveConstraints:(NSArray *)constraints;

/** Removes all explicit constraints that affect the view.
    WARNING: Apple's constraint solver is not optimized for large-scale constraint removal; you may encounter major performance issues after using this method.
    NOTE: This method preserves implicit constraints, such as intrinsic content size constraints, which you usually do not want to remove. */
- (void)autoRemoveConstraintsAffectingView;

/** Removes all constraints that affect the view, optionally including implicit constraints.
    WARNING: Apple's constraint solver is not optimized for large-scale constraint removal; you may encounter major performance issues after using this method.
    NOTE: Implicit constraints are auto-generated lower priority constraints, and you usually do not want to remove these. */
- (void)autoRemoveConstraintsAffectingViewIncludingImplicitConstraints:(BOOL)shouldRemoveImplicitConstraints;

/** Recursively removes all explicit constraints that affect the view and its subviews.
    WARNING: Apple's constraint solver is not optimized for large-scale constraint removal; you may encounter major performance issues after using this method.
    NOTE: This method preserves implicit constraints, such as intrinsic content size constraints, which you usually do not want to remove. */
- (void)autoRemoveConstraintsAffectingViewAndSubviews;

/** Recursively removes all constraints from the view and its subviews, optionally including implicit constraints.
    WARNING: Apple's constraint solver is not optimized for large-scale constraint removal; you may encounter major performance issues after using this method.
    NOTE: Implicit constraints are auto-generated lower priority constraints, and you usually do not want to remove these. */
- (void)autoRemoveConstraintsAffectingViewAndSubviewsIncludingImplicitConstraints:(BOOL)shouldRemoveImplicitConstraints;


#pragma mark Center in Superview

/** Centers the view in its superview. */
- (NSArray *)autoCenterInSuperview;

/** Aligns the view to the same axis of its superview. */
- (NSLayoutConstraint *)autoAlignAxisToSuperviewAxis:(ALAxis)axis;


#pragma mark Pin Edges to Superview

/** Pins the given edge of the view to the same edge of its superview. */
- (NSLayoutConstraint *)autoPinEdgeToSuperviewEdge:(ALEdge)edge;

/** Pins the given edge of the view to the same edge of its superview with an inset. */
- (NSLayoutConstraint *)autoPinEdgeToSuperviewEdge:(ALEdge)edge withInset:(CGFloat)inset;

/** Pins the given edge of the view to the same edge of its superview with an inset as a maximum or minimum. */
- (NSLayoutConstraint *)autoPinEdgeToSuperviewEdge:(ALEdge)edge withInset:(CGFloat)inset relation:(NSLayoutRelation)relation;

/** Pins the edges of the view to the edges of its superview with the given edge insets. */
- (NSArray *)autoPinEdgesToSuperviewEdgesWithInsets:(ALEdgeInsets)insets;

/** Pins 3 of the 4 edges of the view to the edges of its superview with the given edge insets, excluding one edge. */
- (NSArray *)autoPinEdgesToSuperviewEdgesWithInsets:(ALEdgeInsets)insets excludingEdge:(ALEdge)edge;


#pragma mark Pin Edges

/** Pins an edge of the view to a given edge of another view. */
- (NSLayoutConstraint *)autoPinEdge:(ALEdge)edge toEdge:(ALEdge)toEdge ofView:(ALView *)peerView;

/** Pins an edge of the view to a given edge of another view with an offset. */
- (NSLayoutConstraint *)autoPinEdge:(ALEdge)edge toEdge:(ALEdge)toEdge ofView:(ALView *)peerView withOffset:(CGFloat)offset;

/** Pins an edge of the view to a given edge of another view with an offset as a maximum or minimum. */
- (NSLayoutConstraint *)autoPinEdge:(ALEdge)edge toEdge:(ALEdge)toEdge ofView:(ALView *)peerView withOffset:(CGFloat)offset relation:(NSLayoutRelation)relation;


#pragma mark Align Axes

/** Aligns an axis of the view to the same axis of another view. */
- (NSLayoutConstraint *)autoAlignAxis:(ALAxis)axis toSameAxisOfView:(ALView *)peerView;

/** Aligns an axis of the view to the same axis of another view with an offset. */
- (NSLayoutConstraint *)autoAlignAxis:(ALAxis)axis toSameAxisOfView:(ALView *)peerView withOffset:(CGFloat)offset;


#pragma mark Match Dimensions

/** Matches a dimension of the view to a given dimension of another view. */
- (NSLayoutConstraint *)autoMatchDimension:(ALDimension)dimension toDimension:(ALDimension)toDimension ofView:(ALView *)peerView;

/** Matches a dimension of the view to a given dimension of another view with an offset. */
- (NSLayoutConstraint *)autoMatchDimension:(ALDimension)dimension toDimension:(ALDimension)toDimension ofView:(ALView *)peerView withOffset:(CGFloat)offset;

/** Matches a dimension of the view to a given dimension of another view with an offset as a maximum or minimum. */
- (NSLayoutConstraint *)autoMatchDimension:(ALDimension)dimension toDimension:(ALDimension)toDimension ofView:(ALView *)peerView withOffset:(CGFloat)offset relation:(NSLayoutRelation)relation;

/** Matches a dimension of the view to a multiple of a given dimension of another view. */
- (NSLayoutConstraint *)autoMatchDimension:(ALDimension)dimension toDimension:(ALDimension)toDimension ofView:(ALView *)peerView withMultiplier:(CGFloat)multiplier;

/** Matches a dimension of the view to a multiple of a given dimension of another view as a maximum or minimum. */
- (NSLayoutConstraint *)autoMatchDimension:(ALDimension)dimension toDimension:(ALDimension)toDimension ofView:(ALView *)peerView withMultiplier:(CGFloat)multiplier relation:(NSLayoutRelation)relation;


#pragma mark Set Dimensions

/** Sets the view to a specific size. */
- (NSArray *)autoSetDimensionsToSize:(CGSize)size;

/** Sets the given dimension of the view to a specific size. */
- (NSLayoutConstraint *)autoSetDimension:(ALDimension)dimension toSize:(CGFloat)size;

/** Sets the given dimension of the view to a specific size as a maximum or minimum. */
- (NSLayoutConstraint *)autoSetDimension:(ALDimension)dimension toSize:(CGFloat)size relation:(NSLayoutRelation)relation;


#pragma mark Set Content Compression Resistance & Hugging

/** Sets the priority of content compression resistance for an axis.
    NOTE: This method must only be called from within the block passed into the method +[autoSetPriority:forConstraints:] */
- (void)autoSetContentCompressionResistancePriorityForAxis:(ALAxis)axis;

/** Sets the priority of content hugging for an axis.
    NOTE: This method must only be called from within the block passed into the method +[autoSetPriority:forConstraints:] */
- (void)autoSetContentHuggingPriorityForAxis:(ALAxis)axis;


#pragma mark Constrain Any Attributes

/** Constrains an attribute (any ALEdge, ALAxis, or ALDimension) of the view to a given attribute of another view. */
- (NSLayoutConstraint *)autoConstrainAttribute:(NSInteger)attribute toAttribute:(NSInteger)toAttribute ofView:(ALView *)peerView;

/** Constrains an attribute (any ALEdge, ALAxis, or ALDimension) of the view to a given attribute of another view with an offset. */
- (NSLayoutConstraint *)autoConstrainAttribute:(NSInteger)attribute toAttribute:(NSInteger)toAttribute ofView:(ALView *)peerView withOffset:(CGFloat)offset;

/** Constrains an attribute (any ALEdge, ALAxis, or ALDimension) of the view to a given attribute of another view with an offset as a maximum or minimum. */
- (NSLayoutConstraint *)autoConstrainAttribute:(NSInteger)attribute toAttribute:(NSInteger)toAttribute ofView:(ALView *)peerView withOffset:(CGFloat)offset relation:(NSLayoutRelation)relation;

/** Constrains an attribute (any ALEdge, ALAxis, or ALDimension) of the view to a given attribute of another view with a multiplier. */
- (NSLayoutConstraint *)autoConstrainAttribute:(NSInteger)attribute toAttribute:(NSInteger)toAttribute ofView:(ALView *)peerView withMultiplier:(CGFloat)multiplier;

/** Constrains an attribute (any ALEdge, ALAxis, or ALDimension) of the view to a given attribute of another view with a multiplier as a maximum or minimum. */
- (NSLayoutConstraint *)autoConstrainAttribute:(NSInteger)attribute toAttribute:(NSInteger)toAttribute ofView:(ALView *)peerView withMultiplier:(CGFloat)multiplier relation:(NSLayoutRelation)relation;


#pragma mark Pin to Layout Guides (iOS only)

#if TARGET_OS_IPHONE

/** Pins the top edge of the view to the top layout guide of the given view controller with an inset. */
- (NSLayoutConstraint *)autoPinToTopLayoutGuideOfViewController:(UIViewController *)viewController withInset:(CGFloat)inset;

/** Pins the bottom edge of the view to the bottom layout guide of the given view controller with an inset. */
- (NSLayoutConstraint *)autoPinToBottomLayoutGuideOfViewController:(UIViewController *)viewController withInset:(CGFloat)inset;

#endif /* TARGET_OS_IPHONE */

@end


================================================
FILE: JASwipeCellExample/ALView+PureLayout.m
================================================
//
//  ALView+PureLayout.m
//  v1.1.0
//  https://github.com/smileyborg/PureLayout
//
//  Copyright (c) 2012 Richard Turton
//  Copyright (c) 2013-2014 Tyler Fox
//
//  This code is distributed under the terms and conditions of the MIT license.
//
//  Permission is hereby granted, free of charge, to any person obtaining a copy
//  of this software and associated documentation files (the "Software"), to
//  deal in the Software without restriction, including without limitation the
//  rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
//  sell copies of the Software, and to permit persons to whom the Software is
//  furnished to do so, subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be included in
//  all copies or substantial portions of the Software.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
//  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
//  IN THE SOFTWARE.
//

#import "ALView+PureLayout.h"
#import "NSLayoutConstraint+PureLayout.h"


#pragma mark - ALView+PureLayout

@implementation ALView (PureLayout)


#pragma mark Factory & Initializer Methods

/** 
 Creates and returns a new view that does not convert the autoresizing mask into constraints.
 */
+ (instancetype)newAutoLayoutView
{
    ALView *view = [self new];
    view.translatesAutoresizingMaskIntoConstraints = NO;
    return view;
}

/**
 Initializes and returns a new view that does not convert the autoresizing mask into constraints.
 */
- (instancetype)initForAutoLayout
{
    self = [self init];
    if (self) {
        self.translatesAutoresizingMaskIntoConstraints = NO;
    }
    return self;
}


#pragma mark Set Constraint Priority

/** 
 A global variable that determines the priority of all constraints created and added by this category.
 Defaults to Required, will only be a different value while executing a constraints block passed into the
 +[autoSetPriority:forConstraints:] method (as that method will reset the value back to Required
 before returning).
 NOTE: Access to this variable is not synchronized (and should only be done on the main thread).
 */
static ALLayoutPriority _al_globalConstraintPriority = ALLayoutPriorityRequired;

/**
 A global variable that is set to YES while the constraints block passed in to the
 +[autoSetPriority:forConstraints:] method is executing.
 NOTE: Access to this variable is not synchronized (and should only be done on the main thread).
 */
static BOOL _al_isExecutingConstraintsBlock = NO;

/**
 Sets the constraint priority to the given value for all constraints created using the PureLayout
 API within the given constraints block.
 
 NOTE: This method will have no effect (and will NOT set the priority) on constraints created or added 
 using the SDK directly within the block!
 
 @param priority The layout priority to be set on all constraints in the constraints block.
 @param block A block of method calls to the PureLayout API that create and add constraints.
 */
+ (void)autoSetPriority:(ALLayoutPriority)priority forConstraints:(ALConstraintsBlock)block
{
    NSAssert(block, @"The constraints block cannot be nil.");
    if (block) {
        _al_globalConstraintPriority = priority;
        _al_isExecutingConstraintsBlock = YES;
        block();
        _al_isExecutingConstraintsBlock = NO;
        _al_globalConstraintPriority = ALLayoutPriorityRequired;
    }
}


#pragma mark Remove Constraints

/**
 Removes the given constraint from the view it has been added to.
 
 @param constraint The constraint to remove.
 */
+ (void)autoRemoveConstraint:(NSLayoutConstraint *)constraint
{
    if (constraint.secondItem) {
        ALView *commonSuperview = [constraint.firstItem al_commonSuperviewWithView:constraint.secondItem];
        while (commonSuperview) {
            if ([commonSuperview.constraints containsObject:constraint]) {
                [commonSuperview removeConstraint:constraint];
                return;
            }
            commonSuperview = commonSuperview.superview;
        }
    }
    else {
        [constraint.firstItem removeConstraint:constraint];
        return;
    }
    NSAssert(nil, @"Failed to remove constraint: %@", constraint);
}

/**
 Removes the given constraints from the views they have been added to.
 
 @param constraints The constraints to remove.
 */
+ (void)autoRemoveConstraints:(NSArray *)constraints
{
    for (id object in constraints) {
        if ([object isKindOfClass:[NSLayoutConstraint class]]) {
            [self autoRemoveConstraint:((NSLayoutConstraint *)object)];
        } else {
            NSAssert(nil, @"All constraints to remove must be instances of NSLayoutConstraint.");
        }
    }
}

/**
 Removes all explicit constraints that affect the view.
 WARNING: Apple's constraint solver is not optimized for large-scale constraint removal; you may encounter major performance issues after using this method.
          It is not recommended to use this method to "reset" a view for reuse in a different way with new constraints. Create a new view instead.
 NOTE: This method preserves implicit constraints, such as intrinsic content size constraints, which you usually do not want to remove.
 */
- (void)autoRemoveConstraintsAffectingView
{
    [self autoRemoveConstraintsAffectingViewIncludingImplicitConstraints:NO];
}

/**
 Removes all constraints that affect the view, optionally including implicit constraints.
 WARNING: Apple's constraint solver is not optimized for large-scale constraint removal; you may encounter major performance issues after using this method.
          It is not recommended to use this method to "reset" a view for reuse in a different way with new constraints. Create a new view instead.
 NOTE: Implicit constraints are auto-generated lower priority constraints (such as those that attempt to keep a view at
 its intrinsic content size by hugging its content & resisting compression), and you usually do not want to remove these.
 
 @param shouldRemoveImplicitConstraints Whether implicit constraints should be removed or skipped.
 */
- (void)autoRemoveConstraintsAffectingViewIncludingImplicitConstraints:(BOOL)shouldRemoveImplicitConstraints
{
    NSMutableArray *constraintsToRemove = [NSMutableArray new];
    ALView *startView = self;
    do {
        for (NSLayoutConstraint *constraint in startView.constraints) {
            BOOL isImplicitConstraint = [NSStringFromClass([constraint class]) isEqualToString:@"NSContentSizeLayoutConstraint"];
            if (shouldRemoveImplicitConstraints || !isImplicitConstraint) {
                if (constraint.firstItem == self || constraint.secondItem == self) {
                    [constraintsToRemove addObject:constraint];
                }
            }
        }
        startView = startView.superview;
    } while (startView);
    [ALView autoRemoveConstraints:constraintsToRemove];
}

/**
 Recursively removes all explicit constraints that affect the view and its subviews.
 WARNING: Apple's constraint solver is not optimized for large-scale constraint removal; you may encounter major performance issues after using this method.
          It is not recommended to use this method to "reset" views for reuse in a different way with new constraints. Create a new view instead.
 NOTE: This method preserves implicit constraints, such as intrinsic content size constraints, which you usually do not want to remove.
 */
- (void)autoRemoveConstraintsAffectingViewAndSubviews
{
    [self autoRemoveConstraintsAffectingViewAndSubviewsIncludingImplicitConstraints:NO];
}

/** 
 Recursively removes all constraints that affect the view and its subviews, optionally including implicit constraints.
 WARNING: Apple's constraint solver is not optimized for large-scale constraint removal; you may encounter major performance issues after using this method.
          It is not recommended to use this method to "reset" views for reuse in a different way with new constraints. Create a new view instead.
 NOTE: Implicit constraints are auto-generated lower priority constraints (such as those that attempt to keep a view at
 its intrinsic content size by hugging its content & resisting compression), and you usually do not want to remove these.
 
 @param shouldRemoveImplicitConstraints Whether implicit constraints should be removed or skipped.
 */
- (void)autoRemoveConstraintsAffectingViewAndSubviewsIncludingImplicitConstraints:(BOOL)shouldRemoveImplicitConstraints
{
    [self autoRemoveConstraintsAffectingViewIncludingImplicitConstraints:shouldRemoveImplicitConstraints];
    for (ALView *subview in self.subviews) {
        [subview autoRemoveConstraintsAffectingViewAndSubviewsIncludingImplicitConstraints:shouldRemoveImplicitConstraints];
    }
}


#pragma mark Center in Superview

/**
 Centers the view in its superview.
 
 @return An array of constraints added.
 */
- (NSArray *)autoCenterInSuperview
{
    NSMutableArray *constraints = [NSMutableArray new];
    [constraints addObject:[self autoAlignAxisToSuperviewAxis:ALAxisHorizontal]];
    [constraints addObject:[self autoAlignAxisToSuperviewAxis:ALAxisVertical]];
    return constraints;
}

/**
 Aligns the view to the same axis of its superview.
 
 @param axis The axis of this view and of its superview to align.
 @return The constraint added.
 */
- (NSLayoutConstraint *)autoAlignAxisToSuperviewAxis:(ALAxis)axis
{
    self.translatesAutoresizingMaskIntoConstraints = NO;
    ALView *superview = self.superview;
    NSAssert(superview, @"View's superview must not be nil.\nView: %@", self);
    NSLayoutAttribute attribute = [ALView al_attributeForAxis:axis];
    NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:self attribute:attribute relatedBy:NSLayoutRelationEqual toItem:superview attribute:attribute multiplier:1.0 constant:0.0];
    [constraint autoInstall];
    return constraint;
}


#pragma mark Pin Edges to Superview

/**
 Pins the given edge of the view to the same edge of its superview.
 
 @param edge The edge of this view and its superview to pin.
 @return The constraint added.
 */
- (NSLayoutConstraint *)autoPinEdgeToSuperviewEdge:(ALEdge)edge
{
    return [self autoPinEdgeToSuperviewEdge:edge withInset:0.0];
}

/**
 Pins the given edge of the view to the same edge of its superview with an inset.
 
 @param edge The edge of this view and its superview to pin.
 @param inset The amount to inset this view's edge from the superview's edge.
 @return The constraint added.
 */
- (NSLayoutConstraint *)autoPinEdgeToSuperviewEdge:(ALEdge)edge withInset:(CGFloat)inset
{
    return [self autoPinEdgeToSuperviewEdge:edge withInset:inset relation:NSLayoutRelationEqual];
}

/**
 Pins the given edge of the view to the same edge of its superview with an inset as a maximum or minimum.
 
 @param edge The edge of this view and its superview to pin.
 @param inset The amount to inset this view's edge from the superview's edge.
 @param relation Whether the inset should be at least, at most, or exactly equal to the given value.
 @return The constraint added.
 */
- (NSLayoutConstraint *)autoPinEdgeToSuperviewEdge:(ALEdge)edge withInset:(CGFloat)inset relation:(NSLayoutRelation)relation
{
    self.translatesAutoresizingMaskIntoConstraints = NO;
    ALView *superview = self.superview;
    NSAssert(superview, @"View's superview must not be nil.\nView: %@", self);
    if (edge == ALEdgeBottom || edge == ALEdgeRight || edge == ALEdgeTrailing) {
        // The bottom, right, and trailing insets (and relations, if an inequality) are inverted to become offsets
        inset = -inset;
        if (relation == NSLayoutRelationLessThanOrEqual) {
            relation = NSLayoutRelationGreaterThanOrEqual;
        } else if (relation == NSLayoutRelationGreaterThanOrEqual) {
            relation = NSLayoutRelationLessThanOrEqual;
        }
    }
    return [self autoPinEdge:edge toEdge:edge ofView:superview withOffset:inset relation:relation];
}

/**
 Pins the edges of the view to the edges of its superview with the given edge insets.
 The insets.left corresponds to a leading edge constraint, and insets.right corresponds to a trailing edge constraint.
 
 @param insets The insets for this view's edges from its superview's edges.
 @return An array of constraints added.
 */
- (NSArray *)autoPinEdgesToSuperviewEdgesWithInsets:(ALEdgeInsets)insets
{
    NSMutableArray *constraints = [NSMutableArray new];
    [constraints addObject:[self autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:insets.top]];
    [constraints addObject:[self autoPinEdgeToSuperviewEdge:ALEdgeLeading withInset:insets.left]];
    [constraints addObject:[self autoPinEdgeToSuperviewEdge:ALEdgeBottom withInset:insets.bottom]];
    [constraints addObject:[self autoPinEdgeToSuperviewEdge:ALEdgeTrailing withInset:insets.right]];
    return constraints;
}

/**
 Pins 3 of the 4 edges of the view to the edges of its superview with the given edge insets, excluding one edge.
 The insets.left corresponds to a leading edge constraint, and insets.right corresponds to a trailing edge constraint.
 
 @param insets The insets for this view's edges from its superview's edges. The inset corresponding to the excluded edge
               will be ignored.
 @param edge The edge of this view to exclude in pinning to its superview; this method will not apply any constraint to it.
 @return An array of constraints added.
 */
- (NSArray *)autoPinEdgesToSuperviewEdgesWithInsets:(ALEdgeInsets)insets excludingEdge:(ALEdge)edge
{
    NSMutableArray *constraints = [NSMutableArray new];
    if (edge != ALEdgeTop) {
        [constraints addObject:[self autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:insets.top]];
    }
    if (edge != ALEdgeLeading && edge != ALEdgeLeft) {
        [constraints addObject:[self autoPinEdgeToSuperviewEdge:ALEdgeLeading withInset:insets.left]];
    }
    if (edge != ALEdgeBottom) {
        [constraints addObject:[self autoPinEdgeToSuperviewEdge:ALEdgeBottom withInset:insets.bottom]];
    }
    if (edge != ALEdgeTrailing && edge != ALEdgeRight) {
        [constraints addObject:[self autoPinEdgeToSuperviewEdge:ALEdgeTrailing withInset:insets.right]];
    }
    return constraints;
}


#pragma mark Pin Edges

/**
 Pins an edge of the view to a given edge of another view.
 
 @param edge The edge of this view to pin.
 @param toEdge The edge of the peer view to pin to.
 @param peerView The peer view to pin to. Must be in the same view hierarchy as this view.
 @return The constraint added.
 */
- (NSLayoutConstraint *)autoPinEdge:(ALEdge)edge toEdge:(ALEdge)toEdge ofView:(ALView *)peerView
{
    return [self autoPinEdge:edge toEdge:toEdge ofView:peerView withOffset:0.0];
}

/**
 Pins an edge of the view to a given edge of another view with an offset.
 
 @param edge The edge of this view to pin.
 @param toEdge The edge of the peer view to pin to.
 @param peerView The peer view to pin to. Must be in the same view hierarchy as this view.
 @param offset The offset between the edge of this view and the edge of the peer view.
 @return The constraint added.
 */
- (NSLayoutConstraint *)autoPinEdge:(ALEdge)edge toEdge:(ALEdge)toEdge ofView:(ALView *)peerView withOffset:(CGFloat)offset
{
    return [self autoPinEdge:edge toEdge:toEdge ofView:peerView withOffset:offset relation:NSLayoutRelationEqual];
}

/**
 Pins an edge of the view to a given edge of another view with an offset as a maximum or minimum.
 
 @param edge The edge of this view to pin.
 @param toEdge The edge of the peer view to pin to.
 @param peerView The peer view to pin to. Must be in the same view hierarchy as this view.
 @param offset The offset between the edge of this view and the edge of the peer view.
 @param relation Whether the offset should be at least, at most, or exactly equal to the given value.
 @return The constraint added.
 */
- (NSLayoutConstraint *)autoPinEdge:(ALEdge)edge toEdge:(ALEdge)toEdge ofView:(ALView *)peerView withOffset:(CGFloat)offset relation:(NSLayoutRelation)relation
{
    self.translatesAutoresizingMaskIntoConstraints = NO;
    NSLayoutAttribute attribute = [ALView al_attributeForEdge:edge];
    NSLayoutAttribute toAttribute = [ALView al_attributeForEdge:toEdge];
    NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:self attribute:attribute relatedBy:relation toItem:peerView attribute:toAttribute multiplier:1.0 constant:offset];
    [constraint autoInstall];
    return constraint;
}


#pragma mark Align Axes

/**
 Aligns an axis of the view to the same axis of another view.
 
 @param axis The axis of this view and the peer view to align.
 @param peerView The peer view to align to. Must be in the same view hierarchy as this view.
 @return The constraint added.
 */
- (NSLayoutConstraint *)autoAlignAxis:(ALAxis)axis toSameAxisOfView:(ALView *)peerView
{
    return [self autoAlignAxis:axis toSameAxisOfView:peerView withOffset:0.0];
}

/**
 Aligns an axis of the view to the same axis of another view with an offset.
 
 @param axis The axis of this view and the peer view to align.
 @param peerView The peer view to align to. Must be in the same view hierarchy as this view.
 @param offset The offset between the axis of this view and the axis of the peer view.
 @return The constraint added.
 */
- (NSLayoutConstraint *)autoAlignAxis:(ALAxis)axis toSameAxisOfView:(ALView *)peerView withOffset:(CGFloat)offset
{
    self.translatesAutoresizingMaskIntoConstraints = NO;
    NSLayoutAttribute attribute = [ALView al_attributeForAxis:axis];
    NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:self attribute:attribute relatedBy:NSLayoutRelationEqual toItem:peerView attribute:attribute multiplier:1.0 constant:offset];
    [constraint autoInstall];
    return constraint;
}


#pragma mark Match Dimensions

/**
 Matches a dimension of the view to a given dimension of another view.
 
 @param dimension The dimension of this view to pin.
 @param toDimension The dimension of the peer view to pin to.
 @param peerView The peer view to match to. Must be in the same view hierarchy as this view.
 @return The constraint added.
 */
- (NSLayoutConstraint *)autoMatchDimension:(ALDimension)dimension toDimension:(ALDimension)toDimension ofView:(ALView *)peerView
{
    return [self autoMatchDimension:dimension toDimension:toDimension ofView:peerView withOffset:0.0];
}

/**
 Matches a dimension of the view to a given dimension of another view with an offset.
 
 @param dimension The dimension of this view to pin.
 @param toDimension The dimension of the peer view to pin to.
 @param peerView The peer view to match to. Must be in the same view hierarchy as this view.
 @param offset The offset between the dimension of this view and the dimension of the peer view.
 @return The constraint added.
 */
- (NSLayoutConstraint *)autoMatchDimension:(ALDimension)dimension toDimension:(ALDimension)toDimension ofView:(ALView *)peerView withOffset:(CGFloat)offset
{
    return [self autoMatchDimension:dimension toDimension:toDimension ofView:peerView withOffset:offset relation:NSLayoutRelationEqual];
}

/**
 Matches a dimension of the view to a given dimension of another view with an offset as a maximum or minimum.
 
 @param dimension The dimension of this view to pin.
 @param toDimension The dimension of the peer view to pin to.
 @param peerView The peer view to match to. Must be in the same view hierarchy as this view.
 @param offset The offset between the dimension of this view and the dimension of the peer view.
 @param relation Whether the offset should be at least, at most, or exactly equal to the given value.
 @return The constraint added.
 */
- (NSLayoutConstraint *)autoMatchDimension:(ALDimension)dimension toDimension:(ALDimension)toDimension ofView:(ALView *)peerView withOffset:(CGFloat)offset relation:(NSLayoutRelation)relation
{
    self.translatesAutoresizingMaskIntoConstraints = NO;
    NSLayoutAttribute attribute = [ALView al_attributeForDimension:dimension];
    NSLayoutAttribute toAttribute = [ALView al_attributeForDimension:toDimension];
    NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:self attribute:attribute relatedBy:relation toItem:peerView attribute:toAttribute multiplier:1.0 constant:offset];
    [constraint autoInstall];
    return constraint;
}

/**
 Matches a dimension of the view to a multiple of a given dimension of another view.
 
 @param dimension The dimension of this view to pin.
 @param toDimension The dimension of the peer view to pin to.
 @param peerView The peer view to match to. Must be in the same view hierarchy as this view.
 @param multiplier The multiple of the peer view's given dimension that this view's given dimension should be.
 @return The constraint added.
 */
- (NSLayoutConstraint *)autoMatchDimension:(ALDimension)dimension toDimension:(ALDimension)toDimension ofView:(ALView *)peerView withMultiplier:(CGFloat)multiplier
{
    return [self autoMatchDimension:dimension toDimension:toDimension ofView:peerView withMultiplier:multiplier relation:NSLayoutRelationEqual];
}

/**
 Matches a dimension of the view to a multiple of a given dimension of another view as a maximum or minimum.
 
 @param dimension The dimension of this view to pin.
 @param toDimension The dimension of the peer view to pin to.
 @param peerView The peer view to match to. Must be in the same view hierarchy as this view.
 @param multiplier The multiple of the peer view's given dimension that this view's given dimension should be.
 @param relation Whether the multiple should be at least, at most, or exactly equal to the given value.
 @return The constraint added.
 */
- (NSLayoutConstraint *)autoMatchDimension:(ALDimension)dimension toDimension:(ALDimension)toDimension ofView:(ALView *)peerView withMultiplier:(CGFloat)multiplier relation:(NSLayoutRelation)relation
{
    self.translatesAutoresizingMaskIntoConstraints = NO;
    NSLayoutAttribute attribute = [ALView al_attributeForDimension:dimension];
    NSLayoutAttribute toAttribute = [ALView al_attributeForDimension:toDimension];
    NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:self attribute:attribute relatedBy:relation toItem:peerView attribute:toAttribute multiplier:multiplier constant:0.0];
    [constraint autoInstall];
    return constraint;
}


#pragma mark Set Dimensions

/**
 Sets the view to a specific size.
 
 @param size The size to set this view's dimensions to.
 @return An array of constraints added.
 */
- (NSArray *)autoSetDimensionsToSize:(CGSize)size
{
    NSMutableArray *constraints = [NSMutableArray new];
    [constraints addObject:[self autoSetDimension:ALDimensionWidth toSize:size.width]];
    [constraints addObject:[self autoSetDimension:ALDimensionHeight toSize:size.height]];
    return constraints;
}

/**
 Sets the given dimension of the view to a specific size.
 
 @param dimension The dimension of this view to set.
 @param size The size to set the given dimension to.
 @return The constraint added.
 */
- (NSLayoutConstraint *)autoSetDimension:(ALDimension)dimension toSize:(CGFloat)size
{
    return [self autoSetDimension:dimension toSize:size relation:NSLayoutRelationEqual];
}

/**
 Sets the given dimension of the view to a specific size as a maximum or minimum.
 
 @param dimension The dimension of this view to set.
 @param size The size to set the given dimension to.
 @param relation Whether the size should be at least, at most, or exactly equal to the given value.
 @return The constraint added.
 */
- (NSLayoutConstraint *)autoSetDimension:(ALDimension)dimension toSize:(CGFloat)size relation:(NSLayoutRelation)relation
{
    self.translatesAutoresizingMaskIntoConstraints = NO;
    NSLayoutAttribute attribute = [ALView al_attributeForDimension:dimension];
    NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:self attribute:attribute relatedBy:relation toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:0.0 constant:size];
    [constraint autoInstall];
    return constraint;
}


#pragma mark Set Content Compression Resistance & Hugging

/**
 Sets the priority of content compression resistance for an axis.
 NOTE: This method must only be called from within the block passed into the method +[autoSetPriority:forConstraints:]
 
 @param axis The axis to set the content compression resistance priority for.
 */
- (void)autoSetContentCompressionResistancePriorityForAxis:(ALAxis)axis
{
    NSAssert(_al_isExecutingConstraintsBlock, @"%@ should only be called from within the block passed into the method +[autoSetPriority:forConstraints:]", NSStringFromSelector(_cmd));
    if (_al_isExecutingConstraintsBlock) {
        self.translatesAutoresizingMaskIntoConstraints = NO;
        ALLayoutConstraintAxis constraintAxis = [ALView al_constraintAxisForAxis:axis];
#if TARGET_OS_IPHONE
        [self setContentCompressionResistancePriority:_al_globalConstraintPriority forAxis:constraintAxis];
#else
        [self setContentCompressionResistancePriority:_al_globalConstraintPriority forOrientation:constraintAxis];
#endif /* TARGET_OS_IPHONE */
    }
}

/**
 Sets the priority of content hugging for an axis.
 NOTE: This method must only be called from within the block passed into the method +[autoSetPriority:forConstraints:]
 
 @param axis The axis to set the content hugging priority for.
 */
- (void)autoSetContentHuggingPriorityForAxis:(ALAxis)axis
{
    NSAssert(_al_isExecutingConstraintsBlock, @"%@ should only be called from within the block passed into the method +[autoSetPriority:forConstraints:]", NSStringFromSelector(_cmd));
    if (_al_isExecutingConstraintsBlock) {
        self.translatesAutoresizingMaskIntoConstraints = NO;
        ALLayoutConstraintAxis constraintAxis = [ALView al_constraintAxisForAxis:axis];
#if TARGET_OS_IPHONE
        [self setContentHuggingPriority:_al_globalConstraintPriority forAxis:constraintAxis];
#else
        [self setContentHuggingPriority:_al_globalConstraintPriority forOrientation:constraintAxis];
#endif /* TARGET_OS_IPHONE */
    }
}


#pragma mark Constrain Any Attributes

/**
 Constrains an attribute (any ALEdge, ALAxis, or ALDimension) of the view to a given attribute of another view.
 This method can be used to constrain different types of attributes across two views.
 
 @param ALAttribute Any ALEdge, ALAxis, or ALDimension of this view to constrain.
 @param toALAttribute Any ALEdge, ALAxis, or ALDimension of the peer view to constrain to.
 @param peerView The peer view to constrain to. Must be in the same view hierarchy as this view.
 @return The constraint added.
 */
- (NSLayoutConstraint *)autoConstrainAttribute:(NSInteger)ALAttribute toAttribute:(NSInteger)toALAttribute ofView:(ALView *)peerView
{
    return [self autoConstrainAttribute:ALAttribute toAttribute:toALAttribute ofView:peerView withOffset:0.0];
}

/**
 Constrains an attribute (any ALEdge, ALAxis, or ALDimension) of the view to a given attribute of another view with an offset.
 This method can be used to constrain different types of attributes across two views.
 
 @param ALAttribute Any ALEdge, ALAxis, or ALDimension of this view to constrain.
 @param toALAttribute Any ALEdge, ALAxis, or ALDimension of the peer view to constrain to.
 @param peerView The peer view to constrain to. Must be in the same view hierarchy as this view.
 @param offset The offset between the attribute of this view and the attribute of the peer view.
 @return The constraint added.
 */
- (NSLayoutConstraint *)autoConstrainAttribute:(NSInteger)ALAttribute toAttribute:(NSInteger)toALAttribute ofView:(ALView *)peerView withOffset:(CGFloat)offset
{
    return [self autoConstrainAttribute:ALAttribute toAttribute:toALAttribute ofView:peerView withOffset:offset relation:NSLayoutRelationEqual];
}

/**
 Constrains an attribute (any ALEdge, ALAxis, or ALDimension) of the view to a given attribute of another view with an offset as a maximum or minimum.
 This method can be used to constrain different types of attributes across two views.
 
 @param ALAttribute Any ALEdge, ALAxis, or ALDimension of this view to constrain.
 @param toALAttribute Any ALEdge, ALAxis, or ALDimension of the peer view to constrain to.
 @param peerView The peer view to constrain to. Must be in the same view hierarchy as this view.
 @param offset The offset between the attribute of this view and the attribute of the peer view.
 @param relation Whether the offset should be at least, at most, or exactly equal to the given value.
 @return The constraint added.
 */
- (NSLayoutConstraint *)autoConstrainAttribute:(NSInteger)ALAttribute toAttribute:(NSInteger)toALAttribute ofView:(ALView *)peerView withOffset:(CGFloat)offset relation:(NSLayoutRelation)relation
{
    self.translatesAutoresizingMaskIntoConstraints = NO;
    NSLayoutAttribute attribute = [ALView al_attributeForALAttribute:ALAttribute];
    NSLayoutAttribute toAttribute = [ALView al_attributeForALAttribute:toALAttribute];
    NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:self attribute:attribute relatedBy:relation toItem:peerView attribute:toAttribute multiplier:1.0 constant:offset];
    [constraint autoInstall];
    return constraint;
}

/**
 Constrains an attribute (any ALEdge, ALAxis, or ALDimension) of the view to a given attribute of another view with a multiplier.
 This method can be used to constrain different types of attributes across two views.
 
 @param ALAttribute Any ALEdge, ALAxis, or ALDimension of this view to constrain.
 @param toALAttribute Any ALEdge, ALAxis, or ALDimension of the peer view to constrain to.
 @param peerView The peer view to constrain to. Must be in the same view hierarchy as this view.
 @param multiplier The multiplier between the attribute of this view and the attribute of the peer view.
 @return The constraint added.
 */
- (NSLayoutConstraint *)autoConstrainAttribute:(NSInteger)ALAttribute toAttribute:(NSInteger)toALAttribute ofView:(ALView *)peerView withMultiplier:(CGFloat)multiplier
{
    return [self autoConstrainAttribute:ALAttribute toAttribute:toALAttribute ofView:peerView withMultiplier:multiplier relation:NSLayoutRelationEqual];
}

/**
 Constrains an attribute (any ALEdge, ALAxis, or ALDimension) of the view to a given attribute of another view with a multiplier as a maximum or minimum.
 This method can be used to constrain different types of attributes across two views.
 
 @param ALAttribute Any ALEdge, ALAxis, or ALDimension of this view to constrain.
 @param toALAttribute Any ALEdge, ALAxis, or ALDimension of the peer view to constrain to.
 @param peerView The peer view to constrain to. Must be in the same view hierarchy as this view.
 @param multiplier The multiplier between the attribute of this view and the attribute of the peer view.
 @param relation Whether the multiplier should be at least, at most, or exactly equal to the given value.
 @return The constraint added.
 */
- (NSLayoutConstraint *)autoConstrainAttribute:(NSInteger)ALAttribute toAttribute:(NSInteger)toALAttribute ofView:(ALView *)peerView withMultiplier:(CGFloat)multiplier relation:(NSLayoutRelation)relation
{
    self.translatesAutoresizingMaskIntoConstraints = NO;
    NSLayoutAttribute attribute = [ALView al_attributeForALAttribute:ALAttribute];
    NSLayoutAttribute toAttribute = [ALView al_attributeForALAttribute:toALAttribute];
    NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:self attribute:attribute relatedBy:relation toItem:peerView attribute:toAttribute multiplier:multiplier constant:0.0];
    [constraint autoInstall];
    return constraint;
}


#pragma mark Pin to Layout Guides

#if TARGET_OS_IPHONE

/**
 Pins the top edge of the view to the top layout guide of the given view controller with an inset.
 For compatibility with iOS 6 (where layout guides do not exist), this method will simply pin the top edge of
 the view to the top edge of the given view controller's view with an inset.
 
 @param viewController The view controller whose topLayoutGuide should be used to pin to.
 @param inset The amount to inset this view's top edge from the layout guide.
 @return The constraint added.
 */
- (NSLayoutConstraint *)autoPinToTopLayoutGuideOfViewController:(UIViewController *)viewController withInset:(CGFloat)inset
{
    if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_6_1) {
        return [self autoPinEdge:ALEdgeTop toEdge:ALEdgeTop ofView:viewController.view withOffset:inset];
    } else {
        self.translatesAutoresizingMaskIntoConstraints = NO;
        NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:viewController.topLayoutGuide attribute:NSLayoutAttributeBottom multiplier:1.0 constant:inset];
        [viewController.view al_addConstraintUsingGlobalPriority:constraint];
        return constraint;
    }
}

/**
 Pins the bottom edge of the view to the bottom layout guide of the given view controller with an inset.
 For compatibility with iOS 6 (where layout guides do not exist), this method will simply pin the bottom edge of
 the view to the bottom edge of the given view controller's view with an inset.
 
 @param viewController The view controller whose bottomLayoutGuide should be used to pin to.
 @param inset The amount to inset this view's bottom edge from the layout guide.
 @return The constraint added.
 */
- (NSLayoutConstraint *)autoPinToBottomLayoutGuideOfViewController:(UIViewController *)viewController withInset:(CGFloat)inset
{
    if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_6_1) {
        return [self autoPinEdge:ALEdgeBottom toEdge:ALEdgeBottom ofView:viewController.view withOffset:-inset];
    } else {
        self.translatesAutoresizingMaskIntoConstraints = NO;
        NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:viewController.bottomLayoutGuide attribute:NSLayoutAttributeTop multiplier:1.0 constant:-inset];
        [viewController.view al_addConstraintUsingGlobalPriority:constraint];
        return constraint;
    }
}

#endif /* TARGET_OS_IPHONE */


#pragma mark Internal Helper Methods

/**
 Adds the given constraint to this view after setting the constraint's priority to the global constraint priority.
 
 This method is the only one that calls the SDK addConstraint: method directly; all other instances in this category
 should use this method to add constraints so that the global priority is correctly set on constraints.
 
 @param constraint The constraint to set the global priority on and then add to this view.
 */
- (void)al_addConstraintUsingGlobalPriority:(NSLayoutConstraint *)constraint
{
    constraint.priority = _al_globalConstraintPriority;
    [self addConstraint:constraint];
}

/**
 Returns the corresponding NSLayoutAttribute for the given ALEdge.
 
 @return The layout attribute for the given edge.
 */
+ (NSLayoutAttribute)al_attributeForEdge:(ALEdge)edge
{
    NSLayoutAttribute attribute = NSLayoutAttributeNotAnAttribute;
    switch (edge) {
        case ALEdgeLeft:
            attribute = NSLayoutAttributeLeft;
            break;
        case ALEdgeRight:
            attribute = NSLayoutAttributeRight;
            break;
        case ALEdgeTop:
            attribute = NSLayoutAttributeTop;
            break;
        case ALEdgeBottom:
            attribute = NSLayoutAttributeBottom;
            break;
        case ALEdgeLeading:
            attribute = NSLayoutAttributeLeading;
            break;
        case ALEdgeTrailing:
            attribute = NSLayoutAttributeTrailing;
            break;
        default:
            NSAssert(nil, @"Not a valid ALEdge.");
            break;
    }
    return attribute;
}

/**
 Returns the corresponding NSLayoutAttribute for the given ALAxis.
 
 @return The layout attribute for the given axis.
 */
+ (NSLayoutAttribute)al_attributeForAxis:(ALAxis)axis
{
    NSLayoutAttribute attribute = NSLayoutAttributeNotAnAttribute;
    switch (axis) {
        case ALAxisVertical:
            attribute = NSLayoutAttributeCenterX;
            break;
        case ALAxisHorizontal:
            attribute = NSLayoutAttributeCenterY;
            break;
        case ALAxisBaseline:
            attribute = NSLayoutAttributeBaseline;
            break;
        default:
            NSAssert(nil, @"Not a valid ALAxis.");
            break;
    }
    return attribute;
}

/**
 Returns the corresponding NSLayoutAttribute for the given ALDimension.
 
 @return The layout attribute for the given dimension.
 */
+ (NSLayoutAttribute)al_attributeForDimension:(ALDimension)dimension
{
    NSLayoutAttribute attribute = NSLayoutAttributeNotAnAttribute;
    switch (dimension) {
        case ALDimensionWidth:
            attribute = NSLayoutAttributeWidth;
            break;
        case ALDimensionHeight:
            attribute = NSLayoutAttributeHeight;
            break;
        default:
            NSAssert(nil, @"Not a valid ALDimension.");
            break;
    }
    return attribute;
}

/**
 Returns the corresponding NSLayoutAttribute for the given ALAttribute.
 
 @return The layout attribute for the given ALAttribute.
 */
+ (NSLayoutAttribute)al_attributeForALAttribute:(NSInteger)ALAttribute
{
    NSLayoutAttribute attribute = NSLayoutAttributeNotAnAttribute;
    switch (ALAttribute) {
        case ALEdgeLeft:
            attribute = NSLayoutAttributeLeft;
            break;
        case ALEdgeRight:
            attribute = NSLayoutAttributeRight;
            break;
        case ALEdgeTop:
            attribute = NSLayoutAttributeTop;
            break;
        case ALEdgeBottom:
            attribute = NSLayoutAttributeBottom;
            break;
        case ALEdgeLeading:
            attribute = NSLayoutAttributeLeading;
            break;
        case ALEdgeTrailing:
            attribute = NSLayoutAttributeTrailing;
            break;
        case ALDimensionWidth:
            attribute = NSLayoutAttributeWidth;
            break;
        case ALDimensionHeight:
            attribute = NSLayoutAttributeHeight;
            break;
        case ALAxisVertical:
            attribute = NSLayoutAttributeCenterX;
            break;
        case ALAxisHorizontal:
            attribute = NSLayoutAttributeCenterY;
            break;
        case ALAxisBaseline:
            attribute = NSLayoutAttributeBaseline;
            break;
        default:
            NSAssert(nil, @"Not a valid ALAttribute.");
            break;
    }
    return attribute;
}

/**
 Returns the corresponding ALLayoutConstraintAxis for the given ALAxis.
 
 @return The constraint axis for the given axis.
 */
+ (ALLayoutConstraintAxis)al_constraintAxisForAxis:(ALAxis)axis
{
    ALLayoutConstraintAxis constraintAxis;
    switch (axis) {
        case ALAxisVertical:
            constraintAxis = ALLayoutConstraintAxisVertical;
            break;
        case ALAxisHorizontal:
        case ALAxisBaseline:
            constraintAxis = ALLayoutConstraintAxisHorizontal;
            break;
        default:
            NSAssert(nil, @"Not a valid ALAxis.");
            break;
    }
    return constraintAxis;
}

/**
 Returns the common superview for this view and the given peer view.
 Raises an exception if this view and the peer view do not share a common superview.
 
 @return The common superview for the two views.
 */
- (ALView *)al_commonSuperviewWithView:(ALView *)peerView
{
    ALView *commonSuperview = nil;
    ALView *startView = self;
    do {
#if TARGET_OS_IPHONE
        if ([peerView isDescendantOfView:startView]) {
            commonSuperview = startView;
        }
#else
        if ([peerView isDescendantOf:startView]) {
            commonSuperview = startView;
        }
#endif /* TARGET_OS_IPHONE */
        startView = startView.superview;
    } while (startView && !commonSuperview);
    NSAssert(commonSuperview, @"Can't constrain two views that do not share a common superview. Make sure that both views have been added into the same view hierarchy.");
    return commonSuperview;
}

/**
 Aligns this view to a peer view with an alignment option.
 
 @param peerView The peer view to align to.
 @param alignment The alignment option to apply to the two views.
 @param axis The axis along which the views are distributed, used to validate the alignment option.
 @return The constraint added.
 */
- (NSLayoutConstraint *)al_alignToView:(ALView *)peerView withOption:(NSLayoutFormatOptions)alignment forAxis:(ALAxis)axis
{
    NSLayoutConstraint *constraint = nil;
    switch (alignment) {
        case NSLayoutFormatAlignAllCenterX:
            NSAssert(axis == ALAxisVertical, @"Cannot align views that are distributed horizontally with NSLayoutFormatAlignAllCenterX.");
            constraint = [self autoAlignAxis:ALAxisVertical toSameAxisOfView:peerView];
            break;
        case NSLayoutFormatAlignAllCenterY:
            NSAssert(axis != ALAxisVertical, @"Cannot align views that are distributed vertically with NSLayoutFormatAlignAllCenterY.");
            constraint = [self autoAlignAxis:ALAxisHorizontal toSameAxisOfView:peerView];
            break;
        case NSLayoutFormatAlignAllBaseline:
            NSAssert(axis != ALAxisVertical, @"Cannot align views that are distributed vertically with NSLayoutFormatAlignAllBaseline.");
            constraint = [self autoAlignAxis:ALAxisBaseline toSameAxisOfView:peerView];
            break;
        case NSLayoutFormatAlignAllTop:
            NSAssert(axis != ALAxisVertical, @"Cannot align views that are distributed vertically with NSLayoutFormatAlignAllTop.");
            constraint = [self autoPinEdge:ALEdgeTop toEdge:ALEdgeTop ofView:peerView];
            break;
        case NSLayoutFormatAlignAllLeft:
            NSAssert(axis == ALAxisVertical, @"Cannot align views that are distributed horizontally with NSLayoutFormatAlignAllLeft.");
            constraint = [self autoPinEdge:ALEdgeLeft toEdge:ALEdgeLeft ofView:peerView];
            break;
        case NSLayoutFormatAlignAllBottom:
            NSAssert(axis != ALAxisVertical, @"Cannot align views that are distributed vertically with NSLayoutFormatAlignAllBottom.");
            constraint = [self autoPinEdge:ALEdgeBottom toEdge:ALEdgeBottom ofView:peerView];
            break;
        case NSLayoutFormatAlignAllRight:
            NSAssert(axis == ALAxisVertical, @"Cannot align views that are distributed horizontally with NSLayoutFormatAlignAllRight.");
            constraint = [self autoPinEdge:ALEdgeRight toEdge:ALEdgeRight ofView:peerView];
            break;
        case NSLayoutFormatAlignAllLeading:
            NSAssert(axis == ALAxisVertical, @"Cannot align views that are distributed horizontally with NSLayoutFormatAlignAllLeading.");
            constraint = [self autoPinEdge:ALEdgeLeading toEdge:ALEdgeLeading ofView:peerView];
            break;
        case NSLayoutFormatAlignAllTrailing:
            NSAssert(axis == ALAxisVertical, @"Cannot align views that are distributed horizontally with NSLayoutFormatAlignAllTrailing.");
            constraint = [self autoPinEdge:ALEdgeTrailing toEdge:ALEdgeTrailing ofView:peerView];
            break;
        default:
            NSAssert(nil, @"Unsupported alignment option.");
            break;
    }
    return constraint;
}

@end


================================================
FILE: JASwipeCellExample/AppDelegate.h
================================================
//
//  AppDelegate.h
//  JASwipeCell
//
//  Created by Jose Alvarez on 10/8/14.
//  Copyright (c) 2014 Jose Alvarez. All rights reserved.
//
//  Permission is hereby granted, free of charge, to any person obtaining a copy
//  of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//  copies of the Software, and to permit persons to whom the Software is
//  furnished to do so, subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be included in all
//  copies or substantial portions of the Software.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//  SOFTWARE.

#import <UIKit/UIKit.h>

@interface AppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;

@end



================================================
FILE: JASwipeCellExample/AppDelegate.m
================================================
//
//  AppDelegate.m
//  JASwipeCell
//
//  Created by Jose Alvarez on 10/8/14.
//  Copyright (c) 2014 Jose Alvarez. All rights reserved.
//
//  Permission is hereby granted, free of charge, to any person obtaining a copy
//  of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//  copies of the Software, and to permit persons to whom the Software is
//  furnished to do so, subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be included in all
//  copies or substantial portions of the Software.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//  SOFTWARE.

#import "AppDelegate.h"

@interface AppDelegate ()

@end

@implementation AppDelegate
            

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    return YES;
}

- (void)applicationWillResignActive:(UIApplication *)application {
    // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
    // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}

- (void)applicationDidEnterBackground:(UIApplication *)application {
    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}

- (void)applicationWillEnterForeground:(UIApplication *)application {
    // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}

- (void)applicationDidBecomeActive:(UIApplication *)application {
    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}

- (void)applicationWillTerminate:(UIApplication *)application {
    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}

@end


================================================
FILE: JASwipeCellExample/Base.lproj/Main.storyboard
================================================
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="6245" systemVersion="13F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="L6L-E1-MgB">
    <dependencies>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6238"/>
    </dependencies>
    <scenes>
        <!--Table View Controller-->
        <scene sceneID="m0n-7e-bhR">
            <objects>
                <tableViewController id="kOi-XZ-VSr" customClass="JATableViewController" sceneMemberID="viewController">
                    <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" id="zeI-9w-UAo">
                        <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
                        <connections>
                            <outlet property="dataSource" destination="kOi-XZ-VSr" id="453-A0-Lng"/>
                            <outlet property="delegate" destination="kOi-XZ-VSr" id="YyE-eS-8PH"/>
                        </connections>
                    </tableView>
                    <navigationItem key="navigationItem" id="XsN-sE-DJa"/>
                </tableViewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="0Cg-P0-HNz" userLabel="First Responder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="669" y="-12"/>
        </scene>
        <!--Navigation Controller-->
        <scene sceneID="tCg-kr-fkV">
            <objects>
                <navigationController id="L6L-E1-MgB" sceneMemberID="viewController">
                    <navigationBar key="navigationBar" contentMode="scaleToFill" id="siJ-eY-gJJ">
                        <rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
                        <autoresizingMask key="autoresizingMask"/>
                    </navigationBar>
                    <connections>
                        <segue destination="kOi-XZ-VSr" kind="relationship" relationship="rootViewController" id="Zwi-SY-0t9"/>
                    </connections>
                </navigationController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="INi-4U-lUY" userLabel="First Responder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="-69" y="31"/>
        </scene>
    </scenes>
</document>


================================================
FILE: JASwipeCellExample/Images.xcassets/AppIcon.appiconset/Contents.json
================================================
{
  "images" : [
    {
      "idiom" : "iphone",
      "size" : "29x29",
      "scale" : "2x"
    },
    {
      "idiom" : "iphone",
      "size" : "40x40",
      "scale" : "2x"
    },
    {
      "idiom" : "iphone",
      "size" : "60x60",
      "scale" : "2x"
    },
    {
      "idiom" : "iphone",
      "size" : "60x60",
      "scale" : "3x"
    },
    {
      "idiom" : "ipad",
      "size" : "29x29",
      "scale" : "1x"
    },
    {
      "idiom" : "ipad",
      "size" : "29x29",
      "scale" : "2x"
    },
    {
      "idiom" : "ipad",
      "size" : "40x40",
      "scale" : "1x"
    },
    {
      "idiom" : "ipad",
      "size" : "40x40",
      "scale" : "2x"
    },
    {
      "idiom" : "ipad",
      "size" : "76x76",
      "scale" : "1x"
    },
    {
      "idiom" : "ipad",
      "size" : "76x76",
      "scale" : "2x"
    }
  ],
  "info" : {
    "version" : 1,
    "author" : "xcode"
  }
}

================================================
FILE: JASwipeCellExample/Images.xcassets/LaunchImage.launchimage/Contents.json
================================================
{
  "images" : [
    {
      "orientation" : "portrait",
      "idiom" : "iphone",
      "extent" : "full-screen",
      "minimum-system-version" : "7.0",
      "scale" : "2x"
    },
    {
      "orientation" : "portrait",
      "idiom" : "iphone",
      "subtype" : "retina4",
      "extent" : "full-screen",
      "minimum-system-version" : "7.0",
      "scale" : "2x"
    },
    {
      "orientation" : "portrait",
      "idiom" : "ipad",
      "extent" : "full-screen",
      "minimum-system-version" : "7.0",
      "scale" : "1x"
    },
    {
      "orientation" : "landscape",
      "idiom" : "ipad",
      "extent" : "full-screen",
      "minimum-system-version" : "7.0",
      "scale" : "1x"
    },
    {
      "orientation" : "portrait",
      "idiom" : "ipad",
      "extent" : "full-screen",
      "minimum-system-version" : "7.0",
      "scale" : "2x"
    },
    {
      "orientation" : "landscape",
      "idiom" : "ipad",
      "extent" : "full-screen",
      "minimum-system-version" : "7.0",
      "scale" : "2x"
    }
  ],
  "info" : {
    "version" : 1,
    "author" : "xcode"
  }
}

================================================
FILE: JASwipeCellExample/Info.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>CFBundleDevelopmentRegion</key>
	<string>en</string>
	<key>CFBundleExecutable</key>
	<string>${EXECUTABLE_NAME}</string>
	<key>CFBundleIdentifier</key>
	<string>com.joseria.${PRODUCT_NAME:rfc1034identifier}</string>
	<key>CFBundleInfoDictionaryVersion</key>
	<string>6.0</string>
	<key>CFBundleName</key>
	<string>${PRODUCT_NAME}</string>
	<key>CFBundlePackageType</key>
	<string>APPL</string>
	<key>CFBundleShortVersionString</key>
	<string>1.0</string>
	<key>CFBundleSignature</key>
	<string>????</string>
	<key>CFBundleVersion</key>
	<string>1</string>
	<key>LSRequiresIPhoneOS</key>
	<true/>
	<key>UIMainStoryboardFile</key>
	<string>Main</string>
	<key>UIRequiredDeviceCapabilities</key>
	<array>
		<string>armv7</string>
	</array>
	<key>UISupportedInterfaceOrientations</key>
	<array>
		<string>UIInterfaceOrientationPortrait</string>
		<string>UIInterfaceOrientationLandscapeLeft</string>
		<string>UIInterfaceOrientationLandscapeRight</string>
	</array>
	<key>UISupportedInterfaceOrientations~ipad</key>
	<array>
		<string>UIInterfaceOrientationPortrait</string>
		<string>UIInterfaceOrientationPortraitUpsideDown</string>
		<string>UIInterfaceOrientationLandscapeLeft</string>
		<string>UIInterfaceOrientationLandscapeRight</string>
	</array>
</dict>
</plist>


================================================
FILE: JASwipeCellExample/JATableViewCell.h
================================================
//
//  JATableViewCell.h
//  JASwipeCell
//
//  Created by Jose Alvarez on 10/8/14.
//  Copyright (c) 2014 Jose Alvarez. All rights reserved.
//
//  Permission is hereby granted, free of charge, to any person obtaining a copy
//  of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//  copies of the Software, and to permit persons to whom the Software is
//  furnished to do so, subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be included in all
//  copies or substantial portions of the Software.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//  SOFTWARE.


#import <UIKit/UIKit.h>
#import "JASwipeCell.h"

@interface JATableViewCell : JASwipeCell
- (void)configureCellWithTitle:(NSString *)title;
@end


================================================
FILE: JASwipeCellExample/JATableViewCell.m
================================================
//
//  JATableViewCell.m
//  JASwipeCell
//
//  Created by Jose Alvarez on 10/8/14.
//  Copyright (c) 2014 Jose Alvarez. All rights reserved.
//
//  Permission is hereby granted, free of charge, to any person obtaining a copy
//  of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//  copies of the Software, and to permit persons to whom the Software is
//  furnished to do so, subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be included in all
//  copies or substantial portions of the Software.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//  SOFTWARE.


#import "JATableViewCell.h"
#import "PureLayout.h"

@interface JATableViewCell ()
@property (nonatomic, strong) UILabel *titleLabel;
@property (nonatomic) BOOL constraintsSetup;
@end
@implementation JATableViewCell

- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        [self.topContentView addSubview:self.titleLabel];
    }
    return self;
}

- (UILabel *)titleLabel
{
    if (!_titleLabel) {
        _titleLabel = [UILabel newAutoLayoutView];
        _titleLabel.numberOfLines = 0;
        _titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
    }
    return _titleLabel;
}

- (void)updateConstraints
{
    [super updateConstraints];
    
    if (!self.constraintsSetup) {
        [self.titleLabel autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:10];
        [self.titleLabel autoPinEdgeToSuperviewEdge:ALEdgeLeading withInset:10];
        [self.titleLabel autoMatchDimension:ALDimensionWidth toDimension:ALDimensionWidth ofView:self.topContentView withMultiplier:0.9];
        
        self.constraintsSetup = YES;
    }
}

- (void)configureCellWithTitle:(NSString *)title
{
    self.titleLabel.text = title;
}

@end


================================================
FILE: JASwipeCellExample/JATableViewController.h
================================================
//
//  JATableViewController.h
//  JASwipeCell
//
//  Created by Jose Alvarez on 10/8/14.
//  Copyright (c) 2014 Jose Alvarez. All rights reserved.
//
//  Permission is hereby granted, free of charge, to any person obtaining a copy
//  of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//  copies of the Software, and to permit persons to whom the Software is
//  furnished to do so, subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be included in all
//  copies or substantial portions of the Software.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//  SOFTWARE.

#import <UIKit/UIKit.h>

@interface JATableViewController : UITableViewController

@end


================================================
FILE: JASwipeCellExample/JATableViewController.m
================================================
//
//  JATableViewController.m
//  JASwipeCell
//
//  Created by Jose Alvarez on 10/8/14.
//  Copyright (c) 2014 Jose Alvarez. All rights reserved.
//
//  Permission is hereby granted, free of charge, to any person obtaining a copy
//  of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//  copies of the Software, and to permit persons to whom the Software is
//  furnished to do so, subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be included in all
//  copies or substantial portions of the Software.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//  SOFTWARE.

#import "JATableViewController.h"
#import "JATableViewCell.h"
#import "JAActionButton.h"

#define kJATableViewCellReuseIdentifier     @"JATableViewCellIdentifier"

#define kFlagButtonColor        [UIColor colorWithRed:255.0/255.0 green:150.0/255.0 blue:0/255.0 alpha:1]
#define kMoreButtonColor        [UIColor colorWithRed:200.0/255.0 green:200.0/255.0 blue:200.0/255.0 alpha:1]
#define kArchiveButtonColor     [UIColor colorWithRed:60.0/255.0 green:112.0/255.0 blue:168/255.0 alpha:1]
#define kUnreadButtonColor      [UIColor colorWithRed:0/255.0 green:122.0/255.0 blue:255.0/255.0 alpha:1]

@interface JATableViewController ()<JASwipeCellDelegate>
@property (nonatomic, strong) NSMutableArray *tableData;
@end

@implementation JATableViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    self.title = @"JASwipeCell Example";
    
    [self resetData];
    
    [self.tableView registerClass:[JATableViewCell class] forCellReuseIdentifier:kJATableViewCellReuseIdentifier];
    
    UIBarButtonItem *resetButton = [[UIBarButtonItem alloc] initWithTitle:@"Reset" style:UIBarButtonItemStylePlain target:self action:@selector(resetData)];
    self.navigationItem.rightBarButtonItem = resetButton;
}

- (void)resetData
{
    self.tableData = [[NSMutableArray alloc] initWithCapacity:10];
    [self.tableData addObjectsFromArray:@[@"Swipe left all the way",
                                          @"Swipe right all they way",
                                          @"Swipe left - click More button",
                                          @"Swipe left - click Flag button",
                                          /* TODO: solve for accessory types.
                                          @"Swipe left - click Flag button",
                                          @"Swipe left - click Flag button",
                                          @"Swipe left - click Flag button",
                                           */
                                          @"Swipe left - click Archive button",
                                          @"Swipe right - click Mark as unread button",
                                          @"Swipe right - click Delete button"]];
    
    [self.tableView reloadData];
}

- (NSArray *)leftButtons
{
    __typeof(self) __weak weakSelf = self;
    JAActionButton *button1 = [JAActionButton actionButtonWithTitle:@"Delete" color:[UIColor redColor] handler:^(UIButton *actionButton, JASwipeCell*cell) {
        [cell completePinToTopViewAnimation];
        [weakSelf leftMostButtonSwipeCompleted:cell];
        NSLog(@"Left Button: Delete Pressed");
    }];
    
    JAActionButton *button2 = [JAActionButton actionButtonWithTitle:@"Mark as unread" color:kUnreadButtonColor handler:^(UIButton *actionButton, JASwipeCell*cell) {
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Mark As Unread" message:@"Done!" delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles:nil];
        [alert show];
        NSLog(@"Left Button: Mark as unread Pressed");
    }];
    
    return @[button1, button2];
}

- (NSArray *)rightButtons
{
    __typeof(self) __weak weakSelf = self;
    JAActionButton *button1 = [JAActionButton actionButtonWithTitle:@"Archive" color:kArchiveButtonColor handler:^(UIButton *actionButton, JASwipeCell*cell) {
        [cell completePinToTopViewAnimation];
        [weakSelf rightMostButtonSwipeCompleted:cell];
        NSLog(@"Right Button: Archive Pressed");
    }];
    
    JAActionButton *button2 = [JAActionButton actionButtonWithTitle:@"Flag" color:kFlagButtonColor handler:^(UIButton *actionButton, JASwipeCell*cell) {
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Flag" message:@"Flag pressed!" delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles:nil];
        [alert show];
        NSLog(@"Right Button: Flag Pressed");
    }];
    JAActionButton *button3 = [JAActionButton actionButtonWithTitle:@"More" color:kMoreButtonColor handler:^(UIButton *actionButton, JASwipeCell*cell) {
        UIActionSheet *sheet = [[UIActionSheet alloc] initWithTitle:@"More Options" delegate:nil cancelButtonTitle:@"Cancel" destructiveButtonTitle:@"Option 1" otherButtonTitles:@"Option 2",nil];
        [sheet showInView:weakSelf.view];
        NSLog(@"Right Button: More Pressed");
    }];
    
    return @[button1, button2, button3];
}

#pragma mark - Table view data source

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return self.tableData.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    JATableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kJATableViewCellReuseIdentifier];
    
    [cell addActionButtons:[self leftButtons] withButtonWidth:kJAButtonWidth withButtonPosition:JAButtonLocationLeft];
    [cell addActionButtons:[self rightButtons] withButtonWidth:kJAButtonWidth withButtonPosition:JAButtonLocationRight];
    
    cell.delegate = self;
    
    [cell configureCellWithTitle:self.tableData[indexPath.row]];
    [cell setNeedsLayout];
    [cell setNeedsUpdateConstraints];
    [cell updateConstraintsIfNeeded];

    /* TODO: solve for accessory types.
    switch ( indexPath.row % 5 ) {
	case 0:
	default:
		cell.accessoryType = UITableViewCellAccessoryNone;
		break;
	case 1:
		cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
		break;
	case 2:
		cell.accessoryType = UITableViewCellAccessoryCheckmark;
		break;
	case 3:
		cell.accessoryType = UITableViewCellAccessoryDetailButton;
		break;
	case 4:
		cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
		break;
    }*/

    return cell;
}

#pragma mark - UITableViewDelegate methods

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return 70;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
}

#pragma mark - JASwipeCellDelegate methods

- (void)swipingRightForCell:(JASwipeCell *)cell
{
    NSArray *indexPaths = [self.tableView indexPathsForVisibleRows];
    for (NSIndexPath *indexPath in indexPaths) {
        JASwipeCell *visibleCell = (JASwipeCell *)[self.tableView cellForRowAtIndexPath:indexPath];
        if (visibleCell != cell) {
            [visibleCell resetContainerView];
        }
        
    }
}

- (void)swipingLeftForCell:(JASwipeCell *)cell
{
    NSArray *indexPaths = [self.tableView indexPathsForVisibleRows];
    for (NSIndexPath *indexPath in indexPaths) {
        JASwipeCell *visibleCell = (JASwipeCell *)[self.tableView cellForRowAtIndexPath:indexPath];
        if (visibleCell != cell) {
            [visibleCell resetContainerView];
        }
        
    }
}

- (void)leftMostButtonSwipeCompleted:(JASwipeCell *)cell
{
    NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
    [self.tableData removeObjectAtIndex:indexPath.row];
    
    [self.tableView beginUpdates];
    [self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
    [self.tableView endUpdates];
}

- (void)rightMostButtonSwipeCompleted:(JASwipeCell *)cell
{
    NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
    [self.tableData removeObjectAtIndex:indexPath.row];
    
    [self.tableView beginUpdates];
    [self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
    [self.tableView endUpdates];
}

#pragma mark - UIScrollViewDelegate methods

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    NSArray *indexPaths = [self.tableView indexPathsForVisibleRows];
    for (NSIndexPath *indexPath in indexPaths) {
        JASwipeCell *cell = (JASwipeCell *)[self.tableView cellForRowAtIndexPath:indexPath];
        [cell resetContainerView];
    }
}
@end


================================================
FILE: JASwipeCellExample/NSArray+PureLayout.h
================================================
//
//  NSArray+PureLayout.h
//  v1.1.0
//  https://github.com/smileyborg/PureLayout
//
//  Copyright (c) 2012 Richard Turton
//  Copyright (c) 2013-2014 Tyler Fox
//
//  This code is distributed under the terms and conditions of the MIT license.
//
//  Permission is hereby granted, free of charge, to any person obtaining a copy
//  of this software and associated documentation files (the "Software"), to
//  deal in the Software without restriction, including without limitation the
//  rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
//  sell copies of the Software, and to permit persons to whom the Software is
//  furnished to do so, subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be included in
//  all copies or substantial portions of the Software.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
//  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
//  IN THE SOFTWARE.
//

#import "PureLayoutDefines.h"


#pragma mark - NSArray+PureLayout

/**
 A category on NSArray that provides a simple yet powerful interface for applying constraints to groups of views.
 */
@interface NSArray (PureLayout)


#pragma mark Constrain Multiple Views

/** Aligns views in this array to one another along a given edge. */
- (NSArray *)autoAlignViewsToEdge:(ALEdge)edge;

/** Aligns views in this array to one another along a given axis. */
- (NSArray *)autoAlignViewsToAxis:(ALAxis)axis;

/** Matches a given dimension of all the views in this array. */
- (NSArray *)autoMatchViewsDimension:(ALDimension)dimension;

/** Sets the given dimension of all the views in this array to a given size. */
- (NSArray *)autoSetViewsDimension:(ALDimension)dimension toSize:(CGFloat)size;


#pragma mark Distribute Multiple Views

/** Distributes the views in this array equally along the selected axis in their superview. Views will be the same size (variable) in the dimension along the axis and will have spacing (fixed) between them. */
- (NSArray *)autoDistributeViewsAlongAxis:(ALAxis)axis withFixedSpacing:(CGFloat)spacing alignment:(NSLayoutFormatOptions)alignment;

/** Distributes the views in this array equally along the selected axis in their superview. Views will be the same size (variable) in the dimension along the axis and will have spacing (fixed) between them, with optional insets from the first and last views to their superview. */
- (NSArray *)autoDistributeViewsAlongAxis:(ALAxis)axis withFixedSpacing:(CGFloat)spacing insetSpacing:(BOOL)shouldSpaceInsets alignment:(NSLayoutFormatOptions)alignment;

/** Distributes the views in this array equally along the selected axis in their superview. Views will have spacing (fixed) between them, with optional insets from the first and last views to their superview, and optionally constrained to the same size in the dimension along the axis. */
- (NSArray *)autoDistributeViewsAlongAxis:(ALAxis)axis withFixedSpacing:(CGFloat)spacing insetSpacing:(BOOL)shouldSpaceInsets matchedSizes:(BOOL)shouldMatchSizes alignment:(NSLayoutFormatOptions)alignment;

/** Distributes the views in this array equally along the selected axis in their superview. Views will be the same size (fixed) in the dimension along the axis and will have spacing (variable) between them. */
- (NSArray *)autoDistributeViewsAlongAxis:(ALAxis)axis withFixedSize:(CGFloat)size alignment:(NSLayoutFormatOptions)alignment;

/** Distributes the views in this array equally along the selected axis in their superview. Views will be the same size (fixed) in the dimension along the axis and will have spacing (variable) between them, with optional insets from the first and last views to their superview. */
- (NSArray *)autoDistributeViewsAlongAxis:(ALAxis)axis withFixedSize:(CGFloat)size insetSpacing:(BOOL)shouldSpaceInsets alignment:(NSLayoutFormatOptions)alignment;

@end


================================================
FILE: JASwipeCellExample/NSArray+PureLayout.m
================================================
//
//  NSArray+PureLayout.m
//  v1.1.0
//  https://github.com/smileyborg/PureLayout
//
//  Copyright (c) 2012 Richard Turton
//  Copyright (c) 2013-2014 Tyler Fox
//
//  This code is distributed under the terms and conditions of the MIT license.
//
//  Permission is hereby granted, free of charge, to any person obtaining a copy
//  of this software and associated documentation files (the "Software"), to
//  deal in the Software without restriction, including without limitation the
//  rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
//  sell copies of the Software, and to permit persons to whom the Software is
//  furnished to do so, subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be included in
//  all copies or substantial portions of the Software.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
//  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
//  IN THE SOFTWARE.
//

#import "NSArray+PureLayout.h"
#import "ALView+PureLayout.h"
#import "NSLayoutConstraint+PureLayout.h"
#import "PureLayout+Internal.h"


#pragma mark - NSArray+PureLayout

@implementation NSArray (PureLayout)


#pragma mark Constrain Multiple Views

/**
 Aligns views in this array to one another along a given edge.
 Note: This array must contain at least 2 views, and all views must share a common superview.
 
 @param edge The edge to which the subviews will be aligned.
 @return An array of constraints added.
 */
- (NSArray *)autoAlignViewsToEdge:(ALEdge)edge
{
    NSAssert([self al_containsMinimumNumberOfViews:2], @"This array must contain at least 2 views.");
    NSMutableArray *constraints = [NSMutableArray new];
    ALView *previousView = nil;
    for (id object in self) {
        if ([object isKindOfClass:[ALView class]]) {
            ALView *view = (ALView *)object;
            view.translatesAutoresizingMaskIntoConstraints = NO;
            if (previousView) {
                [constraints addObject:[view autoPinEdge:edge toEdge:edge ofView:previousView]];
            }
            previousView = view;
        }
    }
    return constraints;
}

/**
 Aligns views in this array to one another along a given axis.
 Note: This array must contain at least 2 views, and all views must share a common superview.
 
 @param axis The axis to which to subviews will be aligned.
 @return An array of constraints added.
 */
- (NSArray *)autoAlignViewsToAxis:(ALAxis)axis
{
    NSAssert([self al_containsMinimumNumberOfViews:2], @"This array must contain at least 2 views.");
    NSMutableArray *constraints = [NSMutableArray new];
    ALView *previousView = nil;
    for (id object in self) {
        if ([object isKindOfClass:[ALView class]]) {
            ALView *view = (ALView *)object;
            view.translatesAutoresizingMaskIntoConstraints = NO;
            if (previousView) {
                [constraints addObject:[view autoAlignAxis:axis toSameAxisOfView:previousView]];
            }
            previousView = view;
        }
    }
    return constraints;
}

/**
 Matches a given dimension of all the views in this array.
 Note: This array must contain at least 2 views, and all views must share a common superview.
 
 @param dimension The dimension to match for all of the subviews.
 @return An array of constraints added.
 */
- (NSArray *)autoMatchViewsDimension:(ALDimension)dimension
{
    NSAssert([self al_containsMinimumNumberOfViews:2], @"This array must contain at least 2 views.");
    NSMutableArray *constraints = [NSMutableArray new];
    ALView *previousView = nil;
    for (id object in self) {
        if ([object isKindOfClass:[ALView class]]) {
            ALView *view = (ALView *)object;
            view.translatesAutoresizingMaskIntoConstraints = NO;
            if (previousView) {
                [constraints addObject:[view autoMatchDimension:dimension toDimension:dimension ofView:previousView]];
            }
            previousView = view;
        }
    }
    return constraints;
}

/**
 Sets the given dimension of all the views in this array to a given size.
 Note: This array must contain at least 1 view.
 
 @param dimension The dimension of each of the subviews to set.
 @param size The size to set the given dimension of each subview to.
 @return An array of constraints added.
 */
- (NSArray *)autoSetViewsDimension:(ALDimension)dimension toSize:(CGFloat)size
{
    NSAssert([self al_containsMinimumNumberOfViews:1], @"This array must contain at least 1 view.");
    NSMutableArray *constraints = [NSMutableArray new];
    for (id object in self) {
        if ([object isKindOfClass:[ALView class]]) {
            ALView *view = (ALView *)object;
            view.translatesAutoresizingMaskIntoConstraints = NO;
            [constraints addObject:[view autoSetDimension:dimension toSize:size]];
        }
    }
    return constraints;
}


#pragma mark Distribute Multiple Views

/**
 Distributes the views in this array equally along the selected axis in their superview.
 Views will be the same size (variable) in the dimension along the axis and will have spacing (fixed) between them,
 including from the first and last views to their superview.
 
 @param axis The axis along which to distribute the subviews.
 @param spacing The fixed amount of spacing between each subview, before the first subview and after the last subview.
 @param alignment The way in which the subviews will be aligned.
 @return An array of constraints added.
 */
- (NSArray *)autoDistributeViewsAlongAxis:(ALAxis)axis withFixedSpacing:(CGFloat)spacing alignment:(NSLayoutFormatOptions)alignment
{
    return [self autoDistributeViewsAlongAxis:axis withFixedSpacing:spacing insetSpacing:YES alignment:alignment];
}

/**
 Distributes the views in this array equally along the selected axis in their superview.
 Views will be the same size (variable) in the dimension along the axis and will have spacing (fixed) between them.
 The first and last views can optionally be inset from their superview by the same amount of spacing as between views.
 
 @param axis The axis along which to distribute the subviews.
 @param spacing The fixed amount of spacing between each subview.
 @param shouldSpaceInsets Whether the first and last views should be equally inset from their superview.
 @param alignment The way in which the subviews will be aligned.
 @return An array of constraints added.
 */
- (NSArray *)autoDistributeViewsAlongAxis:(ALAxis)axis withFixedSpacing:(CGFloat)spacing insetSpacing:(BOOL)shouldSpaceInsets alignment:(NSLayoutFormatOptions)alignment
{
    return [self autoDistributeViewsAlongAxis:axis withFixedSpacing:spacing insetSpacing:shouldSpaceInsets matchedSizes:YES alignment:alignment];
}

/**
 Distributes the views in this array equally along the selected axis in their superview.
 Views will have fixed spacing between them, and can optionally be constrained to the same size in the dimension along the axis.
 The first and last views can optionally be inset from their superview by the same amount of spacing as between views.
 
 @param axis The axis along which to distribute the subviews.
 @param spacing The fixed amount of spacing between each subview.
 @param shouldSpaceInsets Whether the first and last views should be equally inset from their superview.
 @param shouldMatchSizes Whether all views will be constrained to be the same size in the dimension along the axis.
                         NOTE: All views must specify an intrinsic content size if passing NO, otherwise the layout will be ambiguous!
 @param alignment The way in which the subviews will be aligned.
 @return An array of constraints added.
 */
- (NSArray *)autoDistributeViewsAlongAxis:(ALAxis)axis withFixedSpacing:(CGFloat)spacing insetSpacing:(BOOL)shouldSpaceInsets matchedSizes:(BOOL)shouldMatchSizes alignment:(NSLayoutFormatOptions)alignment
{
    NSAssert([self al_containsMinimumNumberOfViews:2], @"This array must contain at least 2 views to distribute.");
    ALDimension matchedDimension;
    ALEdge firstEdge, lastEdge;
    switch (axis) {
        case ALAxisHorizontal:
        case ALAxisBaseline:
            matchedDimension = ALDimensionWidth;
            firstEdge = ALEdgeLeading;
            lastEdge = ALEdgeTrailing;
            break;
        case ALAxisVertical:
            matchedDimension = ALDimensionHeight;
            firstEdge = ALEdgeTop;
            lastEdge = ALEdgeBottom;
            break;
        default:
            NSAssert(nil, @"Not a valid ALAxis.");
            return nil;
    }
    CGFloat leadingSpacing = shouldSpaceInsets ? spacing : 0.0;
    CGFloat trailingSpacing = shouldSpaceInsets ? spacing : 0.0;
    
    NSMutableArray *constraints = [NSMutableArray new];
    ALView *previousView = nil;
    for (id object in self) {
        if ([object isKindOfClass:[ALView class]]) {
            ALView *view = (ALView *)object;
            view.translatesAutoresizingMaskIntoConstraints = NO;
            if (previousView) {
                // Second, Third, ... View
                [constraints addObject:[view autoPinEdge:firstEdge toEdge:lastEdge ofView:previousView withOffset:spacing]];
                if (shouldMatchSizes) {
                    [constraints addObject:[view autoMatchDimension:matchedDimension toDimension:matchedDimension ofView:previousView]];
                }
                [constraints addObject:[view al_alignToView:previousView withOption:alignment forAxis:axis]];
            }
            else {
                // First view
                [constraints addObject:[view autoPinEdgeToSuperviewEdge:firstEdge withInset:leadingSpacing]];
            }
            previousView = view;
        }
    }
    if (previousView) {
        // Last View
        [constraints addObject:[previousView autoPinEdgeToSuperviewEdge:lastEdge withInset:trailingSpacing]];
    }
    return constraints;
}

/**
 Distributes the views in this array equally along the selected axis in their superview.
 Views will be the same size (fixed) in the dimension along the axis and will have spacing (variable) between them,
 including from the first and last views to their superview.
 
 @param axis The axis along which to distribute the subviews.
 @param size The fixed size of each subview in the dimension along the given axis.
 @param alignment The way in which the subviews will be aligned.
 @return An array of constraints added.
 */
- (NSArray *)autoDistributeViewsAlongAxis:(ALAxis)axis withFixedSize:(CGFloat)size alignment:(NSLayoutFormatOptions)alignment
{
    return [self autoDistributeViewsAlongAxis:axis withFixedSize:size insetSpacing:YES alignment:alignment];
}

/**
 Distributes the views in this array equally along the selected axis in their superview.
 Views will be the same size (fixed) in the dimension along the axis and will have spacing (variable) between them.
 The first and last views can optionally be inset from their superview by the same amount of spacing as between views.
 
 @param axis The axis along which to distribute the subviews.
 @param size The fixed size of each subview in the dimension along the given axis.
 @param shouldSpaceInsets Whether the first and last views should be equally inset from their superview.
 @param alignment The way in which the subviews will be aligned.
 @return An array of constraints added.
 */
- (NSArray *)autoDistributeViewsAlongAxis:(ALAxis)axis withFixedSize:(CGFloat)size insetSpacing:(BOOL)shouldSpaceInsets alignment:(NSLayoutFormatOptions)alignment
{
    NSAssert([self al_containsMinimumNumberOfViews:2], @"This array must contain at least 2 views to distribute.");
    ALDimension fixedDimension;
    NSLayoutAttribute attribute;
    switch (axis) {
        case ALAxisHorizontal:
        case ALAxisBaseline:
            fixedDimension = ALDimensionWidth;
            attribute = NSLayoutAttributeCenterX;
            break;
        case ALAxisVertical:
            fixedDimension = ALDimensionHeight;
            attribute = NSLayoutAttributeCenterY;
            break;
        default:
            NSAssert(nil, @"Not a valid ALAxis.");
            return nil;
    }
    BOOL isRightToLeftLanguage = [NSLocale characterDirectionForLanguage:[[NSBundle mainBundle] preferredLocalizations][0]] == NSLocaleLanguageDirectionRightToLeft;
    BOOL shouldFlipOrder = isRightToLeftLanguage && (axis != ALAxisVertical); // imitate the effect of leading/trailing when distributing horizontally
    
    NSMutableArray *constraints = [NSMutableArray new];
    NSArray *views = [self al_copyViewsOnly];
    NSUInteger numberOfViews = [views count];
    ALView *commonSuperview = [views al_commonSuperviewOfViews];
    ALView *previousView = nil;
    for (NSUInteger i = 0; i < numberOfViews; i++) {
        ALView *view = shouldFlipOrder ? views[numberOfViews - i - 1] : views[i];
        view.translatesAutoresizingMaskIntoConstraints = NO;
        [constraints addObject:[view autoSetDimension:fixedDimension toSize:size]];
        CGFloat multiplier, constant;
        if (shouldSpaceInsets) {
            multiplier = (i * 2.0 + 2.0) / (numberOfViews + 1.0);
            constant = (multiplier - 1.0) * size / 2.0;
        } else {
            multiplier = (i * 2.0) / (numberOfViews - 1.0);
            constant = (-multiplier + 1.0) * size / 2.0;
        }
        NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:view attribute:attribute relatedBy:NSLayoutRelationEqual toItem:commonSuperview attribute:attribute multiplier:multiplier constant:constant];
        [commonSuperview al_addConstraintUsingGlobalPriority:constraint];
        [constraints addObject:constraint];
        if (previousView) {
            [constraints addObject:[view al_alignToView:previousView withOption:alignment forAxis:axis]];
        }
        previousView = view;
    }
    return constraints;
}

#pragma mark Internal Helper Methods

/**
 Returns the common superview for the views in this array.
 Raises an exception if the views in this array do not share a common superview.
 
 @return The common superview for the views in this array.
 */
- (ALView *)al_commonSuperviewOfViews
{
    ALView *commonSuperview = nil;
    ALView *previousView = nil;
    for (id object in self) {
        if ([object isKindOfClass:[ALView class]]) {
            ALView *view = (ALView *)object;
            if (previousView) {
                commonSuperview = [view al_commonSuperviewWithView:commonSuperview];
            } else {
                commonSuperview = view;
            }
            previousView = view;
        }
    }
    NSAssert(commonSuperview, @"Can't constrain views that do not share a common superview. Make sure that all the views in this array have been added into the same view hierarchy.");
    return commonSuperview;
}

/**
 Determines whether this array contains a minimum number of views.
 
 @param minimumNumberOfViews The minimum number of views to check for.
 @return YES if this array contains at least the minimum number of views, NO otherwise.
 */
- (BOOL)al_containsMinimumNumberOfViews:(NSUInteger)minimumNumberOfViews
{
    NSUInteger numberOfViews = 0;
    for (id object in self) {
        if ([object isKindOfClass:[ALView class]]) {
            numberOfViews++;
            if (numberOfViews >= minimumNumberOfViews) {
                return YES;
            }
        }
    }
    return numberOfViews >= minimumNumberOfViews;
}

/**
 Creates a copy of this array containing only the view objects in it.
 
 @return A new array containing only the views that are in this array.
 */
- (NSArray *)al_copyViewsOnly
{
    NSMutableArray *viewsOnlyArray = [NSMutableArray arrayWithCapacity:[self count]];
    for (id object in self) {
        if ([object isKindOfClass:[ALView class]]) {
            [viewsOnlyArray addObject:object];
        }
    }
    return viewsOnlyArray;
}

@end


================================================
FILE: JASwipeCellExample/NSLayoutConstraint+PureLayout.h
================================================
//
//  NSLayoutConstraint+PureLayout.h
//  v1.1.0
//  https://github.com/smileyborg/PureLayout
//
//  Copyright (c) 2013-2014 Tyler Fox
//
//  This code is distributed under the terms and conditions of the MIT license.
//
//  Permission is hereby granted, free of charge, to any person obtaining a copy
//  of this software and associated documentation files (the "Software"), to
//  deal in the Software without restriction, including without limitation the
//  rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
//  sell copies of the Software, and to permit persons to whom the Software is
//  furnished to do so, subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be included in
//  all copies or substantial portions of the Software.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
//  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
//  IN THE SOFTWARE.
//

#import "PureLayoutDefines.h"


#pragma mark - NSLayoutConstraint+PureLayout

/**
 A category on NSLayoutConstraint that allows constraints to be easily removed.
 */
@interface NSLayoutConstraint (PureLayout)

/** Adds the constraint to the appropriate view. */
- (void)autoInstall;

/** Removes the constraint from the view it has been added to. */
- (void)autoRemove;

@end


================================================
FILE: JASwipeCellExample/NSLayoutConstraint+PureLayout.m
================================================
//
//  NSLayoutConstraint+PureLayout.m
//  v1.1.0
//  https://github.com/smileyborg/PureLayout
//
//  Copyright (c) 2013-2014 Tyler Fox
//
//  This code is distributed under the terms and conditions of the MIT license.
//
//  Permission is hereby granted, free of charge, to any person obtaining a copy
//  of this software and associated documentation files (the "Software"), to
//  deal in the Software without restriction, including without limitation the
//  rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
//  sell copies of the Software, and to permit persons to whom the Software is
//  furnished to do so, subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be included in
//  all copies or substantial portions of the Software.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
//  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
//  IN THE SOFTWARE.
//

#import "NSLayoutConstraint+PureLayout.h"
#import "ALView+PureLayout.h"
#import "PureLayout+Internal.h"


#pragma mark - NSLayoutConstraint+PureLayout

@implementation NSLayoutConstraint (PureLayout)

/**
 Adds the constraint to the appropriate view.
 */
- (void)autoInstall
{
    NSAssert(self.firstItem || self.secondItem, @"Can't install a constraint with nil firstItem and secondItem.");
    if (self.firstItem) {
        if (self.secondItem) {
            NSAssert([self.firstItem isKindOfClass:[ALView class]] && [self.secondItem isKindOfClass:[ALView class]], @"Can only automatically install a constraint if both items are views.");
            ALView *commonSuperview = [self.firstItem al_commonSuperviewWithView:self.secondItem];
            [commonSuperview al_addConstraintUsingGlobalPriority:self];
        } else {
            NSAssert([self.firstItem isKindOfClass:[ALView class]], @"Can only automatically install a constraint if the item is a view.");
            [self.firstItem al_addConstraintUsingGlobalPriority:self];
        }
    } else {
        NSAssert([self.secondItem isKindOfClass:[ALView class]], @"Can only automatically install a constraint if the item is a view.");
        [self.secondItem al_addConstraintUsingGlobalPriority:self];
    }
}

/**
 Removes the constraint from the view it has been added to.
 */
- (void)autoRemove
{
    [ALView autoRemoveConstraint:self];
}

@end


================================================
FILE: JASwipeCellExample/PureLayout+Internal.h
================================================
//
//  PureLayout+Internal.h
//  v1.1.0
//  https://github.com/smileyborg/PureLayout
//
//  Copyright (c) 2014 Tyler Fox
//
//  This code is distributed under the terms and conditions of the MIT license.
//
//  Permission is hereby granted, free of charge, to any person obtaining a copy
//  of this software and associated documentation files (the "Software"), to
//  deal in the Software without restriction, including without limitation the
//  rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
//  sell copies of the Software, and to permit persons to whom the Software is
//  furnished to do so, subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be included in
//  all copies or substantial portions of the Software.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
//  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
//  IN THE SOFTWARE.
//

#import "PureLayoutDefines.h"


/**
 A category that exposes the internal (private) helper methods of the ALView+PureLayout category.
 */
@interface ALView (PureLayoutInternal)

+ (NSLayoutAttribute)al_attributeForEdge:(ALEdge)edge;
+ (NSLayoutAttribute)al_attributeForAxis:(ALAxis)axis;
+ (NSLayoutAttribute)al_attributeForDimension:(ALDimension)dimension;
+ (NSLayoutAttribute)al_attributeForALAttribute:(NSInteger)ALAttribute;
+ (ALLayoutConstraintAxis)al_constraintAxisForAxis:(ALAxis)axis;

- (void)al_addConstraintUsingGlobalPriority:(NSLayoutConstraint *)constraint;
- (ALView *)al_commonSuperviewWithView:(ALView *)peerView;
- (NSLayoutConstraint *)al_alignToView:(ALView *)peerView withOption:(NSLayoutFormatOptions)alignment forAxis:(ALAxis)axis;

@end


/**
 A category that exposes the internal (private) helper methods of the NSArray+PureLayout category.
 */
@interface NSArray (PureLayoutInternal)

- (ALView *)al_commonSuperviewOfViews;
- (BOOL)al_containsMinimumNumberOfViews:(NSUInteger)minimumNumberOfViews;
- (NSArray *)al_copyViewsOnly;

@end


================================================
FILE: JASwipeCellExample/PureLayout.h
================================================
//
//  PureLayout.h
//  v1.1.0
//  https://github.com/smileyborg/PureLayout
//
//  Copyright (c) 2014 Tyler Fox
//
//  This code is distributed under the terms and conditions of the MIT license.
//
//  Permission is hereby granted, free of charge, to any person obtaining a copy
//  of this software and associated documentation files (the "Software"), to
//  deal in the Software without restriction, including without limitation the
//  rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
//  sell copies of the Software, and to permit persons to whom the Software is
//  furnished to do so, subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be included in
//  all copies or substantial portions of the Software.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
//  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
//  IN THE SOFTWARE.
//

#ifndef PureLayout_h
#define PureLayout_h

#import "ALView+PureLayout.h"
#import "NSArray+PureLayout.h"
#import "NSLayoutConstraint+PureLayout.h"

#endif /* PureLayout_h */

================================================
FILE: JASwipeCellExample/PureLayoutDefines.h
================================================
//
//  PureLayoutDefines.h
//  v1.1.0
//  https://github.com/smileyborg/PureLayout
//
//  Copyright (c) 2014 Tyler Fox
//
//  This code is distributed under the terms and conditions of the MIT license.
//
//  Permission is hereby granted, free of charge, to any person obtaining a copy
//  of this software and associated documentation files (the "Software"), to
//  deal in the Software without restriction, including without limitation the
//  rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
//  sell copies of the Software, and to permit persons to whom the Software is
//  furnished to do so, subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be included in
//  all copies or substantial portions of the Software.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
//  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
//  IN THE SOFTWARE.
//

#ifndef PureLayoutDefines_h
#define PureLayoutDefines_h

#import <Foundation/Foundation.h>

#if TARGET_OS_IPHONE

    #import <UIKit/UIKit.h>

    #define ALView                                      UIView
    #define ALEdgeInsets                                UIEdgeInsets
    #define ALEdgeInsetsZero                            UIEdgeInsetsZero
    #define ALEdgeInsetsMake                            UIEdgeInsetsMake
    #define ALLayoutConstraintAxis                      UILayoutConstraintAxis
    #define ALLayoutConstraintOrientation               ALLayoutConstraintAxis
    #define ALLayoutConstraintAxisHorizontal            UILayoutConstraintAxisHorizontal
    #define ALLayoutConstraintAxisVertical              UILayoutConstraintAxisVertical
    #define ALLayoutConstraintOrientationHorizontal     ALLayoutConstraintAxisHorizontal
    #define ALLayoutConstraintOrientationVertical       ALLayoutConstraintAxisVertical
    #define ALLayoutPriority                            UILayoutPriority
    #define ALLayoutPriorityRequired                    UILayoutPriorityRequired
    #define ALLayoutPriorityDefaultHigh                 UILayoutPriorityDefaultHigh
    #define ALLayoutPriorityDefaultLow                  UILayoutPriorityDefaultLow
    #define ALLayoutPriorityFittingSizeLevel            UILayoutPriorityFittingSizeLevel
    #define ALLayoutPriorityFittingSizeCompression      ALLayoutPriorityFittingSizeLevel

#else

    #import <Cocoa/Cocoa.h>

    #define ALView                                      NSView
    #define ALEdgeInsets                                NSEdgeInsets
    #define ALEdgeInsetsZero                            NSEdgeInsetsMake(0, 0, 0, 0)
    #define ALEdgeInsetsMake                            NSEdgeInsetsMake
    #define ALLayoutConstraintOrientation               NSLayoutConstraintOrientation
    #define ALLayoutConstraintAxis                      ALLayoutConstraintOrientation
    #define ALLayoutConstraintOrientationHorizontal     NSLayoutConstraintOrientationHorizontal
    #define ALLayoutConstraintOrientationVertical       NSLayoutConstraintOrientationVertical
    #define ALLayoutConstraintAxisHorizontal            ALLayoutConstraintOrientationHorizontal
    #define ALLayoutConstraintAxisVertical              ALLayoutConstraintOrientationVertical
    #define ALLayoutPriority                            NSLayoutPriority
    #define ALLayoutPriorityRequired                    NSLayoutPriorityRequired
    #define ALLayoutPriorityDefaultHigh                 NSLayoutPriorityDefaultHigh
    #define ALLayoutPriorityDefaultLow                  NSLayoutPriorityDefaultLow
    #define ALLayoutPriorityFittingSizeCompression      NSLayoutPriorityFittingSizeCompression
    #define ALLayoutPriorityFittingSizeLevel            ALLayoutPriorityFittingSizeCompression

#endif /* TARGET_OS_IPHONE */


#pragma mark ALAttributes

/** Constants that represent edges of a view. */
typedef NS_ENUM(NSInteger, ALEdge) {
    /** The left edge of the view. */
    ALEdgeLeft = NSLayoutAttributeLeft,
    /** The right edge of the view. */
    ALEdgeRight = NSLayoutAttributeRight,
    /** The top edge of the view. */
    ALEdgeTop = NSLayoutAttributeTop,
    /** The bottom edge of the view. */
    ALEdgeBottom = NSLayoutAttributeBottom,
    /** The leading edge of the view (left edge for left-to-right languages like English, right edge for right-to-left languages like Arabic). */
    ALEdgeLeading = NSLayoutAttributeLeading,
    /** The trailing edge of the view (right edge for left-to-right languages like English, left edge for right-to-left languages like Arabic). */
    ALEdgeTrailing = NSLayoutAttributeTrailing
};

/** Constants that represent dimensions of a view. */
typedef NS_ENUM(NSInteger, ALDimension) {
    /** The width of the view. */
    ALDimensionWidth = NSLayoutAttributeWidth,
    /** The height of the view. */
    ALDimensionHeight = NSLayoutAttributeHeight
};

/** Constants that represent axes of a view. */
typedef NS_ENUM(NSInteger, ALAxis) {
    /** A vertical line through the center of the view. */
    ALAxisVertical = NSLayoutAttributeCenterX,
    /** A horizontal line through the center of the view. */
    ALAxisHorizontal = NSLayoutAttributeCenterY,
    /** A horizontal line at the text baseline (not applicable to all views). */
    ALAxisBaseline = NSLayoutAttributeBaseline
};

/** A block containing method calls to the PureLayout API. Takes no arguments and has no return value. */
typedef void(^ALConstraintsBlock)(void);

#endif /* PureLayoutDefines_h */


================================================
FILE: JASwipeCellExample/main.m
================================================
//
//  main.m
//  JASwipeCell
//
//  Created by Jose Alvarez on 10/8/14.
//  Copyright (c) 2014 Jose Alvarez. All rights reserved.
//
//  Permission is hereby granted, free of charge, to any person obtaining a copy
//  of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//  copies of the Software, and to permit persons to whom the Software is
//  furnished to do so, subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be included in all
//  copies or substantial portions of the Software.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//  SOFTWARE.

#import <UIKit/UIKit.h>
#import "AppDelegate.h"

int main(int argc, char * argv[]) {
    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}


================================================
FILE: JASwipeCellExample.xcodeproj/project.pbxproj
================================================
// !$*UTF8*$!
{
	archiveVersion = 1;
	classes = {
	};
	objectVersion = 46;
	objects = {

/* Begin PBXBuildFile section */
		5FC745F619E642BA00B50690 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5FC745F519E642BA00B50690 /* CoreGraphics.framework */; };
		5FC745F819E642BF00B50690 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5FC745F719E642BF00B50690 /* UIKit.framework */; };
		5FC745FA19E642C600B50690 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5FC745F919E642C600B50690 /* Foundation.framework */; };
		5FF23A4619FB01E600968333 /* ALView+PureLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 5FF23A2E19FB01E600968333 /* ALView+PureLayout.m */; };
		5FF23A4719FB01E600968333 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 5FF23A3019FB01E600968333 /* AppDelegate.m */; };
		5FF23A4819FB01E600968333 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5FF23A3119FB01E600968333 /* Main.storyboard */; };
		5FF23A4919FB01E600968333 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5FF23A3319FB01E600968333 /* Images.xcassets */; };
		5FF23A4A19FB01E600968333 /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5FF23A3419FB01E600968333 /* Info.plist */; };
		5FF23A4D19FB01E600968333 /* JATableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 5FF23A3B19FB01E600968333 /* JATableViewCell.m */; };
		5FF23A4E19FB01E600968333 /* JATableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5FF23A3D19FB01E600968333 /* JATableViewController.m */; };
		5FF23A4F19FB01E600968333 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 5FF23A3E19FB01E600968333 /* main.m */; };
		5FF23A5019FB01E600968333 /* NSArray+PureLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 5FF23A4019FB01E600968333 /* NSArray+PureLayout.m */; };
		5FF23A5119FB01E600968333 /* NSLayoutConstraint+PureLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 5FF23A4219FB01E600968333 /* NSLayoutConstraint+PureLayout.m */; };
		5FF23A5819FB02BF00968333 /* JAActionButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 5FF23A5519FB02BF00968333 /* JAActionButton.m */; };
		5FF23A5919FB02BF00968333 /* JASwipeCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 5FF23A5719FB02BF00968333 /* JASwipeCell.m */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
		5F7548B619874B6200F99E74 /* PBXContainerItemProxy */ = {
			isa = PBXContainerItemProxy;
			containerPortal = 5F75489719874B6200F99E74 /* Project object */;
			proxyType = 1;
			remoteGlobalIDString = 5F75489E19874B6200F99E74;
			remoteInfo = JASwipeCell;
		};
/* End PBXContainerItemProxy section */

/* Begin PBXFileReference section */
		5FC745F119E6402600B50690 /* JASwipeCellExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = JASwipeCellExample.app; sourceTree = BUILT_PRODUCTS_DIR; };
		5FC745F219E6402600B50690 /* JASwipeCellExampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = JASwipeCellExampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
		5FC745F519E642BA00B50690 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
		5FC745F719E642BF00B50690 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
		5FC745F919E642C600B50690 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
		5FF23A2D19FB01E600968333 /* ALView+PureLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ALView+PureLayout.h"; sourceTree = "<group>"; };
		5FF23A2E19FB01E600968333 /* ALView+PureLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "ALView+PureLayout.m"; sourceTree = "<group>"; };
		5FF23A2F19FB01E600968333 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
		5FF23A3019FB01E600968333 /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
		5FF23A3219FB01E600968333 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
		5FF23A3319FB01E600968333 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
		5FF23A3419FB01E600968333 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
		5FF23A3A19FB01E600968333 /* JATableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JATableViewCell.h; sourceTree = "<group>"; };
		5FF23A3B19FB01E600968333 /* JATableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JATableViewCell.m; sourceTree = "<group>"; };
		5FF23A3C19FB01E600968333 /* JATableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JATableViewController.h; sourceTree = "<group>"; };
		5FF23A3D19FB01E600968333 /* JATableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JATableViewController.m; sourceTree = "<group>"; };
		5FF23A3E19FB01E600968333 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
		5FF23A3F19FB01E600968333 /* NSArray+PureLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSArray+PureLayout.h"; sourceTree = "<group>"; };
		5FF23A4019FB01E600968333 /* NSArray+PureLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSArray+PureLayout.m"; sourceTree = "<group>"; };
		5FF23A4119FB01E600968333 /* NSLayoutConstraint+PureLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSLayoutConstraint+PureLayout.h"; sourceTree = "<group>"; };
		5FF23A4219FB01E600968333 /* NSLayoutConstraint+PureLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSLayoutConstraint+PureLayout.m"; sourceTree = "<group>"; };
		5FF23A4319FB01E600968333 /* PureLayout+Internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "PureLayout+Internal.h"; sourceTree = "<group>"; };
		5FF23A4419FB01E600968333 /* PureLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PureLayout.h; sourceTree = "<group>"; };
		5FF23A4519FB01E600968333 /* PureLayoutDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PureLayoutDefines.h; sourceTree = "<group>"; };
		5FF23A5419FB02BF00968333 /* JAActionButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JAActionButton.h; sourceTree = "<group>"; };
		5FF23A5519FB02BF00968333 /* JAActionButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JAActionButton.m; sourceTree = "<group>"; };
		5FF23A5619FB02BF00968333 /* JASwipeCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JASwipeCell.h; sourceTree = "<group>"; };
		5FF23A5719FB02BF00968333 /* JASwipeCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JASwipeCell.m; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
		5F75489C19874B6200F99E74 /* Frameworks */ = {
			isa = PBXFrameworksBuildPhase;
			buildActionMask = 2147483647;
			files = (
				5FC745FA19E642C600B50690 /* Foundation.framework in Frameworks */,
				5FC745F819E642BF00B50690 /* UIKit.framework in Frameworks */,
				5FC745F619E642BA00B50690 /* CoreGraphics.framework in Frameworks */,
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
		5F7548B219874B6200F99E74 /* Frameworks */ = {
			isa = PBXFrameworksBuildPhase;
			buildActionMask = 2147483647;
			files = (
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */
		5F75489619874B6200F99E74 = {
			isa = PBXGroup;
			children = (
				5FF23A2C19FB01E600968333 /* JASwipeCellExample */,
				96DE50230DDF45EBADD5E5A0 /* Frameworks */,
				5FC745FB19E642D900B50690 /* Products */,
			);
			sourceTree = "<group>";
		};
		5FC745FB19E642D900B50690 /* Products */ = {
			isa = PBXGroup;
			children = (
				5FC745F119E6402600B50690 /* JASwipeCellExample.app */,
				5FC745F219E6402600B50690 /* JASwipeCellExampleTests.xctest */,
			);
			name = Products;
			sourceTree = "<group>";
		};
		5FF23A2C19FB01E600968333 /* JASwipeCellExample */ = {
			isa = PBXGroup;
			children = (
				5FF23A2F19FB01E600968333 /* AppDelegate.h */,
				5FF23A3019FB01E600968333 /* AppDelegate.m */,
				5FF23A3119FB01E600968333 /* Main.storyboard */,
				5FF23A3319FB01E600968333 /* Images.xcassets */,
				5FF23A3419FB01E600968333 /* Info.plist */,
				5FF23A3A19FB01E600968333 /* JATableViewCell.h */,
				5FF23A3B19FB01E600968333 /* JATableViewCell.m */,
				5FF23A3C19FB01E600968333 /* JATableViewController.h */,
				5FF23A3D19FB01E600968333 /* JATableViewController.m */,
				5FF23A3E19FB01E600968333 /* main.m */,
				5FF23A5319FB02BF00968333 /* JASwipeCell */,
				5FF23A5219FB01F500968333 /* PureLayout */,
			);
			path = JASwipeCellExample;
			sourceTree = "<group>";
		};
		5FF23A5219FB01F500968333 /* PureLayout */ = {
			isa = PBXGroup;
			children = (
				5FF23A2D19FB01E600968333 /* ALView+PureLayout.h */,
				5FF23A2E19FB01E600968333 /* ALView+PureLayout.m */,
				5FF23A3F19FB01E600968333 /* NSArray+PureLayout.h */,
				5FF23A4019FB01E600968333 /* NSArray+PureLayout.m */,
				5FF23A4119FB01E600968333 /* NSLayoutConstraint+PureLayout.h */,
				5FF23A4219FB01E600968333 /* NSLayoutConstraint+PureLayout.m */,
				5FF23A4319FB01E600968333 /* PureLayout+Internal.h */,
				5FF23A4419FB01E600968333 /* PureLayout.h */,
				5FF23A4519FB01E600968333 /* PureLayoutDefines.h */,
			);
			name = PureLayout;
			sourceTree = "<group>";
		};
		5FF23A5319FB02BF00968333 /* JASwipeCell */ = {
			isa = PBXGroup;
			children = (
				5FF23A5419FB02BF00968333 /* JAActionButton.h */,
				5FF23A5519FB02BF00968333 /* JAActionButton.m */,
				5FF23A5619FB02BF00968333 /* JASwipeCell.h */,
				5FF23A5719FB02BF00968333 /* JASwipeCell.m */,
			);
			path = JASwipeCell;
			sourceTree = SOURCE_ROOT;
		};
		96DE50230DDF45EBADD5E5A0 /* Frameworks */ = {
			isa = PBXGroup;
			children = (
				5FC745F919E642C600B50690 /* Foundation.framework */,
				5FC745F719E642BF00B50690 /* UIKit.framework */,
				5FC745F519E642BA00B50690 /* CoreGraphics.framework */,
			);
			name = Frameworks;
			sourceTree = "<group>";
		};
/* End PBXGroup section */

/* Begin PBXNativeTarget section */
		5F75489E19874B6200F99E74 /* JASwipeCellExample */ = {
			isa = PBXNativeTarget;
			buildConfigurationList = 5F7548BF19874B6200F99E74 /* Build configuration list for PBXNativeTarget "JASwipeCellExample" */;
			buildPhases = (
				5F75489B19874B6200F99E74 /* Sources */,
				5F75489C19874B6200F99E74 /* Frameworks */,
				5F75489D19874B6200F99E74 /* Resources */,
			);
			buildRules = (
			);
			dependencies = (
			);
			name = JASwipeCellExample;
			productName = JASwipeCell;
			productReference = 5FC745F119E6402600B50690 /* JASwipeCellExample.app */;
			productType = "com.apple.product-type.application";
		};
		5F7548B419874B6200F99E74 /* JASwipeCellExampleTests */ = {
			isa = PBXNativeTarget;
			buildConfigurationList = 5F7548C219874B6200F99E74 /* Build configuration list for PBXNativeTarget "JASwipeCellExampleTests" */;
			buildPhases = (
				5F7548B119874B6200F99E74 /* Sources */,
				5F7548B219874B6200F99E74 /* Frameworks */,
				5F7548B319874B6200F99E74 /* Resources */,
			);
			buildRules = (
			);
			dependencies = (
				5F7548B719874B6200F99E74 /* PBXTargetDependency */,
			);
			name = JASwipeCellExampleTests;
			productName = JASwipeCellTests;
			productReference = 5FC745F219E6402600B50690 /* JASwipeCellExampleTests.xctest */;
			productType = "com.apple.product-type.bundle.unit-test";
		};
/* End PBXNativeTarget section */

/* Begin PBXProject section */
		5F75489719874B6200F99E74 /* Project object */ = {
			isa = PBXProject;
			attributes = {
				LastUpgradeCheck = 0600;
				ORGANIZATIONNAME = "Alvarez, Jose (MTV)";
				TargetAttributes = {
					5F75489E19874B6200F99E74 = {
						CreatedOnToolsVersion = 6.0;
						DevelopmentTeam = 7RS6PZH7K6;
					};
					5F7548B419874B6200F99E74 = {
						CreatedOnToolsVersion = 6.0;
						TestTargetID = 5F75489E19874B6200F99E74;
					};
				};
			};
			buildConfigurationList = 5F75489A19874B6200F99E74 /* Build configuration list for PBXProject "JASwipeCellExample" */;
			compatibilityVersion = "Xcode 3.2";
			developmentRegion = English;
			hasScannedForEncodings = 0;
			knownRegions = (
				en,
				Base,
			);
			mainGroup = 5F75489619874B6200F99E74;
			productRefGroup = 5F75489619874B6200F99E74;
			projectDirPath = "";
			projectRoot = "";
			targets = (
				5F75489E19874B6200F99E74 /* JASwipeCellExample */,
				5F7548B419874B6200F99E74 /* JASwipeCellExampleTests */,
			);
		};
/* End PBXProject section */

/* Begin PBXResourcesBuildPhase section */
		5F75489D19874B6200F99E74 /* Resources */ = {
			isa = PBXResourcesBuildPhase;
			buildActionMask = 2147483647;
			files = (
				5FF23A4819FB01E600968333 /* Main.storyboard in Resources */,
				5FF23A4919FB01E600968333 /* Images.xcassets in Resources */,
				5FF23A4A19FB01E600968333 /* Info.plist in Resources */,
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
		5F7548B319874B6200F99E74 /* Resources */ = {
			isa = PBXResourcesBuildPhase;
			buildActionMask = 2147483647;
			files = (
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
/* End PBXResourcesBuildPhase section */

/* Begin PBXSourcesBuildPhase section */
		5F75489B19874B6200F99E74 /* Sources */ = {
			isa = PBXSourcesBuildPhase;
			buildActionMask = 2147483647;
			files = (
				5FF23A5819FB02BF00968333 /* JAActionButton.m in Sources */,
				5FF23A4D19FB01E600968333 /* JATableViewCell.m in Sources */,
				5FF23A4719FB01E600968333 /* AppDelegate.m in Sources */,
				5FF23A4619FB01E600968333 /* ALView+PureLayout.m in Sources */,
				5FF23A5019FB01E600968333 /* NSArray+PureLayout.m in Sources */,
				5FF23A5119FB01E600968333 /* NSLayoutConstraint+PureLayout.m in Sources */,
				5FF23A4E19FB01E600968333 /* JATableViewController.m in Sources */,
				5FF23A5919FB02BF00968333 /* JASwipeCell.m in Sources */,
				5FF23A4F19FB01E600968333 /* main.m in Sources */,
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
		5F7548B119874B6200F99E74 /* Sources */ = {
			isa = PBXSourcesBuildPhase;
			buildActionMask = 2147483647;
			files = (
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
/* End PBXSourcesBuildPhase section */

/* Begin PBXTargetDependency section */
		5F7548B719874B6200F99E74 /* PBXTargetDependency */ = {
			isa = PBXTargetDependency;
			target = 5F75489E19874B6200F99E74 /* JASwipeCellExample */;
			targetProxy = 5F7548B619874B6200F99E74 /* PBXContainerItemProxy */;
		};
/* End PBXTargetDependency section */

/* Begin PBXVariantGroup section */
		5FF23A3119FB01E600968333 /* Main.storyboard */ = {
			isa = PBXVariantGroup;
			children = (
				5FF23A3219FB01E600968333 /* Base */,
			);
			name = Main.storyboard;
			sourceTree = "<group>";
		};
/* End PBXVariantGroup section */

/* Begin XCBuildConfiguration section */
		5F7548BD19874B6200F99E74 /* Debug */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				ALWAYS_SEARCH_USER_PATHS = NO;
				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
				CLANG_CXX_LIBRARY = "libc++";
				CLANG_ENABLE_MODULES = YES;
				CLANG_ENABLE_OBJC_ARC = YES;
				CLANG_WARN_BOOL_CONVERSION = YES;
				CLANG_WARN_CONSTANT_CONVERSION = YES;
				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
				CLANG_WARN_EMPTY_BODY = YES;
				CLANG_WARN_ENUM_CONVERSION = YES;
				CLANG_WARN_INT_CONVERSION = YES;
				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
				CLANG_WARN_UNREACHABLE_CODE = YES;
				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
				COPY_PHASE_STRIP = NO;
				ENABLE_STRICT_OBJC_MSGSEND = YES;
				GCC_C_LANGUAGE_STANDARD = gnu99;
				GCC_DYNAMIC_NO_PIC = NO;
				GCC_OPTIMIZATION_LEVEL = 0;
				GCC_PREPROCESSOR_DEFINITIONS = (
					"DEBUG=1",
					"$(inherited)",
				);
				GCC_SYMBOLS_PRIVATE_EXTERN = NO;
				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
				GCC_WARN_UNDECLARED_SELECTOR = YES;
				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
				GCC_WARN_UNUSED_FUNCTION = YES;
				GCC_WARN_UNUSED_VARIABLE = YES;
				IPHONEOS_DEPLOYMENT_TARGET = 7.0;
				MTL_ENABLE_DEBUG_INFO = YES;
				ONLY_ACTIVE_ARCH = YES;
				SDKROOT = iphoneos;
				TARGETED_DEVICE_FAMILY = "1,2";
			};
			name = Debug;
		};
		5F7548BE19874B6200F99E74 /* Release */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				ALWAYS_SEARCH_USER_PATHS = NO;
				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
				CLANG_CXX_LIBRARY = "libc++";
				CLANG_ENABLE_MODULES = YES;
				CLANG_ENABLE_OBJC_ARC = YES;
				CLANG_WARN_BOOL_CONVERSION = YES;
				CLANG_WARN_CONSTANT_CONVERSION = YES;
				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
				CLANG_WARN_EMPTY_BODY = YES;
				CLANG_WARN_ENUM_CONVERSION = YES;
				CLANG_WARN_INT_CONVERSION = YES;
				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
				CLANG_WARN_UNREACHABLE_CODE = YES;
				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
				COPY_PHASE_STRIP = YES;
				ENABLE_NS_ASSERTIONS = NO;
				ENABLE_STRICT_OBJC_MSGSEND = YES;
				GCC_C_LANGUAGE_STANDARD = gnu99;
				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
				GCC_WARN_UNDECLARED_SELECTOR = YES;
				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
				GCC_WARN_UNUSED_FUNCTION = YES;
				GCC_WARN_UNUSED_VARIABLE = YES;
				IPHONEOS_DEPLOYMENT_TARGET = 7.0;
				MTL_ENABLE_DEBUG_INFO = NO;
				SDKROOT = iphoneos;
				TARGETED_DEVICE_FAMILY = "1,2";
				VALIDATE_PRODUCT = YES;
			};
			name = Release;
		};
		5F7548C019874B6200F99E74 /* Debug */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
				ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
				CODE_SIGN_IDENTITY = "iPhone Developer";
				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
				FRAMEWORK_SEARCH_PATHS = (
					"$(inherited)",
					"$(PROJECT_DIR)",
				);
				INFOPLIST_FILE = JASwipeCellExample/Info.plist;
				IPHONEOS_DEPLOYMENT_TARGET = 7.0;
				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
				PRODUCT_NAME = JASwipeCellExample;
				PROVISIONING_PROFILE = "";
			};
			name = Debug;
		};
		5F7548C119874B6200F99E74 /* Release */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
				ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
				CODE_SIGN_IDENTITY = "iPhone Developer";
				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
				FRAMEWORK_SEARCH_PATHS = (
					"$(inherited)",
					"$(PROJECT_DIR)",
				);
				INFOPLIST_FILE = JASwipeCellExample/Info.plist;
				IPHONEOS_DEPLOYMENT_TARGET = 7.0;
				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
				PRODUCT_NAME = JASwipeCellExample;
				PROVISIONING_PROFILE = "";
			};
			name = Release;
		};
		5F7548C319874B6200F99E74 /* Debug */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/JASwipeCell.app/JASwipeCell";
				FRAMEWORK_SEARCH_PATHS = (
					"$(SDKROOT)/Developer/Library/Frameworks",
					"$(inherited)",
				);
				GCC_PREPROCESSOR_DEFINITIONS = (
					"DEBUG=1",
					"$(inherited)",
				);
				INFOPLIST_FILE = "";
				IPHONEOS_DEPLOYMENT_TARGET = 7.0;
				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
				PRODUCT_NAME = JASwipeCellExampleTests;
				TEST_HOST = "$(BUNDLE_LOADER)";
			};
			name = Debug;
		};
		5F7548C419874B6200F99E74 /* Release */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/JASwipeCell.app/JASwipeCell";
				FRAMEWORK_SEARCH_PATHS = (
					"$(SDKROOT)/Developer/Library/Frameworks",
					"$(inherited)",
				);
				INFOPLIST_FILE = "";
				IPHONEOS_DEPLOYMENT_TARGET = 7.0;
				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
				PRODUCT_NAME = JASwipeCellExampleTests;
				TEST_HOST = "$(BUNDLE_LOADER)";
			};
			name = Release;
		};
/* End XCBuildConfiguration section */

/* Begin XCConfigurationList section */
		5F75489A19874B6200F99E74 /* Build configuration list for PBXProject "JASwipeCellExample" */ = {
			isa = XCConfigurationList;
			buildConfigurations = (
				5F7548BD19874B6200F99E74 /* Debug */,
				5F7548BE19874B6200F99E74 /* Release */,
			);
			defaultConfigurationIsVisible = 0;
			defaultConfigurationName = Release;
		};
		5F7548BF19874B6200F99E74 /* Build configuration list for PBXNativeTarget "JASwipeCellExample" */ = {
			isa = XCConfigurationList;
			buildConfigurations = (
				5F7548C019874B6200F99E74 /* Debug */,
				5F7548C119874B6200F99E74 /* Release */,
			);
			defaultConfigurationIsVisible = 0;
			defaultConfigurationName = Release;
		};
		5F7548C219874B6200F99E74 /* Build configuration list for PBXNativeTarget "JASwipeCellExampleTests" */ = {
			isa = XCConfigurationList;
			buildConfigurations = (
				5F7548C319874B6200F99E74 /* Debug */,
				5F7548C419874B6200F99E74 /* Release */,
			);
			defaultConfigurationIsVisible = 0;
			defaultConfigurationName = Release;
		};
/* End XCConfigurationList section */
	};
	rootObject = 5F75489719874B6200F99E74 /* Project object */;
}


================================================
FILE: JASwipeCellExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata
================================================
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
   version = "1.0">
   <FileRef
      location = "self:JASwipeCell.xcodeproj">
   </FileRef>
</Workspace>


================================================
FILE: JASwipeCellExample.xcodeproj/xcshareddata/xcschemes/JASwipeCellExample.xcscheme
================================================
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
   LastUpgradeVersion = "0610"
   version = "1.3">
   <BuildAction
      parallelizeBuildables = "YES"
      buildImplicitDependencies = "YES">
      <BuildActionEntries>
         <BuildActionEntry
            buildForTesting = "YES"
            buildForRunning = "YES"
            buildForProfiling = "YES"
            buildForArchiving = "YES"
            buildForAnalyzing = "YES">
            <BuildableReference
               BuildableIdentifier = "primary"
               BlueprintIdentifier = "5F75489E19874B6200F99E74"
               BuildableName = "JASwipeCellExample.app"
               BlueprintName = "JASwipeCellExample"
               ReferencedContainer = "container:JASwipeCellExample.xcodeproj">
            </BuildableReference>
         </BuildActionEntry>
         <BuildActionEntry
            buildForTesting = "YES"
            buildForRunning = "YES"
            buildForProfiling = "NO"
            buildForArchiving = "NO"
            buildForAnalyzing = "YES">
            <BuildableReference
               BuildableIdentifier = "primary"
               BlueprintIdentifier = "5F7548B419874B6200F99E74"
               BuildableName = "JASwipeCellExampleTests.xctest"
               BlueprintName = "JASwipeCellExampleTests"
               ReferencedContainer = "container:JASwipeCellExample.xcodeproj">
            </BuildableReference>
         </BuildActionEntry>
      </BuildActionEntries>
   </BuildAction>
   <TestAction
      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
      shouldUseLaunchSchemeArgsEnv = "YES"
      buildConfiguration = "Debug">
      <Testables>
         <TestableReference
            skipped = "NO">
            <BuildableReference
               BuildableIdentifier = "primary"
               BlueprintIdentifier = "5F7548B419874B6200F99E74"
               BuildableName = "JASwipeCellExampleTests.xctest"
               BlueprintName = "JASwipeCellExampleTests"
               ReferencedContainer = "container:JASwipeCellExample.xcodeproj">
            </BuildableReference>
         </TestableReference>
      </Testables>
      <MacroExpansion>
         <BuildableReference
            BuildableIdentifier = "primary"
            BlueprintIdentifier = "5F75489E19874B6200F99E74"
            BuildableName = "JASwipeCellExample.app"
            BlueprintName = "JASwipeCellExample"
            ReferencedContainer = "container:JASwipeCellExample.xcodeproj">
         </BuildableReference>
      </MacroExpansion>
   </TestAction>
   <LaunchAction
      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
      launchStyle = "0"
      useCustomWorkingDirectory = "NO"
      buildConfiguration = "Debug"
      ignoresPersistentStateOnLaunch = "NO"
      debugDocumentVersioning = "YES"
      allowLocationSimulation = "YES">
      <BuildableProductRunnable>
         <BuildableReference
            BuildableIdentifier = "primary"
            BlueprintIdentifier = "5F75489E19874B6200F99E74"
            BuildableName = "JASwipeCellExample.app"
            BlueprintName = "JASwipeCellExample"
            ReferencedContainer = "container:JASwipeCellExample.xcodeproj">
         </BuildableReference>
      </BuildableProductRunnable>
      <AdditionalOptions>
      </AdditionalOptions>
   </LaunchAction>
   <ProfileAction
      shouldUseLaunchSchemeArgsEnv = "YES"
      savedToolIdentifier = ""
      useCustomWorkingDirectory = "NO"
      buildConfiguration = "Release"
      debugDocumentVersioning = "YES">
      <BuildableProductRunnable>
         <BuildableReference
            BuildableIdentifier = "primary"
            BlueprintIdentifier = "5F75489E19874B6200F99E74"
            BuildableName = "JASwipeCellExample.app"
            BlueprintName = "JASwipeCellExample"
            ReferencedContainer = "container:JASwipeCellExample.xcodeproj">
         </BuildableReference>
      </BuildableProductRunnable>
   </ProfileAction>
   <AnalyzeAction
      buildConfiguration = "Debug">
   </AnalyzeAction>
   <ArchiveAction
      buildConfiguration = "Release"
      revealArchiveInOrganizer = "YES">
   </ArchiveAction>
</Scheme>


================================================
FILE: LICENSE
================================================
The MIT License (MIT)

Copyright (c) 2014 Jose Alvarez

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.



================================================
FILE: README.md
================================================
JASwipeCell
===========

[![Build Status](https://travis-ci.org/joseria/JASwipeCell.svg?branch=master)](https://travis-ci.org/joseria/JASwipeCell)
[![CocoaPods](https://img.shields.io/cocoapods/v/JASwipeCell.svg)](http://cocoapods.org/?q=JASwipeCell)

##Overview

An iOS 8 Mail Inspired. A UITableViewCell subclass that displays customizable left or right buttons that are revealed as the user swipes the cell in either direction. The edge-most buttons will pin to the container view and will execute an event similar to how the delete/archive button work in IOS 8 mail.

##Features
* Supports adding actionable buttons on either side of the cell. 
* You can customize a button's title text and color.
* Each button will have a block handler that will execute when pressed.
* The left/right most button will pin to the top container view as the user swipes all the way. This will also execute that button's action. 
* Supports IOS 7+

Example of the buttons revealing as you swipe left:

![image](http://i.imgur.com/mtGJx2f.png)

Example of the right most button pinning to the container view:

![image](http://i.imgur.com/T3v3nWB.png)

##Usage

###Available via CocoaPods

Add the following to your Podfile.

pod 'JASwipeCell'

Run pod install from your Terminal. This will install the necessary files. 

###Set up the cell

First step is to subclass `JASwipeCell.h`. You have full control of the views rendered on this cell and they must be added as subviews to JASwipeCell's topContainerView. You can use a xib file or do this in code. The example provided is done in code using [PureLayout](https://github.com/smileyborg/PureLayout).


###Set up the buttons 

Next step is to set up the left/right buttons. I've created a `JAActionButton` class that has a class method to quickly create a button with a title, background color, and completion handler. 

```objc
- (NSArray *)leftButtons
{
    __typeof(self) __weak weakSelf = self;
    JAActionButton *button1 = [JAActionButton actionButtonWithTitle:@"Delete" color:[UIColor redColor] handler:^(UIButton *actionButton, JASwipeCell*cell) {
        [cell completePinToTopViewAnimation];
        [weakSelf leftMostButtonSwipeCompleted:cell];
    }];
    
    JAActionButton *button2 = [JAActionButton actionButtonWithTitle:@"Mark as unread" color:kUnreadButtonColor handler:^(UIButton *actionButton, JASwipeCell*cell) {
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Mark As Unread" message:@"Done!" delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles:nil];
        [alert show];
    }];
    
    return @[button1, button2];
}

- (NSArray *)rightButtons
{
    __typeof(self) __weak weakSelf = self;
    JAActionButton *button1 = [JAActionButton actionButtonWithTitle:@"Archive" color:kArchiveButtonColor handler:^(UIButton *actionButton, JASwipeCell*cell) {
        [cell completePinToTopViewAnimation];
        [weakSelf rightMostButtonSwipeCompleted:cell];
    }];
    
    JAActionButton *button2 = [JAActionButton actionButtonWithTitle:@"Flag" color:kFlagButtonColor handler:^(UIButton *actionButton, JASwipeCell*cell) {
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Flag" message:@"Flag pressed!" delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles:nil];
        [alert show];
    }];
    JAActionButton *button3 = [JAActionButton actionButtonWithTitle:@"More" color:kMoreButtonColor handler:^(UIButton *actionButton, JASwipeCell*cell) {
        UIActionSheet *sheet = [[UIActionSheet alloc] initWithTitle:@"More Options" delegate:nil cancelButtonTitle:@"Cancel" destructiveButtonTitle:@"Option 1" otherButtonTitles:@"Option 2",nil];
        [sheet showInView:weakSelf.view];
    }];
    
    return @[button1, button2, button3];
}
```

###Set up the table view. 

Now you must create your cell instances using the button creation methods above.

```objc
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    JATableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kJATableViewCellReuseIdentifier];
    
    [cell addActionButtons:[self leftButtons] withButtonWidth:kJAButtonWidth withButtonPosition:JAButtonLocationLeft];
    [cell addActionButtons:[self rightButtons] withButtonWidth:kJAButtonWidth withButtonPosition:JAButtonLocationRight];
    
    cell.delegate = self;
    
    [cell configureCellWithTitle:self.tableData[indexPath.row]];
    [cell setNeedsLayout];
    [cell setNeedsUpdateConstraints];
    [cell updateConstraintsIfNeeded];
    
    return cell;
}
```

###Respond to delegate methods.

There are a list of delegate methods available that get called as swipe events occur on the cell.

```objc
@protocol JASwipeCellDelegate <NSObject>
- (void)leftMostButtonSwipeCompleted:(JASwipeCell *)cell;
- (void)rightMostButtonSwipeCompleted:(JASwipeCell *)cell;
@optional
- (void)swipingRightForCell:(JASwipeCell *)cell;
- (void)swipingLeftForCell:(JASwipeCell *)cell;
@end
```

In the project example, swiping a cell all the way to the left will trigger the "Archive" button to execute. This will call the delegate method `rightMostButtonSwipeCompleted:`, which is responsible for updating the table's data and deleting the row. 

```objc
- (void)rightMostButtonSwipeCompleted:(JASwipeCell *)cell
{
    NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
    [self.tableData removeObjectAtIndex:indexPath.row];
    
    [self.tableView beginUpdates];
    [self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
    [self.tableView endUpdates];
}
```

##Example Project
An example project is provided. It requires IOS7 and can be run on device or simulator. This will work for any device size. 

##Creator
Jose Alvarez

##License
JASwipeCell is available under the MIT license. See the LICENSE file for more info.
Download .txt
gitextract_ndxeqazj/

├── .gitignore
├── .travis.yml
├── JASwipeCell/
│   ├── JAActionButton.h
│   ├── JAActionButton.m
│   ├── JASwipeCell.h
│   └── JASwipeCell.m
├── JASwipeCell.podspec
├── JASwipeCellExample/
│   ├── ALView+PureLayout.h
│   ├── ALView+PureLayout.m
│   ├── AppDelegate.h
│   ├── AppDelegate.m
│   ├── Base.lproj/
│   │   └── Main.storyboard
│   ├── Images.xcassets/
│   │   ├── AppIcon.appiconset/
│   │   │   └── Contents.json
│   │   └── LaunchImage.launchimage/
│   │       └── Contents.json
│   ├── Info.plist
│   ├── JATableViewCell.h
│   ├── JATableViewCell.m
│   ├── JATableViewController.h
│   ├── JATableViewController.m
│   ├── NSArray+PureLayout.h
│   ├── NSArray+PureLayout.m
│   ├── NSLayoutConstraint+PureLayout.h
│   ├── NSLayoutConstraint+PureLayout.m
│   ├── PureLayout+Internal.h
│   ├── PureLayout.h
│   ├── PureLayoutDefines.h
│   └── main.m
├── JASwipeCellExample.xcodeproj/
│   ├── project.pbxproj
│   ├── project.xcworkspace/
│   │   └── contents.xcworkspacedata
│   └── xcshareddata/
│       └── xcschemes/
│           └── JASwipeCellExample.xcscheme
├── LICENSE
└── README.md
Download .txt
SYMBOL INDEX (1 symbols across 1 files)

FILE: JASwipeCell/JASwipeCell.h
  type JAButtonLocationLeft (line 31) | typedef NS_OPTIONS(NSUInteger, JAButtonLocation) {
Condensed preview — 32 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (194K chars).
[
  {
    "path": ".gitignore",
    "chars": 505,
    "preview": "# Xcode\n#\n.DS_Store\nbuild/\n*.pbxuser\n!default.pbxuser\n*.mode1v3\n!default.mode1v3\n*.mode2v3\n!default.mode2v3\n*.perspectiv"
  },
  {
    "path": ".travis.yml",
    "chars": 139,
    "preview": "language: objective-c\nscript:\n  - xctool -project JASwipeCellExample.xcodeproj -scheme JASwipeCellExample -sdk iphonesim"
  },
  {
    "path": "JASwipeCell/JAActionButton.h",
    "chars": 1839,
    "preview": "//\n//  JAActionButton.h\n//  JASwipeCell\n//\n//  Created by Jose Alvarez on 10/8/14.\n//  Copyright (c) 2014 Jose Alvarez. "
  },
  {
    "path": "JASwipeCell/JAActionButton.m",
    "chars": 2320,
    "preview": "//\n//  JAActionButton.m\n//  JASwipeCell\n//\n//  Created by Jose Alvarez on 10/8/14.\n//  Copyright (c) 2014 Jose Alvarez. "
  },
  {
    "path": "JASwipeCell/JASwipeCell.h",
    "chars": 3875,
    "preview": "//\n//  JASwipeCell.h\n//  JASwipeCell\n//\n//  Created by Jose Alvarez on 10/8/14.\n//  Copyright (c) 2014 Jose Alvarez. All"
  },
  {
    "path": "JASwipeCell/JASwipeCell.m",
    "chars": 24727,
    "preview": "//\n//  JASwipeCell.m\n//  JASwipeCell\n//\n//  Created by Jose Alvarez on 10/8/14.\n//  Copyright (c) 2014 Jose Alvarez. All"
  },
  {
    "path": "JASwipeCell.podspec",
    "chars": 1321,
    "preview": "#\n#  Be sure to run `pod spec lint JASwipeCell.podspec' to ensure this is a\n#  valid spec and to remove all comments inc"
  },
  {
    "path": "JASwipeCellExample/ALView+PureLayout.h",
    "chars": 11334,
    "preview": "//\n//  ALView+PureLayout.h\n//  v1.1.0\n//  https://github.com/smileyborg/PureLayout\n//\n//  Copyright (c) 2012 Richard Tur"
  },
  {
    "path": "JASwipeCellExample/ALView+PureLayout.m",
    "chars": 43744,
    "preview": "//\n//  ALView+PureLayout.m\n//  v1.1.0\n//  https://github.com/smileyborg/PureLayout\n//\n//  Copyright (c) 2012 Richard Tur"
  },
  {
    "path": "JASwipeCellExample/AppDelegate.h",
    "chars": 1371,
    "preview": "//\n//  AppDelegate.h\n//  JASwipeCell\n//\n//  Created by Jose Alvarez on 10/8/14.\n//  Copyright (c) 2014 Jose Alvarez. All"
  },
  {
    "path": "JASwipeCellExample/AppDelegate.m",
    "chars": 3138,
    "preview": "//\n//  AppDelegate.m\n//  JASwipeCell\n//\n//  Created by Jose Alvarez on 10/8/14.\n//  Copyright (c) 2014 Jose Alvarez. All"
  },
  {
    "path": "JASwipeCellExample/Base.lproj/Main.storyboard",
    "chars": 2882,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard"
  },
  {
    "path": "JASwipeCellExample/Images.xcassets/AppIcon.appiconset/Contents.json",
    "chars": 909,
    "preview": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\""
  },
  {
    "path": "JASwipeCellExample/Images.xcassets/LaunchImage.launchimage/Contents.json",
    "chars": 1100,
    "preview": "{\n  \"images\" : [\n    {\n      \"orientation\" : \"portrait\",\n      \"idiom\" : \"iphone\",\n      \"extent\" : \"full-screen\",\n     "
  },
  {
    "path": "JASwipeCellExample/Info.plist",
    "chars": 1446,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
  },
  {
    "path": "JASwipeCellExample/JATableViewCell.h",
    "chars": 1379,
    "preview": "//\n//  JATableViewCell.h\n//  JASwipeCell\n//\n//  Created by Jose Alvarez on 10/8/14.\n//  Copyright (c) 2014 Jose Alvarez."
  },
  {
    "path": "JASwipeCellExample/JATableViewCell.m",
    "chars": 2504,
    "preview": "//\n//  JATableViewCell.m\n//  JASwipeCell\n//\n//  Created by Jose Alvarez on 10/8/14.\n//  Copyright (c) 2014 Jose Alvarez."
  },
  {
    "path": "JASwipeCellExample/JATableViewController.h",
    "chars": 1327,
    "preview": "//\n//  JATableViewController.h\n//  JASwipeCell\n//\n//  Created by Jose Alvarez on 10/8/14.\n//  Copyright (c) 2014 Jose Al"
  },
  {
    "path": "JASwipeCellExample/JATableViewController.m",
    "chars": 9140,
    "preview": "//\n//  JATableViewController.m\n//  JASwipeCell\n//\n//  Created by Jose Alvarez on 10/8/14.\n//  Copyright (c) 2014 Jose Al"
  },
  {
    "path": "JASwipeCellExample/NSArray+PureLayout.h",
    "chars": 4248,
    "preview": "//\n//  NSArray+PureLayout.h\n//  v1.1.0\n//  https://github.com/smileyborg/PureLayout\n//\n//  Copyright (c) 2012 Richard Tu"
  },
  {
    "path": "JASwipeCellExample/NSArray+PureLayout.m",
    "chars": 16237,
    "preview": "//\n//  NSArray+PureLayout.m\n//  v1.1.0\n//  https://github.com/smileyborg/PureLayout\n//\n//  Copyright (c) 2012 Richard Tu"
  },
  {
    "path": "JASwipeCellExample/NSLayoutConstraint+PureLayout.h",
    "chars": 1689,
    "preview": "//\n//  NSLayoutConstraint+PureLayout.h\n//  v1.1.0\n//  https://github.com/smileyborg/PureLayout\n//\n//  Copyright (c) 2013"
  },
  {
    "path": "JASwipeCellExample/NSLayoutConstraint+PureLayout.m",
    "chars": 2727,
    "preview": "//\n//  NSLayoutConstraint+PureLayout.m\n//  v1.1.0\n//  https://github.com/smileyborg/PureLayout\n//\n//  Copyright (c) 2013"
  },
  {
    "path": "JASwipeCellExample/PureLayout+Internal.h",
    "chars": 2361,
    "preview": "//\n//  PureLayout+Internal.h\n//  v1.1.0\n//  https://github.com/smileyborg/PureLayout\n//\n//  Copyright (c) 2014 Tyler Fox"
  },
  {
    "path": "JASwipeCellExample/PureLayout.h",
    "chars": 1461,
    "preview": "//\n//  PureLayout.h\n//  v1.1.0\n//  https://github.com/smileyborg/PureLayout\n//\n//  Copyright (c) 2014 Tyler Fox\n//\n//  T"
  },
  {
    "path": "JASwipeCellExample/PureLayoutDefines.h",
    "chars": 5848,
    "preview": "//\n//  PureLayoutDefines.h\n//  v1.1.0\n//  https://github.com/smileyborg/PureLayout\n//\n//  Copyright (c) 2014 Tyler Fox\n/"
  },
  {
    "path": "JASwipeCellExample/main.m",
    "chars": 1429,
    "preview": "//\n//  main.m\n//  JASwipeCell\n//\n//  Created by Jose Alvarez on 10/8/14.\n//  Copyright (c) 2014 Jose Alvarez. All rights"
  },
  {
    "path": "JASwipeCellExample.xcodeproj/project.pbxproj",
    "chars": 22647,
    "preview": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXBuildFile section *"
  },
  {
    "path": "JASwipeCellExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
    "chars": 156,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"self:JASwipeCell.xco"
  },
  {
    "path": "JASwipeCellExample.xcodeproj/xcshareddata/xcschemes/JASwipeCellExample.xcscheme",
    "chars": 4348,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"0610\"\n   version = \"1.3\">\n   <BuildAction\n      "
  },
  {
    "path": "LICENSE",
    "chars": 1080,
    "preview": "The MIT License (MIT)\n\nCopyright (c) 2014 Jose Alvarez\n\nPermission is hereby granted, free of charge, to any person obta"
  },
  {
    "path": "README.md",
    "chars": 5857,
    "preview": "JASwipeCell\n===========\n\n[![Build Status](https://travis-ci.org/joseria/JASwipeCell.svg?branch=master)](https://travis-c"
  }
]

About this extraction

This page contains the full source code of the joseria/JASwipeCell GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 32 files (180.8 KB), approximately 44.7k tokens, and a symbol index with 1 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!