├── Project ├── Demo │ ├── TODO │ ├── en.lproj │ │ └── InfoPlist.strings │ ├── CPDAppDelegate.h │ ├── main.m │ ├── Demo Project-Prefix.pch │ ├── Demo ProjectTests-Prefix.pch │ ├── Images.xcassets │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ └── LaunchImage.launchimage │ │ │ └── Contents.json │ ├── Demo Project-Info.plist │ └── CPDAppDelegate.m ├── DemoTests │ ├── en.lproj │ │ └── InfoPlist.strings │ ├── Demo ProjectTests-Prefix.pch │ ├── Demo ProjectTests-Info.plist │ ├── CPDAcknowledgementLoaderTests.m │ └── CPDLibraryTests.m ├── Demo Project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── Demo Project.xccheckout ├── Demo Project.xcodeproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── Demo Project.xccheckout │ └── project.pbxproj ├── Podfile └── Podfile.lock ├── CPDAcknowledgements ├── private │ ├── .gitkeep │ ├── CPDContributionDetailViewController.h │ ├── CPDCocoaPodsLibrariesLoader.h │ ├── CPDExternalActionHandler.h │ ├── CPDTableViewDataSource.h │ ├── CPDLibraryDetailViewController.h │ ├── CPDExternalActionHandler.m │ ├── CPDCocoaPodsLibrariesLoader.m │ ├── CPDContributionDetailViewController.m │ ├── CPDTableViewDataSource.m │ └── CPDLibraryDetailViewController.m ├── CPDStyle.m ├── CPDContribution.m ├── CPDContribution.h ├── CPDStyle.h ├── CPDAcknowledgementsViewController.h ├── CPDLibrary.h ├── CPDLibrary.m └── CPDAcknowledgementsViewController.m ├── Web ├── library.png ├── contribution.png └── acknowledgements.png ├── CHANGELOG.md ├── .gitignore ├── CPDAcknowledgements.podspec ├── LICENSE ├── README.md └── Rakefile /Project/Demo/TODO: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /CPDAcknowledgements/private/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Project/Demo/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /Project/DemoTests/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /Web/library.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CocoaPods/CPDAcknowledgements/HEAD/Web/library.png -------------------------------------------------------------------------------- /Web/contribution.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CocoaPods/CPDAcknowledgements/HEAD/Web/contribution.png -------------------------------------------------------------------------------- /Web/acknowledgements.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CocoaPods/CPDAcknowledgements/HEAD/Web/acknowledgements.png -------------------------------------------------------------------------------- /CPDAcknowledgements/CPDStyle.m: -------------------------------------------------------------------------------- 1 | #import "CPDStyle.h" 2 | 3 | @interface CPDStyle () 4 | @end 5 | 6 | @implementation CPDStyle 7 | @end -------------------------------------------------------------------------------- /Project/DemoTests/Demo ProjectTests-Prefix.pch: -------------------------------------------------------------------------------- 1 | #define EXP_SHORTHAND 2 | #define MOCKITO_SHORTHAND 3 | 4 | #import 5 | #import 6 | #import -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # CPDAcknowledgements CHANGELOG 2 | 3 | ## 1.0.0 4 | 5 | * Support custom contributors 6 | * Support libraries based on the `cocoapods-acknowledgements` 7 | * Allow custom CSS/HTML for a library 8 | -------------------------------------------------------------------------------- /Project/Demo Project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /CPDAcknowledgements/private/CPDContributionDetailViewController.h: -------------------------------------------------------------------------------- 1 | @class CPDContribution; 2 | @interface CPDContributionDetailViewController : UIViewController 3 | 4 | - (instancetype)initWithContribution:(CPDContribution *)contribution; 5 | 6 | @end -------------------------------------------------------------------------------- /Project/Demo Project.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /CPDAcknowledgements/private/CPDCocoaPodsLibrariesLoader.h: -------------------------------------------------------------------------------- 1 | @import Foundation; 2 | 3 | @class CPDLibrary; 4 | 5 | @interface CPDCocoaPodsLibrariesLoader : NSObject 6 | 7 | + (NSArray *)loadAcknowledgementsWithBundle:(NSBundle *)bundle; 8 | 9 | @end 10 | -------------------------------------------------------------------------------- /CPDAcknowledgements/private/CPDExternalActionHandler.h: -------------------------------------------------------------------------------- 1 | @import Foundation; 2 | 3 | @class CPDLibrary; 4 | 5 | @interface CPDExternalActionHandler : NSObject 6 | + (void)openActionForTwitterHandle:(NSString *)twitterUsername; 7 | + (void)openAddressInBrowser:(NSString *)address; 8 | @end -------------------------------------------------------------------------------- /.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 | xcuserdata 13 | profile 14 | *.moved-aside 15 | DerivedData 16 | .idea/ 17 | *.hmap 18 | 19 | #CocoaPods 20 | Pods 21 | -------------------------------------------------------------------------------- /Project/Demo/CPDAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // CPDAppDelegate.h 3 | // CPDAcknowledgements 4 | // 5 | // Created by Orta on 17/01/2014. 6 | // Copyright (c) 2014 CocoaPods. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface CPDAppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /CPDAcknowledgements/CPDContribution.m: -------------------------------------------------------------------------------- 1 | #import "CPDContribution.h" 2 | 3 | @implementation CPDContribution 4 | 5 | - (id)initWithName:(NSString *)name websiteAddress:(NSString *)address role:(NSString *)role 6 | { 7 | self = [super init]; 8 | if(!self) return self; 9 | 10 | _name = name; 11 | _websiteAddress = address; 12 | _role = role; 13 | 14 | return self; 15 | } 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /Project/Demo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // CPDAcknowledgements 4 | // 5 | // Created by Orta on 17/01/2014. 6 | // Copyright (c) 2014 CocoaPods. All rights reserved. 7 | // 8 | 9 | #import "CPDAppDelegate.h" 10 | 11 | int main(int argc, char * argv[]) 12 | { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([CPDAppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Project/Demo/Demo Project-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | 7 | #import 8 | 9 | #ifndef __IPHONE_5_0 10 | #warning "This project uses features only available in iOS SDK 5.0 and later." 11 | #endif 12 | 13 | #ifdef __OBJC__ 14 | #import 15 | #import 16 | #endif 17 | -------------------------------------------------------------------------------- /Project/Demo/Demo ProjectTests-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | 7 | #import 8 | 9 | #ifndef __IPHONE_5_0 10 | #warning "This project uses features only available in iOS SDK 5.0 and later." 11 | #endif 12 | 13 | #ifdef __OBJC__ 14 | #import 15 | #import 16 | #endif 17 | -------------------------------------------------------------------------------- /Project/Podfile: -------------------------------------------------------------------------------- 1 | plugin 'cocoapods-acknowledgements' 2 | 3 | target "Demo Project" do 4 | pod "CPDAcknowledgements", :path => "../CPDAcknowledgements.podspec" 5 | 6 | # These pods are used only for giving us some data 7 | pod "ORStackView" 8 | pod "IRFEmojiCheatSheet" 9 | 10 | target "Demo ProjectTests" do 11 | inherit! :search_paths 12 | 13 | pod 'Specta', '~> 1.0' 14 | pod 'Expecta', '~> 1.0' 15 | pod 'OCMockito', '~> 1.0' 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /Project/Demo/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" : "40x40", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "60x60", 16 | "scale" : "2x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /CPDAcknowledgements/private/CPDTableViewDataSource.h: -------------------------------------------------------------------------------- 1 | @import UIKit; 2 | 3 | @class CPDLibrary, CPDContribution; 4 | 5 | @interface CPDTableViewDataSource : NSObject 6 | 7 | - (instancetype)initWithAcknowledgements:(NSArray *)acknowledgements contributions:(NSArray *)contributions; 8 | 9 | - (CPDLibrary *)acknowledgementAtIndexPath:(NSIndexPath *)indexPath; 10 | 11 | - (CGFloat)heightForCellAtIndexPath:(NSIndexPath *)path; 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /CPDAcknowledgements/private/CPDLibraryDetailViewController.h: -------------------------------------------------------------------------------- 1 | @import UIKit; 2 | 3 | NS_ASSUME_NONNULL_BEGIN 4 | 5 | @class CPDLibrary; 6 | 7 | @interface CPDLibraryDetailViewController : UIViewController 8 | 9 | - (instancetype)initWithLibrary:(CPDLibrary *)library; 10 | 11 | @property (readwrite, nonatomic, copy) NSString * _Nullable HTML; 12 | @property (readwrite, nonatomic, copy) NSString * _Nullable CSS; 13 | @property (readwrite, nonatomic, copy) NSString * _Nullable headerHTML; 14 | 15 | @end 16 | 17 | NS_ASSUME_NONNULL_END -------------------------------------------------------------------------------- /Project/Demo/Images.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "orientation" : "portrait", 5 | "idiom" : "iphone", 6 | "extent" : "full-screen", 7 | "minimum-system-version" : "7.0", 8 | "scale" : "2x" 9 | }, 10 | { 11 | "orientation" : "portrait", 12 | "idiom" : "iphone", 13 | "subtype" : "retina4", 14 | "extent" : "full-screen", 15 | "minimum-system-version" : "7.0", 16 | "scale" : "2x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /Project/DemoTests/Demo ProjectTests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /CPDAcknowledgements.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "CPDAcknowledgements" 3 | s.version = "1.0.0" 4 | s.summary = "Show your CocoaPods dependencies in-app." 5 | s.description = <<-DESC 6 | Show your CocoaPods library and contributors in-app with smart defaults, and customisable view controllers. 7 | DESC 8 | s.homepage = "https://github.com/CocoaPods/CPDAcknowledgements" 9 | s.license = 'MIT' 10 | s.author = { "Orta Therox" => "orta.therox@gmail.com", "Fabio Pelosin" => "fabiopelosin@gmail.com" } 11 | s.source = { :git => "https://github.com/CocoaPods/CPDAcknowledgements.git", :tag => s.version.to_s } 12 | s.homepage = "https://github.com/CocoaPods/CPDAcknowledgements" 13 | s.social_media_url = "https://twitter.com/CocoaPods" 14 | s.ios.deployment_target = '8.0' 15 | s.source_files = 'CPDAcknowledgements/**/**' 16 | s.private_header_files = 'CPDAcknowledgements/private/*.h' 17 | s.ios.frameworks = 'UIKit' 18 | end 19 | -------------------------------------------------------------------------------- /Project/DemoTests/CPDAcknowledgementLoaderTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // CPDAcknowledgementLoaderTests.m 3 | // Demo Project 4 | // 5 | // Created by Orta on 17/01/2014. 6 | // Copyright (c) 2014 CocoaPods. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | SpecBegin(CPDAcknowledgementsLoader) 13 | 14 | describe(@"loadAcknowledgements with our fixtured data", ^{ 15 | 16 | it(@"returns an array", ^{ 17 | NSArray *values = [CPDCocoaPodsLibrariesLoader loadAcknowledgementsWithBundle:[NSBundle mainBundle]]; 18 | expect([values isKindOfClass:NSArray.class]).to.beTruthy(); 19 | }); 20 | 21 | it(@"it creates CPDAcknowledgements with real data", ^{ 22 | NSArray *values = [CPDCocoaPodsLibrariesLoader loadAcknowledgementsWithBundle:[NSBundle mainBundle]]; 23 | CPDLibrary *acknowledgement = values[0]; 24 | 25 | expect(acknowledgement.title).to.equal(@"CPDAcknowledgements"); 26 | expect(acknowledgement.licenseType).to.equal(@"MIT"); 27 | }); 28 | }); 29 | 30 | SpecEnd 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Orta Therox 2 | Fabio Pelosin 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /CPDAcknowledgements/CPDContribution.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | NS_ASSUME_NONNULL_BEGIN 4 | 5 | /// A class that represents an individual's contributions to the app 6 | /// These are presented as tableview cells with a title and a subtitle 7 | 8 | /// Optionally you can set an avatar address, and CPDAcknowledgements 9 | /// will include a round thumbnail for them. 10 | 11 | @interface CPDContribution : NSObject 12 | 13 | /// Usual inits 14 | - (instancetype)initWithName:(NSString *)name websiteAddress:(NSString * _Nullable)address role:(NSString *)role; 15 | 16 | /// Name of the contributor: .e.g Fabio Pelosin 17 | @property (nonatomic, copy, readonly) NSString *name; 18 | 19 | /// Website address representing the contributor: .e.g https://orta.io 20 | /// if one is not set, you cannot tap on the contributor 21 | 22 | @property (nonatomic, copy, readonly) NSString * _Nullable websiteAddress; 23 | 24 | /// Responsibility in their part of shipping your app 25 | @property (nonatomic, copy, readonly) NSString *role; 26 | 27 | /// Optional avatar url which will be grabbed asynchronously 28 | @property (nonatomic, copy) NSString * _Nullable avatarAddress; 29 | 30 | @end 31 | 32 | NS_ASSUME_NONNULL_END 33 | -------------------------------------------------------------------------------- /Project/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - CPDAcknowledgements (0.5.0) 3 | - Expecta (1.0.5) 4 | - FLKAutoLayout (0.2.1) 5 | - IRFEmojiCheatSheet (0.3.0) 6 | - OCHamcrest (4.3.0) 7 | - OCMockito (1.4.0): 8 | - OCHamcrest (~> 4.0) 9 | - ORStackView (3.0.1): 10 | - FLKAutoLayout (~> 0.2) 11 | - Specta (1.0.5) 12 | 13 | DEPENDENCIES: 14 | - CPDAcknowledgements (from `../CPDAcknowledgements.podspec`) 15 | - Expecta (~> 1.0) 16 | - IRFEmojiCheatSheet 17 | - OCMockito (~> 1.0) 18 | - ORStackView 19 | - Specta (~> 1.0) 20 | 21 | EXTERNAL SOURCES: 22 | CPDAcknowledgements: 23 | :path: "../CPDAcknowledgements.podspec" 24 | 25 | SPEC CHECKSUMS: 26 | CPDAcknowledgements: 32f6dfcc35eed5d9897f13947024b9d32133e2fa 27 | Expecta: e1c022fcd33910b6be89c291d2775b3fe27a89fe 28 | FLKAutoLayout: 9db6b30c2008d230da608e62c607b11c23b942e6 29 | IRFEmojiCheatSheet: 364b2733c4e37c65ef9f56225246cdf42068370f 30 | OCHamcrest: cd63d27f48a266d4412c0b295b01b8f0940efa81 31 | OCMockito: 4981140c9a9ec06c31af40f636e3c0f25f27e6b2 32 | ORStackView: a1bb52748cd0ae29891c140baf22ff8972fb363c 33 | Specta: ac94d110b865115fe60ff2c6d7281053c6f8e8a2 34 | 35 | PODFILE CHECKSUM: 1c110034e6fc846de3ca560c07d3c7cb43780d13 36 | 37 | COCOAPODS: 1.0.0.beta.6 38 | -------------------------------------------------------------------------------- /CPDAcknowledgements/private/CPDExternalActionHandler.m: -------------------------------------------------------------------------------- 1 | #import "CPDExternalActionHandler.h" 2 | #import "CPDLibrary.h" 3 | 4 | 5 | @interface CPDExternalActionHandler () 6 | @end 7 | 8 | @implementation CPDExternalActionHandler 9 | 10 | + (void)openActionForTwitterHandle:(NSString *)twitterUsername 11 | { 12 | UIApplication *application = [UIApplication sharedApplication]; 13 | 14 | BOOL hasTweetBot = [application canOpenURL:[NSURL URLWithString:@"tweetbot://"]]; 15 | if (hasTweetBot) { 16 | NSString *url = [NSString stringWithFormat:@"tweetbot://%@/user_profile/%@", twitterUsername, twitterUsername]; 17 | [application openURL:[NSURL URLWithString:url]]; 18 | return; 19 | } 20 | 21 | BOOL hasOfficialTwitter = [application canOpenURL:[NSURL URLWithString:@"twitter://user"]]; 22 | if (hasOfficialTwitter) { 23 | NSString *url = [NSString stringWithFormat:@"twitter://user?screen_name=%@", twitterUsername]; 24 | [application openURL:[NSURL URLWithString:url]]; 25 | return; 26 | } 27 | 28 | NSString *url = [NSString stringWithFormat:@"https://twitter.com/%@", twitterUsername]; 29 | [application openURL:[NSURL URLWithString:url]]; 30 | } 31 | 32 | + (void)openAddressInBrowser:(NSString *)address 33 | { 34 | NSURL *url = [NSURL URLWithString:address]; 35 | [[UIApplication sharedApplication] openURL:url]; 36 | } 37 | 38 | @end -------------------------------------------------------------------------------- /CPDAcknowledgements/CPDStyle.h: -------------------------------------------------------------------------------- 1 | @import Foundation; 2 | 3 | NS_ASSUME_NONNULL_BEGIN 4 | 5 | /// Allows you to customize the style for the the view 6 | /// controllers for your libraries. 7 | 8 | @interface CPDStyle : NSObject 9 | 10 | /// HTML provided to the view controller, it's nothing too fancy 11 | /// just a string which has a collection of string replacements on it. 12 | /// 13 | /// This is the current default: 14 | /// {{STYLESHEET}}{{HEADER}}

