This commit is contained in:
DDIsFriend
2023-08-18 17:28:57 +08:00
commit f0e8a1709d
4282 changed files with 192396 additions and 0 deletions

View File

@@ -0,0 +1,90 @@
//
// EKAlertMessageView.swift
// SwiftEntryKit
//
// Created by Daniel Huri on 5/5/18.
//
import UIKit
final public class EKAlertMessageView: EKSimpleMessageView, EntryAppearanceDescriptor {
// MARK: Props
var buttonBarView: EKButtonBarView!
private var buttonsBarCompressedConstraint: NSLayoutConstraint!
private var buttonsBarExpandedConstraint: NSLayoutConstraint!
// MARK: EntryAppearenceDescriptor
var bottomCornerRadius: CGFloat = 0 {
didSet {
buttonBarView.bottomCornerRadius = bottomCornerRadius
}
}
// MARK: Setup
public init(with message: EKAlertMessage) {
super.init(with: message.simpleMessage)
setupButtonBarView(with: message.buttonBarContent)
layoutContent(with: message)
}
public required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setupButtonBarView(with content: EKProperty.ButtonBarContent) {
buttonBarView = EKButtonBarView(with: content)
buttonBarView.clipsToBounds = true
addSubview(buttonBarView)
}
func layoutContent(with message: EKAlertMessage) {
switch message.imagePosition {
case .top:
messageContentView.verticalMargins = 16
messageContentView.horizontalMargins = 16
messageContentView.labelsOffset = 5
if let thumbImageView = thumbImageView {
thumbImageView.layoutToSuperview(.top, offset: 20)
thumbImageView.layoutToSuperview(.centerX)
messageContentView.layout(.top, to: .bottom, of: thumbImageView)
} else {
messageContentView.layoutToSuperview(.top)
}
messageContentView.layoutToSuperview(axis: .horizontally)
buttonBarView.layout(.top, to: .bottom, of: messageContentView)
case .left:
messageContentView.verticalMargins = 0
messageContentView.horizontalMargins = 0
messageContentView.labelsOffset = 5
if let thumbImageView = thumbImageView {
thumbImageView.layoutToSuperview(.top, .left, offset: 16)
messageContentView.layout(.left, to: .right, of: thumbImageView, offset: 12)
messageContentView.layout(to: .top, of: thumbImageView, offset: 2)
} else {
messageContentView.layoutToSuperview(.left, .top, offset: 16)
}
messageContentView.layoutToSuperview(.right, offset: -16)
buttonBarView.layout(.top, to: .bottom, of: messageContentView, offset: 10)
}
buttonBarView.layoutToSuperview(axis: .horizontally)
buttonBarView.layoutToSuperview(.bottom)
buttonBarView.alpha = 0
if !message.buttonBarContent.content.isEmpty {
if message.buttonBarContent.expandAnimatedly {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
self.buttonBarView.expand()
}
} else {
buttonBarView.expand()
}
}
}
}

View File

@@ -0,0 +1,130 @@
//
// EKFormMessageView.swift
// SwiftEntryKit
//
// Created by Daniel Huri on 5/15/18.
//
import UIKit
final public class EKFormMessageView: UIView {
private let scrollViewVerticalOffset: CGFloat = 20
// MARK: Props
private let titleLabel = UILabel()
private let scrollView = UIScrollView()
private let textFieldsContent: [EKProperty.TextFieldContent]
private var textFieldViews: [EKTextField] = []
private var buttonBarView: EKButtonBarView!
private let titleContent: EKProperty.LabelContent
// MARK: Setup
public init(with title: EKProperty.LabelContent,
textFieldsContent: [EKProperty.TextFieldContent],
buttonContent: EKProperty.ButtonContent) {
self.titleContent = title
self.textFieldsContent = textFieldsContent
super.init(frame: UIScreen.main.bounds)
setupScrollView()
setupTitleLabel()
setupTextFields(with: textFieldsContent)
setupButton(with: buttonContent)
setupTapGestureRecognizer()
scrollView.layoutIfNeeded()
set(.height,
of: scrollView.contentSize.height + scrollViewVerticalOffset * 2,
priority: .defaultHigh)
}
required public init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setupTextFields(with textFieldsContent: [EKProperty.TextFieldContent]) {
var textFieldIndex = 0
textFieldViews = textFieldsContent.map { content -> EKTextField in
let textField = EKTextField(with: content)
scrollView.addSubview(textField)
textField.tag = textFieldIndex
textFieldIndex += 1
return textField
}
textFieldViews.first!.layout(.top, to: .bottom, of: titleLabel, offset: 20)
textFieldViews.spread(.vertically, offset: 5)
textFieldViews.layoutToSuperview(axis: .horizontally)
}
// Setup tap gesture
private func setupTapGestureRecognizer() {
let tapGestureRecognizer = UITapGestureRecognizer(
target: self,
action: #selector(tapGestureRecognized)
)
tapGestureRecognizer.numberOfTapsRequired = 1
addGestureRecognizer(tapGestureRecognizer)
}
private func setupScrollView() {
addSubview(scrollView)
scrollView.layoutToSuperview(axis: .horizontally, offset: 20)
scrollView.layoutToSuperview(axis: .vertically, offset: scrollViewVerticalOffset)
scrollView.layoutToSuperview(.width, .height, offset: -scrollViewVerticalOffset * 2)
}
private func setupTitleLabel() {
scrollView.addSubview(titleLabel)
titleLabel.layoutToSuperview(.top, .width)
titleLabel.layoutToSuperview(axis: .horizontally)
titleLabel.forceContentWrap(.vertically)
titleLabel.content = titleContent
}
private func setupButton(with buttonContent: EKProperty.ButtonContent) {
var buttonContent = buttonContent
let action = buttonContent.action
buttonContent.action = { [weak self] in
self?.extractTextFieldsContent()
action?()
}
let buttonsBarContent = EKProperty.ButtonBarContent(
with: buttonContent,
separatorColor: .clear,
expandAnimatedly: true
)
buttonBarView = EKButtonBarView(with: buttonsBarContent)
buttonBarView.clipsToBounds = true
scrollView.addSubview(buttonBarView)
buttonBarView.expand()
buttonBarView.layout(.top, to: .bottom, of: textFieldViews.last!, offset: 20)
buttonBarView.layoutToSuperview(.centerX)
buttonBarView.layoutToSuperview(.width, offset: -40)
buttonBarView.layoutToSuperview(.bottom)
buttonBarView.layer.cornerRadius = 5
}
private func extractTextFieldsContent() {
for (content, textField) in zip(textFieldsContent, textFieldViews) {
content.contentWrapper.text = textField.text
}
}
/** Makes a specific text field the first responder */
public func becomeFirstResponder(with textFieldIndex: Int) {
textFieldViews[textFieldIndex].makeFirstResponder()
}
public override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
titleLabel.textColor = titleContent.style.color(for: traitCollection)
}
// MARK: User Intractions
// Tap Gesture
@objc func tapGestureRecognized() {
endEditing(true)
}
}

