From e5ebfde59bb3136d2f4bc8ffd3c85185db0a4e1d Mon Sep 17 00:00:00 2001 From: Salvador Mosca Date: Wed, 21 Aug 2019 10:51:18 +0100 Subject: [PATCH] Migration --- .gitignore | 1 + .swift-version | 1 + README.md | 121 +++++ SwiftCSSFramework.xcodeproj/project.pbxproj | 451 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcschemes/SwiftCSSFramework.xcscheme | 80 ++++ .../DeferredStyles/DeferredStyle.swift | 46 ++ .../RegisteredStatusBarStyles.swift | 35 ++ .../DeferredStyles/RegisteredStyles.swift | 105 ++++ .../DeferredStyles/StyleResover.swift | 36 ++ .../DeferredStyles/Stylize.swift | 27 ++ .../Extensions/OptionalExtensions.swift | 15 + .../Extensions/UIImageViewExtensions.swift | 32 ++ .../UIViewControllerExtensions.swift | 65 +++ .../UIViewControllerSwizzledExtension.swift | 61 +++ .../Extensions/UIViewExtensions.swift | 128 +++++ .../Extensions/UIViewSwizzledExtension.swift | 74 +++ SwiftCSSFramework/Headers/SwiftCSSFramework.h | 18 + SwiftCSSFramework/Info.plist | 26 + .../Protocols/Customizable.swift | 23 + .../Sources/SwiftCSSFramework.swift | 29 ++ SwiftCSSFramework/Utils/Logger.swift | 37 ++ 23 files changed, 1426 insertions(+) create mode 100644 .gitignore create mode 100644 .swift-version create mode 100644 README.md create mode 100644 SwiftCSSFramework.xcodeproj/project.pbxproj create mode 100644 SwiftCSSFramework.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 SwiftCSSFramework.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 SwiftCSSFramework.xcodeproj/xcshareddata/xcschemes/SwiftCSSFramework.xcscheme create mode 100644 SwiftCSSFramework/DeferredStyles/DeferredStyle.swift create mode 100644 SwiftCSSFramework/DeferredStyles/RegisteredStatusBarStyles.swift create mode 100644 SwiftCSSFramework/DeferredStyles/RegisteredStyles.swift create mode 100644 SwiftCSSFramework/DeferredStyles/StyleResover.swift create mode 100644 SwiftCSSFramework/DeferredStyles/Stylize.swift create mode 100644 SwiftCSSFramework/Extensions/OptionalExtensions.swift create mode 100644 SwiftCSSFramework/Extensions/UIImageViewExtensions.swift create mode 100644 SwiftCSSFramework/Extensions/UIViewControllerExtensions.swift create mode 100644 SwiftCSSFramework/Extensions/UIViewControllerSwizzledExtension.swift create mode 100644 SwiftCSSFramework/Extensions/UIViewExtensions.swift create mode 100644 SwiftCSSFramework/Extensions/UIViewSwizzledExtension.swift create mode 100644 SwiftCSSFramework/Headers/SwiftCSSFramework.h create mode 100644 SwiftCSSFramework/Info.plist create mode 100644 SwiftCSSFramework/Protocols/Customizable.swift create mode 100644 SwiftCSSFramework/Sources/SwiftCSSFramework.swift create mode 100644 SwiftCSSFramework/Utils/Logger.swift diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..125ee7a --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.xcuserdatad diff --git a/.swift-version b/.swift-version new file mode 100644 index 0000000..5186d07 --- /dev/null +++ b/.swift-version @@ -0,0 +1 @@ +4.0 diff --git a/README.md b/README.md new file mode 100644 index 0000000..c68f299 --- /dev/null +++ b/README.md @@ -0,0 +1,121 @@ +# Publish new tags + +Update the podspec accordingly with the new version reference. + +``` +git commit ... +git tag +git push --tags +``` + +# Add private repo and publish the new podspec +``` +pod repo add cocoapods https://gitlab.ndrive.com/nlife/cocoapods +pod repo push cocoapods SwiftCSSFramework.podspec +``` + +[![Build Status](https://jenkins.ndrive.com/buildStatus/icon?job=ios-swift-css-framework)](https://jenkins.ndrive.com/view/iOS/job/ios-swift-css-framework/) + +## CocoaPods install + +Add source to your podfile + +``` +source 'git@gitlab.ndrive.com:nlife/cocoapods.git' +``` + +Remember to add +``` +use_frameworks! +``` + +Then reference the pod +``` +pod 'SwiftCSSFramework' +``` + +## Usage + +In order to stylize UIView elements you must create an array of stylizable elements. +Ex: Stylizing all UILabels + +```swift +class Global +{ + static let style : [RegistrableStyle] = + [ + // Applies to all UILabels + Stylize.all() + {(elem: UILabel) in + + elem.textColor = UIColor.grayColor() + + }, + + // Applies to all UILabels having the CSS property set on storyboard (or programmatically) + Stylize.elem("MyLabel") + {(elem: UILabel) in + + elem.textColor = UIColor.blueColor() + + }, + + // Applies to all labels nested in ViewController + Stylize.nestedIn([ViewController.self]) + {(elem: UILabel) in + + elem.textColor = UIColor.redColor() + + }, + + // Applies to all labels with the CSS property ´MyLabel´nested in ViewController + Stylize.elem("MyLabel", childOf: [ViewController.self]) + {(elem: UILabel) in + + elem.textColor = UIColor.cyanColor() + + } + + ] +} + +// NOTE: +// Having this array static will prevent having to identify the items +// so removing this registered styles relies on a more simple implementation +``` + +This array of styles must be registered following the priority (the last setted property will prevail) + +```swift +Styles.register(Global.style) +``` + +In order to change styles is also possible to unregister styles + +```swift +Styles.unregister(Global.style) +``` + +It's possible to force styles to be applied. +By default the style is applied by Swizzling the UIView.willMoveToWindow(_:) in runtime. + +**Therefore using UIView.willMoveToWindow(_:) will be void when using Swift CSS Framework** + +```swift +// The rest of the code was suppressed +import SwiftCSSFramework + +class ViewController: UIViewController +{ + @IBOutlet weak var myLabelOutlet: UILabel! + + func dummyReload() + { + // CSS properties can be set/overridden in runtime + myLabelOutlet.CSS = "myStyle" + + // It is also possible to force styles to be applied + myLabelOutlet.resolveStyle() + } +} +``` diff --git a/SwiftCSSFramework.xcodeproj/project.pbxproj b/SwiftCSSFramework.xcodeproj/project.pbxproj new file mode 100644 index 0000000..f3b699f --- /dev/null +++ b/SwiftCSSFramework.xcodeproj/project.pbxproj @@ -0,0 +1,451 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 0683B4E91F3B1EA80015F3EA /* SwiftCSSFramework.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0683B4E81F3B1EA80015F3EA /* SwiftCSSFramework.swift */; }; + 0683B4EA1F3B235B0015F3EA /* UIViewControllerSwizzledExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0683B4DE1F3B1E7E0015F3EA /* UIViewControllerSwizzledExtension.swift */; }; + 0683B4EB1F3B23670015F3EA /* UIViewControllerExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0683B4DD1F3B1E7E0015F3EA /* UIViewControllerExtensions.swift */; }; + 0683B4EC1F3B239B0015F3EA /* UIViewSwizzledExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0683B4E01F3B1E7E0015F3EA /* UIViewSwizzledExtension.swift */; }; + 0683B4ED1F3B23D30015F3EA /* OptionalExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0683B4DB1F3B1E7E0015F3EA /* OptionalExtensions.swift */; }; + 0683B4EE1F3B23D60015F3EA /* UIImageViewExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0683B4DC1F3B1E7E0015F3EA /* UIImageViewExtensions.swift */; }; + 0683B4EF1F3B23DC0015F3EA /* UIViewExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0683B4DF1F3B1E7E0015F3EA /* UIViewExtensions.swift */; }; + 0683B4F01F3B23E60015F3EA /* DeferredStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0683B4E21F3B1E830015F3EA /* DeferredStyle.swift */; }; + 0683B4F11F3B23E60015F3EA /* RegisteredStatusBarStyles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0683B4E31F3B1E830015F3EA /* RegisteredStatusBarStyles.swift */; }; + 0683B4F21F3B23E60015F3EA /* RegisteredStyles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0683B4E41F3B1E830015F3EA /* RegisteredStyles.swift */; }; + 0683B4F31F3B23E60015F3EA /* StyleResover.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0683B4E51F3B1E830015F3EA /* StyleResover.swift */; }; + 0683B4F41F3B23E60015F3EA /* Stylize.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0683B4E61F3B1E830015F3EA /* Stylize.swift */; }; + B5C01B6C1D13130E00E17566 /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D7FDCE1D106FA7003C0294 /* Logger.swift */; }; + B5C01B6D1D13130E00E17566 /* Customizable.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D7FDCB1D106F4C003C0294 /* Customizable.swift */; }; + B5F526F01D18431500F5DD29 /* SwiftCSSFramework.h in Headers */ = {isa = PBXBuildFile; fileRef = B5F526EF1D18431500F5DD29 /* SwiftCSSFramework.h */; settings = {ATTRIBUTES = (Public, ); }; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 0683B4DB1F3B1E7E0015F3EA /* OptionalExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OptionalExtensions.swift; sourceTree = ""; }; + 0683B4DC1F3B1E7E0015F3EA /* UIImageViewExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIImageViewExtensions.swift; sourceTree = ""; }; + 0683B4DD1F3B1E7E0015F3EA /* UIViewControllerExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIViewControllerExtensions.swift; sourceTree = ""; }; + 0683B4DE1F3B1E7E0015F3EA /* UIViewControllerSwizzledExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIViewControllerSwizzledExtension.swift; sourceTree = ""; }; + 0683B4DF1F3B1E7E0015F3EA /* UIViewExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIViewExtensions.swift; sourceTree = ""; }; + 0683B4E01F3B1E7E0015F3EA /* UIViewSwizzledExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIViewSwizzledExtension.swift; sourceTree = ""; }; + 0683B4E21F3B1E830015F3EA /* DeferredStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeferredStyle.swift; sourceTree = ""; }; + 0683B4E31F3B1E830015F3EA /* RegisteredStatusBarStyles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegisteredStatusBarStyles.swift; sourceTree = ""; }; + 0683B4E41F3B1E830015F3EA /* RegisteredStyles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegisteredStyles.swift; sourceTree = ""; }; + 0683B4E51F3B1E830015F3EA /* StyleResover.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StyleResover.swift; sourceTree = ""; }; + 0683B4E61F3B1E830015F3EA /* Stylize.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Stylize.swift; sourceTree = ""; }; + 0683B4E81F3B1EA80015F3EA /* SwiftCSSFramework.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftCSSFramework.swift; sourceTree = ""; }; + B5C01B361D12F44900E17566 /* SwiftCSSFramework.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftCSSFramework.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + B5D2A7DC1D106AAF0006D52C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + B5D7FDCB1D106F4C003C0294 /* Customizable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Customizable.swift; path = Protocols/Customizable.swift; sourceTree = ""; }; + B5D7FDCE1D106FA7003C0294 /* Logger.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Logger.swift; path = Utils/Logger.swift; sourceTree = ""; }; + B5F526EF1D18431500F5DD29 /* SwiftCSSFramework.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SwiftCSSFramework.h; path = Headers/SwiftCSSFramework.h; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + B5C01B321D12F44900E17566 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 0683B4DA1F3B1E7E0015F3EA /* Extensions */ = { + isa = PBXGroup; + children = ( + 0683B4DB1F3B1E7E0015F3EA /* OptionalExtensions.swift */, + 0683B4DC1F3B1E7E0015F3EA /* UIImageViewExtensions.swift */, + 0683B4DD1F3B1E7E0015F3EA /* UIViewControllerExtensions.swift */, + 0683B4DE1F3B1E7E0015F3EA /* UIViewControllerSwizzledExtension.swift */, + 0683B4DF1F3B1E7E0015F3EA /* UIViewExtensions.swift */, + 0683B4E01F3B1E7E0015F3EA /* UIViewSwizzledExtension.swift */, + ); + path = Extensions; + sourceTree = ""; + }; + 0683B4E11F3B1E830015F3EA /* DeferredStyles */ = { + isa = PBXGroup; + children = ( + 0683B4E21F3B1E830015F3EA /* DeferredStyle.swift */, + 0683B4E31F3B1E830015F3EA /* RegisteredStatusBarStyles.swift */, + 0683B4E41F3B1E830015F3EA /* RegisteredStyles.swift */, + 0683B4E51F3B1E830015F3EA /* StyleResover.swift */, + 0683B4E61F3B1E830015F3EA /* Stylize.swift */, + ); + path = DeferredStyles; + sourceTree = ""; + }; + 0683B4E71F3B1E980015F3EA /* Sources */ = { + isa = PBXGroup; + children = ( + 0683B4E81F3B1EA80015F3EA /* SwiftCSSFramework.swift */, + ); + path = Sources; + sourceTree = ""; + }; + B5D2A7CD1D106AAF0006D52C = { + isa = PBXGroup; + children = ( + B5D2A7D91D106AAF0006D52C /* SwiftCSSFramework */, + B5D2A7D81D106AAF0006D52C /* Products */, + ); + sourceTree = ""; + }; + B5D2A7D81D106AAF0006D52C /* Products */ = { + isa = PBXGroup; + children = ( + B5C01B361D12F44900E17566 /* SwiftCSSFramework.framework */, + ); + name = Products; + sourceTree = ""; + }; + B5D2A7D91D106AAF0006D52C /* SwiftCSSFramework */ = { + isa = PBXGroup; + children = ( + 0683B4E71F3B1E980015F3EA /* Sources */, + 0683B4E11F3B1E830015F3EA /* DeferredStyles */, + 0683B4DA1F3B1E7E0015F3EA /* Extensions */, + B5F526EE1D1842FB00F5DD29 /* Headers */, + B5D7FDCD1D106F83003C0294 /* Utils */, + B5D7FDCA1D106F1F003C0294 /* Protocols */, + B5D2A7DC1D106AAF0006D52C /* Info.plist */, + ); + path = SwiftCSSFramework; + sourceTree = ""; + }; + B5D7FDCA1D106F1F003C0294 /* Protocols */ = { + isa = PBXGroup; + children = ( + B5D7FDCB1D106F4C003C0294 /* Customizable.swift */, + ); + name = Protocols; + sourceTree = ""; + }; + B5D7FDCD1D106F83003C0294 /* Utils */ = { + isa = PBXGroup; + children = ( + B5D7FDCE1D106FA7003C0294 /* Logger.swift */, + ); + name = Utils; + sourceTree = ""; + }; + B5F526EE1D1842FB00F5DD29 /* Headers */ = { + isa = PBXGroup; + children = ( + B5F526EF1D18431500F5DD29 /* SwiftCSSFramework.h */, + ); + name = Headers; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + B5C01B331D12F44900E17566 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + B5F526F01D18431500F5DD29 /* SwiftCSSFramework.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + B5C01B351D12F44900E17566 /* SwiftCSSFramework */ = { + isa = PBXNativeTarget; + buildConfigurationList = B5C01B3B1D12F44900E17566 /* Build configuration list for PBXNativeTarget "SwiftCSSFramework" */; + buildPhases = ( + B5C01B311D12F44900E17566 /* Sources */, + B5C01B321D12F44900E17566 /* Frameworks */, + B5C01B331D12F44900E17566 /* Headers */, + B5C01B341D12F44900E17566 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = SwiftCSSFramework; + productName = SwiftCSSFrameworkMainTarget; + productReference = B5C01B361D12F44900E17566 /* SwiftCSSFramework.framework */; + productType = "com.apple.product-type.framework"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + B5D2A7CE1D106AAF0006D52C /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0730; + LastUpgradeCheck = 1000; + ORGANIZATIONNAME = "Salvador Mósca"; + TargetAttributes = { + B5C01B351D12F44900E17566 = { + CreatedOnToolsVersion = 7.3; + DevelopmentTeam = TPAFX43YU9; + LastSwiftMigration = 0900; + }; + }; + }; + buildConfigurationList = B5D2A7D11D106AAF0006D52C /* Build configuration list for PBXProject "SwiftCSSFramework" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = B5D2A7CD1D106AAF0006D52C; + productRefGroup = B5D2A7D81D106AAF0006D52C /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + B5C01B351D12F44900E17566 /* SwiftCSSFramework */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + B5C01B341D12F44900E17566 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + B5C01B311D12F44900E17566 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 0683B4F11F3B23E60015F3EA /* RegisteredStatusBarStyles.swift in Sources */, + 0683B4F31F3B23E60015F3EA /* StyleResover.swift in Sources */, + 0683B4EA1F3B235B0015F3EA /* UIViewControllerSwizzledExtension.swift in Sources */, + B5C01B6C1D13130E00E17566 /* Logger.swift in Sources */, + 0683B4F21F3B23E60015F3EA /* RegisteredStyles.swift in Sources */, + 0683B4EE1F3B23D60015F3EA /* UIImageViewExtensions.swift in Sources */, + 0683B4ED1F3B23D30015F3EA /* OptionalExtensions.swift in Sources */, + 0683B4EC1F3B239B0015F3EA /* UIViewSwizzledExtension.swift in Sources */, + 0683B4EB1F3B23670015F3EA /* UIViewControllerExtensions.swift in Sources */, + 0683B4F01F3B23E60015F3EA /* DeferredStyle.swift in Sources */, + 0683B4E91F3B1EA80015F3EA /* SwiftCSSFramework.swift in Sources */, + 0683B4EF1F3B23DC0015F3EA /* UIViewExtensions.swift in Sources */, + 0683B4F41F3B23E60015F3EA /* Stylize.swift in Sources */, + B5C01B6D1D13130E00E17566 /* Customizable.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + B5C01B3C1D12F44900E17566 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = SwiftCSSFramework/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MACH_O_TYPE = mh_dylib; + ONLY_ACTIVE_ARCH = NO; + PRODUCT_BUNDLE_IDENTIFIER = com.ndrive.SwiftCSSFrameworkMainTarget; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE = ""; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 4.2; + VALID_ARCHS = "arm64 armv7 armv7s"; + }; + name = Debug; + }; + B5C01B3D1D12F44900E17566 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = SwiftCSSFramework/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MACH_O_TYPE = mh_dylib; + ONLY_ACTIVE_ARCH = NO; + PRODUCT_BUNDLE_IDENTIFIER = com.ndrive.SwiftCSSFrameworkMainTarget; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE = ""; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 4.2; + VALID_ARCHS = "arm64 armv7 armv7s"; + }; + name = Release; + }; + B5D2A7E91D106AAF0006D52C /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_BITCODE = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + OTHER_SWIFT_FLAGS = ""; + PROVISIONING_PROFILE = ""; + SDKROOT = iphoneos; + SWIFT_OBJC_BRIDGING_HEADER = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VALID_ARCHS = "armv6 armv7s armv7"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + B5D2A7EA1D106AAF0006D52C /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_BITCODE = NO; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = NO; + ONLY_ACTIVE_ARCH = NO; + OTHER_SWIFT_FLAGS = ""; + PROVISIONING_PROFILE = ""; + SDKROOT = iphoneos; + SWIFT_OBJC_BRIDGING_HEADER = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VALID_ARCHS = "armv6 armv7s armv7"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + B5C01B3B1D12F44900E17566 /* Build configuration list for PBXNativeTarget "SwiftCSSFramework" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B5C01B3C1D12F44900E17566 /* Debug */, + B5C01B3D1D12F44900E17566 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; + B5D2A7D11D106AAF0006D52C /* Build configuration list for PBXProject "SwiftCSSFramework" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B5D2A7E91D106AAF0006D52C /* Debug */, + B5D2A7EA1D106AAF0006D52C /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; +/* End XCConfigurationList section */ + }; + rootObject = B5D2A7CE1D106AAF0006D52C /* Project object */; +} diff --git a/SwiftCSSFramework.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/SwiftCSSFramework.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..49a564c --- /dev/null +++ b/SwiftCSSFramework.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/SwiftCSSFramework.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/SwiftCSSFramework.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/SwiftCSSFramework.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/SwiftCSSFramework.xcodeproj/xcshareddata/xcschemes/SwiftCSSFramework.xcscheme b/SwiftCSSFramework.xcodeproj/xcshareddata/xcschemes/SwiftCSSFramework.xcscheme new file mode 100644 index 0000000..41ac720 --- /dev/null +++ b/SwiftCSSFramework.xcodeproj/xcshareddata/xcschemes/SwiftCSSFramework.xcscheme @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SwiftCSSFramework/DeferredStyles/DeferredStyle.swift b/SwiftCSSFramework/DeferredStyles/DeferredStyle.swift new file mode 100644 index 0000000..de9382e --- /dev/null +++ b/SwiftCSSFramework/DeferredStyles/DeferredStyle.swift @@ -0,0 +1,46 @@ +// +// DeferredStyle.swift +// SwiftCSS +// +// Created by Salvador Mósca on 06/06/2016. +// Copyright © 2017 NDrive SA. All rights reserved. +// + +import Foundation +import UIKit + +public class DeferredStyle: RegistrableStyle +{ + @objc public var elemName: String + @objc public var parents : [String] + @objc public var type: String + @objc public var styleId: Int + private var style: (T) -> Void + + init(elemName : String? = nil, parents: [String]? = nil, style: @escaping (T) -> Void) + { + self.elemName = elemName ?? "" + self.parents = parents ?? [] + self.type = "\(T.self)" + self.style = style + self.styleId = 0 + } + + @objc public func process(elem: AnyObject) + { + guard let b = elem as? T else { return } + self.style(b) + } +} + +public class StatusBarStyle +{ + public var style: UIStatusBarStyle + public var hide: Bool + + public init(style: UIStatusBarStyle, hide: Bool) + { + self.style = style + self.hide = hide + } +} diff --git a/SwiftCSSFramework/DeferredStyles/RegisteredStatusBarStyles.swift b/SwiftCSSFramework/DeferredStyles/RegisteredStatusBarStyles.swift new file mode 100644 index 0000000..677f2bd --- /dev/null +++ b/SwiftCSSFramework/DeferredStyles/RegisteredStatusBarStyles.swift @@ -0,0 +1,35 @@ +// +// RegisteredStatusBarStyles.swift +// SwiftCSSFramework +// +// Created by Salvador Mósca on 14/07/2016. +// Copyright © 2017 NDrive SA. All rights reserved. +// + +import Foundation + +public class StatusBarStyles +{ + private static var dict: Dictionary StatusBarStyle> = [:] + private static var defaultStyle: (() -> StatusBarStyle)! + + public static func register(dict: Dictionary StatusBarStyle>) throws + { + self.dict = dict + + guard let _defaultStyle = self.dict["default"] else + { + throw SwiftCSSErrors.MissingDefault("One style must be registered as default") + } + + self.defaultStyle = _defaultStyle + } + + static func get(identifier: String?) -> StatusBarStyle + { + // Empty identifier or key not found returns the default + guard identifier.exists && self.dict[identifier!].exists else { return self.defaultStyle() } + + return self.dict[identifier!]!() + } +} diff --git a/SwiftCSSFramework/DeferredStyles/RegisteredStyles.swift b/SwiftCSSFramework/DeferredStyles/RegisteredStyles.swift new file mode 100644 index 0000000..58ce93d --- /dev/null +++ b/SwiftCSSFramework/DeferredStyles/RegisteredStyles.swift @@ -0,0 +1,105 @@ +// +// RegisteredStyles.swift +// SwiftCSS +// +// Created by Salvador Mósca on 14/06/2016. +// Copyright © 2017 NDrive SA. All rights reserved. +// + +import Foundation + +public class Styles +{ + private static private(set) var all: [RegistrableStyle] = [] + private static var stylesDictionary = Dictionary>() + private static var typeMapping = Dictionary() + private static var isReady = false + + public static func register(array: [RegistrableStyle]) + { + self.all += array + } + + public static func getCandidateStylesFor(elem: AnyObject, elemName: String?) -> [RegistrableStyle]? + { + if !self.isReady { return nil } + + let localElemName = elemName ?? "" + let myType = "\(type(of: elem))" + + if let mappedType = typeMapping[myType] + { + return mappedType.isBlacklisted ? nil : (mappedType.cachedStyles![localElemName] ?? mappedType.cachedStyles![""]) + } + + let myTypes = myType.components(separatedBy: "_") + + var foundType = false + + for type in myTypes + { + if let value = self.stylesDictionary[type] + { + typeMapping[myType] = ClassMapping(isBlacklisted: false, mappedClassName: type, cachedStyles: value) + foundType = true + + return value[localElemName] ?? value[""] + } + } + + if !foundType + { + typeMapping[myType] = ClassMapping(isBlacklisted: true, mappedClassName: nil, cachedStyles: nil) + } + + return nil + } + + public static func build() + { + for style in self.all + { + if stylesDictionary[style.type].exists + { + if !(stylesDictionary[style.type]![style.elemName].exists) + { + stylesDictionary[style.type]![style.elemName] = [] + } + } + else + { + stylesDictionary[style.type] = [ style.elemName :[]] + } + } + + for style in self.all + { + if !(stylesDictionary[style.type].exists) + { + continue // Just in case.... + } + + if style.elemName == "" + { + for (key, _) in stylesDictionary[style.type]! + { + stylesDictionary[style.type]![key]!.append(style) + } + } + + else if stylesDictionary[style.type]![style.elemName].exists + { + stylesDictionary[style.type]![style.elemName]!.append(style) + } + } + + self.isReady = true + } +} + +private struct ClassMapping +{ + var isBlacklisted: Bool + var mappedClassName: String? + var cachedStyles: Dictionary? +} diff --git a/SwiftCSSFramework/DeferredStyles/StyleResover.swift b/SwiftCSSFramework/DeferredStyles/StyleResover.swift new file mode 100644 index 0000000..ff6c55b --- /dev/null +++ b/SwiftCSSFramework/DeferredStyles/StyleResover.swift @@ -0,0 +1,36 @@ +// +// StyleResover.swift +// SwiftCSS +// +// Created by Salvador Mósca on 07/06/2016. +// Copyright © 2017 NDrive SA. All rights reserved. +// + +import Foundation +import UIKit + +class StyleResolver +{ + func resolve(elemName: String?, me: UIView) + { + guard let registeredStyles = Styles.getCandidateStylesFor(elem: me, elemName: elemName) else { return } + + registeredStyles.forEach({ + + if me.matchesViewStack(parents: $0.parents) + { + $0.process(elem: me) + } + }) + } + + func hideStatusBar(me: UIViewController) -> Bool + { + return StatusBarStyles.get(identifier: me.getIdentifier()).hide + } + + func statusBarStyle(me: UIViewController) -> UIStatusBarStyle + { + return StatusBarStyles.get(identifier: me.getIdentifier()).style + } +} diff --git a/SwiftCSSFramework/DeferredStyles/Stylize.swift b/SwiftCSSFramework/DeferredStyles/Stylize.swift new file mode 100644 index 0000000..b94f4cf --- /dev/null +++ b/SwiftCSSFramework/DeferredStyles/Stylize.swift @@ -0,0 +1,27 @@ +// +// Stylize.swift +// SwiftCSS +// +// Created by Salvador Mósca on 13/06/2016. +// Copyright © 2017 NDrive SA. All rights reserved. +// + +import Foundation + +public class Stylize +{ + public class func all(_ style: @escaping (T) -> Void) -> DeferredStyle + { + return DeferredStyle(elemName: nil, style: style) + } + + public class func nestedIn(_ parents: [String], style: @escaping (T) -> Void) -> DeferredStyle + { + return DeferredStyle(parents: parents, style: style) + } + + public class func elem(_ elemName: String, childOf: [String]? = nil, style: @escaping (T) -> Void) -> DeferredStyle + { + return DeferredStyle(elemName: elemName, parents: childOf, style: style) + } +} diff --git a/SwiftCSSFramework/Extensions/OptionalExtensions.swift b/SwiftCSSFramework/Extensions/OptionalExtensions.swift new file mode 100644 index 0000000..5b9d221 --- /dev/null +++ b/SwiftCSSFramework/Extensions/OptionalExtensions.swift @@ -0,0 +1,15 @@ +// +// OptionalExtensions.swift +// SwiftCSS +// +// Created by Salvador Mósca on 09/06/2016. +// Copyright © 2017 NDrive SA. All rights reserved. +// + +import Foundation +import UIKit + +extension Optional +{ + var exists:Bool { get { return self != nil }} +} diff --git a/SwiftCSSFramework/Extensions/UIImageViewExtensions.swift b/SwiftCSSFramework/Extensions/UIImageViewExtensions.swift new file mode 100644 index 0000000..deafc8b --- /dev/null +++ b/SwiftCSSFramework/Extensions/UIImageViewExtensions.swift @@ -0,0 +1,32 @@ +// +// UITableViewExtension.swift +// SwiftCSSFramework +// +// Created by Salvador Mósca on 27/06/2016. +// Copyright © 2017 NDrive SA. All rights reserved. +// + +import Foundation +import UIKit + +extension UIImageView +{ + private struct AssociatedKeys + { + static var RenderingMode: Int = 0 + } + + @objc public var renderingMode: UIImage.RenderingMode + { + get + { + let enumValue = (objc_getAssociatedObject(self, &AssociatedKeys.RenderingMode) as? Int) ?? UIImage.RenderingMode.automatic.rawValue + return UIImage.RenderingMode(rawValue: enumValue)! + } + + set + { + objc_setAssociatedObject(self, &AssociatedKeys.RenderingMode, newValue.rawValue , .OBJC_ASSOCIATION_RETAIN_NONATOMIC) + } + } +} diff --git a/SwiftCSSFramework/Extensions/UIViewControllerExtensions.swift b/SwiftCSSFramework/Extensions/UIViewControllerExtensions.swift new file mode 100644 index 0000000..adcae9e --- /dev/null +++ b/SwiftCSSFramework/Extensions/UIViewControllerExtensions.swift @@ -0,0 +1,65 @@ +// +// UIViewControllerExtensions.swift +// SwiftCSSFramework +// +// Created by Salvador Mósca on 14/07/2016. +// Copyright © 2017 NDrive SA. All rights reserved. +// + +import Foundation +import UIKit + +extension UIViewController +{ + private struct AssociatedKeys + { + static var DescriptiveName = "" + } + + private var identifier: String? + { + get + { + return objc_getAssociatedObject(self, &AssociatedKeys.DescriptiveName) as? String + } + + set + { + if let newValue = newValue + { + objc_setAssociatedObject(self, &AssociatedKeys.DescriptiveName, newValue as NSString?, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) + } + } + } + + @IBInspectable + open var StatusBarStyleId: String? + { + set + { + self.identifier = newValue + } + get + { + return self.identifier + } + } + + internal func getIdentifier() -> String? + { + var me: UIViewController? = self + + while me != nil + { + if me!.StatusBarStyleId == "inherit" + { + me = me!.parent + continue + } + + return me!.StatusBarStyleId + } + + return nil + } +} diff --git a/SwiftCSSFramework/Extensions/UIViewControllerSwizzledExtension.swift b/SwiftCSSFramework/Extensions/UIViewControllerSwizzledExtension.swift new file mode 100644 index 0000000..53cc64f --- /dev/null +++ b/SwiftCSSFramework/Extensions/UIViewControllerSwizzledExtension.swift @@ -0,0 +1,61 @@ +// +// UIViewControllerSwizzledExtension.swift +// SwiftCSSFramework +// +// Created by Salvador Mósca on 14/07/2016. +// Copyright © 2017 NDrive SA. All rights reserved. +// + + +import Foundation +import UIKit + +extension UIViewController +{ + class func performSwizzling() throws + { + // Status bar hidden + let originalPrefersStatusBarHiddenSelector = #selector(getter: prefersStatusBarHidden) + let swizzledPrefersStatusBarHiddenSelector = #selector(nsh_prefersStatusBarHidden) + + guard let originalPrefersStatusBarHiddenMethod = class_getInstanceMethod(self, originalPrefersStatusBarHiddenSelector), + let swizzledPrefersStatusBarHiddenMethod = class_getInstanceMethod(self, swizzledPrefersStatusBarHiddenSelector) else { + throw SwiftCSSErrors.Swizzling("Cannot access status bar hidden instance methods") + } + + let didAddPrefersStatusBarHiddenMethod = class_addMethod(self, originalPrefersStatusBarHiddenSelector, method_getImplementation(swizzledPrefersStatusBarHiddenMethod), method_getTypeEncoding(swizzledPrefersStatusBarHiddenMethod)) + + // Status bar style + let originalPreferredStatusBarStyleSelector = #selector(getter: preferredStatusBarStyle) + let swizzledPreferredStatusBarStyleSelector = #selector(nsh_preferredStatusBarStyle) + + guard let originalPreferredStatusBarStyleMethod = class_getInstanceMethod(self, originalPreferredStatusBarStyleSelector), + let swizzledPreferredStatusBarStyleMethod = class_getInstanceMethod(self, swizzledPreferredStatusBarStyleSelector) else { + throw SwiftCSSErrors.Swizzling("Cannot access status bar style instance methods") + } + + let didAddPreferredStatusBarStyleMethod = class_addMethod(self, originalPreferredStatusBarStyleSelector, method_getImplementation(swizzledPreferredStatusBarStyleMethod), method_getTypeEncoding(swizzledPreferredStatusBarStyleMethod)) + + if didAddPrefersStatusBarHiddenMethod && didAddPreferredStatusBarStyleMethod + { + class_replaceMethod(self, swizzledPrefersStatusBarHiddenSelector, method_getImplementation(originalPrefersStatusBarHiddenMethod), method_getTypeEncoding(originalPrefersStatusBarHiddenMethod)) + + class_replaceMethod(self, swizzledPreferredStatusBarStyleSelector, method_getImplementation(originalPreferredStatusBarStyleMethod), method_getTypeEncoding(originalPreferredStatusBarStyleMethod)) + return + } + + method_exchangeImplementations(originalPrefersStatusBarHiddenMethod, swizzledPrefersStatusBarHiddenMethod) + method_exchangeImplementations(originalPreferredStatusBarStyleMethod, swizzledPreferredStatusBarStyleMethod) + } + + @objc func nsh_preferredStatusBarStyle() -> UIStatusBarStyle + { + return StyleResolver().statusBarStyle(me: self) + } + + @objc func nsh_prefersStatusBarHidden() -> Bool + { + guard UIApplication.shared.statusBarOrientation.isPortrait else { return true } + return StyleResolver().hideStatusBar(me: self) + } +} diff --git a/SwiftCSSFramework/Extensions/UIViewExtensions.swift b/SwiftCSSFramework/Extensions/UIViewExtensions.swift new file mode 100644 index 0000000..6b33df5 --- /dev/null +++ b/SwiftCSSFramework/Extensions/UIViewExtensions.swift @@ -0,0 +1,128 @@ +// +// UIViewExtensions.swift +// SwiftCSS +// +// Created by Salvador Mósca on 09/06/2016. +// Copyright © 2017 NDrive SA. All rights reserved. +// + +import Foundation +import UIKit + +extension UIView +{ + private struct AssociatedKeys + { + static var DescriptiveName = "" + static var AppliedStyles: Bool = false + static var ForceApply: Bool = false + static var MyParent: UIView? = nil + } + + public var hasAppliedStyles: Bool + { + get + { + return (objc_getAssociatedObject(self, &AssociatedKeys.AppliedStyles) as? Bool) ?? false + } + + set + { + objc_setAssociatedObject(self, &AssociatedKeys.AppliedStyles, newValue as Bool, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) + } + } + + private var childOf: UIView? + { + get + { + return self.superview ?? objc_getAssociatedObject(self, &AssociatedKeys.MyParent) as? UIView + } + + set + { + objc_setAssociatedObject(self, &AssociatedKeys.MyParent, newValue as UIView?, .OBJC_ASSOCIATION_ASSIGN) + } + } + + private var identifier: String? + { + get + { + return objc_getAssociatedObject(self, &AssociatedKeys.DescriptiveName) as? String + } + + set + { + if let newValue = newValue + { + objc_setAssociatedObject(self, &AssociatedKeys.DescriptiveName, newValue as NSString?, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) + } + } + } + + @IBInspectable + public var CSS: String? + { + set + { + if self.identifier != newValue + { + self.hasAppliedStyles = false + } + + self.identifier = newValue + self.resolveStyle(injectedSuperview: self.superview) + } + + get { return self.identifier } + } + + func getIdentifier() -> String? + { + return self.identifier + } + + public func resolveStyle(injectedSuperview: UIView? = nil) + { + self.childOf = injectedSuperview + + guard !self.hasAppliedStyles && injectedSuperview.exists else { return } + + StyleResolver().resolve(elemName: self.CSS, me: self) + + for subView in self.subviews + { + subView.hasAppliedStyles = false + subView.resolveStyle(injectedSuperview: self) + } + + self.hasAppliedStyles = true + } + + func matchesViewStack(parents: [String]) -> Bool + { + // No parents, if matches type style must be applied + if parents.count == 0 + { + return true + } + + var context: UIView? = self.childOf + + var index = parents.count - 1 + + while context != nil + { + if (context!.CSS.exists && parents[index] == context!.CSS!) { + index -= 1 + } + + guard index >= 0 else { return true } + + context = context!.childOf ?? nil + } + + return false + } +} diff --git a/SwiftCSSFramework/Extensions/UIViewSwizzledExtension.swift b/SwiftCSSFramework/Extensions/UIViewSwizzledExtension.swift new file mode 100644 index 0000000..edee75d --- /dev/null +++ b/SwiftCSSFramework/Extensions/UIViewSwizzledExtension.swift @@ -0,0 +1,74 @@ +// +// UIViewSwizzledExtension.swift +// SwiftCSS +// +// Created by Salvador Mósca on 07/06/2016. +// Copyright © 2017 NDrive SA. All rights reserved. +// +// Reference from NSHipster: http://nshipster.com/swift-objc-runtime/ + +import Foundation +import UIKit + +extension UIView +{ + class func performSwizzling() throws + { + // Move to window methods + let originalMoveToWindowsSelector = #selector(UIView.willMove(toWindow:)) + let swizzledMoveToWindowsSelector = #selector(UIView.nsh_willMove(toWindow:)) + + guard let originalMoveToWindowsMethod = class_getInstanceMethod(self, originalMoveToWindowsSelector), + let swizzledMoveToWindowsMethod = class_getInstanceMethod(self, swizzledMoveToWindowsSelector) else { + throw SwiftCSSErrors.Swizzling("Cannot access instance methods for move to window selectors") + } + + // Move to superview methods + let originalMoveToSuperviewSelector = #selector(UIView.willMove(toSuperview:)) + let swizzledMoveToSuperviewSelector = #selector(UIView.nsh_willMove(toSuperview:)) + + guard let originalMoveToSuperviewMethod = class_getInstanceMethod(self, originalMoveToSuperviewSelector), + let swizzledMoveToSuperviewMethod = class_getInstanceMethod(self, swizzledMoveToSuperviewSelector) else { + throw SwiftCSSErrors.Swizzling("Cannot access instance methods for move to superview selectors") + } + + let didAddMoveToWindowsMethod = class_addMethod(self, originalMoveToWindowsSelector, method_getImplementation(swizzledMoveToWindowsMethod), method_getTypeEncoding(swizzledMoveToWindowsMethod)) + + let didAddMoveToSuperviewMethod = class_addMethod(self, originalMoveToSuperviewSelector, method_getImplementation(swizzledMoveToSuperviewMethod), method_getTypeEncoding(swizzledMoveToSuperviewMethod)) + + + if didAddMoveToWindowsMethod && didAddMoveToSuperviewMethod + { + class_replaceMethod(self, swizzledMoveToWindowsSelector, method_getImplementation(originalMoveToWindowsMethod), method_getTypeEncoding(originalMoveToWindowsMethod)) + + class_replaceMethod(self, swizzledMoveToSuperviewSelector, method_getImplementation(originalMoveToSuperviewMethod), method_getTypeEncoding(originalMoveToSuperviewMethod)) + + return + } + + method_exchangeImplementations(originalMoveToWindowsMethod, swizzledMoveToWindowsMethod) + method_exchangeImplementations(originalMoveToSuperviewMethod, swizzledMoveToSuperviewMethod) + } + + //MARK: - Method Swizzling + @objc func nsh_willMove(toWindow: UIWindow?) + { + if(!toWindow.exists) + { + self.hasAppliedStyles = false + return + } + + self.resolveStyle(injectedSuperview: self.superview) + } + + @objc func nsh_willMove(toSuperview: UIView?) + { + if(!toSuperview.exists) + { + self.hasAppliedStyles = false + } + + self.resolveStyle(injectedSuperview: toSuperview) + } +} diff --git a/SwiftCSSFramework/Headers/SwiftCSSFramework.h b/SwiftCSSFramework/Headers/SwiftCSSFramework.h new file mode 100644 index 0000000..6dcc322 --- /dev/null +++ b/SwiftCSSFramework/Headers/SwiftCSSFramework.h @@ -0,0 +1,18 @@ +// +// SwiftCSSFramework.h +// SwiftCSSFramework +// +// Created by Salvador Mósca on 14/06/2016. +// Copyright © 2017 NDrive SA. All rights reserved. +// + +#import + +//! Project version number for SwiftCSSFramework. +FOUNDATION_EXPORT double SwiftCSSFrameworkVersionNumber; + +//! Project version string for SwiftCSSFramework. +FOUNDATION_EXPORT const unsigned char SwiftCSSFrameworkVersionString[]; + +// In this header, you should import all the public headers of your framework using statements like #import + diff --git a/SwiftCSSFramework/Info.plist b/SwiftCSSFramework/Info.plist new file mode 100644 index 0000000..d3de8ee --- /dev/null +++ b/SwiftCSSFramework/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSPrincipalClass + + + diff --git a/SwiftCSSFramework/Protocols/Customizable.swift b/SwiftCSSFramework/Protocols/Customizable.swift new file mode 100644 index 0000000..317d5d7 --- /dev/null +++ b/SwiftCSSFramework/Protocols/Customizable.swift @@ -0,0 +1,23 @@ +// +// Protocols.swift +// SwiftCSS +// +// Created by Salvador Mósca on 06/06/2016. +// Copyright © 2017 NDrive SA. All rights reserved. +// + +import Foundation + +public protocol Brandable { } + +extension UIView : Brandable {} + +@objc public protocol RegistrableStyle +{ + var elemName: String { get set} + var parents: [String] { get set} + var type: String { get set} + var styleId: Int { get set} // <- Just for checking the apply of the styles + + func process(elem: AnyObject) +} diff --git a/SwiftCSSFramework/Sources/SwiftCSSFramework.swift b/SwiftCSSFramework/Sources/SwiftCSSFramework.swift new file mode 100644 index 0000000..cc4cae2 --- /dev/null +++ b/SwiftCSSFramework/Sources/SwiftCSSFramework.swift @@ -0,0 +1,29 @@ +// +// SwiftCSSFramework.swift +// SwiftCSSFramework +// +// Created by Vitor Magalhães on 09/08/2017. +// Copyright © 2017 Salvador Mósca. All rights reserved. +// + +import Foundation + +@objc public class SwiftCSSFramework: NSObject { + + @discardableResult + override init() { } + + public static func enable() { + _ = swizzle + } + + static private let swizzle: Void = + { + do { + try UIView.performSwizzling() + try UIViewController.performSwizzling() + } catch { + fatalError("SwiftCSSFramework swizzling has failed!") + } + }() +} diff --git a/SwiftCSSFramework/Utils/Logger.swift b/SwiftCSSFramework/Utils/Logger.swift new file mode 100644 index 0000000..4e8273c --- /dev/null +++ b/SwiftCSSFramework/Utils/Logger.swift @@ -0,0 +1,37 @@ +// +// Logger.swift +// SwiftCSS +// +// Created by Salvador Mósca on 13/06/2016. +// Copyright © 2017 NDrive SA. All rights reserved. +// + +import Foundation + +func log(text: String) +{ + if SwiftCSSFrameworkSettings.enableTrace + { + print(text) + } +} + +public class SwiftCSSFrameworkSettings +{ + public static var enableTrace: Bool = true + + public static var version: String { get + { + let dictionary = Bundle.main.infoDictionary! + let version = dictionary["CFBundleShortVersionString"] as! String + let build = dictionary["CFBundleVersion"] as! String + return "SwiftCSSFramework version: \(version) build: \(build)" + }} +} + +public enum SwiftCSSErrors: Error +{ + case MissingDefault(String) + case NoStyleRegistered(String) + case Swizzling(String) +}