From 7e48670179862ac05f93fcca898bc06b2e280949 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Wed, 4 Dec 2019 12:38:57 -0500 Subject: [PATCH] Adding Model for UIColor and supporting UIColor Extension. --- MVMCoreUI.xcodeproj/project.pbxproj | 18 +- MVMCoreUI/Categories/UIColor+Extension.swift | 180 ++++++++++++++++++ .../Models/ConstrainingMoleculeProtocol.swift | 2 +- MVMCoreUI/Models/MoleculeProtocol.swift | 16 +- .../Models/Molecules/FormModelProtocol.swift | 6 +- MVMCoreUI/Models/Molecules/HeaderModel.swift | 3 +- .../Models/Primitive Models/ColorModel.swift | 95 +++++++++ 7 files changed, 305 insertions(+), 15 deletions(-) create mode 100644 MVMCoreUI/Categories/UIColor+Extension.swift create mode 100644 MVMCoreUI/Models/Primitive Models/ColorModel.swift diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index 6a7921e5..9215b753 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -48,6 +48,8 @@ 0A41BA6E2344FCD400D4C0BC /* CATransaction+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A41BA6D2344FCD400D4C0BC /* CATransaction+Extension.swift */; }; 0A7BAD74232A8DC700FB8E22 /* HeadlineBodyButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAD73232A8DC700FB8E22 /* HeadlineBodyButton.swift */; }; 0A7BAFA1232BE61800FB8E22 /* Checkbox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAFA0232BE61800FB8E22 /* Checkbox.swift */; }; + 0AA33B34239813C50067DD0F /* UIColor+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AA33B33239813C50067DD0F /* UIColor+Extension.swift */; }; + 0AA33B36239813EE0067DD0F /* ColorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AA33B35239813EE0067DD0F /* ColorModel.swift */; }; 943784F5236B77BB006A1E82 /* GraphView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 943784F3236B77BB006A1E82 /* GraphView.swift */; }; 943784F6236B77BB006A1E82 /* GraphViewAnimationHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 943784F4236B77BB006A1E82 /* GraphViewAnimationHandler.swift */; }; 9445890C2385BCE300DE9FD4 /* ProgressBarModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9445890B2385BCE300DE9FD4 /* ProgressBarModel.swift */; }; @@ -279,6 +281,8 @@ 0A7BAD73232A8DC700FB8E22 /* HeadlineBodyButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadlineBodyButton.swift; sourceTree = ""; }; 0A7BAFA0232BE61800FB8E22 /* Checkbox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Checkbox.swift; sourceTree = ""; }; 0A7BAFA2232BE63400FB8E22 /* CheckboxWithLabelView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckboxWithLabelView.swift; sourceTree = ""; }; + 0AA33B33239813C50067DD0F /* UIColor+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIColor+Extension.swift"; sourceTree = ""; }; + 0AA33B35239813EE0067DD0F /* ColorModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorModel.swift; sourceTree = ""; }; 943784F3236B77BB006A1E82 /* GraphView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GraphView.swift; sourceTree = ""; }; 943784F4236B77BB006A1E82 /* GraphViewAnimationHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GraphViewAnimationHandler.swift; sourceTree = ""; }; 9445890B2385BCE300DE9FD4 /* ProgressBarModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressBarModel.swift; sourceTree = ""; }; @@ -488,6 +492,7 @@ 01509D96232803B200EF99AA /* Models */ = { isa = PBXGroup; children = ( + 0AA33B322398134B0067DD0F /* Primitive Models */, 017BEB392360EEB40024EF95 /* PageModel.swift */, 01EB3683236097C0006832FA /* MoleculeProtocol.swift */, 012CA9BD2385C692003F810F /* ConstrainingMoleculeProtocol.swift */, @@ -524,6 +529,14 @@ path = Molecules; sourceTree = ""; }; + 0AA33B322398134B0067DD0F /* Primitive Models */ = { + isa = PBXGroup; + children = ( + 0AA33B35239813EE0067DD0F /* ColorModel.swift */, + ); + path = "Primitive Models"; + sourceTree = ""; + }; 946EE1B5237B663A0036751F /* Extensions */ = { isa = PBXGroup; children = ( @@ -779,6 +792,7 @@ D29DF11221E6805F003B2FB9 /* NSLayoutConstraint+MFConvenience.h */, D29DF11421E6805F003B2FB9 /* NSLayoutConstraint+MFConvenience.m */, D22479932316AE5E003FCCF9 /* NSLayoutConstraintExtension.swift */, + 0AA33B33239813C50067DD0F /* UIColor+Extension.swift */, ); path = Categories; sourceTree = ""; @@ -879,7 +893,7 @@ DBC4391722442197001AB423 /* DashLine.swift */, 944589202385D6E900DE9FD4 /* DashLineModel.swift */, DB06250A2293456500B72DD3 /* LeftRightLabelView.swift */, - 012CA99D2385A2D3003F810F /* MFView+ModelExtension.swift */, + 012CA99D2385A2D3003F810F /* MFView+ModelExtension.swift */, D29DF28721E7AC2B003B2FB9 /* ViewConstrainingView.h */, D29DF28821E7AC2B003B2FB9 /* ViewConstrainingView.m */, 012CA99B23859FDC003F810F /* ViewConstrainingView+ModelExtension.swift */, @@ -1208,6 +1222,7 @@ 94C2D9A923872E5E0006CF46 /* LabelAttributeImageModel.swift in Sources */, 012CA98923849699003F810F /* SeperatorModel.swift in Sources */, DBC4391922442197001AB423 /* DashLine.swift in Sources */, + 0AA33B34239813C50067DD0F /* UIColor+Extension.swift in Sources */, 0A7BAD74232A8DC700FB8E22 /* HeadlineBodyButton.swift in Sources */, D29DF29621E7ADB8003B2FB9 /* StackableViewController.m in Sources */, 0116A4E5228B19640094F3ED /* RadioButtonModel.swift in Sources */, @@ -1273,6 +1288,7 @@ 0105618F224BBE7700E1557D /* FormValidator+FormParams.swift in Sources */, 0A7BAFA1232BE61800FB8E22 /* Checkbox.swift in Sources */, D22479962316AF6E003FCCF9 /* HeadlineBodyTextButton.swift in Sources */, + 0AA33B36239813EE0067DD0F /* ColorModel.swift in Sources */, D29DF2AE21E7B3A4003B2FB9 /* MFTextView.m in Sources */, 017BEB382360C6AC0024EF95 /* RadioButtonLabel.swift in Sources */, D29DF18121E69E50003B2FB9 /* MFView.m in Sources */, diff --git a/MVMCoreUI/Categories/UIColor+Extension.swift b/MVMCoreUI/Categories/UIColor+Extension.swift new file mode 100644 index 00000000..56986044 --- /dev/null +++ b/MVMCoreUI/Categories/UIColor+Extension.swift @@ -0,0 +1,180 @@ +// +// UIColor+Extension.swift +// MVMCoreUI +// +// Created by Kevin Christiano on 10/24/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + + +import UIKit + + +extension UIColor { + //-------------------------------------------------- + // MARK: - Brand + //-------------------------------------------------- + + /// HEX: #000000 + public static let mvmBlack = UIColor.black + + /// HEX: #FFFFFF + public static let mvmWhite = UIColor.white + + /// HEX: #D52B1E + public static let mvmRed = UIColor.getColor(red: 213, green: 43, blue: 30) + + /// HEX: #CC4D0F + public static let mvmOrange = UIColor.getColor(red: 204, green: 77, blue: 15) + + /// HEX: #008631 + public static let mvmGreen = UIColor.getColor(red: 0, green: 134, blue: 49) + + /// HEX: #007AB8 + public static let mvmBlue = UIColor.getColor(red: 0, green: 122, blue: 184) + + /// HEX: #007AB8 + public static let mvmBlueGradient = UIColor.getColor(red: 0, green: 122, blue: 184) + + /// HEX: #FFBC3D + public static let mvmYellow = UIColor.getColor(red: 255, green: 188, blue: 61) + + /// HEX: #F6F6F6 + public static let mvmCoolGray1 = UIColor.grayscale(rgb: 246) + + /// HEX: #D8DADA + public static let mvmCoolGray3 = UIColor.getColor(red: 216, green: 218, blue: 218) + + /// HEX: #747676 + public static let mvmCoolGray6 = UIColor.getColor(red: 116, green: 118, blue: 118) + + //-------------------------------------------------- + // MARK: - VZ UP Brand + //-------------------------------------------------- + + /// HEX: #B89B56 + public static let vzupGold = UIColor.getColor(red: 184, green: 155, blue: 68) + + /// HEX: #F9D542 + public static let vzupYellow1 = UIColor.getColor(red: 249, green: 213, blue: 66) + + /// HEX: #F4CA53 + public static let vzupYellow2 = UIColor.getColor(red: 244, green: 202, blue: 83) + + /// HEX: #CC9B2D + public static let vzupYellow3 = UIColor.getColor(red: 204, green: 155, blue: 45) + + //-------------------------------------------------- + // MARK: - Functions + //-------------------------------------------------- + + /// Convenience to get a grayscale UIColor where the same value is used for red, green, and blue. + public class func grayscale(rgb: Int, alpha: CGFloat = 1.0) -> UIColor { + + let grayscale = CGFloat(rgb) / 255.0 + return UIColor(red: grayscale, green: grayscale, blue: grayscale, alpha: alpha) + } + + /// Convenience to get a UIColor via Int. + public class func getColor(red: Int, green: Int, blue: Int, alpha: CGFloat = 1.0) -> UIColor { + + return UIColor(red: CGFloat(red) / 255.0, green: CGFloat(green) / 255.0, blue: CGFloat(blue) / 255.0, alpha: alpha) + } + + /// Convenience to get a UIColor via CGFloat. + public class func getColor(red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat = 1.0) -> UIColor { + + return UIColor(red: red / 255.0, green: green / 255.0, blue: blue / 255.0, alpha: alpha) + } + + /// Gets UIColor via an 8 digit hex string. + public class func getColorBy(hex: String) -> UIColor { + + var hexint: UInt32 = 0 + + let scanner = Scanner(string: hex) + scanner.charactersToBeSkipped = CharacterSet(charactersIn: "#") + scanner.scanHexInt32(&hexint) + + return UIColor(red: (CGFloat((hexint & 0xFF0000) >> 16)) / 255, + green: (CGFloat((hexint & 0xFF00) >> 8)) / 255, + blue: (CGFloat(hexint & 0xFF)) / 255, + alpha: 1) + } + + /// Gets UIColor via an 8 digit hex string. The last two being the alpha channel. + public class func getColorWithTransparencyBy(hex: String) -> UIColor { + + var hexint: UInt32 = 0 + + let scanner = Scanner(string: hex) + scanner.charactersToBeSkipped = CharacterSet(charactersIn: "#") + scanner.scanHexInt32(&hexint) + + return UIColor(red: (CGFloat((hexint & 0xFF000000) >> 24)) / 255, + green: (CGFloat((hexint & 0xFF0000) >> 16)) / 255, + blue: (CGFloat((hexint & 0xFF00) >> 8)) / 255, + alpha: (CGFloat(hexint & 0xFF)) / 255) + } + + public class func gradientColor(_ color: UIColor?) -> UIColor { + + var h: CGFloat = 0 + var s: CGFloat = 0 + var b: CGFloat = 0 + var a: CGFloat = 0 + + if color?.getHue(&h, saturation: &s, brightness: &b, alpha: &a) ?? false { + return UIColor(hue: h, saturation: max(s - 0.17, 0.0), brightness: min(b - 0.03, 1.0), alpha: a) + } + + return .white + } + + public class func setBackgroundColor(forNavigationBar color: UIColor, navigationBar: UINavigationBar, transparent: Bool) { + + DispatchQueue.main.async { + + let view = UIView(frame: CGRect(x: 0, y: 0, width: 1, height: 1)) + view.backgroundColor = color + + UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.isOpaque, 0.0) + + if let context = UIGraphicsGetCurrentContext() { + view.layer.render(in: context) + } + + let image = UIGraphicsGetImageFromCurrentImageContext() + UIGraphicsEndImageContext() + + if transparent { + navigationBar.setBackgroundImage(UIImage(), for: .default) + navigationBar.isTranslucent = false + } else { + navigationBar.setBackgroundImage(image, for: .default) + } + } + } + + /// - parameter color: The UIColor intended to retrieve its hex value. + public class func hexString(for color: UIColor) -> String? { + + guard let components = color.cgColor.components else { return nil } + + if color.cgColor.numberOfComponents >= 3 { + let r = Int(CGFloat(components[0]) * 255) + let g = Int(CGFloat(components[1]) * 255) + let b = Int(CGFloat(components[2]) * 255) + + // If alpha of color is less than 1.0 then alpha hex is relevant. + if color.cgColor.numberOfComponents == 4 && components[3] < 1.0 { + let a = Int(CGFloat(components[3]) * 255) + return String(format: "%02X%02X%02X%02X", r, g, b, a) + } + + return String(format: "%02X%02X%02X", r, g, b) + } + + return nil + } +} diff --git a/MVMCoreUI/Models/ConstrainingMoleculeProtocol.swift b/MVMCoreUI/Models/ConstrainingMoleculeProtocol.swift index 91d4a566..5cb24c4d 100644 --- a/MVMCoreUI/Models/ConstrainingMoleculeProtocol.swift +++ b/MVMCoreUI/Models/ConstrainingMoleculeProtocol.swift @@ -9,7 +9,7 @@ import Foundation public protocol ConstrainingMoleculeProtocol: MoleculeProtocol { - var molecule: MoleculeProtocol? {get} + var molecule: MoleculeProtocol? { get } } extension ConstrainingMoleculeProtocol { diff --git a/MVMCoreUI/Models/MoleculeProtocol.swift b/MVMCoreUI/Models/MoleculeProtocol.swift index 2ddc4061..e8120568 100644 --- a/MVMCoreUI/Models/MoleculeProtocol.swift +++ b/MVMCoreUI/Models/MoleculeProtocol.swift @@ -1,15 +1,15 @@ import Foundation public protocol MoleculeProtocol: Model { - var moleculeName: String? {get} - var backgroundColor: String? {get} - var dictionary: [AnyHashable: Any]? {get} - var molecule: MoleculeProtocol? {get} + var moleculeName: String? { get } + var backgroundColor: String? { get } + var dictionary: [AnyHashable: Any]? { get } + var molecule: MoleculeProtocol? { get } - var useHorizontalMargins: Bool? {get} - var useVerticalMargins: Bool? {get} - var horizontalAlignment: String? {get} - var verticalAlignment: String? {get} + var useHorizontalMargins: Bool? { get } + var useVerticalMargins: Bool? { get } + var horizontalAlignment: String? { get } + var verticalAlignment: String? { get } } extension MoleculeProtocol { diff --git a/MVMCoreUI/Models/Molecules/FormModelProtocol.swift b/MVMCoreUI/Models/Molecules/FormModelProtocol.swift index 4cd76354..aa298716 100644 --- a/MVMCoreUI/Models/Molecules/FormModelProtocol.swift +++ b/MVMCoreUI/Models/Molecules/FormModelProtocol.swift @@ -9,7 +9,7 @@ import Foundation public protocol FormModelProtocol: Model { - var required: Bool? {get} - var fieldKey: String? {get} - var groupName: String? {get} + var required: Bool? { get } + var fieldKey: String? { get } + var groupName: String? { get } } diff --git a/MVMCoreUI/Models/Molecules/HeaderModel.swift b/MVMCoreUI/Models/Molecules/HeaderModel.swift index 0dca783c..5d4129e2 100644 --- a/MVMCoreUI/Models/Molecules/HeaderModel.swift +++ b/MVMCoreUI/Models/Molecules/HeaderModel.swift @@ -15,7 +15,7 @@ import Foundation public var molecule: MoleculeProtocol? public var seperator: MoleculeProtocol? - public init(molecule: MoleculeProtocol?){ + public init(molecule: MoleculeProtocol?) { self.molecule = molecule self.moleculeName = Self.identifier } @@ -38,4 +38,3 @@ import Foundation try container.encodeIfPresent(self.molecule, forKey: .molecule) } } - diff --git a/MVMCoreUI/Models/Primitive Models/ColorModel.swift b/MVMCoreUI/Models/Primitive Models/ColorModel.swift new file mode 100644 index 00000000..68fb16de --- /dev/null +++ b/MVMCoreUI/Models/Primitive Models/ColorModel.swift @@ -0,0 +1,95 @@ +// +// ColorModel.swift +// MVMCoreUI +// +// Created by Kevin Christiano on 11/26/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import UIKit + +/** + Allows Hex values to be modeled into a UIColor object with its surrounding metadata. + */ +open class ColorModel: Codable { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + + static var identifier: String = "color" + + public let uiColor: UIColor + public var hex: String = "" + + public var red: CGFloat = 0 + public var green: CGFloat = 0 + public var blue: CGFloat = 0 + public var alpha: CGFloat = 1 + + public var hexWithHash: String { + return "#" + hex + } + + //-------------------------------------------------- + // MARK: - Class Initializer + //-------------------------------------------------- + + init(uiColor: UIColor) { + self.uiColor = uiColor + + hex = UIColor.hexString(for: uiColor) ?? "" + + if !hex.isEmpty { + determineRGBA() + } + } + + //-------------------------------------------------- + // MARK: - Codable Initializers + //-------------------------------------------------- + + required public init(from decoder: Decoder) throws { + let container = try decoder.singleValueContainer() + hex = try container.decode(String.self).replacingOccurrences(of: "#", with: "") + + if hex.count == 8 { + uiColor = UIColor.getColorWithTransparencyBy(hex: hex) + } else { + uiColor = UIColor.getColorBy(hex: hex) + } + + determineRGBA() + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.singleValueContainer() + try container.encode(hexWithHash) + } + + //-------------------------------------------------- + // MARK: - Methods + //-------------------------------------------------- + + public func convertHexToFloat(start: String.Index, end: String.Index) -> CGFloat { + + return CGFloat(Int(hex[start..