From a4b31f24c2a5ccb0db214f0d9e799fa633a5c900 Mon Sep 17 00:00:00 2001 From: tun57 Date: Sat, 2 Mar 2019 00:47:21 -0800 Subject: [PATCH] Update alertView. --- PanModal.xcodeproj/project.pbxproj | 26 +++++- .../PanModalPresentationController.swift | 2 + .../PanModalPresentable+Defaults.swift | 4 + .../Presentable/PanModalPresentable.swift | 9 ++ Sample/SampleViewController.swift | 16 +++- .../TransientAlertViewController.swift | 69 +++++++++++++++ Sample/View Controllers/Alert/AlertView.swift | 82 ++++++++++++++++++ .../Alert/AlertViewController.swift | 68 +++++++++++++++ .../AlertViewController.swift | 86 ------------------- 9 files changed, 271 insertions(+), 91 deletions(-) create mode 100644 Sample/View Controllers/Alert (Transient)/TransientAlertViewController.swift create mode 100644 Sample/View Controllers/Alert/AlertView.swift create mode 100644 Sample/View Controllers/Alert/AlertViewController.swift delete mode 100644 Sample/View Controllers/AlertViewController.swift diff --git a/PanModal.xcodeproj/project.pbxproj b/PanModal.xcodeproj/project.pbxproj index d1674ee..2236142 100644 --- a/PanModal.xcodeproj/project.pbxproj +++ b/PanModal.xcodeproj/project.pbxproj @@ -35,6 +35,8 @@ DC139073216D9458007A3E64 /* PanModalPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC13906A216D9458007A3E64 /* PanModalPresenter.swift */; }; DC139074216D9458007A3E64 /* PanModalPresentationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC13906C216D9458007A3E64 /* PanModalPresentationController.swift */; }; DC139075216D9458007A3E64 /* DimmedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC13906E216D9458007A3E64 /* DimmedView.swift */; }; + DC3B2EBA222A560A000C8A4A /* TransientAlertViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC3B2EB9222A560A000C8A4A /* TransientAlertViewController.swift */; }; + DC3B2EBE222A58C9000C8A4A /* AlertView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC3B2EBD222A58C9000C8A4A /* AlertView.swift */; }; DCA741AE216D90410021F2F2 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCA741AD216D90410021F2F2 /* AppDelegate.swift */; }; DCC0EE7C21917F2500208DBC /* PanModalPresentable+Defaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCC0EE7B21917F2500208DBC /* PanModalPresentable+Defaults.swift */; }; /* End PBXBuildFile section */ @@ -80,6 +82,8 @@ DC13906A216D9458007A3E64 /* PanModalPresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PanModalPresenter.swift; sourceTree = ""; }; DC13906C216D9458007A3E64 /* PanModalPresentationController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PanModalPresentationController.swift; sourceTree = ""; }; DC13906E216D9458007A3E64 /* DimmedView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DimmedView.swift; sourceTree = ""; }; + DC3B2EB9222A560A000C8A4A /* TransientAlertViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransientAlertViewController.swift; sourceTree = ""; }; + DC3B2EBD222A58C9000C8A4A /* AlertView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertView.swift; sourceTree = ""; }; DCA741AA216D90410021F2F2 /* PanModal.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PanModal.app; sourceTree = BUILT_PRODUCTS_DIR; }; DCA741AD216D90410021F2F2 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; DCA741B9216D90420021F2F2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -249,8 +253,9 @@ DC139079216D9AAA007A3E64 /* View Controllers */ = { isa = PBXGroup; children = ( - 943904EC2226366700859537 /* AlertViewController.swift */, 943904EA2226354100859537 /* BasicViewController.swift */, + DC3B2EBB222A5882000C8A4A /* Alert */, + DC3B2EBC222A5893000C8A4A /* Alert (Transient) */, 743CB2AB222661EA00665A55 /* User Groups (Stacked) */, 743CABD122265F0400634A5A /* User Groups (Navigation Controller) */, 743CABAE2225FC4A00634A5A /* User Groups */, @@ -258,6 +263,23 @@ path = "View Controllers"; sourceTree = ""; }; + DC3B2EBB222A5882000C8A4A /* Alert */ = { + isa = PBXGroup; + children = ( + 943904EC2226366700859537 /* AlertViewController.swift */, + DC3B2EBD222A58C9000C8A4A /* AlertView.swift */, + ); + path = Alert; + sourceTree = ""; + }; + DC3B2EBC222A5893000C8A4A /* Alert (Transient) */ = { + isa = PBXGroup; + children = ( + DC3B2EB9222A560A000C8A4A /* TransientAlertViewController.swift */, + ); + path = "Alert (Transient)"; + sourceTree = ""; + }; DCA741A1216D90410021F2F2 = { isa = PBXGroup; children = ( @@ -397,6 +419,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + DC3B2EBA222A560A000C8A4A /* TransientAlertViewController.swift in Sources */, 743CABB42225FE7700634A5A /* UserGroupMemberPresentable.swift in Sources */, 74C072A3220BA6E500124CE1 /* PanModalAnimator.swift in Sources */, 743CABB8222600C600634A5A /* UserGroupMemberCell.swift in Sources */, @@ -405,6 +428,7 @@ 943904EB2226354100859537 /* BasicViewController.swift in Sources */, DC139073216D9458007A3E64 /* PanModalPresenter.swift in Sources */, 943904EF2226383700859537 /* NavigationController.swift in Sources */, + DC3B2EBE222A58C9000C8A4A /* AlertView.swift in Sources */, 74C072A5220BA76D00124CE1 /* PanModalHeight.swift in Sources */, 94795C9B21F0335D008045A0 /* PanModalPresentationDelegate.swift in Sources */, 943904F32226484F00859537 /* UserGroupStackedViewController.swift in Sources */, diff --git a/PanModal/Controller/PanModalPresentationController.swift b/PanModal/Controller/PanModalPresentationController.swift index 0b20e6c..a5c3c54 100644 --- a/PanModal/Controller/PanModalPresentationController.swift +++ b/PanModal/Controller/PanModalPresentationController.swift @@ -394,6 +394,8 @@ private extension PanModalPresentationController { longFormYPosition = layoutPresentable.longFormYPos anchorModalToLongForm = layoutPresentable.anchorModalToLongForm extendsPanScrolling = layoutPresentable.allowsExtendedPanScrolling + + containerView?.isUserInteractionEnabled = layoutPresentable.isUserInteractionEnabled } /** diff --git a/PanModal/Presentable/PanModalPresentable+Defaults.swift b/PanModal/Presentable/PanModalPresentable+Defaults.swift index 0f64e42..75d22ee 100644 --- a/PanModal/Presentable/PanModalPresentable+Defaults.swift +++ b/PanModal/Presentable/PanModalPresentable+Defaults.swift @@ -65,6 +65,10 @@ public extension PanModalPresentable where Self: UIViewController { return true } + var isUserInteractionEnabled: Bool { + return true + } + var isHapticFeedbackEnabled: Bool { return true } diff --git a/PanModal/Presentable/PanModalPresentable.swift b/PanModal/Presentable/PanModalPresentable.swift index ccd81c2..5802433 100644 --- a/PanModal/Presentable/PanModalPresentable.swift +++ b/PanModal/Presentable/PanModalPresentable.swift @@ -114,6 +114,15 @@ public protocol PanModalPresentable { */ var isPanScrollEnabled: Bool { get } + /** + A flag to toggle user interactions on the container view. + + - Note: Return false to forward touches to the presentingViewController. + + Default is true. + */ + var isUserInteractionEnabled: Bool { get } + /** A flag to determine if haptic feedback should be enabled during presentation. diff --git a/Sample/SampleViewController.swift b/Sample/SampleViewController.swift index 9430b85..8d56496 100644 --- a/Sample/SampleViewController.swift +++ b/Sample/SampleViewController.swift @@ -53,20 +53,22 @@ class SampleViewController: UITableViewController { guard let rowType = RowType(rawValue: indexPath.row) else { return } + dismiss(animated: true, completion: nil) presentPanModal(rowType.presentable.rowVC) } } protocol RowPresentable { var string: String { get } - var rowVC: PanModalPresentable.LayoutType { get } + var rowVC: UIViewController & PanModalPresentable { get } } private extension SampleViewController { enum RowType: Int, CaseIterable { case basic - case transparent + case alert + case transientAlert case userGroups case stacked case navController @@ -75,7 +77,8 @@ private extension SampleViewController { var presentable: RowPresentable { switch self { case .basic: return Basic() - case .transparent: return Transparent() + case .alert: return Alert() + case .transientAlert: return TransientAlert() case .userGroups: return UserGroup() case .stacked: return Stacked() case .navController: return Navigation() @@ -87,11 +90,16 @@ private extension SampleViewController { var rowVC: PanModalPresentable.LayoutType { return BasicViewController() } } - struct Transparent: RowPresentable { + struct Alert: RowPresentable { var string: String { return "Alert" } var rowVC: PanModalPresentable.LayoutType { return AlertViewController() } } + struct TransientAlert: RowPresentable { + var string: String { return "Alert (Transient)"} + var rowVC: PanModalPresentable.LayoutType { return TransientAlertViewController() } + } + struct UserGroup: RowPresentable { var string: String { return "User Groups" } var rowVC: PanModalPresentable.LayoutType { return UserGroupViewController() } diff --git a/Sample/View Controllers/Alert (Transient)/TransientAlertViewController.swift b/Sample/View Controllers/Alert (Transient)/TransientAlertViewController.swift new file mode 100644 index 0000000..ffba0de --- /dev/null +++ b/Sample/View Controllers/Alert (Transient)/TransientAlertViewController.swift @@ -0,0 +1,69 @@ +// +// TransientAlertViewController.swift +// PanModal +// +// Created by Stephen Sowole on 3/1/19. +// Copyright © 2019 Detail. All rights reserved. +// + +import UIKit + +class TransientAlertViewController: AlertViewController { + + private weak var timer: Timer? + private var countdown: Int = 5 + + override func viewDidLoad() { + super.viewDidLoad() + alertView.titleLabel.text = "Transient Alert" + updateMessage() + } + + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + startTimer() + } + + private func startTimer() { + timer?.invalidate() + timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] _ in + self?.countdown -= 1 + self?.updateMessage() + } + } + + @objc func updateMessage() { + guard countdown > 0 else { + invalidateTimer() + dismiss(animated: true, completion: nil) + return + } + alertView.message.text = "Message disppears in \(countdown) seconds" + } + + func invalidateTimer() { + timer?.invalidate() + } + + deinit { + invalidateTimer() + } + + // MARK: - Pan Modal Presentable + + override var showDragIndicator: Bool { + return false + } + + override var anchorModalToLongForm: Bool { + return true + } + + override var backgroundAlpha: CGFloat { + return 0.0 + } + + override var isUserInteractionEnabled: Bool { + return false + } +} diff --git a/Sample/View Controllers/Alert/AlertView.swift b/Sample/View Controllers/Alert/AlertView.swift new file mode 100644 index 0000000..112b619 --- /dev/null +++ b/Sample/View Controllers/Alert/AlertView.swift @@ -0,0 +1,82 @@ +// +// AlertView.swift +// PanModal +// +// Created by Stephen Sowole on 3/1/19. +// Copyright © 2019 Detail. All rights reserved. +// + +import UIKit + +class AlertView: UIView { + + // MARK: - Views + + private let colors = [#colorLiteral(red: 0.7215686275, green: 0.9098039216, blue: 0.5607843137, alpha: 1), #colorLiteral(red: 0.7176470588, green: 0.8784313725, blue: 0.9882352941, alpha: 1), #colorLiteral(red: 0.9725490196, green: 0.937254902, blue: 0.4666666667, alpha: 1), #colorLiteral(red: 0.9490196078, green: 0.7568627451, blue: 0.9803921569, alpha: 1), #colorLiteral(red: 0.9960784314, green: 0.8823529412, blue: 0.6980392157, alpha: 1)] + + private lazy var icon: UIView = { + let icon = UIView() + icon.backgroundColor = colors.randomElement() + icon.layer.cornerRadius = 6.0 + return icon + }() + + let titleLabel: UILabel = { + let label = UILabel() + label.text = "Incoming Message" + label.font = UIFont(name: "Lato-Bold", size: 17.0) + label.textColor = #colorLiteral(red: 0.8196078431, green: 0.8235294118, blue: 0.8274509804, alpha: 1) + return label + }() + + let message: UILabel = { + let label = UILabel() + label.text = "This is an example alert..." + label.font = UIFont(name: "Lato-Regular", size: 13.0) + label.textColor = #colorLiteral(red: 0.7019607843, green: 0.7058823529, blue: 0.7137254902, alpha: 1) + return label + }() + + private lazy var alertStackView: UIStackView = { + let stackView = UIStackView(arrangedSubviews: [titleLabel, message]) + stackView.axis = .vertical + stackView.alignment = .leading + stackView.spacing = 4.0 + return stackView + }() + + init() { + super.init(frame: .zero) + setupView() + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + // MARK: - Layout + + private func setupView() { + backgroundColor = #colorLiteral(red: 0.1019607843, green: 0.1137254902, blue: 0.1294117647, alpha: 1) + layoutIcon() + layoutStackView() + } + + private func layoutIcon() { + addSubview(icon) + icon.translatesAutoresizingMaskIntoConstraints = false + icon.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 14).isActive = true + icon.topAnchor.constraint(equalTo: topAnchor, constant: 14).isActive = true + icon.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -14).isActive = true + icon.widthAnchor.constraint(equalTo: icon.heightAnchor).isActive = true + } + + private func layoutStackView() { + addSubview(alertStackView) + alertStackView.translatesAutoresizingMaskIntoConstraints = false + alertStackView.topAnchor.constraint(equalTo: icon.topAnchor).isActive = true + alertStackView.leadingAnchor.constraint(equalTo: icon.trailingAnchor, constant: 10).isActive = true + alertStackView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -14).isActive = true + alertStackView.bottomAnchor.constraint(equalTo: icon.bottomAnchor).isActive = true + } +} diff --git a/Sample/View Controllers/Alert/AlertViewController.swift b/Sample/View Controllers/Alert/AlertViewController.swift new file mode 100644 index 0000000..60715a3 --- /dev/null +++ b/Sample/View Controllers/Alert/AlertViewController.swift @@ -0,0 +1,68 @@ +// +// AlertViewController.swift +// PanModal +// +// Created by Stephen Sowole on 2/26/19. +// Copyright © 2019 PanModal. All rights reserved. +// + +import UIKit + +class AlertViewController: UIViewController, PanModalPresentable { + + private let alertViewHeight: CGFloat = 68 + + let alertView: AlertView = { + let alertView = AlertView() + alertView.layer.cornerRadius = 10 + return alertView + }() + + override func viewDidLoad() { + super.viewDidLoad() + setupView() + } + + private func setupView() { + view.addSubview(alertView) + alertView.translatesAutoresizingMaskIntoConstraints = false + alertView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true + alertView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20).isActive = true + alertView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20).isActive = true + alertView.heightAnchor.constraint(equalToConstant: alertViewHeight).isActive = true + } + + // MARK: - PanModalPresentable + + var panScrollable: UIScrollView? { + return nil + } + + var shortFormHeight: PanModalHeight { + return .contentHeight(alertViewHeight) + } + + var longFormHeight: PanModalHeight { + return shortFormHeight + } + + var backgroundAlpha: CGFloat { + return 0.1 + } + + var shouldRoundTopCorners: Bool { + return false + } + + var showDragIndicator: Bool { + return true + } + + var anchorModalToLongForm: Bool { + return false + } + + var isUserInteractionEnabled: Bool { + return true + } +} diff --git a/Sample/View Controllers/AlertViewController.swift b/Sample/View Controllers/AlertViewController.swift deleted file mode 100644 index b791099..0000000 --- a/Sample/View Controllers/AlertViewController.swift +++ /dev/null @@ -1,86 +0,0 @@ -// -// AlertViewController.swift -// PanModal -// -// Created by Stephen Sowole on 2/26/19. -// Copyright © 2019 PanModal. All rights reserved. -// - -import UIKit - -class AlertViewController: UIViewController { - - private let alertView: UIView = { - let alertView = UIView() - alertView.backgroundColor = #colorLiteral(red: 0.1019607843, green: 0.1137254902, blue: 0.1294117647, alpha: 1) - alertView.layer.cornerRadius = 20.0 - alertView.translatesAutoresizingMaskIntoConstraints = false - return alertView - }() - - override func viewDidLoad() { - super.viewDidLoad() - setupView() - } - - private func setupView() { - layoutAlertView() - layoutLabel() - } - - private func layoutAlertView() { - view.addSubview(alertView) - - alertView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true - alertView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20).isActive = true - alertView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20).isActive = true - - if #available(iOS 11.0, *) { - let constant: CGFloat = UIApplication.shared.keyWindow?.safeAreaInsets.bottom == 0 ? -20 : 0 - alertView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: constant).isActive = true - } else { - alertView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -20).isActive = true - } - } - - private func layoutLabel() { - let label = UILabel() - - label.text = "THIS IS AN EXAMPLE ALERT" - label.textColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1) - label.font = UIFont(name: "Lato-Bold", size: 16.0) - - alertView.addSubview(label) - - label.translatesAutoresizingMaskIntoConstraints = false - label.centerXAnchor.constraint(equalTo: alertView.centerXAnchor).isActive = true - label.centerYAnchor.constraint(equalTo: alertView.centerYAnchor).isActive = true - } -} - -extension AlertViewController: PanModalPresentable { - - var panScrollable: UIScrollView? { - return nil - } - - var shortFormHeight: PanModalHeight { - return .contentHeight(100) - } - - var longFormHeight: PanModalHeight { - return shortFormHeight - } - - var backgroundAlpha: CGFloat { - return 0.1 - } - - var shouldRoundTopCorners: Bool { - return false - } - - var showDragIndicator: Bool { - return true - } -}