Skip to content

Commit

Permalink
Merge pull request #6 from devpolant/feature/optional-action-buttons
Browse files Browse the repository at this point in the history
Optional action buttons
  • Loading branch information
devpolant authored May 8, 2021
2 parents 716cf7f + 3740eb7 commit 10363a9
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 48 deletions.
2 changes: 1 addition & 1 deletion NativeUI.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "NativeUI"
s.version = "1.1.0"
s.version = "1.2.0"
s.summary = "Library that includes customizable replacements for native UIKit components"

s.description = <<-DESC
Expand Down
10 changes: 10 additions & 0 deletions NativeUI/Sources/Alert/AlertActionSequenceView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ final class AlertActionSequenceView: UIControl {

private let selectionFeedbackGenerator = SelectionFeedbackGenerator()

override var intrinsicContentSize: CGSize {
return CGSize(
width: UIView.noIntrinsicMetric,
height: 44
)
}

// MARK: - Subviews

private final class ActionView: UIView {
Expand Down Expand Up @@ -97,6 +104,9 @@ final class AlertActionSequenceView: UIControl {
stackView.trailingAnchor.constraint(equalTo: trailingAnchor),
stackView.bottomAnchor.constraint(equalTo: bottomAnchor)
])

setContentHuggingPriority(.required, for: .vertical)
setContentCompressionResistancePriority(.required, for: .vertical)
}