View File

@@ -0,0 +1,119 @@
//
// EKMessageContentView.swift
// SwiftEntryKit
//
// Created by Daniel Huri on 4/19/18.
// Copyright (c) 2018 huri000@gmail.com. All rights reserved.
//
import UIKit
public class EKMessageContentView: UIView {
// MARK: Properties
private let titleLabel = UILabel()
private let subtitleLabel = UILabel()
private var horizontalConstraints: QLAxisConstraints!
private var topConstraint: NSLayoutConstraint!
private var bottomConstraint: NSLayoutConstraint!
private var labelsOffsetConstraint: NSLayoutConstraint!
public var titleContent: EKProperty.LabelContent! {
didSet {
titleLabel.content = titleContent
}
}
public var subtitleContent: EKProperty.LabelContent! {
didSet {
subtitleLabel.content = subtitleContent
}
}
public var titleAttributes: EKProperty.LabelStyle! {
didSet {
titleLabel.style = titleAttributes
}
}
public var subtitleAttributes: EKProperty.LabelStyle! {
didSet {
subtitleLabel.style = subtitleAttributes
}
}
public var title: String! {
didSet {
titleLabel.text = title
}
}
public var subtitle: String! {
didSet {
subtitleLabel.text = subtitle
}
}
public var verticalMargins: CGFloat = 20 {
didSet {
topConstraint.constant = verticalMargins
bottomConstraint.constant = -verticalMargins
layoutIfNeeded()
}
}
public var horizontalMargins: CGFloat = 20 {
didSet {
horizontalConstraints.first.constant = horizontalMargins
horizontalConstraints.second.constant = -horizontalMargins
layoutIfNeeded()
}
}
public var labelsOffset: CGFloat = 8 {
didSet {
labelsOffsetConstraint.constant = labelsOffset
layoutIfNeeded()
}
}
// MARK: Setup
public init() {
super.init(frame: UIScreen.main.bounds)
clipsToBounds = true
setupTitleLabel()
setupSubtitleLabel()
}
public required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setupTitleLabel() {
addSubview(titleLabel)
topConstraint = titleLabel.layoutToSuperview(.top, offset: verticalMargins)
horizontalConstraints = titleLabel.layoutToSuperview(axis: .horizontally, offset: horizontalMargins)
titleLabel.forceContentWrap(.vertically)
}
private func setupSubtitleLabel() {
addSubview(subtitleLabel)
labelsOffsetConstraint = subtitleLabel.layout(.top, to: .bottom, of: titleLabel, offset: labelsOffset)
subtitleLabel.layout(to: .left, of: titleLabel)
subtitleLabel.layout(to: .right, of: titleLabel)
bottomConstraint = subtitleLabel.layoutToSuperview(.bottom, offset: -verticalMargins, priority: .must)
subtitleLabel.forceContentWrap(.vertically)
}
private func setupInterfaceStyle() {
titleLabel.textColor = titleContent?.style.color(for: traitCollection)
subtitleLabel.textColor = subtitleContent?.style.color(for: traitCollection)
}
public override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
setupInterfaceStyle()
}
}

