Skip to content

Commit

Permalink
NO-JIRA: Add AlertViewController
Browse files Browse the repository at this point in the history
  • Loading branch information
igorTimofiejczyk committed Aug 31, 2022
1 parent 0d8d120 commit 6174084
Show file tree
Hide file tree
Showing 11 changed files with 431 additions and 6 deletions.
1 change: 1 addition & 0 deletions Style/Sources/Style/Assets.swift
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ public enum Asset {
public static let more = ImageAsset(name: "more")
public static let podium = ImageAsset(name: "podium")
public static let cityLogo = ImageAsset(name: "city_logo")
public static let dogWhileEating = ImageAsset(name: "dog_while_eating")
public static let animealLogo = ImageAsset(name: "animeal_logo")
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"images" : [
{
"filename" : "dog_while_eating.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"preserves-vector-representation" : true
}
}
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public extension ButtonView {
public init(
identifier: String,
viewType: ButtonView.Type,
icon: UIImage?,
icon: UIImage? = nil,
title: String = String.empty
) {
self.identifier = identifier
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,44 @@ public struct ButtonViewFactory: ButtonViewGenerating, StyleEngineContainable {
return ButtonView(contentView: button)
}

public func makeAccentButton() -> ButtonView {
let button = UIButton()
button.layer.cornerRadius = Constants.cornerRadius
button.clipsToBounds = true
button.backgroundColor = designEngine.colors.accent.uiColor

button.setTitleColor(
designEngine.colors.alwaysLight.uiColor,
for: UIControl.State.normal
)
button.setTitleColor(
designEngine.colors.error.uiColor,
for: UIControl.State.highlighted
)

return ButtonView(contentView: button)
}

public func makeAccentInvertedButton() -> ButtonView {
let button = UIButton()
button.layer.cornerRadius = Constants.cornerRadius
button.clipsToBounds = true
button.layer.borderColor = designEngine.colors.accent.cgColor
button.layer.borderWidth = 1

button.backgroundColor = designEngine.colors.backgroundPrimary.uiColor
button.setTitleColor(
designEngine.colors.accent.uiColor,
for: UIControl.State.normal
)
button.setTitleColor(
designEngine.colors.accent.uiColor.withAlphaComponent(0.5),
for: UIControl.State.highlighted
)

return ButtonView(contentView: button)
}

public func makeMyLocationButton() -> ButtonView {
let button = UIButton()
button.backgroundColor = designEngine.colors.backgroundPrimary.uiColor
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import UIKit

class TransitionAnimator: NSObject, UIViewControllerAnimatedTransitioning {
var toViewController: UIViewController!
var fromViewController: UIViewController!
let inDuration: TimeInterval
let outDuration: TimeInterval
let direction: AnimationDirection

init(inDuration: TimeInterval, outDuration: TimeInterval, direction: AnimationDirection) {
self.inDuration = inDuration
self.outDuration = outDuration
self.direction = direction
super.init()
}

internal func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return direction == .in ? inDuration : outDuration
}

internal func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
switch direction {
case .in:
guard let toViewController = transitionContext.viewController(
forKey: UITransitionContextViewControllerKey.to
), let fromViewController = transitionContext.viewController(
forKey: UITransitionContextViewControllerKey.from
) else { return }

self.toViewController = toViewController
self.fromViewController = fromViewController

let container = transitionContext.containerView
container.addSubview(toViewController.view)
case .out:
guard let toViewController = transitionContext.viewController(
forKey: UITransitionContextViewControllerKey.to
), let fromViewController = transitionContext.viewController(
forKey: UITransitionContextViewControllerKey.from
) else { return }

self.toViewController = toViewController
self.fromViewController = fromViewController
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import UIKit

final class ZoomTransition: TransitionAnimator {

init(direction: AnimationDirection) {
super.init(inDuration: 0.22, outDuration: 0.2, direction: direction)
}

override func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
super.animateTransition(using: transitionContext)

switch direction {
case .in:
toViewController.view.transform = CGAffineTransform(scaleX: 0.1, y: 0.1)
UIView.animate(
withDuration: 0.6,
delay: 0.0,
usingSpringWithDamping: 0.6,
initialSpringVelocity: 0,
options: [.curveEaseOut],
animations: { [weak self] in
guard let self = self else { return }
self.toViewController.view.transform = CGAffineTransform(scaleX: 1, y: 1)
},
completion: { _ in
transitionContext.completeTransition(true)
}
)
case .out:
UIView.animate(
withDuration: outDuration,
delay: 0.0,
options: [.curveEaseIn],
animations: { [weak self] in
guard let self = self else { return }
self.fromViewController.view.transform = CGAffineTransform(scaleX: 0.1, y: 0.1)
self.fromViewController.view.alpha = 0.0
},
completion: { _ in
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
}
)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import UIKit

final class BlurryPresentationController: UIPresentationController {
private lazy var overlay: UIVisualEffectView = {
let blurEffectView = UIVisualEffectView()
blurEffectView.backgroundColor = .clear
blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
return blurEffectView
}()
private var blurAnimator: UIViewPropertyAnimator?

override func presentationTransitionWillBegin() {
guard let containerView = containerView else { return }

blurAnimator = UIViewPropertyAnimator(duration: 1, curve: .linear) { [overlay] in
overlay.effect = UIBlurEffect(style: .dark)
}
blurAnimator?.fractionComplete = 0.15 // set the blur intensity.

overlay.frame = containerView.bounds
containerView.insertSubview(overlay, at: 0)

presentedViewController.transitionCoordinator?.animate(
alongsideTransition: { [weak self] _ in
self?.overlay.alpha = 1.0
},
completion: nil
)
}

override func dismissalTransitionWillBegin() {
blurAnimator?.stopAnimation(true)
presentedViewController.transitionCoordinator?.animate(
alongsideTransition: { [weak self] _ in
self?.overlay.alpha = 0.0
},
completion: nil
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import UIKit

final class ZoomTransitionController: NSObject, UIViewControllerTransitioningDelegate {
func presentationController(
forPresented presented: UIViewController,
presenting: UIViewController?,
source: UIViewController
) -> UIPresentationController? {
let presentationController = BlurryPresentationController(
presentedViewController: presented,
presenting: source
)
return presentationController
}

func animationController(
forPresented presented: UIViewController,
presenting: UIViewController,
source: UIViewController
) -> UIViewControllerAnimatedTransitioning? {
return ZoomTransition(direction: .in)
}

func animationController(
forDismissed dismissed: UIViewController
) -> UIViewControllerAnimatedTransitioning? {
return ZoomTransition(direction: .out)
}
}

enum AnimationDirection {
case `in` // swiftlint:disable:this identifier_name
case out
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
import UIKit

/// AlertViewController
///
/// Usage example:
///
/// let alert = AlertViewController(
/// title: "Some Title"
/// )
/// alert.addAction(
/// AlertAction(title: "Action title", style: AlertAction.Style.inverted, handler: { })
/// )
///
/// present(alert, animated: true)
///
public final class AlertViewController: UIViewController {
// MARK: - Private properties
private let actionsContainer = UIStackView()
private let transitionController = ZoomTransitionController()

// MARK: - Initialization
public init(title: String, image: UIImage? = nil) {
super.init(nibName: nil, bundle: nil)

self.transitioningDelegate = transitionController
self.modalPresentationStyle = .custom

setup(title: title, image: image)
}

required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

// MARK: - Public API
public func addAction(_ action: AlertAction) {
let factory = ButtonViewFactory()
var button: ButtonView
switch action.style {
case .accent:
button = factory.makeAccentButton()
case .inverted:
button = factory.makeAccentInvertedButton()
}

button.condifure(
ButtonView.Model(
identifier: UUID().uuidString,
viewType: ButtonView.self,
title: action.title ?? .empty
)
)
button.onTap = { _ in
action.handler?()
}
actionsContainer.addArrangedSubview(button)
}

// MARK: - Private API
private func setup(title: String, image: UIImage?) {
let dialogView = UIView()
dialogView.layer.cornerRadius = 30

view.addSubview(dialogView.prepareForAutoLayout())
dialogView.leadingAnchor ~= view.leadingAnchor + 36
dialogView.trailingAnchor ~= view.trailingAnchor - 36
dialogView.centerXAnchor ~= view.centerXAnchor
dialogView.centerYAnchor ~= view.centerYAnchor
dialogView.backgroundColor = designEngine.colors.backgroundPrimary.uiColor

let contentView = UIStackView()
contentView.axis = .horizontal

dialogView.addSubview(contentView.prepareForAutoLayout())
contentView.topAnchor ~= dialogView.topAnchor + 26
contentView.leadingAnchor ~= dialogView.leadingAnchor + 26
contentView.trailingAnchor ~= dialogView.trailingAnchor - 26
contentView.axis = .vertical

dialogView.addSubview(actionsContainer.prepareForAutoLayout())
actionsContainer.topAnchor ~= contentView.bottomAnchor + 28
actionsContainer.leadingAnchor ~= dialogView.leadingAnchor + 26
actionsContainer.trailingAnchor ~= dialogView.trailingAnchor - 26
actionsContainer.bottomAnchor ~= dialogView.bottomAnchor - 26
actionsContainer.distribution = .fillEqually
actionsContainer.spacing = 12

let titleLabel = UILabel()
titleLabel.font = designEngine.fonts.primary.bold(18).uiFont
titleLabel.textColor = designEngine.colors.textPrimary.uiColor
titleLabel.numberOfLines = 0
titleLabel.text = title

contentView.addArrangedSubview(titleLabel)

if let image = image {
let spacerView = UIView().prepareForAutoLayout()
spacerView.heightAnchor ~= 26
contentView.addArrangedSubview(spacerView)

let imageView = UIImageView()
imageView.image = image
imageView.layer.cornerRadius = 16

contentView.addArrangedSubview(imageView)
}
}
}

// MARK: - AlertAction model
public struct AlertAction {
public let title: String?
public let style: Style
public let handler: (() -> Void)?

public enum Style {
case accent
case inverted
}

public init(
title: String? = nil,
style: Style,
handler: (() -> Void)? = nil
) {
self.title = title
self.style = style
self.handler = handler
}
}
Loading

0 comments on commit 6174084

Please sign in to comment.