Import MGSwipeTableCell 7dbd771c897d3c439d0d7a3f0140fcc881e2a5a0 to provide higher-quality swipe handling than the APIs provide. This would be a great opportunity to use Git submodules, but is currently imported to match with the existing style of the code base (ShortcutRecorder, SGHotKeysLib, and UKPrefsPanel).

This commit is contained in:
Mark Jerde 2017-08-14 23:12:24 -05:00
parent 3210b31350
commit d96df4d8f2
72 changed files with 6714 additions and 0 deletions

26
MGSwipeTableCell/.gitignore vendored Normal file
View file

@ -0,0 +1,26 @@
# Xcode
#
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/

View file

@ -0,0 +1,103 @@
# Changelog
## 1.5.6
- Improve iOS 10.0 support
- Objective-C nullable annotations to improve Swift 3.0 interoperation. Add Swift 3.0 sample.
- Improve accesibility implementation to allow recording UI Tests
- Add preprocessor macro to allow compilations on App Extension projects
- Add swipeBounceRate property. Coefficient applied to cell movement in bounce zone
- Fix issue #216: Crash when combining programmatically created offset animations in consecutive block callbacks
- Fix issue #139: Accessing Buttons in UITests does not work
- Fix issue #134: Crash due to zombie object in expansion
- Fix button text alignment for RTL languages
## 1.5.5
- Fix iOS 8.0 compatibility issue
- Fix issue #190: duplicate callback
## 1.5.4
- Safer animation and callbacks checks after a cell is deleted. Fixes issue #91 caused by a null cell.indexPath because the callback was called while/after a cell is deleted
- Fix issue #168: problem with devices that read right to left (Arabic and Hebrew)
- Fix swipe issues after reloading a table
- Fix issue #163: Swipe not working after deleting a cell
- Add enableSwipeBounces property. Enabled by default, if disabled the swipe bounces will be disabled and the swipe motion will stop right after the button.
- Add allowsOppositeSwipe property. Controls whether swipe gesture is allowed in opposite directions. NO value disables swiping in opposite direction once started in one direction
- Add topMargin and bottomMargin properties to MGSwipeSettings
- Add touchOnDismissSwipe property. Controls whether dismissing a swiped cell when clicking outside of the cell generates a real touch event on the other cell. Default behaviour is the same as the Mail app on iOS. Enable it if you want to allow to start a new swipe while a cell is already in swiped.
- Add a 'BOOL finished' parameter to completion animation callbacks
## 1.5.3
- Fix duplicated callbacks with reused button instances among many cells
- Fix Carthage header for normal projects
## 1.5.2
- Add Carthage support
- Fix issues #160 and #162: Delegate call multiple time on single touch on iOS 9
- Fix programmatic call to setSwipeOffset when swipeView is not yet created
- Fix Swipe backgroundColor change without re-initializing the cell
- Fix UITableCellSelectionStyle on end swipe
- centerIconOverText now takes a spacing argument
## 1.5.1
- Fix default animation values
## 1.5.0
- Feature: Add predefined and configurable easing functions to the API. Swipe animations are now splitted into different settings so you can now use different animations (easing function, duration, etc) for each kind of animations: show swipe, hide swipe, stretch cell from already swiped buttons and more.
- Feature: Full support for Spotify App like swipe animations. Create new Spotify Demo project.
- Feature: add onlySwipeButtons property that allows to only swipe the buttons and keep the cell content static
- Feature: add fromOffset argument to the canSwipe delegate method. Useful for supporting sidebar menus with swipe to open. You can use it to restrict the cell from being swiped if the offset is to close to the edge.
- Feature: add preservesSelectionStatus property that allows to control whether selection/highlight is changed when swiped.
- Feature: add keepButtonsSwiped property to Swipe settings
- Feature: new delegate method: shouldHideSwipeOnTap:(CGPoint) point. Now you can cancel to hide opened swipe depending on the tap point
- Feature: new delegate methods: swipeTableCellWillBeginSwiping & swipeTableCellWillEndSwiping. Useful to make cell changes that only are shown after the cell is swiped open
- Fixed issue #113: Bug when changing the orientation of the device
- Fixed typo throughout readme and source of "swiping"
- Fixed issue #100: canSwipe not working when swipe to the allowed direction and swipe with inertia to the forbidden direction
- Fixed clip mask when animating expansion
- Keep expansion color while expansion is animating to 0
## 1.4.3
- Fixed crash with different class cells in multiple section tables
- Add completion handlers to convenience show/hide methods
## 1.4.2
- Fixed issue #89: Swipe fails after table reload while swipping gesture is active
## 1.4.1
- Implemented Spotify App style cell expansion: added expansionLayout and expansionColor properties to MGSwipeExpansionSettings
- New property allowsSwipeWhenTappingButtons. Fixed issue #80: swiping the cell when you swipe the buttons in the cell
- Fixed issue #78: Swift problem with one enum
- Fixed issue #82: fillOnTrigger not working properly with UITableViewCellAccessoryDisclosureIndicator
- Fixed issue #84: can't compile in xcode 6.3
- Fixed issue #76: Swiped cell state issue when table view is scrolling
## 1.4.0
- Implemented allowsButtonsWithDifferentWidth property to support buttons with different widths
- Implemented allowsMultipleSwipe feature
- Allow starting swiping on one cell while another one is open
- Keep cell's selection state when swipe is closed
- Fixed flash of the cell in its default state before the cell is deleted when fillOnTrigger is set.
- Improved MGSwipeButton. New utility methods to Center image over text, set edge insets, set a fixed with and more.
- Other minor bugfixes
## 1.3.6
- Improved gestureRecognizer ending detection. Fixed issue #50: Not able to swipe to reveal right after scrolling collection view children of cell content view
- Fixed the white background issue when the cell.backgroundColor is set to UIColor.clearColor
- Added utility method to perform swipe expansions programmatically
## 1.3.5
- Fixed issue #43: Two Cell Can Swipe simultaneously

21
MGSwipeTableCell/LICENSE Normal file
View file

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2016 Imanol Fernandez @MortimerGoro
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.

View file

@ -0,0 +1,13 @@
Pod::Spec.new do |s|
s.name = 'MGSwipeTableCell'
s.version = '1.5.6'
s.author = { 'Imanol Fernandez' => 'mortimergoro@gmail.com' }
s.homepage = 'https://github.com/MortimerGoro/MGSwipeTableCell'
s.summary = 'An easy to use UITableViewCell subclass that allows to display swipeable buttons with a variety of transitions'
s.license = 'MIT'
s.source = { :git => 'https://github.com/MortimerGoro/MGSwipeTableCell.git', :tag => s.version.to_s }
s.source_files = 'MGSwipeTableCell'
s.platform = :ios
s.ios.deployment_target = '5.0'
s.requires_arc = true
end

View file

