From febbd282cefd3528241c27281ad3b72a0bc9c5dc Mon Sep 17 00:00:00 2001 From: Krishna Kishore Bandaru Date: Thu, 22 Feb 2024 22:53:19 +0530 Subject: [PATCH] Updated DropShadowable to multiple configs --- VDS.xcodeproj/project.pbxproj | 8 +- .../Icon/ButtonIcon/ButtonIcon.swift | 75 +++++++----- .../TileContainer/TileContainer.swift | 21 ++-- VDS/Protocols/DropShadowable.swift | 113 ++++++++++++++++++ VDS/Protocols/Dropshadowable.swift | 64 ---------- 5 files changed, 174 insertions(+), 107 deletions(-) create mode 100644 VDS/Protocols/DropShadowable.swift delete mode 100644 VDS/Protocols/Dropshadowable.swift diff --git a/VDS.xcodeproj/project.pbxproj b/VDS.xcodeproj/project.pbxproj index b13f7df5..c7a20041 100644 --- a/VDS.xcodeproj/project.pbxproj +++ b/VDS.xcodeproj/project.pbxproj @@ -15,7 +15,7 @@ 5F21D7BF28DCEB3D003E7CD6 /* Useable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F21D7BE28DCEB3D003E7CD6 /* Useable.swift */; }; 5FC35BE328D51405004EBEAC /* Button.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FC35BE228D51405004EBEAC /* Button.swift */; }; 7115BD3C2B84C0C200E0A610 /* TileContainerChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 7115BD3B2B84C0C200E0A610 /* TileContainerChangeLog.txt */; }; - 71BFA70A2B7F70E6000DCE33 /* Dropshadowable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71BFA7092B7F70E6000DCE33 /* Dropshadowable.swift */; }; + 71BFA70A2B7F70E6000DCE33 /* DropShadowable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71BFA7092B7F70E6000DCE33 /* DropShadowable.swift */; }; 71C02B382B7BD98F00E93E66 /* NotificationChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 71C02B372B7BD98F00E93E66 /* NotificationChangeLog.txt */; }; EA0B18022A9E236900F2D0CD /* SelectorGroupBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA0B18012A9E236900F2D0CD /* SelectorGroupBase.swift */; }; EA0B18052A9E2D2D00F2D0CD /* SelectorBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA0B18032A9E2D2D00F2D0CD /* SelectorBase.swift */; }; @@ -181,7 +181,7 @@ 5F21D7BE28DCEB3D003E7CD6 /* Useable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Useable.swift; sourceTree = ""; }; 5FC35BE228D51405004EBEAC /* Button.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Button.swift; sourceTree = ""; }; 7115BD3B2B84C0C200E0A610 /* TileContainerChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = TileContainerChangeLog.txt; sourceTree = ""; }; - 71BFA7092B7F70E6000DCE33 /* Dropshadowable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Dropshadowable.swift; sourceTree = ""; }; + 71BFA7092B7F70E6000DCE33 /* DropShadowable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DropShadowable.swift; sourceTree = ""; }; 71C02B372B7BD98F00E93E66 /* NotificationChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = NotificationChangeLog.txt; sourceTree = ""; }; EA0B18012A9E236900F2D0CD /* SelectorGroupBase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectorGroupBase.swift; sourceTree = ""; }; EA0B18032A9E2D2D00F2D0CD /* SelectorBase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectorBase.swift; sourceTree = ""; }; @@ -560,7 +560,7 @@ EA3361B7288B2AAA0071C351 /* ViewProtocol.swift */, EAB1D2CC28ABE76000DAE764 /* Withable.swift */, 5F21D7BE28DCEB3D003E7CD6 /* Useable.swift */, - 71BFA7092B7F70E6000DCE33 /* Dropshadowable.swift */, + 71BFA7092B7F70E6000DCE33 /* DropShadowable.swift */, ); path = Protocols; sourceTree = ""; @@ -999,7 +999,7 @@ EAB2376229E9880400AABE9A /* TrailingTooltipLabel.swift in Sources */, EAB2376A29E9E59100AABE9A /* TooltipLaunchable.swift in Sources */, EAB2375D29E8789100AABE9A /* Tooltip.swift in Sources */, - 71BFA70A2B7F70E6000DCE33 /* Dropshadowable.swift in Sources */, + 71BFA70A2B7F70E6000DCE33 /* DropShadowable.swift in Sources */, EA0D1C452A6AD73000E5C127 /* RawRepresentable.swift in Sources */, EA985C23296E033A00F2FF2E /* TextArea.swift in Sources */, EAF7F0B3289B1ADC00B287F5 /* ActionLabelAttribute.swift in Sources */, diff --git a/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift b/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift index 16f0416f..97bbbb77 100644 --- a/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift +++ b/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift @@ -232,19 +232,26 @@ open class ButtonIcon: Control, Changeable, FormFieldable { }() } - private struct LowContrastColorFillFloatingConfiguration: Configuration, Dropshadowable { + private struct LowContrastColorFillFloatingConfiguration: Configuration, DropShadowableConfiguration { var kind: Kind = .lowContrast var surfaceType: SurfaceType = .colorFill var floating: Bool = true var backgroundColorConfiguration: AnyColorable = { SurfaceColorConfiguration(VDSColor.paletteWhite, VDSColor.paletteGray20).eraseToAnyColorable() }() - var shadowColorConfiguration: AnyColorable = { - SurfaceColorConfiguration(VDSColor.paletteBlack, VDSColor.paletteBlack).eraseToAnyColorable() - }() - var shadowOpacity: CGFloat = 0.16 - var shadowOffset: CGSize = .init(width: 0, height: 2) - var shadowRadius: CGFloat = 4 + private let dropshadow1Configuration = DropShadowConfiguration().with { + $0.shadowColorConfiguration = SurfaceColorConfiguration(VDSColor.paletteBlack, VDSColor.paletteBlack).eraseToAnyColorable() + $0.shadowOpacityConfiguration = AnyConfigurationValue(CGFloat(0.12), CGFloat(0.22)) + $0.shadowOffsetConfiguration = AnyConfigurationValue(.init(width: 0, height: 1), .init(width: 0, height: 1)) + $0.shadowRadiusConfiguration = AnyConfigurationValue(CGFloat(10), CGFloat(12)) + } + private let dropshadow2Configuration = DropShadowConfiguration().with { + $0.shadowColorConfiguration = SurfaceColorConfiguration(VDSColor.paletteBlack, VDSColor.paletteBlack).eraseToAnyColorable() + $0.shadowOpacityConfiguration = AnyConfigurationValue(CGFloat(0.15), CGFloat(0.22)) + $0.shadowOffsetConfiguration = AnyConfigurationValue(.init(width: 0, height: 2), .init(width: 0, height: 2)) + $0.shadowRadiusConfiguration = AnyConfigurationValue(CGFloat(4), CGFloat(6)) + } + var configurations: [DropShadowable] { [dropshadow1Configuration, dropshadow2Configuration] } } private struct LowContrastMediaConfiguration: Configuration, Borderable { @@ -260,19 +267,26 @@ open class ButtonIcon: Control, Changeable, FormFieldable { }() } - private struct LowContrastMediaFloatingConfiguration: Configuration, Dropshadowable { + private struct LowContrastMediaFloatingConfiguration: Configuration, DropShadowableConfiguration { var kind: Kind = .lowContrast var surfaceType: SurfaceType = .media var floating: Bool = true var backgroundColorConfiguration: AnyColorable = { SurfaceColorConfiguration(VDSColor.paletteWhite, VDSColor.paletteGray20).eraseToAnyColorable() }() - var shadowColorConfiguration: AnyColorable = { - SurfaceColorConfiguration(VDSColor.paletteBlack, VDSColor.paletteBlack).eraseToAnyColorable() - }() - var shadowOpacity: CGFloat = 0.16 - var shadowOffset: CGSize = .init(width: 0, height: 2) - var shadowRadius: CGFloat = 4 + private let dropshadow1Configuration = DropShadowConfiguration().with { + $0.shadowColorConfiguration = SurfaceColorConfiguration(VDSColor.paletteBlack, VDSColor.paletteBlack).eraseToAnyColorable() + $0.shadowOpacityConfiguration = AnyConfigurationValue(CGFloat(0.12), CGFloat(0.22)) + $0.shadowOffsetConfiguration = AnyConfigurationValue(.init(width: 0, height: 1), .init(width: 0, height: 1)) + $0.shadowRadiusConfiguration = AnyConfigurationValue(CGFloat(10), CGFloat(12)) + } + private let dropshadow2Configuration = DropShadowConfiguration().with { + $0.shadowColorConfiguration = SurfaceColorConfiguration(VDSColor.paletteBlack, VDSColor.paletteBlack).eraseToAnyColorable() + $0.shadowOpacityConfiguration = AnyConfigurationValue(CGFloat(0.05), CGFloat(0.15)) + $0.shadowOffsetConfiguration = AnyConfigurationValue(.init(width: 0, height: 2), .init(width: 0, height: 2)) + $0.shadowRadiusConfiguration = AnyConfigurationValue(CGFloat(4), CGFloat(6)) + } + var configurations: [DropShadowable] { [dropshadow1Configuration, dropshadow2Configuration] } } private struct HighContrastConfiguration: Configuration { @@ -291,7 +305,7 @@ open class ButtonIcon: Control, Changeable, FormFieldable { }() } - private struct HighContrastFloatingConfiguration: Configuration, Dropshadowable { + private struct HighContrastFloatingConfiguration: Configuration, DropShadowableConfiguration { var kind: Kind = .highContrast var surfaceType: SurfaceType = .colorFill var floating: Bool = true @@ -305,12 +319,19 @@ open class ButtonIcon: Control, Changeable, FormFieldable { $0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: [.selected, .disabled]) }.eraseToAnyColorable() }() - var shadowColorConfiguration: AnyColorable = { - SurfaceColorConfiguration(VDSColor.paletteBlack, VDSColor.paletteBlack).eraseToAnyColorable() - }() - var shadowOpacity: CGFloat = 0.16 - var shadowOffset: CGSize = .init(width: 0, height: 2) - var shadowRadius: CGFloat = 6 + private let dropshadow1Configuration = DropShadowConfiguration().with { + $0.shadowColorConfiguration = SurfaceColorConfiguration(VDSColor.paletteBlack, VDSColor.paletteBlack).eraseToAnyColorable() + $0.shadowOpacityConfiguration = AnyConfigurationValue(CGFloat(0.22), CGFloat(0.12)) + $0.shadowOffsetConfiguration = AnyConfigurationValue(.init(width: 0, height: 1), .init(width: 0, height: 1)) + $0.shadowRadiusConfiguration = AnyConfigurationValue(CGFloat(12), CGFloat(10)) + } + private let dropshadow2Configuration = DropShadowConfiguration().with { + $0.shadowColorConfiguration = SurfaceColorConfiguration(VDSColor.paletteBlack, VDSColor.paletteBlack).eraseToAnyColorable() + $0.shadowOpacityConfiguration = AnyConfigurationValue(CGFloat(0.15), CGFloat(0.05)) + $0.shadowOffsetConfiguration = AnyConfigurationValue(.init(width: 0, height: 2), .init(width: 0, height: 2)) + $0.shadowRadiusConfiguration = AnyConfigurationValue(CGFloat(6), CGFloat(4)) + } + var configurations: [DropShadowable] { [dropshadow1Configuration, dropshadow2Configuration] } } private var badgeIndicatorDefaultSize: CGSize = .zero @@ -452,12 +473,6 @@ open class ButtonIcon: Control, Changeable, FormFieldable { layer.borderColor = nil layer.borderWidth = 0 } - - if let dropshadowable = currentConfig as? Dropshadowable { - addDropShadow(dropshadowable) - } else { - removeDropShadows() - } badgeIndicatorCenterXConstraint?.constant = badgeIndicatorOffset.x + badgeIndicatorDefaultSize.width/2 badgeIndicatorCenterYConstraint?.constant = badgeIndicatorOffset.y + badgeIndicatorDefaultSize.height/2 @@ -467,6 +482,12 @@ open class ButtonIcon: Control, Changeable, FormFieldable { if showBadgeIndicator { updateExpandDirectionalConstraints() } + + if let configurations = (currentConfig as? DropShadowableConfiguration)?.configurations { + addDropShadows(configurations) + } else { + removeDropShadows() + } } //-------------------------------------------------- diff --git a/VDS/Components/TileContainer/TileContainer.swift b/VDS/Components/TileContainer/TileContainer.swift index 98090ae4..8dc2d9dd 100644 --- a/VDS/Components/TileContainer/TileContainer.swift +++ b/VDS/Components/TileContainer/TileContainer.swift @@ -184,9 +184,15 @@ open class TileContainer: Control { // MARK: - Configuration //-------------------------------------------------- private let cornerRadius = VDSFormControls.borderradius * 2 - private var backgroundColorConfiguration = BackgroundColorConfiguration() - private var dropshadowConfiguration = DropshadowConfiguration() + private let dropShadowConfiguration = DropShadowConfiguration().with { + $0.shadowColorConfiguration = SurfaceColorConfiguration().with { + $0.lightColor = VDSColor.elementsPrimaryOnlight + }.eraseToAnyColorable() + $0.shadowOffsetConfiguration = .init(.init(width: 0, height: 6), .zero) + $0.shadowRadiusConfiguration = .init(3.0, 0.0) + $0.shadowOpacityConfiguration = .init(0.01, 0.0) + } private var borderColorConfiguration = SurfaceColorConfiguration().with { $0.lightColor = VDSColor.elementsLowcontrastOnlight @@ -311,7 +317,7 @@ open class TileContainer: Control { heightConstraint?.isActive = false } if showDropShadows, surface == .light { - addDropShadow(dropshadowConfiguration) + addDropShadow(dropShadowConfiguration) } else { removeDropShadows() } @@ -397,15 +403,6 @@ open class TileContainer: Control { extension TileContainer { - struct DropshadowConfiguration: Dropshadowable { - var shadowColorConfiguration: AnyColorable = SurfaceColorConfiguration().with { - $0.lightColor = VDSColor.elementsPrimaryOnlight - }.eraseToAnyColorable() - var shadowOpacity: CGFloat = 0.01 - var shadowOffset: CGSize = .init(width: 0, height: 6) - var shadowRadius: CGFloat = 3 - } - final class BackgroundColorConfiguration: ObjectColorable { typealias ObjectType = TileContainer diff --git a/VDS/Protocols/DropShadowable.swift b/VDS/Protocols/DropShadowable.swift new file mode 100644 index 00000000..57c44036 --- /dev/null +++ b/VDS/Protocols/DropShadowable.swift @@ -0,0 +1,113 @@ +// +// DropShadowable.swift +// VDS +// +// Created by Bandaru, Krishna Kishore on 16/02/24. +// + +import Foundation +import UIKit + +protocol DropShadowable { + + var shadowColorConfiguration: AnyColorable { get set } + var shadowOpacityConfiguration: AnyConfigurationValue { get set } + var shadowOffsetConfiguration: AnyConfigurationValue { get set } + var shadowRadiusConfiguration: AnyConfigurationValue { get set } +} + +protocol DropShadowableConfiguration { + + var configurations: [DropShadowable] { get } +} + +final class DropShadowConfiguration: DropShadowable, ObjectWithable { + + typealias CGFloatConfigurationValue = AnyConfigurationValue + typealias CGSizeConfigurationValue = AnyConfigurationValue + + var shadowColorConfiguration: AnyColorable + var shadowOpacityConfiguration: CGFloatConfigurationValue + var shadowOffsetConfiguration: CGSizeConfigurationValue + var shadowRadiusConfiguration: CGFloatConfigurationValue + + init(shadowColorConfiguration: AnyColorable = SurfaceColorConfiguration().eraseToAnyColorable(), shadowOpacity: CGFloatConfigurationValue = CGFloatConfigurationValue(1.0, 1.0), shadowOffset: CGSizeConfigurationValue = CGSizeConfigurationValue(.zero, .zero), shadowRadius: CGFloatConfigurationValue = CGFloatConfigurationValue(1.0, 1.0)) { + self.shadowColorConfiguration = shadowColorConfiguration + self.shadowOpacityConfiguration = shadowOpacity + self.shadowOffsetConfiguration = shadowOffset + self.shadowRadiusConfiguration = shadowRadius + } +} + +extension ViewProtocol where Self: UIView { + + func addDropShadow(_ config: DropShadowable) { + addDropShadows([config]) + } + + func addDropShadows(_ configs: [DropShadowable]) { + removeDropShadows() + layer.backgroundColor = backgroundColor?.cgColor + layer.masksToBounds = false + for config in configs { + let shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: layer.cornerRadius) + let shadowLayer = CALayer() + shadowLayer.shadowPath = shadowPath.cgPath + shadowLayer.frame = bounds + shadowLayer.position = .init(x: bounds.midX, y: bounds.midY) + shadowLayer.backgroundColor = backgroundColor?.cgColor + shadowLayer.cornerRadius = layer.cornerRadius + shadowLayer.shadowColor = config.shadowColorConfiguration.getColor(self).cgColor + shadowLayer.shadowOpacity = Float(config.shadowOpacityConfiguration.getValue(self)) + shadowLayer.shadowOffset = config.shadowOffsetConfiguration.getValue(self) + shadowLayer.shadowRadius = config.shadowRadiusConfiguration.getValue(self) + shadowLayer.name = "dropShadowLayer" + shadowLayer.shouldRasterize = true + shadowLayer.rasterizationScale = UIScreen.main.scale + layer.insertSublayer(shadowLayer, at: 0) + } + } + + func removeDropShadows() { + layer.sublayers?.removeAll { $0.name == "dropShadowLayer" } + } + + func addGradientLayer(with firstColor: UIColor, secondColor: UIColor) { + removeGradientLayer() + let gradientLayer = CAGradientLayer() + gradientLayer.frame = bounds + gradientLayer.startPoint = CGPoint(x: 0, y: 1) + gradientLayer.endPoint = CGPoint(x: 1, y: 0) + gradientLayer.position = center + gradientLayer.shouldRasterize = true + gradientLayer.backgroundColor = UIColor.clear.cgColor + gradientLayer.rasterizationScale = UIScreen.main.scale + gradientLayer.cornerRadius = layer.cornerRadius + gradientLayer.colors = [firstColor.cgColor, secondColor.cgColor] + gradientLayer.name = "gradientLayer" + layer.insertSublayer(gradientLayer, at: 0) + } + + func removeGradientLayer() { + layer.sublayers?.removeAll { $0.name == "gradientLayer" } + } +} + +final class AnyConfigurationValue { + + var lightValue: ValueType + var darkValue: ValueType + + public init(_ lightValue: ValueType = ValueType.self, _ darkValue: ValueType = ValueType.self) { + self.lightValue = lightValue + self.darkValue = darkValue + } + + public func getValue(_ object: Any) -> ValueType { + guard let surfaceable = object as? Surfaceable else { + assertionFailure("Self doesn't confirms to Surfaceable") + return lightValue + } + return surfaceable.surface == .light ? lightValue : darkValue + } +} diff --git a/VDS/Protocols/Dropshadowable.swift b/VDS/Protocols/Dropshadowable.swift deleted file mode 100644 index 77f1a475..00000000 --- a/VDS/Protocols/Dropshadowable.swift +++ /dev/null @@ -1,64 +0,0 @@ -// -// Dropshadowable.swift -// VDS -// -// Created by Bandaru, Krishna Kishore on 16/02/24. -// - -import Foundation -import UIKit - -protocol Dropshadowable { - - var shadowColorConfiguration: AnyColorable { get set } - var shadowOpacity: CGFloat { get set } - var shadowOffset: CGSize { get set } - var shadowRadius: CGFloat { get set } -} - -extension ViewProtocol where Self: UIView { - - func addDropShadow(_ config: Dropshadowable) { - removeDropShadows() - layer.backgroundColor = backgroundColor?.cgColor - layer.masksToBounds = false - let shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: layer.cornerRadius) - let shadowLayer = CALayer() - shadowLayer.shadowPath = shadowPath.cgPath - shadowLayer.frame = bounds - shadowLayer.position = center - shadowLayer.backgroundColor = UIColor.clear.cgColor - shadowLayer.cornerRadius = layer.cornerRadius - shadowLayer.shadowColor = config.shadowColorConfiguration.getColor(self).cgColor - shadowLayer.shadowOpacity = Float(config.shadowOpacity) - shadowLayer.shadowOffset = .init(width: config.shadowOffset.width, height: config.shadowOffset.height) - shadowLayer.shadowRadius = config.shadowRadius - shadowLayer.name = "dropShadowLayer" - shadowLayer.shouldRasterize = true - shadowLayer.rasterizationScale = UIScreen.main.scale - layer.insertSublayer(shadowLayer, at: 0) - } - - func removeDropShadows() { - layer.sublayers?.removeAll { $0.name == "dropShadowLayer" } - } - - func addGradientLayer(with firstColor: UIColor, secondColor: UIColor) { - removeGradientLayer() - let gradientLayer = CAGradientLayer() - gradientLayer.frame = bounds - gradientLayer.startPoint = CGPoint(x: 0, y: 1) - gradientLayer.endPoint = CGPoint(x: 1, y: 0) - gradientLayer.position = center - gradientLayer.shouldRasterize = true - gradientLayer.rasterizationScale = UIScreen.main.scale - gradientLayer.cornerRadius = layer.cornerRadius - gradientLayer.colors = [firstColor.cgColor, secondColor.cgColor] - gradientLayer.name = "gradientLayer" - layer.insertSublayer(gradientLayer, at: 0) - } - - func removeGradientLayer() { - layer.sublayers?.removeAll { $0.name == "gradientLayer" } - } -}