├── .gitignore
├── Demo
├── DemoStoryboard.storyboard
├── JCNotificationBannerPresenterDemo.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ └── contents.xcworkspacedata
│ └── xcuserdata
│ │ └── jcoleman.xcuserdatad
│ │ └── xcschemes
│ │ ├── JCNotificationBannerPresenterDemo.xcscheme
│ │ └── xcschememanagement.plist
└── JCNotificationBannerPresenterDemo
│ ├── Default-568h@2x.png
│ ├── Default.png
│ ├── Default@2x.png
│ ├── JCAppDelegate.h
│ ├── JCAppDelegate.m
│ ├── JCNotificationBannerPresenterDemo-Info.plist
│ ├── JCNotificationBannerPresenterDemo-Prefix.pch
│ ├── JCNotificationPresenterDemoViewController.h
│ ├── JCNotificationPresenterDemoViewController.m
│ ├── en.lproj
│ └── InfoPlist.strings
│ └── main.m
├── JCNotificationBannerPresenter.podspec
├── LICENSE.txt
├── Library
├── JCNotificationBanner.h
├── JCNotificationBanner.m
├── JCNotificationBannerPresenter.h
├── JCNotificationBannerPresenter.m
├── JCNotificationBannerPresenterIOS7Style.h
├── JCNotificationBannerPresenterIOS7Style.m
├── JCNotificationBannerPresenterIOSStyle.h
├── JCNotificationBannerPresenterIOSStyle.m
├── JCNotificationBannerPresenterSmokeStyle.h
├── JCNotificationBannerPresenterSmokeStyle.m
├── JCNotificationBannerPresenter_Private.h
├── JCNotificationBannerView.h
├── JCNotificationBannerView.m
├── JCNotificationBannerViewController.h
├── JCNotificationBannerViewController.m
├── JCNotificationBannerViewIOS7Style.h
├── JCNotificationBannerViewIOS7Style.m
├── JCNotificationBannerViewIOSStyle.h
├── JCNotificationBannerViewIOSStyle.m
├── JCNotificationBannerWindow.h
├── JCNotificationBannerWindow.m
├── JCNotificationCenter.h
└── JCNotificationCenter.m
└── README.markdown
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | .DS_Store
3 | build/
4 | *.pbxuser
5 | !default.pbxuser
6 | *.mode1v3
7 | !default.mode1v3
8 | *.mode2v3
9 | !default.mode2v3
10 | *.perspectivev3
11 | !default.perspectivev3
12 | *.xcworkspace
13 | !default.xcworkspace
14 | xcuserdata
15 | profile
16 | *.moved-aside
17 | DerivedData
18 | .idea/
19 |
--------------------------------------------------------------------------------
/Demo/DemoStoryboard.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
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 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/Demo/JCNotificationBannerPresenterDemo.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 53B55DE016CD594E0011222B /* JCNotificationBannerPresenterSmokeStyle.m in Sources */ = {isa = PBXBuildFile; fileRef = 53B55DDF16CD594E0011222B /* JCNotificationBannerPresenterSmokeStyle.m */; };
11 | 53B55DE416CD596D0011222B /* JCNotificationBannerPresenterIOSStyle.m in Sources */ = {isa = PBXBuildFile; fileRef = 53B55DE316CD596D0011222B /* JCNotificationBannerPresenterIOSStyle.m */; };
12 | 53B55DE716CD5A880011222B /* JCNotificationCenter.m in Sources */ = {isa = PBXBuildFile; fileRef = 53B55DE616CD5A880011222B /* JCNotificationCenter.m */; };
13 | 6D0CCF3716AF604200A28EB5 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6D0CCF3616AF604200A28EB5 /* QuartzCore.framework */; };
14 | C40C9695187A45B600CC235F /* JCNotificationBannerPresenterIOS7Style.m in Sources */ = {isa = PBXBuildFile; fileRef = C40C9694187A45B600CC235F /* JCNotificationBannerPresenterIOS7Style.m */; };
15 | C40C9698187A471400CC235F /* JCNotificationBannerViewIOS7Style.m in Sources */ = {isa = PBXBuildFile; fileRef = C40C9697187A471400CC235F /* JCNotificationBannerViewIOS7Style.m */; };
16 | C41E33061640322C0049334F /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C41E33051640322C0049334F /* UIKit.framework */; };
17 | C41E33081640322C0049334F /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C41E33071640322C0049334F /* Foundation.framework */; };
18 | C41E330A1640322C0049334F /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C41E33091640322C0049334F /* CoreGraphics.framework */; };
19 | C41E33101640322C0049334F /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = C41E330E1640322C0049334F /* InfoPlist.strings */; };
20 | C41E33121640322C0049334F /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = C41E33111640322C0049334F /* main.m */; };
21 | C41E33161640322C0049334F /* JCAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = C41E33151640322C0049334F /* JCAppDelegate.m */; };
22 | C41E33181640322C0049334F /* Default.png in Resources */ = {isa = PBXBuildFile; fileRef = C41E33171640322C0049334F /* Default.png */; };
23 | C41E331A1640322C0049334F /* Default@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C41E33191640322C0049334F /* Default@2x.png */; };
24 | C41E331C1640322C0049334F /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C41E331B1640322C0049334F /* Default-568h@2x.png */; };
25 | C41E332E1640354D0049334F /* DemoStoryboard.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C41E332D1640354D0049334F /* DemoStoryboard.storyboard */; };
26 | C41E3331164035F70049334F /* JCNotificationPresenterDemoViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C41E3330164035F70049334F /* JCNotificationPresenterDemoViewController.m */; };
27 | C41E333E164036F20049334F /* JCNotificationBanner.m in Sources */ = {isa = PBXBuildFile; fileRef = C41E3335164036F20049334F /* JCNotificationBanner.m */; };
28 | C41E333F164036F20049334F /* JCNotificationBannerPresenter.m in Sources */ = {isa = PBXBuildFile; fileRef = C41E3337164036F20049334F /* JCNotificationBannerPresenter.m */; };
29 | C41E3340164036F20049334F /* JCNotificationBannerView.m in Sources */ = {isa = PBXBuildFile; fileRef = C41E3339164036F20049334F /* JCNotificationBannerView.m */; };
30 | C41E3341164036F20049334F /* JCNotificationBannerViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C41E333B164036F20049334F /* JCNotificationBannerViewController.m */; };
31 | C41E3342164036F20049334F /* JCNotificationBannerWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = C41E333D164036F20049334F /* JCNotificationBannerWindow.m */; };
32 | C49AA7F516CC40FF0079EDAE /* JCNotificationBannerViewIOSStyle.m in Sources */ = {isa = PBXBuildFile; fileRef = C49AA7F416CC40FF0079EDAE /* JCNotificationBannerViewIOSStyle.m */; };
33 | /* End PBXBuildFile section */
34 |
35 | /* Begin PBXFileReference section */
36 | 53B55DDD16CD594E0011222B /* JCNotificationBannerPresenter_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JCNotificationBannerPresenter_Private.h; sourceTree = ""; };
37 | 53B55DDE16CD594E0011222B /* JCNotificationBannerPresenterSmokeStyle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JCNotificationBannerPresenterSmokeStyle.h; sourceTree = ""; };
38 | 53B55DDF16CD594E0011222B /* JCNotificationBannerPresenterSmokeStyle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JCNotificationBannerPresenterSmokeStyle.m; sourceTree = ""; };
39 | 53B55DE216CD596D0011222B /* JCNotificationBannerPresenterIOSStyle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JCNotificationBannerPresenterIOSStyle.h; sourceTree = ""; };
40 | 53B55DE316CD596D0011222B /* JCNotificationBannerPresenterIOSStyle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JCNotificationBannerPresenterIOSStyle.m; sourceTree = ""; };
41 | 53B55DE516CD5A880011222B /* JCNotificationCenter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JCNotificationCenter.h; sourceTree = ""; };
42 | 53B55DE616CD5A880011222B /* JCNotificationCenter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JCNotificationCenter.m; sourceTree = ""; };
43 | 6D0CCF3616AF604200A28EB5 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
44 | C40C9693187A45B600CC235F /* JCNotificationBannerPresenterIOS7Style.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JCNotificationBannerPresenterIOS7Style.h; sourceTree = ""; };
45 | C40C9694187A45B600CC235F /* JCNotificationBannerPresenterIOS7Style.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JCNotificationBannerPresenterIOS7Style.m; sourceTree = ""; };
46 | C40C9696187A471400CC235F /* JCNotificationBannerViewIOS7Style.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JCNotificationBannerViewIOS7Style.h; sourceTree = ""; };
47 | C40C9697187A471400CC235F /* JCNotificationBannerViewIOS7Style.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JCNotificationBannerViewIOS7Style.m; sourceTree = ""; };
48 | C41E33011640322C0049334F /* JCNotificationBannerPresenterDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = JCNotificationBannerPresenterDemo.app; sourceTree = BUILT_PRODUCTS_DIR; };
49 | C41E33051640322C0049334F /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
50 | C41E33071640322C0049334F /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
51 | C41E33091640322C0049334F /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
52 | C41E330D1640322C0049334F /* JCNotificationBannerPresenterDemo-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "JCNotificationBannerPresenterDemo-Info.plist"; sourceTree = ""; };
53 | C41E330F1640322C0049334F /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; };
54 | C41E33111640322C0049334F /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
55 | C41E33131640322C0049334F /* JCNotificationBannerPresenterDemo-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "JCNotificationBannerPresenterDemo-Prefix.pch"; sourceTree = ""; };
56 | C41E33141640322C0049334F /* JCAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JCAppDelegate.h; sourceTree = ""; };
57 | C41E33151640322C0049334F /* JCAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JCAppDelegate.m; sourceTree = ""; };
58 | C41E33171640322C0049334F /* Default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Default.png; sourceTree = ""; };
59 | C41E33191640322C0049334F /* Default@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default@2x.png"; sourceTree = ""; };
60 | C41E331B1640322C0049334F /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = ""; };
61 | C41E332D1640354D0049334F /* DemoStoryboard.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = DemoStoryboard.storyboard; path = ../DemoStoryboard.storyboard; sourceTree = ""; };
62 | C41E332F164035F70049334F /* JCNotificationPresenterDemoViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JCNotificationPresenterDemoViewController.h; sourceTree = ""; };
63 | C41E3330164035F70049334F /* JCNotificationPresenterDemoViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JCNotificationPresenterDemoViewController.m; sourceTree = ""; };
64 | C41E3334164036F20049334F /* JCNotificationBanner.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JCNotificationBanner.h; sourceTree = ""; };
65 | C41E3335164036F20049334F /* JCNotificationBanner.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JCNotificationBanner.m; sourceTree = ""; };
66 | C41E3336164036F20049334F /* JCNotificationBannerPresenter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JCNotificationBannerPresenter.h; sourceTree = ""; };
67 | C41E3337164036F20049334F /* JCNotificationBannerPresenter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JCNotificationBannerPresenter.m; sourceTree = ""; };
68 | C41E3338164036F20049334F /* JCNotificationBannerView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JCNotificationBannerView.h; sourceTree = ""; };
69 | C41E3339164036F20049334F /* JCNotificationBannerView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JCNotificationBannerView.m; sourceTree = ""; };
70 | C41E333A164036F20049334F /* JCNotificationBannerViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JCNotificationBannerViewController.h; sourceTree = ""; };
71 | C41E333B164036F20049334F /* JCNotificationBannerViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JCNotificationBannerViewController.m; sourceTree = ""; };
72 | C41E333C164036F20049334F /* JCNotificationBannerWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JCNotificationBannerWindow.h; sourceTree = ""; };
73 | C41E333D164036F20049334F /* JCNotificationBannerWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JCNotificationBannerWindow.m; sourceTree = ""; };
74 | C49AA7F316CC40FF0079EDAE /* JCNotificationBannerViewIOSStyle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JCNotificationBannerViewIOSStyle.h; sourceTree = ""; };
75 | C49AA7F416CC40FF0079EDAE /* JCNotificationBannerViewIOSStyle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JCNotificationBannerViewIOSStyle.m; sourceTree = ""; };
76 | /* End PBXFileReference section */
77 |
78 | /* Begin PBXFrameworksBuildPhase section */
79 | C41E32FE1640322C0049334F /* Frameworks */ = {
80 | isa = PBXFrameworksBuildPhase;
81 | buildActionMask = 2147483647;
82 | files = (
83 | 6D0CCF3716AF604200A28EB5 /* QuartzCore.framework in Frameworks */,
84 | C41E33061640322C0049334F /* UIKit.framework in Frameworks */,
85 | C41E33081640322C0049334F /* Foundation.framework in Frameworks */,
86 | C41E330A1640322C0049334F /* CoreGraphics.framework in Frameworks */,
87 | );
88 | runOnlyForDeploymentPostprocessing = 0;
89 | };
90 | /* End PBXFrameworksBuildPhase section */
91 |
92 | /* Begin PBXGroup section */
93 | C41E32F61640322C0049334F = {
94 | isa = PBXGroup;
95 | children = (
96 | C41E330B1640322C0049334F /* JCNotificationBannerPresenterDemo */,
97 | C41E33041640322C0049334F /* Frameworks */,
98 | C41E33021640322C0049334F /* Products */,
99 | );
100 | sourceTree = "";
101 | };
102 | C41E33021640322C0049334F /* Products */ = {
103 | isa = PBXGroup;
104 | children = (
105 | C41E33011640322C0049334F /* JCNotificationBannerPresenterDemo.app */,
106 | );
107 | name = Products;
108 | sourceTree = "";
109 | };
110 | C41E33041640322C0049334F /* Frameworks */ = {
111 | isa = PBXGroup;
112 | children = (
113 | 6D0CCF3616AF604200A28EB5 /* QuartzCore.framework */,
114 | C41E33051640322C0049334F /* UIKit.framework */,
115 | C41E33071640322C0049334F /* Foundation.framework */,
116 | C41E33091640322C0049334F /* CoreGraphics.framework */,
117 | );
118 | name = Frameworks;
119 | sourceTree = "";
120 | };
121 | C41E330B1640322C0049334F /* JCNotificationBannerPresenterDemo */ = {
122 | isa = PBXGroup;
123 | children = (
124 | C41E3333164036F20049334F /* Library */,
125 | C41E33141640322C0049334F /* JCAppDelegate.h */,
126 | C41E33151640322C0049334F /* JCAppDelegate.m */,
127 | C41E332D1640354D0049334F /* DemoStoryboard.storyboard */,
128 | C41E332F164035F70049334F /* JCNotificationPresenterDemoViewController.h */,
129 | C41E3330164035F70049334F /* JCNotificationPresenterDemoViewController.m */,
130 | C41E330C1640322C0049334F /* Supporting Files */,
131 | );
132 | path = JCNotificationBannerPresenterDemo;
133 | sourceTree = "";
134 | };
135 | C41E330C1640322C0049334F /* Supporting Files */ = {
136 | isa = PBXGroup;
137 | children = (
138 | C41E330D1640322C0049334F /* JCNotificationBannerPresenterDemo-Info.plist */,
139 | C41E330E1640322C0049334F /* InfoPlist.strings */,
140 | C41E33111640322C0049334F /* main.m */,
141 | C41E33131640322C0049334F /* JCNotificationBannerPresenterDemo-Prefix.pch */,
142 | C41E33171640322C0049334F /* Default.png */,
143 | C41E33191640322C0049334F /* Default@2x.png */,
144 | C41E331B1640322C0049334F /* Default-568h@2x.png */,
145 | );
146 | name = "Supporting Files";
147 | sourceTree = "";
148 | };
149 | C41E3333164036F20049334F /* Library */ = {
150 | isa = PBXGroup;
151 | children = (
152 | 53B55DE216CD596D0011222B /* JCNotificationBannerPresenterIOSStyle.h */,
153 | 53B55DE316CD596D0011222B /* JCNotificationBannerPresenterIOSStyle.m */,
154 | C40C9693187A45B600CC235F /* JCNotificationBannerPresenterIOS7Style.h */,
155 | C40C9694187A45B600CC235F /* JCNotificationBannerPresenterIOS7Style.m */,
156 | 53B55DDD16CD594E0011222B /* JCNotificationBannerPresenter_Private.h */,
157 | 53B55DDE16CD594E0011222B /* JCNotificationBannerPresenterSmokeStyle.h */,
158 | 53B55DDF16CD594E0011222B /* JCNotificationBannerPresenterSmokeStyle.m */,
159 | C41E3334164036F20049334F /* JCNotificationBanner.h */,
160 | C41E3335164036F20049334F /* JCNotificationBanner.m */,
161 | C41E3336164036F20049334F /* JCNotificationBannerPresenter.h */,
162 | C41E3337164036F20049334F /* JCNotificationBannerPresenter.m */,
163 | C41E3338164036F20049334F /* JCNotificationBannerView.h */,
164 | C41E3339164036F20049334F /* JCNotificationBannerView.m */,
165 | C49AA7F316CC40FF0079EDAE /* JCNotificationBannerViewIOSStyle.h */,
166 | C49AA7F416CC40FF0079EDAE /* JCNotificationBannerViewIOSStyle.m */,
167 | C40C9696187A471400CC235F /* JCNotificationBannerViewIOS7Style.h */,
168 | C40C9697187A471400CC235F /* JCNotificationBannerViewIOS7Style.m */,
169 | C41E333A164036F20049334F /* JCNotificationBannerViewController.h */,
170 | C41E333B164036F20049334F /* JCNotificationBannerViewController.m */,
171 | C41E333C164036F20049334F /* JCNotificationBannerWindow.h */,
172 | C41E333D164036F20049334F /* JCNotificationBannerWindow.m */,
173 | 53B55DE516CD5A880011222B /* JCNotificationCenter.h */,
174 | 53B55DE616CD5A880011222B /* JCNotificationCenter.m */,
175 | );
176 | name = Library;
177 | path = ../../Library;
178 | sourceTree = "";
179 | };
180 | /* End PBXGroup section */
181 |
182 | /* Begin PBXNativeTarget section */
183 | C41E33001640322C0049334F /* JCNotificationBannerPresenterDemo */ = {
184 | isa = PBXNativeTarget;
185 | buildConfigurationList = C41E331F1640322C0049334F /* Build configuration list for PBXNativeTarget "JCNotificationBannerPresenterDemo" */;
186 | buildPhases = (
187 | C41E32FD1640322C0049334F /* Sources */,
188 | C41E32FE1640322C0049334F /* Frameworks */,
189 | C41E32FF1640322C0049334F /* Resources */,
190 | );
191 | buildRules = (
192 | );
193 | dependencies = (
194 | );
195 | name = JCNotificationBannerPresenterDemo;
196 | productName = JCNotificationBannerPresenterDemo;
197 | productReference = C41E33011640322C0049334F /* JCNotificationBannerPresenterDemo.app */;
198 | productType = "com.apple.product-type.application";
199 | };
200 | /* End PBXNativeTarget section */
201 |
202 | /* Begin PBXProject section */
203 | C41E32F81640322C0049334F /* Project object */ = {
204 | isa = PBXProject;
205 | attributes = {
206 | CLASSPREFIX = JC;
207 | LastUpgradeCheck = 0450;
208 | ORGANIZATIONNAME = "James Coleman";
209 | };
210 | buildConfigurationList = C41E32FB1640322C0049334F /* Build configuration list for PBXProject "JCNotificationBannerPresenterDemo" */;
211 | compatibilityVersion = "Xcode 3.2";
212 | developmentRegion = English;
213 | hasScannedForEncodings = 0;
214 | knownRegions = (
215 | en,
216 | );
217 | mainGroup = C41E32F61640322C0049334F;
218 | productRefGroup = C41E33021640322C0049334F /* Products */;
219 | projectDirPath = "";
220 | projectRoot = "";
221 | targets = (
222 | C41E33001640322C0049334F /* JCNotificationBannerPresenterDemo */,
223 | );
224 | };
225 | /* End PBXProject section */
226 |
227 | /* Begin PBXResourcesBuildPhase section */
228 | C41E32FF1640322C0049334F /* Resources */ = {
229 | isa = PBXResourcesBuildPhase;
230 | buildActionMask = 2147483647;
231 | files = (
232 | C41E33101640322C0049334F /* InfoPlist.strings in Resources */,
233 | C41E33181640322C0049334F /* Default.png in Resources */,
234 | C41E331A1640322C0049334F /* Default@2x.png in Resources */,
235 | C41E331C1640322C0049334F /* Default-568h@2x.png in Resources */,
236 | C41E332E1640354D0049334F /* DemoStoryboard.storyboard in Resources */,
237 | );
238 | runOnlyForDeploymentPostprocessing = 0;
239 | };
240 | /* End PBXResourcesBuildPhase section */
241 |
242 | /* Begin PBXSourcesBuildPhase section */
243 | C41E32FD1640322C0049334F /* Sources */ = {
244 | isa = PBXSourcesBuildPhase;
245 | buildActionMask = 2147483647;
246 | files = (
247 | C40C9698187A471400CC235F /* JCNotificationBannerViewIOS7Style.m in Sources */,
248 | C41E33121640322C0049334F /* main.m in Sources */,
249 | C41E33161640322C0049334F /* JCAppDelegate.m in Sources */,
250 | C41E3331164035F70049334F /* JCNotificationPresenterDemoViewController.m in Sources */,
251 | C41E333E164036F20049334F /* JCNotificationBanner.m in Sources */,
252 | C41E333F164036F20049334F /* JCNotificationBannerPresenter.m in Sources */,
253 | C40C9695187A45B600CC235F /* JCNotificationBannerPresenterIOS7Style.m in Sources */,
254 | C41E3340164036F20049334F /* JCNotificationBannerView.m in Sources */,
255 | C41E3341164036F20049334F /* JCNotificationBannerViewController.m in Sources */,
256 | C41E3342164036F20049334F /* JCNotificationBannerWindow.m in Sources */,
257 | C49AA7F516CC40FF0079EDAE /* JCNotificationBannerViewIOSStyle.m in Sources */,
258 | 53B55DE016CD594E0011222B /* JCNotificationBannerPresenterSmokeStyle.m in Sources */,
259 | 53B55DE416CD596D0011222B /* JCNotificationBannerPresenterIOSStyle.m in Sources */,
260 | 53B55DE716CD5A880011222B /* JCNotificationCenter.m in Sources */,
261 | );
262 | runOnlyForDeploymentPostprocessing = 0;
263 | };
264 | /* End PBXSourcesBuildPhase section */
265 |
266 | /* Begin PBXVariantGroup section */
267 | C41E330E1640322C0049334F /* InfoPlist.strings */ = {
268 | isa = PBXVariantGroup;
269 | children = (
270 | C41E330F1640322C0049334F /* en */,
271 | );
272 | name = InfoPlist.strings;
273 | sourceTree = "";
274 | };
275 | /* End PBXVariantGroup section */
276 |
277 | /* Begin XCBuildConfiguration section */
278 | C41E331D1640322C0049334F /* Debug */ = {
279 | isa = XCBuildConfiguration;
280 | buildSettings = {
281 | ALWAYS_SEARCH_USER_PATHS = NO;
282 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
283 | CLANG_CXX_LIBRARY = "libc++";
284 | CLANG_ENABLE_OBJC_ARC = YES;
285 | CLANG_WARN_EMPTY_BODY = YES;
286 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
287 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
288 | COPY_PHASE_STRIP = NO;
289 | GCC_C_LANGUAGE_STANDARD = gnu99;
290 | GCC_DYNAMIC_NO_PIC = NO;
291 | GCC_OPTIMIZATION_LEVEL = 0;
292 | GCC_PREPROCESSOR_DEFINITIONS = (
293 | "DEBUG=1",
294 | "$(inherited)",
295 | );
296 | GCC_SYMBOLS_PRIVATE_EXTERN = NO;
297 | GCC_WARN_ABOUT_RETURN_TYPE = YES;
298 | GCC_WARN_UNINITIALIZED_AUTOS = YES;
299 | GCC_WARN_UNUSED_VARIABLE = YES;
300 | IPHONEOS_DEPLOYMENT_TARGET = 7.0;
301 | ONLY_ACTIVE_ARCH = YES;
302 | SDKROOT = iphoneos6.1;
303 | TARGETED_DEVICE_FAMILY = "1,2";
304 | };
305 | name = Debug;
306 | };
307 | C41E331E1640322C0049334F /* Release */ = {
308 | isa = XCBuildConfiguration;
309 | buildSettings = {
310 | ALWAYS_SEARCH_USER_PATHS = NO;
311 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
312 | CLANG_CXX_LIBRARY = "libc++";
313 | CLANG_ENABLE_OBJC_ARC = YES;
314 | CLANG_WARN_EMPTY_BODY = YES;
315 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
316 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
317 | COPY_PHASE_STRIP = YES;
318 | GCC_C_LANGUAGE_STANDARD = gnu99;
319 | GCC_WARN_ABOUT_RETURN_TYPE = YES;
320 | GCC_WARN_UNINITIALIZED_AUTOS = YES;
321 | GCC_WARN_UNUSED_VARIABLE = YES;
322 | IPHONEOS_DEPLOYMENT_TARGET = 7.0;
323 | OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1";
324 | SDKROOT = iphoneos6.1;
325 | TARGETED_DEVICE_FAMILY = "1,2";
326 | VALIDATE_PRODUCT = YES;
327 | };
328 | name = Release;
329 | };
330 | C41E33201640322C0049334F /* Debug */ = {
331 | isa = XCBuildConfiguration;
332 | buildSettings = {
333 | GCC_PRECOMPILE_PREFIX_HEADER = YES;
334 | GCC_PREFIX_HEADER = "JCNotificationBannerPresenterDemo/JCNotificationBannerPresenterDemo-Prefix.pch";
335 | INFOPLIST_FILE = "JCNotificationBannerPresenterDemo/JCNotificationBannerPresenterDemo-Info.plist";
336 | IPHONEOS_DEPLOYMENT_TARGET = 5.0;
337 | PRODUCT_NAME = "$(TARGET_NAME)";
338 | WRAPPER_EXTENSION = app;
339 | };
340 | name = Debug;
341 | };
342 | C41E33211640322C0049334F /* Release */ = {
343 | isa = XCBuildConfiguration;
344 | buildSettings = {
345 | GCC_PRECOMPILE_PREFIX_HEADER = YES;
346 | GCC_PREFIX_HEADER = "JCNotificationBannerPresenterDemo/JCNotificationBannerPresenterDemo-Prefix.pch";
347 | INFOPLIST_FILE = "JCNotificationBannerPresenterDemo/JCNotificationBannerPresenterDemo-Info.plist";
348 | IPHONEOS_DEPLOYMENT_TARGET = 5.0;
349 | PRODUCT_NAME = "$(TARGET_NAME)";
350 | WRAPPER_EXTENSION = app;
351 | };
352 | name = Release;
353 | };
354 | /* End XCBuildConfiguration section */
355 |
356 | /* Begin XCConfigurationList section */
357 | C41E32FB1640322C0049334F /* Build configuration list for PBXProject "JCNotificationBannerPresenterDemo" */ = {
358 | isa = XCConfigurationList;
359 | buildConfigurations = (
360 | C41E331D1640322C0049334F /* Debug */,
361 | C41E331E1640322C0049334F /* Release */,
362 | );
363 | defaultConfigurationIsVisible = 0;
364 | defaultConfigurationName = Release;
365 | };
366 | C41E331F1640322C0049334F /* Build configuration list for PBXNativeTarget "JCNotificationBannerPresenterDemo" */ = {
367 | isa = XCConfigurationList;
368 | buildConfigurations = (
369 | C41E33201640322C0049334F /* Debug */,
370 | C41E33211640322C0049334F /* Release */,
371 | );
372 | defaultConfigurationIsVisible = 0;
373 | defaultConfigurationName = Release;
374 | };
375 | /* End XCConfigurationList section */
376 | };
377 | rootObject = C41E32F81640322C0049334F /* Project object */;
378 | }
379 |
--------------------------------------------------------------------------------
/Demo/JCNotificationBannerPresenterDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Demo/JCNotificationBannerPresenterDemo.xcodeproj/xcuserdata/jcoleman.xcuserdatad/xcschemes/JCNotificationBannerPresenterDemo.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
51 |
52 |
58 |
59 |
60 |
61 |
62 |
63 |
69 |
70 |
76 |
77 |
78 |
79 |
81 |
82 |
85 |
86 |
87 |
--------------------------------------------------------------------------------
/Demo/JCNotificationBannerPresenterDemo.xcodeproj/xcuserdata/jcoleman.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | JCNotificationBannerPresenterDemo.xcscheme
8 |
9 | orderHint
10 | 0
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | C41E33001640322C0049334F
16 |
17 | primary
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/Demo/JCNotificationBannerPresenterDemo/Default-568h@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jcoleman/JCNotificationBannerPresenter/203ae740269f9b0bfa85ec9a575a3ce84b734630/Demo/JCNotificationBannerPresenterDemo/Default-568h@2x.png
--------------------------------------------------------------------------------
/Demo/JCNotificationBannerPresenterDemo/Default.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jcoleman/JCNotificationBannerPresenter/203ae740269f9b0bfa85ec9a575a3ce84b734630/Demo/JCNotificationBannerPresenterDemo/Default.png
--------------------------------------------------------------------------------
/Demo/JCNotificationBannerPresenterDemo/Default@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jcoleman/JCNotificationBannerPresenter/203ae740269f9b0bfa85ec9a575a3ce84b734630/Demo/JCNotificationBannerPresenterDemo/Default@2x.png
--------------------------------------------------------------------------------
/Demo/JCNotificationBannerPresenterDemo/JCAppDelegate.h:
--------------------------------------------------------------------------------
1 | #import
2 |
3 | @interface JCAppDelegate : UIResponder
4 |
5 | @property (strong, nonatomic) UIWindow* window;
6 |
7 | @end
8 |
--------------------------------------------------------------------------------
/Demo/JCNotificationBannerPresenterDemo/JCAppDelegate.m:
--------------------------------------------------------------------------------
1 | #import "JCAppDelegate.h"
2 | #import "JCNotificationPresenterDemoViewController.h"
3 |
4 | @implementation JCAppDelegate
5 |
6 | - (BOOL) application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {
7 | self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
8 |
9 | UIStoryboard* storyboard = [UIStoryboard storyboardWithName:@"DemoStoryboard" bundle:nil];
10 | JCNotificationPresenterDemoViewController* demoController;
11 | demoController = (JCNotificationPresenterDemoViewController*)[storyboard instantiateInitialViewController];
12 | self.window.rootViewController = demoController;
13 |
14 | self.window.backgroundColor = [UIColor whiteColor];
15 | [self.window makeKeyAndVisible];
16 |
17 | return YES;
18 | }
19 |
20 | @end
21 |
--------------------------------------------------------------------------------
/Demo/JCNotificationBannerPresenterDemo/JCNotificationBannerPresenterDemo-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleDisplayName
8 | ${PRODUCT_NAME}
9 | CFBundleExecutable
10 | ${EXECUTABLE_NAME}
11 | CFBundleIdentifier
12 | com.jtcoleman.${PRODUCT_NAME:rfc1034identifier}
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | ${PRODUCT_NAME}
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | 1.0
25 | LSRequiresIPhoneOS
26 |
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | UISupportedInterfaceOrientations~ipad
38 |
39 | UIInterfaceOrientationPortrait
40 | UIInterfaceOrientationPortraitUpsideDown
41 | UIInterfaceOrientationLandscapeLeft
42 | UIInterfaceOrientationLandscapeRight
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/Demo/JCNotificationBannerPresenterDemo/JCNotificationBannerPresenterDemo-Prefix.pch:
--------------------------------------------------------------------------------
1 | //
2 | // Prefix header for all source files of the 'JCNotificationBannerPresenterDemo' target in the 'JCNotificationBannerPresenterDemo' project
3 | //
4 |
5 | #import
6 |
7 | #ifndef __IPHONE_3_0
8 | #warning "This project uses features only available in iOS SDK 3.0 and later."
9 | #endif
10 |
11 | #ifdef __OBJC__
12 | #import
13 | #import
14 | #endif
15 |
--------------------------------------------------------------------------------
/Demo/JCNotificationBannerPresenterDemo/JCNotificationPresenterDemoViewController.h:
--------------------------------------------------------------------------------
1 | #import
2 | #import "JCNotificationBannerPresenter.h"
3 |
4 | @interface JCNotificationPresenterDemoViewController : UIViewController
5 |
6 |
7 | @end
8 |
--------------------------------------------------------------------------------
/Demo/JCNotificationBannerPresenterDemo/JCNotificationPresenterDemoViewController.m:
--------------------------------------------------------------------------------
1 | #import "JCNotificationPresenterDemoViewController.h"
2 | #import "JCNotificationCenter.h"
3 | #import "JCNotificationBannerPresenterSmokeStyle.h"
4 | #import "JCNotificationBannerPresenterIOSStyle.h"
5 | #import "JCNotificationBannerPresenterIOS7Style.h"
6 |
7 | @interface JCNotificationPresenterDemoViewController ()
8 |
9 | @property (weak, nonatomic) IBOutlet UITextField* titleTextField;
10 | @property (weak, nonatomic) IBOutlet UITextView* messageTextView;
11 | @property (weak, nonatomic) IBOutlet UISegmentedControl* styleSwitch;
12 |
13 | @end
14 |
15 | @implementation JCNotificationPresenterDemoViewController
16 |
17 | - (IBAction) presentNotificationButtonTapped:(id)sender {
18 | switch (self.styleSwitch.selectedSegmentIndex) {
19 | case 0:
20 | [JCNotificationCenter sharedCenter].presenter = [JCNotificationBannerPresenterSmokeStyle new];
21 | break;
22 | case 1:
23 | [JCNotificationCenter sharedCenter].presenter = [JCNotificationBannerPresenterIOSStyle new];
24 | break;
25 | case 2:
26 | default:
27 | [JCNotificationCenter sharedCenter].presenter = [JCNotificationBannerPresenterIOS7Style new];
28 | break;
29 | }
30 |
31 | [JCNotificationCenter
32 | enqueueNotificationWithTitle:self.titleTextField.text
33 | message:self.messageTextView.text
34 | tapHandler:^{
35 | UIAlertView* alert = [[UIAlertView alloc]
36 | initWithTitle:@"Tapped notification"
37 | message:@"Perform some custom action on notification tap event..."
38 | delegate:nil
39 | cancelButtonTitle:@"OK"
40 | otherButtonTitles:nil];
41 | [alert show];
42 | }];
43 | }
44 |
45 | - (void) viewDidUnload {
46 | [self setMessageTextView:nil];
47 | [self setTitleTextField:nil];
48 | [super viewDidUnload];
49 | }
50 |
51 | @end
52 |
--------------------------------------------------------------------------------
/Demo/JCNotificationBannerPresenterDemo/en.lproj/InfoPlist.strings:
--------------------------------------------------------------------------------
1 | /* Localized versions of Info.plist keys */
2 |
3 |
--------------------------------------------------------------------------------
/Demo/JCNotificationBannerPresenterDemo/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // JCNotificationBannerPresenterDemo
4 | //
5 | // Created by James Coleman on 10/30/12.
6 | // Copyright (c) 2012 James Coleman. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | #import "JCAppDelegate.h"
12 |
13 | int main(int argc, char *argv[])
14 | {
15 | @autoreleasepool {
16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([JCAppDelegate class]));
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/JCNotificationBannerPresenter.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 | s.name = 'JCNotificationBannerPresenter'
3 | s.platform = :ios
4 | s.version = '1.1.2'
5 | s.summary = 'A library for generic presentation of "banners" (e.g. to present a push notification) from anywhere inside an iOS app.'
6 | s.license = { :type => 'MIT', :file => 'LICENSE.txt' }
7 | s.homepage = 'https://github.com/jcoleman/JCNotificationBannerPresenter'
8 | s.author = { 'James Coleman' => 'jtc331@gmail.com' }
9 | s.requires_arc = true
10 | s.framework = 'QuartzCore'
11 | s.source = { :git => 'https://github.com/jcoleman/JCNotificationBannerPresenter.git', :tag => s.version }
12 | s.source_files = 'Library/*.{h,m}'
13 | end
14 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2012 James Coleman
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.
--------------------------------------------------------------------------------
/Library/JCNotificationBanner.h:
--------------------------------------------------------------------------------
1 | #import
2 |
3 | typedef void (^JCNotificationBannerTapHandlingBlock)();
4 |
5 | @interface JCNotificationBanner : NSObject
6 |
7 | @property (nonatomic) NSString* title;
8 | @property (nonatomic) NSString* message;
9 | @property (nonatomic, assign) NSTimeInterval timeout;
10 | @property (nonatomic, copy) JCNotificationBannerTapHandlingBlock tapHandler;
11 |
12 | - (JCNotificationBanner*) initWithTitle:(NSString*)title
13 | message:(NSString*)message
14 | tapHandler:(JCNotificationBannerTapHandlingBlock)tapHandler;
15 |
16 | - (JCNotificationBanner*) initWithTitle:(NSString*)title
17 | message:(NSString*)message
18 | timeout:(NSTimeInterval)timeout
19 | tapHandler:(JCNotificationBannerTapHandlingBlock)tapHandler;
20 | @end
21 |
--------------------------------------------------------------------------------
/Library/JCNotificationBanner.m:
--------------------------------------------------------------------------------
1 | #import "JCNotificationBanner.h"
2 |
3 | @implementation JCNotificationBanner
4 |
5 | @synthesize title;
6 | @synthesize message;
7 | @synthesize timeout;
8 | @synthesize tapHandler;
9 |
10 | - (JCNotificationBanner*) initWithTitle:(NSString*)_title
11 | message:(NSString*)_message
12 | tapHandler:(JCNotificationBannerTapHandlingBlock)_tapHandler {
13 |
14 | return [self initWithTitle:_title message:_message timeout:5.0 tapHandler:_tapHandler];
15 | }
16 |
17 |
18 | - (JCNotificationBanner*) initWithTitle:(NSString*)_title
19 | message:(NSString*)_message
20 | timeout:(NSTimeInterval)_timeout
21 | tapHandler:(JCNotificationBannerTapHandlingBlock)_tapHandler {
22 |
23 | self = [super init];
24 | if (self) {
25 | self.title = _title;
26 | self.message = _message;
27 | self.timeout = _timeout;
28 | self.tapHandler = _tapHandler;
29 | }
30 | return self;
31 | }
32 |
33 | @end
34 |
--------------------------------------------------------------------------------
/Library/JCNotificationBannerPresenter.h:
--------------------------------------------------------------------------------
1 | #import
2 | #import "JCNotificationBanner.h"
3 |
4 | typedef void (^JCNotificationBannerPresenterFinishedBlock)();
5 |
6 | @class JCNotificationBannerWindow;
7 |
8 | @interface JCNotificationBannerPresenter : NSObject
9 |
10 | - (void)willBeginPresentingNotifications;
11 | - (void)didFinishPresentingNotifications;
12 | - (void) presentNotification:(JCNotificationBanner*)notification
13 | finished:(JCNotificationBannerPresenterFinishedBlock)finished;
14 |
15 | @end
16 |
--------------------------------------------------------------------------------
/Library/JCNotificationBannerPresenter.m:
--------------------------------------------------------------------------------
1 | #import "JCNotificationBannerPresenter.h"
2 | #import "JCNotificationBannerPresenter_Private.h"
3 | #import "JCNotificationBannerPresenterIOSStyle.h"
4 | #import "JCNotificationBannerViewIOSStyle.h"
5 | #import "JCNotificationBannerView.h"
6 | #import "JCNotificationBannerWindow.h"
7 | #import "JCNotificationBannerViewController.h"
8 | #import
9 |
10 | @implementation JCNotificationBannerPresenter
11 |
12 | // JCNotificationCenter calls this whenever a presenter
13 | // is about to be used to present one or more notifications.
14 | // It is guaranteed to be called exactly once before presentNotification:finished:.
15 | - (void) willBeginPresentingNotifications {
16 | bannerWindow = [self newWindow];
17 | }
18 |
19 | // JCNotificationCenter calls this whenever it has finished
20 | // using a presenter to present notifications.
21 | // It is guaranteed to be called exactly once after
22 | // one or more calls to presentNotification:finished:.
23 | - (void) didFinishPresentingNotifications {
24 | bannerWindow.hidden = YES;
25 | [bannerWindow removeFromSuperview];
26 | bannerWindow.rootViewController = nil;
27 | bannerWindow = nil;
28 | }
29 |
30 | // Override this method in your subclass if your notification
31 | // style uses a window.
32 | - (void) presentNotification:(JCNotificationBanner*)notification
33 | inWindow:(JCNotificationBannerWindow*)window
34 | finished:(JCNotificationBannerPresenterFinishedBlock)finished {
35 | // Abstract. Override this and call finished() whenever you are
36 | // done showing the notification.
37 | }
38 |
39 | // JCNotificationCenter calls this each time a notification should be presented.
40 | // You can take as long as you like, but make sure you call finished() whenever
41 | // you are ready to display the next notification, if any.
42 | //
43 | // If you do not require a window, override -willBeginPresentingNotifications,
44 | // -didFinishPresentingNotifications, and do whatever windowless thing you like.
45 | - (void) presentNotification:(JCNotificationBanner*)notification
46 | finished:(JCNotificationBannerPresenterFinishedBlock)finished {
47 | [self presentNotification:notification
48 | inWindow:bannerWindow
49 | finished:finished];
50 |
51 | }
52 |
53 | #pragma mark - View helpers
54 |
55 | - (JCNotificationBannerWindow*) newWindow {
56 | JCNotificationBannerWindow* window = [[JCNotificationBannerWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
57 | window.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
58 | window.userInteractionEnabled = YES;
59 | window.autoresizesSubviews = YES;
60 | window.opaque = NO;
61 | window.hidden = NO;
62 | return window;
63 | }
64 |
65 | - (UIView*) newContainerViewForNotification:(JCNotificationBanner*)notification {
66 | UIView* container = [UIView new];
67 | container.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
68 | container.userInteractionEnabled = YES;
69 | container.opaque = NO;
70 | return container;
71 | }
72 |
73 | - (JCNotificationBannerView*) newBannerViewForNotification:(JCNotificationBanner*)notification {
74 | JCNotificationBannerView* view = [[JCNotificationBannerView alloc]
75 | initWithNotification:notification];
76 | view.userInteractionEnabled = YES;
77 | view.autoresizingMask = UIViewAutoresizingFlexibleBottomMargin
78 | | UIViewAutoresizingFlexibleLeftMargin
79 | | UIViewAutoresizingFlexibleRightMargin;
80 | return view;
81 | }
82 |
83 | @end
84 |
--------------------------------------------------------------------------------
/Library/JCNotificationBannerPresenterIOS7Style.h:
--------------------------------------------------------------------------------
1 | #import
2 | #import "JCNotificationBannerPresenter.h"
3 |
4 | @interface JCNotificationBannerPresenterIOS7Style : JCNotificationBannerPresenter
5 | @property CGFloat bannerMaxWidth;
6 | @property CGFloat bannerHeight;
7 | @end
8 |
--------------------------------------------------------------------------------
/Library/JCNotificationBannerPresenterIOS7Style.m:
--------------------------------------------------------------------------------
1 | #import "JCNotificationBannerPresenterIOS7Style.h"
2 | #import "JCNotificationBannerPresenter_Private.h"
3 | #import "JCNotificationBannerViewIOS7Style.h"
4 | #import "JCNotificationBannerViewController.h"
5 |
6 | @implementation JCNotificationBannerPresenterIOS7Style
7 |
8 | - (id) init {
9 | if (self = [super init]) {
10 | self.bannerMaxWidth = 350.0;
11 | self.bannerHeight = 60.0;
12 | }
13 | return self;
14 | }
15 |
16 | - (void) presentNotification:(JCNotificationBanner*)notification
17 | inWindow:(JCNotificationBannerWindow*)window
18 | finished:(JCNotificationBannerPresenterFinishedBlock)finished {
19 | JCNotificationBannerViewIOS7Style* banner = (JCNotificationBannerViewIOS7Style*)[self newBannerViewForNotification:notification];
20 |
21 | JCNotificationBannerViewController* bannerViewController = [JCNotificationBannerViewController new];
22 | window.rootViewController = bannerViewController;
23 | UIView* originalControllerView = bannerViewController.view;
24 |
25 | UIView* containerView = [self newContainerViewForNotification:notification];
26 | [containerView addSubview:banner];
27 | bannerViewController.view = containerView;
28 |
29 | window.bannerView = banner;
30 |
31 | containerView.bounds = originalControllerView.bounds;
32 | containerView.transform = originalControllerView.transform;
33 | [banner getCurrentPresentingStateAndAtomicallySetPresentingState:YES];
34 |
35 | CGSize statusBarSize = [[UIApplication sharedApplication] statusBarFrame].size;
36 | // Make the banner fill the width of the screen, minus any requested margins,
37 | // up to self.bannerMaxWidth.
38 | CGSize bannerSize = CGSizeMake(MIN(self.bannerMaxWidth, originalControllerView.bounds.size.width), self.bannerHeight);
39 | // Center the banner horizontally.
40 | CGFloat x = (MAX(statusBarSize.width, statusBarSize.height) / 2) - (bannerSize.width / 2);
41 | // Position the banner offscreen vertically.
42 | CGFloat y = -self.bannerHeight;
43 |
44 | #ifdef __IPHONE_7_0
45 | #if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_7_0
46 | BOOL accountForStatusBarHeight = ([[UIDevice currentDevice].systemVersion intValue] < 7);
47 | #else
48 | // We're building for a pre-iOS7 base SDK.
49 | BOOL accountForStatusBarHeight = YES;
50 | #endif
51 | #else
52 | // We don't even have access to the iOS 7 availability constants.
53 | BOOL accountForStatusBarHeight = YES;
54 | #endif
55 | if (accountForStatusBarHeight) {
56 | y -= (MIN(statusBarSize.width, statusBarSize.height));
57 | }
58 |
59 | banner.frame = CGRectMake(x, y, bannerSize.width, bannerSize.height);
60 |
61 | JCNotificationBannerTapHandlingBlock originalTapHandler = banner.notificationBanner.tapHandler;
62 | JCNotificationBannerTapHandlingBlock wrappingTapHandler = ^{
63 | if ([banner getCurrentPresentingStateAndAtomicallySetPresentingState:NO]) {
64 | if (originalTapHandler) {
65 | originalTapHandler();
66 | }
67 |
68 | [banner removeFromSuperview];
69 | finished();
70 | // Break the retain cycle
71 | notification.tapHandler = nil;
72 | }
73 | };
74 | banner.notificationBanner.tapHandler = wrappingTapHandler;
75 |
76 | // Slide it down while fading it in.
77 | banner.alpha = 0;
78 | [UIView animateWithDuration:0.5 delay:0
79 | options:UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionCurveEaseOut
80 | animations:^{
81 | CGRect newFrame = CGRectOffset(banner.frame, 0, banner.frame.size.height);
82 | banner.frame = newFrame;
83 | banner.alpha = 0.9;
84 | } completion:^(BOOL finished) {
85 | // Empty.
86 | }];
87 |
88 |
89 | // On timeout, slide it up while fading it out.
90 | if (notification.timeout > 0.0) {
91 | dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, notification.timeout * NSEC_PER_SEC);
92 | dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
93 | [UIView animateWithDuration:0.5 delay:0 options:UIViewAnimationOptionCurveEaseIn
94 | animations:^{
95 | banner.frame = CGRectOffset(banner.frame, 0, -banner.frame.size.height);
96 | banner.alpha = 0;
97 | } completion:^(BOOL didFinish) {
98 | if ([banner getCurrentPresentingStateAndAtomicallySetPresentingState:NO]) {
99 | [banner removeFromSuperview];
100 | [containerView removeFromSuperview];
101 | finished();
102 | // Break the retain cycle
103 | notification.tapHandler = nil;
104 | }
105 | }];
106 | });
107 | }
108 | }
109 |
110 | #pragma mark - View helpers
111 |
112 | - (JCNotificationBannerWindow*) newWindow {
113 | JCNotificationBannerWindow* window = [super newWindow];
114 | window.windowLevel = UIWindowLevelStatusBar;
115 | return window;
116 | }
117 |
118 | - (UIView*) newContainerViewForNotification:(JCNotificationBanner*)notification {
119 | UIView* view = [super newContainerViewForNotification:notification];
120 | view.autoresizesSubviews = YES;
121 | return view;
122 | }
123 |
124 | - (JCNotificationBannerView*) newBannerViewForNotification:(JCNotificationBanner*)notification {
125 | JCNotificationBannerViewIOS7Style* view = [[JCNotificationBannerViewIOS7Style alloc]
126 | initWithNotification:notification];
127 | view.userInteractionEnabled = YES;
128 | view.autoresizingMask = UIViewAutoresizingFlexibleBottomMargin
129 | | UIViewAutoresizingFlexibleLeftMargin
130 | | UIViewAutoresizingFlexibleRightMargin;
131 | return view;
132 | }
133 |
134 | @end
135 |
--------------------------------------------------------------------------------
/Library/JCNotificationBannerPresenterIOSStyle.h:
--------------------------------------------------------------------------------
1 | #import "JCNotificationBannerPresenter.h"
2 |
3 | @interface JCNotificationBannerPresenterIOSStyle : JCNotificationBannerPresenter
4 |
5 | @end
6 |
--------------------------------------------------------------------------------
/Library/JCNotificationBannerPresenterIOSStyle.m:
--------------------------------------------------------------------------------
1 | #import "JCNotificationBannerPresenterIOSStyle.h"
2 | #import "JCNotificationBannerPresenter_Private.h"
3 | #import "JCNotificationBannerWindow.h"
4 | #import "JCNotificationBannerViewIOSStyle.h"
5 | #import "JCNotificationBannerView.h"
6 | #import "JCNotificationBannerViewController.h"
7 |
8 | @implementation JCNotificationBannerPresenterIOSStyle
9 |
10 | - (void) presentNotification:(JCNotificationBanner *)notification
11 | inWindow:(JCNotificationBannerWindow*)window
12 | finished:(JCNotificationBannerPresenterFinishedBlock)finished {
13 | JCNotificationBannerView* banner = [self newBannerViewForNotification:notification];
14 |
15 | JCNotificationBannerViewController* bannerViewController = [JCNotificationBannerViewController new];
16 | window.rootViewController = bannerViewController;
17 | UIView* originalControllerView = bannerViewController.view;
18 |
19 | UIView* containerView = [self newContainerViewForNotification:notification];
20 | [containerView addSubview:banner];
21 | bannerViewController.view = containerView;
22 |
23 | window.bannerView = banner;
24 |
25 | containerView.bounds = originalControllerView.bounds;
26 | containerView.transform = originalControllerView.transform;
27 | [banner getCurrentPresentingStateAndAtomicallySetPresentingState:YES];
28 |
29 | CGSize statusBarSize = [[UIApplication sharedApplication] statusBarFrame].size;
30 | CGFloat width = 320.0;
31 | CGFloat height = 60.0;
32 | CGFloat x = (MAX(statusBarSize.width, statusBarSize.height) - width) / 2.0;
33 | CGFloat y = -60.0;
34 | banner.frame = CGRectMake(x, y, width, height);
35 |
36 | JCNotificationBannerTapHandlingBlock originalTapHandler = notification.tapHandler;
37 | JCNotificationBannerTapHandlingBlock wrappingTapHandler = ^{
38 | if ([banner getCurrentPresentingStateAndAtomicallySetPresentingState:NO]) {
39 | if (originalTapHandler) {
40 | originalTapHandler();
41 | }
42 |
43 | [banner removeFromSuperview];
44 | finished();
45 | }
46 | // Break the retain cycle
47 | notification.tapHandler = nil;
48 | };
49 | notification.tapHandler = wrappingTapHandler;
50 |
51 | double startOpacity = 1.0;
52 | double endOpacity = 1.0;
53 | double animationDuration = 0.5;
54 |
55 | CGRect bannerFrameAfterTransition = banner.frame;
56 | bannerFrameAfterTransition.origin.y = MIN(statusBarSize.width, statusBarSize.height);
57 | UIImage* image = [self captureWindowPartWithRect:bannerFrameAfterTransition];
58 |
59 | // Prepare view transform
60 | CALayer* layer = banner.layer;
61 | banner.alpha = startOpacity;
62 | banner.frame = CGRectOffset(banner.frame, 0.0, banner.frame.size.height);
63 | banner.alpha = endOpacity;
64 | layer.anchorPointZ = 0.5f * banner.frame.size.height;
65 | [self rotateLayer:layer fromAngle:-90.0 toAngle:0.0 duration:animationDuration onCompleted:^(){}];
66 |
67 | // Add image of background to layer.
68 | CALayer* imageLayer = [CALayer layer];
69 | imageLayer.frame = banner.frame;
70 | imageLayer.anchorPointZ = 0.5f * banner.frame.size.height;
71 | imageLayer.contents = (id)image.CGImage;
72 | imageLayer.shadowOffset = CGSizeMake(0.0, 1.0);
73 | imageLayer.shadowColor = [UIColor darkGrayColor].CGColor;
74 | imageLayer.shadowRadius = 3.0;
75 | imageLayer.shadowOpacity = 0.8;
76 | [self rotateLayer:imageLayer fromAngle:0.0 toAngle:90.0 duration:animationDuration onCompleted:^(){} ];
77 | [containerView.layer addSublayer:imageLayer];
78 |
79 | // On timeout, slide it up while fading it out.
80 | if (notification.timeout > 0.0) {
81 | dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, notification.timeout * NSEC_PER_SEC);
82 | dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
83 | // Add image of background to layer.
84 | CALayer* imageLayer = [CALayer layer];
85 | imageLayer.frame = banner.frame;
86 | imageLayer.anchorPointZ = 0.5f * banner.frame.size.height;
87 | imageLayer.contents = (id)image.CGImage;
88 | imageLayer.shadowOffset = CGSizeMake(0, 1);
89 | imageLayer.shadowColor = [UIColor darkGrayColor].CGColor;
90 | imageLayer.shadowRadius = 3.0;
91 | imageLayer.shadowOpacity = 0.8;
92 | [self rotateLayer:imageLayer fromAngle:-90.0 toAngle:0.0 duration:animationDuration onCompleted:^(){} ];
93 | [[containerView layer] addSublayer:imageLayer];
94 |
95 | CALayer* layer = [banner layer];
96 | [self rotateLayer:layer fromAngle:0.0 toAngle:90.0 duration:animationDuration onCompleted:^(){
97 | if ([banner getCurrentPresentingStateAndAtomicallySetPresentingState:NO]) {
98 | [banner removeFromSuperview];
99 | [containerView removeFromSuperview];
100 | finished();
101 | }
102 | // Break the retain cycle
103 | notification.tapHandler = nil;
104 | }];
105 | });
106 | }
107 | }
108 |
109 | #pragma mark - View helpers
110 |
111 | - (UIView*) newContainerViewForNotification:(JCNotificationBanner*)notification {
112 | UIView* view = [super newContainerViewForNotification:notification];
113 | view.autoresizesSubviews = YES;
114 | return view;
115 | }
116 |
117 | - (JCNotificationBannerView*) newBannerViewForNotification:(JCNotificationBanner*)notification {
118 | JCNotificationBannerView* view = [[JCNotificationBannerViewIOSStyle alloc]
119 | initWithNotification:notification];
120 | view.userInteractionEnabled = YES;
121 | view.autoresizingMask = UIViewAutoresizingFlexibleBottomMargin
122 | | UIViewAutoresizingFlexibleLeftMargin
123 | | UIViewAutoresizingFlexibleRightMargin;
124 | return view;
125 | }
126 |
127 | #pragma mark - Screenshot
128 |
129 | /**
130 | * @returns part of the keyWindow screenshot rotated by 180 degrees.
131 | */
132 | - (UIImage*) captureWindowPartWithRect:(CGRect)rect {
133 | UIWindow* keyWindow = [[UIApplication sharedApplication] keyWindow];
134 |
135 | CGRect firstCaptureRect = keyWindow.bounds;
136 |
137 | UIGraphicsBeginImageContextWithOptions(firstCaptureRect.size, YES, 0.0);
138 | CGContextRef context = UIGraphicsGetCurrentContext();
139 | [keyWindow.layer renderInContext:context];
140 | UIImage* capturedImage = UIGraphicsGetImageFromCurrentImageContext();
141 | UIGraphicsEndImageContext();
142 |
143 | CGRect contentRectToCrop = rect;
144 | CGFloat rotationNeeded = 0;
145 | CGRect originalRect = rect;
146 | switch ([UIApplication sharedApplication].statusBarOrientation) {
147 | case UIInterfaceOrientationLandscapeLeft:
148 | rotationNeeded = 90;
149 | contentRectToCrop.origin.x = originalRect.origin.y;
150 | contentRectToCrop.origin.y = keyWindow.bounds.size.height - originalRect.origin.x - originalRect.size.width;
151 | contentRectToCrop.size.width = originalRect.size.height;
152 | contentRectToCrop.size.height = originalRect.size.width;
153 | break;
154 |
155 | case UIInterfaceOrientationLandscapeRight:
156 | rotationNeeded = -90;
157 | contentRectToCrop.origin.x = keyWindow.bounds.size.width - originalRect.origin.y - originalRect.size.height;
158 | contentRectToCrop.origin.y = keyWindow.bounds.size.height - originalRect.origin.x - originalRect.size.width ;
159 | contentRectToCrop.size.width = originalRect.size.height;
160 | contentRectToCrop.size.height = originalRect.size.width;
161 | break;
162 |
163 | case UIInterfaceOrientationPortrait:
164 | case UIInterfaceOrientationUnknown:
165 | break;
166 |
167 | case UIInterfaceOrientationPortraitUpsideDown:
168 | rotationNeeded = 180;
169 | contentRectToCrop.origin.x = originalRect.origin.x;
170 | contentRectToCrop.origin.y = keyWindow.bounds.size.height - originalRect.origin.y - originalRect.size.height;
171 | contentRectToCrop.size.width = originalRect.size.width;
172 | contentRectToCrop.size.height = originalRect.size.height;
173 | break;
174 | }
175 |
176 | contentRectToCrop.origin.x *= capturedImage.scale;
177 | contentRectToCrop.origin.y *= capturedImage.scale;
178 | contentRectToCrop.size.width *= capturedImage.scale;
179 | contentRectToCrop.size.height *= capturedImage.scale;
180 |
181 | CGImageRef imageRef = CGImageCreateWithImageInRect([capturedImage CGImage], contentRectToCrop);
182 | UIImage* croppedImage = [UIImage imageWithCGImage:imageRef scale:capturedImage.scale orientation: UIImageOrientationUp];
183 | CGImageRelease(imageRef);
184 |
185 | if (rotationNeeded) {
186 | croppedImage = [self.class rotateImage:croppedImage byDegrees:rotationNeeded];
187 | }
188 |
189 | return croppedImage;
190 | }
191 |
192 | // -----------------------------------------------------------------------
193 | // UIImage Extensions for preparing screenshots under banner by HardyMacia
194 | // (Catamount Software).
195 | // http://www.catamount.com/forums/viewtopic.php?f=21&t=967
196 |
197 | CGFloat DegreesToRadians(CGFloat degrees) { return degrees * M_PI / 180.0; };
198 | CGFloat RadiansToDegrees(CGFloat radians) { return radians * 180.0 / M_PI; };
199 |
200 | + (UIImage*) rotateImage:(UIImage*)image byDegrees:(CGFloat)degrees {
201 | // Calculate the size of the rotated view's containing box for our drawing space
202 | UIView* rotatedViewBox = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, image.size.width, image.size.height)];
203 | CGAffineTransform transform = CGAffineTransformMakeRotation(DegreesToRadians(degrees));
204 | rotatedViewBox.transform = transform;
205 | CGSize rotatedSize = rotatedViewBox.frame.size;
206 |
207 | // Create the bitmap context
208 | UIGraphicsBeginImageContext(rotatedSize);
209 | CGContextRef bitmap = UIGraphicsGetCurrentContext();
210 |
211 | // Move the origin to the middle of the image so we will rotate and scale around the center.
212 | CGContextTranslateCTM(bitmap, rotatedSize.width/2, rotatedSize.height/2);
213 |
214 | // Rotate the image context
215 | CGContextRotateCTM(bitmap, DegreesToRadians(degrees));
216 |
217 | // Now, draw the rotated/scaled image into the context
218 | CGContextScaleCTM(bitmap, 1.0, -1.0);
219 | CGRect imageRect = CGRectMake(-image.size.width / 2.0, -image.size.height / 2.0, image.size.width, image.size.height);
220 | CGContextDrawImage(bitmap, imageRect, image.CGImage);
221 |
222 | UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
223 | UIGraphicsEndImageContext();
224 |
225 | return newImage;
226 | }
227 |
228 | // -----------------------------------------------------------------------
229 |
230 | - (void) rotateLayer:(CALayer*)imageLayer
231 | fromAngle:(CGFloat)fromAngle
232 | toAngle:(CGFloat)toAngle
233 | duration:(CFTimeInterval)duration
234 | onCompleted:(void (^)())onCompletedBlock {
235 | CGFloat fromInRadians = fromAngle * M_PI / 180.0f;
236 | CGFloat toInRadians = toAngle * M_PI / 180.0f;
237 |
238 | // Create animation that rotates by to the end rotation.
239 | CABasicAnimation* animation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.x"];
240 | animation.delegate = self;
241 | animation.duration = duration;
242 | animation.fromValue = @(fromInRadians);
243 | animation.toValue = @(toInRadians);
244 | animation.fillMode = kCAFillModeForwards;
245 | animation.removedOnCompletion = NO;
246 | [animation setValue:[onCompletedBlock copy] forKey:@"onCompleted"];
247 | [imageLayer addAnimation:animation forKey:@"transform.rotation.x"];
248 | }
249 |
250 | - (void) animationDidStop:(CAAnimation*)animation finished:(BOOL)finished {
251 | if (finished) {
252 | void(^onCompletedBlock)() = [animation valueForKey:@"onCompleted"];
253 | if (onCompletedBlock)
254 | onCompletedBlock();
255 | }
256 | [animation setValue:nil forKey:@"onCompleted"];
257 | }
258 |
259 | @end
260 |
--------------------------------------------------------------------------------
/Library/JCNotificationBannerPresenterSmokeStyle.h:
--------------------------------------------------------------------------------
1 | #import
2 | #import "JCNotificationBannerPresenter.h"
3 |
4 | @interface JCNotificationBannerPresenterSmokeStyle : JCNotificationBannerPresenter
5 | @property CGFloat minimumHorizontalMargin;
6 | @property CGFloat bannerMaxWidth;
7 | @property CGFloat bannerHeight;
8 | @end
9 |
--------------------------------------------------------------------------------
/Library/JCNotificationBannerPresenterSmokeStyle.m:
--------------------------------------------------------------------------------
1 | #import "JCNotificationBannerPresenterSmokeStyle.h"
2 | #import "JCNotificationBannerPresenter_Private.h"
3 | #import "JCNotificationBannerView.h"
4 | #import "JCNotificationBannerViewController.h"
5 |
6 | @implementation JCNotificationBannerPresenterSmokeStyle
7 |
8 | - (id) init {
9 | if (self = [super init]) {
10 | self.minimumHorizontalMargin = 10.0;
11 | self.bannerMaxWidth = 350.0;
12 | self.bannerHeight = 60.0;
13 | }
14 | return self;
15 | }
16 |
17 | - (void) presentNotification:(JCNotificationBanner*)notification
18 | inWindow:(JCNotificationBannerWindow*)window
19 | finished:(JCNotificationBannerPresenterFinishedBlock)finished {
20 | JCNotificationBannerView* banner = [self newBannerViewForNotification:notification];
21 |
22 | JCNotificationBannerViewController* bannerViewController = [JCNotificationBannerViewController new];
23 | window.rootViewController = bannerViewController;
24 | UIView* originalControllerView = bannerViewController.view;
25 |
26 | UIView* containerView = [self newContainerViewForNotification:notification];
27 | [containerView addSubview:banner];
28 | bannerViewController.view = containerView;
29 |
30 | window.bannerView = banner;
31 |
32 | containerView.bounds = originalControllerView.bounds;
33 | containerView.transform = originalControllerView.transform;
34 | [banner getCurrentPresentingStateAndAtomicallySetPresentingState:YES];
35 |
36 | CGSize statusBarSize = [[UIApplication sharedApplication] statusBarFrame].size;
37 | // Make the banner fill the width of the screen, minus any requested margins,
38 | // up to self.bannerMaxWidth.
39 | CGSize bannerSize = CGSizeMake(MIN(self.bannerMaxWidth, originalControllerView.bounds.size.width - self.minimumHorizontalMargin * 2.0), self.bannerHeight);
40 | // Center the banner horizontally.
41 | CGFloat x = (MAX(statusBarSize.width, statusBarSize.height) / 2) - (bannerSize.width / 2);
42 | // Position the banner offscreen vertically.
43 | CGFloat y = -self.bannerHeight;
44 |
45 | #ifdef __IPHONE_7_0
46 | #if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_7_0
47 | BOOL accountForStatusBarHeight = ([[UIDevice currentDevice].systemVersion intValue] < 7);
48 | #else
49 | // We're building for a pre-iOS7 base SDK.
50 | BOOL accountForStatusBarHeight = YES;
51 | #endif
52 | #else
53 | // We don't even have access to the iOS 7 availability constants.
54 | BOOL accountForStatusBarHeight = YES;
55 | #endif
56 | if (accountForStatusBarHeight) {
57 | y -= (MIN(statusBarSize.width, statusBarSize.height));
58 | }
59 |
60 | banner.frame = CGRectMake(x, y, bannerSize.width, bannerSize.height);
61 |
62 | JCNotificationBannerTapHandlingBlock originalTapHandler = banner.notificationBanner.tapHandler;
63 | JCNotificationBannerTapHandlingBlock wrappingTapHandler = ^{
64 | if ([banner getCurrentPresentingStateAndAtomicallySetPresentingState:NO]) {
65 | if (originalTapHandler) {
66 | originalTapHandler();
67 | }
68 |
69 | [banner removeFromSuperview];
70 | finished();
71 | // Break the retain cycle
72 | notification.tapHandler = nil;
73 | }
74 | };
75 | banner.notificationBanner.tapHandler = wrappingTapHandler;
76 |
77 | // Slide it down while fading it in.
78 | banner.alpha = 0;
79 | [UIView animateWithDuration:0.5 delay:0
80 | options:UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionCurveEaseOut
81 | animations:^{
82 | CGRect newFrame = CGRectOffset(banner.frame, 0, banner.frame.size.height);
83 | banner.frame = newFrame;
84 | banner.alpha = 0.9;
85 | } completion:^(BOOL finished) {
86 | // Empty.
87 | }];
88 |
89 |
90 | // On timeout, slide it up while fading it out.
91 | if (notification.timeout > 0.0) {
92 | dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, notification.timeout * NSEC_PER_SEC);
93 | dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
94 | [UIView animateWithDuration:0.5 delay:0 options:UIViewAnimationOptionCurveEaseIn
95 | animations:^{
96 | banner.frame = CGRectOffset(banner.frame, 0, -banner.frame.size.height);
97 | banner.alpha = 0;
98 | } completion:^(BOOL didFinish) {
99 | if ([banner getCurrentPresentingStateAndAtomicallySetPresentingState:NO]) {
100 | [banner removeFromSuperview];
101 | [containerView removeFromSuperview];
102 | finished();
103 | // Break the retain cycle
104 | notification.tapHandler = nil;
105 | }
106 | }];
107 | });
108 | }
109 | }
110 |
111 | #pragma mark - View helpers
112 |
113 | - (JCNotificationBannerWindow*) newWindow {
114 | JCNotificationBannerWindow* window = [super newWindow];
115 | window.windowLevel = UIWindowLevelStatusBar;
116 | return window;
117 | }
118 |
119 | @end
120 |
--------------------------------------------------------------------------------
/Library/JCNotificationBannerPresenter_Private.h:
--------------------------------------------------------------------------------
1 | #import
2 | #import "JCNotificationBannerWindow.h"
3 | #import "JCNotificationBannerView.h"
4 |
5 | @interface JCNotificationBannerPresenter () {
6 | @private
7 | JCNotificationBannerWindow* bannerWindow;
8 | }
9 |
10 | - (void) presentNotification:(JCNotificationBanner*)notification
11 | inWindow:(JCNotificationBannerWindow*)window
12 | finished:(JCNotificationBannerPresenterFinishedBlock)finished;
13 |
14 | #pragma mark - View helpers
15 | - (UIView*) newContainerViewForNotification:(JCNotificationBanner*)notification;
16 | - (JCNotificationBannerWindow*) newWindow;
17 | - (JCNotificationBannerView*) newBannerViewForNotification:(JCNotificationBanner*)notification;
18 |
19 | @end
20 |
--------------------------------------------------------------------------------
/Library/JCNotificationBannerView.h:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 | #import "JCNotificationBanner.h"
4 |
5 | @interface JCNotificationBannerView : UIView
6 |
7 | @property (nonatomic) JCNotificationBanner* notificationBanner;
8 | @property (nonatomic) UIImageView* iconImageView;
9 | @property (nonatomic) UILabel* titleLabel;
10 | @property (nonatomic) UILabel* messageLabel;
11 |
12 | - (id) initWithNotification:(JCNotificationBanner*)notification;
13 | - (BOOL) getCurrentPresentingStateAndAtomicallySetPresentingState:(BOOL)state;
14 |
15 | @end
16 |
--------------------------------------------------------------------------------
/Library/JCNotificationBannerView.m:
--------------------------------------------------------------------------------
1 | #import "JCNotificationBannerView.h"
2 |
3 | const CGFloat kJCNotificationBannerViewOutlineWidth = 2.0;
4 | const CGFloat kJCNotificationBannerViewMarginX = 15.0;
5 | const CGFloat kJCNotificationBannerViewMarginY = 5.0;
6 |
7 | @interface JCNotificationBannerView () {
8 | BOOL isPresented;
9 | NSObject* isPresentedMutex;
10 | }
11 |
12 | - (void) handleSingleTap:(UIGestureRecognizer*)gestureRecognizer;
13 |
14 | @end
15 |
16 | @implementation JCNotificationBannerView
17 |
18 | @synthesize notificationBanner;
19 | @synthesize iconImageView;
20 | @synthesize titleLabel;
21 | @synthesize messageLabel;
22 |
23 | - (id) initWithNotification:(JCNotificationBanner*)notification {
24 | self = [super init];
25 | if (self) {
26 | isPresentedMutex = [NSObject new];
27 |
28 | self.backgroundColor = [UIColor clearColor];
29 | self.iconImageView = [UIImageView new];
30 | [self addSubview:self.iconImageView];
31 | self.titleLabel = [UILabel new];
32 | self.titleLabel.font = [UIFont boldSystemFontOfSize:16];
33 | self.titleLabel.textColor = [UIColor lightTextColor];
34 | self.titleLabel.backgroundColor = [UIColor clearColor];
35 | [self addSubview:self.titleLabel];
36 | self.messageLabel = [UILabel new];
37 | self.messageLabel.font = [UIFont systemFontOfSize:14];
38 | self.messageLabel.textColor = [UIColor lightTextColor];
39 | self.messageLabel.backgroundColor = [UIColor clearColor];
40 | self.messageLabel.numberOfLines = 0;
41 | [self addSubview:self.messageLabel];
42 |
43 | UITapGestureRecognizer* tapRecognizer;
44 | tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self
45 | action:@selector(handleSingleTap:)];
46 | [self addGestureRecognizer:tapRecognizer];
47 |
48 | self.notificationBanner = notification;
49 | }
50 | return self;
51 | }
52 |
53 | - (void) drawRect:(CGRect)rect {
54 | CGRect bounds = self.bounds;
55 |
56 | CGFloat lineWidth = kJCNotificationBannerViewOutlineWidth;
57 | CGFloat radius = 10;
58 | CGFloat height = bounds.size.height;
59 | CGFloat width = bounds.size.width;
60 |
61 | CGContextRef context = UIGraphicsGetCurrentContext();
62 |
63 | CGContextSetAllowsAntialiasing(context, true);
64 | CGContextSetShouldAntialias(context, true);
65 |
66 | CGMutablePathRef outlinePath = CGPathCreateMutable();
67 |
68 | CGPathMoveToPoint(outlinePath, NULL, lineWidth, 0);
69 | CGPathAddLineToPoint(outlinePath, NULL, lineWidth, height - radius - lineWidth);
70 | CGPathAddArc(outlinePath, NULL, radius + lineWidth, height - radius - lineWidth, radius, -M_PI, M_PI_2, 1);
71 | CGPathAddLineToPoint(outlinePath, NULL, width - radius - lineWidth, height - lineWidth);
72 | CGPathAddArc(outlinePath, NULL, width - radius - lineWidth, height - radius - lineWidth, radius, M_PI_2, 0, 1);
73 | CGPathAddLineToPoint(outlinePath, NULL, width - lineWidth, 0);
74 |
75 | CGContextSetRGBFillColor(context, 0, 0, 0, 0.9);
76 | CGContextAddPath(context, outlinePath);
77 | CGContextFillPath(context);
78 |
79 | CGContextAddPath(context, outlinePath);
80 | CGContextSetRGBFillColor(context, 0, 0, 0, 1);
81 | CGContextSetLineWidth(context, lineWidth);
82 | CGContextDrawPath(context, kCGPathStroke);
83 |
84 | CGPathRelease(outlinePath);
85 | }
86 |
87 | - (void) layoutSubviews {
88 | if (!(self.frame.size.width > 0)) { return; }
89 |
90 | BOOL hasTitle = notificationBanner ? (notificationBanner.title.length > 0) : NO;
91 |
92 | CGFloat borderY = kJCNotificationBannerViewOutlineWidth + kJCNotificationBannerViewMarginY;
93 | CGFloat borderX = kJCNotificationBannerViewOutlineWidth + kJCNotificationBannerViewMarginX;
94 | CGFloat currentX = borderX;
95 | CGFloat currentY = borderY;
96 | CGFloat contentWidth = self.frame.size.width - (borderX * 2.0);
97 |
98 | currentY += 2.0;
99 | if (hasTitle) {
100 | self.titleLabel.frame = CGRectMake(currentX, currentY, contentWidth, 22.0);
101 | currentY += 22.0;
102 | }
103 | self.messageLabel.frame = CGRectMake(currentX, currentY, contentWidth, (self.frame.size.height - borderY) - currentY);
104 | [self.messageLabel sizeToFit];
105 | CGRect messageFrame = self.messageLabel.frame;
106 | CGFloat spillY = (currentY + messageFrame.size.height + kJCNotificationBannerViewMarginY) - self.frame.size.height;
107 | if (spillY > 0.0) {
108 | messageFrame.size.height -= spillY;
109 | self.messageLabel.frame = messageFrame;
110 | }
111 | }
112 |
113 | - (void) setNotificationBanner:(JCNotificationBanner*)notification {
114 | notificationBanner = notification;
115 |
116 | self.titleLabel.text = notification.title;
117 | self.messageLabel.text = notification.message;
118 | }
119 |
120 | - (void) handleSingleTap:(UIGestureRecognizer *)gestureRecognizer {
121 | if (notificationBanner && notificationBanner.tapHandler) {
122 | notificationBanner.tapHandler();
123 | }
124 | }
125 |
126 | - (BOOL) getCurrentPresentingStateAndAtomicallySetPresentingState:(BOOL)state {
127 | @synchronized(isPresentedMutex) {
128 | BOOL originalState = isPresented;
129 | isPresented = state;
130 | return originalState;
131 | }
132 | }
133 |
134 | @end
135 |
--------------------------------------------------------------------------------
/Library/JCNotificationBannerViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // JCNotificationBannerViewController.h
3 | // GlobalDriver2ClientBooking
4 | //
5 | // Created by James Coleman on 8/26/12.
6 | //
7 | //
8 |
9 | #import
10 |
11 | @interface JCNotificationBannerViewController : UIViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/Library/JCNotificationBannerViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // JCNotificationBannerViewController.m
3 | // GlobalDriver2ClientBooking
4 | //
5 | // Created by James Coleman on 8/26/12.
6 | //
7 | //
8 |
9 | #import "JCNotificationBannerViewController.h"
10 |
11 | @interface JCNotificationBannerViewController ()
12 |
13 | @end
14 |
15 | @implementation JCNotificationBannerViewController
16 |
17 | - (BOOL) shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
18 | // TODO: return result of main window's controller
19 | return YES;
20 | }
21 |
22 | @end
23 |
--------------------------------------------------------------------------------
/Library/JCNotificationBannerViewIOS7Style.h:
--------------------------------------------------------------------------------
1 | //
2 | // JCNotificationBannerViewIOS7Style.h
3 | // JCNotificationBannerPresenterDemo
4 | //
5 | // Created by James Coleman on 1/5/14.
6 | // Copyright (c) 2014 James Coleman. All rights reserved.
7 | //
8 |
9 | #import "JCNotificationBannerView.h"
10 |
11 | @interface JCNotificationBannerViewIOS7Style : JCNotificationBannerView
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/Library/JCNotificationBannerViewIOS7Style.m:
--------------------------------------------------------------------------------
1 | #import "JCNotificationBannerViewIOS7Style.h"
2 |
3 | @implementation JCNotificationBannerViewIOS7Style
4 |
5 | - (id) initWithNotification:(JCNotificationBanner*)notification {
6 | self = [super initWithNotification:notification];
7 | if (self) {
8 | self.titleLabel.textColor = [UIColor whiteColor];
9 | self.messageLabel.textColor = [UIColor whiteColor];
10 | self.backgroundColor = [UIColor colorWithWhite:0.0 alpha:0.9];
11 |
12 | /*self.layer.shadowOffset = CGSizeMake(0, 1);
13 | self.layer.shadowColor = [UIColor darkGrayColor].CGColor;
14 | self.layer.shadowRadius = 3.0;
15 | self.layer.shadowOpacity = 0.8;*/
16 | }
17 | return self;
18 | }
19 |
20 | /** Overriden to do no custom drawing */
21 | - (void) drawRect:(CGRect)rect {
22 | }
23 |
24 | @end
25 |
--------------------------------------------------------------------------------
/Library/JCNotificationBannerViewIOSStyle.h:
--------------------------------------------------------------------------------
1 | #import "JCNotificationBannerView.h"
2 |
3 | @interface JCNotificationBannerViewIOSStyle : JCNotificationBannerView
4 |
5 | @end
6 |
--------------------------------------------------------------------------------
/Library/JCNotificationBannerViewIOSStyle.m:
--------------------------------------------------------------------------------
1 | #import "JCNotificationBannerViewIOSStyle.h"
2 |
3 | @implementation JCNotificationBannerViewIOSStyle
4 |
5 | - (id) initWithNotification:(JCNotificationBanner*)notification {
6 | self = [super initWithNotification:notification];
7 | if (self) {
8 | self.titleLabel.textColor = [UIColor darkTextColor];
9 | self.messageLabel.textColor = [UIColor darkTextColor];
10 | self.backgroundColor = [UIColor whiteColor];
11 |
12 | self.layer.shadowOffset = CGSizeMake(0, 1);
13 | self.layer.shadowColor = [UIColor darkGrayColor].CGColor;
14 | self.layer.shadowRadius = 3.0;
15 | self.layer.shadowOpacity = 0.8;
16 | }
17 | return self;
18 | }
19 |
20 | /** Overriden to do no custom drawing */
21 | - (void) drawRect:(CGRect)rect {
22 | }
23 |
24 | @end
25 |
--------------------------------------------------------------------------------
/Library/JCNotificationBannerWindow.h:
--------------------------------------------------------------------------------
1 | #import
2 |
3 | @interface JCNotificationBannerWindow : UIWindow
4 |
5 | @property (nonatomic) UIView* bannerView;
6 |
7 | @end
8 |
--------------------------------------------------------------------------------
/Library/JCNotificationBannerWindow.m:
--------------------------------------------------------------------------------
1 | #import "JCNotificationBannerWindow.h"
2 |
3 | @implementation JCNotificationBannerWindow
4 |
5 | @synthesize bannerView;
6 |
7 | - (id) initWithFrame:(CGRect)frame {
8 | self = [super initWithFrame:frame];
9 | if (self) {
10 | // Initialization code
11 | }
12 | return self;
13 | }
14 |
15 | - (UIView*) hitTest:(CGPoint)point withEvent:(UIEvent *)event {
16 | UIView* superHitView = [super hitTest:point withEvent:event];
17 | if (superHitView == bannerView) {
18 | return bannerView;
19 | } else {
20 | UIWindow* nextWindow;
21 | BOOL encounteredBannerWindow = NO;
22 | for (UIWindow* window in [[UIApplication sharedApplication].windows reverseObjectEnumerator]) {
23 | if (encounteredBannerWindow && ![window isKindOfClass:[JCNotificationBannerWindow class]]) {
24 | nextWindow = window;
25 | break;
26 | }
27 |
28 | if (!encounteredBannerWindow && [window isKindOfClass:[JCNotificationBannerWindow class]]) {
29 | encounteredBannerWindow = YES;
30 | }
31 | }
32 |
33 | if (nextWindow) {
34 | return [nextWindow hitTest:point withEvent:event];
35 | } else {
36 | return superHitView;
37 | }
38 | }
39 | }
40 |
41 | @end
42 |
--------------------------------------------------------------------------------
/Library/JCNotificationCenter.h:
--------------------------------------------------------------------------------
1 | #import
2 | #import "JCNotificationBanner.h"
3 |
4 | @class JCNotificationBannerPresenter;
5 |
6 | @interface JCNotificationCenter : NSObject
7 |
8 | @property (nonatomic) JCNotificationBannerPresenter* presenter;
9 |
10 | + (JCNotificationCenter*) sharedCenter;
11 |
12 | /** Adds notification to queue with given parameters. */
13 | + (void) enqueueNotificationWithTitle:(NSString*)title
14 | message:(NSString*)message
15 | tapHandler:(JCNotificationBannerTapHandlingBlock)tapHandler;
16 |
17 | - (void) enqueueNotificationWithTitle:(NSString*)title
18 | message:(NSString*)message
19 | tapHandler:(JCNotificationBannerTapHandlingBlock)tapHandler;
20 |
21 | - (void) enqueueNotification:(JCNotificationBanner*)notification;
22 |
23 | @end
24 |
--------------------------------------------------------------------------------
/Library/JCNotificationCenter.m:
--------------------------------------------------------------------------------
1 | #import "JCNotificationCenter.h"
2 | #import "JCNotificationBannerPresenter.h"
3 | #import "JCNotificationBannerPresenterIOSStyle.h"
4 | #import "JCNotificationBannerWindow.h"
5 | #import "JCNotificationBannerPresenter_Private.h"
6 |
7 | @interface JCNotificationCenter () {
8 | @private
9 | NSMutableArray* enqueuedNotifications;
10 | NSLock* isPresentingMutex;
11 | NSObject* notificationQueueMutex;
12 | JCNotificationBannerPresenter* _currentPresenter;
13 | JCNotificationBannerPresenter* _nextPresenter;
14 | }
15 | @end
16 |
17 | @implementation JCNotificationCenter
18 |
19 | - (JCNotificationCenter*) init {
20 | self = [super init];
21 | if (self) {
22 | enqueuedNotifications = [NSMutableArray new];
23 | isPresentingMutex = [NSLock new];
24 | notificationQueueMutex = [NSObject new];
25 | self.presenter = [[[self class] presenterClass] new];
26 | }
27 | return self;
28 | }
29 |
30 | + (JCNotificationCenter*) sharedCenter {
31 | static JCNotificationCenter* sharedCenter = nil;
32 | static dispatch_once_t onceToken;
33 | dispatch_once(&onceToken, ^{
34 | sharedCenter = [[self class] new];
35 | });
36 | return sharedCenter;
37 | }
38 |
39 | + (Class) presenterClass {
40 | return [JCNotificationBannerPresenterIOSStyle class];
41 | }
42 |
43 | /** Adds notification with iOS banner Style to queue with given parameters. */
44 | + (void) enqueueNotificationWithTitle:(NSString*)title
45 | message:(NSString*)message
46 | tapHandler:(JCNotificationBannerTapHandlingBlock)tapHandler {
47 | JCNotificationBanner* notification = [[JCNotificationBanner alloc] initWithTitle:title
48 | message:message
49 | tapHandler:tapHandler];
50 |
51 | [[self sharedCenter] enqueueNotification:notification];
52 | }
53 |
54 | - (void) enqueueNotificationWithTitle:(NSString*)title
55 | message:(NSString*)message
56 | tapHandler:(JCNotificationBannerTapHandlingBlock)tapHandler {
57 | JCNotificationBanner* notification = [[JCNotificationBanner alloc]
58 | initWithTitle:title
59 | message:message
60 | tapHandler:tapHandler];
61 | [self enqueueNotification:notification];
62 | }
63 |
64 | - (void) enqueueNotification:(JCNotificationBanner*)notification {
65 | @synchronized(notificationQueueMutex) {
66 | [enqueuedNotifications addObject:notification];
67 | }
68 | [self beginPresentingNotifications];
69 | }
70 |
71 | - (JCNotificationBanner*) dequeueNotification {
72 | JCNotificationBanner* notification;
73 | @synchronized(notificationQueueMutex) {
74 | if ([enqueuedNotifications count] > 0) {
75 | notification = [enqueuedNotifications objectAtIndex:0];
76 | [enqueuedNotifications removeObjectAtIndex:0];
77 | }
78 | }
79 | return notification;
80 | }
81 |
82 | - (void) beginPresentingNotifications {
83 | dispatch_async(dispatch_get_main_queue(), ^{
84 | if ([isPresentingMutex tryLock]) {
85 | // Check to see if the nextPresenter has changed *during* a group
86 | // of notifications.
87 | if (_currentPresenter != _nextPresenter) {
88 | // Finish up with the original one.
89 | [_currentPresenter didFinishPresentingNotifications];
90 | _currentPresenter = nil;
91 | }
92 |
93 | if (!_currentPresenter) {
94 | _currentPresenter = _nextPresenter;
95 | [_currentPresenter willBeginPresentingNotifications];
96 | }
97 | JCNotificationBanner* nextNotification = [self dequeueNotification];
98 | if (nextNotification) {
99 | [_currentPresenter presentNotification:nextNotification
100 | finished:^{
101 | [self donePresentingNotification:nextNotification];
102 | }];
103 | } else {
104 | [_currentPresenter didFinishPresentingNotifications];
105 | _currentPresenter = nil;
106 | [isPresentingMutex unlock];
107 | }
108 | } else {
109 | // Notification presentation already in progress; do nothing.
110 | }
111 | });
112 | }
113 |
114 | - (void) donePresentingNotification:(JCNotificationBanner*)notification {
115 | // Process any notifications enqueued during this one's presentation.
116 | [isPresentingMutex unlock];
117 | [self beginPresentingNotifications];
118 | }
119 |
120 | - (void) setPresenter:(JCNotificationBannerPresenter*)presenter {
121 | _nextPresenter = presenter;
122 | }
123 |
124 | - (JCNotificationBannerPresenter*) presenter {
125 | return _nextPresenter;
126 | }
127 |
128 | @end
129 |
--------------------------------------------------------------------------------
/README.markdown:
--------------------------------------------------------------------------------
1 | Why?
2 | ----
3 |
4 | Apple doesn't provide an API in iOS for presenting notification banners while the app is running. For many projects the most sensible way to respond to a remote push notification would be to display that notification (in the same style it is presented if your app is not foreground) and allow the user to determine whether the notification merits a response.
5 |
6 | What?
7 | -----
8 |
9 | JCNotificationBannerPresenter allows you to display notification banners asynchronously from any piece of code in your application. It is not view/view-controller specific, you can use it directly from the AppDelegate, for example. It doesn't attempt to mimic the style of Apple's notifications; it seems better to avoid the uncanny valley presented by that endeavor. Just like Apple's notifications, however, this project slides down a banner from the middle of the status bar that times out after a set period of time and slides back up. The banner also can be dismissed by tapping on it, and a custom tap handler can be assigned to trigger some custom action.
10 |
11 | Usage?
12 | ----
13 |
14 | #import "JCNotificationCenter.h"
15 |
16 | …
17 |
18 | - (void) application:(UIApplication*)application didReceiveRemoteNotification:(NSDictionary*)notification {
19 | NSString* title = @"Push Notification";
20 | NSDictionary* aps = [notification objectForKey:@"aps"];
21 | NSString* alert = [aps objectForKey:@"alert"];
22 | [JCNotificationCenter
23 | enqueueNotificationWithTitle:title
24 | message:alert
25 | tapHandler:^{
26 | NSLog(@"Received tap on notification banner!");
27 | }];
28 | }
29 |
30 | By default the banner style is iOS style, which presents banners with a 3D rotation. The project comes with an alternative Smoke appearance, which slides a semi-translucent window down from the status bar. If you want to use the same style for all notifications in your project, you can set the style at compile time by overriding or editing the `+presenterClass` method in JCNotificationCenter.
31 |
32 | Notifications enqueued with the method `+enqueueNotificationWithTitle:message:tapHandler:` will time out in five seconds. You can change this on a per-notification basis by setting the timeout property in JCNotificationBanner and enqueing the banner with `-enqueueNotification:`. A value <= 0 will never timeout and requires user interaction to dismiss.
33 |
34 | Installation?
35 | -------------
36 |
37 | This project includes a `podspec` for usage with [CocoaPods](http://http://cocoapods.org/). Simply add
38 |
39 | pod 'JCNotificationBannerPresenter'
40 |
41 | to your `Podfile` and run `pod install`.
42 |
43 | Alternately, you can configure your project to include the `QuartzCore` (`CoreGraphics` already includes `QuartzCore` ) framework and add all of the `.h` and `.m` files in this project. If your project does not use ARC, you will need to enable ARC on these files. You can enabled ARC per-file by adding the -fobjc-arc flag, as described on [a common StackOverflow question](http://stackoverflow.com/questions/6646052/how-can-i-disable-arc-for-a-single-file-in-a-project).
44 |
45 | License
46 | -------
47 |
48 | This project is licensed under the MIT license. All copyright rights are retained by myself.
49 |
50 | Copyright (c) 2012 James Coleman
51 |
52 | Permission is hereby granted, free of charge, to any person obtaining a copy
53 | of this software and associated documentation files (the "Software"), to deal
54 | in the Software without restriction, including without limitation the rights
55 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
56 | copies of the Software, and to permit persons to whom the Software is
57 | furnished to do so, subject to the following conditions:
58 |
59 | The above copyright notice and this permission notice shall be included in
60 | all copies or substantial portions of the Software.
61 |
62 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
63 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
64 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
65 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
66 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
67 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
68 | THE SOFTWARE.
69 |
--------------------------------------------------------------------------------