View File

@@ -0,0 +1,71 @@
//
// EKNotificationMessageView.swift
// SwiftEntryKit
//
// Created by Daniel Huri on 4/19/18.
// Copyright (c) 2018 huri000@gmail.com. All rights reserved.
//
import UIKit
final public class EKNotificationMessageView: EKSimpleMessageView {
// MARK: Props
private var auxLabel: UILabel!
private var auxiliaryContent: EKProperty.LabelContent!
private let message: EKNotificationMessage
// MARK: Setup
public init(with message: EKNotificationMessage) {
self.message = message
super.init(with: message.simpleMessage)
setupAuxLabel(with: message.auxiliary)
layoutContent(with: message.insets)
}
public required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setupAuxLabel(with content: EKProperty.LabelContent?) {
auxiliaryContent = content
guard let content = content else {
return
}
auxLabel = UILabel()
auxLabel.content = content
addSubview(auxLabel)
}
private func layoutContent(with insets: EKNotificationMessage.Insets) {
messageContentView.verticalMargins = 0
messageContentView.horizontalMargins = 0
messageContentView.labelsOffset = insets.titleToDescription
if let thumbImageView = thumbImageView {
thumbImageView.layoutToSuperview(.left, offset: insets.contentInsets.left)
thumbImageView.layoutToSuperview(.top, offset: insets.contentInsets.top)
messageContentView.layout(.left, to: .right, of: thumbImageView, offset: 12)
messageContentView.layout(to: .top, of: thumbImageView, offset: 4)
} else {
messageContentView.layoutToSuperview(.left, offset: insets.contentInsets.left)
messageContentView.layoutToSuperview(.top, offset: insets.contentInsets.top)
}
if let auxLabel = auxLabel {
auxLabel.layoutToSuperview(.right, offset: -insets.contentInsets.right)
auxLabel.layoutToSuperview(.top, offset: insets.contentInsets.top + 2)
auxLabel.forceContentWrap()
messageContentView.layout(.right, to: .left, of: auxLabel)
} else {
messageContentView.layoutToSuperview(.right, offset: -insets.contentInsets.right)
}
messageContentView.layoutToSuperview(.bottom, offset: -insets.contentInsets.bottom)
}
public override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
auxLabel?.textColor = auxiliaryContent?.style.color(for: traitCollection)
}
}

View File

@@ -0,0 +1,106 @@
//
// EKPopUpMessageView.swift
// SwiftEntryKit
//
// Created by Daniel Huri on 4/20/18.
// Copyright (c) 2018 huri000@gmail.com. All rights reserved.
//
import UIKit
final public class EKPopUpMessageView: UIView {
// MARK: - Properties
private var imageView: UIImageView!
private let titleLabel = UILabel()
private let descriptionLabel = UILabel()
private let actionButton = UIButton()
private let message: EKPopUpMessage
// MARK: - Setup
public init(with message: EKPopUpMessage) {
self.message = message
super.init(frame: UIScreen.main.bounds)
setupImageView()
setupTitleLabel()
setupDescriptionLabel()
setupActionButton()
setupInterfaceStyle()
}
public required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setupImageView() {
guard let themeImage = message.themeImage else {
return
}
imageView = UIImageView()
addSubview(imageView)
imageView.layoutToSuperview(.centerX)
switch themeImage.position {
case .centerToTop(offset: let value):
imageView.layout(.centerY, to: .top, of: self, offset: value)
case .topToTop(offset: let value):
imageView.layoutToSuperview(.top, offset: value)
}
imageView.imageContent = themeImage.image
}
private func setupTitleLabel() {
addSubview(titleLabel)
titleLabel.content = message.title
titleLabel.layoutToSuperview(axis: .horizontally, offset: 30)
if let imageView = imageView {
titleLabel.layout(.top, to: .bottom, of: imageView, offset: 20)
} else {
titleLabel.layoutToSuperview(.top, offset: 20)
}
titleLabel.forceContentWrap(.vertically)
}
private func setupDescriptionLabel() {
addSubview(descriptionLabel)
descriptionLabel.content = message.description
descriptionLabel.layoutToSuperview(axis: .horizontally, offset: 30)
descriptionLabel.layout(.top, to: .bottom, of: titleLabel, offset: 16)
descriptionLabel.forceContentWrap(.vertically)
}
private func setupActionButton() {
addSubview(actionButton)
let height: CGFloat = 45
actionButton.set(.height, of: height)
actionButton.layout(.top, to: .bottom, of: descriptionLabel, offset: 30)
actionButton.layoutToSuperview(.bottom, offset: -30)
actionButton.layoutToSuperview(.centerX)
let buttonAttributes = message.button
actionButton.buttonContent = buttonAttributes
actionButton.contentEdgeInsets = UIEdgeInsets(top: 0, left: 30, bottom: 0, right: 30)
actionButton.layer.cornerRadius = height * 0.5
actionButton.addTarget(self, action: #selector(actionButtonPressed), for: .touchUpInside)
}
private func setupInterfaceStyle() {
titleLabel.textColor = message.title.style.color(for: traitCollection)
imageView?.tintColor = message.themeImage?.image.tintColor(for: traitCollection)
let tapColor = message.button.highlighedLabelColor(for: traitCollection)
actionButton.setTitleColor(tapColor, for: .highlighted)
actionButton.setTitleColor(tapColor, for: .selected)
}
public override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
setupInterfaceStyle()
}
// MARK: - User Interaction
@objc func actionButtonPressed() {
message.action()
}
}

