diff --git a/TIBottomSheet/Sources/BottomSheet/BaseModalViewController+Appearance.swift b/TIBottomSheet/Sources/BottomSheet/BaseModalViewController+Appearance.swift index 53d66d0e..53a4002e 100644 --- a/TIBottomSheet/Sources/BottomSheet/BaseModalViewController+Appearance.swift +++ b/TIBottomSheet/Sources/BottomSheet/BaseModalViewController+Appearance.swift @@ -28,6 +28,7 @@ extension BaseModalViewController { open class BaseAppearance: UIView.BaseAppearance { + public var presentationDetents: [ModalViewPresentationDetent] public var dragViewState: DragView.State public var headerViewState: ModalHeaderView.State public var footerViewState: ModalFooterView.State @@ -36,15 +37,26 @@ extension BaseModalViewController { backgroundColor: UIColor = .clear, border: UIViewBorder = .init(), shadow: UIViewShadow? = nil, + presentationDetents: [ModalViewPresentationDetent] = [.maxHeight], dragViewState: DragView.State = .hidden, headerViewState: ModalHeaderView.State = .hidden, footerViewState: ModalFooterView.State = .hidden) { + self.presentationDetents = presentationDetents self.dragViewState = dragViewState self.headerViewState = headerViewState self.footerViewState = footerViewState - super.init(layout: layout, backgroundColor: backgroundColor, border: border, shadow: shadow) + super.init(layout: layout, + backgroundColor: backgroundColor, + border: border, + shadow: shadow) + } + } + + public final class DefaultAppearance: BaseAppearance, ViewAppearance { + public static var defaultAppearance: Self { + Self() } } } diff --git a/TIBottomSheet/Sources/BottomSheet/BaseModalViewController.swift b/TIBottomSheet/Sources/BottomSheet/BaseModalViewController.swift index 92f1b5c3..b1cf91a2 100644 --- a/TIBottomSheet/Sources/BottomSheet/BaseModalViewController.swift +++ b/TIBottomSheet/Sources/BottomSheet/BaseModalViewController.swift @@ -153,9 +153,7 @@ open class BaseModalViewController [ModalViewPresentationDetent] { - presentationDetents.uniqued().sorted() + viewControllerAppearance.presentationDetents.uniqued().sorted() } private func getHeight(of view: UIView) -> CGFloat { diff --git a/TIBottomSheet/Sources/BottomSheet/DefaultModalWrapperViewController.swift b/TIBottomSheet/Sources/BottomSheet/DefaultModalWrapperViewController.swift index 342de463..b70b056a 100644 --- a/TIBottomSheet/Sources/BottomSheet/DefaultModalWrapperViewController.swift +++ b/TIBottomSheet/Sources/BottomSheet/DefaultModalWrapperViewController.swift @@ -30,6 +30,9 @@ open class DefaultModalWrapperViewController UIView { + contentViewController.view + } } public extension UIViewController { diff --git a/TIBottomSheet/Sources/BottomSheet/Views/PassthroughDimmedView.swift b/TIBottomSheet/Sources/BottomSheet/Views/PassthroughDimmedView.swift index 70056aed..96ec02d4 100644 --- a/TIBottomSheet/Sources/BottomSheet/Views/PassthroughDimmedView.swift +++ b/TIBottomSheet/Sources/BottomSheet/Views/PassthroughDimmedView.swift @@ -24,7 +24,7 @@ import UIKit import PanModal open class PassthroughDimmedView: DimmedView { - weak var hitTestHandlerView: UIView? + public weak var hitTestHandlerView: UIView? public var isTransparent = false diff --git a/TIUIElements/Sources/Appearance/UIButton+AppearanceConfigurable.swift b/TIUIElements/Sources/Appearance/UIButton+AppearanceConfigurable.swift index 6c7b56a5..00afb6a9 100644 --- a/TIUIElements/Sources/Appearance/UIButton+AppearanceConfigurable.swift +++ b/TIUIElements/Sources/Appearance/UIButton+AppearanceConfigurable.swift @@ -30,21 +30,21 @@ extension UIButton { appearance.textAttributes? .configure(button: self, with: title(for: state), - for: state) + for: state) if #available(iOS 15, *) { var config = configuration ?? .plain() configureInsets(in: &config, - contentInsets: appearance.contentLayout.contentInsets, - titleInsets: appearance.contentLayout.titleInsets, - imageInsets: appearance.contentLayout.imageInsets) + contentInsets: appearance.contentLayout.contentInsets.replacingNan(with: .zero), + titleInsets: appearance.contentLayout.titleInsets.replacingNan(with: .zero), + imageInsets: appearance.contentLayout.imageInsets.replacingNan(with: .zero)) configuration = config } else { - contentEdgeInsets = appearance.contentLayout.contentInsets - titleEdgeInsets = appearance.contentLayout.titleInsets - imageEdgeInsets = appearance.contentLayout.imageInsets + contentEdgeInsets = appearance.contentLayout.contentInsets.replacingNan(with: .zero) + titleEdgeInsets = appearance.contentLayout.titleInsets.replacingNan(with: .zero) + imageEdgeInsets = appearance.contentLayout.imageInsets.replacingNan(with: .zero) } super.configureUIView(appearance: appearance) @@ -67,7 +67,7 @@ extension UIButton { currentImage ] .compactMap { $0 } - .first { !($0.size.width.isZero || $0.size.height.isZero) } != nil + .contains { !($0.size.width.isZero || $0.size.height.isZero) } if hasNonEmptyImage { let leadingContentInset: CGFloat diff --git a/TIUIElements/Sources/Separators/ContainerSeparatorTableViewCell.swift b/TIUIElements/Sources/Separators/ContainerSeparatorTableViewCell.swift index 1f34f887..17a54326 100644 --- a/TIUIElements/Sources/Separators/ContainerSeparatorTableViewCell.swift +++ b/TIUIElements/Sources/Separators/ContainerSeparatorTableViewCell.swift @@ -27,15 +27,13 @@ open class ContainerSeparatorTableViewCell: ContainerTableViewCell private lazy var topSeparatorView = createTopSeparator() private lazy var bottomSeparatorView = createBottomSeparator() - private var topViewLeftConstraint: NSLayoutConstraint? - private var topViewRightConstraint: NSLayoutConstraint? - private var topViewTopConstraint: NSLayoutConstraint? - private var topViewHeightConstraint: NSLayoutConstraint? + private lazy var topSeparatorConstraints: SubviewConstraints = { + subviewConstraints(for: topSeparatorView) + }() - private var bottomViewLeftConstraint: NSLayoutConstraint? - private var bottomViewRightConstraint: NSLayoutConstraint? - private var bottomViewBottomConstraint: NSLayoutConstraint? - private var bottomViewHeightConstraint: NSLayoutConstraint? + private lazy var bottomSeparatorConstraints: SubviewConstraints = { + subviewConstraints(for: bottomSeparatorView) + }() open func createTopSeparator() -> UIView { .init() @@ -93,41 +91,17 @@ open class ContainerSeparatorTableViewCell: ContainerTableViewCell open override func configureLayout() { super.configureLayout() - if let separatorSuperview = topSeparatorView.superview { - topViewTopConstraint = topSeparatorView.topAnchor.constraint(equalTo: separatorSuperview.topAnchor) - topViewRightConstraint = separatorSuperview.rightAnchor.constraint(equalTo: topSeparatorView.rightAnchor) - topViewLeftConstraint = topSeparatorView.leftAnchor.constraint(equalTo: separatorSuperview.leftAnchor) + for view in [topSeparatorView, bottomSeparatorView] { + view.translatesAutoresizingMaskIntoConstraints = false } - - topViewHeightConstraint = topSeparatorView.heightAnchor.constraint(equalToConstant: 1) - - if let separatorSuperview = topSeparatorView.superview { - bottomViewRightConstraint = separatorSuperview.rightAnchor.constraint(equalTo: bottomSeparatorView.rightAnchor) - bottomViewLeftConstraint = bottomSeparatorView.leftAnchor.constraint(equalTo: separatorSuperview.leftAnchor) - bottomViewBottomConstraint = bottomSeparatorView.bottomAnchor.constraint(equalTo: separatorSuperview.bottomAnchor) - } - - bottomViewHeightConstraint = bottomSeparatorView.heightAnchor.constraint(equalToConstant: 1) - - NSLayoutConstraint.activate([ - topViewTopConstraint, - topViewRightConstraint, - topViewLeftConstraint, - topViewHeightConstraint, - bottomViewRightConstraint, - bottomViewLeftConstraint, - bottomViewBottomConstraint, - bottomViewHeightConstraint - ].compactMap { $0 }) } open override func configureAppearance() { super.configureAppearance() - [topSeparatorView, bottomSeparatorView].forEach { - $0.isHidden = true - $0.backgroundColor = .black - $0.translatesAutoresizingMaskIntoConstraints = false + for view in [topSeparatorView, bottomSeparatorView] { + view.isHidden = true + view.backgroundColor = .black } } @@ -136,20 +110,37 @@ open class ContainerSeparatorTableViewCell: ContainerTableViewCell private func updateTopSeparator(with appearance: SeparatorAppearance) { topSeparatorView.configureUIView(appearance: appearance) - topViewHeightConstraint?.constant = appearance.layout.size.height - - topViewTopConstraint?.constant = appearance.layout.insets.top - topViewLeftConstraint?.constant = appearance.layout.insets.left - topViewRightConstraint?.constant = appearance.layout.insets.right + topSeparatorConstraints.update(from: appearance.layout) } private func updateBottomSeparator(with appearance: SeparatorAppearance) { bottomSeparatorView.configureUIView(appearance: appearance) - bottomViewHeightConstraint?.constant = appearance.layout.size.height + bottomSeparatorConstraints.update(from: appearance.layout) + } - bottomViewBottomConstraint?.constant = appearance.layout.insets.bottom - bottomViewLeftConstraint?.constant = appearance.layout.insets.left - bottomViewRightConstraint?.constant = appearance.layout.insets.right + private func subviewConstraints(for seperatorView: UIView) -> SubviewConstraints { + let leadingConstraint = seperatorView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor) + let trailingConstraint = seperatorView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor) + let topConstraint = seperatorView.topAnchor.constraint(equalTo: contentView.topAnchor) + let bottomConstraint = seperatorView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor) + + let edgeConstraints = EdgeConstraints(leadingConstraint: leadingConstraint, + trailingConstraint: trailingConstraint, + topConstraint: topConstraint, + bottomConstraint: bottomConstraint) + + let centerXConstraint = seperatorView.centerXAnchor.constraint(equalTo: contentView.centerXAnchor) + let centerYConstraint = seperatorView.centerYAnchor.constraint(equalTo: contentView.centerYAnchor) + + let centerConstraints = CenterConstraints(centerXConstraint: centerXConstraint, + centerYConstraint: centerYConstraint) + + let sizeConstraints = SizeConstraints(widthConstraint: seperatorView.widthAnchor.constraint(equalToConstant: .zero), + heightConstraint: seperatorView.heightAnchor.constraint(equalToConstant: .zero)) + + return SubviewConstraints(edgeConstraints: edgeConstraints, + centerConstraints: centerConstraints, + sizeConstraints: sizeConstraints) } } diff --git a/TIUIElements/Sources/Wrappers/Constraints/SubviewConstraints.swift b/TIUIElements/Sources/Wrappers/Constraints/SubviewConstraints.swift index 99ab271a..5111d28d 100644 --- a/TIUIElements/Sources/Wrappers/Constraints/SubviewConstraints.swift +++ b/TIUIElements/Sources/Wrappers/Constraints/SubviewConstraints.swift @@ -47,14 +47,6 @@ public struct SubviewConstraints: ConstraintsSet { centerConstraints.update(offset: centerOffset) sizeConstraints.update(from: size) edgeConstraints.update(from: insets) - - for verticalConstraint in edgeConstraints.vertical { - verticalConstraint.isActive = !centerOffset.vertical.isFinite - } - - for horizontalConstraint in edgeConstraints.horizontal { - horizontalConstraint.isActive = !centerOffset.horizontal.isFinite - } } // MARK: - WrappedViewLayout shortcut diff --git a/TIUIKitCore/Sources/Extensions/UIKit/UIEdgeInsets+Extensions.swift b/TIUIKitCore/Sources/Extensions/UIKit/UIEdgeInsets+Extensions.swift index c27fb07d..ef46e88d 100644 --- a/TIUIKitCore/Sources/Extensions/UIKit/UIEdgeInsets+Extensions.swift +++ b/TIUIKitCore/Sources/Extensions/UIKit/UIEdgeInsets+Extensions.swift @@ -72,6 +72,13 @@ public extension UIEdgeInsets { .init(top: top, left: left, bottom: bottom, right: right) } + func replacingNan(with defaultValue: CGFloat) -> Self { + .init(top: top.isFinite ? top : defaultValue, + left: left.isFinite ? left : defaultValue, + bottom: bottom.isFinite ? bottom : defaultValue, + right: right.isFinite ? right : defaultValue) + } + func add(_ lhsKeyPath: KeyPath, to rhsKeyPath: KeyPath, of rhs: Self,