{{BODY}}

15 | 16 | @property (nonatomic, copy) NSString * _Nullable libraryHTML; 17 | 18 | /// CSS for styling your library 19 | /// 20 | /// This is the current default: 21 | /// 26 | 27 | @property (nonatomic, copy) NSString * _Nullable libraryCSS; 28 | 29 | /// HTML specifically for showing the header information about a library 30 | /// 31 | /// This is the current default 32 | ///

{{SUMMARY}}

{{VERSION}}

{{SHORT_LICENSE}}


33 | 34 | @property (nonatomic, copy) NSString * _Nullable libraryHeaderHTML; 35 | 36 | @end 37 | 38 | NS_ASSUME_NONNULL_END 39 | -------------------------------------------------------------------------------- /CPDAcknowledgements/CPDAcknowledgementsViewController.h: -------------------------------------------------------------------------------- 1 | @import UIKit; 2 | 3 | NS_ASSUME_NONNULL_BEGIN 4 | 5 | @class CPDStyle, CPDLibrary, CPDContribution; 6 | 7 | /// The main view controller, and the only one that is a part of the public API. 8 | /// This view controller takes a collection of acknowledgements and contributors and presents information about them. 9 | 10 | @interface CPDAcknowledgementsViewController : UITableViewController 11 | 12 | /// This will assume that you have the plugin `cocoapods-acknowledgements` installed and running on a `pod install`, 13 | /// and will pull all the library metadata from that. The style can be used to customize the look and feel of a library's 14 | /// information page. 15 | 16 | - (instancetype)initWithStyle:(CPDStyle * _Nullable )style; 17 | 18 | /// If you put `nil` in contributions the view controller will assume that you have the plugin `cocoapods-acknowledgements` 19 | /// installed and running on a `pod install`, and will pull all the library metadata from that. 20 | /// You can pass in a collection of `CPDContribution`s to provide individual contributions outside of libraries. 21 | /// The style can be used to customize the look and feel of a library's information page. 22 | 23 | - (instancetype)initWithStyle:(CPDStyle * _Nullable )style acknowledgements:(NSArray * _Nullable )acknowledgements contributions:(NSArray * _Nullable )contributions; 24 | 25 | @end 26 | 27 | NS_ASSUME_NONNULL_END 28 | -------------------------------------------------------------------------------- /Project/Demo/Demo Project-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | org.cocoapods.${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 | NSAppTransportSecurity 28 | 29 | NSAllowsArbitraryLoads 30 | 31 | 32 | UIRequiredDeviceCapabilities 33 | 34 | armv7 35 | 36 | UIRequiresFullScreen 37 | 38 | UISupportedInterfaceOrientations 39 | 40 | UIInterfaceOrientationPortrait 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /Project/Demo Project.xcworkspace/xcshareddata/Demo Project.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | BC3E5C4D-79C4-45D6-877E-DDE93BA0B188 9 | IDESourceControlProjectName 10 | Demo Project 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | 27A6F6FE-E753-421A-A7FD-3C3AE35236AF 14 | https://github.com/CocoaPods/CPDAcknowledgements.git 15 | 16 | IDESourceControlProjectPath 17 | Project/Demo Project.xcworkspace 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | 27A6F6FE-E753-421A-A7FD-3C3AE35236AF 21 | ../.. 22 | 23 | IDESourceControlProjectURL 24 | https://github.com/CocoaPods/CPDAcknowledgements.git 25 | IDESourceControlProjectVersion 26 | 110 27 | IDESourceControlProjectWCCIdentifier 28 | 27A6F6FE-E753-421A-A7FD-3C3AE35236AF 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | 27A6F6FE-E753-421A-A7FD-3C3AE35236AF 36 | IDESourceControlWCCName 37 | CPDAcknowledgements 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /Project/Demo Project.xcodeproj/project.xcworkspace/xcshareddata/Demo Project.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | AEFE8164-A184-4ECB-8F57-244BC95FC36D 9 | IDESourceControlProjectName 10 | Demo Project 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | 30FBDC97-286F-4514-9CBF-1ED711AB626C 14 | https://github.com/CocoaPods/CPDAcknowledgements.git 15 | 16 | IDESourceControlProjectPath 17 | Project/Demo Project.xcodeproj/project.xcworkspace 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | 30FBDC97-286F-4514-9CBF-1ED711AB626C 21 | ../../.. 22 | 23 | IDESourceControlProjectURL 24 | https://github.com/CocoaPods/CPDAcknowledgements.git 25 | IDESourceControlProjectVersion 26 | 110 27 | IDESourceControlProjectWCCIdentifier 28 | 30FBDC97-286F-4514-9CBF-1ED711AB626C 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | 30FBDC97-286F-4514-9CBF-1ED711AB626C 36 | IDESourceControlWCCName 37 | CPDAcknowledgements 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /CPDAcknowledgements/CPDLibrary.h: -------------------------------------------------------------------------------- 1 | NS_ASSUME_NONNULL_BEGIN 2 | 3 | @class CPDContribution; 4 | 5 | /// A class that represents a library used in your application 6 | 7 | @interface CPDLibrary : NSObject 8 | 9 | /// Create a library given the default (as of CP 0.30) information 10 | /// from the metadata.plist 11 | 12 | - (instancetype)initWithCocoaPodsMetadataPlistDictionary:(NSDictionary *)dictionary; 13 | 14 | /// Name of the pod 15 | @property (readonly, nonatomic, copy) NSString *title; 16 | 17 | /// Body text of the library's licence 18 | @property (readonly, nonatomic, copy) NSString *licenseBody; 19 | 20 | /// The name of the library's license 21 | @property (readonly, nonatomic, copy) NSString *licenseType; 22 | 23 | /// The libraries description 24 | @property (readonly, nonatomic, copy) NSString * _Nullable summary; 25 | 26 | /// People who have contributed to this library 27 | @property (readonly, nonatomic, copy) NSArray *authors; 28 | 29 | /// Full URL of the social media end-point represented by hte library 30 | @property (readonly, nonatomic, copy) NSString * _Nullable socialMediaAddress; 31 | 32 | /// A longer description of the library 33 | @property (readonly, nonatomic, copy) NSString * _Nullable libraryDescription; 34 | 35 | /// The current version of the library 36 | @property (readonly, nonatomic, copy) NSString *version; 37 | 38 | /// The website representing the library 39 | @property (readonly, nonatomic, copy) NSString * _Nullable websiteAddress; 40 | 41 | /// Actionable titles for platform dependent views 42 | - (NSArray *)actionTitlesForLibrary; 43 | 44 | /// Perform actions from given titles 45 | - (void)performActionAtIndex:(NSInteger)index; 46 | 47 | /// Is it worth showing the popover based on the current available metadata? 48 | - (BOOL)hasActions; 49 | 50 | @end 51 | 52 | NS_ASSUME_NONNULL_END 53 | -------------------------------------------------------------------------------- /Project/Demo/CPDAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // CPDAppDelegate.m 3 | // CPDAcknowledgements 4 | // 5 | // Created by Orta on 17/01/2014. 6 | // Copyright (c) 2014 CocoaPods. All rights reserved. 7 | // 8 | 9 | #import "CPDAppDelegate.h" 10 | #import "CPDContribution.h" 11 | #import 12 | 13 | @implementation CPDAppDelegate 14 | 15 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 16 | { 17 | self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 18 | 19 | CPDContribution *orta = [[CPDContribution alloc] initWithName:@"Orta" websiteAddress:@"http://orta.github.io" role:@"Behind a wheel"]; 20 | orta.avatarAddress = @"https://1.gravatar.com/avatar/f116cb3be23153ec08b94e8bd4dbcfeb?d=https%3A%2F%2Fidenticons.github.com%2F243e8373034964abf7c8a8e57d4df724.png&r=x&s=86"; 21 | 22 | CPDContribution *fabio = [[CPDContribution alloc] initWithName:@"Fabio Pelosin" websiteAddress:@"http://twitter.com/fabiopelosin" role:@"Back Seat Driver"]; 23 | fabio.avatarAddress = @"https://0.gravatar.com/avatar/b6dde1a78e6215a592768c1e78a54adc?d=https%3A%2F%2Fidenticons.github.com%2Fbdc4e72be51d566c2fc9564ed8182611.png&r=x&s=86"; 24 | 25 | CPDContribution *kyle = [[CPDContribution alloc] initWithName:@"Kyle Fuller" websiteAddress:@"http://twitter.com/kylefuller" role:@"Somewhere in the boot"]; 26 | NSArray *contributors = @[orta, fabio, kyle]; 27 | 28 | CPDAcknowledgementsViewController *acknowledgementsViewController = [[CPDAcknowledgementsViewController alloc] initWithStyle:nil acknowledgements:nil contributions:contributors]; 29 | UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:acknowledgementsViewController]; 30 | 31 | self.window.rootViewController = navController; 32 | [self.window makeKeyAndVisible]; 33 | 34 | return YES; 35 | } 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /CPDAcknowledgements/private/CPDCocoaPodsLibrariesLoader.m: -------------------------------------------------------------------------------- 1 | #import "CPDCocoaPodsLibrariesLoader.h" 2 | #import "CPDLibrary.h" 3 | 4 | @implementation CPDCocoaPodsLibrariesLoader 5 | 6 | + (NSArray *)loadAcknowledgementsWithBundle:(NSBundle *)bundle; 7 | { 8 | NSString *path = [self pathForFirstFileWithSuffix:@"-metadata.plist" inBundle:bundle]; 9 | NSDictionary *dictionary = [NSDictionary dictionaryWithContentsOfFile:path]; 10 | return [self acknowledgementsFromDictionary:dictionary]; 11 | } 12 | 13 | + (NSArray *)acknowledgementsFromDictionary:(NSDictionary *)dictionary 14 | { 15 | NSMutableArray *acknowledgements = [NSMutableArray array]; 16 | NSArray *entries = dictionary[@"specs"]; 17 | 18 | for (NSDictionary *entry in entries) { 19 | CPDLibrary *acknowledgement = [[CPDLibrary alloc] initWithCocoaPodsMetadataPlistDictionary:entry]; 20 | 21 | // Feels a bit weird to be including itself in the list. 22 | if ([acknowledgement.title isEqualToString: @"CPDAcknowledgements"]) { continue; } 23 | 24 | [acknowledgements addObject:acknowledgement]; 25 | } 26 | return acknowledgements; 27 | } 28 | 29 | + (NSString *)pathForFirstFileWithSuffix:(NSString *)suffix inBundle:(NSBundle *)bundle 30 | { 31 | NSString *resourcesPath = [bundle resourcePath]; 32 | NSArray *resources = [self filesOfDirectoryAtPath:resourcesPath]; 33 | NSUInteger index = [resources indexOfObjectPassingTest:^BOOL(NSString *path, NSUInteger idx, BOOL *stop) { 34 | return [path hasSuffix:suffix]; 35 | }]; 36 | 37 | if(index == NSNotFound) return nil; 38 | 39 | NSString *path = resources[index]; 40 | return [resourcesPath stringByAppendingPathComponent:path]; 41 | } 42 | 43 | + (NSArray *)filesOfDirectoryAtPath:(NSString *)path 44 | { 45 | NSFileManager *manager = [NSFileManager defaultManager]; 46 | NSError *error; 47 | NSArray *contents = [manager contentsOfDirectoryAtPath:path error:&error]; 48 | if (error) { 49 | NSLog(@"Error getting resources in main bundle - %@", error.localizedDescription); 50 | } 51 | return contents; 52 | } 53 | 54 | @end 55 | -------------------------------------------------------------------------------- /CPDAcknowledgements/private/CPDContributionDetailViewController.m: -------------------------------------------------------------------------------- 1 | #import "CPDContributionDetailViewController.h" 2 | #import "CPDContribution.h" 3 | @import WebKit; 4 | 5 | @interface CPDContributionDetailViewController () 6 | @property (nonatomic, strong) CPDContribution *contribution; 7 | @property (nonatomic, strong) NSURL *urlForAlertView; 8 | @end 9 | 10 | @implementation CPDContributionDetailViewController 11 | 12 | - (id)initWithContribution:(CPDContribution *)contribution 13 | { 14 | if(!contribution.websiteAddress){ 15 | @throw @"The contribution needs to include a web address."; 16 | } 17 | 18 | self = [super init]; 19 | if (!self) return nil; 20 | 21 | _contribution = contribution; 22 | 23 | return self; 24 | } 25 | 26 | - (void)loadView 27 | { 28 | WKWebView *webView = [[WKWebView alloc] init]; 29 | self.view = webView; 30 | 31 | webView.navigationDelegate = self; 32 | if([webView respondsToSelector:@selector(scrollView)]) 33 | webView.scrollView.decelerationRate = UIScrollViewDecelerationRateNormal; 34 | 35 | NSURL *url = [NSURL URLWithString:self.contribution.websiteAddress]; 36 | NSURLRequest *request = [NSURLRequest requestWithURL:url]; 37 | [webView loadRequest:request]; 38 | 39 | [self showSpinnerInNavigationBar]; 40 | } 41 | 42 | 43 | - (void)showSpinnerInNavigationBar 44 | { 45 | UIActivityIndicatorView *indicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]; 46 | [indicator startAnimating]; 47 | self.navigationItem.titleView = indicator; 48 | } 49 | 50 | - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler{ 51 | 52 | if (navigationAction.navigationType == WKNavigationTypeLinkActivated) { 53 | NSString *title = NSLocalizedString(@"Open in Safari", @"Open in Safari popover title"); 54 | NSString *messageFormat = NSLocalizedString(@"Open '%@' in Safari", @"Open in Safari popover body format"); 55 | NSString *message = [NSString stringWithFormat:messageFormat, navigationAction.request.URL.absoluteString]; 56 | self.urlForAlertView = navigationAction.request.URL; 57 | 58 | UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:title message:message delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"Open in Safari", nil]; 59 | [alertView show]; 60 | 61 | decisionHandler(WKNavigationActionPolicyCancel); 62 | } 63 | 64 | decisionHandler(WKNavigationActionPolicyAllow); 65 | } 66 | 67 | - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation 68 | { 69 | self.navigationItem.titleView = nil; 70 | } 71 | 72 | - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex 73 | { 74 | if(buttonIndex != 0) { 75 | [[UIApplication sharedApplication] openURL:self.urlForAlertView]; 76 | } 77 | } 78 | 79 | 80 | @end -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CPDAcknowledgements 2 | 3 | [![Version](http://cocoapod-badges.herokuapp.com/v/CPDAcknowledgements/badge.png)](http://cocoadocs.org/docsets/CPDAcknowledgements) 4 | [![Platform](http://cocoapod-badges.herokuapp.com/p/CPDAcknowledgements/badge.png)](http://cocoadocs.org/docsets/CPDAcknowledgements) 5 | 6 | ## What is CPDAcknowledgements 7 | 8 | CPDAcknowledgements is a collection of View Controllers for iOS projects in order to easily provide acknowledgements for the libraries used in your apps. 9 | 10 | 11 | 12 | 13 | 14 | It exposes an API which allows you to easily add individual contributors, and libraries. You can also customise the style of the pages with ease. 15 | 16 | ``` objc 17 | CPDContribution *orta = [[CPDContribution alloc] initWithName:@"Orta" websiteAddress:@"http://orta.github.io" role:@"Behind a wheel"]; 18 | orta.avatarAddress = @"https://1.gravatar.com/avatar/f116cb3be23153ec08b94e8bd4dbcfeb?d=https%3A%2F%2Fidenticons.github.com%2F243e8373034964abf7c8a8e57d4df724.png&r=x&s=86"; 19 | 20 | CPDContribution *fabio = [[CPDContribution alloc] initWithName:@"Fabio Pelosin" websiteAddress:@"http://twitter.com/fabiopelosin" role:@"Back Seat Driver"]; 21 | fabio.avatarAddress = @"https://0.gravatar.com/avatar/b6dde1a78e6215a592768c1e78a54adc?d=https%3A%2F%2Fidenticons.github.com%2Fbdc4e72be51d566c2fc9564ed8182611.png&r=x&s=86"; 22 | 23 | CPDContribution *kyle = [[CPDContribution alloc] initWithName:@"Kyle Fuller" websiteAddress:@"http://twitter.com/kylefuller" role:@"Somewhere in the boot"]; 24 | NSArray *contributors = @[orta, fabio, kyle]; 25 | 26 | CPDAcknowledgementsViewController *acknowledgementsViewController = [[CPDAcknowledgementsViewController alloc] initWithStyle:nil acknowledgements:nil contributions:contributors]; 27 | UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:acknowledgementsViewController]; 28 | ``` 29 | 30 | ## Demo Project 31 | 32 | To run the example project; clone the repo, and run `pod install` from the Project directory first or run `pod try CPDAcknowledgements` 33 | 34 | ## Installation 35 | 36 | CPDAcknowledgements will be available through [CocoaPods](http://cocoapods.org), to install 37 | it simply add the following line to your Podfile: 38 | 39 | ``` ruby 40 | pod "CPDAcknowledgements" 41 | ``` 42 | 43 | You will need to have the `plugin "cocoapods-acknowledgements"` inside your Podfile, this is what the demo project's Podfile looks like, for example. 44 | 45 | ``` ruby 46 | plugin 'cocoapods-acknowledgements' 47 | 48 | target "Demo Project" do 49 | pod "CPDAcknowledgements", :path => "../CPDAcknowledgements.podspec" 50 | 51 | # These pods are used only for giving us some data 52 | pod "ORStackView" 53 | pod "IRFEmojiCheatSheet" 54 | 55 | target "Demo ProjectTests" do 56 | inherit! :search_paths 57 | 58 | pod 'Specta', '~> 1.0' 59 | pod 'Expecta', '~> 1.0' 60 | pod 'OCMockito', '~> 1.0' 61 | end 62 | end 63 | ``` 64 | 65 | 66 | 67 | ## Author 68 | 69 | Orta Therox, orta.therox@gmail.com 70 | Fabio Pelosin, fabio.pelosin@gmail.com 71 | 72 | ### Acknowledgements 73 | 74 | Inspiration taken from [@orta/life#12](https://github.com/orta/life/issues/12) and [VTAcknowledgementsViewController](https://github.com/vtourraine/VTAcknowledgementsViewController). 75 | 76 | ## License 77 | 78 | CPDAcknowledgements is available under the MIT license. See the LICENSE file for more info. 79 | -------------------------------------------------------------------------------- /CPDAcknowledgements/CPDLibrary.m: -------------------------------------------------------------------------------- 1 | #import "CPDContribution.h" 2 | #import "CPDLibrary.h" 3 | #import "CPDExternalActionHandler.h" 4 | 5 | @implementation CPDLibrary 6 | 7 | - (instancetype)initWithCocoaPodsMetadataPlistDictionary:(NSDictionary *)dictionary 8 | { 9 | self = [super init]; 10 | if (!self) return nil; 11 | 12 | _title = [dictionary[@"name"] copy]; 13 | _licenseBody = [dictionary[@"licenseText"] copy]; 14 | _licenseType = [dictionary[@"licenseType"] copy]; 15 | 16 | _socialMediaAddress = [dictionary[@"socialMediaURL"] copy]; 17 | _libraryDescription = [dictionary[@"description"] copy]; 18 | _summary = [dictionary[@"summary"] copy]; 19 | _version = [dictionary[@"version"] copy]; 20 | 21 | _authors = [self authorsWithObject:dictionary[@"authors"]]; 22 | 23 | return self; 24 | } 25 | 26 | - (NSArray *)authorsWithObject:(id)object 27 | { 28 | if ([object isKindOfClass:NSDictionary.class]){ 29 | NSMutableArray *authors = [NSMutableArray array]; 30 | 31 | [object enumerateKeysAndObjectsUsingBlock:^(NSString *name, NSString* email, BOOL *stop) { 32 | CPDContribution *contribution = [[CPDContribution alloc] initWithName:name websiteAddress:nil role:@""]; 33 | [authors addObject:contribution]; 34 | }]; 35 | 36 | return authors; 37 | } 38 | 39 | if ([object isKindOfClass:NSString.class]){ 40 | return @[[[CPDContribution alloc] initWithName:object websiteAddress:nil role:@""] ]; 41 | } 42 | 43 | return nil; 44 | } 45 | 46 | - (NSString *)twitterHandle 47 | { 48 | if ([self.socialMediaAddress hasPrefix:@"https://twitter"]){ 49 | return [[self.socialMediaAddress componentsSeparatedByString:@"/"] lastObject]; 50 | } 51 | return nil; 52 | } 53 | 54 | - (BOOL)hasActions 55 | { 56 | return self.websiteAddress.length > 0 || [self.socialMediaAddress hasPrefix:@"https://twitter"]; 57 | } 58 | 59 | - (NSDictionary *)actionsWithSelectors 60 | { 61 | return @{ 62 | NSLocalizedString(@"Open Website", @"Open Website alert text"): NSStringFromSelector(@selector(openLibraryWebsite)), 63 | [NSString stringWithFormat:@"@%@", self.twitterHandle]: NSStringFromSelector(@selector(openTwitterPage)), 64 | }; 65 | } 66 | 67 | - (NSArray *)actionTitlesForLibrary 68 | { 69 | NSMutableArray *actionTitles = [NSMutableArray array]; 70 | if (self.websiteAddress.length > 0){ 71 | [actionTitles addObject:NSLocalizedString(@"Open Website", @"Open Website alert text")]; 72 | } 73 | 74 | if ([self.socialMediaAddress hasPrefix:@"https://twitter"]){ 75 | [actionTitles addObject:[@"@" stringByAppendingString:self.twitterHandle]]; 76 | } 77 | 78 | return actionTitles; 79 | } 80 | 81 | - (void)performActionAtIndex:(NSInteger)index 82 | { 83 | if (self.websiteAddress.length > 0) { index--; } 84 | 85 | NSString *title = self.actionTitlesForLibrary[index]; 86 | NSString *selectorString = self.actionsWithSelectors[title]; 87 | SEL action = NSSelectorFromString(selectorString); 88 | 89 | #pragma clang diagnostic push 90 | #pragma clang diagnostic ignored "-Warc-performSelector-leaks" 91 | [self performSelector:action]; 92 | #pragma clang diagnostic pop 93 | } 94 | 95 | - (void)openTwitterPage 96 | { 97 | [CPDExternalActionHandler openActionForTwitterHandle:self.twitterHandle]; 98 | } 99 | 100 | - (void)openLibraryWebsite 101 | { 102 | [CPDExternalActionHandler openAddressInBrowser:self.websiteAddress]; 103 | } 104 | 105 | @end 106 | -------------------------------------------------------------------------------- /CPDAcknowledgements/CPDAcknowledgementsViewController.m: -------------------------------------------------------------------------------- 1 | #import "CPDLibrary.h" 2 | #import "CPDTableViewDataSource.h" 3 | #import "CPDCocoaPodsLibrariesLoader.h" 4 | #import "CPDAcknowledgementsViewController.h" 5 | #import "CPDLibraryDetailViewController.h" 6 | #import "CPDContribution.h" 7 | #import "CPDContributionDetailViewController.h" 8 | #import "CPDStyle.h" 9 | 10 | @interface CPDAcknowledgementsViewController () 11 | @property (nonatomic, strong) CPDTableViewDataSource *dataSource; 12 | @property (nonatomic, strong) CPDStyle *style; 13 | @end 14 | 15 | @implementation CPDAcknowledgementsViewController 16 | 17 | - (instancetype)init 18 | { 19 | return [self initWithStyle:nil]; 20 | } 21 | 22 | - (instancetype)initWithStyle:(CPDStyle *)style 23 | { 24 | return [self initWithStyle:style acknowledgements:nil contributions:nil]; 25 | } 26 | 27 | - (instancetype)initWithStyle:(CPDStyle *)style acknowledgements:(NSArray *)acknowledgements contributions:(NSArray *)contributions 28 | { 29 | self = [super initWithStyle:UITableViewStyleGrouped]; 30 | if (!self) return nil; 31 | 32 | [self configureAcknowledgements:acknowledgements contributions:contributions]; 33 | _style = style; 34 | 35 | self.title = @"Acknowledgements"; 36 | 37 | return self; 38 | } 39 | 40 | - (instancetype)initWithCoder:(NSCoder *)aDecoder 41 | { 42 | self = [super initWithCoder:aDecoder]; 43 | if (!self) return nil; 44 | 45 | [self configureAcknowledgements:nil contributions:nil]; 46 | 47 | self.title = @"Acknowledgements"; 48 | 49 | return self; 50 | } 51 | 52 | - (void)configureAcknowledgements:(NSArray *)acknowledgements contributions:(NSArray *)contributions 53 | { 54 | if(!acknowledgements){ 55 | NSBundle *bundle = [NSBundle mainBundle]; 56 | acknowledgements = [CPDCocoaPodsLibrariesLoader loadAcknowledgementsWithBundle:bundle]; 57 | } 58 | 59 | _dataSource = [[CPDTableViewDataSource alloc] initWithAcknowledgements:acknowledgements contributions:contributions]; 60 | } 61 | 62 | - (void)loadView 63 | { 64 | [super loadView]; 65 | self.tableView.dataSource = self.dataSource; 66 | } 67 | 68 | - (void)viewWillAppear:(BOOL)animated 69 | { 70 | [super viewWillAppear:animated]; 71 | NSAssert(self.navigationController, @"The AcknowledgementVC needs to be inside a navigation controller."); 72 | 73 | } 74 | 75 | #pragma mark UITableViewDelegate methods 76 | 77 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath; 78 | { 79 | id acknowledgement = [self.dataSource acknowledgementAtIndexPath:indexPath]; 80 | 81 | id detailController; 82 | if ([acknowledgement isKindOfClass:CPDLibrary.class]){ 83 | detailController = [[CPDLibraryDetailViewController alloc] initWithLibrary:acknowledgement]; 84 | [detailController setCSS:self.style.libraryCSS]; 85 | [detailController setHTML:self.style.libraryHTML]; 86 | [detailController setHeaderHTML:self.style.libraryHeaderHTML]; 87 | 88 | } else if([acknowledgement isKindOfClass:CPDContribution.class]){ 89 | CPDContribution *contribution = acknowledgement; 90 | if (contribution.websiteAddress){ 91 | detailController = [[CPDContributionDetailViewController alloc] initWithContribution:contribution]; 92 | } 93 | } 94 | 95 | [self.navigationController pushViewController:detailController animated:YES]; 96 | } 97 | 98 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 99 | { 100 | return [self.dataSource heightForCellAtIndexPath:indexPath]; 101 | } 102 | 103 | @end 104 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | desc "Runs the specs [EMPTY]" 2 | task :spec do 3 | # Provide your own implementation 4 | end 5 | 6 | task :version do 7 | git_remotes = `git remote`.strip.split("\n") 8 | 9 | if git_remotes.count > 0 10 | puts "-- fetching version number from github" 11 | sh 'git fetch' 12 | 13 | remote_version = remote_spec_version 14 | end 15 | 16 | if remote_version.nil? 17 | puts "There is no current released version. You're about to release a new Pod." 18 | version = "0.0.1" 19 | else 20 | puts "The current released version of your pod is " + remote_spec_version.to_s() 21 | version = suggested_version_number 22 | end 23 | 24 | puts "Enter the version you want to release (" + version + ") " 25 | new_version_number = $stdin.gets.strip 26 | if new_version_number == "" 27 | new_version_number = version 28 | end 29 | 30 | replace_version_number(new_version_number) 31 | end 32 | 33 | desc "Release a new version of the Pod" 34 | task :release do 35 | 36 | puts "* Running version" 37 | sh "rake version" 38 | 39 | unless ENV['SKIP_CHECKS'] 40 | if `git symbolic-ref HEAD 2>/dev/null`.strip.split('/').last != 'master' 41 | $stderr.puts "[!] You need to be on the `master' branch in order to be able to do a release." 42 | exit 1 43 | end 44 | 45 | if `git tag`.strip.split("\n").include?(spec_version) 46 | $stderr.puts "[!] A tag for version `#{spec_version}' already exists. Change the version in the podspec" 47 | exit 1 48 | end 49 | 50 | puts "You are about to release `#{spec_version}`, is that correct? [y/n]" 51 | exit if $stdin.gets.strip.downcase != 'y' 52 | end 53 | 54 | puts "* Running specs" 55 | sh "rake spec" 56 | 57 | puts "* Linting the podspec" 58 | sh "pod lib lint" 59 | 60 | # Then release 61 | sh "git commit #{podspec_path} CHANGELOG.md -m 'Release #{spec_version}'" 62 | sh "git tag -a #{spec_version} -m 'Release #{spec_version}'" 63 | sh "git push origin master" 64 | sh "git push origin --tags" 65 | sh "pod push master #{podspec_path}" 66 | end 67 | 68 | # @return [Pod::Version] The version as reported by the Podspec. 69 | # 70 | def spec_version 71 | require 'cocoapods' 72 | spec = Pod::Specification.from_file(podspec_path) 73 | spec.version 74 | end 75 | 76 | # @return [Pod::Version] The version as reported by the Podspec from remote. 77 | # 78 | def remote_spec_version 79 | require 'cocoapods-core' 80 | 81 | if spec_file_exist_on_remote? 82 | remote_spec = eval(`git show origin/master:#{podspec_path}`) 83 | remote_spec.version 84 | else 85 | nil 86 | end 87 | end 88 | 89 | # @return [Bool] If the remote repository has a copy of the podpesc file or not. 90 | # 91 | def spec_file_exist_on_remote? 92 | test_condition = `if git rev-parse --verify --quiet origin/master:#{podspec_path} >/dev/null; 93 | then 94 | echo 'true' 95 | else 96 | echo 'false' 97 | fi` 98 | 99 | 'true' == test_condition.strip 100 | end 101 | 102 | # @return [String] The relative path of the Podspec. 103 | # 104 | def podspec_path 105 | podspecs = Dir.glob('*.podspec') 106 | if podspecs.count == 1 107 | podspecs.first 108 | else 109 | raise "Could not select a podspec" 110 | end 111 | end 112 | 113 | # @return [String] The suggested version number based on the local and remote version numbers. 114 | # 115 | def suggested_version_number 116 | if spec_version != remote_spec_version 117 | spec_version.to_s() 118 | else 119 | next_version(spec_version).to_s() 120 | end 121 | end 122 | 123 | # @param [Pod::Version] version 124 | # the version for which you need the next version 125 | # 126 | # @note It is computed by bumping the last component of the versino string by 1. 127 | # 128 | # @return [Pod::Version] The version that comes next after the version supplied. 129 | # 130 | def next_version(version) 131 | version_components = version.to_s().split("."); 132 | last = (version_components.last.to_i() + 1).to_s 133 | version_components[-1] = last 134 | Pod::Version.new(version_components.join(".")) 135 | end 136 | 137 | # @param [String] new_version_number 138 | # the new version number 139 | # 140 | # @note This methods replaces the version number in the podspec file with a new version number. 141 | # 142 | # @return void 143 | # 144 | def replace_version_number(new_version_number) 145 | text = File.read(podspec_path) 146 | text.gsub!(/(s.version( )*= ")#{spec_version}(")/, "\\1#{new_version_number}\\3") 147 | File.open(podspec_path, "w") { |file| file.puts text } 148 | end -------------------------------------------------------------------------------- /Project/DemoTests/CPDLibraryTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // CPDLibraryTests 3 | // Created by orta on 19/01/2014. 4 | // 5 | // Copyright (c) 2014 http://artsy.net. All rights reserved. 6 | 7 | #import 8 | #import "CPDLibrary.h" 9 | 10 | CPDLibrary *libraryWithDictionary(NSDictionary *dictionary); 11 | 12 | SpecBegin(CPDLibrary) 13 | 14 | describe(@"loading from dictionary", ^{ 15 | it(@"sets expected values", ^{ 16 | CPDLibrary *library = libraryWithDictionary( @{ 17 | @"CPDName": @"Name", 18 | @"CPDLicenseText": @"LicenseText", 19 | @"CPDLicenseType": @"LicenseType", 20 | @"CPDSocialMediaURL": @"SocialMediaURL", 21 | @"CPDDescription": @"Description", 22 | @"CPDVersion": @"Version", 23 | @"CPDSummary" : @"Summary" 24 | }); 25 | 26 | expect(library.title).to.equal(@"Name"); 27 | expect(library.licenseBody).to.equal(@"LicenseText"); 28 | expect(library.licenseType).to.equal(@"LicenseType"); 29 | expect(library.socialMediaAddress).to.equal(@"SocialMediaURL"); 30 | expect(library.libraryDescription).to.equal(@"Description"); 31 | expect(library.version).to.equal(@"Version"); 32 | expect(library.summary).to.equal(@"Summary"); 33 | 34 | }); 35 | 36 | it(@"handles NSString author name correctly", ^{ 37 | CPDLibrary *library = libraryWithDictionary( @{ 38 | @"CPDAuthors": @"Name", 39 | }); 40 | 41 | expect(library.authors.count).to.equal(1); 42 | expect([library.authors[0] name]).to.equal(@"Name"); 43 | }); 44 | 45 | it(@"handles NSDictionary authors correctly", ^{ 46 | CPDLibrary *library = libraryWithDictionary( @{ 47 | @"CPDAuthors": @{ @"Key": @"Value" }, 48 | }); 49 | 50 | expect(library.authors.count).to.equal(1); 51 | expect([library.authors[0] name]).to.equal(@"Key"); 52 | expect([library.authors[0] websiteAddress]).to.equal(@"mailto:Value"); 53 | }); 54 | 55 | it(@"handles multiple NSDictionary authors correctly", ^{ 56 | CPDLibrary *library = libraryWithDictionary( @{ 57 | @"CPDAuthors": @{ @"Key": @"Value", @"Key2" : @"Value2" }, 58 | }); 59 | expect(library.authors.count).to.equal(2); 60 | }); 61 | }); 62 | 63 | describe(@"action items", ^{ 64 | it(@"shows twitter urls for social", ^{ 65 | 66 | CPDLibrary *library = libraryWithDictionary( @{ 67 | @"CPDSocialMediaURL": @"https://twitter.com/orta" 68 | }); 69 | 70 | NSArray *actions = library.actionTitlesForLibrary; 71 | expect(actions.count).to.equal(1); 72 | expect(actions[0]).to.equal(@"@orta"); 73 | }); 74 | 75 | // it(@"shows website if one exists", ^{ 76 | // CPDLibrary *library = libraryWithDictionary( @{ 77 | // @"CPDSocialMediaURL": @"https://twitter.com/orta" 78 | // }); 79 | // 80 | // NSArray *actions = library.actionTitlesForLibrary; 81 | // expect(actions.count).to.equal(1); 82 | // expect(actions[0]).to.equal(@"@orta"); 83 | // }); 84 | 85 | describe(@"with a project author", ^{ 86 | it(@" says email author for 1 author", ^{ 87 | CPDLibrary *library = libraryWithDictionary( @{ 88 | @"CPDAuthors": @"Name", 89 | }); 90 | 91 | NSArray *actions = library.actionTitlesForLibrary; 92 | expect(actions.count).to.equal(1); 93 | expect(actions[0]).to.contain(@"Author"); 94 | }); 95 | 96 | it(@" says email author for 1 author", ^{ 97 | CPDLibrary *library = libraryWithDictionary( @{ 98 | @"CPDAuthors": @{ @"Key": @"Value", @"Key2" : @"Value2" }, 99 | }); 100 | 101 | NSArray *actions = library.actionTitlesForLibrary; 102 | expect(actions.count).to.equal(1); 103 | expect(actions[0]).to.contain(@"Authors"); 104 | }); 105 | }); 106 | 107 | describe(@"calling actions", ^{ 108 | CPDLibrary *library = libraryWithDictionary( @{ 109 | @"CPDSocialMediaURL": @"https://twitter.com/orta", 110 | @"CPDAuthors": @{ @"Key": @"Value", @"Key2" : @"Value2"} , 111 | }); 112 | 113 | NSString *mailIndex = 0; 114 | 115 | it(@"handles opening emails", ^{ 116 | 117 | }); 118 | }); 119 | }); 120 | 121 | 122 | SpecEnd 123 | 124 | CPDLibrary *libraryWithDictionary(NSDictionary *dictionary){ 125 | return [[CPDLibrary alloc] initWithCocoaPodsMetadataPlistDictionary:dictionary]; 126 | } -------------------------------------------------------------------------------- /CPDAcknowledgements/private/CPDTableViewDataSource.m: -------------------------------------------------------------------------------- 1 | #import "CPDTableViewDataSource.h" 2 | #import "CPDLibrary.h" 3 | #import "CPDContribution.h" 4 | 5 | static const NSString *CPDTitle = @"CPDTitle"; 6 | static const NSString *CPDEntries = @"CPDEntries"; 7 | 8 | @interface CPDTableViewDataSource() 9 | @property (nonatomic, strong) NSMutableArray *sections; 10 | @end 11 | 12 | @implementation CPDTableViewDataSource 13 | 14 | - (id)initWithAcknowledgements:(NSArray *)acknowledgements contributions:(NSArray *)contributions 15 | { 16 | self = [super init]; 17 | if (!self) return nil; 18 | 19 | _sections = [NSMutableArray array]; 20 | 21 | if (contributions){ 22 | [_sections addObject:@{ 23 | CPDTitle: NSLocalizedString(@"Contributions", @"Contributions in detail view"), 24 | CPDEntries: contributions, 25 | }]; 26 | } 27 | 28 | if (acknowledgements){ 29 | [_sections addObject:@{ 30 | CPDTitle: NSLocalizedString(@"Libraries", @"Libraries in detail view"), 31 | CPDEntries: acknowledgements, 32 | }]; 33 | } 34 | 35 | return self; 36 | } 37 | 38 | #pragma mark UITableViewDataSource methods 39 | 40 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 41 | { 42 | return self.sections.count; 43 | } 44 | 45 | - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section 46 | { 47 | NSDictionary *sectionInfo = self.sections[(NSUInteger) section]; 48 | return sectionInfo[CPDTitle]; 49 | } 50 | 51 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 52 | { 53 | NSDictionary *sectionInfo = self.sections[(NSUInteger) section]; 54 | return [sectionInfo[CPDEntries] count]; 55 | } 56 | 57 | - (CGFloat)heightForCellAtIndexPath:(NSIndexPath *)indexPath 58 | { 59 | id item = [self acknowledgementAtIndexPath:indexPath]; 60 | return [item isKindOfClass:CPDContribution.class] ? 60 : 44; 61 | } 62 | 63 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 64 | { 65 | id item = [self acknowledgementAtIndexPath:indexPath]; 66 | NSString *identifier = NSStringFromClass([item class]); 67 | 68 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier]; 69 | if (!cell) { 70 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:identifier]; 71 | cell.separatorInset = UIEdgeInsetsZero; 72 | } 73 | 74 | if ([item isKindOfClass:CPDLibrary.class]){ 75 | cell.textLabel.text = [item title]; 76 | cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; 77 | 78 | } else if ([item isKindOfClass:CPDContribution.class]){ 79 | [self configureCell:cell withContribution:item]; 80 | } 81 | 82 | return cell; 83 | } 84 | 85 | - (void)configureCell:(UITableViewCell *)cell withContribution:(CPDContribution *)contribution 86 | { 87 | cell.textLabel.text = [contribution name]; 88 | cell.detailTextLabel.text = [contribution role]; 89 | cell.detailTextLabel.textColor = [UIColor grayColor]; 90 | 91 | BOOL supportsFullViewController = (contribution.websiteAddress != nil); 92 | cell.accessoryType = supportsFullViewController ? UITableViewCellAccessoryDisclosureIndicator : UITableViewCellAccessoryNone; 93 | cell.selectionStyle = supportsFullViewController ? UITableViewCellSelectionStyleGray : UITableViewCellSelectionStyleNone; 94 | 95 | if ([contribution avatarAddress]){ 96 | [self setImageAsyncForCell:cell contribution:contribution]; 97 | } 98 | } 99 | 100 | - (void)setImageAsyncForCell:(UITableViewCell *)cell contribution:(CPDContribution *)contribution 101 | { 102 | UIImageView *imageView = cell.imageView; 103 | imageView.layer.cornerRadius = 46; 104 | imageView.layer.masksToBounds = YES; 105 | imageView.transform = CGAffineTransformMakeScale(0.45, 0.45); 106 | 107 | dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0ul); 108 | dispatch_async(queue, ^{ 109 | NSURL *imageURL = [NSURL URLWithString:[contribution avatarAddress]]; 110 | NSData *data = [NSData dataWithContentsOfURL:imageURL]; 111 | dispatch_async(dispatch_get_main_queue(), ^{ 112 | UIImage *image = [UIImage imageWithData:data]; 113 | imageView.image = image; 114 | [cell setNeedsLayout]; 115 | }); 116 | }); 117 | } 118 | 119 | - (CPDLibrary *)acknowledgementAtIndexPath:(NSIndexPath *)indexPath 120 | { 121 | NSDictionary *section = self.sections[(NSUInteger) indexPath.section]; 122 | return section[CPDEntries][(NSUInteger) indexPath.row]; 123 | } 124 | 125 | @end 126 | -------------------------------------------------------------------------------- /CPDAcknowledgements/private/CPDLibraryDetailViewController.m: -------------------------------------------------------------------------------- 1 | #import "CPDLibraryDetailViewController.h" 2 | #import "CPDLibrary.h" 3 | 4 | @import WebKit; 5 | 6 | @interface CPDLibraryDetailViewController () 7 | @property (nonatomic, strong) WKWebView *view; 8 | @property (readonly, nonatomic, strong) CPDLibrary *library; 9 | @end 10 | 11 | @implementation CPDLibraryDetailViewController 12 | 13 | @dynamic view; 14 | 15 | - (id)initWithLibrary:(CPDLibrary *)library 16 | { 17 | self = [super init]; 18 | if (!self) return nil; 19 | 20 | _library = library; 21 | self.title = _library.title; 22 | 23 | return self; 24 | } 25 | 26 | - (void)viewWillAppear:(BOOL)animated 27 | { 28 | [super viewWillAppear:animated]; 29 | 30 | if (self.library.hasActions) { 31 | UIBarButtonItem *shareButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAction target:self action:@selector(shareTapped:)]; 32 | self.navigationItem.rightBarButtonItem = shareButton; 33 | } 34 | } 35 | 36 | - (void)shareTapped:(UIBarButtonItem *)sender 37 | { 38 | UIActionSheet *actionSheet = [[UIActionSheet alloc] init]; 39 | actionSheet.delegate = self; 40 | 41 | [self.library.actionTitlesForLibrary enumerateObjectsUsingBlock:^(NSString *title, NSUInteger idx, BOOL *stop) { 42 | [actionSheet addButtonWithTitle:title]; 43 | }]; 44 | 45 | [actionSheet addButtonWithTitle:@"Cancel"]; 46 | [actionSheet setCancelButtonIndex:actionSheet.numberOfButtons - 1]; 47 | [actionSheet showFromBarButtonItem:sender animated:YES]; 48 | } 49 | 50 | - (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex 51 | { 52 | if(buttonIndex == actionSheet.cancelButtonIndex) return; 53 | 54 | [self.library performActionAtIndex:buttonIndex]; 55 | } 56 | 57 | - (void)loadView 58 | { 59 | self.view = [self createWebview];; 60 | [self openLicenseInWebview:self.view]; 61 | } 62 | 63 | - (void)openLicenseInWebview:(WKWebView *)webView 64 | { 65 | NSString *html = self.HTML ?: [self.class defaultHTMLTemplate]; 66 | NSString *headerHTML = self.headerHTML ?: [self.class defaultHeaderTemplate]; 67 | NSString *css = self.CSS ?: [self.class defaultCSS]; 68 | NSString *renderedHTML = [self.class generatedHTMLWithHTML:html headerHTML:headerHTML CSS:css acknowledgement:self.library]; 69 | 70 | [webView loadHTMLString:renderedHTML baseURL:nil]; 71 | } 72 | 73 | - (WKWebView *)createWebview 74 | { 75 | WKWebView *webView = [[WKWebView alloc] init]; 76 | webView.backgroundColor = [UIColor whiteColor]; 77 | webView.opaque = NO; 78 | webView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth; 79 | 80 | 81 | if([webView respondsToSelector:@selector(scrollView)]) 82 | webView.scrollView.decelerationRate = UIScrollViewDecelerationRateNormal; 83 | 84 | return webView; 85 | } 86 | 87 | + (NSString *)generatedHTMLWithHTML:(NSString *)html headerHTML:(NSString *)headerHTML CSS:(NSString *)css acknowledgement:(CPDLibrary *)acknowledgement 88 | { 89 | NSMutableString *mutableHTML = [html mutableCopy]; 90 | 91 | NSString *summary = acknowledgement.libraryDescription.length > 0 ? acknowledgement.libraryDescription : acknowledgement.summary; 92 | 93 | [mutableHTML replaceOccurrencesOfString:@"{{STYLESHEET}}" withString:css options:0 range:NSMakeRange(0, mutableHTML.length)]; 94 | NSString *htmlLicense = [acknowledgement.licenseBody stringByReplacingOccurrencesOfString:@"\n\n" withString:@"