View File

@@ -0,0 +1,110 @@
//
// EKRatingMessageView.swift
// SwiftEntryKit
//
// Created by Daniel Huri on 6/1/18.
// Copyright (c) 2018 huri000@gmail.com. All rights reserved.
//
import UIKit
final public class EKRatingMessageView: UIView, EntryAppearanceDescriptor {
// MARK: Properties
private var message: EKRatingMessage
// MARK: EntryAppearenceDescriptor
var bottomCornerRadius: CGFloat = 0 {
didSet {
buttonBarView.bottomCornerRadius = bottomCornerRadius
}
}
private var selectedIndex: Int! {
didSet {
message.selectedIndex = selectedIndex
let item = message.ratingItems[selectedIndex]
set(title: item.title,
description: item.description)
}
}
private let messageContentView = EKMessageContentView()
private let symbolsView = EKRatingSymbolsContainerView()
private var buttonBarView: EKButtonBarView!
public init(with message: EKRatingMessage) {
self.message = message
super.init(frame: UIScreen.main.bounds)
setupMessageContentView()
setupSymbolsView()
setupButtonBarView()
set(title: message.initialTitle,
description: message.initialDescription)
}
required public init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func set(title: EKProperty.LabelContent,
description: EKProperty.LabelContent) {
messageContentView.titleContent = title
messageContentView.subtitleContent = description
UIView.animate(withDuration: 0.4,
delay: 0,
usingSpringWithDamping: 1,
initialSpringVelocity: 0,
options: [.transitionCrossDissolve],
animations: {
SwiftEntryKit.layoutIfNeeded()
}, completion: nil)
}
private func setupMessageContentView() {
addSubview(messageContentView)
messageContentView.verticalMargins = 20
messageContentView.horizontalMargins = 30
messageContentView.layoutToSuperview(axis: .horizontally,
priority: .must)
messageContentView.layoutToSuperview(.top, offset: 10)
}
private func setupSymbolsView() {
addSubview(symbolsView)
symbolsView.setup(with: message) { [unowned self] (index: Int) in
self.message.selectedIndex = index
self.message.selection?(index)
self.selectedIndex = index
self.animateIn()
}
symbolsView.layoutToSuperview(.centerX)
symbolsView.layout(.top,
to: .bottom,
of: messageContentView,
offset: 10,
priority: .must)
}
private func setupButtonBarView() {
buttonBarView = EKButtonBarView(with: message.buttonBarContent)
buttonBarView.clipsToBounds = true
buttonBarView.alpha = 0
addSubview(buttonBarView)
buttonBarView.layout(.top,
to: .bottom,
of: symbolsView,
offset: 30)
buttonBarView.layoutToSuperview(.bottom)
buttonBarView.layoutToSuperview(axis: .horizontally)
}
// MARK: - Internal Animation
private func animateIn() {
layoutIfNeeded()
buttonBarView.expand()
}
}

View File

@@ -0,0 +1,58 @@
//
// EKMessageView.swift
// SwiftEntryKit
//
// Created by Daniel Huri on 5/5/18.
//
import UIKit
public class EKSimpleMessageView: UIView {
// MARK: Props
var thumbImageView: UIImageView!
let messageContentView = EKMessageContentView()
private let message: EKSimpleMessage
// MARK: Setup
init(with message: EKSimpleMessage) {
self.message = message
super.init(frame: UIScreen.main.bounds)
setupThumbImageView(with: message.image)
setupMessageContentView(with: message.title,
description: message.description)
}
required public init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setupThumbImageView(with content: EKProperty.ImageContent?) {
guard let content = content else {
return
}
thumbImageView = UIImageView()
addSubview(thumbImageView)
thumbImageView.imageContent = content
}
private func setupMessageContentView(with title: EKProperty.LabelContent,
description: EKProperty.LabelContent) {
messageContentView.titleContent = title
messageContentView.subtitleContent = description
addSubview(messageContentView)
}
private func setupInterfaceStyle() {
if let image = message.image {
thumbImageView?.tintColor = image.tint?.color(
for: traitCollection,
mode: image.displayMode
)
}
}
public override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
setupInterfaceStyle()
}
}

View File