@ -0,0 +1,297 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
C63EE56F1BBA07ED008F46BB /* MGSwipeTableCell.h in Headers */ = {isa = PBXBuildFile; fileRef = C63EE56E1BBA07ED008F46BB /* MGSwipeTableCell.h */; settings = {ATTRIBUTES = (Public, ); }; };
C63EE5881BBA083B008F46BB /* MGSwipeButton.h in Headers */ = {isa = PBXBuildFile; fileRef = C63EE5851BBA083B008F46BB /* MGSwipeButton.h */; settings = {ATTRIBUTES = (Public, ); }; };
C63EE5891BBA083B008F46BB /* MGSwipeButton.m in Sources */ = {isa = PBXBuildFile; fileRef = C63EE5861BBA083B008F46BB /* MGSwipeButton.m */; };
C63EE58A1BBA083B008F46BB /* MGSwipeTableCell.m in Sources */ = {isa = PBXBuildFile; fileRef = C63EE5871BBA083B008F46BB /* MGSwipeTableCell.m */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
C63EE56B1BBA07ED008F46BB /* MGSwipeTableCell.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MGSwipeTableCell.framework; sourceTree = BUILT_PRODUCTS_DIR; };
C63EE56E1BBA07ED008F46BB /* MGSwipeTableCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MGSwipeTableCell.h; sourceTree = "<group>"; };
C63EE5701BBA07ED008F46BB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
C63EE5851BBA083B008F46BB /* MGSwipeButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGSwipeButton.h; sourceTree = "<group>"; };
C63EE5861BBA083B008F46BB /* MGSwipeButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGSwipeButton.m; sourceTree = "<group>"; };
C63EE5871BBA083B008F46BB /* MGSwipeTableCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGSwipeTableCell.m; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
C63EE5671BBA07ED008F46BB /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
C63EE5611BBA07ED008F46BB = {
isa = PBXGroup;
children = (
C63EE56D1BBA07ED008F46BB /* MGSwipeTableCell */,
C63EE56C1BBA07ED008F46BB /* Products */,
);
sourceTree = "<group>";
};
C63EE56C1BBA07ED008F46BB /* Products */ = {
isa = PBXGroup;
children = (
C63EE56B1BBA07ED008F46BB /* MGSwipeTableCell.framework */,
);
name = Products;
sourceTree = "<group>";
};
C63EE56D1BBA07ED008F46BB /* MGSwipeTableCell */ = {
isa = PBXGroup;
children = (
C63EE56E1BBA07ED008F46BB /* MGSwipeTableCell.h */,
C63EE5851BBA083B008F46BB /* MGSwipeButton.h */,
C63EE5861BBA083B008F46BB /* MGSwipeButton.m */,
C63EE5871BBA083B008F46BB /* MGSwipeTableCell.m */,
C63EE5701BBA07ED008F46BB /* Info.plist */,
);
path = MGSwipeTableCell;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
C63EE5681BBA07ED008F46BB /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
C63EE56F1BBA07ED008F46BB /* MGSwipeTableCell.h in Headers */,
C63EE5881BBA083B008F46BB /* MGSwipeButton.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
C63EE56A1BBA07ED008F46BB /* MGSwipeTableCell */ = {
isa = PBXNativeTarget;
buildConfigurationList = C63EE57F1BBA07ED008F46BB /* Build configuration list for PBXNativeTarget "MGSwipeTableCell" */;
buildPhases = (
C63EE5661BBA07ED008F46BB /* Sources */,
C63EE5671BBA07ED008F46BB /* Frameworks */,
C63EE5681BBA07ED008F46BB /* Headers */,
C63EE5691BBA07ED008F46BB /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = MGSwipeTableCell;
productName = MGSwipeTableCell;
productReference = C63EE56B1BBA07ED008F46BB /* MGSwipeTableCell.framework */;
productType = "com.apple.product-type.framework";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
C63EE5621BBA07ED008F46BB /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0700;
ORGANIZATIONNAME = mortimergoro;
TargetAttributes = {
C63EE56A1BBA07ED008F46BB = {
CreatedOnToolsVersion = 7.0;
};
};
};
buildConfigurationList = C63EE5651BBA07ED008F46BB /* Build configuration list for PBXProject "MGSwipeTableCell" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
);
mainGroup = C63EE5611BBA07ED008F46BB;
productRefGroup = C63EE56C1BBA07ED008F46BB /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
C63EE56A1BBA07ED008F46BB /* MGSwipeTableCell */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
C63EE5691BBA07ED008F46BB /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
C63EE5661BBA07ED008F46BB /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
C63EE5891BBA083B008F46BB /* MGSwipeButton.m in Sources */,
C63EE58A1BBA083B008F46BB /* MGSwipeTableCell.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
C63EE57D1BBA07ED008F46BB /* 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;
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
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 = 9.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Debug;
};
C63EE57E1BBA07ED008F46BB /* 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 = NO;
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
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 = 9.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Release;
};
C63EE5801BBA07ED008F46BB /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = MGSwipeTableCell/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.mortimergoro.MGSwipeTableCell;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
};
name = Debug;
};
C63EE5811BBA07ED008F46BB /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = MGSwipeTableCell/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.mortimergoro.MGSwipeTableCell;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
C63EE5651BBA07ED008F46BB /* Build configuration list for PBXProject "MGSwipeTableCell" */ = {
isa = XCConfigurationList;
buildConfigurations = (
C63EE57D1BBA07ED008F46BB /* Debug */,
C63EE57E1BBA07ED008F46BB /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
C63EE57F1BBA07ED008F46BB /* Build configuration list for PBXNativeTarget "MGSwipeTableCell" */ = {
isa = XCConfigurationList;
buildConfigurations = (
C63EE5801BBA07ED008F46BB /* Debug */,
C63EE5811BBA07ED008F46BB /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = C63EE5621BBA07ED008F46BB /* Project object */;
}

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:MGSwipeTableCell.xcodeproj">
</FileRef>
</Workspace>

View file

@ -0,0 +1,26 @@
<?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>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>

View file

@ -0,0 +1,51 @@
/*
* MGSwipeTableCell is licensed under MIT license. See LICENSE.md file for more information.
* Copyright (c) 2016 Imanol Fernandez @MortimerGoro
*/
#import <UIKit/UIKit.h>
@class MGSwipeTableCell;
/**
* This is a convenience class to create MGSwipeTableCell buttons
* Using this class is optional because MGSwipeTableCell is button agnostic and can use any UIView for that purpose
* Anyway, it's recommended that you use this class because is totally tested and easy to use ;)
*/
@interface MGSwipeButton : UIButton
/**
* Convenience block callback for developers lazy to implement the MGSwipeTableCellDelegate.
* @return Return YES to autohide the swipe view
*/
typedef BOOL(^ MGSwipeButtonCallback)(MGSwipeTableCell * _Nonnull cell);
@property (nonatomic, strong, nullable) MGSwipeButtonCallback callback;
/** A width for the expanded buttons. Defaults to 0, which means sizeToFit will be called. */
@property (nonatomic, assign) CGFloat buttonWidth;
/**
* Convenience static constructors
*/
+(nonnull instancetype) buttonWithTitle:(nonnull NSString *) title backgroundColor:(nullable UIColor *) color;
+(nonnull instancetype) buttonWithTitle:(nonnull NSString *) title backgroundColor:(nullable UIColor *) color padding:(NSInteger) padding;
+(nonnull instancetype) buttonWithTitle:(nonnull NSString *) title backgroundColor:(nullable UIColor *) color insets:(UIEdgeInsets) insets;
+(nonnull instancetype) buttonWithTitle:(nonnull NSString *) title backgroundColor:(nullable UIColor *) color callback:(nullable MGSwipeButtonCallback) callback;
+(nonnull instancetype) buttonWithTitle:(nonnull NSString *) title backgroundColor:(nullable UIColor *) color padding:(NSInteger) padding callback:(nullable MGSwipeButtonCallback) callback;
+(nonnull instancetype) buttonWithTitle:(nonnull NSString *) title backgroundColor:(nullable UIColor *) color insets:(UIEdgeInsets) insets callback:(nullable MGSwipeButtonCallback) callback;
+(nonnull instancetype) buttonWithTitle:(nonnull NSString *) title icon:(nullable UIImage*) icon backgroundColor:(nullable UIColor *) color;
+(nonnull instancetype) buttonWithTitle:(nonnull NSString *) title icon:(nullable UIImage*) icon backgroundColor:(nullable UIColor *) color padding:(NSInteger) padding;
+(nonnull instancetype) buttonWithTitle:(nonnull NSString *) title icon:(nullable UIImage*) icon backgroundColor:(nullable UIColor *) color insets:(UIEdgeInsets) insets;
+(nonnull instancetype) buttonWithTitle:(nonnull NSString *) title icon:(nullable UIImage*) icon backgroundColor:(nullable UIColor *) color callback:(nullable MGSwipeButtonCallback) callback;
+(nonnull instancetype) buttonWithTitle:(nonnull NSString *) title icon:(nullable UIImage*) icon backgroundColor:(nullable UIColor *) color padding:(NSInteger) padding callback:(nullable MGSwipeButtonCallback) callback;
+(nonnull instancetype) buttonWithTitle:(nonnull NSString *) title icon:(nullable UIImage*) icon backgroundColor:(nullable UIColor *) color insets:(UIEdgeInsets) insets callback:(nullable MGSwipeButtonCallback) callback;
-(void) setPadding:(CGFloat) padding;
-(void) setEdgeInsets:(UIEdgeInsets)insets;
-(void) centerIconOverText;
-(void) centerIconOverTextWithSpacing: (CGFloat) spacing;
-(void) iconTintColor:(nullable UIColor *)tintColor;
@end

View file

@ -0,0 +1,159 @@
/*
* MGSwipeTableCell is licensed under MIT license. See LICENSE.md file for more information.
* Copyright (c) 2016 Imanol Fernandez @MortimerGoro
*/
#import "MGSwipeButton.h"
@class MGSwipeTableCell;
@implementation MGSwipeButton
+(instancetype) buttonWithTitle:(NSString *) title backgroundColor:(UIColor *) color
{
return [self buttonWithTitle:title icon:nil backgroundColor:color];
}
+(instancetype) buttonWithTitle:(NSString *) title backgroundColor:(UIColor *) color padding:(NSInteger) padding
{
return [self buttonWithTitle:title icon:nil backgroundColor:color insets:UIEdgeInsetsMake(0, padding, 0, padding)];
}
+(instancetype) buttonWithTitle:(NSString *) title backgroundColor:(UIColor *) color insets:(UIEdgeInsets) insets
{
return [self buttonWithTitle:title icon:nil backgroundColor:color insets:insets];
}
+(instancetype) buttonWithTitle:(NSString *) title backgroundColor:(UIColor *) color callback:(MGSwipeButtonCallback) callback
{
return [self buttonWithTitle:title icon:nil backgroundColor:color callback:callback];
}
+(instancetype) buttonWithTitle:(NSString *) title backgroundColor:(UIColor *) color padding:(NSInteger) padding callback:(MGSwipeButtonCallback) callback
{
return [self buttonWithTitle:title icon:nil backgroundColor:color insets:UIEdgeInsetsMake(0, padding, 0, padding) callback:callback];
}
+(instancetype) buttonWithTitle:(NSString *) title backgroundColor:(UIColor *) color insets:(UIEdgeInsets) insets callback:(MGSwipeButtonCallback) callback
{
return [self buttonWithTitle:title icon:nil backgroundColor:color insets:insets callback:callback];
}
+(instancetype) buttonWithTitle:(NSString *) title icon:(UIImage*) icon backgroundColor:(UIColor *) color
{
return [self buttonWithTitle:title icon:icon backgroundColor:color callback:nil];
}
+(instancetype) buttonWithTitle:(NSString *) title icon:(UIImage*) icon backgroundColor:(UIColor *) color padding:(NSInteger) padding
{
return [self buttonWithTitle:title icon:icon backgroundColor:color insets:UIEdgeInsetsMake(0, padding, 0, padding) callback:nil];
}
+(instancetype) buttonWithTitle:(NSString *) title icon:(UIImage*) icon backgroundColor:(UIColor *) color insets:(UIEdgeInsets) insets
{
return [self buttonWithTitle:title icon:icon backgroundColor:color insets:insets callback:nil];
}
+(instancetype) buttonWithTitle:(NSString *) title icon:(UIImage*) icon backgroundColor:(UIColor *) color callback:(MGSwipeButtonCallback) callback
{
return [self buttonWithTitle:title icon:icon backgroundColor:color padding:10 callback:callback];
}
+(instancetype) buttonWithTitle:(NSString *) title icon:(UIImage*) icon backgroundColor:(UIColor *) color padding:(NSInteger) padding callback:(MGSwipeButtonCallback) callback
{
return [self buttonWithTitle:title icon:icon backgroundColor:color insets:UIEdgeInsetsMake(0, padding, 0, padding) callback:callback];
}
+(instancetype) buttonWithTitle:(NSString *) title icon:(UIImage*) icon backgroundColor:(UIColor *) color insets:(UIEdgeInsets) insets callback:(MGSwipeButtonCallback) callback
{
MGSwipeButton * button = [self buttonWithType:UIButtonTypeCustom];
button.backgroundColor = color;
button.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
button.titleLabel.textAlignment = NSTextAlignmentCenter;
[button setTitle:title forState:UIControlStateNormal];
[button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[button setImage:icon forState:UIControlStateNormal];
button.callback = callback;
[button setEdgeInsets:insets];
return button;
}
-(BOOL) callMGSwipeConvenienceCallback: (MGSwipeTableCell *) sender
{
if (_callback) {
return _callback(sender);
}
return NO;
}
-(void) centerIconOverText
{
[self centerIconOverTextWithSpacing: 3.0];
}
-(void) centerIconOverTextWithSpacing: (CGFloat) spacing {
CGSize size = self.imageView.image.size;
if ([UIDevice currentDevice].systemVersion.floatValue >= 9.0 && [UIApplication sharedApplication].userInterfaceLayoutDirection == UIUserInterfaceLayoutDirectionRightToLeft) {
self.titleEdgeInsets = UIEdgeInsetsMake(0.0,
0.0,
-(size.height + spacing),
-size.width);
size = [self.titleLabel.text sizeWithAttributes:@{ NSFontAttributeName: self.titleLabel.font }];
self.imageEdgeInsets = UIEdgeInsetsMake(-(size.height + spacing),
-size.width,
0.0,
0.0);
}
else
{
self.titleEdgeInsets = UIEdgeInsetsMake(0.0,
-size.width,
-(size.height + spacing),
0.0);
size = [self.titleLabel.text sizeWithAttributes:@{ NSFontAttributeName: self.titleLabel.font }];
self.imageEdgeInsets = UIEdgeInsetsMake(-(size.height + spacing),
0.0,
0.0,
-size.width);
}
}
-(void) setPadding:(CGFloat) padding
{
self.contentEdgeInsets = UIEdgeInsetsMake(0, padding, 0, padding);
[self sizeToFit];
}
- (void)setButtonWidth:(CGFloat)buttonWidth
{
_buttonWidth = buttonWidth;
if (_buttonWidth > 0)
{
CGRect frame = self.frame;
frame.size.width = _buttonWidth;
self.frame = frame;
}
else
{
[self sizeToFit];
}
}
-(void) setEdgeInsets:(UIEdgeInsets)insets
{
self.contentEdgeInsets = insets;
[self sizeToFit];
}
-(void) iconTintColor:(UIColor *)tintColor
{
UIImage *currentIcon = self.imageView.image;
if (currentIcon.renderingMode != UIImageRenderingModeAlwaysTemplate) {
currentIcon = [currentIcon imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
[self setImage:currentIcon forState:UIControlStateNormal];
}
self.tintColor = tintColor;
}
@end

View file

@ -0,0 +1,276 @@
/*
* MGSwipeTableCell is licensed under MIT license. See LICENSE.md file for more information.
* Copyright (c) 2016 Imanol Fernandez @MortimerGoro
*/
#import <UIKit/UIKit.h>
#import "MGSwipeButton.h"
/** Transition types */
typedef NS_ENUM(NSInteger, MGSwipeTransition) {
MGSwipeTransitionBorder = 0,
MGSwipeTransitionStatic,
MGSwipeTransitionDrag,
MGSwipeTransitionClipCenter,
MGSwipeTransitionRotate3D
};
/** Compatibility with older versions */
#define MGSwipeTransition3D MGSwipeTransitionRotate3D
#define MGSwipeStateSwippingLeftToRight MGSwipeStateSwipingLeftToRight
#define MGSwipeStateSwippingRightToLeft MGSwipeStateSwipingRightToLeft
/** Swipe directions */
typedef NS_ENUM(NSInteger, MGSwipeDirection) {
MGSwipeDirectionLeftToRight = 0,
MGSwipeDirectionRightToLeft
};
/** Swipe state */
typedef NS_ENUM(NSInteger, MGSwipeState) {
MGSwipeStateNone = 0,
MGSwipeStateSwipingLeftToRight,
MGSwipeStateSwipingRightToLeft,
MGSwipeStateExpandingLeftToRight,
MGSwipeStateExpandingRightToLeft,
};
/** Swipe state */
typedef NS_ENUM(NSInteger, MGSwipeExpansionLayout) {
MGSwipeExpansionLayoutBorder = 0,
MGSwipeExpansionLayoutCenter,
MGSwipeExpansionLayoutNone
};
/** Swipe Easing Function */
typedef NS_ENUM(NSInteger, MGSwipeEasingFunction) {
MGSwipeEasingFunctionLinear = 0,
MGSwipeEasingFunctionQuadIn,
MGSwipeEasingFunctionQuadOut,
MGSwipeEasingFunctionQuadInOut,
MGSwipeEasingFunctionCubicIn,
MGSwipeEasingFunctionCubicOut,
MGSwipeEasingFunctionCubicInOut,
MGSwipeEasingFunctionBounceIn,
MGSwipeEasingFunctionBounceOut,
MGSwipeEasingFunctionBounceInOut
};
/**
* Swipe animation settings
**/
@interface MGSwipeAnimation : NSObject
/** Animation duration in seconds. Default value 0.3 */
@property (nonatomic, assign) CGFloat duration;
/** Animation easing function. Default value EaseOutBounce */
@property (nonatomic, assign) MGSwipeEasingFunction easingFunction;
/** Override this method to implement custom easing functions */
-(CGFloat) value:(CGFloat) elapsed duration:(CGFloat) duration from:(CGFloat) from to:(CGFloat) to;
@end
/**
* Swipe settings
**/
@interface MGSwipeSettings: NSObject
/** Transition used while swiping buttons */
@property (nonatomic, assign) MGSwipeTransition transition;
/** Size proportional threshold to hide/keep the buttons when the user ends swiping. Default value 0.5 */
@property (nonatomic, assign) CGFloat threshold;
/** Optional offset to change the swipe buttons position. Relative to the cell border position. Default value: 0
** For example it can be used to avoid cropped buttons when sectionIndexTitlesForTableView is used in the UITableView
**/
@property (nonatomic, assign) CGFloat offset;
/** Top margin of the buttons relative to the contentView */
@property (nonatomic, assign) CGFloat topMargin;
/** Bottom margin of the buttons relative to the contentView */
@property (nonatomic, assign) CGFloat bottomMargin;
/** Distance between the buttons. Default value : 0 */
@property (nonatomic, assign) CGFloat buttonsDistance;
/** Animation settings when the swipe buttons are shown */
@property (nonatomic, strong, nonnull) MGSwipeAnimation * showAnimation;
/** Animation settings when the swipe buttons are hided */
@property (nonatomic, strong, nonnull) MGSwipeAnimation * hideAnimation;
/** Animation settings when the cell is stretched from the swipe buttons */
@property (nonatomic, strong, nonnull) MGSwipeAnimation * stretchAnimation;
/** Property to read or change swipe animation durations. Default value 0.3 */
@property (nonatomic, assign) CGFloat animationDuration DEPRECATED_ATTRIBUTE;
/** If true the buttons are kept swiped when the threshold is reached and the user ends the gesture
* If false, the buttons are always hidden when the user ends the swipe gesture
*/
@property (nonatomic, assign) BOOL keepButtonsSwiped;
/** If true the table cell is not swiped, just the buttons **/
@property (nonatomic, assign) BOOL onlySwipeButtons;
/** If NO the swipe bounces will be disabled, the swipe motion will stop right after the button */
@property (nonatomic, assign) BOOL enableSwipeBounces;
/** Coefficient applied to cell movement in bounce zone. Set to value between 0.0 and 1.0
to make the cell 'resist' swiping after buttons are revealed. Default is 1.0 */
@property (nonatomic, assign) CGFloat swipeBounceRate;
@end
/**
* Expansion settings to make expandable buttons
* Swipe button are not expandable by default
**/
@interface MGSwipeExpansionSettings: NSObject
/** index of the expandable button (in the left or right buttons arrays) */
@property (nonatomic, assign) NSInteger buttonIndex;
/** if true the button fills the cell on trigger, else it bounces back to its initial position */
@property (nonatomic, assign) BOOL fillOnTrigger;
/** Size proportional threshold to trigger the expansion button. Default value 1.5 */
@property (nonatomic, assign) CGFloat threshold;
/** Optional expansion color. Expanded button's background color is used by default **/
@property (nonatomic, strong, nullable) UIColor * expansionColor;
/** Defines the layout of the expanded button **/
@property (nonatomic, assign) MGSwipeExpansionLayout expansionLayout;
/** Animation settings when the expansion is triggered **/
@property (nonatomic, strong, nonnull) MGSwipeAnimation * triggerAnimation;
/** Property to read or change expansion animation durations. Default value 0.2
* The target animation is the change of a button from normal state to expanded state
*/
@property (nonatomic, assign) CGFloat animationDuration;
@end
/** helper forward declaration */
@class MGSwipeTableCell;
/**
* Optional delegate to configure swipe buttons or to receive triggered actions.
* Buttons can be configured inline when the cell is created instead of using this delegate,
* but using the delegate improves memory usage because buttons are only created in demand
*/
@protocol MGSwipeTableCellDelegate <NSObject>
@optional
/**
* Delegate method to enable/disable swipe gestures
* @return YES if swipe is allowed
**/
-(BOOL) swipeTableCell:(nonnull MGSwipeTableCell*) cell canSwipe:(MGSwipeDirection) direction fromPoint:(CGPoint) point;
-(BOOL) swipeTableCell:(nonnull MGSwipeTableCell*) cell canSwipe:(MGSwipeDirection) direction DEPRECATED_ATTRIBUTE; //backwards compatibility
/**
* Delegate method invoked when the current swipe state changes
@param state the current Swipe State
@param gestureIsActive YES if the user swipe gesture is active. No if the uses has already ended the gesture
**/
-(void) swipeTableCell:(nonnull MGSwipeTableCell*) cell didChangeSwipeState:(MGSwipeState) state gestureIsActive:(BOOL) gestureIsActive;
/**
* Called when the user clicks a swipe button or when a expandable button is automatically triggered
* @return YES to autohide the current swipe buttons
**/
-(BOOL) swipeTableCell:(nonnull MGSwipeTableCell*) cell tappedButtonAtIndex:(NSInteger) index direction:(MGSwipeDirection)direction fromExpansion:(BOOL) fromExpansion;
/**
* Delegate method to setup the swipe buttons and swipe/expansion settings
* Buttons can be any kind of UIView but it's recommended to use the convenience MGSwipeButton class
* Setting up buttons with this delegate instead of using cell properties improves memory usage because buttons are only created in demand
* @param cell the UITableViewCell to configure. You can get the indexPath using [tableView indexPathForCell:cell]
* @param direction The swipe direction (left to right or right to left)
* @param swipeSettings instance to configure the swipe transition and setting (optional)
* @param expansionSettings instance to configure button expansions (optional)
* @return Buttons array
**/
-(nullable NSArray<UIView*>*) swipeTableCell:(nonnull MGSwipeTableCell*) cell swipeButtonsForDirection:(MGSwipeDirection)direction
swipeSettings:(nonnull MGSwipeSettings*) swipeSettings expansionSettings:(nonnull MGSwipeExpansionSettings*) expansionSettings;
/**
* Called when the user taps on a swiped cell
* @return YES to autohide the current swipe buttons
**/
-(BOOL) swipeTableCell:(nonnull MGSwipeTableCell *)cell shouldHideSwipeOnTap:(CGPoint) point;
/**
* Called when the cell will begin swiping
* Useful to make cell changes that only are shown after the cell is swiped open
**/
-(void) swipeTableCellWillBeginSwiping:(nonnull MGSwipeTableCell *) cell;
/**
* Called when the cell will end swiping
**/
-(void) swipeTableCellWillEndSwiping:(nonnull MGSwipeTableCell *) cell;
@end
/**
* Swipe Cell class
* To implement swipe cells you have to override from this class
* You can create the cells programmatically, using xibs or storyboards
*/
@interface MGSwipeTableCell : UITableViewCell
/** optional delegate (not retained) */
@property (nonatomic, weak, nullable) id<MGSwipeTableCellDelegate> delegate;
/** optional to use contentView alternative. Use this property instead of contentView to support animated views while swiping */
@property (nonatomic, strong, readonly, nonnull) UIView * swipeContentView;
/**
* Left and right swipe buttons and its settings.
* Buttons can be any kind of UIView but it's recommended to use the convenience MGSwipeButton class
*/
@property (nonatomic, copy, nonnull) NSArray<UIView*> * leftButtons;
@property (nonatomic, copy, nonnull) NSArray<UIView*> * rightButtons;
@property (nonatomic, strong, nonnull) MGSwipeSettings * leftSwipeSettings;
@property (nonatomic, strong, nonnull) MGSwipeSettings * rightSwipeSettings;
/** Optional settings to allow expandable buttons */
@property (nonatomic, strong, nonnull) MGSwipeExpansionSettings * leftExpansion;
@property (nonatomic, strong, nonnull) MGSwipeExpansionSettings * rightExpansion;
/** Readonly property to fetch the current swipe state */
@property (nonatomic, readonly) MGSwipeState swipeState;
/** Readonly property to check if the user swipe gesture is currently active */
@property (nonatomic, readonly) BOOL isSwipeGestureActive;
// default is NO. Controls whether multiple cells can be swiped simultaneously
@property (nonatomic) BOOL allowsMultipleSwipe;
// default is NO. Controls whether buttons with different width are allowed. Buttons are resized to have the same size by default.
@property (nonatomic) BOOL allowsButtonsWithDifferentWidth;
//default is YES. Controls whether swipe gesture is allowed when the touch starts into the swiped buttons
@property (nonatomic) BOOL allowsSwipeWhenTappingButtons;
//default is YES. Controls whether swipe gesture is allowed in opposite directions. NO value disables swiping in opposite direction once started in one direction
@property (nonatomic) BOOL allowsOppositeSwipe;
// default is NO. Controls whether the cell selection/highlight status is preserved when expansion occurs
@property (nonatomic) BOOL preservesSelectionStatus;
/* default is NO. Controls whether dismissing a swiped cell when tapping outside of the cell generates a real touch event on the other cell.
Default behaviour is the same as the Mail app on iOS. Enable it if you want to allow to start a new swipe while a cell is already in swiped in a single step. */
@property (nonatomic) BOOL touchOnDismissSwipe;
/** Optional background color for swipe overlay. If not set, its inferred automatically from the cell contentView */
@property (nonatomic, strong, nullable) UIColor * swipeBackgroundColor;
/** Property to read or change the current swipe offset programmatically */
@property (nonatomic, assign) CGFloat swipeOffset;
/** Utility methods to show or hide swipe buttons programmatically */
-(void) hideSwipeAnimated: (BOOL) animated;
-(void) hideSwipeAnimated: (BOOL) animated completion:(nullable void(^)(BOOL finished)) completion;
-(void) showSwipe: (MGSwipeDirection) direction animated: (BOOL) animated;
-(void) showSwipe: (MGSwipeDirection) direction animated: (BOOL) animated completion:(nullable void(^)(BOOL finished)) completion;
-(void) setSwipeOffset:(CGFloat)offset animated: (BOOL) animated completion:(nullable void(^)(BOOL finished)) completion;
-(void) setSwipeOffset:(CGFloat)offset animation: (nullable MGSwipeAnimation *) animation completion:(nullable void(^)(BOOL finished)) completion;
-(void) expandSwipe: (MGSwipeDirection) direction animated: (BOOL) animated;
/** Refresh method to be used when you want to update the cell contents while the user is swiping */
-(void) refreshContentView;
/** Refresh method to be used when you want to dynamically change the left or right buttons (add or remove)
* If you only want to change the title or the backgroundColor of a button you can change it's properties (get the button instance from leftButtons or rightButtons arrays)
* @param usingDelegate if YES new buttons will be fetched using the MGSwipeTableCellDelegate. Otherwise new buttons will be fetched from leftButtons/rightButtons properties.
*/
-(void) refreshButtons: (BOOL) usingDelegate;
@end

File diff suppressed because it is too large Load diff

222
MGSwipeTableCell/README.md Normal file
View file

@ -0,0 +1,222 @@
MGSwipeTableCell
================
[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)
MGSwipeTableCell is an easy to use UITableViewCell subclass that allows to display swipeable buttons with a variety of transitions.
This library is compatible with all the different ways to create a UITableViewCell: system predefined styles, programmatically created cells, cells loaded from a xib and prototype cells within a storyboard. You can use autolayout if you want.
Works on iOS >= 5.0. Tested on all iOS versions on iPhone and iPad: iOS 5, iOS 6, iOS 7 and iOS 8.
## Transitions demo
### Border transition
<p align="center"><img src="https://raw.githubusercontent.com/MortimerGoro/MGSwipeTableCell/master/readme-assets/border.gif" /></p>
### Clip transition
<p align="center"><img src="https://raw.githubusercontent.com/MortimerGoro/MGSwipeTableCell/master/readme-assets/clip.gif" /></p>
### 3D transition
<p align="center"><img src="https://raw.githubusercontent.com/MortimerGoro/MGSwipeTableCell/master/readme-assets/3d.gif" /></p>
### Static transition
<p align="center"><img src="https://raw.githubusercontent.com/MortimerGoro/MGSwipeTableCell/master/readme-assets/static.gif" /></p>
### Drag transition
<p align="center"><img src="https://raw.githubusercontent.com/MortimerGoro/MGSwipeTableCell/master/readme-assets/drag.gif" /></p>
## API Reference
See [`MGSwipeTableCell.h`](MGSwipeTableCell/MGSwipeTableCell.h) header file for a complete overview of the capabilities of the class.
See [`MailAppDemo`](demo/MailAppDemo) for a complete project which mimics Apple's Mail App (written in Objective-C)
See [`MailAppDemoSwift`](demo/MailAppDemoSwift) for a complete project which mimics Apple's Mail App (Written in Swift)
See [`SpotifyDemo`](demo/SpotifyDemo) for a complete project which mimics Spotify App swipe style
See [`MGSwipeDemo`](demo/MGSwipeDemo) for a complete project where you can test the variety of transitions on a real device/simulator.
##Setup your project
You can use CocoaPods to include MGSwipeTableCell into you project:
pod 'MGSwipeTableCell'
You can use Carthage to include MGSwipeTableCell into your project. Just add this dependency to your Cartfile:
github "MortimerGoro/MGSwipeTableCell"
## Usage
### Basic
Integrating MGSwipeTableCell in your project is very easy. Basically, you only have to inherit from MGSwipeTableCell instead of UITableViewCell, or directly instantiate MGSwipeTableCell instances with iOS predefined cell styles. You can layout your cell content as you are used to do, MGSwipeTableCell doesn't force you to change layouts.
Here is a example of a MGSwipeTableCell using iOS predefined styles. You can set an array of buttons to cell.leftButtons and/or cell.rightButtons properties. MGSwipeButton is a convenience class, you are not forced to use it. You can use your own UIButtons or UIViews. You can configure transitions (and swipe thresholds) with the leftSwipeSettings and/or rightSwipeSettings properties
##### Objective-C
```objc
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString * reuseIdentifier = @"programmaticCell";
MGSwipeTableCell * cell = [self.tableView dequeueReusableCellWithIdentifier:reuseIdentifier];
if (!cell) {
cell = [[MGSwipeTableCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:reuseIdentifier];
}
cell.textLabel.text = @"Title";
cell.detailTextLabel.text = @"Detail text";
cell.delegate = self; //optional
//configure left buttons
cell.leftButtons = @[[MGSwipeButton buttonWithTitle:@"" icon:[UIImage imageNamed:@"check.png"] backgroundColor:[UIColor greenColor]],
[MGSwipeButton buttonWithTitle:@"" icon:[UIImage imageNamed:@"fav.png"] backgroundColor:[UIColor blueColor]]];
cell.leftSwipeSettings.transition = MGSwipeTransition3D;
//configure right buttons
cell.rightButtons = @[[MGSwipeButton buttonWithTitle:@"Delete" backgroundColor:[UIColor redColor]],
[MGSwipeButton buttonWithTitle:@"More" backgroundColor:[UIColor lightGrayColor]]];
cell.rightSwipeSettings.transition = MGSwipeTransition3D;
return cell;
}
```
##### Swift
```swift
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let reuseIdentifier = "programmaticCell"
var cell = tableView.dequeueReusableCell(withIdentifier: reuseIdentifier, for: indexPath) as! MGSwipeTableCell
cell.textLabel!.text = "Title"
cell.detailTextLabel!.text = "Detail text"
cell.delegate = self //optional
//configure left buttons
cell.leftButtons = [MGSwipeButton(title: "", icon: UIImage(named:"check.png"), backgroundColor: .green),
MGSwipeButton(title: "", icon: UIImage(named:"fav.png"), backgroundColor: .blue)]
cell.leftSwipeSettings.transition = .rotate3D
//configure right buttons
cell.rightButtons = [MGSwipeButton(title: "Delete", backgroundColor: .red),
MGSwipeButton(title: "More",backgroundColor: .lightGray)]
cell.rightSwipeSettings.transition = .rotate3D
return cell
}
```
In order to listen for button click events you can implement the optional MGSwipeTableCellDelegate, or if you are too lazy to do that, the MGSwipeButton class comes with a convenience block callback ;)
##### Objective-c
```objc
[MGSwipeButton buttonWithTitle:@"More" backgroundColor:[UIColor lightGrayColor] callback:^BOOL(MGSwipeTableCell *sender) {
NSLog(@"Convenience callback for swipe buttons!");
}]
```
##### Swift
```swift
MGSwipeButton(title: "Delete", backgroundColor: .red) {
(sender: MGSwipeTableCell!) -> Bool in
print("Convenience callback for swipe buttons!")
return true
}
```
### Delegate
MGSwipeTableCellDelegate is an optional delegate to configure swipe buttons or to receive triggered actions or another events. Buttons can be configured inline when the cell is created instead of using this delegate, but using the delegate improves memory usage since buttons are only created on demand.
```objc
@protocol MGSwipeTableCellDelegate <NSObject>
@optional
/**
* Delegate method to enable/disable swipe gestures
* @return YES if swipe is allowed
**/
-(BOOL) swipeTableCell:(MGSwipeTableCell*) cell canSwipe:(MGSwipeDirection) direction;
/**
* Delegate method invoked when the current swipe state changes
@param state the current Swipe State
@param gestureIsActive YES if the user swipe gesture is active. No if the uses has already ended the gesture
**/
-(void) swipeTableCell:(MGSwipeTableCell*) cell didChangeSwipeState:(MGSwipeState) state gestureIsActive:(BOOL) gestureIsActive;
/**
* Called when the user clicks a swipe button or when a expandable button is automatically triggered
* @return YES to autohide the current swipe buttons
**/
-(BOOL) swipeTableCell:(MGSwipeTableCell*) cell tappedButtonAtIndex:(NSInteger) index direction:(MGSwipeDirection)direction fromExpansion:(BOOL) fromExpansion;
/**
* Delegate method to setup the swipe buttons and swipe/expansion settings
* Buttons can be any kind of UIView but it's recommended to use the convenience MGSwipeButton class
* Setting up buttons with this delegate instead of using cell properties improves memory usage because buttons are only created in demand
* @param swipeTableCell the UITableVieCel to configure. You can get the indexPath using [tableView indexPathForCell:cell]
* @param direction The swipe direction (left to right or right to left)
* @param swipeSettings instance to configure the swipe transition and setting (optional)
* @param expansionSettings instance to configure button expansions (optional)
* @return Buttons array
**/
-(NSArray*) swipeTableCell:(MGSwipeTableCell*) cell swipeButtonsForDirection:(MGSwipeDirection)direction
swipeSettings:(MGSwipeSettings*) swipeSettings expansionSettings:(MGSwipeExpansionSettings*) expansionSettings;
@end
```
### Expandable buttons
Buttons are not expandable by default. You can set up expandable buttons using cell.leftExpansion and cell.rightExpansion properties
Expandable button events are triggered automatically when the user ends the swipe gesture and the expansion is active (configurable via threshold value). Triggered expandable buttons can bounce back to their initial position or fill the entire UITableViewCell, you can select the desired animation using fillOnTrigger property.
```objc
@interface MGSwipeExpansionSettings: NSObject
/** index of the expandable button (in the left or right buttons arrays) */
@property (nonatomic, assign) NSInteger buttonIndex;
/** if true the button fills the cell on trigger, else it bounces back to its initial position */
@property (nonatomic, assign) BOOL fillOnTrigger;
/** Size proportional threshold to trigger the expansion button. Default value 1.5 */
@property (nonatomic, assign) CGFloat threshold;
@end
```
### Rounded corners and swipe buttons
MGSwipeTableCell supports rounded corners. Example:
```objc
cell.layer.cornerRadius = 50
cell.backgroundColor = UIColor.gray
cell.clipsToBounds = true
cell.swipeBackgroundColor = UIColor.gray
```
<p align="center"><img src="https://github.com/MortimerGoro/MGSwipeTableCell/blob/master/readme-assets/RoundTableViewCell.png" width="30%" /></p>
## License
The MIT License (MIT)
Copyright (c) 2014 Imanol Fernandez @MortimerGoro
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.

View file

@ -0,0 +1,374 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
1130ABC61AAA6B3400BEB4D3 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 1130ABC51AAA6B3400BEB4D3 /* LaunchScreen.xib */; };
113D5E101996AD7400066AE3 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 113D5E0F1996AD7400066AE3 /* Foundation.framework */; };
113D5E121996AD7400066AE3 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 113D5E111996AD7400066AE3 /* CoreGraphics.framework */; };
113D5E141996AD7400066AE3 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 113D5E131996AD7400066AE3 /* UIKit.framework */; };
113D5E1A1996AD7400066AE3 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 113D5E181996AD7400066AE3 /* InfoPlist.strings */; };
113D5E1C1996AD7400066AE3 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 113D5E1B1996AD7400066AE3 /* main.m */; };
113D5E201996AD7400066AE3 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 113D5E1F1996AD7400066AE3 /* AppDelegate.m */; };
113D5E221996AD7400066AE3 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 113D5E211996AD7400066AE3 /* Images.xcassets */; };
1146855619D4609F00D28118 /* background.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 1146855519D4609F00D28118 /* background.jpg */; };
1162A9611996AECA00A1DC80 /* TestData.m in Sources */ = {isa = PBXBuildFile; fileRef = 1162A9601996AECA00A1DC80 /* TestData.m */; };
11CF2E9B19D7357F0092A789 /* MGSwipeButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 11CF2E9919D7357F0092A789 /* MGSwipeButton.m */; };
11CF2E9C19D7357F0092A789 /* MGSwipeTableCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 11CF2E9A19D7357F0092A789 /* MGSwipeTableCell.m */; };
11D0A0141996AFDE008D8809 /* DemoViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 11D0A0131996AFDE008D8809 /* DemoViewController.m */; };
11D0A0181996AFF1008D8809 /* check@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 11D0A0151996AFF1008D8809 /* check@2x.png */; };
11D0A0191996AFF1008D8809 /* fav@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 11D0A0161996AFF1008D8809 /* fav@2x.png */; };
11D0A01A1996AFF1008D8809 /* menu@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 11D0A0171996AFF1008D8809 /* menu@2x.png */; };
11D0A01C1996B2BE008D8809 /* autolayout_test.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 11D0A01B1996B2BE008D8809 /* autolayout_test.storyboard */; };
11D0A01E1996C339008D8809 /* cat@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 11D0A01D1996C339008D8809 /* cat@2x.png */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
1130ABC51AAA6B3400BEB4D3 /* LaunchScreen.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = LaunchScreen.xib; sourceTree = "<group>"; };
113D5E0C1996AD7400066AE3 /* MGSwipeDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MGSwipeDemo.app; sourceTree = BUILT_PRODUCTS_DIR; };
113D5E0F1996AD7400066AE3 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
113D5E111996AD7400066AE3 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
113D5E131996AD7400066AE3 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
113D5E171996AD7400066AE3 /* MGSwipeDemo-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "MGSwipeDemo-Info.plist"; sourceTree = "<group>"; };
113D5E191996AD7400066AE3 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
113D5E1B1996AD7400066AE3 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
113D5E1D1996AD7400066AE3 /* MGSwipeDemo-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "MGSwipeDemo-Prefix.pch"; sourceTree = "<group>"; };
113D5E1E1996AD7400066AE3 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
113D5E1F1996AD7400066AE3 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
113D5E211996AD7400066AE3 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
113D5E281996AD7400066AE3 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; };
1146855519D4609F00D28118 /* background.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; name = background.jpg; path = assets/background.jpg; sourceTree = "<group>"; };
1162A9601996AECA00A1DC80 /* TestData.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TestData.m; sourceTree = "<group>"; };
1162A9621996AEDA00A1DC80 /* TestData.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TestData.h; sourceTree = "<group>"; };
11CF2E9719D7357F0092A789 /* MGSwipeButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MGSwipeButton.h; path = ../../MGSwipeTableCell/MGSwipeButton.h; sourceTree = "<group>"; };
11CF2E9819D7357F0092A789 /* MGSwipeTableCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MGSwipeTableCell.h; path = ../../MGSwipeTableCell/MGSwipeTableCell.h; sourceTree = "<group>"; };
11CF2E9919D7357F0092A789 /* MGSwipeButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGSwipeButton.m; path = ../../MGSwipeTableCell/MGSwipeButton.m; sourceTree = "<group>"; };
11CF2E9A19D7357F0092A789 /* MGSwipeTableCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGSwipeTableCell.m; path = ../../MGSwipeTableCell/MGSwipeTableCell.m; sourceTree = "<group>"; };
11D0A0121996AFDE008D8809 /* DemoViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DemoViewController.h; sourceTree = "<group>"; };
11D0A0131996AFDE008D8809 /* DemoViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DemoViewController.m; sourceTree = "<group>"; };
11D0A0151996AFF1008D8809 /* check@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "check@2x.png"; path = "assets/check@2x.png"; sourceTree = "<group>"; };
11D0A0161996AFF1008D8809 /* fav@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "fav@2x.png"; path = "assets/fav@2x.png"; sourceTree = "<group>"; };
11D0A0171996AFF1008D8809 /* menu@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "menu@2x.png"; path = "assets/menu@2x.png"; sourceTree = "<group>"; };
11D0A01B1996B2BE008D8809 /* autolayout_test.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = autolayout_test.storyboard; sourceTree = "<group>"; };
11D0A01D1996C339008D8809 /* cat@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "cat@2x.png"; path = "assets/cat@2x.png"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
113D5E091996AD7400066AE3 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
113D5E121996AD7400066AE3 /* CoreGraphics.framework in Frameworks */,
113D5E141996AD7400066AE3 /* UIKit.framework in Frameworks */,
113D5E101996AD7400066AE3 /* Foundation.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
113D5E031996AD7400066AE3 = {
isa = PBXGroup;
children = (
1162A9581996AE0E00A1DC80 /* MGSwipeTableCell */,
113D5E151996AD7400066AE3 /* MGSwipeDemo */,
113D5E0E1996AD7400066AE3 /* Frameworks */,
113D5E0D1996AD7400066AE3 /* Products */,
);
sourceTree = "<group>";
};
113D5E0D1996AD7400066AE3 /* Products */ = {
isa = PBXGroup;
children = (
113D5E0C1996AD7400066AE3 /* MGSwipeDemo.app */,
);
name = Products;
sourceTree = "<group>";
};
113D5E0E1996AD7400066AE3 /* Frameworks */ = {
isa = PBXGroup;
children = (
113D5E0F1996AD7400066AE3 /* Foundation.framework */,
113D5E111996AD7400066AE3 /* CoreGraphics.framework */,
113D5E131996AD7400066AE3 /* UIKit.framework */,
113D5E281996AD7400066AE3 /* XCTest.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
113D5E151996AD7400066AE3 /* MGSwipeDemo */ = {
isa = PBXGroup;
children = (
1162A95F1996AE5400A1DC80 /* assets */,
113D5E1E1996AD7400066AE3 /* AppDelegate.h */,
113D5E1F1996AD7400066AE3 /* AppDelegate.m */,
1162A9621996AEDA00A1DC80 /* TestData.h */,
1162A9601996AECA00A1DC80 /* TestData.m */,
11D0A0121996AFDE008D8809 /* DemoViewController.h */,
11D0A0131996AFDE008D8809 /* DemoViewController.m */,
11D0A01B1996B2BE008D8809 /* autolayout_test.storyboard */,
113D5E211996AD7400066AE3 /* Images.xcassets */,
113D5E161996AD7400066AE3 /* Supporting Files */,
1130ABC51AAA6B3400BEB4D3 /* LaunchScreen.xib */,
);
path = MGSwipeDemo;
sourceTree = "<group>";
};
113D5E161996AD7400066AE3 /* Supporting Files */ = {
isa = PBXGroup;
children = (
113D5E171996AD7400066AE3 /* MGSwipeDemo-Info.plist */,
113D5E181996AD7400066AE3 /* InfoPlist.strings */,
113D5E1B1996AD7400066AE3 /* main.m */,
113D5E1D1996AD7400066AE3 /* MGSwipeDemo-Prefix.pch */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
1162A9581996AE0E00A1DC80 /* MGSwipeTableCell */ = {
isa = PBXGroup;
children = (
11CF2E9719D7357F0092A789 /* MGSwipeButton.h */,
11CF2E9919D7357F0092A789 /* MGSwipeButton.m */,
11CF2E9819D7357F0092A789 /* MGSwipeTableCell.h */,
11CF2E9A19D7357F0092A789 /* MGSwipeTableCell.m */,
);
name = MGSwipeTableCell;
sourceTree = "<group>";
};
1162A95F1996AE5400A1DC80 /* assets */ = {
isa = PBXGroup;
children = (
1146855519D4609F00D28118 /* background.jpg */,
11D0A01D1996C339008D8809 /* cat@2x.png */,
11D0A0151996AFF1008D8809 /* check@2x.png */,
11D0A0161996AFF1008D8809 /* fav@2x.png */,
11D0A0171996AFF1008D8809 /* menu@2x.png */,
);
name = assets;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
113D5E0B1996AD7400066AE3 /* MGSwipeDemo */ = {
isa = PBXNativeTarget;
buildConfigurationList = 113D5E381996AD7400066AE3 /* Build configuration list for PBXNativeTarget "MGSwipeDemo" */;
buildPhases = (
113D5E081996AD7400066AE3 /* Sources */,
113D5E091996AD7400066AE3 /* Frameworks */,
113D5E0A1996AD7400066AE3 /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = MGSwipeDemo;
productName = MGSwipeDemo;
productReference = 113D5E0C1996AD7400066AE3 /* MGSwipeDemo.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
113D5E041996AD7400066AE3 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0510;
ORGANIZATIONNAME = "Imanol Fernandez Gorostizaga";
};
buildConfigurationList = 113D5E071996AD7400066AE3 /* Build configuration list for PBXProject "MGSwipeDemo" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
);
mainGroup = 113D5E031996AD7400066AE3;
productRefGroup = 113D5E0D1996AD7400066AE3 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
113D5E0B1996AD7400066AE3 /* MGSwipeDemo */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
113D5E0A1996AD7400066AE3 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
11D0A0191996AFF1008D8809 /* fav@2x.png in Resources */,
11D0A01C1996B2BE008D8809 /* autolayout_test.storyboard in Resources */,
113D5E1A1996AD7400066AE3 /* InfoPlist.strings in Resources */,
11D0A01E1996C339008D8809 /* cat@2x.png in Resources */,
11D0A01A1996AFF1008D8809 /* menu@2x.png in Resources */,
1146855619D4609F00D28118 /* background.jpg in Resources */,
113D5E221996AD7400066AE3 /* Images.xcassets in Resources */,
1130ABC61AAA6B3400BEB4D3 /* LaunchScreen.xib in Resources */,
11D0A0181996AFF1008D8809 /* check@2x.png in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
113D5E081996AD7400066AE3 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
1162A9611996AECA00A1DC80 /* TestData.m in Sources */,
11CF2E9C19D7357F0092A789 /* MGSwipeTableCell.m in Sources */,
11D0A0141996AFDE008D8809 /* DemoViewController.m in Sources */,
11CF2E9B19D7357F0092A789 /* MGSwipeButton.m in Sources */,
113D5E201996AD7400066AE3 /* AppDelegate.m in Sources */,
113D5E1C1996AD7400066AE3 /* main.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
113D5E181996AD7400066AE3 /* InfoPlist.strings */ = {
isa = PBXVariantGroup;
children = (
113D5E191996AD7400066AE3 /* en */,
);
name = InfoPlist.strings;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
113D5E361996AD7400066AE3 /* 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__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
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 = 5.0;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
113D5E371996AD7400066AE3 /* 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__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = YES;
ENABLE_NS_ASSERTIONS = NO;
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 = 5.0;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
113D5E391996AD7400066AE3 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
ENABLE_BITCODE = NO;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "MGSwipeDemo/MGSwipeDemo-Prefix.pch";
INFOPLIST_FILE = "MGSwipeDemo/MGSwipeDemo-Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
PRODUCT_NAME = "$(TARGET_NAME)";
WRAPPER_EXTENSION = app;
};
name = Debug;
};
113D5E3A1996AD7400066AE3 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
ENABLE_BITCODE = NO;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "MGSwipeDemo/MGSwipeDemo-Prefix.pch";
INFOPLIST_FILE = "MGSwipeDemo/MGSwipeDemo-Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
PRODUCT_NAME = "$(TARGET_NAME)";
WRAPPER_EXTENSION = app;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
113D5E071996AD7400066AE3 /* Build configuration list for PBXProject "MGSwipeDemo" */ = {
isa = XCConfigurationList;
buildConfigurations = (
113D5E361996AD7400066AE3 /* Debug */,
113D5E371996AD7400066AE3 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
113D5E381996AD7400066AE3 /* Build configuration list for PBXNativeTarget "MGSwipeDemo" */ = {
isa = XCConfigurationList;
buildConfigurations = (
113D5E391996AD7400066AE3 /* Debug */,
113D5E3A1996AD7400066AE3 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 113D5E041996AD7400066AE3 /* Project object */;
}

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:MGSwipeDemo.xcodeproj">
</FileRef>
</Workspace>

View file

@ -0,0 +1,12 @@
/*
* MGSwipeTableCell is licensed under MIT licensed. See LICENSE.md file for more information.
* Copyright (c) 2014 Imanol Fernandez @MortimerGoro
*/
#import <UIKit/UIKit.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@end

View file

@ -0,0 +1,52 @@
/*
* MGSwipeTableCell is licensed under MIT licensed. See LICENSE.md file for more information.
* Copyright (c) 2014 Imanol Fernandez @MortimerGoro
*/
#import "AppDelegate.h"
#import "DemoViewController.h"
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
DemoViewController * vc = [[DemoViewController alloc] init];
UINavigationController * navigation = [[UINavigationController alloc] initWithRootViewController:vc];
navigation.navigationBar.translucent = NO;
self.window.rootViewController = navigation;
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
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

View file

@ -0,0 +1,14 @@
/*
* MGSwipeTableCell is licensed under MIT license. See LICENSE.md file for more information.
* Copyright (c) 2014 Imanol Fernandez @MortimerGoro
*/
#import <UIKit/UIKit.h>
#import "MGSwipeTableCell.h"
@interface DemoViewController : UIViewController<UITableViewDataSource, UITableViewDelegate, MGSwipeTableCellDelegate, UIActionSheetDelegate>
@property (nonatomic, assign) BOOL testingStoryboardCell;
@property (strong, nonatomic) IBOutlet UITableView *tableView;
@end

View file

@ -0,0 +1,257 @@
/*
* MGSwipeTableCell is licensed under MIT license. See LICENSE.md file for more information.
* Copyright (c) 2014 Imanol Fernandez @MortimerGoro
*/
#import "DemoViewController.h"
#import "TestData.h"
#import "MGSwipeButton.h"
#define TEST_USE_MG_DELEGATE 1
@implementation DemoViewController
{
NSMutableArray * tests;
UIBarButtonItem * prevButton;
UITableViewCellAccessoryType accessory;
UIImageView * background; //used for transparency test
BOOL allowMultipleSwipe;
}
-(void) cancelTableEditClick: (id) sender
{
[_tableView setEditing: NO animated: YES];
self.navigationItem.rightBarButtonItem = prevButton;
prevButton = nil;
}
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex == actionSheet.cancelButtonIndex) {
return;
}
if (buttonIndex == 1) {
tests = [TestData data];
[_tableView reloadData];
}
else if (buttonIndex == 2) {
_tableView.allowsMultipleSelectionDuringEditing = YES;
[_tableView setEditing: YES animated: YES];
prevButton = self.navigationItem.rightBarButtonItem;
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Cancel" style:UIBarButtonItemStyleDone target:self action:@selector(cancelTableEditClick:)];
}
else if (buttonIndex == 3) {
accessory++;
if (accessory >=4) {
accessory = 0;
}
[_tableView reloadData];
}
else if (buttonIndex == 4) {
if (background) {
[background removeFromSuperview];
_tableView.backgroundColor = [UIColor whiteColor];
}
else {
background = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"background.jpg"]];
background.frame = self.view.bounds;
background.contentMode = UIViewContentModeScaleToFill;
background.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self.view insertSubview:background belowSubview:_tableView];
_tableView.backgroundColor = [UIColor clearColor];
}
[_tableView reloadData];
}
else if (buttonIndex == 5) {
allowMultipleSwipe = !allowMultipleSwipe;
[_tableView reloadData];
}
else {
UIStoryboard *sb = [UIStoryboard storyboardWithName:@"autolayout_test" bundle:nil];
DemoViewController *vc = [sb instantiateInitialViewController];
vc.testingStoryboardCell = YES;
[self.navigationController pushViewController:vc animated:YES];
}
}
-(void) actionClick: (id) sender
{
UIActionSheet * sheet = [[UIActionSheet alloc] initWithTitle:@"Select action" delegate:self cancelButtonTitle:@"Cancel" destructiveButtonTitle:nil otherButtonTitles: nil];
[sheet addButtonWithTitle:@"Reload test"];
[sheet addButtonWithTitle:@"Multiselect test"];
[sheet addButtonWithTitle:@"Change accessory button"];
[sheet addButtonWithTitle:@"Transparency test"];
[sheet addButtonWithTitle: allowMultipleSwipe ? @"Single Swipe" : @"Multiple Swipe"];
if (!_testingStoryboardCell) {
[sheet addButtonWithTitle:@"Storyboard test"];
}
[sheet showInView:self.view];
}
- (void)viewDidLoad
{
[super viewDidLoad];
tests = [TestData data];
self.title = @"MGSwipeCell";
if (!_testingStoryboardCell) {
_tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];
_tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
_tableView.dataSource = self;
_tableView.delegate = self;
[self.view addSubview:_tableView];
}
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAction target:self action:@selector(actionClick:)];
}
-(NSArray *) createLeftButtons: (int) number
{
NSMutableArray * result = [NSMutableArray array];
UIColor * colors[3] = {[UIColor greenColor],
[UIColor colorWithRed:0 green:0x99/255.0 blue:0xcc/255.0 alpha:1.0],
[UIColor colorWithRed:0.59 green:0.29 blue:0.08 alpha:1.0]};
UIImage * icons[3] = {[UIImage imageNamed:@"check.png"], [UIImage imageNamed:@"fav.png"], [UIImage imageNamed:@"menu.png"]};
for (int i = 0; i < number; ++i)
{
MGSwipeButton * button = [MGSwipeButton buttonWithTitle:@"" icon:icons[i] backgroundColor:colors[i] padding:15 callback:^BOOL(MGSwipeTableCell * sender){
NSLog(@"Convenience callback received (left).");
return YES;
}];
[result addObject:button];
}
return result;
}
-(NSArray *) createRightButtons: (int) number
{
NSMutableArray * result = [NSMutableArray array];
NSString* titles[2] = {@"Delete", @"More"};
UIColor * colors[2] = {[UIColor redColor], [UIColor lightGrayColor]};
for (int i = 0; i < number; ++i)
{
MGSwipeButton * button = [MGSwipeButton buttonWithTitle:titles[i] backgroundColor:colors[i] callback:^BOOL(MGSwipeTableCell * sender){
NSLog(@"Convenience callback received (right).");
BOOL autoHide = i != 0;
return autoHide; //Don't autohide in delete button to improve delete expansion animation
}];
[result addObject:button];
}
return result;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
{
return tests.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
MGSwipeTableCell * cell;
if (_testingStoryboardCell) {
/**
* Test using storyboard and prototype cell that uses autolayout
**/
cell = [_tableView dequeueReusableCellWithIdentifier:@"prototypeCell"];
}
else {
/**
* Test using programmatically created cells
**/
static NSString * reuseIdentifier = @"programmaticCell";
cell = [_tableView dequeueReusableCellWithIdentifier:reuseIdentifier];
if (!cell) {
cell = [[MGSwipeTableCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:reuseIdentifier];
}
}
TestData * data = [tests objectAtIndex:indexPath.row];
cell.textLabel.text = data.title;
cell.textLabel.font = [UIFont systemFontOfSize:16];
cell.detailTextLabel.text = data.detailTitle;
cell.accessoryType = accessory;
cell.delegate = self;
cell.allowsMultipleSwipe = allowMultipleSwipe;
if (background) { //transparency test
cell.backgroundColor = [UIColor clearColor];
cell.selectedBackgroundView = [[UIView alloc] init];
cell.selectedBackgroundView.backgroundColor = [[UIColor yellowColor] colorWithAlphaComponent:0.3];
cell.contentView.backgroundColor = [UIColor clearColor];
cell.swipeBackgroundColor = [UIColor clearColor];
cell.textLabel.textColor = [UIColor yellowColor];
cell.detailTextLabel.textColor = [UIColor yellowColor];
}
#if !TEST_USE_MG_DELEGATE
cell.leftSwipeSettings.transition = data.transition;
cell.rightSwipeSettings.transition = data.transition;
cell.leftExpansion.buttonIndex = data.leftExpandableIndex;
cell.leftExpansion.fillOnTrigger = NO;
cell.rightExpansion.buttonIndex = data.rightExpandableIndex;
cell.rightExpansion.fillOnTrigger = YES;
cell.leftButtons = [self createLeftButtons:data.leftButtonsCount];
cell.rightButtons = [self createRightButtons:data.rightButtonsCount];
#endif
return cell;
}
#if TEST_USE_MG_DELEGATE
-(NSArray*) swipeTableCell:(MGSwipeTableCell*) cell swipeButtonsForDirection:(MGSwipeDirection)direction
swipeSettings:(MGSwipeSettings*) swipeSettings expansionSettings:(MGSwipeExpansionSettings*) expansionSettings;
{
TestData * data = [tests objectAtIndex:[_tableView indexPathForCell:cell].row];
swipeSettings.transition = data.transition;
if (direction == MGSwipeDirectionLeftToRight) {
expansionSettings.buttonIndex = data.leftExpandableIndex;
expansionSettings.fillOnTrigger = NO;
return [self createLeftButtons:data.leftButtonsCount];
}
else {
expansionSettings.buttonIndex = data.rightExpandableIndex;
expansionSettings.fillOnTrigger = YES;
return [self createRightButtons:data.rightButtonsCount];
}
}
#endif
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 60;
}
-(BOOL) swipeTableCell:(MGSwipeTableCell*) cell tappedButtonAtIndex:(NSInteger) index direction:(MGSwipeDirection)direction fromExpansion:(BOOL) fromExpansion
{
NSLog(@"Delegate: button tapped, %@ position, index %d, from Expansion: %@",
direction == MGSwipeDirectionLeftToRight ? @"left" : @"right", (int)index, fromExpansion ? @"YES" : @"NO");
if (direction == MGSwipeDirectionRightToLeft && index == 0) {
//delete button
NSIndexPath * path = [_tableView indexPathForCell:cell];
[tests removeObjectAtIndex:path.row];
[_tableView deleteRowsAtIndexPaths:@[path] withRowAnimation:UITableViewRowAnimationLeft];
return NO; //Don't autohide to improve delete expansion animation
}
return YES;
}
-(void) tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath
{
NSLog(@"Tapped accessory button");
}
@end

View file

@ -0,0 +1,58 @@
{
"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"
}
}

View file

@ -0,0 +1,51 @@
{
"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"
}
}

View file

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="6214" systemVersion="14A314h" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6207"/>
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB">
<rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text=" Copyright (c) 2015 Imanol Fernandez Gorostizaga. All rights reserved." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="8ie-xW-0ye">
<rect key="frame" x="20" y="439" width="441" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
<variation key="widthClass=compact">
<fontDescription key="fontDescription" type="system" pointSize="11"/>
</variation>
</label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="MGSwipeDemo" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="kId-c2-rCX">
<rect key="frame" x="20" y="140" width="441" height="43"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="36"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
<constraints>
<constraint firstItem="kId-c2-rCX" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="bottom" multiplier="1/3" constant="1" id="Kid-kn-2rF"/>
<constraint firstAttribute="centerX" secondItem="kId-c2-rCX" secondAttribute="centerX" id="Koa-jz-hwk"/>
<constraint firstAttribute="bottom" secondItem="8ie-xW-0ye" secondAttribute="bottom" constant="20" id="Kzo-t9-V3l"/>
<constraint firstItem="8ie-xW-0ye" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="MfP-vx-nX0"/>
<constraint firstAttribute="centerX" secondItem="8ie-xW-0ye" secondAttribute="centerX" id="ZEH-qu-HZ9"/>
<constraint firstItem="kId-c2-rCX" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="fvb-Df-36g"/>
</constraints>
<nil key="simulatedStatusBarMetrics"/>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<point key="canvasLocation" x="404" y="445"/>
</view>
</objects>
</document>

View file

@ -0,0 +1,47 @@
<?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>CFBundleDisplayName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>ludei.${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.0</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</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>

View file

@ -0,0 +1,16 @@
//
// Prefix header
//
// The contents of this file are implicitly included at the beginning of every source file.
//
#import <Availability.h>
#ifndef __IPHONE_3_0
#warning "This project uses features only available in iOS SDK 3.0 and later."
#endif
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#endif

View file

@ -0,0 +1,23 @@
/*
* MGSwipeTableCell is licensed under MIT licensed. See LICENSE.md file for more information.
* Copyright (c) 2014 Imanol Fernandez @MortimerGoro
*/
#import "MGSwipeTableCell.h"
@interface TestData : NSObject
@property (nonatomic) MGSwipeTransition transition;
@property (nonatomic) int leftButtonsCount;
@property (nonatomic) int rightButtonsCount;
@property (nonatomic) int leftExpandableIndex;
@property (nonatomic) int rightExpandableIndex;
-(NSString *) title;
-(NSString *) detailTitle;
+(NSMutableArray*) data;
@end

View file

@ -0,0 +1,75 @@
/*
* MGSwipeTableCell is licensed under MIT licensed. See LICENSE.md file for more information.
* Copyright (c) 2014 Imanol Fernandez @MortimerGoro
*/
#import "TestData.h"
#import "MGSwipeButton.h"
@implementation TestData
-(NSString *) title
{
NSString * modeTitle;
switch (_transition) {
case MGSwipeTransition3D: modeTitle = @"3D"; break;
case MGSwipeTransitionClipCenter: modeTitle = @"clip"; break;
case MGSwipeTransitionDrag: modeTitle = @"drag"; break;
case MGSwipeTransitionBorder: modeTitle = @"border"; break;
case MGSwipeTransitionStatic: modeTitle = @"static";break;
}
modeTitle = [NSString stringWithFormat:@"%@ transition", modeTitle];
NSString * buttons;
if (_leftButtonsCount <= 0 && _rightButtonsCount <= 0) {
return @"No buttons";
}
else if (_leftButtonsCount > 0 && _rightButtonsCount > 0) {
buttons = [NSString stringWithFormat:@"%d left, %d right", _leftButtonsCount, _rightButtonsCount];
}
else if (_leftButtonsCount > 0) {
buttons = [NSString stringWithFormat:@"%d left", _leftButtonsCount];
}
else {
buttons = [NSString stringWithFormat:@"%d right", _rightButtonsCount];
}
return [NSString stringWithFormat:@"%@, %@", buttons, modeTitle];
}
-(NSString *) detailTitle
{
return _leftExpandableIndex >=0 || _rightExpandableIndex >= 0 ? @"Expandable" : @"Not expandable";
}
+(NSMutableArray *) data
{
NSMutableArray * tests = [NSMutableArray array];
MGSwipeTransition transitions[] = {MGSwipeTransitionBorder, MGSwipeTransitionStatic, MGSwipeTransitionClipCenter, MGSwipeTransitionDrag, MGSwipeTransition3D};
int numTransitions = sizeof(transitions)/sizeof(MGSwipeTransition);
int buttonCombinations[] = {3,2, 2,1, 0,2, 2,0};
int numCombinations = sizeof(buttonCombinations) / (sizeof(int) * 2);
int expansionCombinations[] = {-1, -1, 0, 0};
int numExpansions = sizeof(expansionCombinations)/ (sizeof(int) * 2);
for (int i = 0; i < numCombinations; ++i) {
for (int j = 0; j < numTransitions; ++j) {
for (int z = 0; z < numExpansions; ++z) {
TestData * data = [[TestData alloc] init];
data.leftButtonsCount = buttonCombinations[2 * i];
data.rightButtonsCount = buttonCombinations[2 * i + 1];
data.transition = transitions[j];
data.leftExpandableIndex = data.leftButtonsCount ? expansionCombinations[2 * z] : -1;
data.rightExpandableIndex = data.rightButtonsCount ? expansionCombinations[2 * z + 1] : -1;
[tests addObject:data];
}
}
}
return tests;
}
@end

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 820 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

View file

@ -0,0 +1,75 @@
<?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" initialViewController="obU-ao-dp2">
<dependencies>
<deployment version="1536" defaultVersion="1280" identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6238"/>
</dependencies>
<scenes>
<!--Demo View Controller-->
<scene sceneID="RzA-6l-jmH">
<objects>
<viewController id="obU-ao-dp2" customClass="DemoViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="e1m-rV-Rw8"/>
<viewControllerLayoutGuide type="bottom" id="gW7-Px-uIu"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="iVC-tC-ekG">
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" translatesAutoresizingMaskIntoConstraints="NO" id="Icz-Ez-2qz">
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<prototypes>
<tableViewCell contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="prototypeCell" id="jfa-oN-DSo" customClass="MGSwipeTableCell">
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="jfa-oN-DSo" id="RQ7-Fg-6FO">
<autoresizingMask key="autoresizingMask"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="cat.png" translatesAutoresizingMaskIntoConstraints="NO" id="O4J-Sj-TY1">
<rect key="frame" x="265" y="5" width="50" height="33"/>
<constraints>
<constraint firstAttribute="width" constant="50" id="daW-gL-ohF"/>
</constraints>
</imageView>
</subviews>
<constraints>
<constraint firstItem="O4J-Sj-TY1" firstAttribute="top" secondItem="RQ7-Fg-6FO" secondAttribute="top" constant="5" id="3Zu-DA-YOR"/>
<constraint firstAttribute="bottom" secondItem="O4J-Sj-TY1" secondAttribute="bottom" constant="5" id="Q2G-mI-5px"/>
<constraint firstAttribute="trailing" secondItem="O4J-Sj-TY1" secondAttribute="trailing" constant="5" id="ysY-dn-d6d"/>
</constraints>
</tableViewCellContentView>
</tableViewCell>
</prototypes>
<connections>
<outlet property="dataSource" destination="obU-ao-dp2" id="JOX-nm-3T6"/>
<outlet property="delegate" destination="obU-ao-dp2" id="LiV-OP-8qX"/>
</connections>
</tableView>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstAttribute="trailing" secondItem="Icz-Ez-2qz" secondAttribute="trailing" id="6Nz-7o-Ccb"/>
<constraint firstItem="Icz-Ez-2qz" firstAttribute="top" secondItem="iVC-tC-ekG" secondAttribute="top" id="ALD-sU-fMf"/>
<constraint firstItem="gW7-Px-uIu" firstAttribute="top" secondItem="Icz-Ez-2qz" secondAttribute="bottom" id="T3Z-fm-eYh"/>
<constraint firstItem="Icz-Ez-2qz" firstAttribute="leading" secondItem="iVC-tC-ekG" secondAttribute="leading" id="Vxd-vE-2Uo"/>
</constraints>
</view>
<connections>
<outlet property="tableView" destination="Icz-Ez-2qz" id="B0t-eF-mMH"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dKY-xM-hks" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="712" y="157"/>
</scene>
</scenes>
<resources>
<image name="cat.png" width="128" height="128"/>
</resources>
<simulatedMetricsContainer key="defaultSimulatedMetrics">
<simulatedStatusBarMetrics key="statusBar"/>
<simulatedOrientationMetrics key="orientation"/>
<simulatedScreenMetrics key="destination" type="retina4"/>
</simulatedMetricsContainer>
</document>

View file

@ -0,0 +1,2 @@
/* Localized versions of Info.plist keys */

View file

@ -0,0 +1,18 @@
//
// main.m
// MGSwipeDemo
//
// Created by Imanol Fernandez Gorostizag on 09/08/14.
// Copyright (c) 2014 Imanol Fernandez Gorostizaga. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
int main(int argc, char * argv[])
{
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}

View file

@ -0,0 +1,307 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
11754E2919D5C1EA009CE7B5 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 11754E2819D5C1EA009CE7B5 /* main.m */; };
11754E2C19D5C1EA009CE7B5 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 11754E2B19D5C1EA009CE7B5 /* AppDelegate.m */; };
11754E2F19D5C1EA009CE7B5 /* MailViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 11754E2E19D5C1EA009CE7B5 /* MailViewController.m */; };
11754E3419D5C1EA009CE7B5 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 11754E3319D5C1EA009CE7B5 /* Images.xcassets */; };
11754E4E19D5C3A1009CE7B5 /* MailTableCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 11754E4D19D5C3A1009CE7B5 /* MailTableCell.m */; };
11754E5419D5C3E5009CE7B5 /* MGSwipeButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 11754E5219D5C3E5009CE7B5 /* MGSwipeButton.m */; };
11754E5519D5C3E5009CE7B5 /* MGSwipeTableCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 11754E5319D5C3E5009CE7B5 /* MGSwipeTableCell.m */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
11754E2319D5C1EA009CE7B5 /* MailAppDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MailAppDemo.app; sourceTree = BUILT_PRODUCTS_DIR; };
11754E2719D5C1EA009CE7B5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
11754E2819D5C1EA009CE7B5 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
11754E2A19D5C1EA009CE7B5 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
11754E2B19D5C1EA009CE7B5 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
11754E2D19D5C1EA009CE7B5 /* MailViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MailViewController.h; sourceTree = "<group>"; };
11754E2E19D5C1EA009CE7B5 /* MailViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MailViewController.m; sourceTree = "<group>"; };
11754E3319D5C1EA009CE7B5 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
11754E4C19D5C3A1009CE7B5 /* MailTableCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MailTableCell.h; sourceTree = "<group>"; };
11754E4D19D5C3A1009CE7B5 /* MailTableCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MailTableCell.m; sourceTree = "<group>"; };
11754E5019D5C3E5009CE7B5 /* MGSwipeButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MGSwipeButton.h; path = ../../MGSwipeTableCell/MGSwipeButton.h; sourceTree = "<group>"; };
11754E5119D5C3E5009CE7B5 /* MGSwipeTableCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MGSwipeTableCell.h; path = ../../MGSwipeTableCell/MGSwipeTableCell.h; sourceTree = "<group>"; };
11754E5219D5C3E5009CE7B5 /* MGSwipeButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGSwipeButton.m; path = ../../MGSwipeTableCell/MGSwipeButton.m; sourceTree = "<group>"; };
11754E5319D5C3E5009CE7B5 /* MGSwipeTableCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGSwipeTableCell.m; path = ../../MGSwipeTableCell/MGSwipeTableCell.m; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
11754E2019D5C1EA009CE7B5 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
11754E1A19D5C1EA009CE7B5 = {
isa = PBXGroup;
children = (
11754E4F19D5C3CE009CE7B5 /* MGSwipeTableCell */,
11754E2519D5C1EA009CE7B5 /* MailAppDemo */,
11754E2419D5C1EA009CE7B5 /* Products */,
);
sourceTree = "<group>";
};
11754E2419D5C1EA009CE7B5 /* Products */ = {
isa = PBXGroup;
children = (
11754E2319D5C1EA009CE7B5 /* MailAppDemo.app */,
);
name = Products;
sourceTree = "<group>";
};
11754E2519D5C1EA009CE7B5 /* MailAppDemo */ = {
isa = PBXGroup;
children = (
11754E2A19D5C1EA009CE7B5 /* AppDelegate.h */,
11754E2B19D5C1EA009CE7B5 /* AppDelegate.m */,
11754E2D19D5C1EA009CE7B5 /* MailViewController.h */,
11754E2E19D5C1EA009CE7B5 /* MailViewController.m */,
11754E4C19D5C3A1009CE7B5 /* MailTableCell.h */,
11754E4D19D5C3A1009CE7B5 /* MailTableCell.m */,
11754E3319D5C1EA009CE7B5 /* Images.xcassets */,
11754E2619D5C1EA009CE7B5 /* Supporting Files */,
);
path = MailAppDemo;
sourceTree = "<group>";
};
11754E2619D5C1EA009CE7B5 /* Supporting Files */ = {
isa = PBXGroup;
children = (
11754E2719D5C1EA009CE7B5 /* Info.plist */,
11754E2819D5C1EA009CE7B5 /* main.m */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
11754E4F19D5C3CE009CE7B5 /* MGSwipeTableCell */ = {
isa = PBXGroup;
children = (
11754E5019D5C3E5009CE7B5 /* MGSwipeButton.h */,
11754E5219D5C3E5009CE7B5 /* MGSwipeButton.m */,
11754E5119D5C3E5009CE7B5 /* MGSwipeTableCell.h */,
11754E5319D5C3E5009CE7B5 /* MGSwipeTableCell.m */,
);
name = MGSwipeTableCell;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
11754E2219D5C1EA009CE7B5 /* MailAppDemo */ = {
isa = PBXNativeTarget;
buildConfigurationList = 11754E4619D5C1EA009CE7B5 /* Build configuration list for PBXNativeTarget "MailAppDemo" */;
buildPhases = (
11754E1F19D5C1EA009CE7B5 /* Sources */,
11754E2019D5C1EA009CE7B5 /* Frameworks */,
11754E2119D5C1EA009CE7B5 /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = MailAppDemo;
productName = MailAppDemo;
productReference = 11754E2319D5C1EA009CE7B5 /* MailAppDemo.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
11754E1B19D5C1EA009CE7B5 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0600;
ORGANIZATIONNAME = Mortimer;
TargetAttributes = {
11754E2219D5C1EA009CE7B5 = {
CreatedOnToolsVersion = 6.0.1;
};
};
};
buildConfigurationList = 11754E1E19D5C1EA009CE7B5 /* Build configuration list for PBXProject "MailAppDemo" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 11754E1A19D5C1EA009CE7B5;
productRefGroup = 11754E2419D5C1EA009CE7B5 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
11754E2219D5C1EA009CE7B5 /* MailAppDemo */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
11754E2119D5C1EA009CE7B5 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
11754E3419D5C1EA009CE7B5 /* Images.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
11754E1F19D5C1EA009CE7B5 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
11754E2F19D5C1EA009CE7B5 /* MailViewController.m in Sources */,
11754E5519D5C3E5009CE7B5 /* MGSwipeTableCell.m in Sources */,
11754E4E19D5C3A1009CE7B5 /* MailTableCell.m in Sources */,
11754E5419D5C3E5009CE7B5 /* MGSwipeButton.m in Sources */,
11754E2C19D5C1EA009CE7B5 /* AppDelegate.m in Sources */,
11754E2919D5C1EA009CE7B5 /* main.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
11754E4419D5C1EA009CE7B5 /* 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 = 5.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
11754E4519D5C1EA009CE7B5 /* 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 = 5.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
11754E4719D5C1EA009CE7B5 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = MailAppDemo/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
};
11754E4819D5C1EA009CE7B5 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = MailAppDemo/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
11754E1E19D5C1EA009CE7B5 /* Build configuration list for PBXProject "MailAppDemo" */ = {
isa = XCConfigurationList;
buildConfigurations = (
11754E4419D5C1EA009CE7B5 /* Debug */,
11754E4519D5C1EA009CE7B5 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
11754E4619D5C1EA009CE7B5 /* Build configuration list for PBXNativeTarget "MailAppDemo" */ = {
isa = XCConfigurationList;
buildConfigurations = (
11754E4719D5C1EA009CE7B5 /* Debug */,
11754E4819D5C1EA009CE7B5 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 11754E1B19D5C1EA009CE7B5 /* Project object */;
}

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:MailAppDemo.xcodeproj">
</FileRef>
</Workspace>

View file

@ -0,0 +1,14 @@
/*
* MGSwipeTableCell is licensed under MIT license. See LICENSE.md file for more information.
* Copyright (c) 2014 Imanol Fernandez @MortimerGoro
*/
#import <UIKit/UIKit.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@end

View file

@ -0,0 +1,48 @@
/*
* MGSwipeTableCell is licensed under MIT license. See LICENSE.md file for more information.
* Copyright (c) 2014 Imanol Fernandez @MortimerGoro
*/
#import "AppDelegate.h"
#import "MailViewController.h"
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
MailViewController * vc = [[MailViewController alloc] init];
UINavigationController * navigation = [[UINavigationController alloc] initWithRootViewController:vc];
navigation.navigationBar.translucent = NO;
self.window.rootViewController = navigation;
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
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

View file

@ -0,0 +1,68 @@
{
"images" : [
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "3x"
},
{
"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"
}
}

View file

@ -0,0 +1,89 @@
{
"images" : [
{
"idiom" : "iphone",
"scale" : "1x",
"orientation" : "portrait"
},
{
"idiom" : "iphone",
"scale" : "2x",
"orientation" : "portrait"
},
{
"orientation" : "portrait",
"idiom" : "iphone",
"subtype" : "retina4",
"scale" : "2x"
},
{
"orientation" : "portrait",
"idiom" : "iphone",
"minimum-system-version" : "7.0",
"scale" : "2x"
},
{
"orientation" : "portrait",
"idiom" : "iphone",
"minimum-system-version" : "7.0",
"subtype" : "retina4",
"scale" : "2x"
},
{
"orientation" : "portrait",
"idiom" : "ipad",
"extent" : "to-status-bar",
"scale" : "1x"
},
{
"orientation" : "portrait",
"idiom" : "ipad",
"extent" : "to-status-bar",
"scale" : "2x"
},
{
"orientation" : "landscape",
"idiom" : "ipad",
"extent" : "to-status-bar",
"scale" : "1x"
},
{
"orientation" : "landscape",
"idiom" : "ipad",
"extent" : "to-status-bar",
"scale" : "2x"
},
{
"orientation" : "portrait",
"idiom" : "ipad",
"minimum-system-version" : "7.0",
"extent" : "full-screen",
"scale" : "1x"
},
{
"orientation" : "portrait",
"idiom" : "ipad",
"minimum-system-version" : "7.0",
"extent" : "full-screen",
"scale" : "2x"
},
{
"orientation" : "landscape",
"idiom" : "ipad",
"minimum-system-version" : "7.0",
"extent" : "full-screen",
"scale" : "1x"
},
{
"orientation" : "landscape",
"idiom" : "ipad",
"minimum-system-version" : "7.0",
"extent" : "full-screen",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View file

@ -0,0 +1,45 @@
<?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>Mortimer.$(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>UILaunchStoryboardName</key>
<string>LaunchScreen</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>

View file

@ -0,0 +1,25 @@
/*
* MGSwipeTableCell is licensed under MIT license. See LICENSE.md file for more information.
* Copyright (c) 2014 Imanol Fernandez @MortimerGoro
*/
#import <Foundation/Foundation.h>
#import "MGSwipeTableCell.h"
@interface MailIndicatorView : UIView
@property (nonatomic, strong) UIColor * indicatorColor;
@property (nonatomic, strong) UIColor * innerColor;
@end
@interface MailTableCell : MGSwipeTableCell
@property (nonatomic, strong) UILabel * mailFrom;
@property (nonatomic, strong) UILabel * mailSubject;
@property (nonatomic, strong) UITextView * mailMessage;
@property (nonatomic, strong) UILabel * mailTime;
@property (nonatomic, strong) MailIndicatorView * indicatorView;
-(instancetype) initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier;
@end

View file

@ -0,0 +1,99 @@
/*
* MGSwipeTableCell is licensed under MIT license. See LICENSE.md file for more information.
* Copyright (c) 2014 Imanol Fernandez @MortimerGoro
*/
#import "MailTableCell.h"
@implementation MailIndicatorView
-(void) drawRect:(CGRect)rect
{
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextAddEllipseInRect(ctx, rect);
CGContextSetFillColor(ctx, CGColorGetComponents(_indicatorColor.CGColor));
CGContextFillPath(ctx);
if (_innerColor) {
CGFloat innerSize = rect.size.width * 0.5;
CGRect innerRect = CGRectMake(rect.origin.x + rect.size.width * 0.5 - innerSize * 0.5,
rect.origin.y + rect.size.height * 0.5 - innerSize * 0.5,
innerSize, innerSize);
CGContextAddEllipseInRect(ctx, innerRect);
CGContextSetFillColor(ctx, CGColorGetComponents(_innerColor.CGColor));
CGContextFillPath(ctx);
}
}
-(void) setIndicatorColor:(UIColor *)indicatorColor
{
_indicatorColor = indicatorColor;
[self setNeedsDisplay];
}
-(void) setInnerColor:(UIColor *)innerColor
{
_innerColor = innerColor;
[self setNeedsDisplay];
}
@end
@implementation MailTableCell
-(instancetype) initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
_mailFrom = [[UILabel alloc] initWithFrame:CGRectZero];
_mailMessage = [[UITextView alloc] initWithFrame:CGRectZero];
_mailSubject = [[UILabel alloc] initWithFrame:CGRectZero];
_mailTime = [[UILabel alloc] initWithFrame:CGRectZero];
_mailFrom.font = [UIFont fontWithName:@"HelveticaNeue" size:18.0f];
_mailSubject.font = [UIFont fontWithName:@"HelveticaNeue-Light" size:15.0f];
_mailMessage.font = [UIFont fontWithName:@"HelveticaNeue-Light" size:14.0f];
_mailTime.font = [UIFont fontWithName:@"HelveticaNeue-Light" size:13.0f];
_mailMessage.scrollEnabled = NO;
_mailMessage.editable = NO;
_mailMessage.backgroundColor = [UIColor clearColor];
_mailMessage.contentInset = UIEdgeInsetsMake(-5, -5, 0, 0);
_mailMessage.textColor = [UIColor grayColor];
_mailMessage.userInteractionEnabled = NO;
_indicatorView = [[MailIndicatorView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];
_indicatorView.backgroundColor = [UIColor clearColor];
[self.contentView addSubview:_mailFrom];
[self.contentView addSubview:_mailMessage];
[self.contentView addSubview:_mailSubject];
[self.contentView addSubview:_mailTime];
[self.contentView addSubview:_indicatorView];
}
return self;
}
-(void) layoutSubviews
{
[super layoutSubviews];
CGFloat leftPadding = 25.0;
CGFloat topPadding = 3.0;
CGFloat textWidth = self.contentView.bounds.size.width - leftPadding * 2;
CGFloat dateWidth = 40;
_mailFrom.frame = CGRectMake(leftPadding, topPadding, textWidth, 20);
_mailSubject.frame = CGRectMake(leftPadding, _mailFrom.frame.origin.y + _mailFrom.frame.size.height + topPadding, textWidth - dateWidth, 17);
CGFloat messageHeight = self.contentView.bounds.size.height - (_mailSubject.frame.origin.y + _mailSubject.frame.size.height) - topPadding * 2;
_mailMessage.frame = CGRectMake(leftPadding, _mailSubject.frame.origin.y + _mailSubject.frame.size.height + topPadding, textWidth, messageHeight);
CGRect frame = _mailFrom.frame;
frame.origin.x = self.contentView.frame.size.width - leftPadding - dateWidth;
frame.size.width = dateWidth;
_mailTime.frame = frame;
_indicatorView.center = CGPointMake(leftPadding * 0.5, _mailFrom.frame.origin.y + _mailFrom.frame.size.height * 0.5);
}
@end

View file

@ -0,0 +1,14 @@
/*
* MGSwipeTableCell is licensed under MIT license. See LICENSE.md file for more information.
* Copyright (c) 2014 Imanol Fernandez @MortimerGoro
*/
#import <UIKit/UIKit.h>
#import "MGSwipeTableCell.h"
@interface MailViewController : UIViewController<UITableViewDelegate, UITableViewDataSource, MGSwipeTableCellDelegate, UIActionSheetDelegate>
@property (nonatomic, strong) UITableView * tableView;
@end

View file

@ -0,0 +1,316 @@
/*
* MGSwipeTableCell is licensed under MIT license. See LICENSE.md file for more information.
* Copyright (c) 2014 Imanol Fernandez @MortimerGoro
*/
#import "MailViewController.h"
#import "MailTableCell.h"
#import "MGSwipeButton.h"
@interface MailData : NSObject
@property (nonatomic, strong) NSString * from;
@property (nonatomic, strong) NSString * subject;
@property (nonatomic, strong) NSString * message;
@property (nonatomic, strong) NSString * date;
@property (nonatomic, assign) BOOL read;
@property (nonatomic, assign) BOOL flag;
@end
@implementation MailData
@end
typedef void(^MailActionCallback)(BOOL cancelled, BOOL deleted, NSInteger actionIndex);
@implementation MailViewController
{
NSMutableArray * demoData;
MailActionCallback actionCallback;
UIRefreshControl * refreshControl;
}
-(void) prepareDemoData
{
demoData = [NSMutableArray array];
NSArray * from = @[
@"Vincent",
@"Mr Glass",
@"Marsellus",
@"Ringo",
@"Sullivan",
@"Mr Wolf",
@"Butch Coolidge",
@"Marvin",
@"Captain Koons",
@"Jules",
@"Jimmie Dimmick"
];
NSArray * subjects = @[
@"You think water moves fast?",
@"They called me Mr Glass",
@"The path of the righteous man",
@"Do you see any Teletubbies in here?",
@"Now that we know who you are",
@"My money's in that office, right?",
@"Now we took an oath",
@"That show's called a pilot",
@"I know who I am. I'm not a mistake",
@"It all makes sense!",
@"The selfish and the tyranny of evil men",
];
NSArray * messages = @[
@"You should see ice. It moves like it has a mind. Like it knows it killed the world once and got a taste for murder. After the avalanche, it took us a week to climb out.",
@"And I will strike down upon thee with great vengeance and furious anger those who would attempt to poison and destroy My brothers.",
@"Look, just because I don't be givin' no man a foot massage don't make it right for Marsellus to throw Antwone into a glass motherfuckin' house",
@"No? Well, that's what you see at a toy store. And you must think you're in a toy store, because you're here shopping for an infant named Jeb.",
@"In a comic, you know how you can tell who the arch-villain's going to be? He's the exact opposite of the hero",
@"If she start giving me some bullshit about it ain't there, and we got to go someplace else and get it, I'm gonna shoot you in the head then and there.",
@"that I'm breaking now. We said we'd say it was the snow that killed the other two, but it wasn't. Nature is lethal but it doesn't hold a candle to man.",
@"Then they show that show to the people who make shows, and on the strength of that one show they decide if they're going to make more shows.",
@"And most times they're friends, like you and me! I should've known way back when...",
@"After the avalanche, it took us a week to climb out. Now, I don't know exactly when we turned on each other, but I know that seven of us survived the slide",
@"Blessed is he who, in the name of charity and good will, shepherds the weak through the valley of darkness, for he is truly his brother's keeper and the finder of lost children",
];
for (int i = 0; i < messages.count; ++i) {
MailData * mail = [[MailData alloc] init];
mail.from = [from objectAtIndex:i];
mail.subject = [subjects objectAtIndex:i];
mail.message = [messages objectAtIndex:i];
mail.date = [NSString stringWithFormat:@"11:%d", 43 - i];
[demoData addObject:mail];
}
}
-(void) refreshCallback
{
[self prepareDemoData];
[_tableView reloadData];
[refreshControl endRefreshing];
}
- (void)viewDidLoad {
[super viewDidLoad];
_tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];
_tableView.delegate = self;
_tableView.dataSource = self;
[self.view addSubview:_tableView];
self.title = @"MSwipeTableCell MailApp";
refreshControl = [[UIRefreshControl alloc] init];
[refreshControl addTarget:self action:@selector(refreshCallback) forControlEvents:UIControlEventValueChanged];
[self.tableView addSubview:refreshControl];
[self prepareDemoData];
}
-(void) viewDidAppear:(BOOL)animated
{
[self.tableView reloadData];
}
-(void) viewWillLayoutSubviews
{
[super viewWillLayoutSubviews];
_tableView.frame = self.view.bounds;
}
-(void) deleteMail:(NSIndexPath *) indexPath
{
[demoData removeObjectAtIndex:indexPath.row];
[_tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationLeft];
}
-(MailData *) mailForIndexPath:(NSIndexPath*) path
{
return [demoData objectAtIndex:path.row];
}
-(void) updateCellIndicactor:(MailData *) mail cell:(MailTableCell*) cell
{
UIColor * color;
UIColor * innerColor;
if (!mail.read && mail.flag) {
color = [UIColor colorWithRed:1.0 green:149/255.0 blue:0.05 alpha:1.0];
innerColor = [UIColor colorWithRed:0 green:122/255.0 blue:1.0 alpha:1.0];
}
else if (mail.flag) {
color = [UIColor colorWithRed:1.0 green:149/255.0 blue:0.05 alpha:1.0];
}
else if (mail.read) {
color = [UIColor clearColor];
}
else {
color = [UIColor colorWithRed:0 green:122/255.0 blue:1.0 alpha:1.0];
}
cell.indicatorView.indicatorColor = color;
cell.indicatorView.innerColor = innerColor;
}
-(void) showMailActions:(MailData *) mail callback:(MailActionCallback) callback
{
actionCallback = callback;
UIActionSheet * sheet = [[UIActionSheet alloc] initWithTitle:@"Actions" delegate:self cancelButtonTitle:@"Cancel" destructiveButtonTitle:@"Trash" otherButtonTitles:mail.read ? @"Mark as unread": @"Mark as read", @"Flag", nil];
[sheet showInView:self.view];
}
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
actionCallback(buttonIndex == actionSheet.cancelButtonIndex, buttonIndex == actionSheet.destructiveButtonIndex, buttonIndex);
actionCallback = nil;
}
-(NSString *) readButtonText:(BOOL) read
{
return read ? @"Mark as\nunread" :@"Mark as\nread";
}
#pragma mark Table Delegate
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return demoData.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString * identifier = @"MailCell";
MailTableCell * cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (!cell) {
cell = [[MailTableCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
}
cell.delegate = self;
MailData * data = [demoData objectAtIndex:indexPath.row];
cell.mailFrom.text = data.from;
cell.mailSubject.text = data.subject;
cell.mailMessage.text = data.message;
cell.mailTime.text = data.date;
[self updateCellIndicactor:data cell:cell];
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 110;
}
#pragma mark Swipe Delegate
-(BOOL) swipeTableCell:(MGSwipeTableCell*) cell canSwipe:(MGSwipeDirection) direction;
{
return YES;
}
-(NSArray*) swipeTableCell:(MGSwipeTableCell*) cell swipeButtonsForDirection:(MGSwipeDirection)direction
swipeSettings:(MGSwipeSettings*) swipeSettings expansionSettings:(MGSwipeExpansionSettings*) expansionSettings
{
swipeSettings.transition = MGSwipeTransitionBorder;
expansionSettings.buttonIndex = 0;
__weak MailViewController * me = self;
MailData * mail = [me mailForIndexPath:[self.tableView indexPathForCell:cell]];
if (direction == MGSwipeDirectionLeftToRight) {
expansionSettings.fillOnTrigger = NO;
expansionSettings.threshold = 2;
return @[[MGSwipeButton buttonWithTitle:[me readButtonText:mail.read] backgroundColor:[UIColor colorWithRed:0 green:122/255.0 blue:1.0 alpha:1.0] padding:5 callback:^BOOL(MGSwipeTableCell *sender) {
MailData * mail = [me mailForIndexPath:[me.tableView indexPathForCell:sender]];
mail.read = !mail.read;
[me updateCellIndicactor:mail cell:(MailTableCell*)sender];
[cell refreshContentView]; //needed to refresh cell contents while swipping
//change button text
[(UIButton*)[cell.leftButtons objectAtIndex:0] setTitle:[me readButtonText:mail.read] forState:UIControlStateNormal];
return YES;
}]];
}
else {
expansionSettings.fillOnTrigger = YES;
expansionSettings.threshold = 1.1;
CGFloat padding = 15;
MGSwipeButton * trash = [MGSwipeButton buttonWithTitle:@"Trash" backgroundColor:[UIColor colorWithRed:1.0 green:59/255.0 blue:50/255.0 alpha:1.0] padding:padding callback:^BOOL(MGSwipeTableCell *sender) {
NSIndexPath * indexPath = [me.tableView indexPathForCell:sender];
[me deleteMail:indexPath];
return NO; //don't autohide to improve delete animation
}];
MGSwipeButton * flag = [MGSwipeButton buttonWithTitle:@"Flag" backgroundColor:[UIColor colorWithRed:1.0 green:149/255.0 blue:0.05 alpha:1.0] padding:padding callback:^BOOL(MGSwipeTableCell *sender) {
MailData * mail = [me mailForIndexPath:[me.tableView indexPathForCell:sender]];
mail.flag = !mail.flag;
[me updateCellIndicactor:mail cell:(MailTableCell*)sender];
[cell refreshContentView]; //needed to refresh cell contents while swipping
return YES;
}];
MGSwipeButton * more = [MGSwipeButton buttonWithTitle:@"More" backgroundColor:[UIColor colorWithRed:200/255.0 green:200/255.0 blue:205/255.0 alpha:1.0] padding:padding callback:^BOOL(MGSwipeTableCell *sender) {
NSIndexPath * indexPath = [me.tableView indexPathForCell:sender];
MailData * mail = [me mailForIndexPath:indexPath];
MailTableCell * cell = (MailTableCell*) sender;
[me showMailActions:mail callback:^(BOOL cancelled, BOOL deleted, NSInteger actionIndex) {
if (cancelled) {
return;
}
if (deleted) {
[me deleteMail:indexPath];
}
else if (actionIndex == 1) {
mail.read = !mail.read;
[(UIButton*)[cell.leftButtons objectAtIndex:0] setTitle:[me readButtonText:mail.read] forState:UIControlStateNormal];
[me updateCellIndicactor:mail cell:cell];
[cell refreshContentView]; //needed to refresh cell contents while swipping
}
else if (actionIndex == 2) {
mail.flag = !mail.flag;
[me updateCellIndicactor:mail cell:cell];
[cell refreshContentView]; //needed to refresh cell contents while swipping
}
[cell hideSwipeAnimated:YES];
}];
return NO; //avoid autohide swipe
}];
return @[trash, flag, more];
}
return nil;
}
-(void) swipeTableCell:(MGSwipeTableCell*) cell didChangeSwipeState:(MGSwipeState)state gestureIsActive:(BOOL)gestureIsActive
{
NSString * str;
switch (state) {
case MGSwipeStateNone: str = @"None"; break;
case MGSwipeStateSwippingLeftToRight: str = @"SwippingLeftToRight"; break;
case MGSwipeStateSwippingRightToLeft: str = @"SwippingRightToLeft"; break;
case MGSwipeStateExpandingLeftToRight: str = @"ExpandingLeftToRight"; break;
case MGSwipeStateExpandingRightToLeft: str = @"ExpandingRightToLeft"; break;
}
NSLog(@"Swipe state: %@ ::: Gesture: %@", str, gestureIsActive ? @"Active" : @"Ended");
}
@end

View file

@ -0,0 +1,16 @@
//
// main.m
// MailAppDemo
//
// Created by Imanol Fernandez Gorostizaga on 26/09/14.
// Copyright (c) 2014 Mortimer. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
int main(int argc, char * argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}

View file

@ -0,0 +1,455 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
11E2036A1A1A9B440084A446 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11E203691A1A9B440084A446 /* AppDelegate.swift */; };
11E2036C1A1A9B440084A446 /* MailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11E2036B1A1A9B440084A446 /* MailViewController.swift */; };
11E203711A1A9B440084A446 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 11E203701A1A9B440084A446 /* Images.xcassets */; };
11E203741A1A9B440084A446 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 11E203721A1A9B440084A446 /* LaunchScreen.xib */; };
11E203801A1A9B440084A446 /* MailAppDemoSwiftTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11E2037F1A1A9B440084A446 /* MailAppDemoSwiftTests.swift */; };
11E2038A1A1A9CEF0084A446 /* MailTableCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11E203891A1A9CEF0084A446 /* MailTableCell.swift */; };
11FC3C8B1B6C132A0067CA0A /* MGSwipeButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 11FC3C881B6C132A0067CA0A /* MGSwipeButton.m */; };
11FC3C8C1B6C132A0067CA0A /* MGSwipeTableCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 11FC3C8A1B6C132A0067CA0A /* MGSwipeTableCell.m */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
11E2037A1A1A9B440084A446 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 11E2035C1A1A9B440084A446 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 11E203631A1A9B440084A446;
remoteInfo = MailAppDemoSwift;
};
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
11E203641A1A9B440084A446 /* MailAppDemoSwift.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MailAppDemoSwift.app; sourceTree = BUILT_PRODUCTS_DIR; };
11E203681A1A9B440084A446 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
11E203691A1A9B440084A446 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
11E2036B1A1A9B440084A446 /* MailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MailViewController.swift; sourceTree = "<group>"; };
11E203701A1A9B440084A446 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
11E203731A1A9B440084A446 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = "<group>"; };
11E203791A1A9B440084A446 /* MailAppDemoSwiftTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MailAppDemoSwiftTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
11E2037E1A1A9B440084A446 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
11E2037F1A1A9B440084A446 /* MailAppDemoSwiftTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MailAppDemoSwiftTests.swift; sourceTree = "<group>"; };
11E203891A1A9CEF0084A446 /* MailTableCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MailTableCell.swift; sourceTree = "<group>"; };
11FC3C871B6C132A0067CA0A /* MGSwipeButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MGSwipeButton.h; path = ../../MGSwipeTableCell/MGSwipeButton.h; sourceTree = "<group>"; };
11FC3C881B6C132A0067CA0A /* MGSwipeButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGSwipeButton.m; path = ../../MGSwipeTableCell/MGSwipeButton.m; sourceTree = "<group>"; };
11FC3C891B6C132A0067CA0A /* MGSwipeTableCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MGSwipeTableCell.h; path = ../../MGSwipeTableCell/MGSwipeTableCell.h; sourceTree = "<group>"; };
11FC3C8A1B6C132A0067CA0A /* MGSwipeTableCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGSwipeTableCell.m; path = ../../MGSwipeTableCell/MGSwipeTableCell.m; sourceTree = "<group>"; };
11FC3C8D1B6C15230067CA0A /* ObjCBridgingHeader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ObjCBridgingHeader.h; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
11E203611A1A9B440084A446 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
11E203761A1A9B440084A446 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
11E2035B1A1A9B440084A446 = {
isa = PBXGroup;
children = (
11FC3C861B6C13180067CA0A /* MGSwipeTableCell */,
11E203661A1A9B440084A446 /* MailAppDemoSwift */,
11E2037C1A1A9B440084A446 /* MailAppDemoSwiftTests */,
11E203651A1A9B440084A446 /* Products */,
);
sourceTree = "<group>";
};
11E203651A1A9B440084A446 /* Products */ = {
isa = PBXGroup;
children = (
11E203641A1A9B440084A446 /* MailAppDemoSwift.app */,
11E203791A1A9B440084A446 /* MailAppDemoSwiftTests.xctest */,
);
name = Products;
sourceTree = "<group>";
};
11E203661A1A9B440084A446 /* MailAppDemoSwift */ = {
isa = PBXGroup;
children = (
11E203691A1A9B440084A446 /* AppDelegate.swift */,
11E2036B1A1A9B440084A446 /* MailViewController.swift */,
11E203891A1A9CEF0084A446 /* MailTableCell.swift */,
11FC3C8D1B6C15230067CA0A /* ObjCBridgingHeader.h */,
11E203701A1A9B440084A446 /* Images.xcassets */,
11E203721A1A9B440084A446 /* LaunchScreen.xib */,
11E203671A1A9B440084A446 /* Supporting Files */,
);
path = MailAppDemoSwift;
sourceTree = "<group>";
};
11E203671A1A9B440084A446 /* Supporting Files */ = {
isa = PBXGroup;
children = (
11E203681A1A9B440084A446 /* Info.plist */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
11E2037C1A1A9B440084A446 /* MailAppDemoSwiftTests */ = {
isa = PBXGroup;
children = (
11E2037F1A1A9B440084A446 /* MailAppDemoSwiftTests.swift */,
11E2037D1A1A9B440084A446 /* Supporting Files */,
);
path = MailAppDemoSwiftTests;
sourceTree = "<group>";
};
11E2037D1A1A9B440084A446 /* Supporting Files */ = {
isa = PBXGroup;
children = (
11E2037E1A1A9B440084A446 /* Info.plist */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
11FC3C861B6C13180067CA0A /* MGSwipeTableCell */ = {
isa = PBXGroup;
children = (
11FC3C871B6C132A0067CA0A /* MGSwipeButton.h */,
11FC3C881B6C132A0067CA0A /* MGSwipeButton.m */,
11FC3C891B6C132A0067CA0A /* MGSwipeTableCell.h */,
11FC3C8A1B6C132A0067CA0A /* MGSwipeTableCell.m */,
);
name = MGSwipeTableCell;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
11E203631A1A9B440084A446 /* MailAppDemoSwift */ = {
isa = PBXNativeTarget;
buildConfigurationList = 11E203831A1A9B440084A446 /* Build configuration list for PBXNativeTarget "MailAppDemoSwift" */;
buildPhases = (
11E203601A1A9B440084A446 /* Sources */,
11E203611A1A9B440084A446 /* Frameworks */,
11E203621A1A9B440084A446 /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = MailAppDemoSwift;
productName = MailAppDemoSwift;
productReference = 11E203641A1A9B440084A446 /* MailAppDemoSwift.app */;
productType = "com.apple.product-type.application";
};
11E203781A1A9B440084A446 /* MailAppDemoSwiftTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 11E203861A1A9B440084A446 /* Build configuration list for PBXNativeTarget "MailAppDemoSwiftTests" */;
buildPhases = (
11E203751A1A9B440084A446 /* Sources */,
11E203761A1A9B440084A446 /* Frameworks */,
11E203771A1A9B440084A446 /* Resources */,
);
buildRules = (
);
dependencies = (
11E2037B1A1A9B440084A446 /* PBXTargetDependency */,
);
name = MailAppDemoSwiftTests;
productName = MailAppDemoSwiftTests;
productReference = 11E203791A1A9B440084A446 /* MailAppDemoSwiftTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
11E2035C1A1A9B440084A446 /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftMigration = 0730;
LastSwiftUpdateCheck = 0730;
LastUpgradeCheck = 0610;
ORGANIZATIONNAME = "Imanol Fernandez";
TargetAttributes = {
11E203631A1A9B440084A446 = {
CreatedOnToolsVersion = 6.1;
LastSwiftMigration = 0810;
};
11E203781A1A9B440084A446 = {
CreatedOnToolsVersion = 6.1;
DevelopmentTeam = 4W4992Q3W8;
LastSwiftMigration = 0810;
TestTargetID = 11E203631A1A9B440084A446;
};
};
};
buildConfigurationList = 11E2035F1A1A9B440084A446 /* Build configuration list for PBXProject "MailAppDemoSwift" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 11E2035B1A1A9B440084A446;
productRefGroup = 11E203651A1A9B440084A446 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
11E203631A1A9B440084A446 /* MailAppDemoSwift */,
11E203781A1A9B440084A446 /* MailAppDemoSwiftTests */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
11E203621A1A9B440084A446 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
11E203741A1A9B440084A446 /* LaunchScreen.xib in Resources */,
11E203711A1A9B440084A446 /* Images.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
11E203771A1A9B440084A446 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
11E203601A1A9B440084A446 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
11E2038A1A1A9CEF0084A446 /* MailTableCell.swift in Sources */,
11E2036C1A1A9B440084A446 /* MailViewController.swift in Sources */,
11FC3C8B1B6C132A0067CA0A /* MGSwipeButton.m in Sources */,
11E2036A1A1A9B440084A446 /* AppDelegate.swift in Sources */,
11FC3C8C1B6C132A0067CA0A /* MGSwipeTableCell.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
11E203751A1A9B440084A446 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
11E203801A1A9B440084A446 /* MailAppDemoSwiftTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
11E2037B1A1A9B440084A446 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 11E203631A1A9B440084A446 /* MailAppDemoSwift */;
targetProxy = 11E2037A1A1A9B440084A446 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
11E203721A1A9B440084A446 /* LaunchScreen.xib */ = {
isa = PBXVariantGroup;
children = (
11E203731A1A9B440084A446 /* Base */,
);
name = LaunchScreen.xib;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
11E203811A1A9B440084A446 /* 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 = 8.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
11E203821A1A9B440084A446 /* 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 = 8.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
11E203841A1A9B440084A446 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_IDENTITY = "iPhone Developer";
DEVELOPMENT_TEAM = "";
INFOPLIST_FILE = MailAppDemoSwift/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE = "";
SWIFT_OBJC_BRIDGING_HEADER = MailAppDemoSwift/ObjCBridgingHeader.h;
SWIFT_VERSION = 3.0;
};
name = Debug;
};
11E203851A1A9B440084A446 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_IDENTITY = "iPhone Developer";
DEVELOPMENT_TEAM = "";
INFOPLIST_FILE = MailAppDemoSwift/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE = "";
SWIFT_OBJC_BRIDGING_HEADER = MailAppDemoSwift/ObjCBridgingHeader.h;
SWIFT_VERSION = 3.0;
};
name = Release;
};
11E203871A1A9B440084A446 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
FRAMEWORK_SEARCH_PATHS = (
"$(SDKROOT)/Developer/Library/Frameworks",
"$(inherited)",
);
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
INFOPLIST_FILE = MailAppDemoSwiftTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 3.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/MailAppDemoSwift.app/MailAppDemoSwift";
};
name = Debug;
};
11E203881A1A9B440084A446 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
FRAMEWORK_SEARCH_PATHS = (
"$(SDKROOT)/Developer/Library/Frameworks",
"$(inherited)",
);
INFOPLIST_FILE = MailAppDemoSwiftTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 3.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/MailAppDemoSwift.app/MailAppDemoSwift";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
11E2035F1A1A9B440084A446 /* Build configuration list for PBXProject "MailAppDemoSwift" */ = {
isa = XCConfigurationList;
buildConfigurations = (
11E203811A1A9B440084A446 /* Debug */,
11E203821A1A9B440084A446 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
11E203831A1A9B440084A446 /* Build configuration list for PBXNativeTarget "MailAppDemoSwift" */ = {
isa = XCConfigurationList;
buildConfigurations = (
11E203841A1A9B440084A446 /* Debug */,
11E203851A1A9B440084A446 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
11E203861A1A9B440084A446 /* Build configuration list for PBXNativeTarget "MailAppDemoSwiftTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
11E203871A1A9B440084A446 /* Debug */,
11E203881A1A9B440084A446 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 11E2035C1A1A9B440084A446 /* Project object */;
}

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:MailAppDemoSwift.xcodeproj">
</FileRef>
</Workspace>

View file

@ -0,0 +1,52 @@
//
// AppDelegate.swift
// MailAppDemoSwift
//
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds);
let controller = MailViewController();
let navigation = UINavigationController(rootViewController: controller);
window?.rootViewController = navigation;
window?.backgroundColor = UIColor.white;
window?.makeKeyAndVisible();
// Override point for customization after application launch.
return true
}
func applicationWillResignActive(_ application: UIApplication) {
// 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.
}
func applicationDidEnterBackground(_ application: UIApplication) {
// 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.
}
func applicationWillEnterForeground(_ application: UIApplication) {
// 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.
}
func applicationDidBecomeActive(_ application: UIApplication) {
// 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.
}
func applicationWillTerminate(_ application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
}

View file

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="6214" systemVersion="14A314h" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6207"/>
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB">
<rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text=" Copyright (c) 2014 Imanol Fernandez. All rights reserved." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="8ie-xW-0ye">
<rect key="frame" x="20" y="439" width="441" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="MailAppDemoSwift" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="kId-c2-rCX">
<rect key="frame" x="20" y="140" width="441" height="43"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="36"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
<constraints>
<constraint firstItem="kId-c2-rCX" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="bottom" multiplier="1/3" constant="1" id="5cJ-9S-tgC"/>
<constraint firstAttribute="centerX" secondItem="kId-c2-rCX" secondAttribute="centerX" id="Koa-jz-hwk"/>
<constraint firstAttribute="bottom" secondItem="8ie-xW-0ye" secondAttribute="bottom" constant="20" id="Kzo-t9-V3l"/>
<constraint firstItem="8ie-xW-0ye" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="MfP-vx-nX0"/>
<constraint firstAttribute="centerX" secondItem="8ie-xW-0ye" secondAttribute="centerX" id="ZEH-qu-HZ9"/>
<constraint firstItem="kId-c2-rCX" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="fvb-Df-36g"/>
</constraints>
<nil key="simulatedStatusBarMetrics"/>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<point key="canvasLocation" x="548" y="455"/>
</view>
</objects>
</document>

View file

@ -0,0 +1,68 @@
{
"images" : [
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "3x"
},
{
"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"
}
}

View file

@ -0,0 +1,45 @@
<?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>mortimergoro.$(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>UILaunchStoryboardName</key>
<string>LaunchScreen</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>

View file

@ -0,0 +1,120 @@
//
// MailTableCell.swift
// MailAppDemoSwift
//
import UIKit
class MailIndicatorView: UIView {
var indicatorColor : UIColor {
didSet {
self.setNeedsDisplay();
}
}
var innerColor : UIColor? {
didSet {
self.setNeedsDisplay();
}
}
override init(frame:CGRect) {
indicatorColor = UIColor.clear;
super.init(frame:frame);
}
required init?(coder aDecoder: NSCoder) {
indicatorColor = UIColor.clear;
super.init(coder: aDecoder);
}
override func draw(_ rect: CGRect) {
let ctx = UIGraphicsGetCurrentContext();
ctx?.addEllipse(in: rect);
ctx?.setFillColor(indicatorColor.cgColor.components!);
ctx?.fillPath();
if innerColor != nil {
let innerSize = rect.size.width * 0.5;
let innerRect = CGRect(x: rect.origin.x + rect.size.width * 0.5 - innerSize * 0.5,
y: rect.origin.y + rect.size.height * 0.5 - innerSize * 0.5,
width: innerSize, height: innerSize);
ctx?.addEllipse(in: innerRect);
ctx?.setFillColor(innerColor!.cgColor.components!);
ctx?.fillPath();
}
}
}
class MailTableCell: MGSwipeTableCell {
var mailFrom: UILabel!;
var mailSubject: UILabel!;
var mailMessage: UITextView!;
var mailTime: UILabel!;
var indicatorView: MailIndicatorView!;
func initViews() {
mailFrom = UILabel(frame: CGRect.zero);
mailMessage = UITextView(frame: CGRect.zero);
mailSubject = UILabel(frame: CGRect.zero);
mailTime = UILabel(frame: CGRect.zero);
mailFrom.font = UIFont(name:"HelveticaNeue", size:18.0);
mailSubject.font = UIFont(name:"HelveticaNeue-Light", size:15.0);
mailMessage.font = UIFont(name:"HelveticaNeue-Light", size:14.0);
mailTime.font = UIFont(name:"HelveticaNeue-Light", size:13.0);
mailMessage.isScrollEnabled = false;
mailMessage.isEditable = false;
mailMessage.backgroundColor = UIColor.clear;
mailMessage.contentInset = UIEdgeInsetsMake(-5, -5, 0, 0);
mailMessage.textColor = UIColor.gray;
mailMessage.isUserInteractionEnabled = false;
indicatorView = MailIndicatorView(frame: CGRect(x: 0, y: 0, width: 10, height: 10));
indicatorView.backgroundColor = UIColor.clear;
contentView.addSubview(mailFrom);
contentView.addSubview(mailMessage);
contentView.addSubview(mailSubject);
contentView.addSubview(mailTime);
contentView.addSubview(indicatorView);
}
override init(style: UITableViewCellStyle, reuseIdentifier:String?)
{
super.init(style:style, reuseIdentifier: reuseIdentifier);
initViews();
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder);
initViews();
}
override func layoutSubviews() {
super.layoutSubviews();
let leftPadding:CGFloat = 25.0;
let topPadding:CGFloat = 3.0;
let textWidth = contentView.bounds.size.width - 2.0 * leftPadding;
let dateWidth:CGFloat = 40;
mailFrom.frame = CGRect(x: leftPadding, y: topPadding, width: textWidth, height: 20);
mailSubject.frame = CGRect(x: leftPadding, y: mailFrom.frame.origin.y + mailFrom.frame.size.height + topPadding, width: textWidth - dateWidth, height: 17);
let messageHeight = contentView.bounds.size.height - (mailSubject.frame.origin.y + mailSubject.frame.size.height) - topPadding * 2;
mailMessage.frame = CGRect(x: leftPadding, y: mailSubject.frame.origin.y + mailSubject.frame.size.height + topPadding, width: textWidth, height: messageHeight);
var frame = mailFrom.frame;
frame.origin.x = self.contentView.frame.size.width - leftPadding - dateWidth;
frame.size.width = dateWidth;
mailTime.frame = frame;
indicatorView.center = CGPoint(x: leftPadding * 0.5, y: mailFrom.frame.origin.y + mailFrom.frame.size.height * 0.5);
}
}

View file

@ -0,0 +1,277 @@
//
// ViewController.swift
// MailAppDemoSwift
//
import UIKit
class MailData {
var from: String!;
var subject: String!;
var message: String!;
var date: String!;
var read = false;
var flag = false;
}
typealias MailActionCallback = (_ cancelled: Bool, _ deleted: Bool, _ actionIndex: Int) -> Void
class MailViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, MGSwipeTableCellDelegate, UIActionSheetDelegate {
var tableView: UITableView!;
var demoData = [MailData]();
var refreshControl: UIRefreshControl!;
var actionCallback: MailActionCallback?;
func prepareDemoData() {
var from = [
"Vincent",
"Mr Glass",
"Marsellus",
"Ringo",
"Sullivan",
"Mr Wolf",
"Butch Coolidge",
"Marvin",
"Captain Koons",
"Jules",
"Jimmie Dimmick"
];
var subjects = [
"You think water moves fast?",
"They called me Mr Glass",
"The path of the righteous man",
"Do you see any Teletubbies in here?",
"Now that we know who you are",
"My money's in that office, right?",
"Now we took an oath",
"That show's called a pilot",
"I know who I am. I'm not a mistake",
"It all makes sense!",
"The selfish and the tyranny of evil men",
];
var messages = [
"You should see ice. It moves like it has a mind. Like it knows it killed the world once and got a taste for murder. After the avalanche, it took us a week to climb out.",
"And I will strike down upon thee with great vengeance and furious anger those who would attempt to poison and destroy My brothers.",
"Look, just because I don't be givin' no man a foot massage don't make it right for Marsellus to throw Antwone into a glass motherfuckin' house",
"No? Well, that's what you see at a toy store. And you must think you're in a toy store, because you're here shopping for an infant named Jeb.",
"In a comic, you know how you can tell who the arch-villain's going to be? He's the exact opposite of the hero",
"If she start giving me some bullshit about it ain't there, and we got to go someplace else and get it, I'm gonna shoot you in the head then and there.",
"that I'm breaking now. We said we'd say it was the snow that killed the other two, but it wasn't. Nature is lethal but it doesn't hold a candle to man.",
"Then they show that show to the people who make shows, and on the strength of that one show they decide if they're going to make more shows.",
"And most times they're friends, like you and me! I should've known way back when...",
"After the avalanche, it took us a week to climb out. Now, I don't know exactly when we turned on each other, but I know that seven of us survived the slide",
"Blessed is he who, in the name of charity and good will, shepherds the weak through the valley of darkness, for he is truly his brother's keeper and the finder of lost children",
];
for i in 0 ..< messages.count {
let mail = MailData();
mail.from = from[i];
mail.subject = subjects[i];
mail.message = messages[i];
mail.date = String(format: "11:%d", arguments: [43 - i]);
demoData.append(mail);
}
}
func mailForIndexPath(_ path: IndexPath) -> MailData {
return demoData[(path as NSIndexPath).row];
}
func refreshCallback() {
prepareDemoData();
tableView.reloadData();
refreshControl.endRefreshing();
}
func deleteMail(_ path:IndexPath) {
demoData.remove(at: (path as NSIndexPath).row);
tableView.deleteRows(at: [path], with: .left);
}
func updateCellIndicator(_ mail: MailData, cell: MailTableCell) {
var color: UIColor;
var innerColor : UIColor?;
if !mail.read && mail.flag {
color = UIColor.init(red: 1.0, green: 149/255.0, blue: 0.05, alpha: 1.0);
innerColor = UIColor.init(red: 0.0, green: 122/255.0, blue: 1.0, alpha: 1.0);
}
else if mail.flag {
color = UIColor.init(red: 1.0, green: 149/255.0, blue: 0.05, alpha: 1.0);
}
else if mail.read {
color = UIColor.clear;
}
else {
color = UIColor.init(red: 0.0, green: 122/255.0, blue: 1.0, alpha: 1.0);
}
cell.indicatorView.indicatorColor = color;
cell.indicatorView.innerColor = innerColor;
}
func showMailActions(_ mail: MailData, callback: @escaping MailActionCallback) {
actionCallback = callback;
let sheet = UIActionSheet.init(title: "Actions", delegate: self, cancelButtonTitle: "Cancel", destructiveButtonTitle: "Trash");
sheet.addButton(withTitle: "Mark as unread");
sheet.addButton(withTitle: "Mark as read");
sheet.addButton(withTitle: "Flag");
sheet.show(in: self.view);
}
func actionSheet(_ actionSheet: UIActionSheet, clickedButtonAt index: Int) {
if let action = actionCallback {
action(index == actionSheet.cancelButtonIndex,
index == actionSheet.destructiveButtonIndex,
index);
actionCallback = nil;
}
}
func readButtonText(_ read:Bool) -> String {
return read ? "Mark as\nunread" : "Mark as\nread";
}
override func viewDidLoad() {
super.viewDidLoad()
tableView = UITableView(frame: view.bounds, style: UITableViewStyle.plain);
tableView.delegate = self;
tableView.dataSource = self;
view.addSubview(tableView);
self.title = "MSwipeTableCell MailApp";
refreshControl = UIRefreshControl();
refreshControl.addTarget(self, action: #selector(refreshCallback), for: UIControlEvents.valueChanged);
tableView.addSubview(refreshControl);
prepareDemoData();
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return demoData.count;
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let identifier = "MailCell";
var cell: MailTableCell! = tableView.dequeueReusableCell(withIdentifier: identifier) as? MailTableCell;
if cell == nil {
cell = MailTableCell(style: UITableViewCellStyle.default, reuseIdentifier: identifier);
}
cell.delegate = self;
let data: MailData = demoData[(indexPath as NSIndexPath).row];
cell!.mailFrom.text = data.from;
cell!.mailSubject.text = data.subject;
cell!.mailMessage.text = data.message;
cell!.mailTime.text = data.date;
updateCellIndicator(data, cell: cell);
return cell;
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 110;
}
func swipeTableCell(_ cell: MGSwipeTableCell, canSwipe direction: MGSwipeDirection) -> Bool {
return true;
}
func swipeTableCell(_ cell: MGSwipeTableCell, swipeButtonsFor direction: MGSwipeDirection, swipeSettings: MGSwipeSettings, expansionSettings: MGSwipeExpansionSettings) -> [UIView]? {
swipeSettings.transition = MGSwipeTransition.border;
expansionSettings.buttonIndex = 0;
let mail = mailForIndexPath(tableView.indexPath(for: cell)!);
if direction == MGSwipeDirection.leftToRight {
expansionSettings.fillOnTrigger = false;
expansionSettings.threshold = 2;
let color = UIColor.init(red:0.0, green:122/255.0, blue:1.0, alpha:1.0);
return [
MGSwipeButton(title: readButtonText(mail.read), backgroundColor: color, callback: { (cell) -> Bool in
mail.read = !mail.read;
self.updateCellIndicator(mail, cell: cell as! MailTableCell);
cell.refreshContentView();
(cell.leftButtons[0] as! UIButton).setTitle(self.readButtonText(mail.read), for: UIControlState());
return true;
})
]
}
else {
expansionSettings.fillOnTrigger = true;
expansionSettings.threshold = 1.1;
let padding = 15;
let color1 = UIColor.init(red:1.0, green:59/255.0, blue:50/255.0, alpha:1.0);
let color2 = UIColor.init(red:1.0, green:149/255.0, blue:0.05, alpha:1.0);
let color3 = UIColor.init(red:200/255.0, green:200/255.0, blue:205/255.0, alpha:1.0);
let trash = MGSwipeButton(title: "Trash", backgroundColor: color1, padding: padding, callback: { (cell) -> Bool in
self.deleteMail(self.tableView.indexPath(for: cell)!);
return false; //don't autohide to improve delete animation
});
let flag = MGSwipeButton(title: "Flag", backgroundColor: color2, padding: padding, callback: { (cell) -> Bool in
let mail = self.mailForIndexPath(self.tableView.indexPath(for: cell)!);
mail.flag = !mail.flag;
self.updateCellIndicator(mail, cell: cell as! MailTableCell);
cell.refreshContentView(); //needed to refresh cell contents while swipping
return true; //autohide
});
let more = MGSwipeButton(title: "More", backgroundColor: color3, padding: padding, callback: { (cell) -> Bool in
let path = self.tableView.indexPath(for: cell)!;
let mail = self.mailForIndexPath(path);
self.showMailActions(mail, callback: { (cancelled, deleted, index) in
if cancelled {
return;
}
else if deleted {
self.deleteMail(path);
}
else if index == 1 {
mail.read = !mail.read;
self.updateCellIndicator(mail, cell: cell as! MailTableCell);
cell.refreshContentView();
(cell.leftButtons[0] as! UIButton).setTitle(self.readButtonText(mail.read), for: UIControlState());
cell.hideSwipe(animated: true);
}
else if index == 2 {
mail.flag = !mail.flag;
self.updateCellIndicator(mail, cell: cell as! MailTableCell);
cell.refreshContentView(); //needed to refresh cell contents while swipping
cell.hideSwipe(animated: true);
}
});
return false; // Don't autohide
});
return [trash, flag, more];
}
}
}

View file

@ -0,0 +1,2 @@
#import "MGSwipeTableCell.h"
#import "MGSwipeButton.h"

View file

@ -0,0 +1,24 @@
<?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>mortimergoro.$(PRODUCT_NAME:rfc1034identifier)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>

View file

@ -0,0 +1,36 @@
//
// MailAppDemoSwiftTests.swift
// MailAppDemoSwiftTests
//
// Created by Imanol Fernandez Gorostizag on 17/11/14.
// Copyright (c) 2014 Imanol Fernandez. All rights reserved.
//
import UIKit
import XCTest
class MailAppDemoSwiftTests: XCTestCase {
override func setUp() {
super.setUp()
// Put setup code here. This method is called before the invocation of each test method in the class.
}
override func tearDown() {
// Put teardown code here. This method is called after the invocation of each test method in the class.
super.tearDown()
}
func testExample() {
// This is an example of a functional test case.
XCTAssert(true, "Pass")
}
func testPerformanceExample() {
// This is an example of a performance test case.
self.measure() {
// Put the code you want to measure the time of here.
}
}
}

View file

@ -0,0 +1,305 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
110B828F1B5E9E7C00423D6D /* more@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 110B828E1B5E9E7C00423D6D /* more@2x.png */; };
11754E2919D5C1EA009CE7B5 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 11754E2819D5C1EA009CE7B5 /* main.m */; };
11754E2C19D5C1EA009CE7B5 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 11754E2B19D5C1EA009CE7B5 /* AppDelegate.m */; };
11754E2F19D5C1EA009CE7B5 /* SpotifyViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 11754E2E19D5C1EA009CE7B5 /* SpotifyViewController.m */; };
11754E3419D5C1EA009CE7B5 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 11754E3319D5C1EA009CE7B5 /* Images.xcassets */; };
11754E5419D5C3E5009CE7B5 /* MGSwipeButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 11754E5219D5C3E5009CE7B5 /* MGSwipeButton.m */; };
11754E5519D5C3E5009CE7B5 /* MGSwipeTableCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 11754E5319D5C3E5009CE7B5 /* MGSwipeTableCell.m */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
110B828E1B5E9E7C00423D6D /* more@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "more@2x.png"; sourceTree = "<group>"; };
11754E2319D5C1EA009CE7B5 /* SpotifyDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SpotifyDemo.app; sourceTree = BUILT_PRODUCTS_DIR; };
11754E2719D5C1EA009CE7B5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
11754E2819D5C1EA009CE7B5 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
11754E2A19D5C1EA009CE7B5 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
11754E2B19D5C1EA009CE7B5 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
11754E2D19D5C1EA009CE7B5 /* SpotifyViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SpotifyViewController.h; sourceTree = "<group>"; };
11754E2E19D5C1EA009CE7B5 /* SpotifyViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SpotifyViewController.m; sourceTree = "<group>"; };
11754E3319D5C1EA009CE7B5 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
11754E5019D5C3E5009CE7B5 /* MGSwipeButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MGSwipeButton.h; path = ../../MGSwipeTableCell/MGSwipeButton.h; sourceTree = "<group>"; };
11754E5119D5C3E5009CE7B5 /* MGSwipeTableCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MGSwipeTableCell.h; path = ../../MGSwipeTableCell/MGSwipeTableCell.h; sourceTree = "<group>"; };
11754E5219D5C3E5009CE7B5 /* MGSwipeButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGSwipeButton.m; path = ../../MGSwipeTableCell/MGSwipeButton.m; sourceTree = "<group>"; };
11754E5319D5C3E5009CE7B5 /* MGSwipeTableCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGSwipeTableCell.m; path = ../../MGSwipeTableCell/MGSwipeTableCell.m; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
11754E2019D5C1EA009CE7B5 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
11754E1A19D5C1EA009CE7B5 = {
isa = PBXGroup;
children = (
11754E4F19D5C3CE009CE7B5 /* MGSwipeTableCell */,
11754E2519D5C1EA009CE7B5 /* SpotifyDemo */,
11754E2419D5C1EA009CE7B5 /* Products */,
);
sourceTree = "<group>";
};
11754E2419D5C1EA009CE7B5 /* Products */ = {
isa = PBXGroup;
children = (
11754E2319D5C1EA009CE7B5 /* SpotifyDemo.app */,
);
name = Products;
sourceTree = "<group>";
};
11754E2519D5C1EA009CE7B5 /* SpotifyDemo */ = {
isa = PBXGroup;
children = (
110B828E1B5E9E7C00423D6D /* more@2x.png */,
11754E2A19D5C1EA009CE7B5 /* AppDelegate.h */,
11754E2B19D5C1EA009CE7B5 /* AppDelegate.m */,
11754E2D19D5C1EA009CE7B5 /* SpotifyViewController.h */,
11754E2E19D5C1EA009CE7B5 /* SpotifyViewController.m */,
11754E3319D5C1EA009CE7B5 /* Images.xcassets */,
11754E2619D5C1EA009CE7B5 /* Supporting Files */,
);
path = SpotifyDemo;
sourceTree = "<group>";
};
11754E2619D5C1EA009CE7B5 /* Supporting Files */ = {
isa = PBXGroup;
children = (
11754E2719D5C1EA009CE7B5 /* Info.plist */,
11754E2819D5C1EA009CE7B5 /* main.m */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
11754E4F19D5C3CE009CE7B5 /* MGSwipeTableCell */ = {
isa = PBXGroup;
children = (
11754E5019D5C3E5009CE7B5 /* MGSwipeButton.h */,
11754E5219D5C3E5009CE7B5 /* MGSwipeButton.m */,
11754E5119D5C3E5009CE7B5 /* MGSwipeTableCell.h */,
11754E5319D5C3E5009CE7B5 /* MGSwipeTableCell.m */,
);
name = MGSwipeTableCell;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
11754E2219D5C1EA009CE7B5 /* SpotifyDemo */ = {
isa = PBXNativeTarget;
buildConfigurationList = 11754E4619D5C1EA009CE7B5 /* Build configuration list for PBXNativeTarget "SpotifyDemo" */;
buildPhases = (
11754E1F19D5C1EA009CE7B5 /* Sources */,
11754E2019D5C1EA009CE7B5 /* Frameworks */,
11754E2119D5C1EA009CE7B5 /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = SpotifyDemo;
productName = SpotifyDemo;
productReference = 11754E2319D5C1EA009CE7B5 /* SpotifyDemo.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
11754E1B19D5C1EA009CE7B5 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0600;
ORGANIZATIONNAME = Mortimer;
TargetAttributes = {
11754E2219D5C1EA009CE7B5 = {
CreatedOnToolsVersion = 6.0.1;
};
};
};
buildConfigurationList = 11754E1E19D5C1EA009CE7B5 /* Build configuration list for PBXProject "SpotifyDemo" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 11754E1A19D5C1EA009CE7B5;
productRefGroup = 11754E2419D5C1EA009CE7B5 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
11754E2219D5C1EA009CE7B5 /* SpotifyDemo */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
11754E2119D5C1EA009CE7B5 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
11754E3419D5C1EA009CE7B5 /* Images.xcassets in Resources */,
110B828F1B5E9E7C00423D6D /* more@2x.png in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
11754E1F19D5C1EA009CE7B5 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
11754E2F19D5C1EA009CE7B5 /* SpotifyViewController.m in Sources */,
11754E5519D5C3E5009CE7B5 /* MGSwipeTableCell.m in Sources */,
11754E5419D5C3E5009CE7B5 /* MGSwipeButton.m in Sources */,
11754E2C19D5C1EA009CE7B5 /* AppDelegate.m in Sources */,
11754E2919D5C1EA009CE7B5 /* main.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
11754E4419D5C1EA009CE7B5 /* 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 = 5.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
11754E4519D5C1EA009CE7B5 /* 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 = 5.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
11754E4719D5C1EA009CE7B5 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = SpotifyDemo/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_NAME = SpotifyDemo;
};
name = Debug;
};
11754E4819D5C1EA009CE7B5 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = SpotifyDemo/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_NAME = SpotifyDemo;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
11754E1E19D5C1EA009CE7B5 /* Build configuration list for PBXProject "SpotifyDemo" */ = {
isa = XCConfigurationList;
buildConfigurations = (
11754E4419D5C1EA009CE7B5 /* Debug */,
11754E4519D5C1EA009CE7B5 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
11754E4619D5C1EA009CE7B5 /* Build configuration list for PBXNativeTarget "SpotifyDemo" */ = {
isa = XCConfigurationList;
buildConfigurations = (
11754E4719D5C1EA009CE7B5 /* Debug */,
11754E4819D5C1EA009CE7B5 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 11754E1B19D5C1EA009CE7B5 /* Project object */;
}

View file

@ -0,0 +1,14 @@
/*
* MGSwipeTableCell is licensed under MIT license. See LICENSE.md file for more information.
* Copyright (c) 2014 Imanol Fernandez @MortimerGoro
*/
#import <UIKit/UIKit.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@end

View file

@ -0,0 +1,48 @@
/*
* MGSwipeTableCell is licensed under MIT license. See LICENSE.md file for more information.
* Copyright (c) 2014 Imanol Fernandez @MortimerGoro
*/
#import "AppDelegate.h"
#import "SpotifyViewController.h"
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
SpotifyViewController * vc = [[SpotifyViewController alloc] init];
UINavigationController * navigation = [[UINavigationController alloc] initWithRootViewController:vc];
navigation.navigationBar.translucent = NO;
self.window.rootViewController = navigation;
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
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

View file

@ -0,0 +1,68 @@
{
"images" : [
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "3x"
},
{
"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"
}
}

View file

@ -0,0 +1,89 @@
{
"images" : [
{
"idiom" : "iphone",
"scale" : "1x",
"orientation" : "portrait"
},
{
"idiom" : "iphone",
"scale" : "2x",
"orientation" : "portrait"
},
{
"orientation" : "portrait",
"idiom" : "iphone",
"subtype" : "retina4",
"scale" : "2x"
},
{
"orientation" : "portrait",
"idiom" : "iphone",
"minimum-system-version" : "7.0",
"scale" : "2x"
},
{
"orientation" : "portrait",
"idiom" : "iphone",
"minimum-system-version" : "7.0",
"subtype" : "retina4",
"scale" : "2x"
},
{
"orientation" : "portrait",
"idiom" : "ipad",
"extent" : "to-status-bar",
"scale" : "1x"
},
{
"orientation" : "portrait",
"idiom" : "ipad",
"extent" : "to-status-bar",
"scale" : "2x"
},
{
"orientation" : "landscape",
"idiom" : "ipad",
"extent" : "to-status-bar",
"scale" : "1x"
},
{
"orientation" : "landscape",
"idiom" : "ipad",
"extent" : "to-status-bar",
"scale" : "2x"
},
{
"orientation" : "portrait",
"idiom" : "ipad",
"minimum-system-version" : "7.0",
"extent" : "full-screen",
"scale" : "1x"
},
{
"orientation" : "portrait",
"idiom" : "ipad",
"minimum-system-version" : "7.0",
"extent" : "full-screen",
"scale" : "2x"
},
{
"orientation" : "landscape",
"idiom" : "ipad",
"minimum-system-version" : "7.0",
"extent" : "full-screen",
"scale" : "1x"
},
{
"orientation" : "landscape",
"idiom" : "ipad",
"minimum-system-version" : "7.0",
"extent" : "full-screen",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View file

@ -0,0 +1,47 @@
<?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.mortimergoro.spotifydemo</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>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UIStatusBarHidden</key>
<true/>
<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>

View file

@ -0,0 +1,14 @@
/*
* MGSwipeTableCell is licensed under MIT license. See LICENSE.md file for more information.
* Copyright (c) 2014 Imanol Fernandez @MortimerGoro
*/
#import <UIKit/UIKit.h>
#import "MGSwipeTableCell.h"
@interface SpotifyViewController : UIViewController<UITableViewDelegate, UITableViewDataSource, MGSwipeTableCellDelegate, UIActionSheetDelegate>
@property (nonatomic, strong) UITableView * tableView;
@end

View file

@ -0,0 +1,223 @@
/*
* MGSwipeTableCell is licensed under MIT license. See LICENSE.md file for more information.
* Copyright (c) 2014 Imanol Fernandez @MortimerGoro
*/
#import "SpotifyViewController.h"
#import "MGSwipeButton.h"
@interface SongData : NSObject
@property (nonatomic, strong) NSString * title;
@property (nonatomic, strong) NSString * album;
@end
@implementation SongData
@end
typedef void(^MailActionCallback)(BOOL cancelled, BOOL deleted, NSInteger actionIndex);
@implementation SpotifyViewController
{
NSMutableArray * demoData;
MailActionCallback actionCallback;
UIRefreshControl * refreshControl;
}
-(BOOL) prefersStatusBarHidden
{
return YES;
}
-(void) prepareDemoData
{
demoData = [NSMutableArray array];
NSArray * titles = @[
@"Vincent",
@"Mr Glass",
@"Marsellus",
@"Ringo",
@"Sullivan",
@"Mr Wolf",
@"Butch Coolidge",
@"Marvin",
@"Captain Koons",
@"Jules",
@"Jimmie Dimmick"
];
NSArray * albums = @[
@"You think water moves fast?",
@"They called me Mr Glass",
@"The path of the righteous man",
@"Do you see any Teletubbies in here?",
@"Now that we know who you are",
@"My money's in that office, right?",
@"Now we took an oath",
@"That show's called a pilot",
@"I know who I am. I'm not a mistake",
@"It all makes sense!",
@"The selfish and the tyranny of evil men",
];
for (int i = 0; i < titles.count; ++i) {
SongData * song = [[SongData alloc] init];
song.title = [titles objectAtIndex:i];
song.album = [albums objectAtIndex:i];
[demoData addObject:song];
}
}
-(void) refreshCallback
{
[self prepareDemoData];
[_tableView reloadData];
[refreshControl endRefreshing];
}
- (void)viewDidLoad {
[super viewDidLoad];
[self.navigationController setNavigationBarHidden:YES animated:NO];
_tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];
_tableView.delegate = self;
_tableView.dataSource = self;
_tableView.separatorColor = [UIColor clearColor];
_tableView.backgroundColor = [UIColor colorWithRed:15/255.0 green:16/255.0 blue:16/255.0 alpha:1.0];
[self.view addSubview:_tableView];
self.title = @"Spotify App Demo";
refreshControl = [[UIRefreshControl alloc] init];
[refreshControl addTarget:self action:@selector(refreshCallback) forControlEvents:UIControlEventValueChanged];
[self.tableView addSubview:refreshControl];
[self prepareDemoData];
}
-(void) viewDidAppear:(BOOL)animated
{
[self.tableView reloadData];
}
-(void) viewWillLayoutSubviews
{
[super viewWillLayoutSubviews];
_tableView.frame = self.view.bounds;
}
-(void) deleteMail:(NSIndexPath *) indexPath
{
[demoData removeObjectAtIndex:indexPath.row];
[_tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationLeft];
}
-(SongData *) songForIndexPath:(NSIndexPath*) path
{
return [demoData objectAtIndex:path.row];
}
#pragma mark Table Delegate
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return demoData.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString * identifier = @"SongCell";
MGSwipeTableCell * cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (!cell) {
cell = [[MGSwipeTableCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:identifier];
cell.textLabel.font = [UIFont fontWithName:@"HelveticaNeue-Light" size:21.0f];
cell.textLabel.textColor = [UIColor colorWithRed:152/255.0 green:152/255.0 blue:157/255.0 alpha:1.0];
cell.textLabel.font = [UIFont fontWithName:@"HelveticaNeue-Light" size:17.0f];
cell.detailTextLabel.textColor = cell.textLabel.textColor;
cell.backgroundColor = [UIColor colorWithRed:15/255.0 green:16/255.0 blue:16/255.0 alpha:1.0];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
UIImageView * view = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"more.png"]];
view.contentMode = UIViewContentModeScaleAspectFit;
view.frame = CGRectMake(0, 0, 25, 25);
cell.accessoryView = view;
}
cell.delegate = self;
SongData * data = [demoData objectAtIndex:indexPath.row];
cell.textLabel.text = data.title;
cell.detailTextLabel.text = data.album;
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 50;
}
#pragma mark Swipe Delegate
-(BOOL) swipeTableCell:(MGSwipeTableCell*) cell canSwipe:(MGSwipeDirection) direction;
{
return YES;
}
-(NSArray*) swipeTableCell:(MGSwipeTableCell*) cell swipeButtonsForDirection:(MGSwipeDirection)direction
swipeSettings:(MGSwipeSettings*) swipeSettings expansionSettings:(MGSwipeExpansionSettings*) expansionSettings
{
swipeSettings.transition = MGSwipeTransitionClipCenter;
swipeSettings.keepButtonsSwiped = NO;
expansionSettings.buttonIndex = 0;
expansionSettings.threshold = 1.0;
expansionSettings.expansionLayout = MGSwipeExpansionLayoutCenter;
expansionSettings.expansionColor = [UIColor colorWithRed:33/255.0 green:175/255.0 blue:67/255.0 alpha:1.0];
expansionSettings.triggerAnimation.easingFunction = MGSwipeEasingFunctionCubicOut;
expansionSettings.fillOnTrigger = NO;
__weak SpotifyViewController * me = self;
UIColor * color = [UIColor colorWithRed:47/255.0 green:47/255.0 blue:49/255.0 alpha:1.0];
UIFont * font = [UIFont fontWithName:@"HelveticaNeue-Light" size:14.0f];
if (direction == MGSwipeDirectionLeftToRight) {
MGSwipeButton * queueButton = [MGSwipeButton buttonWithTitle:@"QUEUE" backgroundColor:color padding:15 callback:^BOOL(MGSwipeTableCell *sender) {
SongData * song = [me songForIndexPath:[me.tableView indexPathForCell:sender]];
NSLog(@"Queue song: %@", song.title);
return YES;
}];
queueButton.titleLabel.font = font;
return @[queueButton];
}
else {
MGSwipeButton * saveButton = [MGSwipeButton buttonWithTitle:@"SAVE" backgroundColor:color padding:15 callback:^BOOL(MGSwipeTableCell *sender) {
SongData * song = [me songForIndexPath:[me.tableView indexPathForCell:sender]];
NSLog(@"Save song: %@", song.title);
return YES; //don't autohide to improve delete animation
}];
saveButton.titleLabel.font = font;
return @[saveButton];
}
return nil;
}
-(void) swipeTableCell:(MGSwipeTableCell*) cell didChangeSwipeState:(MGSwipeState)state gestureIsActive:(BOOL)gestureIsActive
{
NSString * str;
switch (state) {
case MGSwipeStateNone: str = @"None"; break;
case MGSwipeStateSwippingLeftToRight: str = @"SwippingLeftToRight"; break;
case MGSwipeStateSwippingRightToLeft: str = @"SwippingRightToLeft"; break;
case MGSwipeStateExpandingLeftToRight: str = @"ExpandingLeftToRight"; break;
case MGSwipeStateExpandingRightToLeft: str = @"ExpandingRightToLeft"; break;
}
NSLog(@"Swipe state: %@ ::: Gesture: %@", str, gestureIsActive ? @"Active" : @"Ended");
}
@end

View file

@ -0,0 +1,16 @@
//
// main.m
// MailAppDemo
//
// Created by Imanol Fernandez Gorostizaga on 26/09/14.
// Copyright (c) 2014 Mortimer. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
int main(int argc, char * argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 400 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 319 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 352 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 365 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 326 KiB