├── Icon.png ├── Icon@2x.png ├── LTBlacklist ├── Default.png ├── Default@2x.png ├── Default-568h@2x.png ├── Images │ ├── BlockIcon@2x.png │ └── UnblockIcon@2x.png ├── Blacklist │ ├── LTPhoneNumber.m │ ├── LTBlacklistViewController.h │ ├── LTPhoneNumber.h │ ├── LTBlacklistTableViewCell.h │ ├── LTBlacklistItem.h │ ├── LTBlacklist.h │ ├── LTBlacklistItem.m │ ├── LTBlacklistTableViewCell.m │ ├── LTBlacklistViewController.m │ └── LTBlacklist.m ├── main.m ├── LTAppDelegate.h ├── LTBlacklist-Prefix.pch ├── LTBlacklist-Info.plist ├── LTAppDelegate.m └── Vendors │ ├── MCSwipeTableViewCell │ ├── MCSwipeTableViewCell.h │ └── MCSwipeTableViewCell.m │ ├── WCAlertView │ ├── WCAlertView.h │ └── WCAlertView.m │ └── ObjectiveCGenerics.h ├── LTBlacklist.xcodeproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── LTBlacklist.xccheckout └── project.pbxproj ├── README.md ├── LICENSE └── .gitignore /Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lexrus/LTBlacklist/HEAD/Icon.png -------------------------------------------------------------------------------- /Icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lexrus/LTBlacklist/HEAD/Icon@2x.png -------------------------------------------------------------------------------- /LTBlacklist/Default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lexrus/LTBlacklist/HEAD/LTBlacklist/Default.png -------------------------------------------------------------------------------- /LTBlacklist/Default@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lexrus/LTBlacklist/HEAD/LTBlacklist/Default@2x.png -------------------------------------------------------------------------------- /LTBlacklist/Default-568h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lexrus/LTBlacklist/HEAD/LTBlacklist/Default-568h@2x.png -------------------------------------------------------------------------------- /LTBlacklist/Images/BlockIcon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lexrus/LTBlacklist/HEAD/LTBlacklist/Images/BlockIcon@2x.png -------------------------------------------------------------------------------- /LTBlacklist/Images/UnblockIcon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lexrus/LTBlacklist/HEAD/LTBlacklist/Images/UnblockIcon@2x.png -------------------------------------------------------------------------------- /LTBlacklist.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /LTBlacklist/Blacklist/LTPhoneNumber.m: -------------------------------------------------------------------------------- 1 | // 2 | // LTPhoneNumber.m 3 | // LTBlacklist 4 | // 5 | // Created by Lex on 7/30/13. 6 | // Copyright (c) 2013 LexTang.com. All rights reserved. 7 | // 8 | 9 | #import "LTPhoneNumber.h" 10 | 11 | @implementation LTPhoneNumber 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /LTBlacklist/Blacklist/LTBlacklistViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // LTBlacklistViewController.h 3 | // LTBlacklist 4 | // 5 | // Created by Lex on 7/12/13. 6 | // Copyright (c) 2013 LexTang.com. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface LTBlacklistViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /LTBlacklist/Blacklist/LTPhoneNumber.h: -------------------------------------------------------------------------------- 1 | // 2 | // LTPhoneNumber.h 3 | // LTBlacklist 4 | // 5 | // Created by Lex on 7/30/13. 6 | // Copyright (c) 2013 LexTang.com. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "ObjectiveCGenerics.h" 11 | 12 | GENERICSABLE(LTPhoneNumber) 13 | 14 | @interface LTPhoneNumber : NSString 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /LTBlacklist/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // LTBlacklist 4 | // 5 | // Created by Lex on 6/26/13. 6 | // Copyright (c) 2013 LexTang.com. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "LTAppDelegate.h" 12 | 13 | int main(int argc, char *argv[]) 14 | { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([LTAppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LTBlacklist 2 | The missing Blacklist app for your iOS 5/6+. No Jailbreak Required! 3 | 4 | ![Hero](https://f.cloud.github.com/assets/219689/1192769/2d2d072e-2467-11e3-89cd-2d257b2255ed.jpg) 5 | 6 | # Credits 7 | LTBlacklist was created by [Lex Tang](http://lextang.com/) 8 | 9 | # License 10 | * This code is distributed under the terms and conditions of the MIT license. 11 | 12 | # Third part code 13 | * [Unplugged](https://github.com/davidkaminsky/Unplugged/) 14 | * [WCAlertView](https://github.com/m1entus/WCAlertView) 15 | * [MCSwipeTableviewCell](https://github.com/alikaragoz/MCSwipeTableViewCell) -------------------------------------------------------------------------------- /LTBlacklist/LTAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // LTAppDelegate.h 3 | // LTBlacklist 4 | // 5 | // Created by Lex on 6/26/13. 6 | // Copyright (c) 2013 LexTang.com. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface LTAppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | @property (assign, nonatomic) UIBackgroundTaskIdentifier bgTask; 16 | @property (assign, nonatomic) BOOL background; 17 | @property (strong, nonatomic) dispatch_block_t expirationHandler; 18 | @property (assign, nonatomic) BOOL jobExpired; 19 | 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /LTBlacklist/Blacklist/LTBlacklistTableViewCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // LTBlacklistTableViewCell.h 3 | // LTBlacklist 4 | // 5 | // Created by Lex on 7/12/13. 6 | // Copyright (c) 2013 LexTang.com. All rights reserved. 7 | // 8 | 9 | #import "MCSwipeTableViewCell.h" 10 | @class LTBlacklistItem; 11 | @class RHPerson; 12 | 13 | FOUNDATION_EXPORT float const kBlacklistCellHeight; 14 | FOUNDATION_EXPORT NSString * const kBlacklistCellIdentifier; 15 | 16 | @interface LTBlacklistTableViewCell : MCSwipeTableViewCell 17 | @property (strong, nonatomic) LTBlacklistItem *item; 18 | @property (assign, nonatomic, getter = isBlocked) BOOL blocked; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /LTBlacklist/LTBlacklist-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'LTBlacklist' target in the 'LTBlacklist' project 3 | // 4 | 5 | #import 6 | 7 | #ifndef __IPHONE_5_0 8 | #warning "This project uses features only available in iOS SDK 5.0 and later." 9 | #endif 10 | 11 | #ifdef __OBJC__ 12 | #import 13 | #import 14 | 15 | #define APP_VERSION [NSString stringWithFormat:@"%@(%@)", \ 16 | [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"], \ 17 | [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"]] 18 | #endif 19 | -------------------------------------------------------------------------------- /LTBlacklist/Blacklist/LTBlacklistItem.h: -------------------------------------------------------------------------------- 1 | // 2 | // LTBlacklistItem.h 3 | // LTBlacklist 4 | // 5 | // Created by Lex on 7/12/13. 6 | // Copyright (c) 2013 LexTang.com. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "ObjectiveCGenerics.h" 11 | #import "LTPhoneNumber.h" 12 | 13 | GENERICSABLE(LTBlacklistItem) 14 | 15 | @interface LTBlacklistItem : NSObject 16 | 17 | @property (strong, nonatomic) NSString *title; 18 | @property (assign, nonatomic) BOOL blocked; 19 | @property (assign, nonatomic) uint blockedCount; 20 | @property (strong, nonatomic) NSString *locationName; 21 | @property (strong, nonatomic) LTPhoneNumber *phoneNumber; 22 | // TODO: Last block date 23 | 24 | + (LTBlacklistItem*)itemWithNumber:(LTPhoneNumber*)number; 25 | + (LTBlacklistItem*)itemWithNumber:(LTPhoneNumber*)number title:(NSString *)title; 26 | - (id)initWithDictionary:(NSDictionary*)dict; 27 | - (NSDictionary *)dictionaryRepresentation; 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2013 LexTang.com 2 | 3 | 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: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | 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. -------------------------------------------------------------------------------- /LTBlacklist/Blacklist/LTBlacklist.h: -------------------------------------------------------------------------------- 1 | // 2 | // LTBlacklist.h 3 | // LTBlacklist 4 | // 5 | // Created by Lex on 7/22/13. 6 | // Copyright (c) 2013 LexTang.com. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "LTPhoneNumber.h" 11 | #import "LTBlacklistItem.h" 12 | 13 | @interface LTBlacklist : NSObject 14 | @property (strong, nonatomic, readonly) NSArray *blockedPhoneNumbers; 15 | @property (strong, nonatomic, readonly) NSArray *blockedItems; 16 | 17 | + (LTBlacklist *)shared; 18 | 19 | #pragma mark - Phone observer control 20 | 21 | - (void)activate; 22 | - (void)deactivate; 23 | 24 | 25 | #pragma mark - Blacklist manager 26 | 27 | - (void)blockPhoneNumber:(LTPhoneNumber*)phoneNumber; 28 | - (LTBlacklistItem*)itemByPhoneNumber:(LTPhoneNumber*)phoneNumber; 29 | - (void)updateBlockedItem:(LTBlacklistItem*)blockedItem; 30 | - (void)unblockPhoneNumber:(LTPhoneNumber*)phoneNumber; 31 | - (void)addItem:(LTPhoneNumber*)phoneNumber; 32 | - (void)removeItem:(LTPhoneNumber*)phoneNumber; 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Node.js modules 2 | node_modules/* 3 | 4 | # Compiled Python files 5 | *.pyc 6 | 7 | # Folder view configuration files 8 | .DS_Store 9 | Desktop.ini 10 | 11 | # Thumbnail cache files 12 | ._* 13 | Thumbs.db 14 | 15 | # Files that might appear on external disks 16 | .Spotlight-V100 17 | .Trashes 18 | 19 | # Exclude the Podspecs 20 | Pods/* 21 | Podfile.lock 22 | 23 | # Exclude any PSD/AI source 24 | #*.psd 25 | #*.ai 26 | 27 | # Exclude generated files 28 | VersionX-revision.h 29 | 30 | # Exclude the build products 31 | build/* 32 | build.output 33 | pkg/* 34 | *.o 35 | 36 | # Exclude temp nibs and swap files 37 | *~.nib 38 | *.swp 39 | *~ 40 | 41 | # Sparkle distribution Private Key (Don't check me in!) 42 | dsa_priv.pem 43 | 44 | # Exclude user-specific XCode 3 and 4 files 45 | *.mode1 46 | *.mode1v3 47 | *.mode2v3 48 | *.perspective 49 | *.perspectivev3 50 | *.pbxuser 51 | *.xcuserdatad 52 | xcuserdata 53 | profile 54 | DerivedData 55 | 56 | # Exclude ReleaseNotes 57 | RELEASENOTES 58 | RELEASENOTES.* 59 | release_notes 60 | release_notes.* 61 | 62 | # Other source repository archive directories (protects when importing) 63 | .hg 64 | .svn 65 | CVS 66 | 67 | # idea project files 68 | .idea 69 | *.hmap 70 | -------------------------------------------------------------------------------- /LTBlacklist.xcodeproj/project.xcworkspace/xcshareddata/LTBlacklist.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | 073ECFB7-0060-4D98-BC9F-417580657358 9 | IDESourceControlProjectName 10 | LTBlacklist 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | D2306B73-B23E-4EA0-B5EF-E7778886BD63 14 | https://github.com/lexrus/LTBlacklist.git 15 | 16 | IDESourceControlProjectPath 17 | LTBlacklist.xcodeproj/project.xcworkspace 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | D2306B73-B23E-4EA0-B5EF-E7778886BD63 21 | ../.. 22 | 23 | IDESourceControlProjectURL 24 | https://github.com/lexrus/LTBlacklist.git 25 | IDESourceControlProjectVersion 26 | 110 27 | IDESourceControlProjectWCCIdentifier 28 | D2306B73-B23E-4EA0-B5EF-E7778886BD63 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | D2306B73-B23E-4EA0-B5EF-E7778886BD63 36 | IDESourceControlWCCName 37 | LTBlacklist 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /LTBlacklist/LTBlacklist-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIcons 12 | 13 | CFBundlePrimaryIcon 14 | 15 | CFBundleIconFiles 16 | 17 | Icon@2x.png 18 | Icon.png 19 | 20 | UIPrerenderedIcon 21 | 22 | 23 | 24 | CFBundleIdentifier 25 | com.LexTang.${PRODUCT_NAME:rfc1034identifier} 26 | CFBundleInfoDictionaryVersion 27 | 6.0 28 | CFBundleName 29 | ${PRODUCT_NAME} 30 | CFBundlePackageType 31 | APPL 32 | CFBundleShortVersionString 33 | 0.1 34 | CFBundleSignature 35 | ???? 36 | CFBundleVersion 37 | 1 38 | LSRequiresIPhoneOS 39 | 40 | UIBackgroundModes 41 | 42 | voip 43 | 44 | UIPrerenderedIcon 45 | 46 | UIRequiredDeviceCapabilities 47 | 48 | armv7 49 | 50 | UIStatusBarStyle 51 | UIStatusBarStyleBlackOpaque 52 | UIStatusBarTintParameters 53 | 54 | UINavigationBar 55 | 56 | Style 57 | UIBarStyleBlack 58 | Translucent 59 | 60 | 61 | 62 | UISupportedInterfaceOrientations 63 | 64 | UIInterfaceOrientationPortrait 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /LTBlacklist/Blacklist/LTBlacklistItem.m: -------------------------------------------------------------------------------- 1 | // 2 | // LTBlacklistItem.m 3 | // LTBlacklist 4 | // 5 | // Created by Lex on 7/12/13. 6 | // Copyright (c) 2013 LexTang.com. All rights reserved. 7 | // 8 | 9 | #import "LTBlacklistItem.h" 10 | 11 | @implementation LTBlacklistItem 12 | 13 | + (LTBlacklistItem*)itemWithNumber:(LTPhoneNumber*)number 14 | { 15 | if (!number) return nil; 16 | return [LTBlacklistItem itemWithNumber:number title:@""]; 17 | } 18 | 19 | + (LTBlacklistItem*)itemWithNumber:(LTPhoneNumber*)number title:(NSString *)title 20 | { 21 | NSDictionary *dict = @{@"phoneNumber": number, 22 | @"title": title, 23 | @"blocked": @(NO), 24 | @"blockedCount": @(0)}; 25 | LTBlacklistItem *instance = [[LTBlacklistItem alloc] initWithDictionary:dict]; 26 | return instance; 27 | } 28 | 29 | - (id)initWithDictionary:(NSDictionary *)dict 30 | { 31 | self = [super init]; 32 | if (self) { 33 | self.phoneNumber = dict[@"phoneNumber"]; 34 | self.title = dict[@"title"]; 35 | self.blocked = [dict[@"blocked"] boolValue]; 36 | self.blockedCount = [dict[@"blockedCount"] unsignedIntValue]; 37 | } 38 | return self; 39 | } 40 | 41 | - (NSDictionary *)dictionaryRepresentation 42 | { 43 | NSDictionary *dict = @{@"title": self.title, 44 | @"phoneNumber": self.phoneNumber, 45 | @"blocked": @(self.blocked), 46 | @"blockedCount": @(self.blockedCount)}; 47 | return dict; 48 | } 49 | 50 | - (NSString *)description 51 | { 52 | return [NSString stringWithFormat:@"%@ %@", self.title, self.phoneNumber]; 53 | } 54 | 55 | #pragma mark - NSCoding methods 56 | 57 | - (id)initWithCoder:(NSCoder *)aDecoder 58 | { 59 | self = [super init]; 60 | self.phoneNumber = [aDecoder decodeObjectForKey:@"phoneNumber"]; 61 | self.title = [aDecoder decodeObjectForKey:@"title"]; 62 | self.blocked = [aDecoder decodeBoolForKey:@"blocked"]; 63 | self.blockedCount = [aDecoder decodeInt64ForKey:@"blockedCount"]; 64 | return self; 65 | } 66 | 67 | - (void)encodeWithCoder:(NSCoder *)aCoder 68 | { 69 | [aCoder encodeObject:self.phoneNumber forKey:@"phoneNumber"]; 70 | [aCoder encodeObject:self.title forKey:@"title"]; 71 | [aCoder encodeBool:self.blocked forKey:@"blocked"]; 72 | [aCoder encodeInt64:self.blockedCount forKey:@"blockedCount"]; 73 | } 74 | 75 | @end 76 | -------------------------------------------------------------------------------- /LTBlacklist/Blacklist/LTBlacklistTableViewCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // LTBlacklistTableViewCell.m 3 | // LTBlacklist 4 | // 5 | // Created by Lex on 7/12/13. 6 | // Copyright (c) 2013 LexTang.com. All rights reserved. 7 | // 8 | 9 | #import "LTBlacklistTableViewCell.h" 10 | #import "LTBlacklist.h" 11 | 12 | float const kBlacklistCellHeight = 44; 13 | NSString * const kBlacklistCellIdentifier = @"kBlacklistCellIdentifier"; 14 | 15 | @implementation LTBlacklistTableViewCell 16 | { 17 | UILabel *_blockedIndicator; 18 | } 19 | 20 | - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier 21 | { 22 | self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; 23 | if (self) { 24 | self.backgroundColor = [UIColor blackColor]; 25 | self.textLabel.textColor = [UIColor whiteColor]; 26 | 27 | [self setFirstStateIconName:@"BlockIcon" 28 | firstColor:[UIColor colorWithWhite:0.2 alpha:1.0f] 29 | secondStateIconName:@"" 30 | secondColor:[UIColor redColor] 31 | thirdIconName:@"UnblockIcon" 32 | thirdColor:[UIColor colorWithWhite:0.2 alpha:1.0f] 33 | fourthIconName:@"" 34 | fourthColor:[UIColor greenColor]]; 35 | [self.contentView setBackgroundColor:[UIColor whiteColor]]; 36 | [self setSelectionStyle:UITableViewCellSelectionStyleNone]; 37 | [self setMode:MCSwipeTableViewCellModeSwitch]; 38 | } 39 | return self; 40 | } 41 | 42 | - (void)willMoveToSuperview:(UIView *)newSuperview 43 | { 44 | if (newSuperview) { 45 | self.contentView.backgroundColor = [UIColor blackColor]; 46 | } 47 | } 48 | 49 | - (void)setItem:(LTBlacklistItem *)item 50 | { 51 | _item = item; 52 | self.textLabel.font = [UIFont systemFontOfSize:16]; 53 | if (_item.blockedCount <= 1) { 54 | self.textLabel.text = _item.phoneNumber; 55 | } else { 56 | self.textLabel.text = [NSString stringWithFormat:@"%@ x %i", _item.phoneNumber, _item.blockedCount]; 57 | } 58 | self.blocked = _item.blocked; 59 | } 60 | 61 | - (void)setBlocked:(BOOL)blocked 62 | { 63 | if (blocked) { 64 | if (!_blockedIndicator) { 65 | _blockedIndicator = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100, kBlacklistCellHeight)]; 66 | _blockedIndicator.backgroundColor = [UIColor clearColor]; 67 | _blockedIndicator.textColor = [UIColor whiteColor]; 68 | _blockedIndicator.font = [UIFont systemFontOfSize:12]; 69 | _blockedIndicator.textAlignment = (UITextAlignment)UITextAlignmentRight; 70 | _blockedIndicator.autoresizingMask = UIViewAutoresizingFlexibleTopMargin|UIViewAutoresizingFlexibleBottomMargin; 71 | _blockedIndicator.frame = CGRectMake(self.bounds.size.width - 100 - 15, 72 | 0, 73 | 100, 74 | kBlacklistCellHeight); 75 | _blockedIndicator.text = NSLocalizedString(@"BLOCKED", nil); 76 | [self.contentView addSubview:_blockedIndicator]; 77 | } 78 | } else if (_blockedIndicator) { 79 | [_blockedIndicator removeFromSuperview]; 80 | _blockedIndicator = nil; 81 | } 82 | } 83 | 84 | @end 85 | -------------------------------------------------------------------------------- /LTBlacklist/LTAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // LTAppDelegate.m 3 | // LTBlacklist 4 | // 5 | // Created by Lex on 6/26/13. 6 | // Copyright (c) 2013 LexTang.com. All rights reserved. 7 | // 8 | 9 | #import "LTAppDelegate.h" 10 | #import "LTBlacklistViewController.h" 11 | #import "LTBlacklist.h" 12 | #import "WCAlertView.h" 13 | 14 | @implementation LTAppDelegate 15 | 16 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 17 | { 18 | 19 | self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 20 | 21 | UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:[[LTBlacklistViewController alloc] init]]; 22 | navigationController.navigationBar.tintColor = [UIColor blackColor]; 23 | 24 | self.window.rootViewController = navigationController; 25 | self.window.backgroundColor = [UIColor whiteColor]; 26 | [self.window makeKeyAndVisible]; 27 | 28 | [[LTBlacklist shared] activate]; 29 | 30 | [WCAlertView setDefaultStyle:WCAlertViewStyleBlack]; 31 | [WCAlertView setDefaultCustomiaztonBlock:^(WCAlertView *alertView) { 32 | alertView.labelTextColor = [UIColor whiteColor]; 33 | alertView.labelShadowColor = [UIColor blackColor]; 34 | alertView.outerFrameColor = [UIColor blackColor]; 35 | alertView.buttonTextColor = [UIColor whiteColor]; 36 | alertView.buttonShadowColor = [UIColor blackColor]; 37 | }]; 38 | 39 | [self keepAlive]; 40 | 41 | return YES; 42 | } 43 | 44 | // https://github.com/davidkaminsky/Unplugged/ 45 | - (void)keepAlive 46 | { 47 | UIApplication* app = [UIApplication sharedApplication]; 48 | 49 | __weak __typeof(&*self)weakSelf = self; 50 | self.expirationHandler = ^{ 51 | __strong __typeof(&*weakSelf)strongSelf = weakSelf; 52 | [app endBackgroundTask:strongSelf.bgTask]; 53 | strongSelf.bgTask = UIBackgroundTaskInvalid; 54 | strongSelf.bgTask = [app beginBackgroundTaskWithExpirationHandler:strongSelf.expirationHandler]; 55 | NSLog(@"Expired"); 56 | strongSelf.jobExpired = YES; 57 | while(strongSelf.jobExpired) { 58 | // spin while we wait for the task to actually end. 59 | [NSThread sleepForTimeInterval:1]; 60 | } 61 | // Restart the background task so we can run forever. 62 | [strongSelf startBackgroundTask]; 63 | }; 64 | self.bgTask = [app beginBackgroundTaskWithExpirationHandler:_expirationHandler]; 65 | } 66 | 67 | - (void)startBackgroundTask 68 | { 69 | NSLog(@"Restarting task"); 70 | // Start the long-running task. 71 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 72 | // When the job expires it still keeps running since we never exited it. Thus have the expiration handler 73 | // set a flag that the job expired and use that to exit the while loop and end the task. 74 | while(self.background && !self.jobExpired) 75 | { 76 | [NSThread sleepForTimeInterval:1]; 77 | } 78 | 79 | self.jobExpired = NO; 80 | }); 81 | } 82 | 83 | - (void)applicationDidBecomeActive:(UIApplication *)application 84 | { 85 | [[UIApplication sharedApplication] setApplicationIconBadgeNumber:0]; 86 | } 87 | 88 | - (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification 89 | { 90 | [[UIApplication sharedApplication] cancelLocalNotification:notification]; 91 | } 92 | 93 | - (void)applicationWillTerminate:(UIApplication *)application 94 | { 95 | [[LTBlacklist shared] deactivate]; 96 | } 97 | 98 | @end 99 | -------------------------------------------------------------------------------- /LTBlacklist/Vendors/MCSwipeTableViewCell/MCSwipeTableViewCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // MCSwipeTableViewCell.h 3 | // MCSwipeTableViewCell 4 | // 5 | // Created by Ali Karagoz on 24/02/13. 6 | // Copyright (c) 2013 Mad Castle. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class MCSwipeTableViewCell; 12 | 13 | typedef NS_ENUM(NSUInteger, MCSwipeTableViewCellState){ 14 | MCSwipeTableViewCellStateNone = 0, 15 | MCSwipeTableViewCellState1, 16 | MCSwipeTableViewCellState2, 17 | MCSwipeTableViewCellState3, 18 | MCSwipeTableViewCellState4 19 | }; 20 | 21 | typedef NS_ENUM(NSUInteger, MCSwipeTableViewCellDirection){ 22 | MCSwipeTableViewCellDirectionLeft = 0, 23 | MCSwipeTableViewCellDirectionCenter, 24 | MCSwipeTableViewCellDirectionRight 25 | }; 26 | 27 | typedef NS_ENUM(NSUInteger, MCSwipeTableViewCellMode){ 28 | MCSwipeTableViewCellModeNone = 0, 29 | MCSwipeTableViewCellModeExit, 30 | MCSwipeTableViewCellModeSwitch 31 | }; 32 | 33 | @protocol MCSwipeTableViewCellDelegate 34 | 35 | @optional 36 | 37 | // When the user starts swiping the cell this method is called 38 | - (void)swipeTableViewCellDidStartSwiping:(MCSwipeTableViewCell *)cell; 39 | 40 | // When the user is dragging, this method is called and return the dragged percentage from the border 41 | - (void)swipeTableViewCell:(MCSwipeTableViewCell *)cell didSwipWithPercentage:(CGFloat)percentage; 42 | 43 | // When the user releases the cell, after swiping it, this method is called 44 | - (void)swipeTableViewCell:(MCSwipeTableViewCell *)cell didEndSwipingSwipingWithState:(MCSwipeTableViewCellState)state mode:(MCSwipeTableViewCellMode)mode; 45 | 46 | @end 47 | 48 | @interface MCSwipeTableViewCell : UITableViewCell 49 | 50 | @property (nonatomic, assign) id delegate; 51 | 52 | @property (nonatomic, copy) NSString *firstIconName; 53 | @property (nonatomic, copy) NSString *secondIconName; 54 | @property (nonatomic, copy) NSString *thirdIconName; 55 | @property (nonatomic, copy) NSString *fourthIconName; 56 | 57 | @property (nonatomic, strong) UIColor *firstColor; 58 | @property (nonatomic, strong) UIColor *secondColor; 59 | @property (nonatomic, strong) UIColor *thirdColor; 60 | @property (nonatomic, strong) UIColor *fourthColor; 61 | 62 | // Color for background, when any state hasn't triggered yet 63 | @property (nonatomic, strong) UIColor *defaultColor; 64 | 65 | // This is the general mode for all states 66 | // If a specific mode for a state isn't defined, this mode will be taken in action 67 | @property (nonatomic, assign) MCSwipeTableViewCellMode mode; 68 | 69 | // Individual mode for states 70 | @property (nonatomic, assign) MCSwipeTableViewCellMode modeForState1; 71 | @property (nonatomic, assign) MCSwipeTableViewCellMode modeForState2; 72 | @property (nonatomic, assign) MCSwipeTableViewCellMode modeForState3; 73 | @property (nonatomic, assign) MCSwipeTableViewCellMode modeForState4; 74 | 75 | @property (nonatomic, assign) BOOL isDragging; 76 | @property (nonatomic, assign) BOOL shouldDrag; 77 | @property (nonatomic, assign) BOOL shouldAnimatesIcons; 78 | 79 | - (id)initWithStyle:(UITableViewCellStyle)style 80 | reuseIdentifier:(NSString *)reuseIdentifier 81 | firstStateIconName:(NSString *)firstIconName 82 | firstColor:(UIColor *)firstColor 83 | secondStateIconName:(NSString *)secondIconName 84 | secondColor:(UIColor *)secondColor 85 | thirdIconName:(NSString *)thirdIconName 86 | thirdColor:(UIColor *)thirdColor 87 | fourthIconName:(NSString *)fourthIconName 88 | fourthColor:(UIColor *)fourthColor; 89 | 90 | - (void)setFirstStateIconName:(NSString *)firstIconName 91 | firstColor:(UIColor *)firstColor 92 | secondStateIconName:(NSString *)secondIconName 93 | secondColor:(UIColor *)secondColor 94 | thirdIconName:(NSString *)thirdIconName 95 | thirdColor:(UIColor *)thirdColor 96 | fourthIconName:(NSString *)fourthIconName 97 | fourthColor:(UIColor *)fourthColor; 98 | 99 | @end 100 | -------------------------------------------------------------------------------- /LTBlacklist/Vendors/WCAlertView/WCAlertView.h: -------------------------------------------------------------------------------- 1 | // 2 | // WCAlertView.h 3 | // WCAlertView 4 | // 5 | // Created by Michał Zaborowski on 18/07/12. 6 | // Copyright (c) 2012 Michał Zaborowski. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | #import 27 | 28 | @class WCAlertView; 29 | 30 | typedef NS_ENUM(NSInteger, WCAlertViewStyle) 31 | { 32 | WCAlertViewStyleDefault = 0, 33 | 34 | WCAlertViewStyleWhite, 35 | WCAlertViewStyleWhiteHatched, 36 | WCAlertViewStyleBlack, 37 | WCAlertViewStyleBlackHatched, 38 | WCAlertViewStyleViolet, 39 | WCAlertViewStyleVioletHatched, 40 | 41 | WCAlertViewStyleCustomizationBlock, 42 | }; 43 | 44 | typedef void(^CustomizationBlock)(WCAlertView *alertView); 45 | 46 | @interface WCAlertView : UIAlertView 47 | 48 | /* 49 | * Predefined alert styles 50 | */ 51 | @property (nonatomic,assign) WCAlertViewStyle style; 52 | 53 | /* 54 | * Title and message label styles 55 | */ 56 | @property (nonatomic,strong) UIColor *labelTextColor; 57 | @property (nonatomic,strong) UIColor *labelShadowColor; 58 | @property (nonatomic,assign) CGSize labelShadowOffset; 59 | @property (nonatomic,strong) UIFont *titleFont; 60 | @property (nonatomic,strong) UIFont *messageFont; 61 | 62 | /* 63 | * Button styles 64 | */ 65 | @property (nonatomic,strong) UIColor *buttonTextColor; 66 | @property (nonatomic,strong) UIFont *buttonFont; 67 | @property (nonatomic,strong) UIColor *buttonShadowColor; 68 | @property (nonatomic,assign) CGSize buttonShadowOffset; 69 | @property (nonatomic,assign) CGFloat buttonShadowBlur; 70 | 71 | /* 72 | * Background gradient colors and locations 73 | */ 74 | @property (nonatomic,strong) NSArray *gradientLocations; 75 | @property (nonatomic,strong) NSArray *gradientColors; 76 | 77 | @property (nonatomic,assign) CGFloat cornerRadius; 78 | /* 79 | * Inner frame shadow (optional) 80 | * Stroke path to cover up pixialation on corners from clipping! 81 | */ 82 | @property (nonatomic,strong) UIColor *innerFrameShadowColor; 83 | @property (nonatomic,strong) UIColor *innerFrameStrokeColor; 84 | 85 | /* 86 | * Hatched lines 87 | */ 88 | @property (nonatomic,strong) UIColor *verticalLineColor; 89 | 90 | @property (nonatomic,strong) UIColor *hatchedLinesColor; 91 | @property (nonatomic,strong) UIColor *hatchedBackgroundColor; 92 | 93 | /* 94 | * Outer frame color 95 | */ 96 | @property (nonatomic,strong) UIColor *outerFrameColor; 97 | @property (nonatomic,assign) CGFloat outerFrameLineWidth; 98 | @property (nonatomic,strong) UIColor *outerFrameShadowColor; 99 | @property (nonatomic,assign) CGSize outerFrameShadowOffset; 100 | @property (nonatomic,assign) CGFloat outerFrameShadowBlur; 101 | 102 | /* 103 | * Setting default appearance for all WCAlertView's 104 | */ 105 | + (void)setDefaultStyle:(WCAlertViewStyle)style; 106 | + (void)setDefaultCustomiaztonBlock:(CustomizationBlock)block; 107 | 108 | 109 | + (id)showAlertWithTitle:(NSString *)title message:(NSString *)message customizationBlock:(void (^)(WCAlertView *alertView))customization 110 | completionBlock:(void (^)(NSUInteger buttonIndex, WCAlertView *alertView))block 111 | cancelButtonTitle:(NSString *)cancelButtonTitle otherButtonTitles:(NSString *)otherButtonTitles, ... NS_REQUIRES_NIL_TERMINATION; 112 | 113 | 114 | @end 115 | -------------------------------------------------------------------------------- /LTBlacklist/Blacklist/LTBlacklistViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // LTBlacklistViewController.m 3 | // LTBlacklist 4 | // 5 | // Created by Lex on 7/12/13. 6 | // Copyright (c) 2013 LexTang.com. All rights reserved. 7 | // 8 | 9 | #import "LTBlacklistViewController.h" 10 | #import "LTBlacklistTableViewCell.h" 11 | #import "LTBlacklist.h" 12 | #import "WCAlertView.h" 13 | 14 | static const float kSegmentedControlMargin = 10.0f; 15 | 16 | @interface LTBlacklistViewController () 17 | @property (strong, nonatomic) UITableView *tableView; 18 | 19 | @end 20 | 21 | @implementation LTBlacklistViewController 22 | 23 | - (id)init 24 | { 25 | self = [super init]; 26 | if (self) { 27 | self.title = NSLocalizedString(@"Blacklist", nil); 28 | self.view.backgroundColor = [UIColor blackColor]; 29 | } 30 | return self; 31 | } 32 | 33 | - (void)viewDidLoad 34 | { 35 | [super viewDidLoad]; 36 | 37 | UIBarButtonItem *addButton = [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"Add", nil) 38 | style:UIBarButtonItemStylePlain 39 | target:self 40 | action:@selector(showAddForm)]; 41 | self.navigationItem.rightBarButtonItem = addButton; 42 | 43 | UIBarButtonItem *aboutButton = [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"About", nil) 44 | style:UIBarButtonItemStylePlain 45 | target:self 46 | action:@selector(showAboutView)]; 47 | self.navigationItem.leftBarButtonItem = aboutButton; 48 | 49 | _tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain]; 50 | _tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight; 51 | _tableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine; 52 | _tableView.backgroundColor = [UIColor blackColor]; 53 | _tableView.rowHeight = kBlacklistCellHeight; 54 | _tableView.separatorColor = [UIColor colorWithWhite:0.15f alpha:1.0f]; 55 | [self.view addSubview:_tableView]; 56 | } 57 | 58 | - (void)viewDidAppear:(BOOL)animated 59 | { 60 | [super viewDidAppear:animated]; 61 | _tableView.delegate = self; 62 | _tableView.dataSource = self; 63 | [_tableView reloadData]; 64 | } 65 | 66 | - (void)viewWillDisappear:(BOOL)animated 67 | { 68 | [super viewWillDisappear:animated]; 69 | _tableView.delegate = nil; 70 | _tableView.dataSource = nil; 71 | } 72 | 73 | - (void)didReceiveMemoryWarning 74 | { 75 | [super didReceiveMemoryWarning]; 76 | } 77 | 78 | #pragma mark - TableView datasource 79 | 80 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 81 | { 82 | return [LTBlacklist shared].blockedItems.count; 83 | } 84 | 85 | - (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 86 | { 87 | LTBlacklistTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kBlacklistCellIdentifier]; 88 | if (!cell) { 89 | cell = [[LTBlacklistTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kBlacklistCellIdentifier]; 90 | } 91 | cell.item = [LTBlacklist shared].blockedItems[indexPath.row]; 92 | cell.delegate = self; 93 | return cell; 94 | } 95 | 96 | #pragma mark - TableView delegate 97 | 98 | - (void)swipeTableViewCell:(LTBlacklistTableViewCell *)cell didEndSwipingSwipingWithState:(MCSwipeTableViewCellState)state mode:(MCSwipeTableViewCellMode)mode 99 | { 100 | if (state == MCSwipeTableViewCellState1) { 101 | [[LTBlacklist shared] blockPhoneNumber:cell.item.phoneNumber]; 102 | } else if (state == MCSwipeTableViewCellState3) { 103 | [[LTBlacklist shared] unblockPhoneNumber:cell.item.phoneNumber]; 104 | } else if (state == MCSwipeTableViewCellState2) { 105 | [[LTBlacklist shared] removeItem:cell.item.phoneNumber]; 106 | } else if (state == MCSwipeTableViewCellState4) { 107 | 108 | } 109 | [self.tableView reloadData]; 110 | } 111 | 112 | #pragma mark - Actions 113 | 114 | - (void)showAddForm 115 | { 116 | __weak __typeof(&*self)weakSelf = self; 117 | [WCAlertView showAlertWithTitle:NSLocalizedString(@"Block phone number", nil) 118 | message:nil 119 | customizationBlock:^(WCAlertView *alertView) { 120 | alertView.alertViewStyle = UIAlertViewStylePlainTextInput; 121 | UITextField *textField = [alertView textFieldAtIndex:0]; 122 | textField.keyboardType = UIKeyboardTypePhonePad; 123 | textField.textAlignment = UITextAlignmentCenter; 124 | textField.font = [UIFont boldSystemFontOfSize:18]; 125 | } completionBlock:^(NSUInteger buttonIndex, WCAlertView *alertView) { 126 | if (buttonIndex != alertView.cancelButtonIndex) { 127 | UITextField *textField = [alertView textFieldAtIndex:0]; 128 | NSString *phoneNumber = textField.text; 129 | if (phoneNumber && phoneNumber.length > 0) { 130 | [[LTBlacklist shared] blockPhoneNumber:(LTPhoneNumber*)phoneNumber]; 131 | } 132 | __strong __typeof(&*weakSelf)strongSelf = weakSelf; 133 | [strongSelf.tableView reloadData]; 134 | } 135 | } cancelButtonTitle:NSLocalizedString(@"Cancel", nil) 136 | otherButtonTitles:NSLocalizedString(@"Okay", nil), nil]; 137 | } 138 | 139 | - (void)showAboutView 140 | { 141 | [WCAlertView showAlertWithTitle:[NSString stringWithFormat:@"LTBlacklist %@", APP_VERSION] 142 | message:@"By Lex Tang (http://LexTang.com)\nhttps://github.com/lexrus/LTBlacklist" 143 | customizationBlock:^(WCAlertView *alertView) { 144 | alertView.messageFont = [UIFont systemFontOfSize:14]; 145 | } completionBlock:^(NSUInteger buttonIndex, WCAlertView *alertView) { 146 | 147 | } cancelButtonTitle:NSLocalizedString(@"Okay", nil) 148 | otherButtonTitles:nil]; 149 | } 150 | 151 | @end 152 | -------------------------------------------------------------------------------- /LTBlacklist/Vendors/ObjectiveCGenerics.h: -------------------------------------------------------------------------------- 1 | //Copyright 2013 Tomer Shiri generics@shiri.info 2 | // 3 | //Licensed under the Apache License, Version 2.0 (the "License"); 4 | //you may not use this file except in compliance with the License. 5 | //You may obtain a copy of the License at 6 | // 7 | //http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | //Unless required by applicable law or agreed to in writing, software 10 | //distributed under the License is distributed on an "AS IS" BASIS, 11 | //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | //See the License for the specific language governing permissions and 13 | //limitations under the License. 14 | 15 | #if NS_BLOCKS_AVAILABLE 16 | #define GENERICSABLE(__className) \ 17 | GENERICSABLEWITHOUTBLOCKS(__className) \ 18 | GENERICSABLEWITHBLOCKS(__className) 19 | #else 20 | #define GENERICSABLE(__className) GENERICSABLEWITHOUTBLOCKS(__className) 21 | #endif 22 | 23 | #define GENERICSABLEWITHOUTBLOCKS(__className)\ 24 | @protocol __className \ 25 | @end \ 26 | @class __className; \ 27 | typedef NSComparisonResult (^__className##Comparator)(__className* obj1, __className* obj2); \ 28 | \ 29 | @interface NSEnumerator (__className##_NSEnumerator_Generics) <__className> \ 30 | - (__className*)nextObject; \ 31 | - (NSArray<__className>*)allObjects; \ 32 | @end \ 33 | \ 34 | @interface NSArray (__className##_NSArray_Generics) <__className> \ 35 | \ 36 | - (__className*)objectAtIndex:(NSUInteger)index; \ 37 | - (NSArray<__className>*)arrayByAddingObject:(__className*)anObject; \ 38 | - (NSArray*)arrayByAddingObjectsFromArray:(NSArray<__className>*)otherArray; \ 39 | - (BOOL)containsObject:(__className*)anObject; \ 40 | - (__className*)firstObjectCommonWithArray:(NSArray<__className>*)otherArray; \ 41 | - (NSUInteger)indexOfObject:(__className*)anObject; \ 42 | - (NSUInteger)indexOfObject:(__className*)anObject inRange:(NSRange)range; \ 43 | - (NSUInteger)indexOfObjectIdenticalTo:(__className*)anObject; \ 44 | - (NSUInteger)indexOfObjectIdenticalTo:(__className*)anObject inRange:(NSRange)range; \ 45 | - (BOOL)isEqualToArray:(NSArray<__className>*)otherArray; \ 46 | - (__className*)lastObject; \ 47 | - (NSEnumerator<__className>*)objectEnumerator; \ 48 | - (NSEnumerator<__className>*)reverseObjectEnumerator; \ 49 | - (NSArray<__className>*)sortedArrayUsingFunction:(NSInteger (*)(__className*, __className*, void *))comparator context:(void *)context; \ 50 | - (NSArray<__className>*)sortedArrayUsingFunction:(NSInteger (*)(__className*, __className*, void *))comparator context:(void *)context hint:(NSData *)hint; \ 51 | - (NSArray<__className>*)sortedArrayUsingSelector:(SEL)comparator; \ 52 | - (NSArray<__className>*)subarrayWithRange:(NSRange)range; \ 53 | - (NSArray<__className>*)objectsAtIndexes:(NSIndexSet *)indexes; \ 54 | - (__className*)objectAtIndexedSubscript:(NSUInteger)idx NS_AVAILABLE(10_8, 6_0); \ 55 | \ 56 | + (NSArray<__className>*)array; \ 57 | + (NSArray<__className>*)arrayWithObject:(__className*)anObject; \ 58 | + (NSArray<__className>*)arrayWithObjects:(const id [])objects count:(NSUInteger)cnt; \ 59 | + (NSArray<__className>*)arrayWithObjects:(__className*)firstObj, ... NS_REQUIRES_NIL_TERMINATION; \ 60 | + (NSArray<__className>*)arrayWithArray:(NSArray<__className>*)array; \ 61 | \ 62 | - (NSArray<__className>*)initWithObjects:(const id [])objects count:(NSUInteger)cnt; \ 63 | - (NSArray<__className>*)initWithObjects:(id)firstObj, ... NS_REQUIRES_NIL_TERMINATION; \ 64 | - (NSArray<__className>*)initWithArray:(NSArray *)array; \ 65 | - (NSArray<__className>*)initWithArray:(NSArray *)array copyItems:(BOOL)flag; \ 66 | \ 67 | + (NSArray<__className>*)arrayWithContentsOfFile:(NSString *)path; \ 68 | + (NSArray<__className>*)arrayWithContentsOfURL:(NSURL *)url; \ 69 | - (NSArray<__className>*)initWithContentsOfFile:(NSString *)path; \ 70 | - (NSArray<__className>*)initWithContentsOfURL:(NSURL *)url; \ 71 | \ 72 | @end \ 73 | \ 74 | @interface NSMutableArray (__className##_NSMutableArray_Generics) <__className> \ 75 | \ 76 | - (void)addObjectsFromArray:(NSArray<__className>*)otherArray; \ 77 | - (void)removeObject:(__className*)anObject inRange:(NSRange)range; \ 78 | - (void)removeObject:(__className*)anObject; \ 79 | - (void)removeObjectIdenticalTo:(__className*)anObject inRange:(NSRange)range; \ 80 | - (void)removeObjectIdenticalTo:(__className*)anObject; \ 81 | - (void)removeObjectsInArray:(NSArray<__className>*)otherArray; \ 82 | \ 83 | - (void)replaceObjectsInRange:(NSRange)range withObjectsFromArray:(NSArray<__className>*)otherArray range:(NSRange)otherRange; \ 84 | - (void)replaceObjectsInRange:(NSRange)range withObjectsFromArray:(NSArray<__className>*)otherArray; \ 85 | - (void)setArray:(NSArray<__className>*)otherArray; \ 86 | - (void)sortUsingFunction:(NSInteger (*)(__className*, __className*, void *))compare context:(void *)context; \ 87 | \ 88 | - (void)insertObjects:(NSArray<__className>*)objects atIndexes:(NSIndexSet *)indexes; \ 89 | - (void)removeObjectsAtIndexes:(NSIndexSet *)indexes; \ 90 | - (void)replaceObjectsAtIndexes:(NSIndexSet *)indexes withObjects:(NSArray<__className>*)objects; \ 91 | \ 92 | - (void)setObject:(__className*)obj atIndexedSubscript:(NSUInteger)idx NS_AVAILABLE(10_8, 6_0); \ 93 | \ 94 | + (NSMutableArray<__className>*)array; \ 95 | + (NSMutableArray<__className>*)arrayWithObject:(__className*)anObject; \ 96 | + (NSMutableArray<__className>*)arrayWithObjects:(const id [])objects count:(NSUInteger)cnt; \ 97 | + (NSMutableArray<__className>*)arrayWithObjects:(__className*)firstObj, ... NS_REQUIRES_NIL_TERMINATION; \ 98 | + (NSMutableArray<__className>*)arrayWithArray:(NSArray<__className>*)array; \ 99 | \ 100 | - (NSMutableArray<__className>*)initWithObjects:(const id [])objects count:(NSUInteger)cnt; \ 101 | - (NSMutableArray<__className>*)initWithObjects:(id)firstObj, ... NS_REQUIRES_NIL_TERMINATION; \ 102 | - (NSMutableArray<__className>*)initWithArray:(NSArray *)array; \ 103 | - (NSMutableArray<__className>*)initWithArray:(NSArray *)array copyItems:(BOOL)flag; \ 104 | \ 105 | + (NSMutableArray<__className>*)arrayWithContentsOfFile:(NSString *)path; \ 106 | + (NSMutableArray<__className>*)arrayWithContentsOfURL:(NSURL *)url; \ 107 | - (NSMutableArray<__className>*)initWithContentsOfFile:(NSString *)path; \ 108 | - (NSMutableArray<__className>*)initWithContentsOfURL:(NSURL *)url; \ 109 | \ 110 | @end \ 111 | \ 112 | @interface NSSet (__className##_NSSet_Generics) <__className> \ 113 | \ 114 | - (__className*)member:(__className*)object; \ 115 | - (NSEnumerator<__className>*)objectEnumerator; \ 116 | \ 117 | - (NSArray<__className>*)allObjects; \ 118 | - (__className*)anyObject; \ 119 | - (BOOL)containsObject:(__className*)anObject; \ 120 | - (BOOL)intersectsSet:(NSSet<__className>*)otherSet; \ 121 | - (BOOL)isEqualToSet:(NSSet<__className>*)otherSet; \ 122 | - (BOOL)isSubsetOfSet:(NSSet<__className>*)otherSet; \ 123 | \ 124 | - (NSSet<__className>*)setByAddingObject:(__className*)anObject NS_AVAILABLE(10_5, 2_0); \ 125 | - (NSSet<__className>*)setByAddingObjectsFromSet:(NSSet<__className>*)other NS_AVAILABLE(10_5, 2_0); \ 126 | - (NSSet<__className>*)setByAddingObjectsFromArray:(NSArray *)other NS_AVAILABLE(10_5, 2_0); \ 127 | \ 128 | + (NSSet<__className>*)set; \ 129 | + (NSSet<__className>*)setWithObject:(__className*)object; \ 130 | + (NSSet<__className>*)setWithObjects:(const id [])objects count:(NSUInteger)cnt; \ 131 | + (NSSet<__className>*)setWithObjects:(__className*)firstObj, ... NS_REQUIRES_NIL_TERMINATION; \ 132 | + (NSSet<__className>*)setWithSet:(NSSet<__className>*)set; \ 133 | + (NSSet<__className>*)setWithArray:(NSArray<__className>*)array; \ 134 | \ 135 | - (NSSet<__className>*)initWithObjects:(const id [])objects count:(NSUInteger)cnt; \ 136 | - (NSSet<__className>*)initWithObjects:(__className*)firstObj, ... NS_REQUIRES_NIL_TERMINATION; \ 137 | - (NSSet<__className>*)initWithSet:(NSSet<__className>*)set; \ 138 | - (NSSet<__className>*)initWithSet:(NSSet<__className>*)set copyItems:(BOOL)flag; \ 139 | - (NSSet<__className>*)initWithArray:(NSArray<__className>*)array; \ 140 | \ 141 | @end \ 142 | \ 143 | @interface NSMutableSet (__className##_NSMutableSet_Generics) <__className> \ 144 | \ 145 | - (void)addObject:(__className*)object; \ 146 | - (void)removeObject:(__className*)object; \ 147 | - (void)addObjectsFromArray:(NSArray<__className>*)array; \ 148 | - (void)intersectSet:(NSSet<__className>*)otherSet; \ 149 | - (void)minusSet:(NSSet<__className>*)otherSet; \ 150 | - (void)unionSet:(NSSet<__className>*)otherSet; \ 151 | \ 152 | - (void)setSet:(NSSet<__className>*)otherSet; \ 153 | + (NSSet<__className>*)setWithCapacity:(NSUInteger)numItems; \ 154 | - (NSSet<__className>*)initWithCapacity:(NSUInteger)numItems; \ 155 | \ 156 | @end \ 157 | \ 158 | @interface NSCountedSet (__className##_NSCountedSet_Generics) <__className> \ 159 | \ 160 | - (NSSet<__className>*)initWithCapacity:(NSUInteger)numItems; \ 161 | - (NSSet<__className>*)initWithArray:(NSArray<__className>*)array; \ 162 | - (NSSet<__className>*)initWithSet:(NSSet<__className>*)set; \ 163 | - (NSUInteger)countForObject:(__className*)object; \ 164 | - (NSEnumerator<__className>*)objectEnumerator; \ 165 | - (void)addObject:(__className*)object; \ 166 | - (void)removeObject:(__className*)object; \ 167 | \ 168 | @end \ 169 | 170 | #if NS_BLOCKS_AVAILABLE 171 | 172 | #define GENERICSABLEWITHBLOCKS(__className) \ 173 | \ 174 | @interface NSMutableArray (__className##_NSMutableArray_BLOCKS_Generics) <__className> \ 175 | - (void)sortUsingComparator:(__className##Comparator)cmptr NS_AVAILABLE(10_6, 4_0); \ 176 | - (void)sortWithOptions:(NSSortOptions)opts usingComparator:(__className##Comparator)cmptr NS_AVAILABLE(10_6, 4_0); \ 177 | @end \ 178 | @interface NSSet (__className##_NSSet_BLOCKS_Generics) <__className> \ 179 | - (void)enumerateObjectsUsingBlock:(void (^)(__className* obj, BOOL *stop))block NS_AVAILABLE(10_6, 4_0); \ 180 | - (void)enumerateObjectsWithOptions:(NSEnumerationOptions)opts usingBlock:(void (^)(__className* obj, BOOL *stop))block NS_AVAILABLE(10_6, 4_0); \ 181 | - (NSSet<__className>*)objectsPassingTest:(BOOL (^)(__className* obj, BOOL *stop))predicate NS_AVAILABLE(10_6, 4_0); \ 182 | - (NSSet<__className>*)objectsWithOptions:(NSEnumerationOptions)opts passingTest:(BOOL (^)(__className* obj, BOOL *stop))predicate NS_AVAILABLE(10_6, 4_0); \ 183 | @end \ 184 | 185 | #endif 186 | -------------------------------------------------------------------------------- /LTBlacklist/Blacklist/LTBlacklist.m: -------------------------------------------------------------------------------- 1 | // 2 | // LTBlacklist.m 3 | // LTBlacklist 4 | // 5 | // Created by Lex on 7/22/13. 6 | // Copyright (c) 2013 LexTang.com. All rights reserved. 7 | // 8 | 9 | #import "LTBlacklist.h" 10 | #import 11 | 12 | #define kBlockedPhoneNumbersCacheKey @"blockedPhoneNumbers" 13 | 14 | typedef NS_ENUM(short, CTCallStatus) { 15 | kCTCallStatusCallIn = 4, 16 | kCTCallStatusHungUp = 5 17 | }; 18 | 19 | static const CFStringRef kCTCallStatusChangeNotification = CFSTR("kCTCallStatusChangeNotification"); 20 | extern NSString *CTCallCopyAddress(void*, CTCall *); 21 | extern void CTCallDisconnect(CTCall*); 22 | extern CFNotificationCenterRef CTTelephonyCenterGetDefault(); 23 | extern void CTTelephonyCenterAddObserver(CFNotificationCenterRef center, 24 | const void *observer, 25 | CFNotificationCallback callBack, 26 | CFStringRef name, 27 | const void *object, 28 | CFNotificationSuspensionBehavior suspensionBehavior); 29 | extern void CTTelephonyCenterRemoveObserver(CFNotificationCenterRef center, 30 | const void *observer, 31 | CFStringRef name, 32 | const void *object); 33 | 34 | @interface LTBlacklist () 35 | 36 | @property (strong, nonatomic) NSCache *cache; 37 | @property (copy, nonatomic, readonly) NSString *path; 38 | 39 | @end 40 | 41 | @implementation LTBlacklist 42 | 43 | + (instancetype)shared 44 | { 45 | static dispatch_once_t onceToken; 46 | static LTBlacklist *__instance; 47 | dispatch_once(&onceToken, ^{ 48 | __instance = [[super alloc] init]; 49 | __instance.cache = [[NSCache alloc] init]; 50 | }); 51 | return __instance; 52 | } 53 | 54 | 55 | #pragma mark - Private 56 | 57 | - (NSString *)path 58 | { 59 | static dispatch_once_t pathToken; 60 | static NSString *__path; 61 | dispatch_once(&pathToken, ^{ 62 | __path = (NSString*)NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, 63 | NSUserDomainMask, 64 | YES)[0]; 65 | }); 66 | return __path; 67 | } 68 | 69 | - (NSString *)blacklistPath 70 | { 71 | return [self.path stringByAppendingPathComponent:@"LTBlacklist.json"]; 72 | } 73 | 74 | #pragma mark - Phone observer control 75 | 76 | static void callHandler(CFNotificationCenterRef center, void *observer, 77 | CFStringRef name, const void *object, CFDictionaryRef userInfo) { 78 | NSDictionary *info = (__bridge NSDictionary *)(userInfo); 79 | CTCall *call = (CTCall *)info[@"kCTCall"]; 80 | CTCallStatus status = (CTCallStatus)[info[@"kCTCallStatus"] shortValue]; 81 | 82 | if (status == kCTCallStatusCallIn) { 83 | LTPhoneNumber *phoneNumber = (LTPhoneNumber *)CTCallCopyAddress(NULL, call); 84 | 85 | NSLog(@"Call in: %@", phoneNumber); 86 | 87 | LTBlacklistItem *item = [[LTBlacklist shared] itemByPhoneNumber:phoneNumber]; 88 | if (item) { 89 | if (item.blocked) { 90 | item.blockedCount++; 91 | CTCallDisconnect(call); 92 | } 93 | 94 | [[LTBlacklist shared] updateBlockedItem:item]; 95 | [[LTBlacklist shared] notify:phoneNumber]; 96 | } else { 97 | [[LTBlacklist shared] addItem:phoneNumber]; 98 | } 99 | } 100 | } 101 | 102 | - (void)notify:(LTPhoneNumber*)phoneNumber 103 | { 104 | UILocalNotification *notification = [[UILocalNotification alloc] init]; 105 | notification.timeZone = [NSTimeZone defaultTimeZone]; 106 | notification.fireDate = [[NSDate date] dateByAddingTimeInterval:1.5f]; 107 | notification.alertBody = [NSString stringWithFormat:@"Blocked %@", phoneNumber]; 108 | notification.alertAction = NSLocalizedString(@"Show LTBlacklist", nil); 109 | [[UIApplication sharedApplication] scheduleLocalNotification:notification]; 110 | } 111 | 112 | - (void)activate { 113 | CTTelephonyCenterAddObserver(CTTelephonyCenterGetDefault(), 114 | NULL, 115 | &callHandler, 116 | kCTCallStatusChangeNotification, 117 | NULL, 118 | CFNotificationSuspensionBehaviorHold 119 | ); 120 | } 121 | 122 | - (void)deactivate { 123 | CTTelephonyCenterRemoveObserver(CTTelephonyCenterGetDefault(), 124 | NULL, 125 | kCTCallStatusChangeNotification, 126 | NULL); 127 | } 128 | 129 | #pragma mark - Blacklist read & write 130 | 131 | - (NSArray*)blockedItems 132 | { 133 | if ([[NSFileManager defaultManager] fileExistsAtPath:[self blacklistPath]]) { 134 | NSData *jsonData = [NSData dataWithContentsOfFile:[self blacklistPath]]; 135 | NSArray *blockedItems = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:NULL]; 136 | NSMutableArray *parsedItems = [NSMutableArray array]; 137 | if (blockedItems && [blockedItems isKindOfClass:[NSArray class]]) { 138 | for (NSDictionary *itemDict in blockedItems) { 139 | [parsedItems addObject:[[LTBlacklistItem alloc] initWithDictionary:itemDict]]; 140 | } 141 | return parsedItems; 142 | } 143 | } 144 | return @[]; 145 | } 146 | 147 | - (void)setBlockedItems:(NSArray *)blockedItems 148 | { 149 | NSError *serializeError = nil; 150 | 151 | NSMutableArray *serialzableItems = [NSMutableArray array]; 152 | for (LTBlacklistItem *item in blockedItems) { 153 | [serialzableItems addObject:[item dictionaryRepresentation]]; 154 | } 155 | 156 | NSData *jsonData = [NSJSONSerialization dataWithJSONObject:serialzableItems options:0 error:&serializeError]; 157 | if (serializeError.code != noErr) { 158 | NSLog(@"%@", serializeError.localizedDescription); 159 | return; 160 | } 161 | 162 | NSError *writeError = nil; 163 | [jsonData writeToFile:[self blacklistPath] options:NSDataWritingAtomic error:&writeError]; 164 | if (writeError.code != noErr) { 165 | NSLog(@"%@", writeError.localizedDescription); 166 | } 167 | } 168 | 169 | #pragma mark - Blacklist manager 170 | 171 | - (NSArray *)blockedPhoneNumbers { 172 | NSArray *__blockedPhoneNumbers = [self.cache objectForKey:kBlockedPhoneNumbersCacheKey]; 173 | if (!__blockedPhoneNumbers) { 174 | NSMutableArray *newBlockedPhoneNumbers = [NSMutableArray array]; 175 | for (LTBlacklistItem *item in self.blockedItems) { 176 | if (item.blocked) 177 | [newBlockedPhoneNumbers addObject:item.phoneNumber.description]; 178 | } 179 | __blockedPhoneNumbers = [NSArray arrayWithArray:newBlockedPhoneNumbers]; 180 | [self.cache setObject:__blockedPhoneNumbers forKey:kBlockedPhoneNumbersCacheKey]; 181 | } 182 | return __blockedPhoneNumbers; 183 | } 184 | 185 | - (LTBlacklistItem*)itemByPhoneNumber:(LTPhoneNumber*)phoneNumber 186 | { 187 | if (!phoneNumber) return nil; 188 | for (LTBlacklistItem *item in self.blockedItems) { 189 | if ([phoneNumber rangeOfString:item.phoneNumber].location != NSNotFound) { 190 | return item; 191 | } 192 | } 193 | return nil; 194 | } 195 | 196 | - (void)updateBlockedItem:(LTBlacklistItem*)blockedItem 197 | { 198 | NSMutableArray *newItems = [NSMutableArray arrayWithArray:self.blockedItems]; 199 | uint i = 0; 200 | for (LTBlacklistItem *item in newItems) { 201 | if ([item.phoneNumber isEqualToString:blockedItem.phoneNumber]) { 202 | [newItems replaceObjectAtIndex:i withObject:blockedItem]; 203 | break; 204 | } 205 | i++; 206 | } 207 | self.blockedItems = newItems; 208 | } 209 | 210 | - (void)unblockPhoneNumber:(LTPhoneNumber *)phoneNumber { 211 | NSMutableArray *newItems = [NSMutableArray arrayWithArray:self.blockedItems]; 212 | for (LTBlacklistItem *item in newItems) { 213 | if ([item.phoneNumber.description isEqualToString:phoneNumber]) { 214 | item.blocked = NO; 215 | break; 216 | } 217 | } 218 | self.blockedItems = newItems; 219 | } 220 | 221 | - (void)blockPhoneNumber:(LTPhoneNumber *)phoneNumber { 222 | NSMutableArray *newItems = [NSMutableArray arrayWithArray:self.blockedItems]; 223 | BOOL exists = NO; 224 | for (LTBlacklistItem *item in newItems) { 225 | if ([item.phoneNumber isEqualToString:phoneNumber]) { 226 | item.blocked = YES; 227 | exists = YES; 228 | break; 229 | } 230 | } 231 | if (!exists) { 232 | LTBlacklistItem *item = [LTBlacklistItem itemWithNumber:phoneNumber]; 233 | if (item) { 234 | item.blocked = YES; 235 | [newItems addObject:item]; 236 | } 237 | } 238 | self.blockedItems = newItems; 239 | } 240 | 241 | - (void)addItem:(LTPhoneNumber *)phoneNumber 242 | { 243 | NSMutableArray *newItems = [NSMutableArray arrayWithArray:self.blockedItems]; 244 | BOOL exists = NO; 245 | for (LTBlacklistItem *item in newItems) { 246 | if ([item.phoneNumber isEqualToString:phoneNumber]) { 247 | exists = YES; 248 | break; 249 | } 250 | } 251 | if (!exists) { 252 | LTBlacklistItem *newItem = [LTBlacklistItem itemWithNumber:phoneNumber]; 253 | [newItems addObject:newItem]; 254 | } 255 | self.blockedItems = newItems; 256 | } 257 | 258 | - (void)removeItem:(LTPhoneNumber *)phoneNumber 259 | { 260 | NSMutableArray *newItems = [NSMutableArray arrayWithArray:self.blockedItems]; 261 | for (LTBlacklistItem *item in newItems) { 262 | if ([item.phoneNumber isEqualToString:phoneNumber]) { 263 | [newItems removeObject:item]; 264 | break; 265 | } 266 | } 267 | self.blockedItems = newItems; 268 | } 269 | 270 | @end 271 | -------------------------------------------------------------------------------- /LTBlacklist/Vendors/MCSwipeTableViewCell/MCSwipeTableViewCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // MCSwipeTableViewCell.m 3 | // MCSwipeTableViewCell 4 | // 5 | // Created by Ali Karagoz on 24/02/13. 6 | // Copyright (c) 2013 Mad Castle. All rights reserved. 7 | // 8 | 9 | #import "MCSwipeTableViewCell.h" 10 | 11 | static CGFloat const kMCStop1 = 0.25; // Percentage limit to trigger the first action 12 | static CGFloat const kMCStop2 = 0.75; // Percentage limit to trigger the second action 13 | static CGFloat const kMCBounceAmplitude = 20.0; // Maximum bounce amplitude when using the MCSwipeTableViewCellModeSwitch mode 14 | static NSTimeInterval const kMCBounceDuration1 = 0.2; // Duration of the first part of the bounce animation 15 | static NSTimeInterval const kMCBounceDuration2 = 0.1; // Duration of the second part of the bounce animation 16 | static NSTimeInterval const kMCDurationLowLimit = 0.25; // Lowest duration when swipping the cell because we try to simulate velocity 17 | static NSTimeInterval const kMCDurationHightLimit = 0.1; // Highest duration when swipping the cell because we try to simulate velocity 18 | 19 | @interface MCSwipeTableViewCell () 20 | 21 | @property (nonatomic, assign) MCSwipeTableViewCellDirection direction; 22 | @property (nonatomic, assign) CGFloat currentPercentage; 23 | 24 | @property (nonatomic, strong) UIPanGestureRecognizer *panGestureRecognizer; 25 | @property (nonatomic, strong) UIImageView *slidingImageView; 26 | @property (nonatomic, strong) NSString *currentImageName; 27 | @property (nonatomic, strong) UIView *colorIndicatorView; 28 | 29 | @end 30 | 31 | @implementation MCSwipeTableViewCell 32 | 33 | #pragma mark - Initialization 34 | 35 | - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { 36 | self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; 37 | if (self) { 38 | [self initializer]; 39 | } 40 | return self; 41 | } 42 | - (id)initWithCoder:(NSCoder *)aDecoder { 43 | self = [super initWithCoder:aDecoder]; 44 | if (self) { 45 | [self initializer]; 46 | } 47 | return self; 48 | } 49 | - (id)init { 50 | self = [super init]; 51 | if (self) { 52 | [self initializer]; 53 | } 54 | return self; 55 | } 56 | 57 | #pragma mark - Custom Initializer 58 | 59 | - (id)initWithStyle:(UITableViewCellStyle)style 60 | reuseIdentifier:(NSString *)reuseIdentifier 61 | firstStateIconName:(NSString *)firstIconName 62 | firstColor:(UIColor *)firstColor 63 | secondStateIconName:(NSString *)secondIconName 64 | secondColor:(UIColor *)secondColor 65 | thirdIconName:(NSString *)thirdIconName 66 | thirdColor:(UIColor *)thirdColor 67 | fourthIconName:(NSString *)fourthIconName 68 | fourthColor:(UIColor *)fourthColor { 69 | 70 | self = [self initWithStyle:style reuseIdentifier:reuseIdentifier]; 71 | if (self) { 72 | [self setFirstStateIconName:firstIconName 73 | firstColor:firstColor 74 | secondStateIconName:secondIconName 75 | secondColor:secondColor 76 | thirdIconName:thirdIconName 77 | thirdColor:thirdColor 78 | fourthIconName:fourthIconName 79 | fourthColor:fourthColor]; 80 | } 81 | return self; 82 | } 83 | 84 | - (void)initializer { 85 | 86 | _mode = MCSwipeTableViewCellModeNone; 87 | 88 | _colorIndicatorView = [[UIView alloc] initWithFrame:self.bounds]; 89 | [_colorIndicatorView setAutoresizingMask:UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth]; 90 | [_colorIndicatorView setBackgroundColor:(self.defaultColor ? self.defaultColor : [UIColor clearColor])]; 91 | [self insertSubview:_colorIndicatorView atIndex:0]; 92 | 93 | _slidingImageView = [[UIImageView alloc] init]; 94 | [_slidingImageView setContentMode:UIViewContentModeCenter]; 95 | [_colorIndicatorView addSubview:_slidingImageView]; 96 | 97 | _panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePanGestureRecognizer:)]; 98 | [self addGestureRecognizer:_panGestureRecognizer]; 99 | [_panGestureRecognizer setDelegate:self]; 100 | 101 | _isDragging = NO; 102 | 103 | // By default the cells are draggable 104 | _shouldDrag = YES; 105 | 106 | // By default the icons are animating 107 | _shouldAnimatesIcons = YES; 108 | 109 | // Set state modes 110 | _modeForState1 = MCSwipeTableViewCellModeNone; 111 | _modeForState2 = MCSwipeTableViewCellModeNone; 112 | _modeForState3 = MCSwipeTableViewCellModeNone; 113 | _modeForState4 = MCSwipeTableViewCellModeNone; 114 | } 115 | 116 | #pragma mark - Setter 117 | 118 | - (void)setFirstStateIconName:(NSString *)firstIconName 119 | firstColor:(UIColor *)firstColor 120 | secondStateIconName:(NSString *)secondIconName 121 | secondColor:(UIColor *)secondColor 122 | thirdIconName:(NSString *)thirdIconName 123 | thirdColor:(UIColor *)thirdColor 124 | fourthIconName:(NSString *)fourthIconName 125 | fourthColor:(UIColor *)fourthColor { 126 | 127 | [self setFirstIconName:firstIconName]; 128 | [self setSecondIconName:secondIconName]; 129 | [self setThirdIconName:thirdIconName]; 130 | [self setFourthIconName:fourthIconName]; 131 | 132 | [self setFirstColor:firstColor]; 133 | [self setSecondColor:secondColor]; 134 | [self setThirdColor:thirdColor]; 135 | [self setFourthColor:fourthColor]; 136 | } 137 | 138 | #pragma mark - Prepare reuse 139 | - (void)prepareForReuse { 140 | [super prepareForReuse]; 141 | 142 | // Clearing before presenting back the cell to the user 143 | [_colorIndicatorView setBackgroundColor:[UIColor clearColor]]; 144 | 145 | // clearing the dragging flag 146 | _isDragging = NO; 147 | 148 | // Before reuse we need to reset it's state 149 | _shouldDrag = YES; 150 | _shouldAnimatesIcons = YES; 151 | _mode = MCSwipeTableViewCellModeNone; 152 | _modeForState1 = MCSwipeTableViewCellModeNone; 153 | _modeForState2 = MCSwipeTableViewCellModeNone; 154 | _modeForState3 = MCSwipeTableViewCellModeNone; 155 | _modeForState4 = MCSwipeTableViewCellModeNone; 156 | } 157 | 158 | #pragma mark - Handle Gestures 159 | 160 | - (void)handlePanGestureRecognizer:(UIPanGestureRecognizer *)gesture { 161 | 162 | // The user do not want you to be dragged! 163 | if (!_shouldDrag) return; 164 | 165 | UIGestureRecognizerState state = [gesture state]; 166 | CGPoint translation = [gesture translationInView:self]; 167 | CGPoint velocity = [gesture velocityInView:self]; 168 | CGFloat percentage = [self percentageWithOffset:CGRectGetMinX(self.contentView.frame) relativeToWidth:CGRectGetWidth(self.bounds)]; 169 | NSTimeInterval animationDuration = [self animationDurationWithVelocity:velocity]; 170 | _direction = [self directionWithPercentage:percentage]; 171 | 172 | if (state == UIGestureRecognizerStateBegan || state == UIGestureRecognizerStateChanged) { 173 | _isDragging = YES; 174 | 175 | CGPoint center = {self.contentView.center.x + translation.x, self.contentView.center.y}; 176 | [self.contentView setCenter:center]; 177 | [self animateWithOffset:CGRectGetMinX(self.contentView.frame)]; 178 | [gesture setTranslation:CGPointZero inView:self]; 179 | 180 | // Notifying the delegate that we are dragging with an offset percentage 181 | if ([_delegate respondsToSelector:@selector(swipeTableViewCell:didSwipWithPercentage:)]) { 182 | [_delegate swipeTableViewCell:self didSwipWithPercentage:percentage]; 183 | } 184 | } 185 | 186 | else if (state == UIGestureRecognizerStateEnded || state == UIGestureRecognizerStateCancelled) { 187 | _isDragging = NO; 188 | 189 | _currentImageName = [self imageNameWithPercentage:percentage]; 190 | _currentPercentage = percentage; 191 | 192 | // Current state 193 | MCSwipeTableViewCellState cellState = [self stateWithPercentage:percentage]; 194 | 195 | // Current mode 196 | MCSwipeTableViewCellMode cellMode; 197 | 198 | if (cellState == MCSwipeTableViewCellState1 && self.modeForState1 != MCSwipeTableViewCellModeNone) { 199 | cellMode = self.modeForState1; 200 | } else if (cellState == MCSwipeTableViewCellState2 && self.modeForState2 != MCSwipeTableViewCellModeNone) { 201 | cellMode = self.modeForState2; 202 | } else if (cellState == MCSwipeTableViewCellState3 && self.modeForState3 != MCSwipeTableViewCellModeNone) { 203 | cellMode = self.modeForState3; 204 | } else if (cellState == MCSwipeTableViewCellState4 && self.modeForState4 != MCSwipeTableViewCellModeNone) { 205 | cellMode = self.modeForState4; 206 | } else { 207 | cellMode = self.mode; 208 | } 209 | 210 | if (cellMode == MCSwipeTableViewCellModeExit && _direction != MCSwipeTableViewCellDirectionCenter && [self validateState:cellState]) 211 | [self moveWithDuration:animationDuration andDirection:_direction]; 212 | else 213 | [self bounceToOrigin]; 214 | } 215 | } 216 | 217 | #pragma mark - UIGestureRecognizerDelegate 218 | - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer { 219 | if ([gestureRecognizer class] == [UIPanGestureRecognizer class]) { 220 | 221 | UIPanGestureRecognizer *g = (UIPanGestureRecognizer *)gestureRecognizer; 222 | CGPoint point = [g velocityInView:self]; 223 | 224 | if (fabsf(point.x) > fabsf(point.y) ) { 225 | 226 | // We notify the delegate that we just started dragging 227 | if ([_delegate respondsToSelector:@selector(swipeTableViewCellDidStartSwiping:)]) { 228 | [_delegate swipeTableViewCellDidStartSwiping:self]; 229 | } 230 | 231 | return YES; 232 | } 233 | } 234 | return NO; 235 | } 236 | 237 | #pragma mark - Utils 238 | - (CGFloat)offsetWithPercentage:(CGFloat)percentage relativeToWidth:(CGFloat)width { 239 | CGFloat offset = percentage * width; 240 | 241 | if (offset < -width) offset = -width; 242 | else if (offset > width) offset = width; 243 | 244 | return offset; 245 | } 246 | 247 | - (CGFloat)percentageWithOffset:(CGFloat)offset relativeToWidth:(CGFloat)width { 248 | CGFloat percentage = offset / width; 249 | 250 | if (percentage < -1.0) percentage = -1.0; 251 | else if (percentage > 1.0) percentage = 1.0; 252 | 253 | return percentage; 254 | } 255 | 256 | - (NSTimeInterval)animationDurationWithVelocity:(CGPoint)velocity { 257 | CGFloat width = CGRectGetWidth(self.bounds); 258 | NSTimeInterval animationDurationDiff = kMCDurationHightLimit - kMCDurationLowLimit; 259 | CGFloat horizontalVelocity = velocity.x; 260 | 261 | if (horizontalVelocity < -width) horizontalVelocity = -width; 262 | else if (horizontalVelocity > width) horizontalVelocity = width; 263 | 264 | return (kMCDurationHightLimit + kMCDurationLowLimit) - fabs(((horizontalVelocity / width) * animationDurationDiff)); 265 | } 266 | 267 | - (MCSwipeTableViewCellDirection)directionWithPercentage:(CGFloat)percentage { 268 | if (percentage < 0) 269 | return MCSwipeTableViewCellDirectionLeft; 270 | else if (percentage > 0) 271 | return MCSwipeTableViewCellDirectionRight; 272 | else 273 | return MCSwipeTableViewCellDirectionCenter; 274 | } 275 | 276 | - (NSString *)imageNameWithPercentage:(CGFloat)percentage { 277 | NSString *imageName; 278 | 279 | // Image 280 | if (percentage >= 0 && percentage < kMCStop2) 281 | imageName = _firstIconName; 282 | else if (percentage >= kMCStop2) 283 | imageName = _secondIconName; 284 | else if (percentage < 0 && percentage > -kMCStop2) 285 | imageName = _thirdIconName; 286 | else if (percentage <= -kMCStop2) 287 | imageName = _fourthIconName; 288 | 289 | return imageName; 290 | } 291 | - (CGFloat)imageAlphaWithPercentage:(CGFloat)percentage { 292 | CGFloat alpha; 293 | 294 | if (percentage >= 0 && percentage < kMCStop1) 295 | alpha = percentage / kMCStop1; 296 | else if (percentage < 0 && percentage > -kMCStop1) 297 | alpha = fabsf(percentage / kMCStop1); 298 | else alpha = 1.0; 299 | 300 | return alpha; 301 | } 302 | 303 | - (UIColor *)colorWithPercentage:(CGFloat)percentage { 304 | UIColor *color; 305 | 306 | // Background Color 307 | if (percentage >= kMCStop1 && percentage < kMCStop2) 308 | color = _firstColor; 309 | else if (percentage >= kMCStop2) 310 | color = _secondColor; 311 | else if (percentage < -kMCStop1 && percentage > -kMCStop2) 312 | color = _thirdColor; 313 | else if (percentage <= -kMCStop2) 314 | color = _fourthColor; 315 | else 316 | color = self.defaultColor ? self.defaultColor : [UIColor clearColor]; 317 | 318 | return color; 319 | } 320 | 321 | - (MCSwipeTableViewCellState)stateWithPercentage:(CGFloat)percentage { 322 | MCSwipeTableViewCellState state; 323 | 324 | state = MCSwipeTableViewCellStateNone; 325 | 326 | if (percentage >= kMCStop1 && [self validateState:MCSwipeTableViewCellState1]) 327 | state = MCSwipeTableViewCellState1; 328 | 329 | if (percentage >= kMCStop2 && [self validateState:MCSwipeTableViewCellState2]) 330 | state = MCSwipeTableViewCellState2; 331 | 332 | if (percentage <= -kMCStop1 && [self validateState:MCSwipeTableViewCellState3]) 333 | state = MCSwipeTableViewCellState3; 334 | 335 | if (percentage <= -kMCStop2 && [self validateState:MCSwipeTableViewCellState4]) 336 | state = MCSwipeTableViewCellState4; 337 | 338 | return state; 339 | } 340 | 341 | - (BOOL)validateState:(MCSwipeTableViewCellState)state { 342 | BOOL isValid = YES; 343 | 344 | switch (state) { 345 | case MCSwipeTableViewCellStateNone: { 346 | isValid = NO; 347 | } 348 | break; 349 | 350 | case MCSwipeTableViewCellState1: { 351 | if (!_firstColor && !_firstIconName) 352 | isValid = NO; 353 | } 354 | break; 355 | 356 | case MCSwipeTableViewCellState2: { 357 | if (!_secondColor && !_secondIconName) 358 | isValid = NO; 359 | } 360 | break; 361 | 362 | case MCSwipeTableViewCellState3: { 363 | if (!_thirdColor && !_thirdIconName) 364 | isValid = NO; 365 | } 366 | break; 367 | 368 | case MCSwipeTableViewCellState4: { 369 | if (!_fourthColor && !_fourthIconName) 370 | isValid = NO; 371 | } 372 | break; 373 | 374 | default: 375 | break; 376 | } 377 | 378 | return isValid; 379 | } 380 | 381 | #pragma mark - Movement 382 | 383 | - (void)animateWithOffset:(CGFloat)offset { 384 | CGFloat percentage = [self percentageWithOffset:offset relativeToWidth:CGRectGetWidth(self.bounds)]; 385 | 386 | // Image Name 387 | NSString *imageName = [self imageNameWithPercentage:percentage]; 388 | 389 | // Image Position 390 | if (imageName != nil) { 391 | [_slidingImageView setImage:[UIImage imageNamed:imageName]]; 392 | [_slidingImageView setAlpha:[self imageAlphaWithPercentage:percentage]]; 393 | [self slideImageWithPercentage:percentage imageName:imageName isDragging:self.shouldAnimatesIcons]; 394 | } 395 | 396 | // Color 397 | UIColor *color = [self colorWithPercentage:percentage]; 398 | if (color != nil) { 399 | [_colorIndicatorView setBackgroundColor:color]; 400 | } 401 | } 402 | 403 | - (void)slideImageWithPercentage:(CGFloat)percentage imageName:(NSString *)imageName isDragging:(BOOL)isDragging { 404 | UIImage *slidingImage = [UIImage imageNamed:imageName]; 405 | CGSize slidingImageSize = slidingImage.size; 406 | CGRect slidingImageRect; 407 | 408 | CGPoint position = CGPointZero; 409 | 410 | position.y = CGRectGetHeight(self.bounds) / 2.0; 411 | 412 | if (isDragging) { 413 | if (percentage >= 0 && percentage < kMCStop1) { 414 | position.x = [self offsetWithPercentage:(kMCStop1 / 2) relativeToWidth:CGRectGetWidth(self.bounds)]; 415 | } 416 | 417 | else if (percentage >= kMCStop1) { 418 | position.x = [self offsetWithPercentage:percentage - (kMCStop1 / 2) relativeToWidth:CGRectGetWidth(self.bounds)]; 419 | } 420 | else if (percentage < 0 && percentage >= -kMCStop1) { 421 | position.x = CGRectGetWidth(self.bounds) - [self offsetWithPercentage:(kMCStop1 / 2) relativeToWidth:CGRectGetWidth(self.bounds)]; 422 | } 423 | 424 | else if (percentage < -kMCStop1) { 425 | position.x = CGRectGetWidth(self.bounds) + [self offsetWithPercentage:percentage + (kMCStop1 / 2) relativeToWidth:CGRectGetWidth(self.bounds)]; 426 | } 427 | } 428 | else { 429 | if (_direction == MCSwipeTableViewCellDirectionRight) { 430 | position.x = [self offsetWithPercentage:(kMCStop1 / 2) relativeToWidth:CGRectGetWidth(self.bounds)]; 431 | } 432 | else if (_direction == MCSwipeTableViewCellDirectionLeft) { 433 | position.x = CGRectGetWidth(self.bounds) - [self offsetWithPercentage:(kMCStop1 / 2) relativeToWidth:CGRectGetWidth(self.bounds)]; 434 | } 435 | else { 436 | return; 437 | } 438 | } 439 | 440 | 441 | slidingImageRect = CGRectMake(position.x - slidingImageSize.width / 2.0, 442 | position.y - slidingImageSize.height / 2.0, 443 | slidingImageSize.width, 444 | slidingImageSize.height); 445 | 446 | slidingImageRect = CGRectIntegral(slidingImageRect); 447 | [_slidingImageView setFrame:slidingImageRect]; 448 | } 449 | 450 | - (void)moveWithDuration:(NSTimeInterval)duration andDirection:(MCSwipeTableViewCellDirection)direction { 451 | CGFloat origin; 452 | 453 | if (direction == MCSwipeTableViewCellDirectionLeft) 454 | origin = -CGRectGetWidth(self.bounds); 455 | else 456 | origin = CGRectGetWidth(self.bounds); 457 | 458 | CGFloat percentage = [self percentageWithOffset:origin relativeToWidth:CGRectGetWidth(self.bounds)]; 459 | CGRect rect = self.contentView.frame; 460 | rect.origin.x = origin; 461 | 462 | // Color 463 | UIColor *color = [self colorWithPercentage:_currentPercentage]; 464 | if (color != nil) { 465 | [_colorIndicatorView setBackgroundColor:color]; 466 | } 467 | 468 | // Image 469 | if (_currentImageName != nil) { 470 | [_slidingImageView setImage:[UIImage imageNamed:_currentImageName]]; 471 | } 472 | 473 | [UIView animateWithDuration:duration 474 | delay:0.0 475 | options:(UIViewAnimationOptionCurveEaseOut | UIViewAnimationOptionAllowUserInteraction) 476 | animations:^{ 477 | [self.contentView setFrame:rect]; 478 | [_slidingImageView setAlpha:0]; 479 | [self slideImageWithPercentage:percentage imageName:_currentImageName isDragging:self.shouldAnimatesIcons]; 480 | } 481 | completion:^(BOOL finished) { 482 | [self notifyDelegate]; 483 | }]; 484 | } 485 | 486 | - (void)bounceToOrigin { 487 | CGFloat bounceDistance = kMCBounceAmplitude * _currentPercentage; 488 | 489 | [UIView animateWithDuration:kMCBounceDuration1 490 | delay:0 491 | options:(UIViewAnimationOptionCurveEaseOut) 492 | animations:^{ 493 | CGRect frame = self.contentView.frame; 494 | frame.origin.x = -bounceDistance; 495 | [self.contentView setFrame:frame]; 496 | [_slidingImageView setAlpha:0.0]; 497 | [self slideImageWithPercentage:0 imageName:_currentImageName isDragging:NO]; 498 | 499 | // Clearing the indicator view 500 | [_colorIndicatorView setBackgroundColor:[UIColor clearColor]]; 501 | } 502 | completion:^(BOOL finished1) { 503 | 504 | [UIView animateWithDuration:kMCBounceDuration2 505 | delay:0 506 | options:UIViewAnimationOptionCurveEaseIn 507 | animations:^{ 508 | CGRect frame = self.contentView.frame; 509 | frame.origin.x = 0; 510 | [self.contentView setFrame:frame]; 511 | } 512 | completion:^(BOOL finished2) { 513 | [self notifyDelegate]; 514 | }]; 515 | }]; 516 | } 517 | 518 | #pragma mark - Delegate Notification 519 | 520 | - (void)notifyDelegate { 521 | MCSwipeTableViewCellState state = [self stateWithPercentage:_currentPercentage]; 522 | 523 | MCSwipeTableViewCellMode mode = self.mode; 524 | 525 | if (mode == MCSwipeTableViewCellModeNone) { 526 | switch (state) { 527 | case MCSwipeTableViewCellState1: { 528 | mode = self.modeForState1; 529 | } break; 530 | 531 | case MCSwipeTableViewCellState2: { 532 | mode = self.modeForState2; 533 | } break; 534 | 535 | case MCSwipeTableViewCellState3: { 536 | mode = self.modeForState3; 537 | } break; 538 | 539 | case MCSwipeTableViewCellState4: { 540 | mode = self.modeForState4; 541 | } break; 542 | 543 | default: 544 | break; 545 | } 546 | } 547 | 548 | if (state != MCSwipeTableViewCellStateNone) { 549 | if ([_delegate respondsToSelector:@selector(swipeTableViewCell:didEndSwipingSwipingWithState:mode:)]) { 550 | [_delegate swipeTableViewCell:self didEndSwipingSwipingWithState:state mode:mode]; 551 | } 552 | } 553 | } 554 | 555 | @end -------------------------------------------------------------------------------- /LTBlacklist.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | D70C8E6917CCF62B006E3D38 /* Icon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = D70C8E6817CCF62B006E3D38 /* Icon@2x.png */; }; 11 | D70C8E6B17CCF637006E3D38 /* Icon.png in Resources */ = {isa = PBXBuildFile; fileRef = D70C8E6A17CCF637006E3D38 /* Icon.png */; }; 12 | D721238717A7B80D007D9CD7 /* LTPhoneNumber.m in Sources */ = {isa = PBXBuildFile; fileRef = D721238617A7B80D007D9CD7 /* LTPhoneNumber.m */; }; 13 | D7577621179D09E800538D2C /* LTBlacklist.m in Sources */ = {isa = PBXBuildFile; fileRef = D7577620179D09E800538D2C /* LTBlacklist.m */; }; 14 | D757764117A0FBA500538D2C /* BlockIcon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = D757763617A0FBA500538D2C /* BlockIcon@2x.png */; }; 15 | D757764B17A0FBA500538D2C /* UnblockIcon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = D757764017A0FBA500538D2C /* UnblockIcon@2x.png */; }; 16 | D78D345C177B202F002007AE /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D78D345B177B202F002007AE /* UIKit.framework */; }; 17 | D78D345E177B202F002007AE /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D78D345D177B202F002007AE /* Foundation.framework */; }; 18 | D78D3460177B202F002007AE /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D78D345F177B202F002007AE /* CoreGraphics.framework */; }; 19 | D78D3468177B202F002007AE /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = D78D3467177B202F002007AE /* main.m */; }; 20 | D78D346C177B202F002007AE /* LTAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = D78D346B177B202F002007AE /* LTAppDelegate.m */; }; 21 | D78D346E177B202F002007AE /* Default.png in Resources */ = {isa = PBXBuildFile; fileRef = D78D346D177B202F002007AE /* Default.png */; }; 22 | D78D3470177B202F002007AE /* Default@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = D78D346F177B202F002007AE /* Default@2x.png */; }; 23 | D78D3472177B202F002007AE /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = D78D3471177B202F002007AE /* Default-568h@2x.png */; }; 24 | D7A0D36E17EEE7AE0004BB99 /* MCSwipeTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = D7A0D36D17EEE7AE0004BB99 /* MCSwipeTableViewCell.m */; }; 25 | D7A0D37417EF2EE90004BB99 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D7A0D37317EF2EE90004BB99 /* QuartzCore.framework */; settings = {ATTRIBUTES = (Required, ); }; }; 26 | D7A0D37C17EF37E80004BB99 /* WCAlertView.m in Sources */ = {isa = PBXBuildFile; fileRef = D7A0D37B17EF37E80004BB99 /* WCAlertView.m */; }; 27 | D7A0D37E17EF44660004BB99 /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D7A0D37D17EF44660004BB99 /* AVFoundation.framework */; }; 28 | D7A0D38317EF47C60004BB99 /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D7A0D38217EF47C60004BB99 /* AudioToolbox.framework */; }; 29 | D7CBE1C71790440100C6A0D4 /* CoreTelephony.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D7CBE1C61790440100C6A0D4 /* CoreTelephony.framework */; }; 30 | D7CBE1CE1790465800C6A0D4 /* LTBlacklistViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D7CBE1CD1790465800C6A0D4 /* LTBlacklistViewController.m */; }; 31 | D7CBE1DD1790564B00C6A0D4 /* LTBlacklistItem.m in Sources */ = {isa = PBXBuildFile; fileRef = D7CBE1DC1790564B00C6A0D4 /* LTBlacklistItem.m */; }; 32 | D7CBE1E017905A2800C6A0D4 /* LTBlacklistTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = D7CBE1DF17905A2800C6A0D4 /* LTBlacklistTableViewCell.m */; }; 33 | /* End PBXBuildFile section */ 34 | 35 | /* Begin PBXFileReference section */ 36 | D70C8E6817CCF62B006E3D38 /* Icon@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon@2x.png"; sourceTree = ""; }; 37 | D70C8E6A17CCF637006E3D38 /* Icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Icon.png; sourceTree = ""; }; 38 | D721238517A7B80D007D9CD7 /* LTPhoneNumber.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LTPhoneNumber.h; sourceTree = ""; }; 39 | D721238617A7B80D007D9CD7 /* LTPhoneNumber.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LTPhoneNumber.m; sourceTree = ""; }; 40 | D757761F179D09E800538D2C /* LTBlacklist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LTBlacklist.h; sourceTree = ""; }; 41 | D7577620179D09E800538D2C /* LTBlacklist.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LTBlacklist.m; sourceTree = ""; }; 42 | D7577623179D0B3C00538D2C /* ObjectiveCGenerics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ObjectiveCGenerics.h; sourceTree = ""; }; 43 | D757763617A0FBA500538D2C /* BlockIcon@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "BlockIcon@2x.png"; sourceTree = ""; }; 44 | D757764017A0FBA500538D2C /* UnblockIcon@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "UnblockIcon@2x.png"; sourceTree = ""; }; 45 | D78D3458177B202F002007AE /* LTBlacklist.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = LTBlacklist.app; sourceTree = BUILT_PRODUCTS_DIR; }; 46 | D78D345B177B202F002007AE /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 47 | D78D345D177B202F002007AE /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 48 | D78D345F177B202F002007AE /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 49 | D78D3463177B202F002007AE /* LTBlacklist-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "LTBlacklist-Info.plist"; sourceTree = ""; }; 50 | D78D3467177B202F002007AE /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 51 | D78D3469177B202F002007AE /* LTBlacklist-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "LTBlacklist-Prefix.pch"; sourceTree = ""; }; 52 | D78D346A177B202F002007AE /* LTAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LTAppDelegate.h; sourceTree = ""; }; 53 | D78D346B177B202F002007AE /* LTAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LTAppDelegate.m; sourceTree = ""; }; 54 | D78D346D177B202F002007AE /* Default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Default.png; sourceTree = ""; }; 55 | D78D346F177B202F002007AE /* Default@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default@2x.png"; sourceTree = ""; }; 56 | D78D3471177B202F002007AE /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = ""; }; 57 | D7A0D36C17EEE7AE0004BB99 /* MCSwipeTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCSwipeTableViewCell.h; sourceTree = ""; }; 58 | D7A0D36D17EEE7AE0004BB99 /* MCSwipeTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MCSwipeTableViewCell.m; sourceTree = ""; }; 59 | D7A0D36F17EF2E180004BB99 /* Reveal.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Reveal.framework; path = "../../../../Applications/Reveal.app/Contents/SharedSupport/iOS-Libraries/Reveal.framework"; sourceTree = ""; }; 60 | D7A0D37117EF2E7A0004BB99 /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = System/Library/Frameworks/CFNetwork.framework; sourceTree = SDKROOT; }; 61 | D7A0D37317EF2EE90004BB99 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; 62 | D7A0D37A17EF37E80004BB99 /* WCAlertView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WCAlertView.h; sourceTree = ""; }; 63 | D7A0D37B17EF37E80004BB99 /* WCAlertView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WCAlertView.m; sourceTree = ""; }; 64 | D7A0D37D17EF44660004BB99 /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; }; 65 | D7A0D38217EF47C60004BB99 /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; }; 66 | D7CBE1C61790440100C6A0D4 /* CoreTelephony.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreTelephony.framework; path = System/Library/Frameworks/CoreTelephony.framework; sourceTree = SDKROOT; }; 67 | D7CBE1C81790441700C6A0D4 /* AddressBook.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AddressBook.framework; path = System/Library/Frameworks/AddressBook.framework; sourceTree = SDKROOT; }; 68 | D7CBE1CC1790465700C6A0D4 /* LTBlacklistViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LTBlacklistViewController.h; sourceTree = ""; }; 69 | D7CBE1CD1790465800C6A0D4 /* LTBlacklistViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LTBlacklistViewController.m; sourceTree = ""; }; 70 | D7CBE1DB1790564B00C6A0D4 /* LTBlacklistItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LTBlacklistItem.h; sourceTree = ""; }; 71 | D7CBE1DC1790564B00C6A0D4 /* LTBlacklistItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LTBlacklistItem.m; sourceTree = ""; }; 72 | D7CBE1DE17905A2800C6A0D4 /* LTBlacklistTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LTBlacklistTableViewCell.h; sourceTree = ""; }; 73 | D7CBE1DF17905A2800C6A0D4 /* LTBlacklistTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LTBlacklistTableViewCell.m; sourceTree = ""; }; 74 | /* End PBXFileReference section */ 75 | 76 | /* Begin PBXFrameworksBuildPhase section */ 77 | D78D3455177B202F002007AE /* Frameworks */ = { 78 | isa = PBXFrameworksBuildPhase; 79 | buildActionMask = 2147483647; 80 | files = ( 81 | D7A0D38317EF47C60004BB99 /* AudioToolbox.framework in Frameworks */, 82 | D7A0D37E17EF44660004BB99 /* AVFoundation.framework in Frameworks */, 83 | D7A0D37417EF2EE90004BB99 /* QuartzCore.framework in Frameworks */, 84 | D78D3460177B202F002007AE /* CoreGraphics.framework in Frameworks */, 85 | D7CBE1C71790440100C6A0D4 /* CoreTelephony.framework in Frameworks */, 86 | D78D345E177B202F002007AE /* Foundation.framework in Frameworks */, 87 | D78D345C177B202F002007AE /* UIKit.framework in Frameworks */, 88 | ); 89 | runOnlyForDeploymentPostprocessing = 0; 90 | }; 91 | /* End PBXFrameworksBuildPhase section */ 92 | 93 | /* Begin PBXGroup section */ 94 | D7577622179D0B3C00538D2C /* Vendors */ = { 95 | isa = PBXGroup; 96 | children = ( 97 | D7A0D37917EF37E80004BB99 /* WCAlertView */, 98 | D7A0D36B17EEE7AE0004BB99 /* MCSwipeTableViewCell */, 99 | D7577623179D0B3C00538D2C /* ObjectiveCGenerics.h */, 100 | ); 101 | path = Vendors; 102 | sourceTree = ""; 103 | }; 104 | D757762D179E73B600538D2C /* Images */ = { 105 | isa = PBXGroup; 106 | children = ( 107 | D757763617A0FBA500538D2C /* BlockIcon@2x.png */, 108 | D757764017A0FBA500538D2C /* UnblockIcon@2x.png */, 109 | ); 110 | path = Images; 111 | sourceTree = ""; 112 | }; 113 | D78D344F177B202F002007AE = { 114 | isa = PBXGroup; 115 | children = ( 116 | D78D345A177B202F002007AE /* Frameworks */, 117 | D78D3461177B202F002007AE /* LTBlacklist */, 118 | D78D3459177B202F002007AE /* Products */, 119 | D70C8E6A17CCF637006E3D38 /* Icon.png */, 120 | D70C8E6817CCF62B006E3D38 /* Icon@2x.png */, 121 | ); 122 | sourceTree = ""; 123 | }; 124 | D78D3459177B202F002007AE /* Products */ = { 125 | isa = PBXGroup; 126 | children = ( 127 | D78D3458177B202F002007AE /* LTBlacklist.app */, 128 | ); 129 | name = Products; 130 | sourceTree = ""; 131 | }; 132 | D78D345A177B202F002007AE /* Frameworks */ = { 133 | isa = PBXGroup; 134 | children = ( 135 | D7A0D38217EF47C60004BB99 /* AudioToolbox.framework */, 136 | D7A0D37D17EF44660004BB99 /* AVFoundation.framework */, 137 | D7A0D37317EF2EE90004BB99 /* QuartzCore.framework */, 138 | D7A0D37117EF2E7A0004BB99 /* CFNetwork.framework */, 139 | D7A0D36F17EF2E180004BB99 /* Reveal.framework */, 140 | D7CBE1C81790441700C6A0D4 /* AddressBook.framework */, 141 | D78D345F177B202F002007AE /* CoreGraphics.framework */, 142 | D7CBE1C61790440100C6A0D4 /* CoreTelephony.framework */, 143 | D78D345D177B202F002007AE /* Foundation.framework */, 144 | D78D345B177B202F002007AE /* UIKit.framework */, 145 | ); 146 | name = Frameworks; 147 | sourceTree = ""; 148 | }; 149 | D78D3461177B202F002007AE /* LTBlacklist */ = { 150 | isa = PBXGroup; 151 | children = ( 152 | D7CBE1CB1790464A00C6A0D4 /* Blacklist */, 153 | D757762D179E73B600538D2C /* Images */, 154 | D78D3462177B202F002007AE /* Supporting Files */, 155 | D7577622179D0B3C00538D2C /* Vendors */, 156 | D78D346A177B202F002007AE /* LTAppDelegate.h */, 157 | D78D346B177B202F002007AE /* LTAppDelegate.m */, 158 | ); 159 | path = LTBlacklist; 160 | sourceTree = ""; 161 | }; 162 | D78D3462177B202F002007AE /* Supporting Files */ = { 163 | isa = PBXGroup; 164 | children = ( 165 | D78D3471177B202F002007AE /* Default-568h@2x.png */, 166 | D78D346D177B202F002007AE /* Default.png */, 167 | D78D346F177B202F002007AE /* Default@2x.png */, 168 | D78D3463177B202F002007AE /* LTBlacklist-Info.plist */, 169 | D78D3469177B202F002007AE /* LTBlacklist-Prefix.pch */, 170 | D78D3467177B202F002007AE /* main.m */, 171 | ); 172 | name = "Supporting Files"; 173 | sourceTree = ""; 174 | }; 175 | D7A0D36B17EEE7AE0004BB99 /* MCSwipeTableViewCell */ = { 176 | isa = PBXGroup; 177 | children = ( 178 | D7A0D36C17EEE7AE0004BB99 /* MCSwipeTableViewCell.h */, 179 | D7A0D36D17EEE7AE0004BB99 /* MCSwipeTableViewCell.m */, 180 | ); 181 | path = MCSwipeTableViewCell; 182 | sourceTree = ""; 183 | }; 184 | D7A0D37917EF37E80004BB99 /* WCAlertView */ = { 185 | isa = PBXGroup; 186 | children = ( 187 | D7A0D37A17EF37E80004BB99 /* WCAlertView.h */, 188 | D7A0D37B17EF37E80004BB99 /* WCAlertView.m */, 189 | ); 190 | path = WCAlertView; 191 | sourceTree = ""; 192 | }; 193 | D7CBE1CB1790464A00C6A0D4 /* Blacklist */ = { 194 | isa = PBXGroup; 195 | children = ( 196 | D757761F179D09E800538D2C /* LTBlacklist.h */, 197 | D7577620179D09E800538D2C /* LTBlacklist.m */, 198 | D7CBE1DB1790564B00C6A0D4 /* LTBlacklistItem.h */, 199 | D7CBE1DC1790564B00C6A0D4 /* LTBlacklistItem.m */, 200 | D7CBE1DE17905A2800C6A0D4 /* LTBlacklistTableViewCell.h */, 201 | D7CBE1DF17905A2800C6A0D4 /* LTBlacklistTableViewCell.m */, 202 | D7CBE1CC1790465700C6A0D4 /* LTBlacklistViewController.h */, 203 | D7CBE1CD1790465800C6A0D4 /* LTBlacklistViewController.m */, 204 | D721238517A7B80D007D9CD7 /* LTPhoneNumber.h */, 205 | D721238617A7B80D007D9CD7 /* LTPhoneNumber.m */, 206 | ); 207 | path = Blacklist; 208 | sourceTree = ""; 209 | }; 210 | /* End PBXGroup section */ 211 | 212 | /* Begin PBXNativeTarget section */ 213 | D78D3457177B202F002007AE /* LTBlacklist */ = { 214 | isa = PBXNativeTarget; 215 | buildConfigurationList = D78D3475177B202F002007AE /* Build configuration list for PBXNativeTarget "LTBlacklist" */; 216 | buildPhases = ( 217 | D78D3454177B202F002007AE /* Sources */, 218 | D78D3455177B202F002007AE /* Frameworks */, 219 | D78D3456177B202F002007AE /* Resources */, 220 | ); 221 | buildRules = ( 222 | ); 223 | dependencies = ( 224 | ); 225 | name = LTBlacklist; 226 | productName = LTBlacklist; 227 | productReference = D78D3458177B202F002007AE /* LTBlacklist.app */; 228 | productType = "com.apple.product-type.application"; 229 | }; 230 | /* End PBXNativeTarget section */ 231 | 232 | /* Begin PBXProject section */ 233 | D78D3450177B202F002007AE /* Project object */ = { 234 | isa = PBXProject; 235 | attributes = { 236 | CLASSPREFIX = LT; 237 | LastUpgradeCheck = 0460; 238 | ORGANIZATIONNAME = LexTang.com; 239 | TargetAttributes = { 240 | D78D3457177B202F002007AE = { 241 | SystemCapabilities = { 242 | com.apple.BackgroundModes = { 243 | enabled = 1; 244 | }; 245 | }; 246 | }; 247 | }; 248 | }; 249 | buildConfigurationList = D78D3453177B202F002007AE /* Build configuration list for PBXProject "LTBlacklist" */; 250 | compatibilityVersion = "Xcode 3.2"; 251 | developmentRegion = English; 252 | hasScannedForEncodings = 0; 253 | knownRegions = ( 254 | en, 255 | "zh-Hans", 256 | "zh-Hant", 257 | ); 258 | mainGroup = D78D344F177B202F002007AE; 259 | productRefGroup = D78D3459177B202F002007AE /* Products */; 260 | projectDirPath = ""; 261 | projectRoot = ""; 262 | targets = ( 263 | D78D3457177B202F002007AE /* LTBlacklist */, 264 | ); 265 | }; 266 | /* End PBXProject section */ 267 | 268 | /* Begin PBXResourcesBuildPhase section */ 269 | D78D3456177B202F002007AE /* Resources */ = { 270 | isa = PBXResourcesBuildPhase; 271 | buildActionMask = 2147483647; 272 | files = ( 273 | D757764117A0FBA500538D2C /* BlockIcon@2x.png in Resources */, 274 | D78D3472177B202F002007AE /* Default-568h@2x.png in Resources */, 275 | D78D346E177B202F002007AE /* Default.png in Resources */, 276 | D78D3470177B202F002007AE /* Default@2x.png in Resources */, 277 | D70C8E6B17CCF637006E3D38 /* Icon.png in Resources */, 278 | D70C8E6917CCF62B006E3D38 /* Icon@2x.png in Resources */, 279 | D757764B17A0FBA500538D2C /* UnblockIcon@2x.png in Resources */, 280 | ); 281 | runOnlyForDeploymentPostprocessing = 0; 282 | }; 283 | /* End PBXResourcesBuildPhase section */ 284 | 285 | /* Begin PBXSourcesBuildPhase section */ 286 | D78D3454177B202F002007AE /* Sources */ = { 287 | isa = PBXSourcesBuildPhase; 288 | buildActionMask = 2147483647; 289 | files = ( 290 | D78D346C177B202F002007AE /* LTAppDelegate.m in Sources */, 291 | D7A0D37C17EF37E80004BB99 /* WCAlertView.m in Sources */, 292 | D7577621179D09E800538D2C /* LTBlacklist.m in Sources */, 293 | D7CBE1DD1790564B00C6A0D4 /* LTBlacklistItem.m in Sources */, 294 | D7CBE1E017905A2800C6A0D4 /* LTBlacklistTableViewCell.m in Sources */, 295 | D7A0D36E17EEE7AE0004BB99 /* MCSwipeTableViewCell.m in Sources */, 296 | D7CBE1CE1790465800C6A0D4 /* LTBlacklistViewController.m in Sources */, 297 | D721238717A7B80D007D9CD7 /* LTPhoneNumber.m in Sources */, 298 | D78D3468177B202F002007AE /* main.m in Sources */, 299 | ); 300 | runOnlyForDeploymentPostprocessing = 0; 301 | }; 302 | /* End PBXSourcesBuildPhase section */ 303 | 304 | /* Begin XCBuildConfiguration section */ 305 | D78D3473177B202F002007AE /* Debug */ = { 306 | isa = XCBuildConfiguration; 307 | buildSettings = { 308 | ALWAYS_SEARCH_USER_PATHS = NO; 309 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 310 | CLANG_CXX_LIBRARY = "libc++"; 311 | CLANG_ENABLE_OBJC_ARC = YES; 312 | CLANG_WARN_CONSTANT_CONVERSION = YES; 313 | CLANG_WARN_EMPTY_BODY = YES; 314 | CLANG_WARN_ENUM_CONVERSION = YES; 315 | CLANG_WARN_INT_CONVERSION = YES; 316 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 317 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 318 | COPY_PHASE_STRIP = NO; 319 | GCC_C_LANGUAGE_STANDARD = gnu99; 320 | GCC_DYNAMIC_NO_PIC = NO; 321 | GCC_OPTIMIZATION_LEVEL = 0; 322 | GCC_PREPROCESSOR_DEFINITIONS = ( 323 | "DEBUG=1", 324 | "$(inherited)", 325 | ); 326 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 327 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 328 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 329 | GCC_WARN_UNUSED_VARIABLE = YES; 330 | IPHONEOS_DEPLOYMENT_TARGET = 6.1; 331 | ONLY_ACTIVE_ARCH = YES; 332 | SDKROOT = iphoneos; 333 | }; 334 | name = Debug; 335 | }; 336 | D78D3474177B202F002007AE /* Release */ = { 337 | isa = XCBuildConfiguration; 338 | buildSettings = { 339 | ALWAYS_SEARCH_USER_PATHS = NO; 340 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 341 | CLANG_CXX_LIBRARY = "libc++"; 342 | CLANG_ENABLE_OBJC_ARC = YES; 343 | CLANG_WARN_CONSTANT_CONVERSION = YES; 344 | CLANG_WARN_EMPTY_BODY = YES; 345 | CLANG_WARN_ENUM_CONVERSION = YES; 346 | CLANG_WARN_INT_CONVERSION = YES; 347 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 348 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 349 | COPY_PHASE_STRIP = YES; 350 | GCC_C_LANGUAGE_STANDARD = gnu99; 351 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 352 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 353 | GCC_WARN_UNUSED_VARIABLE = YES; 354 | IPHONEOS_DEPLOYMENT_TARGET = 6.1; 355 | OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; 356 | SDKROOT = iphoneos; 357 | VALIDATE_PRODUCT = YES; 358 | }; 359 | name = Release; 360 | }; 361 | D78D3476177B202F002007AE /* Debug */ = { 362 | isa = XCBuildConfiguration; 363 | buildSettings = { 364 | CODE_SIGN_IDENTITY = "iPhone Developer: SHENGGANG TANG (929PMK8K46)"; 365 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer: SHENGGANG TANG (929PMK8K46)"; 366 | FRAMEWORK_SEARCH_PATHS = "$(inherited)"; 367 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 368 | GCC_PREFIX_HEADER = "LTBlacklist/LTBlacklist-Prefix.pch"; 369 | INFOPLIST_FILE = "LTBlacklist/LTBlacklist-Info.plist"; 370 | IPHONEOS_DEPLOYMENT_TARGET = 5.0; 371 | OTHER_LDFLAGS = ""; 372 | PRODUCT_NAME = "$(TARGET_NAME)"; 373 | PROVISIONING_PROFILE = "DA721D82-FEAC-4529-A8C7-37D8C95D0EB9"; 374 | "PROVISIONING_PROFILE[sdk=iphoneos*]" = "DA721D82-FEAC-4529-A8C7-37D8C95D0EB9"; 375 | WRAPPER_EXTENSION = app; 376 | }; 377 | name = Debug; 378 | }; 379 | D78D3477177B202F002007AE /* Release */ = { 380 | isa = XCBuildConfiguration; 381 | buildSettings = { 382 | FRAMEWORK_SEARCH_PATHS = "$(inherited)"; 383 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 384 | GCC_PREFIX_HEADER = "LTBlacklist/LTBlacklist-Prefix.pch"; 385 | INFOPLIST_FILE = "LTBlacklist/LTBlacklist-Info.plist"; 386 | IPHONEOS_DEPLOYMENT_TARGET = 5.0; 387 | PRODUCT_NAME = "$(TARGET_NAME)"; 388 | WRAPPER_EXTENSION = app; 389 | }; 390 | name = Release; 391 | }; 392 | /* End XCBuildConfiguration section */ 393 | 394 | /* Begin XCConfigurationList section */ 395 | D78D3453177B202F002007AE /* Build configuration list for PBXProject "LTBlacklist" */ = { 396 | isa = XCConfigurationList; 397 | buildConfigurations = ( 398 | D78D3473177B202F002007AE /* Debug */, 399 | D78D3474177B202F002007AE /* Release */, 400 | ); 401 | defaultConfigurationIsVisible = 0; 402 | defaultConfigurationName = Release; 403 | }; 404 | D78D3475177B202F002007AE /* Build configuration list for PBXNativeTarget "LTBlacklist" */ = { 405 | isa = XCConfigurationList; 406 | buildConfigurations = ( 407 | D78D3476177B202F002007AE /* Debug */, 408 | D78D3477177B202F002007AE /* Release */, 409 | ); 410 | defaultConfigurationIsVisible = 0; 411 | defaultConfigurationName = Release; 412 | }; 413 | /* End XCConfigurationList section */ 414 | }; 415 | rootObject = D78D3450177B202F002007AE /* Project object */; 416 | } 417 | -------------------------------------------------------------------------------- /LTBlacklist/Vendors/WCAlertView/WCAlertView.m: -------------------------------------------------------------------------------- 1 | // 2 | // WCAlertView.m 3 | // WCAlertView 4 | // 5 | // Created by Michał Zaborowski on 18/07/12. 6 | // Copyright (c) 2012 Michał Zaborowski. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | #import "WCAlertView.h" 27 | #import 28 | #import 29 | #import 30 | 31 | @interface WCAlertView () 32 | 33 | @end 34 | 35 | @implementation WCAlertView 36 | @synthesize buttonShadowColor = _buttonShadowColor; 37 | @synthesize buttonShadowOffset = _buttonShadowOffset; 38 | @synthesize buttonTextColor = _buttonTextColor; 39 | @synthesize verticalLineColor = _verticalLineColor; 40 | @synthesize innerFrameShadowColor = _innerFrameShadowColor; 41 | @synthesize hatchedLinesColor = _hatchedLinesColor; 42 | @synthesize outerFrameColor = _outerFrameColor; 43 | @synthesize hatchedBackgroundColor = _hatchedBackgroundColor; 44 | @synthesize style = _style; 45 | @synthesize buttonShadowBlur = _buttonShadowBlur; 46 | @synthesize buttonFont = _buttonFont; 47 | 48 | 49 | static WCAlertViewStyle kDefaultAlertStyle = WCAlertViewStyleDefault; 50 | static CustomizationBlock kDefauldCustomizationBlock = nil; 51 | 52 | + (void)setDefaultStyle:(WCAlertViewStyle)style 53 | { 54 | 55 | kDefaultAlertStyle = style; 56 | 57 | } 58 | 59 | + (void)setDefaultCustomiaztonBlock:(CustomizationBlock)block 60 | { 61 | kDefauldCustomizationBlock = block; 62 | } 63 | 64 | + (id)showAlertWithTitle:(NSString *)title message:(NSString *)message customizationBlock:(void (^)(WCAlertView *alertView))customization completionBlock:(void (^)(NSUInteger buttonIndex, WCAlertView *alertView))block cancelButtonTitle:(NSString *)cancelButtonTitle otherButtonTitles:(NSString *)otherButtonTitles, ... 65 | { 66 | 67 | WCAlertView *alertView = [[self alloc] initWithTitle:title message:message completionBlock:block cancelButtonTitle:cancelButtonTitle otherButtonTitles:nil]; 68 | 69 | NSInteger otherButtonCount = 0; 70 | 71 | // Fix Issue #14: Cancel and Ok buttons are switched 72 | // If Cancel button is added first and other button count is more than 1, 73 | // cancel and ok buttons are switched 74 | 75 | if (otherButtonTitles != nil) { 76 | id eachObject; 77 | va_list argumentList; 78 | if (otherButtonTitles) { 79 | otherButtonCount++; 80 | va_start(argumentList, otherButtonTitles); 81 | while ((eachObject = va_arg(argumentList, id))) { 82 | otherButtonCount++; 83 | } 84 | va_end(argumentList); 85 | } 86 | } 87 | 88 | if (otherButtonCount <= 1 && cancelButtonTitle) { 89 | [alertView addButtonWithTitle:cancelButtonTitle]; 90 | alertView.cancelButtonIndex = [alertView numberOfButtons] - 1; 91 | } 92 | 93 | if (otherButtonTitles != nil) { 94 | id eachObject; 95 | va_list argumentList; 96 | if (otherButtonTitles) { 97 | [alertView addButtonWithTitle:otherButtonTitles]; 98 | va_start(argumentList, otherButtonTitles); 99 | while ((eachObject = va_arg(argumentList, id))) { 100 | [alertView addButtonWithTitle:eachObject]; 101 | } 102 | va_end(argumentList); 103 | } 104 | } 105 | 106 | if (cancelButtonTitle && otherButtonCount > 1) { 107 | [alertView addButtonWithTitle:cancelButtonTitle]; 108 | alertView.cancelButtonIndex = [alertView numberOfButtons] - 1; 109 | } 110 | 111 | if (customization) { 112 | customization(alertView); 113 | } 114 | 115 | [alertView show]; 116 | 117 | return alertView; 118 | 119 | } 120 | 121 | - (id)initWithTitle:(NSString *)title message:(NSString *)message delegate:(id)delegate cancelButtonTitle:(NSString *)cancelButtonTitle otherButtonTitles:(NSString *)otherButtonTitles, ... 122 | { 123 | if (self = [super initWithTitle:title message:message delegate:delegate cancelButtonTitle:cancelButtonTitle otherButtonTitles:nil]) { 124 | 125 | [self defaultStyle]; 126 | 127 | if (kDefauldCustomizationBlock) { 128 | self.style = WCAlertViewStyleCustomizationBlock; 129 | } 130 | 131 | va_list args; 132 | va_start(args, otherButtonTitles); 133 | for (NSString *anOtherButtonTitle = otherButtonTitles; anOtherButtonTitle != nil; anOtherButtonTitle = va_arg(args, NSString*)) { 134 | [self addButtonWithTitle:anOtherButtonTitle]; 135 | } 136 | } 137 | return self; 138 | } 139 | 140 | 141 | - (id)initWithTitle:(NSString *)title message:(NSString *)message completionBlock:(void (^)(NSUInteger buttonIndex, WCAlertView *alertView))block cancelButtonTitle:(NSString *)cancelButtonTitle otherButtonTitles:(NSString *)otherButtonTitles, ... { 142 | objc_setAssociatedObject(self, "blockCallback", [block copy], OBJC_ASSOCIATION_RETAIN_NONATOMIC); 143 | 144 | if (self = [self initWithTitle:title message:message delegate:self cancelButtonTitle:nil otherButtonTitles:nil]) { 145 | 146 | id eachObject; 147 | va_list argumentList; 148 | if (otherButtonTitles) { 149 | [self addButtonWithTitle:otherButtonTitles]; 150 | va_start(argumentList, otherButtonTitles); 151 | while ((eachObject = va_arg(argumentList, id))) { 152 | [self addButtonWithTitle:eachObject]; 153 | } 154 | va_end(argumentList); 155 | } 156 | } 157 | return self; 158 | } 159 | 160 | - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex { 161 | void (^block)(NSUInteger buttonIndex, UIAlertView *alertView) = objc_getAssociatedObject(self, "blockCallback"); 162 | if (block) { 163 | block(buttonIndex, self); 164 | } 165 | 166 | } 167 | 168 | - (void)setStyle:(WCAlertViewStyle)style 169 | { 170 | if (style != _style) { 171 | _style = style; 172 | [self customizeAlertViewStyle:style]; 173 | } 174 | } 175 | 176 | - (void)defaultStyle 177 | { 178 | self.buttonShadowBlur = 2.0f; 179 | self.buttonShadowOffset = CGSizeMake(0.5f, 0.5f); 180 | self.labelShadowOffset = CGSizeMake(0.0f, 1.0f); 181 | self.gradientLocations = @[ @0.0f, @0.57f, @1.0f]; 182 | self.cornerRadius = 10.0f; 183 | self.labelTextColor = [UIColor whiteColor]; 184 | self.outerFrameLineWidth = 2.0f; 185 | self.outerFrameShadowBlur = 6.0f; 186 | self.outerFrameShadowColor = [UIColor colorWithRed:0.0f/255.0f green:0.0f/255.0f blue:0.0f/255.0f alpha:1.0f]; 187 | self.outerFrameShadowOffset = CGSizeMake(0.0f, 1.0f); 188 | self.style = kDefaultAlertStyle; 189 | 190 | } 191 | 192 | - (void)customizeAlertViewStyle:(WCAlertViewStyle)style 193 | { 194 | switch (style) { 195 | case WCAlertViewStyleDefault: 196 | break; 197 | case WCAlertViewStyleWhite: 198 | [self whiteAlertHatched:NO]; 199 | break; 200 | case WCAlertViewStyleWhiteHatched: 201 | [self whiteAlertHatched:YES]; 202 | break; 203 | case WCAlertViewStyleBlack: 204 | [self blackAlertHatched:NO]; 205 | break; 206 | case WCAlertViewStyleBlackHatched: 207 | [self blackAlertHatched:YES]; 208 | break; 209 | case WCAlertViewStyleViolet: 210 | [self violetAlertHetched:NO]; 211 | break; 212 | case WCAlertViewStyleVioletHatched: 213 | [self violetAlertHetched:YES]; 214 | break; 215 | case WCAlertViewStyleCustomizationBlock: 216 | if (kDefauldCustomizationBlock) { 217 | kDefauldCustomizationBlock(self); 218 | } 219 | break; 220 | default: 221 | self.style = kDefaultAlertStyle; 222 | break; 223 | } 224 | } 225 | 226 | - (void)violetAlertHetched:(BOOL)hatched 227 | { 228 | self.labelTextColor = [UIColor whiteColor]; 229 | self.labelShadowColor = [UIColor colorWithRed:0.004 green:0.003 blue:0.006 alpha:0.700]; 230 | 231 | UIColor *topGradient = [UIColor colorWithRed:0.66f green:0.63f blue:1.00f alpha:1.00f]; 232 | UIColor *middleGradient = [UIColor colorWithRed:0.508 green:0.498 blue:0.812 alpha:1.000]; 233 | UIColor *bottomGradient = [UIColor colorWithRed:0.419 green:0.405 blue:0.654 alpha:1.000]; 234 | self.gradientColors = @[topGradient,middleGradient,bottomGradient]; 235 | 236 | self.outerFrameColor = [UIColor whiteColor]; 237 | self.innerFrameStrokeColor = [UIColor colorWithRed:0.25f green:0.25f blue:0.41f alpha:1.00f]; 238 | self.innerFrameShadowColor = [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.2]; 239 | 240 | self.buttonTextColor = [UIColor whiteColor]; 241 | self.buttonShadowBlur = 2.0; 242 | self.buttonShadowColor = [UIColor colorWithRed:0.004 green:0.003 blue:0.006 alpha:1.000]; 243 | 244 | 245 | if (hatched) { 246 | self.outerFrameColor = [UIColor colorWithRed:0.25f green:0.25f blue:0.41f alpha:1.00f]; 247 | self.outerFrameShadowOffset = CGSizeMake(0.0, 0.0); 248 | self.outerFrameShadowBlur = 0.0; 249 | self.outerFrameShadowColor = [UIColor clearColor]; 250 | self.outerFrameLineWidth = 0.5f; 251 | self.verticalLineColor = [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.5]; 252 | self.hatchedLinesColor = [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.1]; 253 | } 254 | } 255 | 256 | - (void)whiteAlertHatched:(BOOL)hatched 257 | { 258 | self.labelTextColor = [UIColor colorWithRed:0.11f green:0.08f blue:0.39f alpha:1.00f]; 259 | self.labelShadowColor = [UIColor whiteColor]; 260 | 261 | UIColor *topGradient = [UIColor colorWithRed:1.0f green:1.0f blue:1.0f alpha:1.0f]; 262 | UIColor *middleGradient = [UIColor colorWithRed:0.93f green:0.94f blue:0.96f alpha:1.0f]; 263 | UIColor *bottomGradient = [UIColor colorWithRed:0.89f green:0.89f blue:0.92f alpha:1.00f]; 264 | self.gradientColors = @[topGradient,middleGradient,bottomGradient]; 265 | 266 | self.outerFrameColor = [UIColor colorWithRed:250.0f/255.0f green:250.0f/255.0f blue:250.0f/255.0f alpha:1.0f]; 267 | 268 | self.buttonTextColor = [UIColor colorWithRed:0.11f green:0.08f blue:0.39f alpha:1.00f]; 269 | self.buttonShadowColor = [UIColor whiteColor]; 270 | 271 | if (hatched) { 272 | self.verticalLineColor = [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.1]; 273 | self.hatchedLinesColor = [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.1]; 274 | } 275 | } 276 | 277 | - (void)blackAlertHatched:(BOOL)hatched 278 | { 279 | self.labelTextColor = [UIColor colorWithRed:210.0f/255.0f green:210.0f/255.0f blue:210.0f/255.0f alpha:1.0f]; 280 | self.labelShadowColor = [UIColor blackColor]; 281 | self.labelShadowOffset = CGSizeMake(0.0f, 1.0f); 282 | 283 | UIColor *topGradient = [UIColor colorWithRed:0.27f green:0.27f blue:0.27f alpha:1.0f]; 284 | UIColor *middleGradient = [UIColor colorWithRed:0.21f green:0.21f blue:0.21f alpha:1.0f]; 285 | UIColor *bottomGradient = [UIColor colorWithRed:0.15f green:0.15f blue:0.15f alpha:1.00f]; 286 | self.gradientColors = @[topGradient,middleGradient,bottomGradient]; 287 | 288 | self.outerFrameColor = [UIColor colorWithRed:210.0f/255.0f green:210.0f/255.0f blue:210.0f/255.0f alpha:1.0f]; 289 | 290 | self.buttonTextColor = [UIColor colorWithRed:210.0f/255.0f green:210.0f/255.0f blue:210.0f/255.0f alpha:1.0f]; 291 | self.buttonShadowColor = [UIColor blackColor]; 292 | 293 | if (hatched) { 294 | self.verticalLineColor = [UIColor blackColor]; 295 | self.innerFrameShadowColor = [UIColor blackColor]; 296 | self.hatchedLinesColor = [UIColor blackColor]; 297 | } 298 | 299 | } 300 | 301 | #pragma mark - 302 | #pragma mark UIView Overrides 303 | - (void)layoutSubviews 304 | { 305 | [super layoutSubviews]; 306 | 307 | if (self.style) { 308 | for (UIView *subview in self.subviews){ 309 | 310 | //Find and hide UIImageView Containing Blue Background 311 | if ([subview isMemberOfClass:[UIImageView class]]) { 312 | 313 | CGRect rect = [subview frame]; 314 | 315 | // Find and hide only background image view 316 | // It prevent hiding UITextFiled for UIAlertViewStyleLoginAndPasswordInput 317 | 318 | if (rect.origin.x == 0 || rect.origin.y == 0) { 319 | subview.hidden = YES; 320 | } 321 | 322 | } 323 | 324 | //Find and get styles of UILabels 325 | if ([subview isMemberOfClass:[UILabel class]]) { 326 | UILabel *label = (UILabel*)subview; 327 | label.textColor = self.labelTextColor; 328 | label.shadowColor = self.labelShadowColor; 329 | label.shadowOffset = self.labelShadowOffset; 330 | 331 | if ( self.titleFont 332 | && [label.text isEqualToString:self.title]) { 333 | label.font = self.titleFont; 334 | } 335 | 336 | if (self.messageFont 337 | && [label.text isEqualToString:self.message]) { 338 | label.font = self.messageFont; 339 | } 340 | } 341 | 342 | // Hide button title labels 343 | if ([subview isKindOfClass:[UIButton class]]) { 344 | UIButton *button = (UIButton *)subview; 345 | button.titleLabel.alpha = 0; 346 | } 347 | } 348 | } 349 | 350 | } 351 | 352 | - (void)drawRect:(CGRect)rect 353 | { 354 | [super drawRect:rect]; 355 | 356 | if (self.style) { 357 | 358 | /* 359 | * Current graphics context 360 | */ 361 | 362 | CGContextRef context = UIGraphicsGetCurrentContext(); 363 | 364 | /* 365 | * Create base shape with rounded corners from bounds 366 | */ 367 | 368 | CGRect activeBounds = self.bounds; 369 | CGFloat cornerRadius = self.cornerRadius; 370 | CGFloat inset = 5.5f; 371 | CGFloat originX = activeBounds.origin.x + inset; 372 | CGFloat originY = activeBounds.origin.y + inset; 373 | CGFloat width = activeBounds.size.width - (inset*2.0f); 374 | CGFloat height = activeBounds.size.height - ((inset+2.0)*2.0f); 375 | 376 | CGFloat buttonOffset = self.bounds.size.height - 50.5f; 377 | 378 | CGRect bPathFrame = CGRectMake(originX, originY, width, height); 379 | CGPathRef path = [UIBezierPath bezierPathWithRoundedRect:bPathFrame cornerRadius:cornerRadius].CGPath; 380 | 381 | /* 382 | * Create base shape with fill and shadow 383 | */ 384 | 385 | CGContextAddPath(context, path); 386 | CGContextSetFillColorWithColor(context, [UIColor colorWithRed:210.0f/255.0f green:210.0f/255.0f blue:210.0f/255.0f alpha:1.0f].CGColor); 387 | CGContextSetShadowWithColor(context, self.outerFrameShadowOffset, self.outerFrameShadowBlur, self.outerFrameShadowColor.CGColor); 388 | CGContextDrawPath(context, kCGPathFill); 389 | 390 | /* 391 | * Clip state 392 | */ 393 | 394 | CGContextSaveGState(context); //Save Context State Before Clipping To "path" 395 | CGContextAddPath(context, path); 396 | CGContextClip(context); 397 | 398 | //////////////DRAW GRADIENT 399 | /* 400 | * Draw grafient from gradientLocations 401 | */ 402 | 403 | CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 404 | size_t count = [self.gradientLocations count]; 405 | 406 | CGFloat *locations = malloc(count * sizeof(CGFloat)); 407 | [self.gradientLocations enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { 408 | locations[idx] = [((NSNumber *)obj) floatValue]; 409 | }]; 410 | 411 | CGFloat *components = malloc([self.gradientColors count] * 4 * sizeof(CGFloat)); 412 | 413 | [self.gradientColors enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { 414 | UIColor *color = (UIColor *)obj; 415 | 416 | NSInteger startIndex = (idx * 4); 417 | 418 | if ([color respondsToSelector:@selector(getRed:green:blue:alpha:)]) { 419 | [color getRed:&components[startIndex] 420 | green:&components[startIndex+1] 421 | blue:&components[startIndex+2] 422 | alpha:&components[startIndex+3]]; 423 | } else { 424 | const CGFloat *colorComponent = CGColorGetComponents(color.CGColor); 425 | 426 | components[startIndex] = colorComponent[0]; 427 | components[startIndex+1] = colorComponent[1]; 428 | components[startIndex+2] = colorComponent[2]; 429 | components[startIndex+3] = colorComponent[3]; 430 | } 431 | }]; 432 | 433 | CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, components, locations, count); 434 | 435 | CGPoint startPoint = CGPointMake(activeBounds.size.width * 0.5f, 0.0f); 436 | CGPoint endPoint = CGPointMake(activeBounds.size.width * 0.5f, activeBounds.size.height); 437 | 438 | CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0); 439 | CGColorSpaceRelease(colorSpace); 440 | CGGradientRelease(gradient); 441 | free(locations); 442 | free(components); 443 | 444 | /* 445 | * Hatched background 446 | */ 447 | 448 | if (self.hatchedLinesColor || self.hatchedBackgroundColor) { 449 | CGContextSaveGState(context); //Save Context State Before Clipping "hatchPath" 450 | CGRect hatchFrame = CGRectMake(0.0f, buttonOffset-15, activeBounds.size.width, (activeBounds.size.height - buttonOffset+1.0f)+15); 451 | CGContextClipToRect(context, hatchFrame); 452 | 453 | if (self.hatchedBackgroundColor) { 454 | CGFloat red,green,blue,alpha; 455 | 456 | if ([self.hatchedBackgroundColor respondsToSelector:@selector(getRed:green:blue:alpha:)]) { 457 | [self.hatchedBackgroundColor getRed:&red green:&green blue:&blue alpha:&alpha]; 458 | } else { 459 | const CGFloat *colorComponent = CGColorGetComponents(self.hatchedBackgroundColor.CGColor); 460 | 461 | red = colorComponent[0]; 462 | green = colorComponent[1]; 463 | blue = colorComponent[2]; 464 | alpha = colorComponent[3]; 465 | } 466 | 467 | CGContextSetRGBFillColor(context, red,green, blue, alpha); 468 | CGContextFillRect(context, hatchFrame); 469 | } 470 | 471 | if (self.hatchedLinesColor) { 472 | CGFloat spacer = 4.0f; 473 | int rows = (activeBounds.size.width + activeBounds.size.height/spacer); 474 | CGFloat padding = 0.0f; 475 | CGMutablePathRef hatchPath = CGPathCreateMutable(); 476 | for(int i=1; i<=rows; i++) { 477 | CGPathMoveToPoint(hatchPath, NULL, spacer * i, padding); 478 | CGPathAddLineToPoint(hatchPath, NULL, padding, spacer * i); 479 | } 480 | CGContextAddPath(context, hatchPath); 481 | CGPathRelease(hatchPath); 482 | CGContextSetLineWidth(context, 1.0f); 483 | CGContextSetLineCap(context, kCGLineCapButt); 484 | CGContextSetStrokeColorWithColor(context, self.hatchedLinesColor.CGColor); 485 | CGContextDrawPath(context, kCGPathStroke); 486 | } 487 | 488 | CGContextRestoreGState(context); //Restore Last Context State Before Clipping "hatchPath" 489 | } 490 | 491 | /* 492 | * Draw vertical line 493 | */ 494 | 495 | if (self.verticalLineColor) { 496 | CGMutablePathRef linePath = CGPathCreateMutable(); 497 | CGFloat linePathY = (buttonOffset - 1.0f) - 15; 498 | CGPathMoveToPoint(linePath, NULL, 0.0f, linePathY); 499 | CGPathAddLineToPoint(linePath, NULL, activeBounds.size.width, linePathY); 500 | CGContextAddPath(context, linePath); 501 | CGPathRelease(linePath); 502 | CGContextSetLineWidth(context, 1.0f); 503 | CGContextSaveGState(context); //Save Context State Before Drawing "linePath" Shadow 504 | CGContextSetStrokeColorWithColor(context, self.verticalLineColor.CGColor); 505 | CGContextSetShadowWithColor(context, CGSizeMake(0.0f, 1.0f), 0.0f, [UIColor colorWithRed:255.0f/255.0f green:255.0f/255.0f blue:255.0f/255.0f alpha:0.2f].CGColor); 506 | CGContextDrawPath(context, kCGPathStroke); 507 | CGContextRestoreGState(context); //Restore Context State After Drawing "linePath" Shadow 508 | } 509 | 510 | /* 511 | * Stroke color for inner path 512 | */ 513 | 514 | if (self.innerFrameShadowColor || self.innerFrameStrokeColor) { 515 | CGContextAddPath(context, path); 516 | CGContextSetLineWidth(context, 3.0f); 517 | 518 | if (self.innerFrameStrokeColor) { 519 | CGContextSetStrokeColorWithColor(context, self.innerFrameStrokeColor.CGColor); 520 | } 521 | if (self.innerFrameShadowColor) { 522 | CGContextSetShadowWithColor(context, CGSizeMake(0.0f, 0.0f), 6.0f, self.innerFrameShadowColor.CGColor); 523 | } 524 | 525 | CGContextDrawPath(context, kCGPathStroke); 526 | } 527 | 528 | /* 529 | * Stroke path to cover up pixialation on corners from clipping 530 | */ 531 | 532 | CGContextRestoreGState(context); //Restore First Context State Before Clipping "path" 533 | CGContextAddPath(context, path); 534 | CGContextSetLineWidth(context, self.outerFrameLineWidth); 535 | CGContextSetStrokeColorWithColor(context, self.outerFrameColor.CGColor); 536 | CGContextSetShadowWithColor(context, CGSizeMake(0.0f, 0.0f), 0.0f, [UIColor colorWithRed:0.0f/255.0f green:0.0f/255.0f blue:0.0f/255.0f alpha:0.1f].CGColor); 537 | CGContextDrawPath(context, kCGPathStroke); 538 | 539 | /* 540 | * Drawing button labels 541 | */ 542 | 543 | for (UIView *subview in self.subviews){ 544 | 545 | if ([subview isKindOfClass:[UIButton class]]) 546 | { 547 | UIButton *button = (UIButton *)subview; 548 | 549 | CGContextSetTextDrawingMode(context, kCGTextFill); 550 | CGContextSetFillColorWithColor(context, self.buttonTextColor.CGColor); 551 | CGContextSetShadowWithColor(context, self.buttonShadowOffset, self.buttonShadowBlur, self.buttonShadowColor.CGColor); 552 | 553 | UIFont *buttonFont = button.titleLabel.font; 554 | 555 | if (self.buttonFont) 556 | buttonFont = self.buttonFont; 557 | 558 | // Calculate the font size to make sure large text is rendered correctly 559 | CGFloat neededFontSize; 560 | [button.titleLabel.text sizeWithFont:buttonFont minFontSize:8.0 actualFontSize:&neededFontSize forWidth:button.frame.size.width-6 lineBreakMode:NSLineBreakByWordWrapping]; 561 | if (neededFontSize < buttonFont.pointSize){ 562 | buttonFont = [UIFont fontWithName:buttonFont.fontName size:neededFontSize]; 563 | } 564 | 565 | 566 | #if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_6_0 567 | 568 | [button.titleLabel.text drawInRect:CGRectMake(button.frame.origin.x, button.frame.origin.y+10, button.frame.size.width, button.frame.size.height-10) withFont:buttonFont lineBreakMode:NSLineBreakByWordWrapping alignment:NSTextAlignmentCenter]; 569 | #else 570 | [button.titleLabel.text drawInRect:CGRectMake(button.frame.origin.x, button.frame.origin.y+10, button.frame.size.width, button.frame.size.height-10) withFont:buttonFont lineBreakMode:NSLineBreakByTruncatingMiddle alignment:UITextAlignmentCenter]; 571 | 572 | #endif 573 | 574 | } 575 | 576 | } 577 | } 578 | 579 | } 580 | 581 | @end 582 | 583 | --------------------------------------------------------------------------------