@@ -0,0 +1,191 @@
//
// ButtonsBarView.swift
// SwiftEntryKit_Example
//
// Created by Daniel Huri on 4/28/18.
// Copyright (c) 2018 huri000@gmail.com. All rights reserved.
//
import UIKit
/**
Dynamic button bar view
Buttons are set according to the received content.
1-2 buttons spread horizontally
3 or more buttons spread vertically
*/
final public class EKButtonBarView: UIView {
// MARK: - Properties
private var buttonViews: [EKButtonView] = []
private var separatorViews: [UIView] = []
private let buttonBarContent: EKProperty.ButtonBarContent
private let spreadAxis: QLAxis
private let oppositeAxis: QLAxis
private let relativeEdge: NSLayoutConstraint.Attribute
var bottomCornerRadius: CGFloat = 0 {
didSet {
adjustRoundCornersIfNecessary()
}
}
private lazy var buttonEdgeRatio: CGFloat = {
return 1.0 / CGFloat(self.buttonBarContent.content.count)
}()
private(set) lazy var intrinsicHeight: CGFloat = {
var height: CGFloat = 0
switch buttonBarContent.content.count {
case 0:
height += 1
case 1...buttonBarContent.horizontalDistributionThreshold:
height += buttonBarContent.buttonHeight
default:
for _ in 1...buttonBarContent.content.count {
height += buttonBarContent.buttonHeight
}
}
return height
}()
private var compressedConstraint: NSLayoutConstraint!
private lazy var expandedConstraint: NSLayoutConstraint = {
return set(.height, of: intrinsicHeight, priority: .defaultLow)
}()
// MARK: Setup
required public init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
public init(with buttonBarContent: EKProperty.ButtonBarContent) {
self.buttonBarContent = buttonBarContent
if buttonBarContent.content.count <= buttonBarContent.horizontalDistributionThreshold {
spreadAxis = .horizontally
oppositeAxis = .vertically
relativeEdge = .width
} else {
spreadAxis = .vertically
oppositeAxis = .horizontally
relativeEdge = .height
}
super.init(frame: .zero)
setupButtonBarContent()
setupSeparatorViews()
compressedConstraint = set(.height, of: 1, priority: .must)
}
public override func layoutSubviews() {
super.layoutSubviews()
adjustRoundCornersIfNecessary()
}
private func setupButtonBarContent() {
for content in buttonBarContent.content {
let buttonView = EKButtonView(content: content)
addSubview(buttonView)
buttonViews.append(buttonView)
}
layoutButtons()
}
private func layoutButtons() {
guard !buttonViews.isEmpty else {
return
}
let suffix = Array(buttonViews.dropFirst())
if !suffix.isEmpty {
suffix.layout(.height, to: buttonViews.first!)
}
buttonViews.layoutToSuperview(axis: oppositeAxis)
buttonViews.spread(spreadAxis, stretchEdgesToSuperview: true)
buttonViews.layout(relativeEdge, to: self, ratio: buttonEdgeRatio, priority: .must)
}
private func setupTopSeperatorView() {
let topSeparatorView = UIView()
addSubview(topSeparatorView)
topSeparatorView.set(.height, of: 1)
topSeparatorView.layoutToSuperview(.left, .right, .top)
separatorViews.append(topSeparatorView)
}
private func setupSeperatorView(after view: UIView) {
let midSepView = UIView()
addSubview(midSepView)
let sepAttribute: NSLayoutConstraint.Attribute
let buttonAttribute: NSLayoutConstraint.Attribute
switch oppositeAxis {
case .vertically:
sepAttribute = .centerX
buttonAttribute = .right
case .horizontally:
sepAttribute = .centerY
buttonAttribute = .bottom
}
midSepView.layout(sepAttribute, to: buttonAttribute, of: view)
midSepView.set(relativeEdge, of: 1)
midSepView.layoutToSuperview(axis: oppositeAxis)
separatorViews.append(midSepView)
}
private func setupSeparatorViews() {
setupTopSeperatorView()
for button in buttonViews.dropLast() {
setupSeperatorView(after: button)
}
setupInterfaceStyle()
}
// Amination
public func expand() {
let expansion = {
self.compressedConstraint.priority = .defaultLow
self.expandedConstraint.priority = .must
/* NOTE: Calling layoutIfNeeded for the whole view hierarchy.
Sometimes it's easier to just use frames instead of AutoLayout for
hierarch complexity considerations. Here the animation influences almost the
entire view hierarchy. */
SwiftEntryKit.layoutIfNeeded()
}
alpha = 1
if buttonBarContent.expandAnimatedly {
let damping: CGFloat = buttonBarContent.content.count <= 2 ? 0.4 : 0.8
SwiftEntryKit.layoutIfNeeded()
UIView.animate(withDuration: 0.8, delay: 0, usingSpringWithDamping: damping, initialSpringVelocity: 0, options: [.beginFromCurrentState, .allowUserInteraction, .layoutSubviews, .allowAnimatedContent], animations: {
expansion()
}, completion: nil)
} else {
expansion()
}
}
public func compress() {
compressedConstraint.priority = .must
expandedConstraint.priority = .defaultLow
}
private func adjustRoundCornersIfNecessary() {
let size = CGSize(width: bottomCornerRadius, height: bottomCornerRadius)
let path = UIBezierPath(roundedRect: bounds, byRoundingCorners: .bottom, cornerRadii: size)
let maskLayer = CAShapeLayer()
maskLayer.path = path.cgPath
layer.mask = maskLayer
}
private func setupInterfaceStyle() {
for view in separatorViews {
view.backgroundColor = buttonBarContent.separatorColor(for: traitCollection)
}
}
public override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
setupInterfaceStyle()
}
}

