// // ModelColorConfiguration.swift // VDS // // Created by Matt Bruce on 8/4/22. // import Foundation import UIKit public typealias ObjectColorable = Colorable & Initable & ObjectWithable public class ControlColorConfiguration: StateColorConfiguration, ObjectColorable { public typealias ObjectType = UIControl & Surfaceable required public override init() {} public func getColor(_ object: any ObjectType) -> UIColor { return getColor(object.surface, forState: object.state) } } public class ViewColorConfiguration: StateColorConfiguration, ObjectColorable { public typealias ObjectType = Disabling & Surfaceable required public override init() {} public func setSurfaceColors(_ lightColor: UIColor, _ darkColor: UIColor, forDisabled disabled: Bool) { setSurfaceColors(lightColor, darkColor, forState: disabled) } public func getColor(_ object: any ObjectType) -> UIColor { return getColor(object.surface, forState: object.disabled) } } public class StateColorConfiguration { struct StateColor { var state: StateType var surfaceConfig: SurfaceColorConfiguration } private var stateColors: [StateColor] = [] public init() { } public func getColor(_ surface: Surface, forState state: StateType) -> UIColor { if let stateColor = stateColors.first(where: {$0.state == state }) { return stateColor.surfaceConfig.getColor(surface) } else { return .clear //default } } public func setSurfaceColors(_ lightColor: UIColor, _ darkColor: UIColor, forState state: StateType) { stateColors.append(.init(state: state, surfaceConfig: .init(lightColor, darkColor))) } public func reset() { stateColors.removeAll() } } /// 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) } } ///------------------------------------------------------------------- ///MARK -- DisabledSurfaceColorable ///------------------------------------------------------------------- public protocol DisabledSurfaceColorable: ObjectColorable { var disabled: SurfaceColorConfiguration { get set } var enabled: SurfaceColorConfiguration { get set } } extension DisabledSurfaceColorable { public func getDisabledColor (_ object: M) -> UIColor { object.disabled ? disabled.getColor(object) : enabled.getColor(object) } } /// Meant to be used in a Object that implements the following interfaces for 4 possible color combinations /// - Disabling (var disabled: Bool) /// - Surfaceable (var surface: Surface) /// /// let model = TestModel() /// model.surface = .dark /// model.disabled = false /// /// let config = DisabledSurfaceColorConfiguration() /// /// //disabled == false /// config.enabled.lightColor = .black /// config.enabled.darkColor = .white /// /// //disabled == true /// config.disabled.lightColor = .gray /// config.disabled.darkColor = .lightGray /// /// let textColor = config.getColor(model) //returns .white /// /// open class DisabledSurfaceColorConfiguration: DisabledSurfaceColorable { public typealias ObjectType = Surfaceable & Disabling public var disabled = SurfaceColorConfiguration() public var enabled = SurfaceColorConfiguration() required public init(){} public func getColor(_ object: any ObjectType) -> UIColor { getDisabledColor(object) } } ///------------------------------------------------------------------- ///MARK -- BinaryColorable ///------------------------------------------------------------------- public protocol BinaryColorable{ var useTrueColor: Bool { get } } extension BinaryColorable where Self: Control { public var useTrueColor: Bool { return isSelected } } ///------------------------------------------------------------------- ///MARK -- BinarySurfaceColorable ///------------------------------------------------------------------- public protocol BinarySurfaceColorable: ObjectColorable { var forTrue: SurfaceColorConfiguration { get set } var forFalse: SurfaceColorConfiguration { get set } } extension BinarySurfaceColorable { public func getBinaryColor(_ object: M) -> UIColor { object.useTrueColor ? forTrue.getColor(object) : forFalse.getColor(object) } } /// Meant to be used in a Object that implements the following interfaces for 4 possible color combinations /// - BinaryColorable (var userTrueColor: Bool) /// - Surfaceable (var surface: Surface) /// /// let model = TestModel() /// model.surface = .dark /// model.on = true //this is read in the extension var userTrueColor /// let config = BinarySurfaceColorConfiguration() /// /// //True from BinaryColorable.userTrueColor /// config.forTrue.lightColor = .black /// config.forTrue.darkColor = .white /// /// //False from BinaryColorable.userTrueColor /// config.forFalse.lightColor = .red /// config.forFalse.darkColor = .red /// /// let textColor = config.getColor(model) //returns .white /// /// final public class BinarySurfaceColorConfiguration: BinarySurfaceColorable { public typealias ObjectType = Surfaceable & BinaryColorable public var forTrue = SurfaceColorConfiguration() public var forFalse = SurfaceColorConfiguration() required public init(){} public func getColor(_ object: any ObjectType) -> UIColor { getBinaryColor(object) } } ///------------------------------------------------------------------- ///MARK -- BinaryDisabledSurfaceColorable ///------------------------------------------------------------------- public protocol BinaryDisabledSurfaceColorable: ObjectColorable { var forTrue: DisabledSurfaceColorConfiguration { get set } var forFalse: DisabledSurfaceColorConfiguration { get set } } extension BinaryDisabledSurfaceColorable { public func getBinaryColor(_ object: M) -> UIColor { object.useTrueColor ? forTrue.getColor(object) : forFalse.getColor(object) } } /// Meant to be used in a Object that implements the following interfaces for 8 possible color combinations /// - BinaryColorable (var userTrueColor: Bool) /// - Disabling (var disabled: Bool) /// - Surfaceable (var surface: Surface) /// /// let model = TestModel() /// model.on = false /// model.disabled = false /// model.surface = .light /// let config = BinaryDisabledSurfaceColorConfiguration() /// /// //True /// config.forTrue.enabled.lightColor = .black /// config.forTrue.enabled.darkColor = .white /// config.forTrue.disabled.lightColor = .darkGray /// config.forTrue.disabled.darkColor = .lightGray /// /// //False /// config.forFalse.enabled.lightColor = .red /// config.forFalse.enabled.darkColor = .red /// config.forFalse.disabled.lightColor =.darkGray /// config.forFalse.disabled.darkColor = .lightGray /// /// let textColor = config.getColor(model) /// /// final public class BinaryDisabledSurfaceColorConfiguration: BinaryDisabledSurfaceColorable { public typealias ObjectType = Disabling & Surfaceable & BinaryColorable public var forTrue = DisabledSurfaceColorConfiguration() public var forFalse = DisabledSurfaceColorConfiguration() required public init(){} public func getColor(_ object: any ObjectType) -> UIColor { getBinaryColor(object) } } public class ControlStateColorConfiguration: ObjectColorable { public typealias ObjectType = UIControl & Surfaceable public var disabled = SurfaceColorConfiguration() public var normal = SurfaceColorConfiguration() public var highlighted: SurfaceColorConfiguration? public var selected: SurfaceColorConfiguration? public var error: SurfaceColorConfiguration? required public init(){} public func setColorable(_ config: SurfaceColorConfiguration, for state: UIControl.State) { switch state { case .disabled: disabled = config case .highlighted: highlighted = config case .selected: selected = config case .error: error = config default: normal = config } } public func getColor(_ object: any ObjectType) -> UIColor { if object.state == .disabled { return disabled.getColor(object) } else if let highlighted, object.state == .highlighted { return highlighted.getColor(object) } else if let selected, object.state == .selected { return selected.getColor(object) } else if let error, object.state == .error { return error.getColor(object) } else { return normal.getColor(object) } } }