diff --git a/.swift-version b/.swift-version index 9f55b2c..5186d07 100644 --- a/.swift-version +++ b/.swift-version @@ -1 +1 @@ -3.0 +4.0 diff --git a/.swiftlint.yml b/.swiftlint.yml index 536c8d8..ba5b3c6 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -7,6 +7,7 @@ disabled_rules: - type_body_length - trailing_whitespace - cyclomatic_complexity + - identifier_name included: - Samples diff --git a/Iconic.podspec b/Iconic.podspec index 71fc034..7c463ee 100644 --- a/Iconic.podspec +++ b/Iconic.podspec @@ -1,39 +1,34 @@ -@version = '1.3' +@version = '1.4' Pod::Spec.new do |s| - + s.name = 'Iconic' s.version = @version s.summary = 'Auto-generated icon font library for iOS [beta]' s.description = 'Iconic will help you make icon fonts integration on iOS easy and effortless. Its main component is in charge of auto-generating strongly typed code in Swift, fully compatible with Objective-C, allowing the integration of vector icons as image or text in your apps.' - + s.homepage = 'https://github.com/dzenbot/Iconic' s.screenshots = '' s.author = { 'Ignacio Romero Zurbuchen' => 'iromero@dzen.cl' } - + s.license = { :type => 'MIT', :file => 'LICENSE' } - + s.source = { :git => 'https://github.com/dzenbot/Iconic.git', :tag => @version } - + s.source_files = 'Source/*.{swift}' s.resources = 'Source/**/*.{ttf,otf}' - s.preserve_paths = 'Source/Catalog/**/*.*' + s.preserve_paths = 'Source/' s.framework = 'UIKit', 'CoreText' - + s.ios.deployment_target = '8.0' s.tvos.deployment_target = '9.0' s.watchos.deployment_target = '2.0' - s.pod_target_xcconfig = { - 'ENABLE_BITCODE' => 'NO', - 'SWIFT_VERSION' => '3.0', - } - - s.prepare_command = "sh Source/Iconizer.sh '#{ENV['FONT_PATH']}' --verbose" + s.prepare_command = "sh Source/Iconizer.sh '#{ENV['FONT_PATH']}' '#{ENV['CUSTOM_FONT_NAME']}'" end diff --git a/Samples/Podfile b/Samples/Podfile index 6a1bffa..06db699 100644 --- a/Samples/Podfile +++ b/Samples/Podfile @@ -33,11 +33,3 @@ target 'Tests' do pod 'FBSnapshotTestCase/Core' iconic end - -post_install do |installer| - installer.pods_project.targets.each do |target| - target.build_configurations.each do |config| - config.build_settings['SWIFT_VERSION'] = '3.0' - end - end -end diff --git a/Samples/Samples.xcodeproj/project.pbxproj b/Samples/Samples.xcodeproj/project.pbxproj index d3c6fda..1a10dd8 100644 --- a/Samples/Samples.xcodeproj/project.pbxproj +++ b/Samples/Samples.xcodeproj/project.pbxproj @@ -380,7 +380,6 @@ F50ADBFC1D112CDA004A5A4C /* Resources */, F51590BA1DEB811500C23C25 /* Run SwiftLint */, 66899069AA8DB41CAA16348F /* [CP] Embed Pods Frameworks */, - 4F8B2FA0AB7958800E8CA04A /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -400,7 +399,6 @@ F52915291D83B08E006305E4 /* Resources */, F52915281D83B08E006305E4 /* Frameworks */, B72B7A6B427AB1106382AE87 /* [CP] Embed Pods Frameworks */, - 2FE47DC5D0C4319209558F1E /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -423,7 +421,6 @@ F56977811DC9CAE3005EDE73 /* Embed Watch Content */, F51590B91DEB80E200C23C25 /* Run SwiftLint */, 66EF12CCF24C41A99ED12DFB /* [CP] Embed Pods Frameworks */, - 7DFCE678A53C4566F95D47F2 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -443,7 +440,6 @@ F569775D1DC9CAE3005EDE73 /* Resources */, F569777F1DC9CAE3005EDE73 /* Embed App Extensions */, 4227694CE5B908A8E2312F7C /* Frameworks */, - 890D74CD09505F4756B3B136 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -465,7 +461,6 @@ F56977691DC9CAE3005EDE73 /* Resources */, F51590BB1DEB812700C23C25 /* Run SwiftLint */, 4615DB9C948EDC46C04C07FD /* [CP] Embed Pods Frameworks */, - 97629D2F95B3544A817EE61C /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -493,22 +488,22 @@ }; F529152A1D83B08E006305E4 = { CreatedOnToolsVersion = 7.3.1; - LastSwiftMigration = 0810; + LastSwiftMigration = 0920; ProvisioningStyle = Manual; }; F558DA061CF1AF1A0014717C = { CreatedOnToolsVersion = 7.3.1; - LastSwiftMigration = 0810; + LastSwiftMigration = 0920; ProvisioningStyle = Manual; }; F569775E1DC9CAE3005EDE73 = { CreatedOnToolsVersion = 8.1; - LastSwiftMigration = 0810; + LastSwiftMigration = 0920; ProvisioningStyle = Manual; }; F569776A1DC9CAE3005EDE73 = { CreatedOnToolsVersion = 8.1; - LastSwiftMigration = 0810; + LastSwiftMigration = 0920; ProvisioningStyle = Manual; }; }; @@ -588,13 +583,16 @@ files = ( ); inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", ); name = "[CP] Check Pods Manifest.lock"; outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-tvOS-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n"; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; 0F1636CC8BBFF46B28293083 /* [CP] Check Pods Manifest.lock */ = { @@ -603,28 +601,16 @@ files = ( ); inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", ); name = "[CP] Check Pods Manifest.lock"; outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-watchOS-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n"; - showEnvVarsInLog = 0; - }; - 2FE47DC5D0C4319209558F1E /* [CP] Copy Pods Resources */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "[CP] Copy Pods Resources"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Tests/Pods-Tests-resources.sh\"\n"; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; 4615DB9C948EDC46C04C07FD /* [CP] Embed Pods Frameworks */ = { @@ -633,39 +619,30 @@ files = ( ); inputPaths = ( + "${SRCROOT}/Pods/Target Support Files/Pods-watchOS Extension/Pods-watchOS Extension-frameworks.sh", + "${BUILT_PRODUCTS_DIR}/Iconic-watchOS2.0/Iconic.framework", ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Iconic.framework", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-watchOS Extension/Pods-watchOS Extension-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; - 4F8B2FA0AB7958800E8CA04A /* [CP] Copy Pods Resources */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "[CP] Copy Pods Resources"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-tvOS/Pods-tvOS-resources.sh\"\n"; - showEnvVarsInLog = 0; - }; 66899069AA8DB41CAA16348F /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( + "${SRCROOT}/Pods/Target Support Files/Pods-tvOS/Pods-tvOS-frameworks.sh", + "${BUILT_PRODUCTS_DIR}/Iconic-tvOS9.0/Iconic.framework", ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Iconic.framework", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; @@ -678,9 +655,12 @@ files = ( ); inputPaths = ( + "${SRCROOT}/Pods/Target Support Files/Pods-iOS/Pods-iOS-frameworks.sh", + "${BUILT_PRODUCTS_DIR}/Iconic-iOS8.0/Iconic.framework", ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Iconic.framework", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; @@ -693,58 +673,16 @@ files = ( ); inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", ); name = "[CP] Check Pods Manifest.lock"; outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Tests-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n"; - showEnvVarsInLog = 0; - }; - 7DFCE678A53C4566F95D47F2 /* [CP] Copy Pods Resources */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "[CP] Copy Pods Resources"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-iOS/Pods-iOS-resources.sh\"\n"; - showEnvVarsInLog = 0; - }; - 890D74CD09505F4756B3B136 /* [CP] Copy Pods Resources */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "[CP] Copy Pods Resources"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-watchOS/Pods-watchOS-resources.sh\"\n"; - showEnvVarsInLog = 0; - }; - 97629D2F95B3544A817EE61C /* [CP] Copy Pods Resources */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "[CP] Copy Pods Resources"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-watchOS Extension/Pods-watchOS Extension-resources.sh\"\n"; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; B31DA642B1C54052FDD0ACF8 /* [CP] Check Pods Manifest.lock */ = { @@ -753,13 +691,16 @@ files = ( ); inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", ); name = "[CP] Check Pods Manifest.lock"; outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-watchOS Extension-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n"; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; B72B7A6B427AB1106382AE87 /* [CP] Embed Pods Frameworks */ = { @@ -768,9 +709,14 @@ files = ( ); inputPaths = ( + "${SRCROOT}/Pods/Target Support Files/Pods-Tests/Pods-Tests-frameworks.sh", + "${BUILT_PRODUCTS_DIR}/Iconic-iOS9.3/Iconic.framework", + "${BUILT_PRODUCTS_DIR}/FBSnapshotTestCase/FBSnapshotTestCase.framework", ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Iconic.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FBSnapshotTestCase.framework", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; @@ -825,13 +771,16 @@ files = ( ); inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", ); name = "[CP] Check Pods Manifest.lock"; outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-iOS-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n"; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ @@ -954,7 +903,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.dzn.iconic-tvos"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = appletvos; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.2; TARGETED_DEVICE_FAMILY = 3; TVOS_DEPLOYMENT_TARGET = 9.0; }; @@ -974,7 +923,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.dzn.iconic-tvos"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = appletvos; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.2; TARGETED_DEVICE_FAMILY = 3; TVOS_DEPLOYMENT_TARGET = 9.0; }; @@ -995,7 +944,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Tests/Supporting Files/Tests-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.2; }; name = Debug; }; @@ -1013,7 +962,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.dzn.Iconic-Tests"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Tests/Supporting Files/Tests-Bridging-Header.h"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.2; }; name = Release; }; @@ -1061,6 +1010,7 @@ ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 4.0; }; name = Debug; }; @@ -1101,6 +1051,7 @@ MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 4.0; VALIDATE_PRODUCT = YES; }; name = Release; @@ -1119,7 +1070,7 @@ PRODUCT_NAME = iOS; SWIFT_OBJC_BRIDGING_HEADER = "iOS/Classes/iOS-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.2; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; @@ -1137,7 +1088,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.dzn.iconic-ios"; PRODUCT_NAME = iOS; SWIFT_OBJC_BRIDGING_HEADER = "iOS/Classes/iOS-Bridging-Header.h"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.2; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; @@ -1159,7 +1110,7 @@ SDKROOT = watchos; SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.2; TARGETED_DEVICE_FAMILY = 4; WATCHOS_DEPLOYMENT_TARGET = 2.0; }; @@ -1181,7 +1132,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = watchos; SKIP_INSTALL = YES; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.2; TARGETED_DEVICE_FAMILY = 4; WATCHOS_DEPLOYMENT_TARGET = 2.0; }; @@ -1204,7 +1155,7 @@ SDKROOT = watchos; SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.2; TARGETED_DEVICE_FAMILY = 4; WATCHOS_DEPLOYMENT_TARGET = 2.0; }; @@ -1226,7 +1177,7 @@ PRODUCT_NAME = "${TARGET_NAME}"; SDKROOT = watchos; SKIP_INSTALL = YES; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.2; TARGETED_DEVICE_FAMILY = 4; WATCHOS_DEPLOYMENT_TARGET = 2.0; }; diff --git a/Samples/Samples.xcworkspace/contents.xcworkspacedata b/Samples/Samples.xcworkspace/contents.xcworkspacedata index 6f0a135..3e99cce 100644 --- a/Samples/Samples.xcworkspace/contents.xcworkspacedata +++ b/Samples/Samples.xcworkspace/contents.xcworkspacedata @@ -1,81 +1,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Samples/Samples.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Samples/Samples.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/Samples/Samples.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Samples/iOS/Classes/AppDelegate.swift b/Samples/iOS/Classes/AppDelegate.swift index c18b68b..5a61b47 100644 --- a/Samples/iOS/Classes/AppDelegate.swift +++ b/Samples/iOS/Classes/AppDelegate.swift @@ -27,11 +27,11 @@ class AppDelegate: UIResponder, UIApplicationDelegate { FontAwesomeIcon.register() } - func application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { + private func application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { return true } - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { + private func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { return true } } diff --git a/Samples/iOS/Classes/FirstViewController.swift b/Samples/iOS/Classes/FirstViewController.swift index c590d15..0c1cbae 100644 --- a/Samples/iOS/Classes/FirstViewController.swift +++ b/Samples/iOS/Classes/FirstViewController.swift @@ -44,7 +44,7 @@ class FirstViewController: UITableViewController { super.viewWillAppear(animated) } - func didTapRightItem() { + @objc func didTapRightItem() { // Do something } @@ -108,8 +108,7 @@ class FirstViewController: UITableViewController { } extension UIViewController { - - func updateTitleView() { + @objc func updateTitleView() { guard let title = self.title else { return @@ -123,8 +122,8 @@ extension UIViewController { let titleSize = CGFloat(20) let edgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: titleSize/2) - let attributes = [NSForegroundColorAttributeName: color, - NSFontAttributeName: UIFont.systemFont(ofSize: titleSize)] as [String : AnyObject] + let attributes = [NSAttributedString.Key.foregroundColor: color, + NSAttributedString.Key.font: UIFont.systemFont(ofSize: titleSize)] as [NSAttributedString.Key: Any] let mString = NSMutableAttributedString(string: title, attributes: attributes) diff --git a/Samples/iOS/Classes/SecondViewController.swift b/Samples/iOS/Classes/SecondViewController.swift index a8c7910..8ef7908 100644 --- a/Samples/iOS/Classes/SecondViewController.swift +++ b/Samples/iOS/Classes/SecondViewController.swift @@ -46,7 +46,7 @@ class SecondViewController: UIViewController { super.viewWillAppear(animated) } - func didTapRightItem() { + @objc func didTapRightItem() { navigationController?.navigationBar.isHidden = true tabBarController?.tabBar.isHidden = true } @@ -89,7 +89,7 @@ class StepSlider: UISlider { self.addGestureRecognizer(tapGesture) } - func didTapSlider(_ gesture: UIGestureRecognizer) { + @objc func didTapSlider(_ gesture: UIGestureRecognizer) { let location = gesture.location(in: gesture.view) diff --git a/Samples/watchOS Extension/InterfaceController.swift b/Samples/watchOS Extension/InterfaceController.swift index 625574e..3f2efcb 100644 --- a/Samples/watchOS Extension/InterfaceController.swift +++ b/Samples/watchOS Extension/InterfaceController.swift @@ -24,17 +24,18 @@ class InterfaceController: WKInterfaceController { let githubIcon = FontAwesomeIcon.githubIcon let upArrowIcon = FontAwesomeIcon.angleUpIcon let downArrowIcon = FontAwesomeIcon.angleDownIcon - - override class func initialize() { - + + private static let runOnce: Void = { // It is important to register the icon font as soon as possible, // and make the resources available right after launching the app. // // This example uses Awesome Font // http://fontawesome.io/cheatsheet/ - + FontAwesomeIcon.register() - } + }() + + static let shared = InterfaceController() override func awake(withContext context: Any?) { super.awake(withContext: context) diff --git a/Source/IconDrawable.swift b/Source/IconDrawable.swift index 0b610ce..762271f 100644 --- a/Source/IconDrawable.swift +++ b/Source/IconDrawable.swift @@ -14,38 +14,38 @@ public final class Iconic: NSObject { } /** The IconDrawable protocol defines the complete interface of an Iconic icon's capabilities. */ public protocol IconDrawable { - + /** The icon font's family name. */ static var familyName: String { get } - + /** The icon font's total count of available icons. */ static var count: Int { get } - + /** The icon's name. */ var name: String { get } - + /** The icon's unicode. */ var unicode: String { get } - + /** Creates a new instance with the specified icon name. If there is no valid name is recognised, this initializer falls back to the first available icon. - + - parameter iconName: The icon name to use for the new instance. */ init(named iconName: String) - + /** Returns the icon as an attributed string with the given pointSize and color. - + - parameter pointSize: The size of the font. - parameter color: The tint color of the font. */ func attributedString(ofSize pointSize: CGFloat, color: UIColor?) -> NSAttributedString - + /** Returns the icon as an attributed string with the given pointSize, color and padding. - + - parameter pointSize: The size of the font. - parameter color: The tint color of the font. - parameter edgeInsets: The edge insets to be used as horizontal and vertical padding. @@ -54,34 +54,34 @@ public protocol IconDrawable { /** Returns the icon as an image with the given size and color. - + - parameter size: The size of the image, in points. - parameter color: A tint color for the image. */ func image(ofSize size: CGSize, color: UIColor?) -> UIImage - + /** Returns the icon as an image with the given size, color and padding. - + - parameter size: The size of the image, in points. - parameter color: The tint color of the image. - parameter edgeInsets: The edge insets to be used as padding values. */ func image(ofSize size: CGSize, color: UIColor?, edgeInsets: UIEdgeInsets) -> UIImage - + /** Creates and returns the icon font object for the specified size. - + - parameter fontSize: The size (in points) to which the font is scaled. */ static func font(ofSize fontSize: CGFloat) -> UIFont - + /** Registers the icon font with the font manager. Note: an exception will be thrown if the resource (ttf/otf) font file is not found in the bundle. */ static func register() - + /** Unregisters the icon font from the font manager. */ @@ -90,128 +90,133 @@ public protocol IconDrawable { /** This extension adds the required default implementation for Iconic to work. */ extension IconDrawable { - + public func attributedString(ofSize pointSize: CGFloat, color: UIColor?) -> NSAttributedString { - + let font = Self.font(ofSize: pointSize) - var attributes = [NSFontAttributeName : font] as [String : AnyObject] - + + var attributes: [NSAttributedString.Key: Any] = [NSAttributedString.Key.font : font] + if let color = color { - attributes[NSForegroundColorAttributeName] = color + attributes[NSAttributedString.Key.foregroundColor] = color } - + return NSAttributedString(string: unicode, attributes: attributes) } - + public func attributedString(ofSize pointSize: CGFloat, color: UIColor?, edgeInsets: UIEdgeInsets) -> NSAttributedString { - + let aString = attributedString(ofSize: pointSize, color: color) let mString = NSMutableAttributedString(attributedString: aString) - + let range = NSRange(location: 0, length: mString.length) - mString.addAttribute(NSBaselineOffsetAttributeName, value: edgeInsets.bottom-edgeInsets.top, range: range) - - let leftSpace = NSAttributedString(string: " ", attributes: [NSKernAttributeName: edgeInsets.left]) - let rightSpace = NSAttributedString(string: " ", attributes: [NSKernAttributeName: edgeInsets.right]) - + mString.addAttribute(NSAttributedString.Key.baselineOffset, value: edgeInsets.bottom-edgeInsets.top, range: range) + + let leftSpace = NSAttributedString(string: " ", attributes: [NSAttributedString.Key.kern: edgeInsets.left]) + let rightSpace = NSAttributedString(string: " ", attributes: [NSAttributedString.Key.kern: edgeInsets.right]) + mString.insert(rightSpace, at: mString.length) mString.insert(leftSpace, at: 0) - + return mString } - + public func image(ofSize size: CGSize, color: UIColor?) -> UIImage { - + return image(ofSize: size, color: color, edgeInsets: .zero) } - + public func image(ofSize size: CGSize, color: UIColor?, edgeInsets: UIEdgeInsets) -> UIImage { - + let pointSize = min(size.width, size.height) let aString = attributedString(ofSize: pointSize, color: color) let mString = NSMutableAttributedString(attributedString: aString) - + var rect = CGRect(x: 0, y: 0, width: size.width, height: size.height) rect.origin.y -= edgeInsets.top rect.size.width -= edgeInsets.left + edgeInsets.right rect.size.height -= edgeInsets.top + edgeInsets.bottom - + let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.alignment = .center - + let range = NSRange(location: 0, length: mString.length) - - mString.addAttribute(NSParagraphStyleAttributeName, value: paragraphStyle, range: range) - + + mString.addAttribute(NSAttributedString.Key.paragraphStyle, value: paragraphStyle, range: range) + // Renders the attributed string as image using Text Kit UIGraphicsBeginImageContextWithOptions(rect.size, false, 0.0) mString.draw(in: rect) let image = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() - + return image! } - + public static func font(ofSize fontSize: CGFloat) -> UIFont { - + // Needs a default size, since zero would return a system font object. let size = (fontSize == 0) ? 10.0 : fontSize - + return UIFont(name: familyName, size: size)! } - + public static func register() { - + // No need to register the font more than once if UIFont.familyNames.contains(familyName) { return } - - let url = resourceUrl() + + guard let url = resourceUrl() else { + print("Unable to register font '\(familyName)' beacuse URL was nil!") + return + } var error: Unmanaged? = nil - let descriptors = CTFontManagerCreateFontDescriptorsFromURL(url) as NSArray? - + let descriptors = CTFontManagerCreateFontDescriptorsFromURL(url as CFURL) as NSArray? + guard let descriptor = (descriptors as? [CTFontDescriptor])?.first else { assertionFailure("Could not retrieve font descriptors of font at path '\(url)',") return } - + let font = CTFontCreateWithFontDescriptorAndOptions(descriptor, 0.0, nil, [.preventAutoActivation]) let fontName = CTFontCopyPostScriptName(font) as String - + // Registers font dynamically - if CTFontManagerRegisterFontsForURL(url, .none, &error) == false || error != nil { - assertionFailure("Failed registering font with the postscript name '\(fontName)' at path '\(url)' with error: \(error).") + if CTFontManagerRegisterFontsForURL(url as CFURL, .none, &error) == false || error != nil { + assertionFailure("Failed registering font with the postscript name '\(fontName)' at path '\(url)' with error: \(String(describing: error)).") } - + print("Font '\(familyName)' registered successfully!") } - + public static func unregister() { - + // No need to unregister if the font isn't registered if UIFont.familyNames.contains(familyName) == false { return } - - let url = resourceUrl() + + guard let url = resourceUrl() else { + print("Unable to unregister font '\(familyName)' beacuse URL was nil!") + return + } var error: Unmanaged? = nil - - if CTFontManagerUnregisterFontsForURL(url, .none, &error) == false || error != nil { - assertionFailure("Failed unregistering font with name '\(familyName)' at path '\(url)' with error: \(error).") + + if CTFontManagerUnregisterFontsForURL(url as CFURL, .none, &error) == false || error != nil { + assertionFailure("Failed unregistering font with name '\(familyName)' at path '\(url)' with error: \(String(describing: error)).") } - + print("Font '\(familyName)' unregistered successfully!") } - - fileprivate static func resourceUrl() -> CFURL { - + + fileprivate static func resourceUrl() -> URL? { let extensions = ["otf", "ttf"] let bundle = Bundle(for: Iconic.self) - - let url = extensions.flatMap { bundle.url(forResource: familyName, withExtension: $0) }.first - - return url as CFURL! + + return extensions.compactMap { bundle.url(forResource: familyName, withExtension: $0) }.first } } + diff --git a/Source/IconImageView.swift b/Source/IconImageView.swift index 04f57ab..0f99e36 100644 --- a/Source/IconImageView.swift +++ b/Source/IconImageView.swift @@ -9,45 +9,44 @@ import UIKit #if os(iOS) || os(tvOS) - /** An Image View subclass, capable of rendering icons. Only supported for iOS and tvOS. */ public class IconImageView: UIImageView { - + // MARK: - Public Variables - + /** The icon drawable to be used as image. */ public var iconDrawable: IconDrawable? { didSet { updateIconImage() } } - + // MARK: - Overrides - + public override var frame: CGRect { didSet { updateIconImage() } } - + public override func layoutSubviews() { super.layoutSubviews() - + updateIconImage() } - + // MARK: - Image Constructor - + /** Updates the icon image, only when the frame is not empty. */ fileprivate func updateIconImage() { - + // No need to update the icon with empty frame if frame.isEmpty { return } - + if let icon = iconDrawable { let image = icon.image(ofSize: frame.size, color: nil) self.image = image.withRenderingMode(.alwaysTemplate) @@ -56,5 +55,5 @@ public class IconImageView: UIImageView { } } } - #endif + diff --git a/Source/Iconizer.sh b/Source/Iconizer.sh index bc986bb..489b4f7 100755 --- a/Source/Iconizer.sh +++ b/Source/Iconizer.sh @@ -6,12 +6,15 @@ # Created by Ignacio Romero on 5/28/16. # Copyright © 2016 DZN Labs All rights reserved. # -# Script in charge of executing SwitfGen, passing the icon font file path, the enum name and the custom stencil as arguments. +# Script in charge of executing SwiftGen, passing the icon font file path, the enum name and the custom stencil as arguments. # # The optional font file path passed as arg INPUT_PATH=$1 +# The optional custom name to use instead of deriving one via file name +CUSTOM_NAME=$2 + # The root path for the generated files OUTPUT_PATH=Source @@ -32,16 +35,16 @@ function getFileTitle() # Removes the file extension name="${FILE_NAME%.*}" - + # Splits and removes all substrings with the separator characters in the file name # like whitespaces, dash, underscore, etc. title="${name%%[" -_–"]*}" - + # Specially, we want to strip the string starting from the word "Icon", and append it manually, # so a string like 'MaterialIconsFont' would look like 'MaterialIcon'. title="${title%%"icon"*}" title="${title%%"Icon"*}Icon" - + # Upper case the first character title="$(tr '[:lower:]' '[:upper:]' <<< ${title:0:1})${title:1}" @@ -53,10 +56,8 @@ function iconize() # Input variables FONT_PATH=$1 FONT_NAME=$2 + OUTPUT_NAME=$3 - # Capitalized first word of the file name, with the 'Icon' suffix. - # ie: FontAwesomeIcon out of a string like 'FontAwesome' - OUTPUT_NAME=$( getFileTitle "${FONT_NAME}" ) echo "Iconizer: Generating API name '${OUTPUT_NAME}'" # Creates the output folder (no error if existing) @@ -68,7 +69,7 @@ function iconize() # Moves and renames the JSON output to the HTML directory mv ${OUTPUT_PATH}/${OUTPUT_NAME}.json ${CATALOG_PATH}/data.json echo "Iconizer: Moving catalog's json to '${CATALOG_PATH}/data.json'" - + # Copies the font file to the HTML directory cp -r ${FONT_PATH} ${CATALOG_PATH}/${FONT_NAME} echo "Iconizer: Moving catalog's font to '${CATALOG_PATH}/${FONT_NAME}'" @@ -78,17 +79,25 @@ function init() { # Input variables FONT_PATH=$1 + CUSTOM_NAME=$2 echo "Iconizer: Initializing with font at path '${FONT_PATH}'" # Input's file name and extension FONT_NAME=$(basename "${FONT_PATH}") INPUT_EXTENSION="${FONT_NAME##*.}" + + if [ -z "$CUSTOM_NAME" ]; then + # Capitalized first word of the file name, with the 'Icon' suffix. + # ie: FontAwesomeIcon out of a string like 'FontAwesome' + CUSTOM_NAME=$( getFileTitle "${FONT_NAME}" ) + fi + echo "Iconizer: Processing file '${FONT_NAME}' with extension '${INPUT_EXTENSION}'" # Only TTF and OTF are supported font files if [ ${INPUT_EXTENSION} = 'ttf' ] || [ ${INPUT_EXTENSION} = 'otf' ]; then - iconize ${FONT_PATH} ${FONT_NAME} + iconize ${FONT_PATH} ${FONT_NAME} ${CUSTOM_NAME} else echo "Iconizer: Unsupported '${INPUT_EXTENSION}' file. Please provide a TTF or OTF file path." fi @@ -101,6 +110,8 @@ if [ -z ${INPUT_PATH} ]; then # Uses FontAwesome as default init 'Fonts/FontAwesome/FontAwesome.otf' -else +elif [ -z ${CUSTOM_NAME} ]; then init ${INPUT_PATH} +else + init ${INPUT_PATH} ${CUSTOM_NAME} fi diff --git a/Source/iconic-default.stencil b/Source/iconic-default.stencil index cb38cea..c6f896f 100644 --- a/Source/iconic-default.stencil +++ b/Source/iconic-default.stencil @@ -4,18 +4,13 @@ import UIKit {% if icons %} /** A wrapper class for Objective-C compatibility. */ -public extension Iconic { +@objc public extension Iconic { /** The icon font's family name. */ class var {{enumName|lowerFirstWord}}FamilyName: NSString { return {{enumName}}.familyName as NSString } - /** The icon font's total count of available icons. */ - class var {{enumName|lowerFirstWord}}Count: Int { - return {{enumName}}.count - } - /** Returns the icon font object for the specified size. @@ -111,7 +106,7 @@ public final class {{enumName}}View: IconImageView { } } -public extension UIBarButtonItem { +@objc public extension UIBarButtonItem { /** Initializes a new item using the specified icon and other properties. @@ -122,13 +117,13 @@ public extension UIBarButtonItem { - parameter action: The action to send to target when this item is selected. */ convenience init(withIcon icon: {{enumName}}, size: CGSize, target: AnyObject?, action: Selector) { - + let image = icon.image(ofSize: size, color: .black) self.init(image: image, style: .plain, target: target, action: action) } } -public extension UITabBarItem { +@objc public extension UITabBarItem { /** Initializes a new item using the specified icon and other properties. @@ -139,13 +134,13 @@ public extension UITabBarItem { - parameter title: The item's title. If nil, a title is not displayed. */ convenience init(withIcon icon: {{enumName}}, size: CGSize, title: String?) { - + let image = icon.image(ofSize: size, color: .black) self.init(title: title, image: image, tag: icon.rawValue) } } -public extension UIButton { +@objc public extension UIButton { /** Sets the icon to use for the specified state. @@ -153,10 +148,10 @@ public extension UIButton { - parameter icon: The icon to be used as image. - parameter size: The size of the image, in points. - parameter color: The color of the image. - - parameter state: The state that uses the specified title. The values are described in UIControlState. + - parameter state: The state that uses the specified title. The values are described in UIControl.State. */ - func setIconImage(withIcon icon: {{enumName}}, size: CGSize, color: UIColor?, forState state: UIControlState) { - + func setIconImage(withIcon icon: {{enumName}}, size: CGSize, color: UIColor?, forState state: UIControl.State) { + let image = icon.image(ofSize: size, color: color ?? .black) setImage(image, for: state) } @@ -165,13 +160,10 @@ public extension UIButton { #endif /** A list with available icon glyphs from the icon font. */ -@objc public enum {{enumName}}: Int { +@objc public enum {{enumName}}: Int, CaseIterable { {% for icon in icons %} case {{icon.name|swiftIdentifier|snakeToCamelCase|lowerFirstWord}}Icon {% endfor %} - - /** The icon font's total count of available icons. */ - public static var count: Int { return {{ icons.count }} } } extension {{enumName}} : IconDrawable { @@ -183,7 +175,7 @@ extension {{enumName}} : IconDrawable { /** Creates a new instance with the specified icon name. - If there is no valid name is recognised, this initializer falls back to the first available icon. + If there is no valid name recognised, this initializer falls back to the first available icon. - parameter iconName: The icon name to use for the new instance. */ @@ -196,6 +188,23 @@ extension {{enumName}} : IconDrawable { } } + /** + Creates a new instance with the specified icon name. + If there is no valid name recognised, the given fallback value will be used. + If the fallback value is not recognised, this initializer falls back to the first available icon. + + - parameter iconName: The icon name to use for the new instance. + - parameter fallbackIconName: The fallback icon name to use for the new instance if the iconName doesn't exist. + */ + public init(named iconName: String, fallbackIconName: String) { + switch iconName.lowercased() { + {% for icon in icons %} + case "{{icon.name|swiftIdentifier|lowercase}}": self = .{{icon.name|swiftIdentifier|snakeToCamelCase|lowerFirstWord}}Icon + {% endfor %} + default: self = {{enumName}}(named: fallbackIconName) + } + } + /** The icon's name. */ public var name: String { switch self {