View File

@@ -0,0 +1,97 @@
//
// EKButtonView.swift
// SwiftEntryKit
//
// Created by Daniel Huri on 12/8/18.
// Copyright © 2018 CocoaPods. All rights reserved.
//
import UIKit
final class EKButtonView: UIView {
// MARK: - Properties
private let button = UIButton()
private let titleLabel = UILabel()
private let content: EKProperty.ButtonContent
// MARK: - Setup
init(content: EKProperty.ButtonContent) {
self.content = content
super.init(frame: .zero)
setupTitleLabel()
setupButton()
setupAcceessibility()
setupInterfaceStyle()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setupAcceessibility() {
isAccessibilityElement = false
button.isAccessibilityElement = true
button.accessibilityIdentifier = content.accessibilityIdentifier
button.accessibilityLabel = content.label.text
}
private func setupButton() {
addSubview(button)
button.fillSuperview()
button.addTarget(self, action: #selector(buttonTouchUp),
for: [.touchUpInside, .touchUpOutside, .touchCancel])
button.addTarget(self, action: #selector(buttonTouchDown),
for: .touchDown)
button.addTarget(self, action: #selector(buttonTouchUpInside),
for: .touchUpInside)
}
private func setupTitleLabel() {
titleLabel.numberOfLines = content.label.style.numberOfLines
titleLabel.font = content.label.style.font
titleLabel.text = content.label.text
titleLabel.textAlignment = .center
titleLabel.lineBreakMode = .byWordWrapping
addSubview(titleLabel)
titleLabel.layoutToSuperview(axis: .horizontally,
offset: content.contentEdgeInset)
titleLabel.layoutToSuperview(axis: .vertically,
offset: content.contentEdgeInset)
}
private func setBackground(by content: EKProperty.ButtonContent,
isHighlighted: Bool) {
if isHighlighted {
backgroundColor = content.highlightedBackgroundColor(for: traitCollection)
} else {
backgroundColor = content.backgroundColor(for: traitCollection)
}
}
private func setupInterfaceStyle() {
backgroundColor = content.backgroundColor(for: traitCollection)
titleLabel.textColor = content.label.style.color(for: traitCollection)
}
// MARK: - Selectors
@objc func buttonTouchUpInside() {
content.action?()
}
@objc func buttonTouchDown() {
setBackground(by: content, isHighlighted: true)
}
@objc func buttonTouchUp() {
setBackground(by: content, isHighlighted: false)
}
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
setupInterfaceStyle()
}
}

View File