"]; 95 | 96 | [mutableHTML replaceOccurrencesOfString:@"{{BODY}}" withString:htmlLicense options:0 range:NSMakeRange(0, mutableHTML.length)]; 97 | [mutableHTML replaceOccurrencesOfString:@"{{HEADER}}" withString:headerHTML options:0 range:NSMakeRange(0, mutableHTML.length)]; 98 | 99 | [mutableHTML replaceOccurrencesOfString:@"{{SUMMARY}}" withString:summary options:0 range:NSMakeRange(0, mutableHTML.length)]; 100 | [mutableHTML replaceOccurrencesOfString:@"{{VERSION}}" withString:acknowledgement.version options:0 range:NSMakeRange(0, mutableHTML.length)]; 101 | [mutableHTML replaceOccurrencesOfString:@"{{SHORT_LICENSE}}" withString:acknowledgement.licenseType options:0 range:NSMakeRange(0, mutableHTML.length)]; 102 | 103 | return [mutableHTML copy]; 104 | } 105 | 106 | + (NSString *)defaultHTMLTemplate 107 | { 108 | return @"{{STYLESHEET}}{{HEADER}}

{{BODY}}

"; 109 | } 110 | 111 | 112 | + (NSString *)defaultHeaderTemplate 113 | { 114 | return @"

