141 lines
6.1 KiB
Swift
141 lines
6.1 KiB
Swift
//
|
|
// Checkbox.swift
|
|
// VDS
|
|
//
|
|
// Created by Matt Bruce on 7/22/22.
|
|
//
|
|
|
|
import Foundation
|
|
import UIKit
|
|
import VDSColorTokens
|
|
import VDSFormControlsTokens
|
|
import Combine
|
|
|
|
public class Checkbox: CheckboxBase<DefaultCheckboxModel>{}
|
|
|
|
open class CheckboxBase<ModelType: CheckboxModel>: SelectorBase<ModelType> {
|
|
//--------------------------------------------------
|
|
// MARK: - Configuration Properties
|
|
//--------------------------------------------------
|
|
public let checkboxSize = CGSize(width: 20, height: 20)
|
|
|
|
private var checkboxBackgroundColorConfiguration: CheckboxErrorColorConfiguration = {
|
|
let config = CheckboxErrorColorConfiguration()
|
|
config.forTrue.enabled.lightColor = VDSColor.elementsPrimaryOnlight
|
|
config.forTrue.enabled.darkColor = VDSColor.elementsPrimaryOndark
|
|
config.forTrue.disabled.lightColor = VDSColor.interactiveDisabledOnlight
|
|
config.forTrue.disabled.darkColor = VDSColor.interactiveDisabledOndark
|
|
//error doesn't care enabled/disable
|
|
config.error.forTrue.lightColor = VDSColor.elementsPrimaryOnlight
|
|
config.error.forTrue.darkColor = VDSColor.elementsPrimaryOndark
|
|
config.error.forFalse.lightColor = VDSColor.feedbackErrorBackgroundOnlight
|
|
config.error.forFalse.darkColor = VDSColor.feedbackErrorBackgroundOndark
|
|
return config
|
|
}()
|
|
|
|
private var checkboxBorderColorConfiguration: CheckboxErrorColorConfiguration = {
|
|
let config = CheckboxErrorColorConfiguration()
|
|
config.forTrue.enabled.lightColor = VDSColor.elementsPrimaryOnlight
|
|
config.forTrue.enabled.darkColor = VDSColor.elementsPrimaryOndark
|
|
config.forFalse.enabled.lightColor = VDSFormControlsColor.borderOnlight
|
|
config.forFalse.enabled.darkColor = VDSFormControlsColor.borderOndark
|
|
config.forTrue.disabled.lightColor = VDSColor.interactiveDisabledOnlight
|
|
config.forTrue.disabled.darkColor = VDSColor.interactiveDisabledOndark
|
|
config.forFalse.disabled.lightColor = VDSColor.interactiveDisabledOnlight
|
|
config.forFalse.disabled.darkColor = VDSColor.interactiveDisabledOndark
|
|
//error doesn't care enabled/disable
|
|
config.error.forTrue.lightColor = VDSColor.elementsPrimaryOnlight
|
|
config.error.forTrue.darkColor = VDSColor.elementsPrimaryOndark
|
|
config.error.forFalse.lightColor = VDSColor.feedbackErrorOnlight
|
|
config.error.forFalse.darkColor = VDSColor.feedbackErrorOndark
|
|
return config
|
|
}()
|
|
|
|
private var checkboxCheckColorConfiguration: BinarySurfaceColorConfiguration<ModelType> = {
|
|
let config = BinarySurfaceColorConfiguration<ModelType>()
|
|
config.forTrue.lightColor = VDSColor.elementsPrimaryOndark
|
|
config.forTrue.darkColor = VDSColor.elementsPrimaryOnlight
|
|
return config
|
|
}()
|
|
|
|
//--------------------------------------------------
|
|
// MARK: - Checkbox View
|
|
//--------------------------------------------------
|
|
/// Manages the appearance of the checkbox.
|
|
private var shapeLayer: CAShapeLayer?
|
|
|
|
open override func getSelectorSize() -> CGSize {
|
|
return checkboxSize
|
|
}
|
|
|
|
open override func updateSelector(_ viewModel: ModelType) {
|
|
//get the colors
|
|
let backgroundColor = checkboxBackgroundColorConfiguration.getColor(viewModel)
|
|
let borderColor = checkboxBorderColorConfiguration.getColor(viewModel)
|
|
let checkColor = checkboxCheckColorConfiguration.getColor(viewModel)
|
|
|
|
if let shapeLayer = shapeLayer, let sublayers = layer.sublayers, sublayers.contains(shapeLayer) {
|
|
shapeLayer.removeFromSuperlayer()
|
|
self.shapeLayer = nil
|
|
}
|
|
|
|
selectorView.backgroundColor = backgroundColor
|
|
selectorView.layer.borderColor = borderColor.cgColor
|
|
selectorView.layer.cornerRadius = 2.0
|
|
selectorView.layer.borderWidth = 1.0
|
|
|
|
if shapeLayer == nil {
|
|
let bounds = selectorView.bounds
|
|
let length = max(bounds.size.height, bounds.size.width)
|
|
guard length > 0.0, shapeLayer == nil else { return }
|
|
|
|
//draw the checkmark layer
|
|
let xInsetLeft = length * 0.25
|
|
let yInsetTop = length * 0.3
|
|
let innerWidth = length - (xInsetLeft + length * 0.25) // + Right X Inset
|
|
let innerHeight = length - (yInsetTop + length * 0.35) // + Bottom Y Inset
|
|
|
|
let startPoint = CGPoint(x: xInsetLeft, y: yInsetTop + (innerHeight / 2))
|
|
let pivotOffSet = CGPoint(x: xInsetLeft + (innerWidth * 0.33), y: yInsetTop + innerHeight)
|
|
let endOffset = CGPoint(x: xInsetLeft + innerWidth, y: yInsetTop)
|
|
|
|
let bezierPath = UIBezierPath()
|
|
bezierPath.move(to: startPoint)
|
|
bezierPath.addLine(to: pivotOffSet)
|
|
bezierPath.addLine(to: endOffset)
|
|
|
|
let shapeLayer = CAShapeLayer()
|
|
self.shapeLayer = shapeLayer
|
|
shapeLayer.frame = bounds
|
|
layer.addSublayer(shapeLayer)
|
|
shapeLayer.strokeColor = checkColor.cgColor
|
|
shapeLayer.fillColor = UIColor.clear.cgColor
|
|
shapeLayer.path = bezierPath.cgPath
|
|
shapeLayer.lineJoin = .miter
|
|
shapeLayer.lineWidth = 2
|
|
CATransaction.withDisabledAnimations {
|
|
shapeLayer.strokeEnd = model.selected ? 1 : 0
|
|
}
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------
|
|
// MARK: - Color Class Configurations
|
|
//--------------------------------------------------
|
|
private class CheckboxErrorColorConfiguration: BinaryDisabledSurfaceColorConfiguration<ModelType> {
|
|
public let error = BinarySurfaceColorConfiguration<ModelType>()
|
|
override func getColor(_ viewModel: ModelType) -> UIColor {
|
|
//only show error is enabled and showError == true
|
|
let showErrorColor = !viewModel.disabled && viewModel.hasError
|
|
|
|
if showErrorColor {
|
|
return error.getColor(viewModel)
|
|
} else {
|
|
return super.getColor(viewModel)
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|