// // ModelColorConfiguration.swift // VDS // // Created by Matt Bruce on 8/4/22. // import Foundation import UIKit public typealias ObjectColorable = Colorable & Initable & ObjectWithable /// Meant to be used in a Object that implements the following interfaces for 2 possible color combinations /// - Surfaceable (var surface: Surface) /// /// let model = TestModel() /// model.surface = .light /// /// let config = SurfaceColorConfiguration() /// config.lightColor = .black /// config.darkColor = .white /// /// let textColor = config.getColor(model) //returns .black open class SurfaceColorConfiguration: ObjectColorable { public typealias ObjectType = Surfaceable public var lightColor: UIColor = .clear public var darkColor: UIColor = .clear required public init(){} public init(_ lightColor: UIColor, _ darkColor: UIColor) { self.lightColor = lightColor self.darkColor = darkColor } public func getColor(_ surface: Surface) -> UIColor { return surface == .light ? lightColor : darkColor } public func getColor(_ object: any ObjectType) -> UIColor { return getColor(object.surface) } } /// Struct to Hold onto KeyType and SurfaceConfiguration public struct KeyColorConfiguration { var key: KeyType var surfaceConfig: SurfaceColorConfiguration } // Protocol to Hold onto the relationship of KeyType and SurfaceConfiguration public protocol KeyColorConfigurable: ObjectColorable { associatedtype KeyType: Equatable var keyColors: [KeyColorConfiguration] { get set } } extension KeyColorConfigurable { public func setSurfaceColors(_ lightColor: UIColor, _ darkColor: UIColor, forKey key: KeyType) { keyColors.append(.init(key: key, surfaceConfig: .init(lightColor, darkColor))) } public func reset() { keyColors.removeAll() } } extension KeyColorConfigurable where ObjectType: Surfaceable { public func getColor(for object: ObjectType, with key: KeyType) -> UIColor { if let keyColor = keyColors.first(where: {$0.key == key }) { return keyColor.surfaceConfig.getColor(object) } else { return .clear //default } } } public class ControlColorConfiguration: KeyColorConfigurable { public typealias KeyType = UIControl.State public typealias ObjectType = Surfaceable & UIControl public var keyColors: [KeyColorConfiguration] = [] public required init() { } public func setSurfaceColors(_ lightColor: UIColor, _ darkColor: UIColor, forState state: KeyType) { setSurfaceColors(lightColor, darkColor, forKey: state) } public func getColor(_ object: any ObjectType) -> UIColor { let state = object.state let surface = object.surface // find the exact match if let keyColor = keyColors.first(where: {$0.key == state }) { return keyColor.surfaceConfig.getColor(surface) } else if state.contains(.disabled), let keyColor = keyColors.first(where: {$0.key == .disabled }) { return keyColor.surfaceConfig.getColor(surface) } else if state.contains(.highlighted), let keyColor = keyColors.first(where: {$0.key == .highlighted }) { return keyColor.surfaceConfig.getColor(surface) } else { return .clear } } } public class ViewColorConfiguration: KeyColorConfigurable { public typealias KeyType = Bool public typealias ObjectType = Surfaceable & Disabling public var keyColors: [KeyColorConfiguration] = [] public required init() { } public func setSurfaceColors(_ lightColor: UIColor, _ darkColor: UIColor, forDisabled disabled: KeyType) { setSurfaceColors(lightColor, darkColor, forKey: disabled) } public func getColor(_ object: ObjectType) -> UIColor { if let keyColor = keyColors.first(where: {$0.key == object.disabled }) { return keyColor.surfaceConfig.getColor(object) } else { return .clear //default } } } /// Generic Class that allows reflection for a object's specific property (equatable) to be defined as the lookup for a SurfaceConfiguration public class KeyedColorConfiguration : KeyColorConfigurable { //Type of Class that at least implements Surfaceable public typealias ObjectType = ObjectType //where the value exist for the object public var keyPath: KeyPath? /// Array of structs where the KeyValue is registered against a SurfaceColorConfiguration public var keyColors: [KeyColorConfiguration] = [] public required init() {} //this must be used public required convenience init(keyPath: KeyPath) { self.init() self.keyPath = keyPath } public func getKeyValue(_ object: ObjectType) -> KeyType? { guard let keyPath else { fatalError("keyPath must not be empty, make sure you initialize this class using init(keyPath: \\Object.property) method") } return object[keyPath: keyPath] } public func getColor(_ object: ObjectType) -> UIColor { if let key = getKeyValue(object), let keyColor = keyColors.first(where: {$0.key == key }) { return keyColor.surfaceConfig.getColor(object) } else { return .clear //default } } }