LeadKit/TIUIElements/Sources/Views/ListItemView/BaseListItemView.swift

191 lines
9.7 KiB
Swift

//
// Copyright (c) 2023 Touch Instinct
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the Software), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
import TIUIKitCore
import UIKit
open class BaseListItemView<LeadingView: UIView,
MiddleView: UIView,
TrailingView: UIView>: BaseInitializableView {
public let leadingView = LeadingView()
public let middleView = MiddleView()
public let trailingView = TrailingView()
// MARK: - Constraints
public private(set) lazy var middleViewLeadingConstraint: NSLayoutConstraint = {
middleView.leadingAnchor.constraint(equalTo: leadingView.trailingAnchor)
}()
public private(set) lazy var leadingViewConstraints: SubviewConstraints = {
SubviewConstraints(edgeConstraints: EdgeConstraints(leadingConstraint: leadingView.leadingAnchor.constraint(equalTo: leadingAnchor),
trailingConstraint: middleViewLeadingConstraint,
topConstraint: leadingView.topAnchor.constraint(equalTo: topAnchor),
bottomConstraint: leadingView.bottomAnchor.constraint(equalTo: bottomAnchor)),
centerConstraints: CenterConstraints(centerXConstraint: leadingView.centerXAnchor.constraint(equalTo: centerXAnchor),
centerYConstraint: leadingView.centerYAnchor.constraint(equalTo: centerYAnchor)),
sizeConstraints: SizeConstraints(widthConstraint: leadingView.widthAnchor.constraint(equalToConstant: .zero),
heightConstraint: leadingView.heightAnchor.constraint(equalToConstant: .zero)))
}()
public private(set) lazy var trailingViewLeadingToMiddleViewConstraint: NSLayoutConstraint = {
trailingView.leadingAnchor.constraint(equalTo: middleView.trailingAnchor)
}()
public private(set) lazy var middleViewConstraints: SubviewConstraints = {
SubviewConstraints(edgeConstraints: EdgeConstraints(leadingConstraint: middleViewLeadingConstraint,
trailingConstraint: trailingViewLeadingToMiddleViewConstraint,
topConstraint: middleView.topAnchor.constraint(equalTo: topAnchor),
bottomConstraint: middleView.bottomAnchor.constraint(equalTo: bottomAnchor)),
centerConstraints: CenterConstraints(centerXConstraint: middleView.centerXAnchor.constraint(equalTo: centerXAnchor),
centerYConstraint: middleView.centerYAnchor.constraint(equalTo: centerYAnchor)),
sizeConstraints: SizeConstraints(widthConstraint: middleView.widthAnchor.constraint(equalToConstant: .zero),
heightConstraint: middleView.heightAnchor.constraint(equalToConstant: .zero)))
}()
public private(set) lazy var middleViewLeadingToSuperViewConstraint: NSLayoutConstraint = {
middleView.leadingAnchor.constraint(equalTo: leadingAnchor)
}()
public private(set) lazy var middleViewTrailingToSuperViewConstraint: NSLayoutConstraint = {
middleView.trailingAnchor.constraint(equalTo: trailingAnchor)
}()
public private(set) lazy var trailingViewConstraints: SubviewConstraints = {
SubviewConstraints(edgeConstraints: EdgeConstraints(leadingConstraint: trailingViewLeadingToMiddleViewConstraint,
trailingConstraint: trailingView.trailingAnchor.constraint(equalTo: trailingAnchor),
topConstraint: trailingView.topAnchor.constraint(equalTo: topAnchor),
bottomConstraint: trailingView.bottomAnchor.constraint(equalTo: bottomAnchor)),
centerConstraints: CenterConstraints(centerXConstraint: middleView.centerXAnchor.constraint(equalTo: centerXAnchor),
centerYConstraint: trailingView.centerYAnchor.constraint(equalTo: centerYAnchor)),
sizeConstraints: SizeConstraints(widthConstraint: trailingView.widthAnchor.constraint(equalToConstant: .zero),
heightConstraint: trailingView.heightAnchor.constraint(equalToConstant: .zero)))
}()
// MARK: - Public Properties
open var isLeadingViewHidden: Bool {
leadingView.isHidden
}
open var isTrailingViewHidden: Bool {
trailingView.isHidden
}
// MARK: - BaseInitializableView
open override func addViews() {
super.addViews()
addSubviews(leadingView, middleView, trailingView)
}
open override func configureLayout() {
super.configureLayout()
[leadingView, middleView, trailingView]
.forEach { $0.translatesAutoresizingMaskIntoConstraints = false }
[leadingViewConstraints, middleViewConstraints, trailingViewConstraints]
.forEach { $0.update(insets: .zero, size: .infinity, centerOffset: .nan) }
}
// MARK: - Public methods
public func configureBaseListItem(appearance: BaseListItemAppearance<some WrappedViewAppearance,
some WrappedViewAppearance,
some WrappedViewAppearance>) {
configureUIView(appearance: appearance)
updateLeadingViewLayout(leadingViewLayout: appearance.leadingViewAppearance.layout,
middleViewLayout: appearance.middleViewAppearance.layout)
updateMiddleViewLayout(middleViewLayout: appearance.middleViewAppearance.layout)
updateTrailingViewLayout(trailingViewLayout: appearance.trailingAppearance.layout,
middleViewLayout: appearance.middleViewAppearance.layout)
}
// MARK: - Private methdos
private func updateLeadingViewLayout(leadingViewLayout: WrappedViewLayout,
middleViewLayout: WrappedViewLayout) {
let leadingToSuperviewContraint: NSLayoutConstraint
let leadingViewLeftInset: CGFloat
if isLeadingViewHidden {
leadingViewConstraints.deactivate()
middleViewLeadingToSuperViewConstraint.isActive = true
leadingToSuperviewContraint = middleViewLeadingToSuperViewConstraint
leadingViewLeftInset = middleViewLayout.insets.left
} else {
middleViewLeadingConstraint.constant = leadingViewLayout.insets.right + middleViewLayout.insets.left
leadingViewConstraints.edgeConstraints.leadingConstraint.isActive = true
middleViewConstraints.edgeConstraints.leadingConstraint.isActive = true
middleViewLeadingToSuperViewConstraint.isActive = false
leadingViewConstraints.update(from: leadingViewLayout)
leadingToSuperviewContraint = leadingViewConstraints.edgeConstraints.leadingConstraint
leadingViewLeftInset = leadingViewLayout.insets.left
}
leadingToSuperviewContraint.constant = leadingViewLeftInset
}
private func updateMiddleViewLayout(middleViewLayout: WrappedViewLayout) {
middleViewConstraints.update(from: middleViewLayout)
}
private func updateTrailingViewLayout(trailingViewLayout: WrappedViewLayout,
middleViewLayout: WrappedViewLayout) {
let trailingToSuperviewConstraint: NSLayoutConstraint
let trailingViewRightInset: CGFloat
if isTrailingViewHidden {
trailingViewConstraints.deactivate()
middleViewTrailingToSuperViewConstraint.isActive = true
trailingToSuperviewConstraint = middleViewTrailingToSuperViewConstraint
trailingViewRightInset = middleViewLayout.insets.right
} else {
trailingViewLeadingToMiddleViewConstraint.constant = middleViewLayout.insets.right + trailingViewLayout.insets.left
trailingViewLeadingToMiddleViewConstraint.isActive = true
middleViewTrailingToSuperViewConstraint.isActive = false
trailingViewConstraints.update(from: trailingViewLayout)
trailingToSuperviewConstraint = trailingViewConstraints.edgeConstraints.trailingConstraint
trailingViewRightInset = trailingViewLayout.insets.right
}
trailingToSuperviewConstraint.constant = -trailingViewRightInset
}
}