├── .gitignore ├── .idea └── codeStyleSettings.xml ├── LICENSE ├── Podfile ├── README.md ├── RKNotificationHub.podspec ├── RKNotificationHub.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ └── RKNotificationHub.xccheckout │ └── xcuserdata │ │ └── cwrichardkim93.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcuserdata │ └── cwrichardkim93.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ ├── RKNotificationHub.xcscheme │ └── xcschememanagement.plist ├── RKNotificationHub ├── AppDelegate.h ├── AppDelegate.m ├── Base.lproj │ ├── LaunchScreen.xib │ └── Main.storyboard ├── Images.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ ├── LaunchImage.launchimage │ │ └── Contents.json │ └── earth.imageset │ │ ├── Contents.json │ │ ├── earth-1-1.png │ │ ├── earth-1.png │ │ └── earth.png ├── Info.plist ├── RKNotificationHub.h ├── RKNotificationHub.m ├── ViewController.h ├── ViewController.m └── main.m └── RKNotificationHubTests ├── Info.plist └── RKNotificationHubTests.m /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .DS_Store 3 | -------------------------------------------------------------------------------- /.idea/codeStyleSettings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 36 | 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Choong-Won Richard Kim 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | # platform :ios, '6.0' 3 | 4 | target 'RKNotificationHub' do 5 | 6 | end 7 | 8 | target 'RKNotificationHubTests' do 9 | 10 | end 11 | 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | RKNotificationHub 2 | ================= 3 | 4 | A way to quickly add a notification icon to a UIView (iOS6 and up). [Support](http://cwrichardkim.com) 5 | 6 | ![demo](http://i.imgur.com/SpE2BQv.gif) 7 | 8 | Code: 9 | ``` objc 10 | RKNotificationHub* hub = [[RKNotificationHub alloc]initWithView:yourView]; // sets the count to 0 11 | [hub increment]; // increments the count to 1, making the notification visible 12 | ``` 13 | 14 | ### Pod 15 | ``` 16 | pod 'RKNotificationHub' 17 | ``` 18 | 19 | ### USAGE 20 | ![increment](http://i.imgur.com/zpgkNtE.gif) 21 | ``` objc 22 | [hub increment]; 23 | ``` 24 | ``` objc 25 | -(void)increment; 26 | -(void)incrementBy:(int)amount; 27 | -(void)decrement; 28 | -(void)decrementBy:(int)amount; 29 | @property (nonatomic, assign) int count; //%%% set to a certain number 30 | ``` 31 | 32 | __Combine Actions!__ 33 | 34 | ![blink](http://i.imgur.com/boGyL9T.gif) 35 | ``` objc 36 | [hub increment]; 37 | [hub pop]; 38 | ``` 39 | 40 | ### CUSTOMIZE 41 | ![blink](http://i.imgur.com/Ftbrh87.gif) 42 | ``` objc 43 | //%%% COLOR 44 | [hub setCircleColor:[UIColor colorWithRed:0.98 green:0.66 blue:0.2 alpha:1] 45 | labelColor:[UIColor whiteColor]]; 46 | ``` 47 | 48 | ![frame](http://i.imgur.com/6w9WaO4.png?1) 49 | ```objc 50 | //%%% CIRCLE FRAME 51 | [hub setCircleAtFrame:CGRectMake(-10, -10, 30, 30)]; //frame relative to the view you set it to 52 | 53 | //%%% MOVE FRAME 54 | [hub moveCircleByX:-5 Y:5]; // moves the circle 5 pixels left and down from its current position 55 | 56 | //%%% CIRCLE SIZE 57 | [hub scaleCircleSizeBy:2]; // doubles the size of the circle, keeps the same center 58 | ``` 59 | 60 | ![blank](http://i.imgur.com/rhiKOPH.png) 61 | ``` objc 62 | //%%% BLANK BADGE 63 | [hub hideCount]; 64 | /* shoutout to imkevinxu for this suggestion */ 65 | ``` 66 | 67 | 68 | ### TROUBLESHOOTING 69 | **Notification isn't showing up!** 70 | * If the hub value is < 1, the circle hides. Try calling `[increment]` 71 | * Make sure the view you set the hub to is visible (i.e. did you call `[self.view addSubview: yourView]`?) 72 | * Make sure you didn't call `[hideCount]` anywhere. Call `[showCount]` to counter this 73 | 74 | **It isn't incrementing / decrementing properly!** 75 | * I've written it so that any count < 1 doesn't show up. If you need help customizing this, reach out to me 76 | 77 | **The circle is in a weird place** 78 | * If you want to resize the circle, use `[scaleCircleSizeBy:]`. 0.5 will give you half the size, 2 will give you double 79 | * If the circle is just a few pixels off, use `[moveCircleByX: Y:]`. This shifts the circle by the number of pixels given 80 | * If you want to manually set the circle, call `[setCircleAtFrame:]` and give it your own CGRect 81 | 82 | **Something else isn't working properly** 83 | * Send me a tweet @cwRichardKim with #RKNotificationHub so that other people can search these issues too 84 | * Use github's issue reporter on the right 85 | * Send me an email cwRichardKim@gmail.com (might take a few days) 86 | 87 | 88 | ### Updates 89 | * 1.0.0 first release with cocoapod 90 | * 1.0.1 cocoapod allows iOS 7.0 91 | * 1.0.2 added "hideCount", "showCount", and "count" methods, allowing indeterminate badges with no number 92 | * 1.0.5 added bubble expansion for larger numbers [(gif)](http://i.imgur.com/cpQuShT.gif) 93 | * 2.0.0 changed count to `NSUInteger` (removed support for negative counts), made local constants `static const` 94 | * 2.0.1 iOS 6 compatability 95 | * 2.0.2 changed count back to 'int' for better swift compatability 96 | * 2.0.4 fixed cocoapod update issue 97 | 98 | ### Areas for Improvements / involvement 99 | * A mechanism for adding a custom animation 100 | * Singleton option 101 | -------------------------------------------------------------------------------- /RKNotificationHub.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | 3 | # ――― Spec Metadata ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 4 | # 5 | # These will help people to find your library, and whilst it 6 | # can feel like a chore to fill in it's definitely to your advantage. The 7 | # summary should be tweet-length, and the description more in depth. 8 | # 9 | 10 | s.name = "RKNotificationHub" 11 | s.version = "2.0.5" 12 | s.summary = "iOS: Make any UIView a full fledged notification center" 13 | 14 | s.description = "A simple one line solution to turning adding a notification bubble to any UIView. Easily increment, decrement, an animate the notification, -Notification, -Notification Center, -objectivec, -ios, -iphone, -xcode" 15 | 16 | s.homepage = "https://github.com/cwRichardKim/RKNotificationHub" 17 | s.screenshots = "http://i.imgur.com/OlYystx.gif" 18 | 19 | 20 | # ――― Spec License ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 21 | # 22 | # Licensing your code is important. See http://choosealicense.com for more info. 23 | # CocoaPods will detect a license file if there is a named LICENSE* 24 | # Popular ones are 'MIT', 'BSD' and 'Apache License, Version 2.0'. 25 | # 26 | 27 | # s.license = "MIT (example)" 28 | s.license = { :type => "MIT", :file => "LICENSE" } 29 | 30 | 31 | # ――― Author Metadata ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 32 | # 33 | # Specify the authors of the library, with email addresses. Email addresses 34 | # of the authors are extracted from the SCM log. E.g. $ git log. CocoaPods also 35 | # accepts just a name if you'd rather not provide an email address. 36 | # 37 | # Specify a social_media_url where others can refer to, for example a twitter 38 | # profile URL. 39 | # 40 | 41 | s.author = "cwrichardkim" 42 | # s.authors = { "cwrichardkim93" => "cwrichardkim93@gmail.com" } 43 | s.social_media_url = "http://twitter.com/cwrichardkim" 44 | 45 | # ――― Platform Specifics ――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 46 | # 47 | # If this Pod runs only on iOS or OS X, then specify the platform and 48 | # the deployment target. You can optionally include the target after the platform. 49 | # 50 | 51 | # s.platform = :ios 52 | s.platform = :ios, "6.0" 53 | 54 | # When using multiple platforms 55 | # s.ios.deployment_target = "5.0" 56 | # s.osx.deployment_target = "10.7" 57 | 58 | 59 | # ――― Source Location ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 60 | # 61 | # Specify the location from where the source should be retrieved. 62 | # Supports git, hg, bzr, svn and HTTP. 63 | # 64 | 65 | s.source = { :git => "https://github.com/cwRichardKim/RKNotificationHub.git", :tag => s.version.to_s } 66 | 67 | 68 | # ――― Source Code ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 69 | # 70 | # CocoaPods is smart about how it includes source code. For source files 71 | # giving a folder will include any h, m, mm, c & cpp files. For header 72 | # files it will include any header in the folder. 73 | # Not including the public_header_files will make all headers public. 74 | # 75 | 76 | s.source_files = 'RKNotificationHub/RKNotificationHub.h', 'RKNotificationHub/RKNotificationHub.m' 77 | 78 | # s.public_header_files = "Classes/**/*.h" 79 | 80 | 81 | # ――― Resources ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 82 | # 83 | # A list of resources included with the Pod. These are copied into the 84 | # target bundle with a build phase script. Anything else will be cleaned. 85 | # You can preserve files from being cleaned, please don't preserve 86 | # non-essential files like tests, examples and documentation. 87 | # 88 | 89 | # s.resource = "icon.png" 90 | # s.resources = "Resources/*.png" 91 | 92 | 93 | # ――― Project Linking ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 94 | # 95 | # Link your library with frameworks, or libraries. Libraries do not include 96 | # the lib prefix of their name. 97 | # 98 | 99 | # s.framework = "SomeFramework" 100 | # s.frameworks = "SomeFramework", "AnotherFramework" 101 | 102 | # s.library = "iconv" 103 | # s.libraries = "iconv", "xml2" 104 | 105 | 106 | # ――― Project Settings ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 107 | # 108 | # If your library depends on compiler flags you can set them in the xcconfig hash 109 | # where they will only apply to your library. If you depend on other Podspecs 110 | # you can include multiple dependencies to ensure it works. 111 | 112 | s.requires_arc = true 113 | 114 | # s.xcconfig = { "HEADER_SEARCH_PATHS" => "$(SDKROOT)/usr/include/libxml2" } 115 | # s.dependency "JSONKit", "~> 1.4" 116 | 117 | end 118 | -------------------------------------------------------------------------------- /RKNotificationHub.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 998DB1B519DAEA72006655C8 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 998DB1B419DAEA72006655C8 /* main.m */; }; 11 | 998DB1B819DAEA72006655C8 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 998DB1B719DAEA72006655C8 /* AppDelegate.m */; }; 12 | 998DB1BB19DAEA72006655C8 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 998DB1BA19DAEA72006655C8 /* ViewController.m */; }; 13 | 998DB1BE19DAEA72006655C8 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 998DB1BC19DAEA72006655C8 /* Main.storyboard */; }; 14 | 998DB1C019DAEA72006655C8 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 998DB1BF19DAEA72006655C8 /* Images.xcassets */; }; 15 | 998DB1C319DAEA72006655C8 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 998DB1C119DAEA72006655C8 /* LaunchScreen.xib */; }; 16 | 998DB1CF19DAEA72006655C8 /* RKNotificationHubTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 998DB1CE19DAEA72006655C8 /* RKNotificationHubTests.m */; }; 17 | 998DB1DA19DAEE12006655C8 /* RKNotificationHub.m in Sources */ = {isa = PBXBuildFile; fileRef = 998DB1D919DAEE12006655C8 /* RKNotificationHub.m */; }; 18 | 998DB1E219DAFE9D006655C8 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 998DB1E119DAFE9D006655C8 /* QuartzCore.framework */; }; 19 | /* End PBXBuildFile section */ 20 | 21 | /* Begin PBXContainerItemProxy section */ 22 | 998DB1C919DAEA72006655C8 /* PBXContainerItemProxy */ = { 23 | isa = PBXContainerItemProxy; 24 | containerPortal = 998DB1A719DAEA72006655C8 /* Project object */; 25 | proxyType = 1; 26 | remoteGlobalIDString = 998DB1AE19DAEA72006655C8; 27 | remoteInfo = RKNotificationHub; 28 | }; 29 | /* End PBXContainerItemProxy section */ 30 | 31 | /* Begin PBXFileReference section */ 32 | 998DB1AF19DAEA72006655C8 /* RKNotificationHub.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RKNotificationHub.app; sourceTree = BUILT_PRODUCTS_DIR; }; 33 | 998DB1B319DAEA72006655C8 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 34 | 998DB1B419DAEA72006655C8 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 35 | 998DB1B619DAEA72006655C8 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 36 | 998DB1B719DAEA72006655C8 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 37 | 998DB1B919DAEA72006655C8 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 38 | 998DB1BA19DAEA72006655C8 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 39 | 998DB1BD19DAEA72006655C8 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 40 | 998DB1BF19DAEA72006655C8 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 41 | 998DB1C219DAEA72006655C8 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; 42 | 998DB1C819DAEA72006655C8 /* RKNotificationHubTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RKNotificationHubTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 43 | 998DB1CD19DAEA72006655C8 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 44 | 998DB1CE19DAEA72006655C8 /* RKNotificationHubTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RKNotificationHubTests.m; sourceTree = ""; }; 45 | 998DB1D819DAEE12006655C8 /* RKNotificationHub.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RKNotificationHub.h; sourceTree = ""; }; 46 | 998DB1D919DAEE12006655C8 /* RKNotificationHub.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKNotificationHub.m; sourceTree = ""; }; 47 | 998DB1E119DAFE9D006655C8 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; 48 | /* End PBXFileReference section */ 49 | 50 | /* Begin PBXFrameworksBuildPhase section */ 51 | 998DB1AC19DAEA72006655C8 /* Frameworks */ = { 52 | isa = PBXFrameworksBuildPhase; 53 | buildActionMask = 2147483647; 54 | files = ( 55 | 998DB1E219DAFE9D006655C8 /* QuartzCore.framework in Frameworks */, 56 | ); 57 | runOnlyForDeploymentPostprocessing = 0; 58 | }; 59 | 998DB1C519DAEA72006655C8 /* Frameworks */ = { 60 | isa = PBXFrameworksBuildPhase; 61 | buildActionMask = 2147483647; 62 | files = ( 63 | ); 64 | runOnlyForDeploymentPostprocessing = 0; 65 | }; 66 | /* End PBXFrameworksBuildPhase section */ 67 | 68 | /* Begin PBXGroup section */ 69 | 998DB1A619DAEA72006655C8 = { 70 | isa = PBXGroup; 71 | children = ( 72 | 998DB1E119DAFE9D006655C8 /* QuartzCore.framework */, 73 | 998DB1B119DAEA72006655C8 /* RKNotificationHub */, 74 | 998DB1CB19DAEA72006655C8 /* RKNotificationHubTests */, 75 | 998DB1B019DAEA72006655C8 /* Products */, 76 | ); 77 | sourceTree = ""; 78 | }; 79 | 998DB1B019DAEA72006655C8 /* Products */ = { 80 | isa = PBXGroup; 81 | children = ( 82 | 998DB1AF19DAEA72006655C8 /* RKNotificationHub.app */, 83 | 998DB1C819DAEA72006655C8 /* RKNotificationHubTests.xctest */, 84 | ); 85 | name = Products; 86 | sourceTree = ""; 87 | }; 88 | 998DB1B119DAEA72006655C8 /* RKNotificationHub */ = { 89 | isa = PBXGroup; 90 | children = ( 91 | 998DB1B619DAEA72006655C8 /* AppDelegate.h */, 92 | 998DB1B719DAEA72006655C8 /* AppDelegate.m */, 93 | 998DB1B919DAEA72006655C8 /* ViewController.h */, 94 | 998DB1BA19DAEA72006655C8 /* ViewController.m */, 95 | 998DB1D819DAEE12006655C8 /* RKNotificationHub.h */, 96 | 998DB1D919DAEE12006655C8 /* RKNotificationHub.m */, 97 | 998DB1BC19DAEA72006655C8 /* Main.storyboard */, 98 | 998DB1BF19DAEA72006655C8 /* Images.xcassets */, 99 | 998DB1C119DAEA72006655C8 /* LaunchScreen.xib */, 100 | 998DB1B219DAEA72006655C8 /* Supporting Files */, 101 | ); 102 | path = RKNotificationHub; 103 | sourceTree = ""; 104 | }; 105 | 998DB1B219DAEA72006655C8 /* Supporting Files */ = { 106 | isa = PBXGroup; 107 | children = ( 108 | 998DB1B319DAEA72006655C8 /* Info.plist */, 109 | 998DB1B419DAEA72006655C8 /* main.m */, 110 | ); 111 | name = "Supporting Files"; 112 | sourceTree = ""; 113 | }; 114 | 998DB1CB19DAEA72006655C8 /* RKNotificationHubTests */ = { 115 | isa = PBXGroup; 116 | children = ( 117 | 998DB1CE19DAEA72006655C8 /* RKNotificationHubTests.m */, 118 | 998DB1CC19DAEA72006655C8 /* Supporting Files */, 119 | ); 120 | path = RKNotificationHubTests; 121 | sourceTree = ""; 122 | }; 123 | 998DB1CC19DAEA72006655C8 /* Supporting Files */ = { 124 | isa = PBXGroup; 125 | children = ( 126 | 998DB1CD19DAEA72006655C8 /* Info.plist */, 127 | ); 128 | name = "Supporting Files"; 129 | sourceTree = ""; 130 | }; 131 | /* End PBXGroup section */ 132 | 133 | /* Begin PBXNativeTarget section */ 134 | 998DB1AE19DAEA72006655C8 /* RKNotificationHub */ = { 135 | isa = PBXNativeTarget; 136 | buildConfigurationList = 998DB1D219DAEA72006655C8 /* Build configuration list for PBXNativeTarget "RKNotificationHub" */; 137 | buildPhases = ( 138 | 998DB1AB19DAEA72006655C8 /* Sources */, 139 | 998DB1AC19DAEA72006655C8 /* Frameworks */, 140 | 998DB1AD19DAEA72006655C8 /* Resources */, 141 | ); 142 | buildRules = ( 143 | ); 144 | dependencies = ( 145 | ); 146 | name = RKNotificationHub; 147 | productName = RKNotificationHub; 148 | productReference = 998DB1AF19DAEA72006655C8 /* RKNotificationHub.app */; 149 | productType = "com.apple.product-type.application"; 150 | }; 151 | 998DB1C719DAEA72006655C8 /* RKNotificationHubTests */ = { 152 | isa = PBXNativeTarget; 153 | buildConfigurationList = 998DB1D519DAEA72006655C8 /* Build configuration list for PBXNativeTarget "RKNotificationHubTests" */; 154 | buildPhases = ( 155 | 998DB1C419DAEA72006655C8 /* Sources */, 156 | 998DB1C519DAEA72006655C8 /* Frameworks */, 157 | 998DB1C619DAEA72006655C8 /* Resources */, 158 | ); 159 | buildRules = ( 160 | ); 161 | dependencies = ( 162 | 998DB1CA19DAEA72006655C8 /* PBXTargetDependency */, 163 | ); 164 | name = RKNotificationHubTests; 165 | productName = RKNotificationHubTests; 166 | productReference = 998DB1C819DAEA72006655C8 /* RKNotificationHubTests.xctest */; 167 | productType = "com.apple.product-type.bundle.unit-test"; 168 | }; 169 | /* End PBXNativeTarget section */ 170 | 171 | /* Begin PBXProject section */ 172 | 998DB1A719DAEA72006655C8 /* Project object */ = { 173 | isa = PBXProject; 174 | attributes = { 175 | LastUpgradeCheck = 0600; 176 | ORGANIZATIONNAME = "Richard Kim"; 177 | TargetAttributes = { 178 | 998DB1AE19DAEA72006655C8 = { 179 | CreatedOnToolsVersion = 6.0; 180 | }; 181 | 998DB1C719DAEA72006655C8 = { 182 | CreatedOnToolsVersion = 6.0; 183 | TestTargetID = 998DB1AE19DAEA72006655C8; 184 | }; 185 | }; 186 | }; 187 | buildConfigurationList = 998DB1AA19DAEA72006655C8 /* Build configuration list for PBXProject "RKNotificationHub" */; 188 | compatibilityVersion = "Xcode 3.2"; 189 | developmentRegion = English; 190 | hasScannedForEncodings = 0; 191 | knownRegions = ( 192 | en, 193 | Base, 194 | ); 195 | mainGroup = 998DB1A619DAEA72006655C8; 196 | productRefGroup = 998DB1B019DAEA72006655C8 /* Products */; 197 | projectDirPath = ""; 198 | projectRoot = ""; 199 | targets = ( 200 | 998DB1AE19DAEA72006655C8 /* RKNotificationHub */, 201 | 998DB1C719DAEA72006655C8 /* RKNotificationHubTests */, 202 | ); 203 | }; 204 | /* End PBXProject section */ 205 | 206 | /* Begin PBXResourcesBuildPhase section */ 207 | 998DB1AD19DAEA72006655C8 /* Resources */ = { 208 | isa = PBXResourcesBuildPhase; 209 | buildActionMask = 2147483647; 210 | files = ( 211 | 998DB1BE19DAEA72006655C8 /* Main.storyboard in Resources */, 212 | 998DB1C319DAEA72006655C8 /* LaunchScreen.xib in Resources */, 213 | 998DB1C019DAEA72006655C8 /* Images.xcassets in Resources */, 214 | ); 215 | runOnlyForDeploymentPostprocessing = 0; 216 | }; 217 | 998DB1C619DAEA72006655C8 /* Resources */ = { 218 | isa = PBXResourcesBuildPhase; 219 | buildActionMask = 2147483647; 220 | files = ( 221 | ); 222 | runOnlyForDeploymentPostprocessing = 0; 223 | }; 224 | /* End PBXResourcesBuildPhase section */ 225 | 226 | /* Begin PBXSourcesBuildPhase section */ 227 | 998DB1AB19DAEA72006655C8 /* Sources */ = { 228 | isa = PBXSourcesBuildPhase; 229 | buildActionMask = 2147483647; 230 | files = ( 231 | 998DB1BB19DAEA72006655C8 /* ViewController.m in Sources */, 232 | 998DB1DA19DAEE12006655C8 /* RKNotificationHub.m in Sources */, 233 | 998DB1B819DAEA72006655C8 /* AppDelegate.m in Sources */, 234 | 998DB1B519DAEA72006655C8 /* main.m in Sources */, 235 | ); 236 | runOnlyForDeploymentPostprocessing = 0; 237 | }; 238 | 998DB1C419DAEA72006655C8 /* Sources */ = { 239 | isa = PBXSourcesBuildPhase; 240 | buildActionMask = 2147483647; 241 | files = ( 242 | 998DB1CF19DAEA72006655C8 /* RKNotificationHubTests.m in Sources */, 243 | ); 244 | runOnlyForDeploymentPostprocessing = 0; 245 | }; 246 | /* End PBXSourcesBuildPhase section */ 247 | 248 | /* Begin PBXTargetDependency section */ 249 | 998DB1CA19DAEA72006655C8 /* PBXTargetDependency */ = { 250 | isa = PBXTargetDependency; 251 | target = 998DB1AE19DAEA72006655C8 /* RKNotificationHub */; 252 | targetProxy = 998DB1C919DAEA72006655C8 /* PBXContainerItemProxy */; 253 | }; 254 | /* End PBXTargetDependency section */ 255 | 256 | /* Begin PBXVariantGroup section */ 257 | 998DB1BC19DAEA72006655C8 /* Main.storyboard */ = { 258 | isa = PBXVariantGroup; 259 | children = ( 260 | 998DB1BD19DAEA72006655C8 /* Base */, 261 | ); 262 | name = Main.storyboard; 263 | sourceTree = ""; 264 | }; 265 | 998DB1C119DAEA72006655C8 /* LaunchScreen.xib */ = { 266 | isa = PBXVariantGroup; 267 | children = ( 268 | 998DB1C219DAEA72006655C8 /* Base */, 269 | ); 270 | name = LaunchScreen.xib; 271 | sourceTree = ""; 272 | }; 273 | /* End PBXVariantGroup section */ 274 | 275 | /* Begin XCBuildConfiguration section */ 276 | 998DB1D019DAEA72006655C8 /* Debug */ = { 277 | isa = XCBuildConfiguration; 278 | buildSettings = { 279 | ALWAYS_SEARCH_USER_PATHS = NO; 280 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 281 | CLANG_CXX_LIBRARY = "libc++"; 282 | CLANG_ENABLE_MODULES = YES; 283 | CLANG_ENABLE_OBJC_ARC = YES; 284 | CLANG_WARN_BOOL_CONVERSION = YES; 285 | CLANG_WARN_CONSTANT_CONVERSION = YES; 286 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 287 | CLANG_WARN_EMPTY_BODY = YES; 288 | CLANG_WARN_ENUM_CONVERSION = YES; 289 | CLANG_WARN_INT_CONVERSION = YES; 290 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 291 | CLANG_WARN_UNREACHABLE_CODE = YES; 292 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 293 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 294 | COPY_PHASE_STRIP = NO; 295 | ENABLE_STRICT_OBJC_MSGSEND = YES; 296 | GCC_C_LANGUAGE_STANDARD = gnu99; 297 | GCC_DYNAMIC_NO_PIC = NO; 298 | GCC_OPTIMIZATION_LEVEL = 0; 299 | GCC_PREPROCESSOR_DEFINITIONS = ( 300 | "DEBUG=1", 301 | "$(inherited)", 302 | ); 303 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 304 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 305 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 306 | GCC_WARN_UNDECLARED_SELECTOR = YES; 307 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 308 | GCC_WARN_UNUSED_FUNCTION = YES; 309 | GCC_WARN_UNUSED_VARIABLE = YES; 310 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 311 | MTL_ENABLE_DEBUG_INFO = YES; 312 | ONLY_ACTIVE_ARCH = YES; 313 | SDKROOT = iphoneos; 314 | }; 315 | name = Debug; 316 | }; 317 | 998DB1D119DAEA72006655C8 /* Release */ = { 318 | isa = XCBuildConfiguration; 319 | buildSettings = { 320 | ALWAYS_SEARCH_USER_PATHS = NO; 321 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 322 | CLANG_CXX_LIBRARY = "libc++"; 323 | CLANG_ENABLE_MODULES = YES; 324 | CLANG_ENABLE_OBJC_ARC = YES; 325 | CLANG_WARN_BOOL_CONVERSION = YES; 326 | CLANG_WARN_CONSTANT_CONVERSION = YES; 327 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 328 | CLANG_WARN_EMPTY_BODY = YES; 329 | CLANG_WARN_ENUM_CONVERSION = YES; 330 | CLANG_WARN_INT_CONVERSION = YES; 331 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 332 | CLANG_WARN_UNREACHABLE_CODE = YES; 333 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 334 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 335 | COPY_PHASE_STRIP = YES; 336 | ENABLE_NS_ASSERTIONS = NO; 337 | ENABLE_STRICT_OBJC_MSGSEND = YES; 338 | GCC_C_LANGUAGE_STANDARD = gnu99; 339 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 340 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 341 | GCC_WARN_UNDECLARED_SELECTOR = YES; 342 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 343 | GCC_WARN_UNUSED_FUNCTION = YES; 344 | GCC_WARN_UNUSED_VARIABLE = YES; 345 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 346 | MTL_ENABLE_DEBUG_INFO = NO; 347 | SDKROOT = iphoneos; 348 | VALIDATE_PRODUCT = YES; 349 | }; 350 | name = Release; 351 | }; 352 | 998DB1D319DAEA72006655C8 /* Debug */ = { 353 | isa = XCBuildConfiguration; 354 | buildSettings = { 355 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 356 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 357 | INFOPLIST_FILE = RKNotificationHub/Info.plist; 358 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 359 | PRODUCT_NAME = "$(TARGET_NAME)"; 360 | }; 361 | name = Debug; 362 | }; 363 | 998DB1D419DAEA72006655C8 /* Release */ = { 364 | isa = XCBuildConfiguration; 365 | buildSettings = { 366 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 367 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 368 | INFOPLIST_FILE = RKNotificationHub/Info.plist; 369 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 370 | PRODUCT_NAME = "$(TARGET_NAME)"; 371 | }; 372 | name = Release; 373 | }; 374 | 998DB1D619DAEA72006655C8 /* Debug */ = { 375 | isa = XCBuildConfiguration; 376 | buildSettings = { 377 | BUNDLE_LOADER = "$(TEST_HOST)"; 378 | FRAMEWORK_SEARCH_PATHS = ( 379 | "$(SDKROOT)/Developer/Library/Frameworks", 380 | "$(inherited)", 381 | ); 382 | GCC_PREPROCESSOR_DEFINITIONS = ( 383 | "DEBUG=1", 384 | "$(inherited)", 385 | ); 386 | INFOPLIST_FILE = RKNotificationHubTests/Info.plist; 387 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 388 | PRODUCT_NAME = "$(TARGET_NAME)"; 389 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/RKNotificationHub.app/RKNotificationHub"; 390 | }; 391 | name = Debug; 392 | }; 393 | 998DB1D719DAEA72006655C8 /* Release */ = { 394 | isa = XCBuildConfiguration; 395 | buildSettings = { 396 | BUNDLE_LOADER = "$(TEST_HOST)"; 397 | FRAMEWORK_SEARCH_PATHS = ( 398 | "$(SDKROOT)/Developer/Library/Frameworks", 399 | "$(inherited)", 400 | ); 401 | INFOPLIST_FILE = RKNotificationHubTests/Info.plist; 402 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 403 | PRODUCT_NAME = "$(TARGET_NAME)"; 404 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/RKNotificationHub.app/RKNotificationHub"; 405 | }; 406 | name = Release; 407 | }; 408 | /* End XCBuildConfiguration section */ 409 | 410 | /* Begin XCConfigurationList section */ 411 | 998DB1AA19DAEA72006655C8 /* Build configuration list for PBXProject "RKNotificationHub" */ = { 412 | isa = XCConfigurationList; 413 | buildConfigurations = ( 414 | 998DB1D019DAEA72006655C8 /* Debug */, 415 | 998DB1D119DAEA72006655C8 /* Release */, 416 | ); 417 | defaultConfigurationIsVisible = 0; 418 | defaultConfigurationName = Release; 419 | }; 420 | 998DB1D219DAEA72006655C8 /* Build configuration list for PBXNativeTarget "RKNotificationHub" */ = { 421 | isa = XCConfigurationList; 422 | buildConfigurations = ( 423 | 998DB1D319DAEA72006655C8 /* Debug */, 424 | 998DB1D419DAEA72006655C8 /* Release */, 425 | ); 426 | defaultConfigurationIsVisible = 0; 427 | defaultConfigurationName = Release; 428 | }; 429 | 998DB1D519DAEA72006655C8 /* Build configuration list for PBXNativeTarget "RKNotificationHubTests" */ = { 430 | isa = XCConfigurationList; 431 | buildConfigurations = ( 432 | 998DB1D619DAEA72006655C8 /* Debug */, 433 | 998DB1D719DAEA72006655C8 /* Release */, 434 | ); 435 | defaultConfigurationIsVisible = 0; 436 | defaultConfigurationName = Release; 437 | }; 438 | /* End XCConfigurationList section */ 439 | }; 440 | rootObject = 998DB1A719DAEA72006655C8 /* Project object */; 441 | } 442 | -------------------------------------------------------------------------------- /RKNotificationHub.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /RKNotificationHub.xcodeproj/project.xcworkspace/xcshareddata/RKNotificationHub.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | B8D09011-1D77-4809-B086-095EB7183CB0 9 | IDESourceControlProjectName 10 | RKNotificationHub 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | 520F45C700A540DF04AC14D3D535CA39508D941F 14 | https://github.com/cwRichardKim/RKNotificationHub.git 15 | 16 | IDESourceControlProjectPath 17 | RKNotificationHub.xcodeproj 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | 520F45C700A540DF04AC14D3D535CA39508D941F 21 | ../.. 22 | 23 | IDESourceControlProjectURL 24 | https://github.com/cwRichardKim/RKNotificationHub.git 25 | IDESourceControlProjectVersion 26 | 111 27 | IDESourceControlProjectWCCIdentifier 28 | 520F45C700A540DF04AC14D3D535CA39508D941F 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | 520F45C700A540DF04AC14D3D535CA39508D941F 36 | IDESourceControlWCCName 37 | RKNotificationHub 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /RKNotificationHub.xcodeproj/project.xcworkspace/xcuserdata/cwrichardkim93.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cwRichardKim/RKNotificationHub/b6592f1226774dbeededbf03ea8cc26827881315/RKNotificationHub.xcodeproj/project.xcworkspace/xcuserdata/cwrichardkim93.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /RKNotificationHub.xcodeproj/xcuserdata/cwrichardkim93.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /RKNotificationHub.xcodeproj/xcuserdata/cwrichardkim93.xcuserdatad/xcschemes/RKNotificationHub.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 65 | 66 | 75 | 76 | 82 | 83 | 84 | 85 | 86 | 87 | 93 | 94 | 100 | 101 | 102 | 103 | 105 | 106 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /RKNotificationHub.xcodeproj/xcuserdata/cwrichardkim93.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | RKNotificationHub.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 998DB1AE19DAEA72006655C8 16 | 17 | primary 18 | 19 | 20 | 998DB1C719DAEA72006655C8 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /RKNotificationHub/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // RKNotificationHub 4 | // 5 | // Created by Richard Kim on 9/30/14. 6 | // Copyright (c) 2014 Richard Kim. All rights reserved. 7 | // 8 | 9 | /* Credits: Earth Icon made by http://www.icomoon.io */ 10 | 11 | #import 12 | 13 | @interface AppDelegate : UIResponder 14 | 15 | @property (strong, nonatomic) UIWindow *window; 16 | 17 | 18 | @end 19 | 20 | -------------------------------------------------------------------------------- /RKNotificationHub/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // RKNotificationHub 4 | // 5 | // Created by Richard Kim on 9/30/14. 6 | // Copyright (c) 2014 Richard Kim. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 18 | return YES; 19 | } 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /RKNotificationHub/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 20 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /RKNotificationHub/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /RKNotificationHub/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /RKNotificationHub/Images.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "orientation" : "portrait", 5 | "idiom" : "iphone", 6 | "minimum-system-version" : "7.0", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "orientation" : "portrait", 11 | "idiom" : "iphone", 12 | "minimum-system-version" : "7.0", 13 | "subtype" : "retina4", 14 | "scale" : "2x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /RKNotificationHub/Images.xcassets/earth.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "earth.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x", 11 | "filename" : "earth-1.png" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x", 16 | "filename" : "earth-1-1.png" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /RKNotificationHub/Images.xcassets/earth.imageset/earth-1-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cwRichardKim/RKNotificationHub/b6592f1226774dbeededbf03ea8cc26827881315/RKNotificationHub/Images.xcassets/earth.imageset/earth-1-1.png -------------------------------------------------------------------------------- /RKNotificationHub/Images.xcassets/earth.imageset/earth-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cwRichardKim/RKNotificationHub/b6592f1226774dbeededbf03ea8cc26827881315/RKNotificationHub/Images.xcassets/earth.imageset/earth-1.png -------------------------------------------------------------------------------- /RKNotificationHub/Images.xcassets/earth.imageset/earth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cwRichardKim/RKNotificationHub/b6592f1226774dbeededbf03ea8cc26827881315/RKNotificationHub/Images.xcassets/earth.imageset/earth.png -------------------------------------------------------------------------------- /RKNotificationHub/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | com.cwRichardKim.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /RKNotificationHub/RKNotificationHub.h: -------------------------------------------------------------------------------- 1 | // 2 | // RKNotificationHub.h 3 | // RKNotificationHub 4 | // 5 | // Created by Richard Kim on 9/30/14. 6 | // Copyright (c) 2014 Richard Kim. All rights reserved. 7 | // 8 | 9 | /* 10 | 11 | Copyright (c) 2014 Choong-Won Richard Kim 12 | 13 | Permission is hereby granted, free of charge, to any person obtaining a copy 14 | of this software and associated documentation files (the "Software"), to deal 15 | in the Software without restriction, including without limitation the rights 16 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | copies of the Software, and to permit persons to whom the Software is furnished 18 | to do so, subject to the following conditions: 19 | 20 | The above copyright notice and this permission notice shall be included in all 21 | copies or substantial portions of the Software. 22 | 23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 | THE SOFTWARE. 30 | 31 | */ 32 | 33 | 34 | #import 35 | #import 36 | 37 | /** 38 | * The default diameter of the notification hub view. 39 | */ 40 | FOUNDATION_EXPORT CGFloat const RKNotificationHubDefaultDiameter; 41 | 42 | @interface RKNotificationHub : NSObject 43 | 44 | //%%% setup 45 | - (id)initWithView:(UIView *)view; 46 | - (id)initWithBarButtonItem:(UIBarButtonItem *)barButtonItem; 47 | 48 | //%%% adjustment methods 49 | - (void)setView:(UIView *)view andCount:(int)startCount; 50 | - (void)setCircleAtFrame:(CGRect)frame; 51 | - (void)setCircleColor:(UIColor*)circleColor labelColor:(UIColor*)labelColor; 52 | - (void)setCircleBorderColor:(UIColor *)color borderWidth:(CGFloat)width; 53 | - (void)moveCircleByX:(CGFloat)x Y:(CGFloat)y; 54 | - (void)scaleCircleSizeBy:(CGFloat)scale; 55 | @property (nonatomic, strong) UIFont *countLabelFont; 56 | 57 | //%%% changing the count 58 | - (void)increment; 59 | - (void)incrementBy:(int)amount; 60 | - (void)decrement; 61 | - (void)decrementBy:(int)amount; 62 | @property (nonatomic, assign) int count; 63 | @property (nonatomic, assign) int maxCount; 64 | 65 | //%%% hiding / showing the count 66 | - (void)hideCount; 67 | - (void)showCount; 68 | 69 | //%%% animations 70 | - (void)pop; 71 | - (void)blink; 72 | - (void)bump; 73 | 74 | @property (nonatomic)UIView *hubView; 75 | 76 | @end 77 | -------------------------------------------------------------------------------- /RKNotificationHub/RKNotificationHub.m: -------------------------------------------------------------------------------- 1 | // 2 | // RKNotificationHub.m 3 | // RKNotificationHub 4 | // 5 | // Created by Richard Kim on 9/30/14. 6 | // Copyright (c) 2014 Richard Kim. All rights reserved. 7 | // 8 | 9 | #import "RKNotificationHub.h" 10 | #import 11 | 12 | //%%% default diameter 13 | CGFloat const RKNotificationHubDefaultDiameter = 30; 14 | static CGFloat const kCountMagnitudeAdaptationRatio = 0.3; 15 | //%%% pop values 16 | static CGFloat const kPopStartRatio = .85; 17 | static CGFloat const kPopOutRatio = 1.05; 18 | static CGFloat const kPopInRatio = .95; 19 | 20 | //%%% blink values 21 | static CGFloat const kBlinkDuration = 0.1; 22 | static CGFloat const kBlinkAlpha = 0.1; 23 | 24 | //%%% bump values 25 | static CGFloat const kFirstBumpDistance = 8.0; 26 | static CGFloat const kBumpTimeSeconds = 0.13; 27 | static CGFloat const SECOND_BUMP_DIST = 4.0; 28 | static CGFloat const kBumpTimeSeconds2 = 0.1; 29 | 30 | @interface RKView : UIView 31 | @property (nonatomic) BOOL isUserChangingBackgroundColor; 32 | @end 33 | 34 | @implementation RKView 35 | 36 | - (void)setBackgroundColor:(UIColor *)backgroundColor 37 | { 38 | if (self.isUserChangingBackgroundColor) { 39 | super.backgroundColor = backgroundColor; 40 | self.isUserChangingBackgroundColor = NO; 41 | } 42 | } 43 | 44 | @end 45 | 46 | 47 | @implementation RKNotificationHub { 48 | int curOrderMagnitude; 49 | UILabel *countLabel; 50 | RKView *redCircle; 51 | CGPoint initialCenter; 52 | CGRect baseFrame; 53 | CGRect initialFrame; 54 | BOOL isIndeterminateMode; 55 | } 56 | 57 | @synthesize hubView; 58 | 59 | #pragma mark - SETUP 60 | 61 | - (id)initWithView:(UIView *)view 62 | { 63 | self = [super init]; 64 | if (!self) return nil; 65 | 66 | _maxCount = 100000; 67 | [self setView:view andCount:0]; 68 | 69 | return self; 70 | } 71 | 72 | - (id)initWithBarButtonItem:(UIBarButtonItem *)barButtonItem 73 | { 74 | self = [self initWithView:[barButtonItem valueForKey:@"view"]]; 75 | [self scaleCircleSizeBy:0.7]; 76 | [self moveCircleByX:-5.0 Y:0]; 77 | 78 | return self; 79 | } 80 | 81 | //%%% give this a view and an initial count (0 hides the notification circle) 82 | // and it will make a hub for you 83 | - (void)setView:(UIView *)view andCount:(int)startCount 84 | { 85 | curOrderMagnitude = 0; 86 | 87 | CGRect frame = view.frame; 88 | 89 | isIndeterminateMode = NO; 90 | 91 | redCircle = [[RKView alloc]init]; 92 | redCircle.userInteractionEnabled = NO; 93 | redCircle.isUserChangingBackgroundColor = YES; 94 | redCircle.backgroundColor = [UIColor redColor]; 95 | 96 | countLabel = [[UILabel alloc]initWithFrame:redCircle.frame]; 97 | countLabel.userInteractionEnabled = NO; 98 | self.count = startCount; 99 | [countLabel setTextAlignment:NSTextAlignmentCenter]; 100 | countLabel.textColor = [UIColor whiteColor]; 101 | countLabel.backgroundColor = [UIColor clearColor]; 102 | 103 | [self setCircleAtFrame:CGRectMake(frame.size.width- (RKNotificationHubDefaultDiameter*2/3), -RKNotificationHubDefaultDiameter/3, RKNotificationHubDefaultDiameter, RKNotificationHubDefaultDiameter)]; 104 | 105 | [view addSubview:redCircle]; 106 | [view addSubview:countLabel]; 107 | [view bringSubviewToFront:redCircle]; 108 | [view bringSubviewToFront:countLabel]; 109 | hubView = view; 110 | [self checkZero]; 111 | } 112 | 113 | //%%% set the frame of the notification circle relative to the button 114 | - (void)setCircleAtFrame:(CGRect)frame 115 | { 116 | [redCircle setFrame:frame]; 117 | initialCenter = CGPointMake(frame.origin.x+frame.size.width/2, frame.origin.y+frame.size.height/2); 118 | baseFrame = frame; 119 | initialFrame = frame; 120 | countLabel.frame = redCircle.frame; 121 | redCircle.layer.cornerRadius = frame.size.height/2; 122 | [countLabel setFont:[UIFont fontWithName:@"HelveticaNeue" size:frame.size.width/2]]; 123 | [self expandToFitLargerDigits]; 124 | } 125 | 126 | //%%% moves the circle by x amount on the x axis and y amount on the y axis 127 | - (void)moveCircleByX:(CGFloat)x Y:(CGFloat)y 128 | { 129 | CGRect frame = redCircle.frame; 130 | frame.origin.x += x; 131 | frame.origin.y += y; 132 | [self setCircleAtFrame:frame]; 133 | } 134 | 135 | //%%% changes the size of the circle. setting a scale of 1 has no effect 136 | - (void)scaleCircleSizeBy:(CGFloat)scale 137 | { 138 | CGRect fr = initialFrame; 139 | CGFloat width = fr.size.width * scale; 140 | CGFloat height = fr.size.height * scale; 141 | CGFloat wdiff = (fr.size.width - width) / 2; 142 | CGFloat hdiff = (fr.size.height - height) / 2; 143 | 144 | CGRect frame = CGRectMake(fr.origin.x + wdiff, fr.origin.y + hdiff, width, height); 145 | [self setCircleAtFrame:frame]; 146 | } 147 | 148 | //%%% change the color of the notification circle 149 | - (void)setCircleColor:(UIColor*)circleColor labelColor:(UIColor*)labelColor 150 | { 151 | redCircle.isUserChangingBackgroundColor = YES; 152 | redCircle.backgroundColor = circleColor; 153 | [countLabel setTextColor:labelColor]; 154 | } 155 | 156 | - (void)setCircleBorderColor:(UIColor *)color borderWidth:(CGFloat)width { 157 | redCircle.layer.borderColor = color.CGColor; 158 | redCircle.layer.borderWidth = width; 159 | } 160 | 161 | - (void)hideCount 162 | { 163 | countLabel.hidden = YES; 164 | isIndeterminateMode = YES; 165 | } 166 | 167 | - (void)showCount 168 | { 169 | isIndeterminateMode = NO; 170 | [self checkZero]; 171 | } 172 | 173 | #pragma mark - ATTRIBUTES 174 | 175 | //%%% increases count by 1 176 | - (void)increment 177 | { 178 | [self incrementBy:1]; 179 | } 180 | 181 | //%%% increases count by amount 182 | - (void)incrementBy:(int)amount 183 | { 184 | self.count += amount; 185 | } 186 | 187 | //%%% decreases count 188 | - (void)decrement 189 | { 190 | [self decrementBy:1]; 191 | } 192 | 193 | //%%% decreases count by amount 194 | - (void)decrementBy:(int)amount 195 | { 196 | if (amount >= self.count) { 197 | self.count = 0; 198 | return; 199 | } 200 | self.count -= amount; 201 | } 202 | 203 | //%%% set the count yourself 204 | - (void)setCount:(int)newCount 205 | { 206 | _count = newCount; 207 | 208 | NSString *labelText = [NSString stringWithFormat:@"%@", @(self.count)]; 209 | 210 | if (_count > self.maxCount){ 211 | labelText = [NSString stringWithFormat:@"%@+", @(self.maxCount)]; 212 | } 213 | 214 | countLabel.text = labelText; 215 | [self checkZero]; 216 | [self expandToFitLargerDigits]; 217 | } 218 | 219 | //%% set the font of the label 220 | - (void)setCountLabelFont:(UIFont *)font 221 | { 222 | [countLabel setFont:font]; 223 | } 224 | 225 | - (UIFont *)countLabelFont 226 | { 227 | return countLabel.font; 228 | } 229 | 230 | #pragma mark - ANIMATION 231 | 232 | //%%% animation that resembles facebook's pop 233 | - (void)pop 234 | { 235 | const float height = baseFrame.size.height; 236 | const float width = baseFrame.size.width; 237 | const float pop_start_h = height * kPopStartRatio; 238 | const float pop_start_w = width * kPopStartRatio; 239 | const float time_start = 0.05; 240 | const float pop_out_h = height * kPopOutRatio; 241 | const float pop_out_w = width * kPopOutRatio; 242 | const float time_out = .2; 243 | const float pop_in_h = height * kPopInRatio; 244 | const float pop_in_w = width * kPopInRatio; 245 | const float time_in = .05; 246 | const float pop_end_h = height; 247 | const float pop_end_w = width; 248 | const float time_end = 0.05; 249 | 250 | CABasicAnimation *startSize = [CABasicAnimation animationWithKeyPath:@"cornerRadius"]; 251 | startSize.duration = time_start; 252 | startSize.beginTime = 0; 253 | startSize.fromValue = @(pop_end_h / 2); 254 | startSize.toValue = @(pop_start_h / 2); 255 | startSize.removedOnCompletion = FALSE; 256 | 257 | CABasicAnimation *outSize = [CABasicAnimation animationWithKeyPath:@"cornerRadius"]; 258 | outSize.duration = time_out; 259 | outSize.beginTime = time_start; 260 | outSize.fromValue = startSize.toValue; 261 | outSize.toValue = @(pop_out_h / 2); 262 | outSize.removedOnCompletion = FALSE; 263 | 264 | CABasicAnimation *inSize = [CABasicAnimation animationWithKeyPath:@"cornerRadius"]; 265 | inSize.duration = time_in; 266 | inSize.beginTime = time_start+time_out; 267 | inSize.fromValue = outSize.toValue; 268 | inSize.toValue = @(pop_in_h / 2); 269 | inSize.removedOnCompletion = FALSE; 270 | 271 | CABasicAnimation *endSize = [CABasicAnimation animationWithKeyPath:@"cornerRadius"]; 272 | endSize.duration = time_end; 273 | endSize.beginTime = time_in+time_out+time_start; 274 | endSize.fromValue = inSize.toValue; 275 | endSize.toValue = @(pop_end_h / 2); 276 | endSize.removedOnCompletion = FALSE; 277 | 278 | CAAnimationGroup *group = [CAAnimationGroup animation]; 279 | [group setDuration: time_start+time_out+time_in+time_end]; 280 | [group setAnimations:@[startSize, outSize, inSize, endSize]]; 281 | 282 | [redCircle.layer addAnimation:group forKey:nil]; 283 | 284 | [UIView animateWithDuration:time_start animations:^{ 285 | CGRect frame = redCircle.frame; 286 | CGPoint center = redCircle.center; 287 | frame.size.height = pop_start_h; 288 | frame.size.width = pop_start_w; 289 | redCircle.frame = frame; 290 | redCircle.center = center; 291 | }completion:^(BOOL complete){ 292 | [UIView animateWithDuration:time_out animations:^{ 293 | CGRect frame = redCircle.frame; 294 | CGPoint center = redCircle.center; 295 | frame.size.height = pop_out_h; 296 | frame.size.width = pop_out_w; 297 | redCircle.frame = frame; 298 | redCircle.center = center; 299 | }completion:^(BOOL complete){ 300 | [UIView animateWithDuration:time_in animations:^{ 301 | CGRect frame = redCircle.frame; 302 | CGPoint center = redCircle.center; 303 | frame.size.height = pop_in_h; 304 | frame.size.width = pop_in_w; 305 | redCircle.frame = frame; 306 | redCircle.center = center; 307 | }completion:^(BOOL complete){ 308 | [UIView animateWithDuration:time_end animations:^{ 309 | CGRect frame = redCircle.frame; 310 | CGPoint center = redCircle.center; 311 | frame.size.height = pop_end_h; 312 | frame.size.width = pop_end_w; 313 | redCircle.frame = frame; 314 | redCircle.center = center; 315 | }]; 316 | }]; 317 | }]; 318 | }]; 319 | } 320 | 321 | //%%% animation that flashes on an off 322 | - (void)blink 323 | { 324 | [self setAlpha:kBlinkAlpha]; 325 | 326 | [UIView animateWithDuration:kBlinkDuration animations:^{ 327 | [self setAlpha:1]; 328 | }completion:^(BOOL complete){ 329 | [UIView animateWithDuration:kBlinkDuration animations:^{ 330 | [self setAlpha:kBlinkAlpha]; 331 | }completion:^(BOOL complete){ 332 | [UIView animateWithDuration:kBlinkDuration animations:^{ 333 | [self setAlpha:1]; 334 | }]; 335 | }]; 336 | }]; 337 | } 338 | 339 | //%%% animation that jumps similar to OSX dock icons 340 | - (void)bump 341 | { 342 | if (!CGPointEqualToPoint(initialCenter,redCircle.center)) { 343 | //%%% canel previous animation 344 | } 345 | 346 | [self bumpCenterY:0]; 347 | [UIView animateWithDuration:kBumpTimeSeconds animations:^{ 348 | [self bumpCenterY:kFirstBumpDistance]; 349 | }completion:^(BOOL complete){ 350 | [UIView animateWithDuration:kBumpTimeSeconds animations:^{ 351 | [self bumpCenterY:0]; 352 | }completion:^(BOOL complete){ 353 | [UIView animateWithDuration:kBumpTimeSeconds2 animations:^{ 354 | [self bumpCenterY:SECOND_BUMP_DIST]; 355 | }completion:^(BOOL complete){ 356 | [UIView animateWithDuration:kBumpTimeSeconds2 animations:^{ 357 | [self bumpCenterY:0]; 358 | }]; 359 | }]; 360 | }]; 361 | }]; 362 | } 363 | 364 | #pragma mark - HELPERS 365 | 366 | //%%% changes the Y origin of the notification circle 367 | - (void)bumpCenterY:(float)yVal 368 | { 369 | CGPoint center = redCircle.center; 370 | center.y = initialCenter.y-yVal; 371 | redCircle.center = center; 372 | countLabel.center = center; 373 | } 374 | 375 | - (void)setAlpha:(float)alpha 376 | { 377 | redCircle.alpha = alpha; 378 | countLabel.alpha = alpha; 379 | } 380 | 381 | //%%% hides the notification if the value is 0 382 | - (void)checkZero 383 | { 384 | if (self.count <= 0) { 385 | redCircle.hidden = YES; 386 | countLabel.hidden = YES; 387 | } else { 388 | redCircle.hidden = NO; 389 | if (!isIndeterminateMode) { 390 | countLabel.hidden = NO; 391 | } 392 | } 393 | } 394 | 395 | - (void)expandToFitLargerDigits { 396 | int orderOfMagnitude = log10((double)self.count); 397 | orderOfMagnitude = (orderOfMagnitude >= 2) ? orderOfMagnitude : 1; 398 | CGRect frame = initialFrame; 399 | frame.size.width = initialFrame.size.width * (1 + kCountMagnitudeAdaptationRatio * (orderOfMagnitude - 1)); 400 | frame.origin.x = initialFrame.origin.x - (frame.size.width - initialFrame.size.width) / 2; 401 | 402 | [redCircle setFrame:frame]; 403 | initialCenter = CGPointMake(frame.origin.x+frame.size.width/2, frame.origin.y+frame.size.height/2); 404 | baseFrame = frame; 405 | countLabel.frame = redCircle.frame; 406 | curOrderMagnitude = orderOfMagnitude; 407 | } 408 | 409 | @end 410 | -------------------------------------------------------------------------------- /RKNotificationHub/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // RKNotificationHub 4 | // 5 | // Created by Richard Kim on 9/30/14. 6 | // Copyright (c) 2014 Richard Kim. All rights reserved. 7 | // 8 | 9 | /* 10 | 11 | Copyright (c) 2014 Choong-Won Richard Kim 12 | 13 | Permission is hereby granted, free of charge, to any person obtaining a copy 14 | of this software and associated documentation files (the "Software"), to deal 15 | in the Software without restriction, including without limitation the rights 16 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | copies of the Software, and to permit persons to whom the Software is furnished 18 | to do so, subject to the following conditions: 19 | 20 | The above copyright notice and this permission notice shall be included in all 21 | copies or substantial portions of the Software. 22 | 23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 | THE SOFTWARE. 30 | 31 | */ 32 | 33 | 34 | #import 35 | 36 | @interface ViewController : UIViewController 37 | 38 | - (IBAction)barButtonPressed:(id)sender; 39 | 40 | @end 41 | 42 | -------------------------------------------------------------------------------- /RKNotificationHub/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // RKNotificationHub 4 | // 5 | // Created by Richard Kim on 9/30/14. 6 | // Copyright (c) 2014 Richard Kim. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "RKNotificationHub.h" 11 | 12 | @interface ViewController () { 13 | RKNotificationHub *hub; 14 | RKNotificationHub *barHub; 15 | } 16 | @property (weak, nonatomic) IBOutlet UIBarButtonItem *barButtonItem; 17 | 18 | @end 19 | 20 | @implementation ViewController 21 | 22 | - (void)viewDidLoad { 23 | [super viewDidLoad]; 24 | [self setupButton]; 25 | 26 | UIImageView *imageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"earth"]]; 27 | imageView.frame = CGRectMake(self.view.frame.size.width/2 - 35, 120, 70, 70); 28 | 29 | hub = [[RKNotificationHub alloc]initWithView:imageView]; 30 | [hub moveCircleByX:-5 Y:5]; // moves the circle five pixels left and 5 down 31 | // [hub hideCount]; // uncomment for a blank badge 32 | 33 | barHub = [[RKNotificationHub alloc] initWithBarButtonItem: _barButtonItem]; 34 | [barHub increment]; 35 | 36 | [self.view addSubview:imageView]; 37 | } 38 | 39 | 40 | - (IBAction)barButtonPressed:(id)sender { 41 | [barHub increment]; 42 | [barHub pop]; 43 | } 44 | 45 | -(void)testIncrement 46 | { 47 | [hub increment]; 48 | 49 | [hub pop]; 50 | // [hub blink]; 51 | // [hub bump]; 52 | } 53 | 54 | // (ignore this, for personal stress testing purposes) 55 | - (void)stressTest { 56 | [hub setCount:pow(10, arc4random_uniform(5))]; 57 | int rand = arc4random_uniform(7); 58 | switch (rand) 59 | { 60 | case 0: 61 | [hub scaleCircleSizeBy: 1.2]; 62 | break; 63 | case 1: 64 | [hub scaleCircleSizeBy: .833]; 65 | break; 66 | default: 67 | break; 68 | } 69 | rand = arc4random_uniform(4); 70 | switch (rand) 71 | { 72 | case 0: 73 | [hub pop]; 74 | break; 75 | case 1: 76 | [hub blink]; 77 | break; 78 | case 2: 79 | [hub bump]; 80 | break; 81 | default: 82 | break; 83 | } 84 | } 85 | 86 | -(void)setupButton 87 | { 88 | UIColor* color = [UIColor colorWithRed:.15 green:.67 blue:.88 alpha:1]; 89 | 90 | UIButton *button = [[UIButton alloc]initWithFrame:CGRectMake(50, 400, 200, 60)]; 91 | button.center = self.view.center; 92 | [button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; 93 | [button setTitle:@"Increment" forState:UIControlStateNormal]; 94 | [button setBackgroundColor:color]; 95 | button.layer.cornerRadius = 5; 96 | [button addTarget:self action:@selector(testIncrement) forControlEvents:UIControlEventTouchUpInside]; 97 | 98 | [self.view addSubview:button]; 99 | } 100 | 101 | - (void)didReceiveMemoryWarning { 102 | [super didReceiveMemoryWarning]; 103 | // Dispose of any resources that can be recreated. 104 | } 105 | 106 | @end 107 | -------------------------------------------------------------------------------- /RKNotificationHub/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // RKNotificationHub 4 | // 5 | // Created by Richard Kim on 9/30/14. 6 | // Copyright (c) 2014 Richard Kim. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /RKNotificationHubTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | com.cwRichardKim.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /RKNotificationHubTests/RKNotificationHubTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // RKNotificationHubTests.m 3 | // RKNotificationHubTests 4 | // 5 | // Created by Richard Kim on 9/30/14. 6 | // Copyright (c) 2014 Richard Kim. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface RKNotificationHubTests : XCTestCase 13 | 14 | @end 15 | 16 | @implementation RKNotificationHubTests 17 | 18 | - (void)setUp { 19 | [super setUp]; 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | } 22 | 23 | - (void)tearDown { 24 | // Put teardown code here. This method is called after the invocation of each test method in the class. 25 | [super tearDown]; 26 | } 27 | 28 | - (void)testExample { 29 | // This is an example of a functional test case. 30 | XCTAssert(YES, @"Pass"); 31 | } 32 | 33 | - (void)testPerformanceExample { 34 | // This is an example of a performance test case. 35 | [self measureBlock:^{ 36 | // Put the code you want to measure the time of here. 37 | }]; 38 | } 39 | 40 | @end 41 | --------------------------------------------------------------------------------