{{SUMMARY}}

{{VERSION}}

{{SHORT_LICENSE}}


"; 115 | } 116 | 117 | + (NSString *)defaultCSS 118 | { 119 | return @""; 123 | } 124 | 125 | @end 126 | -------------------------------------------------------------------------------- /Project/Demo Project.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1DD00FB91CA5D40800F717AD /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1DD00FB81CA5D40800F717AD /* WebKit.framework */; }; 11 | 342F9EBDA81A787D5ED68844 /* CPDLibraryTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 342F94FCBD3B4E6AED697FE4 /* CPDLibraryTests.m */; }; 12 | 5E05DE4C73BFC16313B12C48 /* libPods-Demo Project.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1F53DE9542605F5DD0F6C920 /* libPods-Demo Project.a */; }; 13 | 600F98FE18896F8C00896B83 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 600F98FD18896F8C00896B83 /* Foundation.framework */; }; 14 | 600F990018896F8C00896B83 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 600F98FF18896F8C00896B83 /* CoreGraphics.framework */; }; 15 | 600F990218896F8C00896B83 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 600F990118896F8C00896B83 /* UIKit.framework */; }; 16 | 600F990818896F8C00896B83 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 600F990618896F8C00896B83 /* InfoPlist.strings */; }; 17 | 600F990A18896F8C00896B83 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 600F990918896F8C00896B83 /* main.m */; }; 18 | 600F990E18896F8C00896B83 /* CPDAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 600F990D18896F8C00896B83 /* CPDAppDelegate.m */; }; 19 | 600F991618896F8C00896B83 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 600F991518896F8C00896B83 /* Images.xcassets */; }; 20 | 600F991D18896F8C00896B83 /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 600F991C18896F8C00896B83 /* XCTest.framework */; }; 21 | 600F991E18896F8C00896B83 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 600F98FD18896F8C00896B83 /* Foundation.framework */; }; 22 | 600F991F18896F8C00896B83 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 600F990118896F8C00896B83 /* UIKit.framework */; }; 23 | 600F992718896F8C00896B83 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 600F992518896F8C00896B83 /* InfoPlist.strings */; }; 24 | 60CD4D411889755D00B05988 /* CPDAcknowledgementLoaderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 60CD4D401889755D00B05988 /* CPDAcknowledgementLoaderTests.m */; }; 25 | A435F80FA9F44903AD0DA689 /* Pods-Demo Project-metadata.plist in Resources */ = {isa = PBXBuildFile; fileRef = 7591EBACBB9945269F29C20E /* Pods-Demo Project-metadata.plist */; }; 26 | FC63C3BDF94BFC662F680FA0 /* libPods-Demo ProjectTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8890379CD1ABE9052565D71C /* libPods-Demo ProjectTests.a */; }; 27 | FE62E41A3EAB430AB94607EE /* Pods-Demo ProjectTests-metadata.plist in Resources */ = {isa = PBXBuildFile; fileRef = 1891B092BA7F47F5AF73E4FA /* Pods-Demo ProjectTests-metadata.plist */; }; 28 | /* End PBXBuildFile section */ 29 | 30 | /* Begin PBXContainerItemProxy section */ 31 | 600F992018896F8C00896B83 /* PBXContainerItemProxy */ = { 32 | isa = PBXContainerItemProxy; 33 | containerPortal = 600F98F218896F8C00896B83 /* Project object */; 34 | proxyType = 1; 35 | remoteGlobalIDString = 600F98F918896F8C00896B83; 36 | remoteInfo = CPDAcknowledgements; 37 | }; 38 | /* End PBXContainerItemProxy section */ 39 | 40 | /* Begin PBXFileReference section */ 41 | 1891B092BA7F47F5AF73E4FA /* Pods-Demo ProjectTests-metadata.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; name = "Pods-Demo ProjectTests-metadata.plist"; path = "Pods/Pods-Demo ProjectTests-metadata.plist"; sourceTree = ""; }; 42 | 1DD00FB81CA5D40800F717AD /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; }; 43 | 1F53DE9542605F5DD0F6C920 /* libPods-Demo Project.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Demo Project.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 44 | 342F94FCBD3B4E6AED697FE4 /* CPDLibraryTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CPDLibraryTests.m; sourceTree = ""; }; 45 | 3F723B5B19941F9506703F03 /* Pods-Demo ProjectTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Demo ProjectTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-Demo ProjectTests/Pods-Demo ProjectTests.release.xcconfig"; sourceTree = ""; }; 46 | 600F98FA18896F8C00896B83 /* Demo Project.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Demo Project.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 47 | 600F98FD18896F8C00896B83 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 48 | 600F98FF18896F8C00896B83 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 49 | 600F990118896F8C00896B83 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 50 | 600F990518896F8C00896B83 /* Demo Project-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Demo Project-Info.plist"; sourceTree = ""; }; 51 | 600F990718896F8C00896B83 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 52 | 600F990918896F8C00896B83 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 53 | 600F990B18896F8C00896B83 /* Demo Project-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Demo Project-Prefix.pch"; sourceTree = ""; }; 54 | 600F990C18896F8C00896B83 /* CPDAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CPDAppDelegate.h; sourceTree = ""; }; 55 | 600F990D18896F8C00896B83 /* CPDAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CPDAppDelegate.m; sourceTree = ""; }; 56 | 600F991518896F8C00896B83 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 57 | 600F991B18896F8C00896B83 /* Demo ProjectTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Demo ProjectTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 58 | 600F991C18896F8C00896B83 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; 59 | 600F992418896F8C00896B83 /* Demo ProjectTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Demo ProjectTests-Info.plist"; sourceTree = ""; }; 60 | 600F992618896F8C00896B83 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 61 | 60786E1D1889A0F900DB7AF2 /* TODO */ = {isa = PBXFileReference; lastKnownFileType = text; name = TODO; path = Demo/TODO; sourceTree = ""; }; 62 | 60786E201889A14800DB7AF2 /* CHANGELOG.md */ = {isa = PBXFileReference; lastKnownFileType = text; name = CHANGELOG.md; path = ../CHANGELOG.md; sourceTree = ""; }; 63 | 60786E211889A14800DB7AF2 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = text; name = README.md; path = ../README.md; sourceTree = ""; }; 64 | 60CD4D401889755D00B05988 /* CPDAcknowledgementLoaderTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CPDAcknowledgementLoaderTests.m; sourceTree = ""; }; 65 | 60CD4D42188975EC00B05988 /* Demo ProjectTests-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Demo ProjectTests-Prefix.pch"; sourceTree = ""; }; 66 | 60F70A6C1CB93CE400B42FD9 /* CPDAcknowledgements.podspec */ = {isa = PBXFileReference; lastKnownFileType = text; name = CPDAcknowledgements.podspec; path = ../CPDAcknowledgements.podspec; sourceTree = ""; }; 67 | 703A91C7447D18F3EBE10F25 /* Pods-Demo ProjectTests-metadata.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; name = "Pods-Demo ProjectTests-metadata.plist"; path = "Pods/Pods-Demo ProjectTests-metadata.plist"; sourceTree = ""; }; 68 | 7591EBACBB9945269F29C20E /* Pods-Demo Project-metadata.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; name = "Pods-Demo Project-metadata.plist"; path = "Pods/Pods-Demo Project-metadata.plist"; sourceTree = ""; }; 69 | 8890379CD1ABE9052565D71C /* libPods-Demo ProjectTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Demo ProjectTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 70 | A00E52103B8B81B9C64488D0 /* Pods-Demo Project-metadata.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; name = "Pods-Demo Project-metadata.plist"; path = "Pods/Pods-Demo Project-metadata.plist"; sourceTree = ""; }; 71 | C03DE825D677BF2C8F4C6060 /* Pods-Demo ProjectTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Demo ProjectTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Demo ProjectTests/Pods-Demo ProjectTests.debug.xcconfig"; sourceTree = ""; }; 72 | C60D1451F3DF087E92171FBA /* Pods-Demo Project.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Demo Project.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Demo Project/Pods-Demo Project.debug.xcconfig"; sourceTree = ""; }; 73 | FC1FDCC999FEC4A3AB4D382B /* Pods-Demo Project.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Demo Project.release.xcconfig"; path = "Pods/Target Support Files/Pods-Demo Project/Pods-Demo Project.release.xcconfig"; sourceTree = ""; }; 74 | /* End PBXFileReference section */ 75 | 76 | /* Begin PBXFrameworksBuildPhase section */ 77 | 600F98F718896F8C00896B83 /* Frameworks */ = { 78 | isa = PBXFrameworksBuildPhase; 79 | buildActionMask = 2147483647; 80 | files = ( 81 | 1DD00FB91CA5D40800F717AD /* WebKit.framework in Frameworks */, 82 | 600F990018896F8C00896B83 /* CoreGraphics.framework in Frameworks */, 83 | 600F990218896F8C00896B83 /* UIKit.framework in Frameworks */, 84 | 600F98FE18896F8C00896B83 /* Foundation.framework in Frameworks */, 85 | 5E05DE4C73BFC16313B12C48 /* libPods-Demo Project.a in Frameworks */, 86 | ); 87 | runOnlyForDeploymentPostprocessing = 0; 88 | }; 89 | 600F991818896F8C00896B83 /* Frameworks */ = { 90 | isa = PBXFrameworksBuildPhase; 91 | buildActionMask = 2147483647; 92 | files = ( 93 | 600F991D18896F8C00896B83 /* XCTest.framework in Frameworks */, 94 | 600F991F18896F8C00896B83 /* UIKit.framework in Frameworks */, 95 | 600F991E18896F8C00896B83 /* Foundation.framework in Frameworks */, 96 | FC63C3BDF94BFC662F680FA0 /* libPods-Demo ProjectTests.a in Frameworks */, 97 | ); 98 | runOnlyForDeploymentPostprocessing = 0; 99 | }; 100 | /* End PBXFrameworksBuildPhase section */ 101 | 102 | /* Begin PBXGroup section */ 103 | 600F98F118896F8C00896B83 = { 104 | isa = PBXGroup; 105 | children = ( 106 | 60F70A6C1CB93CE400B42FD9 /* CPDAcknowledgements.podspec */, 107 | 60786E201889A14800DB7AF2 /* CHANGELOG.md */, 108 | 60786E211889A14800DB7AF2 /* README.md */, 109 | 60786E1D1889A0F900DB7AF2 /* TODO */, 110 | 600F990318896F8C00896B83 /* Demo */, 111 | 600F992218896F8C00896B83 /* Tests */, 112 | 600F98FC18896F8C00896B83 /* Frameworks */, 113 | 600F98FB18896F8C00896B83 /* Products */, 114 | 60CD4D351889736B00B05988 /* CocoaPods */, 115 | FC5327A8FB2CC8018057D7F8 /* Pods */, 116 | ); 117 | sourceTree = ""; 118 | }; 119 | 600F98FB18896F8C00896B83 /* Products */ = { 120 | isa = PBXGroup; 121 | children = ( 122 | 600F98FA18896F8C00896B83 /* Demo Project.app */, 123 | 600F991B18896F8C00896B83 /* Demo ProjectTests.xctest */, 124 | ); 125 | name = Products; 126 | sourceTree = ""; 127 | }; 128 | 600F98FC18896F8C00896B83 /* Frameworks */ = { 129 | isa = PBXGroup; 130 | children = ( 131 | 1DD00FB81CA5D40800F717AD /* WebKit.framework */, 132 | 600F98FD18896F8C00896B83 /* Foundation.framework */, 133 | 600F98FF18896F8C00896B83 /* CoreGraphics.framework */, 134 | 600F990118896F8C00896B83 /* UIKit.framework */, 135 | 600F991C18896F8C00896B83 /* XCTest.framework */, 136 | 1F53DE9542605F5DD0F6C920 /* libPods-Demo Project.a */, 137 | 8890379CD1ABE9052565D71C /* libPods-Demo ProjectTests.a */, 138 | ); 139 | name = Frameworks; 140 | sourceTree = ""; 141 | }; 142 | 600F990318896F8C00896B83 /* Demo */ = { 143 | isa = PBXGroup; 144 | children = ( 145 | 600F990C18896F8C00896B83 /* CPDAppDelegate.h */, 146 | 600F990D18896F8C00896B83 /* CPDAppDelegate.m */, 147 | 600F991518896F8C00896B83 /* Images.xcassets */, 148 | 600F990418896F8C00896B83 /* Supporting Files */, 149 | ); 150 | path = Demo; 151 | sourceTree = ""; 152 | }; 153 | 600F990418896F8C00896B83 /* Supporting Files */ = { 154 | isa = PBXGroup; 155 | children = ( 156 | 600F990B18896F8C00896B83 /* Demo Project-Prefix.pch */, 157 | 600F990518896F8C00896B83 /* Demo Project-Info.plist */, 158 | 600F990618896F8C00896B83 /* InfoPlist.strings */, 159 | 600F990918896F8C00896B83 /* main.m */, 160 | ); 161 | name = "Supporting Files"; 162 | sourceTree = ""; 163 | }; 164 | 600F992218896F8C00896B83 /* Tests */ = { 165 | isa = PBXGroup; 166 | children = ( 167 | 60CD4D42188975EC00B05988 /* Demo ProjectTests-Prefix.pch */, 168 | 60CD4D401889755D00B05988 /* CPDAcknowledgementLoaderTests.m */, 169 | 600F992318896F8C00896B83 /* Supporting Files */, 170 | 342F94FCBD3B4E6AED697FE4 /* CPDLibraryTests.m */, 171 | ); 172 | name = Tests; 173 | path = DemoTests; 174 | sourceTree = ""; 175 | }; 176 | 600F992318896F8C00896B83 /* Supporting Files */ = { 177 | isa = PBXGroup; 178 | children = ( 179 | 600F992418896F8C00896B83 /* Demo ProjectTests-Info.plist */, 180 | 600F992518896F8C00896B83 /* InfoPlist.strings */, 181 | ); 182 | name = "Supporting Files"; 183 | sourceTree = ""; 184 | }; 185 | 60CD4D351889736B00B05988 /* CocoaPods */ = { 186 | isa = PBXGroup; 187 | children = ( 188 | 7591EBACBB9945269F29C20E /* Pods-Demo Project-metadata.plist */, 189 | 1891B092BA7F47F5AF73E4FA /* Pods-Demo ProjectTests-metadata.plist */, 190 | ); 191 | name = CocoaPods; 192 | sourceTree = ""; 193 | }; 194 | FC5327A8FB2CC8018057D7F8 /* Pods */ = { 195 | isa = PBXGroup; 196 | children = ( 197 | A00E52103B8B81B9C64488D0 /* Pods-Demo Project-metadata.plist */, 198 | 703A91C7447D18F3EBE10F25 /* Pods-Demo ProjectTests-metadata.plist */, 199 | C60D1451F3DF087E92171FBA /* Pods-Demo Project.debug.xcconfig */, 200 | FC1FDCC999FEC4A3AB4D382B /* Pods-Demo Project.release.xcconfig */, 201 | C03DE825D677BF2C8F4C6060 /* Pods-Demo ProjectTests.debug.xcconfig */, 202 | 3F723B5B19941F9506703F03 /* Pods-Demo ProjectTests.release.xcconfig */, 203 | ); 204 | name = Pods; 205 | sourceTree = ""; 206 | }; 207 | /* End PBXGroup section */ 208 | 209 | /* Begin PBXNativeTarget section */ 210 | 600F98F918896F8C00896B83 /* Demo Project */ = { 211 | isa = PBXNativeTarget; 212 | buildConfigurationList = 600F992C18896F8C00896B83 /* Build configuration list for PBXNativeTarget "Demo Project" */; 213 | buildPhases = ( 214 | 4B6CFF8F26551B31C58C9DD2 /* 📦 Check Pods Manifest.lock */, 215 | 600F98F618896F8C00896B83 /* Sources */, 216 | 600F98F718896F8C00896B83 /* Frameworks */, 217 | 600F98F818896F8C00896B83 /* Resources */, 218 | 507FB86BDEE4A7D1CD56A2D4 /* 📦 Embed Pods Frameworks */, 219 | C9FD72C672D8EE63A9DD2693 /* 📦 Copy Pods Resources */, 220 | ); 221 | buildRules = ( 222 | ); 223 | dependencies = ( 224 | ); 225 | name = "Demo Project"; 226 | productName = CPDAcknowledgements; 227 | productReference = 600F98FA18896F8C00896B83 /* Demo Project.app */; 228 | productType = "com.apple.product-type.application"; 229 | }; 230 | 600F991A18896F8C00896B83 /* Demo ProjectTests */ = { 231 | isa = PBXNativeTarget; 232 | buildConfigurationList = 600F992F18896F8C00896B83 /* Build configuration list for PBXNativeTarget "Demo ProjectTests" */; 233 | buildPhases = ( 234 | 3D107C7EF6F18036380F8322 /* 📦 Check Pods Manifest.lock */, 235 | 600F991718896F8C00896B83 /* Sources */, 236 | 600F991818896F8C00896B83 /* Frameworks */, 237 | 600F991918896F8C00896B83 /* Resources */, 238 | AE98BF747250A0F93E269347 /* 📦 Embed Pods Frameworks */, 239 | 91D7E2FA6C96D278EF147F51 /* 📦 Copy Pods Resources */, 240 | ); 241 | buildRules = ( 242 | ); 243 | dependencies = ( 244 | 600F992118896F8C00896B83 /* PBXTargetDependency */, 245 | ); 246 | name = "Demo ProjectTests"; 247 | productName = CPDAcknowledgementsTests; 248 | productReference = 600F991B18896F8C00896B83 /* Demo ProjectTests.xctest */; 249 | productType = "com.apple.product-type.bundle.unit-test"; 250 | }; 251 | /* End PBXNativeTarget section */ 252 | 253 | /* Begin PBXProject section */ 254 | 600F98F218896F8C00896B83 /* Project object */ = { 255 | isa = PBXProject; 256 | attributes = { 257 | CLASSPREFIX = CPD; 258 | LastUpgradeCheck = 0500; 259 | ORGANIZATIONNAME = CocoaPods; 260 | TargetAttributes = { 261 | 600F991A18896F8C00896B83 = { 262 | TestTargetID = 600F98F918896F8C00896B83; 263 | }; 264 | }; 265 | }; 266 | buildConfigurationList = 600F98F518896F8C00896B83 /* Build configuration list for PBXProject "Demo Project" */; 267 | compatibilityVersion = "Xcode 3.2"; 268 | developmentRegion = English; 269 | hasScannedForEncodings = 0; 270 | knownRegions = ( 271 | en, 272 | Base, 273 | ); 274 | mainGroup = 600F98F118896F8C00896B83; 275 | productRefGroup = 600F98FB18896F8C00896B83 /* Products */; 276 | projectDirPath = ""; 277 | projectRoot = ""; 278 | targets = ( 279 | 600F98F918896F8C00896B83 /* Demo Project */, 280 | 600F991A18896F8C00896B83 /* Demo ProjectTests */, 281 | ); 282 | }; 283 | /* End PBXProject section */ 284 | 285 | /* Begin PBXResourcesBuildPhase section */ 286 | 600F98F818896F8C00896B83 /* Resources */ = { 287 | isa = PBXResourcesBuildPhase; 288 | buildActionMask = 2147483647; 289 | files = ( 290 | 600F991618896F8C00896B83 /* Images.xcassets in Resources */, 291 | 600F990818896F8C00896B83 /* InfoPlist.strings in Resources */, 292 | A435F80FA9F44903AD0DA689 /* Pods-Demo Project-metadata.plist in Resources */, 293 | ); 294 | runOnlyForDeploymentPostprocessing = 0; 295 | }; 296 | 600F991918896F8C00896B83 /* Resources */ = { 297 | isa = PBXResourcesBuildPhase; 298 | buildActionMask = 2147483647; 299 | files = ( 300 | 600F992718896F8C00896B83 /* InfoPlist.strings in Resources */, 301 | FE62E41A3EAB430AB94607EE /* Pods-Demo ProjectTests-metadata.plist in Resources */, 302 | ); 303 | runOnlyForDeploymentPostprocessing = 0; 304 | }; 305 | /* End PBXResourcesBuildPhase section */ 306 | 307 | /* Begin PBXShellScriptBuildPhase section */ 308 | 3D107C7EF6F18036380F8322 /* 📦 Check Pods Manifest.lock */ = { 309 | isa = PBXShellScriptBuildPhase; 310 | buildActionMask = 2147483647; 311 | files = ( 312 | ); 313 | inputPaths = ( 314 | ); 315 | name = "📦 Check Pods Manifest.lock"; 316 | outputPaths = ( 317 | ); 318 | runOnlyForDeploymentPostprocessing = 0; 319 | shellPath = /bin/sh; 320 | shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; 321 | showEnvVarsInLog = 0; 322 | }; 323 | 4B6CFF8F26551B31C58C9DD2 /* 📦 Check Pods Manifest.lock */ = { 324 | isa = PBXShellScriptBuildPhase; 325 | buildActionMask = 2147483647; 326 | files = ( 327 | ); 328 | inputPaths = ( 329 | ); 330 | name = "📦 Check Pods Manifest.lock"; 331 | outputPaths = ( 332 | ); 333 | runOnlyForDeploymentPostprocessing = 0; 334 | shellPath = /bin/sh; 335 | shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; 336 | showEnvVarsInLog = 0; 337 | }; 338 | 507FB86BDEE4A7D1CD56A2D4 /* 📦 Embed Pods Frameworks */ = { 339 | isa = PBXShellScriptBuildPhase; 340 | buildActionMask = 2147483647; 341 | files = ( 342 | ); 343 | inputPaths = ( 344 | ); 345 | name = "📦 Embed Pods Frameworks"; 346 | outputPaths = ( 347 | ); 348 | runOnlyForDeploymentPostprocessing = 0; 349 | shellPath = /bin/sh; 350 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Demo Project/Pods-Demo Project-frameworks.sh\"\n"; 351 | showEnvVarsInLog = 0; 352 | }; 353 | 91D7E2FA6C96D278EF147F51 /* 📦 Copy Pods Resources */ = { 354 | isa = PBXShellScriptBuildPhase; 355 | buildActionMask = 2147483647; 356 | files = ( 357 | ); 358 | inputPaths = ( 359 | ); 360 | name = "📦 Copy Pods Resources"; 361 | outputPaths = ( 362 | ); 363 | runOnlyForDeploymentPostprocessing = 0; 364 | shellPath = /bin/sh; 365 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Demo ProjectTests/Pods-Demo ProjectTests-resources.sh\"\n"; 366 | showEnvVarsInLog = 0; 367 | }; 368 | AE98BF747250A0F93E269347 /* 📦 Embed Pods Frameworks */ = { 369 | isa = PBXShellScriptBuildPhase; 370 | buildActionMask = 2147483647; 371 | files = ( 372 | ); 373 | inputPaths = ( 374 | ); 375 | name = "📦 Embed Pods Frameworks"; 376 | outputPaths = ( 377 | ); 378 | runOnlyForDeploymentPostprocessing = 0; 379 | shellPath = /bin/sh; 380 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Demo ProjectTests/Pods-Demo ProjectTests-frameworks.sh\"\n"; 381 | showEnvVarsInLog = 0; 382 | }; 383 | C9FD72C672D8EE63A9DD2693 /* 📦 Copy Pods Resources */ = { 384 | isa = PBXShellScriptBuildPhase; 385 | buildActionMask = 2147483647; 386 | files = ( 387 | ); 388 | inputPaths = ( 389 | ); 390 | name = "📦 Copy Pods Resources"; 391 | outputPaths = ( 392 | ); 393 | runOnlyForDeploymentPostprocessing = 0; 394 | shellPath = /bin/sh; 395 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Demo Project/Pods-Demo Project-resources.sh\"\n"; 396 | showEnvVarsInLog = 0; 397 | }; 398 | /* End PBXShellScriptBuildPhase section */ 399 | 400 | /* Begin PBXSourcesBuildPhase section */ 401 | 600F98F618896F8C00896B83 /* Sources */ = { 402 | isa = PBXSourcesBuildPhase; 403 | buildActionMask = 2147483647; 404 | files = ( 405 | 600F990E18896F8C00896B83 /* CPDAppDelegate.m in Sources */, 406 | 600F990A18896F8C00896B83 /* main.m in Sources */, 407 | ); 408 | runOnlyForDeploymentPostprocessing = 0; 409 | }; 410 | 600F991718896F8C00896B83 /* Sources */ = { 411 | isa = PBXSourcesBuildPhase; 412 | buildActionMask = 2147483647; 413 | files = ( 414 | 60CD4D411889755D00B05988 /* CPDAcknowledgementLoaderTests.m in Sources */, 415 | 342F9EBDA81A787D5ED68844 /* CPDLibraryTests.m in Sources */, 416 | ); 417 | runOnlyForDeploymentPostprocessing = 0; 418 | }; 419 | /* End PBXSourcesBuildPhase section */ 420 | 421 | /* Begin PBXTargetDependency section */ 422 | 600F992118896F8C00896B83 /* PBXTargetDependency */ = { 423 | isa = PBXTargetDependency; 424 | target = 600F98F918896F8C00896B83 /* Demo Project */; 425 | targetProxy = 600F992018896F8C00896B83 /* PBXContainerItemProxy */; 426 | }; 427 | /* End PBXTargetDependency section */ 428 | 429 | /* Begin PBXVariantGroup section */ 430 | 600F990618896F8C00896B83 /* InfoPlist.strings */ = { 431 | isa = PBXVariantGroup; 432 | children = ( 433 | 600F990718896F8C00896B83 /* en */, 434 | ); 435 | name = InfoPlist.strings; 436 | sourceTree = ""; 437 | }; 438 | 600F992518896F8C00896B83 /* InfoPlist.strings */ = { 439 | isa = PBXVariantGroup; 440 | children = ( 441 | 600F992618896F8C00896B83 /* en */, 442 | ); 443 | name = InfoPlist.strings; 444 | sourceTree = ""; 445 | }; 446 | /* End PBXVariantGroup section */ 447 | 448 | /* Begin XCBuildConfiguration section */ 449 | 600F992A18896F8C00896B83 /* Debug */ = { 450 | isa = XCBuildConfiguration; 451 | buildSettings = { 452 | ALWAYS_SEARCH_USER_PATHS = NO; 453 | ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)"; 454 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 455 | CLANG_CXX_LIBRARY = "libc++"; 456 | CLANG_ENABLE_MODULES = YES; 457 | CLANG_ENABLE_OBJC_ARC = YES; 458 | CLANG_WARN_BOOL_CONVERSION = YES; 459 | CLANG_WARN_CONSTANT_CONVERSION = YES; 460 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 461 | CLANG_WARN_EMPTY_BODY = YES; 462 | CLANG_WARN_ENUM_CONVERSION = YES; 463 | CLANG_WARN_INT_CONVERSION = YES; 464 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 465 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 466 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 467 | COPY_PHASE_STRIP = NO; 468 | GCC_C_LANGUAGE_STANDARD = gnu99; 469 | GCC_DYNAMIC_NO_PIC = NO; 470 | GCC_OPTIMIZATION_LEVEL = 0; 471 | GCC_PREPROCESSOR_DEFINITIONS = ( 472 | "DEBUG=1", 473 | "$(inherited)", 474 | ); 475 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 476 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 477 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 478 | GCC_WARN_UNDECLARED_SELECTOR = YES; 479 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 480 | GCC_WARN_UNUSED_FUNCTION = YES; 481 | GCC_WARN_UNUSED_VARIABLE = YES; 482 | IPHONEOS_DEPLOYMENT_TARGET = 6.0; 483 | ONLY_ACTIVE_ARCH = YES; 484 | SDKROOT = iphoneos; 485 | }; 486 | name = Debug; 487 | }; 488 | 600F992B18896F8C00896B83 /* Release */ = { 489 | isa = XCBuildConfiguration; 490 | buildSettings = { 491 | ALWAYS_SEARCH_USER_PATHS = NO; 492 | ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)"; 493 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 494 | CLANG_CXX_LIBRARY = "libc++"; 495 | CLANG_ENABLE_MODULES = YES; 496 | CLANG_ENABLE_OBJC_ARC = YES; 497 | CLANG_WARN_BOOL_CONVERSION = YES; 498 | CLANG_WARN_CONSTANT_CONVERSION = YES; 499 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 500 | CLANG_WARN_EMPTY_BODY = YES; 501 | CLANG_WARN_ENUM_CONVERSION = YES; 502 | CLANG_WARN_INT_CONVERSION = YES; 503 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 504 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 505 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 506 | COPY_PHASE_STRIP = YES; 507 | ENABLE_NS_ASSERTIONS = NO; 508 | GCC_C_LANGUAGE_STANDARD = gnu99; 509 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 510 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 511 | GCC_WARN_UNDECLARED_SELECTOR = YES; 512 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 513 | GCC_WARN_UNUSED_FUNCTION = YES; 514 | GCC_WARN_UNUSED_VARIABLE = YES; 515 | IPHONEOS_DEPLOYMENT_TARGET = 6.0; 516 | SDKROOT = iphoneos; 517 | VALIDATE_PRODUCT = YES; 518 | }; 519 | name = Release; 520 | }; 521 | 600F992D18896F8C00896B83 /* Debug */ = { 522 | isa = XCBuildConfiguration; 523 | baseConfigurationReference = C60D1451F3DF087E92171FBA /* Pods-Demo Project.debug.xcconfig */; 524 | buildSettings = { 525 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 526 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 527 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 528 | GCC_PREFIX_HEADER = "Demo/Demo Project-Prefix.pch"; 529 | INFOPLIST_FILE = "Demo/Demo Project-Info.plist"; 530 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 531 | PRODUCT_NAME = "Demo Project"; 532 | WRAPPER_EXTENSION = app; 533 | }; 534 | name = Debug; 535 | }; 536 | 600F992E18896F8C00896B83 /* Release */ = { 537 | isa = XCBuildConfiguration; 538 | baseConfigurationReference = FC1FDCC999FEC4A3AB4D382B /* Pods-Demo Project.release.xcconfig */; 539 | buildSettings = { 540 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 541 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 542 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 543 | GCC_PREFIX_HEADER = "Demo/Demo Project-Prefix.pch"; 544 | INFOPLIST_FILE = "Demo/Demo Project-Info.plist"; 545 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 546 | PRODUCT_NAME = "Demo Project"; 547 | WRAPPER_EXTENSION = app; 548 | }; 549 | name = Release; 550 | }; 551 | 600F993018896F8C00896B83 /* Debug */ = { 552 | isa = XCBuildConfiguration; 553 | baseConfigurationReference = C03DE825D677BF2C8F4C6060 /* Pods-Demo ProjectTests.debug.xcconfig */; 554 | buildSettings = { 555 | ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)"; 556 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/Demo Project.app/Demo Project"; 557 | FRAMEWORK_SEARCH_PATHS = ( 558 | "$(SDKROOT)/Developer/Library/Frameworks", 559 | "$(inherited)", 560 | "$(DEVELOPER_FRAMEWORKS_DIR)", 561 | ); 562 | GCC_INCREASE_PRECOMPILED_HEADER_SHARING = YES; 563 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 564 | GCC_PREFIX_HEADER = "DemoTests/Demo ProjectTests-Prefix.pch"; 565 | GCC_PREPROCESSOR_DEFINITIONS = ( 566 | "DEBUG=1", 567 | "$(inherited)", 568 | ); 569 | INFOPLIST_FILE = "Demo/Demo Project-Info.plist"; 570 | PRODUCT_NAME = "Demo ProjectTests"; 571 | TEST_HOST = "$(BUNDLE_LOADER)"; 572 | WRAPPER_EXTENSION = xctest; 573 | }; 574 | name = Debug; 575 | }; 576 | 600F993118896F8C00896B83 /* Release */ = { 577 | isa = XCBuildConfiguration; 578 | baseConfigurationReference = 3F723B5B19941F9506703F03 /* Pods-Demo ProjectTests.release.xcconfig */; 579 | buildSettings = { 580 | ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)"; 581 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/Demo Project.app/Demo Project"; 582 | FRAMEWORK_SEARCH_PATHS = ( 583 | "$(SDKROOT)/Developer/Library/Frameworks", 584 | "$(inherited)", 585 | "$(DEVELOPER_FRAMEWORKS_DIR)", 586 | ); 587 | GCC_INCREASE_PRECOMPILED_HEADER_SHARING = YES; 588 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 589 | GCC_PREFIX_HEADER = "DemoTests/Demo ProjectTests-Prefix.pch"; 590 | INFOPLIST_FILE = "Demo/Demo Project-Info.plist"; 591 | PRODUCT_NAME = "Demo ProjectTests"; 592 | TEST_HOST = "$(BUNDLE_LOADER)"; 593 | WRAPPER_EXTENSION = xctest; 594 | }; 595 | name = Release; 596 | }; 597 | /* End XCBuildConfiguration section */ 598 | 599 | /* Begin XCConfigurationList section */ 600 | 600F98F518896F8C00896B83 /* Build configuration list for PBXProject "Demo Project" */ = { 601 | isa = XCConfigurationList; 602 | buildConfigurations = ( 603 | 600F992A18896F8C00896B83 /* Debug */, 604 | 600F992B18896F8C00896B83 /* Release */, 605 | ); 606 | defaultConfigurationIsVisible = 0; 607 | defaultConfigurationName = Release; 608 | }; 609 | 600F992C18896F8C00896B83 /* Build configuration list for PBXNativeTarget "Demo Project" */ = { 610 | isa = XCConfigurationList; 611 | buildConfigurations = ( 612 | 600F992D18896F8C00896B83 /* Debug */, 613 | 600F992E18896F8C00896B83 /* Release */, 614 | ); 615 | defaultConfigurationIsVisible = 0; 616 | defaultConfigurationName = Release; 617 | }; 618 | 600F992F18896F8C00896B83 /* Build configuration list for PBXNativeTarget "Demo ProjectTests" */ = { 619 | isa = XCConfigurationList; 620 | buildConfigurations = ( 621 | 600F993018896F8C00896B83 /* Debug */, 622 | 600F993118896F8C00896B83 /* Release */, 623 | ); 624 | defaultConfigurationIsVisible = 0; 625 | defaultConfigurationName = Release; 626 | }; 627 | /* End XCConfigurationList section */ 628 | }; 629 | rootObject = 600F98F218896F8C00896B83 /* Project object */; 630 | } 631 | --------------------------------------------------------------------------------