├── 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 | 
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 |
--------------------------------------------------------------------------------