// // 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 } }