@@ -0,0 +1,69 @@
//
// EKRatingSymbolView.swift
// SwiftEntryKit
//
// Created by Daniel Huri on 6/1/18.
// Copyright (c) 2018 huri000@gmail.com. All rights reserved.
//
import UIKit
final public class EKRatingSymbolView: UIView {
private let button = UIButton()
private let imageView = UIImageView()
private let unselectedImage: EKProperty.ImageContent
private let selectedImage: EKProperty.ImageContent
var selection: EKRatingMessage.Selection
public var isSelected: Bool {
set {
imageView.imageContent = newValue ? selectedImage : unselectedImage
}
get {
return imageView.image == selectedImage.images.first
}
}
public init(unselectedImage: EKProperty.ImageContent, selectedImage: EKProperty.ImageContent, selection: @escaping EKRatingMessage.Selection) {
self.unselectedImage = unselectedImage
self.selectedImage = selectedImage
self.selection = selection
super.init(frame: .zero)
setupImageView()
setupButton()
}
required public init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setupButton() {
addSubview(button)
button.fillSuperview()
button.addTarget(self, action: #selector(touchUpInside), for: .touchUpInside)
button.addTarget(self, action: #selector(touchDown), for: [.touchDown])
button.addTarget(self, action: #selector(touchUp), for: [.touchUpInside, .touchUpOutside, .touchCancel])
}
private func setupImageView() {
addSubview(imageView)
imageView.imageContent = unselectedImage
imageView.centerInSuperview()
imageView.sizeToSuperview(withRatio: 0.7)
}
@objc func touchUpInside() {
selection(tag)
}
@objc func touchDown() {
transform = CGAffineTransform(scaleX: 1.15, y: 1.15)
}
@objc func touchUp() {
transform = CGAffineTransform(scaleX: 1, y: 1)
}
}

View File

@@ -0,0 +1,62 @@
//
// EKRatingSymbolsContainerView.swift
// SwiftEntryKit
//
// Created by Daniel Huri on 6/1/18.
// Copyright (c) 2018 huri000@gmail.com. All rights reserved.
//
import UIKit
final public class EKRatingSymbolsContainerView: UIView {
private var message: EKRatingMessage!
private var symbolsArray: [EKRatingSymbolView] = []
public func setup(with message: EKRatingMessage,
externalSelection: @escaping EKRatingMessage.Selection) {
self.message = message
let internalSelection = { [unowned self] (index: Int) in
self.select(index: index)
externalSelection(index)
}
for (index, item) in message.ratingItems.enumerated() {
let itemView = EKRatingSymbolView(unselectedImage: item.unselectedImage,
selectedImage: item.selectedImage,
selection: internalSelection)
itemView.tag = index
addSubview(itemView)
itemView.set(.height, of: item.size.height)
itemView.set(.width, of: item.size.width)
symbolsArray.append(itemView)
}
symbolsArray.layoutToSuperview(axis: .vertically, priority: .must)
symbolsArray.spread(.horizontally, stretchEdgesToSuperview: true)
select(index: message.selectedIndex)
}
private func select(index: Int? = nil) {
var delay: TimeInterval = 0
for (i, view) in symbolsArray.enumerated() {
DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
if let index = index, i <= index {
view.isSelected = true
view.transform = CGAffineTransform(scaleX: 1.5, y: 1.5)
} else if view.isSelected || index == nil {
view.isSelected = false
view.transform = CGAffineTransform(scaleX: 0.5, y: 0.5)
}
UIView.animate(withDuration: 0.6,
delay: 0,
usingSpringWithDamping: 0.5,
initialSpringVelocity: 0,
options: [.allowUserInteraction], animations: {
view.transform = .identity
}, completion: nil)
}
delay += 0.05
}
}
}

View File

@@ -0,0 +1,88 @@
//
// EKTextField.swift
// SwiftEntryKit
//
// Created by Daniel Huri on 5/16/18.
//
import Foundation
import UIKit
final public class EKTextField: UIView {
// MARK: - Properties
static let totalHeight: CGFloat = 45
private let content: EKProperty.TextFieldContent
private let imageView = UIImageView()
private let textField = UITextField()
private let separatorView = UIView()
public var text: String {
set {
textField.text = newValue
}
get {
return textField.text ?? ""
}
}
// MARK: - Setup
public init(with content: EKProperty.TextFieldContent) {
self.content = content
super.init(frame: UIScreen.main.bounds)
setupImageView()
setupTextField()
setupSeparatorView()
textField.accessibilityIdentifier = content.accessibilityIdentifier
}
required public init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setupImageView() {
addSubview(imageView)
imageView.contentMode = .center
imageView.set(.width, .height, of: EKTextField.totalHeight)
imageView.layoutToSuperview(.leading)
imageView.image = content.leadingImage
imageView.tintColor = content.tintColor(for: traitCollection)
}
private func setupTextField() {
addSubview(textField)
textField.textFieldContent = content
textField.delegate = content.delegate
textField.set(.height, of: EKTextField.totalHeight)
textField.layout(.leading, to: .trailing, of: imageView)
textField.layoutToSuperview(.top, .trailing)
imageView.layout(to: .centerY, of: textField)
}
private func setupSeparatorView() {
addSubview(separatorView)
separatorView.layout(.top, to: .bottom, of: textField)
separatorView.set(.height, of: 1)
separatorView.layoutToSuperview(.bottom)
separatorView.layoutToSuperview(axis: .horizontally, offset: 10)
separatorView.backgroundColor = content.bottomBorderColor.color(
for: traitCollection,
mode: content.displayMode
)
}
public func makeFirstResponder() {
textField.becomeFirstResponder()
}
public override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
separatorView.backgroundColor = content.bottomBorderColor(for: traitCollection)
imageView.tintColor = content.tintColor(for: traitCollection)
textField.textColor = content.textStyle.color(for: traitCollection)
textField.placeholder = content.placeholder
}
}

View File

@@ -0,0 +1,18 @@
//
// EntryAppearanceDescriptor.swift
// SwiftEntryKit
//
// Created by Daniel Huri on 1/5/19.
// Copyright © 2019 CocoaPods. All rights reserved.
//
import UIKit
/**
An anti-pattern for SwiftEntryKit views to know more about their appearence,
if necessary, since views don't have access to EKAttributes.
This is a solution to bug #117 (round buttons in alert)
*/
protocol EntryAppearanceDescriptor: AnyObject {
var bottomCornerRadius: CGFloat { get set }
}

View File

@@ -0,0 +1,35 @@
//
// EKAccessoryNoteMessageView.swift
// SwiftEntryKit
//
// Created by Daniel Huri on 5/4/18.
//
import UIKit
public class EKAccessoryNoteMessageView: UIView {
// MARK: Props
private let contentView = UIView()
private var noteMessageView: EKNoteMessageView!
var accessoryView: UIView!
func setup(with content: EKProperty.LabelContent) {
clipsToBounds = true
addSubview(contentView)
contentView.layoutToSuperview(.centerX, .top, .bottom)
contentView.layoutToSuperview(.left, relation: .greaterThanOrEqual, offset: 16)
contentView.layoutToSuperview(.right, relation: .lessThanOrEqual, offset: -16)
noteMessageView = EKNoteMessageView(with: content)
noteMessageView.horizontalOffset = 8
noteMessageView.verticalOffset = 7
contentView.addSubview(noteMessageView)
noteMessageView.layoutToSuperview(.top, .bottom, .trailing)
contentView.addSubview(accessoryView)
accessoryView.layoutToSuperview(.leading, .centerY)
accessoryView.layout(.trailing, to: .leading, of: noteMessageView)
}
}

View File

@@ -0,0 +1,28 @@
//
// EKImageNoteMessageView.swift
// SwiftEntryKit
//
// Created by Daniel Huri on 5/4/18.
//
import UIKit
public class EKImageNoteMessageView: EKAccessoryNoteMessageView {
// MARK: Setup
public required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
public init(with content: EKProperty.LabelContent, imageContent: EKProperty.ImageContent) {
super.init(frame: UIScreen.main.bounds)
setup(with: content, imageContent: imageContent)
}
private func setup(with content: EKProperty.LabelContent, imageContent: EKProperty.ImageContent) {
let imageView = UIImageView()
imageView.imageContent = imageContent
accessoryView = imageView
super.setup(with: content)
}
}

View File

@@ -0,0 +1,52 @@
//
// EKNoteMessageView.swift
// SwiftEntryKit
//
// Created by Daniel Huri on 4/19/18.
// Copyright (c) 2018 huri000@gmail.com. All rights reserved.
//
import UIKit
public class EKNoteMessageView: UIView {
// MARK: Props
private let label = UILabel()
private var horizontalConstrainsts: QLAxisConstraints!
private var verticalConstrainsts: QLAxisConstraints!
public var horizontalOffset: CGFloat = 10 {
didSet {
horizontalConstrainsts.first.constant = horizontalOffset
horizontalConstrainsts.second.constant = -horizontalOffset
layoutIfNeeded()
}
}
public var verticalOffset: CGFloat = 5 {
didSet {
verticalConstrainsts.first.constant = verticalOffset
verticalConstrainsts.second.constant = -verticalOffset
layoutIfNeeded()
}
}
// MARK: Setup
public init(with content: EKProperty.LabelContent) {
super.init(frame: UIScreen.main.bounds)
setup(with: content)
}
public required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setup(with content: EKProperty.LabelContent) {
clipsToBounds = true
addSubview(label)
label.content = content
horizontalConstrainsts = label.layoutToSuperview(axis: .horizontally, offset: horizontalOffset, priority: .must)
verticalConstrainsts = label.layoutToSuperview(axis: .vertically, offset: verticalOffset, priority: .must)
}
}

View File

@@ -0,0 +1,45 @@
//
// EKProcessingNoteMessageView.swift
// SwiftEntryKit
//
// Created by Daniel Huri on 4/20/18.
// Copyright (c) 2018 huri000@gmail.com. All rights reserved.
//
import UIKit
public class EKProcessingNoteMessageView: EKAccessoryNoteMessageView {
// MARK: Props
private var activityIndicatorView: UIActivityIndicatorView!
private var noteMessageView: EKNoteMessageView!
/** Activity indication can be turned off / on */
public var isProcessing: Bool = true {
didSet {
if isProcessing {
activityIndicatorView.startAnimating()
} else {
activityIndicatorView.stopAnimating()
}
}
}
// MARK: Setup
public required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
public init(with content: EKProperty.LabelContent, activityIndicator: UIActivityIndicatorView.Style) {
super.init(frame: UIScreen.main.bounds)
setup(with: content, activityIndicator: activityIndicator)
}
private func setup(with content: EKProperty.LabelContent, activityIndicator: UIActivityIndicatorView.Style, setProcessing: Bool = true) {
activityIndicatorView = UIActivityIndicatorView()
activityIndicatorView.style = activityIndicator
isProcessing = setProcessing
accessoryView = activityIndicatorView
super.setup(with: content)
}
}

View File

@@ -0,0 +1,46 @@
//
// EKXStatusBarMessageView.swift
// SwiftEntryKit
//
// Created by Daniel Huri on 4/19/18.
// Copyright (c) 2018 huri000@gmail.com. All rights reserved.
//
import UIKit
public class EKXStatusBarMessageView: UIView {
// MARK: Props
private let leadingLabel = UILabel()
private let trailingLabel = UILabel()
// MARK: Setup
public init(leading: EKProperty.LabelContent, trailing: EKProperty.LabelContent) {
super.init(frame: UIScreen.main.bounds)
setup(leading: leading, trailing: trailing)
}
public required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setup(leading: EKProperty.LabelContent, trailing: EKProperty.LabelContent) {
clipsToBounds = true
set(.height, of: UIApplication.shared.statusBarFrame.maxY)
addSubview(leadingLabel)
leadingLabel.content = leading
leadingLabel.layoutToSuperview(axis: .vertically)
leadingLabel.layoutToSuperview(.leading)
leadingLabel.layoutToSuperview(.width, ratio: 0.26)
addSubview(trailingLabel)
trailingLabel.content = trailing
trailingLabel.layoutToSuperview(axis: .vertically)
trailingLabel.layoutToSuperview(.trailing)
trailingLabel.layoutToSuperview(.width, ratio: 0.26)
}
}