// MARK: - Setup
Expand Down
98 changes: 56 additions & 42 deletions NativeUI/Sources/Alert/AlertView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ final class AlertView: UIView {

// MARK: - Subviews

// MARK: Blur

private lazy var blurView: UIVisualEffectView = {
let blurEffect = UIBlurEffect(style: .extraLight)

Expand All @@ -32,14 +34,16 @@ final class AlertView: UIView {
return effectView
}()

// MARK: Content

private lazy var contentContainerView: UIView = {
let containerView = UIView()
containerView.translatesAutoresizingMaskIntoConstraints = false
blurView.contentView.addSubview(containerView)
return containerView
}()

private lazy var verticalStackView: UIStackView = {
private lazy var contentStackView: UIStackView = {
let stackView = UIStackView()
stackView.translatesAutoresizingMaskIntoConstraints = false
contentContainerView.addSubview(stackView)
Expand All @@ -66,19 +70,26 @@ final class AlertView: UIView {
return contentView
}()

// MARK: Actions

private lazy var actionsStackView: UIStackView = {
let stackView = UIStackView()
stackView.translatesAutoresizingMaskIntoConstraints = false
blurView.contentView.addSubview(stackView)
return stackView
}()

private lazy var contentSeparatorView: UIView = {
let separatorView = UIView()
separatorView.backgroundColor = separatorColor
separatorView.translatesAutoresizingMaskIntoConstraints = false
blurView.contentView.addSubview(separatorView)
return separatorView
}()

private lazy var actionsContainerView: AlertActionSequenceView = {
let containerView = AlertActionSequenceView()
containerView.translatesAutoresizingMaskIntoConstraints = false
blurView.contentView.addSubview(containerView)
return containerView
private lazy var actionSequenceView: AlertActionSequenceView = {
let sequenceView = AlertActionSequenceView()
sequenceView.translatesAutoresizingMaskIntoConstraints = false
return sequenceView
}()

// MARK: - Init
Expand Down Expand Up @@ -111,35 +122,38 @@ final class AlertView: UIView {
contentContainerView.leadingAnchor.constraint(equalTo: blurView.contentView.leadingAnchor),
contentContainerView.trailingAnchor.constraint(equalTo: blurView.contentView.trailingAnchor),

verticalStackView.topAnchor.constraint(equalTo: contentContainerView.topAnchor, constant: Layout.Content.top),
verticalStackView.leadingAnchor.constraint(equalTo: contentContainerView.leadingAnchor, constant: Layout.Content.horizontal),
verticalStackView.trailingAnchor.constraint(equalTo: contentContainerView.trailingAnchor, constant: -Layout.Content.horizontal),
verticalStackView.bottomAnchor.constraint(equalTo: contentContainerView.bottomAnchor, constant: -Layout.Content.bottom),

contentSeparatorView.topAnchor.constraint(equalTo: contentContainerView.bottomAnchor),
contentSeparatorView.leadingAnchor.constraint(equalTo: blurView.contentView.leadingAnchor),
contentSeparatorView.trailingAnchor.constraint(equalTo: blurView.contentView.trailingAnchor),
contentSeparatorView.heightAnchor.constraint(equalToConstant: Layout.separatorThickness),
contentStackView.topAnchor.constraint(equalTo: contentContainerView.topAnchor, constant: Layout.Content.top),
contentStackView.leadingAnchor.constraint(equalTo: contentContainerView.leadingAnchor, constant: Layout.Content.horizontal),
contentStackView.trailingAnchor.constraint(equalTo: contentContainerView.trailingAnchor, constant: -Layout.Content.horizontal),
contentStackView.bottomAnchor.constraint(equalTo: contentContainerView.bottomAnchor, constant: -Layout.Content.bottom),

actionsContainerView.topAnchor.constraint(equalTo: contentSeparatorView.bottomAnchor),
actionsContainerView.leadingAnchor.constraint(equalTo: blurView.contentView.leadingAnchor),
actionsContainerView.trailingAnchor.constraint(equalTo: blurView.contentView.trailingAnchor),
actionsContainerView.bottomAnchor.constraint(equalTo: blurView.contentView.bottomAnchor),
actionsContainerView.heightAnchor.constraint(equalToConstant: Layout.Button.height)
actionsStackView.topAnchor.constraint(equalTo: contentContainerView.bottomAnchor),
actionsStackView.leadingAnchor.constraint(equalTo: blurView.contentView.leadingAnchor),
actionsStackView.trailingAnchor.constraint(equalTo: blurView.contentView.trailingAnchor),
actionsStackView.bottomAnchor.constraint(equalTo: blurView.contentView.bottomAnchor)
])

verticalStackView.axis = .vertical
verticalStackView.spacing = Layout.Content.verticalSpacing
verticalStackView.addArrangedSubview(titleLabel)
verticalStackView.addArrangedSubview(messageLabel)
verticalStackView.addArrangedSubview(customContentView)
contentStackView.axis = .vertical
contentStackView.spacing = Layout.Content.verticalSpacing
contentStackView.addArrangedSubview(titleLabel)
contentStackView.addArrangedSubview(messageLabel)
contentStackView.addArrangedSubview(customContentView)

actionsStackView.axis = .vertical
actionsStackView.spacing = 0
actionsStackView.addArrangedSubview(contentSeparatorView)
actionsStackView.addArrangedSubview(actionSequenceView)

NSLayoutConstraint.activate([
contentSeparatorView.heightAnchor.constraint(equalToConstant: Layout.separatorThickness)
])

titleLabel.setContentHuggingPriority(.required, for: .vertical)
titleLabel.setContentCompressionResistancePriority(.required, for: .vertical)
messageLabel.setContentHuggingPriority(.required, for: .vertical)
messageLabel.setContentCompressionResistancePriority(.required, for: .vertical)
[titleLabel, messageLabel].forEach {
$0.setContentHuggingPriority(.required, for: .vertical)
$0.setContentCompressionResistancePriority(.required, for: .vertical)
}

actionsContainerView.delegate = self
actionSequenceView.delegate = self
}

private func setupAppearance() {
Expand Down Expand Up @@ -191,13 +205,17 @@ final class AlertView: UIView {
}
customContentView.isHidden = viewModel.contentView == nil

let actionsViewModel = AlertActionSequenceViewModel(
actions: viewModel.actions,
disabledTintColor: viewModel.disabledTintColor,
separatorColor: separatorColor,
separatorWidth: Layout.separatorThickness
)
actionsContainerView.setup(viewModel: actionsViewModel)
if !viewModel.actions.isEmpty {
let actionsViewModel = AlertActionSequenceViewModel(
actions: viewModel.actions,
disabledTintColor: viewModel.disabledTintColor,
separatorColor: separatorColor,
separatorWidth: Layout.separatorThickness
)
actionSequenceView.setup(viewModel: actionsViewModel)
}
contentSeparatorView.isHidden = viewModel.actions.isEmpty
actionSequenceView.isHidden = viewModel.actions.isEmpty
}

// MARK: - Layout
Expand All @@ -214,10 +232,6 @@ final class AlertView: UIView {
static let horizontal: CGFloat = 16
static let verticalSpacing: CGFloat = 4
}

enum Button {
static let height: CGFloat = 44
}
}
}

Expand Down
32 changes: 31 additions & 1 deletion NativeUI/Sources/Alert/AlertViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,19 @@ public final class AlertViewController: UIViewController, AlertViewDelegate {

public var shouldDismissAutomatically: Bool = true

public var shouldDismissOnBackgroundTap: Bool = false

private var viewModel: Alert

// MARK: - Subviews

private lazy var backgroundView: UIView = {
let backgroundView = UIView()
backgroundView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(backgroundView)
return backgroundView
}()

private(set) lazy var alertView: AlertView = {
let alertView = AlertView()
alertView.translatesAutoresizingMaskIntoConstraints = false
Expand All @@ -30,6 +39,7 @@ public final class AlertViewController: UIViewController, AlertViewDelegate {
super.init(nibName: nil, bundle: nil)
modalPresentationStyle = .custom
transitioningDelegate = self
shouldDismissOnBackgroundTap = viewModel.actions.isEmpty
}

required init?(coder: NSCoder) {
Expand All @@ -42,6 +52,7 @@ public final class AlertViewController: UIViewController, AlertViewDelegate {
super.viewDidLoad()
setupAppearance()
setupLayout()
setupGestures()
setupViewModel()
}

Expand All @@ -54,7 +65,7 @@ public final class AlertViewController: UIViewController, AlertViewDelegate {
// MARK: - UI Setup

private func setupAppearance() {
view.backgroundColor = UIColor.black.withAlphaComponent(0.2)
backgroundView.backgroundColor = UIColor.black.withAlphaComponent(0.2)

if let tintColor = viewModel.tintColor {
view.tintColor = tintColor
Expand All @@ -77,18 +88,37 @@ public final class AlertViewController: UIViewController, AlertViewDelegate {
}

NSLayoutConstraint.activate([
backgroundView.topAnchor.constraint(equalTo: view.topAnchor),
backgroundView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
backgroundView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
backgroundView.bottomAnchor.constraint(equalTo: view.bottomAnchor),

alertView.widthAnchor.constraint(equalToConstant: Layout.width),
alertView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
alertView.centerYAnchor.constraint(equalTo: safeAreaLayoutGuide.centerYAnchor),
alertView.topAnchor.constraint(greaterThanOrEqualTo: view.topAnchor, constant: Layout.verticalInset)
])
}

private func setupGestures() {
guard shouldDismissOnBackgroundTap else {
return
}
let recognizer = UITapGestureRecognizer(target: self, action: #selector(actionBackgroundViewTapped(sender:)))
backgroundView.addGestureRecognizer(recognizer)
}

private func setupViewModel() {
alertView.delegate = self
alertView.setup(viewModel: viewModel)
}

// MARK: - Actions

@objc private func actionBackgroundViewTapped(sender: UIGestureRecognizer) {
dismiss(animated: true, completion: nil)
}

// MARK: - Layout

private enum Layout {
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@

# NativeUI

## Requirements:
## Minimum Requirements:
- iOS 9.0
- Xcode 11.0
- Xcode 12.0
- Swift 5

## Installation
Expand All @@ -16,15 +16,15 @@

```ruby
target 'MyApp' do
pod 'NativeUI', '~> 1.1'
pod 'NativeUI', '~> 1.2'
end
```

If you don't need to connect all UI components you may use subspecs like:

```ruby
target 'MyApp' do
pod 'NativeUI/Alert', '~> 1.1'
pod 'NativeUI/Alert', '~> 1.2'
end
```

Expand Down

0 comments on commit 10363a9

Please sign in to comment.