diff --git a/MFCard/Card /Helper Class/LBZSpinner.swift b/MFCard/Card /Helper Class/LBZSpinner.swift
index 7ab151b..1cc2166 100755
--- a/MFCard/Card /Helper Class/LBZSpinner.swift
+++ b/MFCard/Card /Helper Class/LBZSpinner.swift
@@ -68,7 +68,7 @@ import UIKit
fileprivate func initCustomView() {
backgroundColor = UIColor.clear // clear black background
- NotificationCenter.default.addObserver(self, selector: #selector(LBZSpinner.orientationChanged), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil)
+ NotificationCenter.default.addObserver(self, selector: #selector(LBZSpinner.orientationChanged), name: UIDevice.orientationDidChangeNotification, object: nil)
//Open spinner click
let gesture = UITapGestureRecognizer(target: self, action: #selector(LBZSpinner.openSpinner(_:)))
@@ -150,7 +150,7 @@ import UIKit
viewChooseDisable = UIView(frame: parentView.frame) // view back click
if(dDLblurEnable) { // with blur effect
- let blurEffect = UIBlurEffect(style: UIBlurEffectStyle.dark)
+ let blurEffect = UIBlurEffect(style: UIBlurEffect.Style.dark)
blurEffectView = UIVisualEffectView(effect: blurEffect)
blurEffectView.effect = nil
blurEffectView.backgroundColor = UIColor.black.withAlphaComponent(0)
@@ -192,7 +192,7 @@ import UIKit
UIView.animate(withDuration: 0.3,
delay: 0.0,
- options: UIViewAnimationOptions.transitionFlipFromBottom,
+ options: UIView.AnimationOptions.transitionFlipFromBottom,
animations: {
self.tableviewChoose.frame.size.height = self.heightTableview
self.tableviewChooseShadow.frame.size.height = self.heightTableview
@@ -214,7 +214,7 @@ import UIKit
UIView.animate(withDuration: 0.3,
delay: 0.0,
- options: UIViewAnimationOptions.transitionFlipFromBottom,
+ options: UIView.AnimationOptions.transitionFlipFromBottom,
animations: {
self.tableviewChoose.frame.origin.y = globalPoint.y-self.heightTableview+self.frame.height
self.tableviewChoose.frame.size.height = self.heightTableview
@@ -240,7 +240,7 @@ import UIKit
tableviewChoose.isUserInteractionEnabled = true
tableviewChoose.showsHorizontalScrollIndicator = false
tableviewChoose.showsVerticalScrollIndicator = false
- tableviewChoose.separatorStyle = UITableViewCellSeparatorStyle.none
+ tableviewChoose.separatorStyle = UITableViewCell.SeparatorStyle.none
tableviewChoose.layer.cornerRadius = 5
//Show stroke
@@ -277,7 +277,7 @@ import UIKit
if(tableviewChoose != nil) {
UIView.animate(withDuration: 0.3,
delay: 0.0,
- options: UIViewAnimationOptions.transitionFlipFromBottom,
+ options: UIView.AnimationOptions.transitionFlipFromBottom,
animations: {
self.tableviewChoose.alpha = 0.0
self.tableviewChooseShadow.alpha = 0.0
diff --git a/MFCard/Card /MFCardView.swift b/MFCard/Card /MFCardView.swift
index bfd1b17..49ccd7e 100644
--- a/MFCard/Card /MFCardView.swift
+++ b/MFCard/Card /MFCardView.swift
@@ -78,9 +78,9 @@ extension MFCardDelegate{
public var toast = true
public var topDistance = 100
- public var blurStyle:UIBlurEffect = UIBlurEffect(style: UIBlurEffectStyle.dark)
+ public var blurStyle:UIBlurEffect = UIBlurEffect(style: UIBlurEffect.Style.dark)
- public var cardTypeAnimation :UIViewAnimationOptions = [.transitionFlipFromBottom, .curveLinear]
+ public var cardTypeAnimation :UIView.AnimationOptions = [.transitionFlipFromBottom, .curveLinear]
//MARK:
//MARK: initialization
public init(withViewController:UIViewController) {
@@ -116,7 +116,7 @@ extension MFCardDelegate{
self.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[view]|", options: [], metrics: nil, views: ["view": self.view]))
self.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[view]|", options: [], metrics: nil, views: ["view": self.view]))
//Orientation Observer
- NotificationCenter.default.addObserver(self, selector: #selector(self.orientationDidChange), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil)
+ NotificationCenter.default.addObserver(self, selector: #selector(self.orientationDidChange), name: UIDevice.orientationDidChangeNotification, object: nil)
self.layoutIfNeeded()
self.updateConstraintsIfNeeded()
@@ -153,11 +153,11 @@ extension MFCardDelegate{
txtCardNoP4.delegate = self
txtCvc.delegate = self
- txtCardNoP1.addTarget(self, action: #selector(MFCardView.textFieldDidChange(_:)), for: UIControlEvents.editingChanged)
- txtCardNoP2.addTarget(self, action: #selector(MFCardView.textFieldDidChange(_:)), for: UIControlEvents.editingChanged)
- txtCardNoP3.addTarget(self, action: #selector(MFCardView.textFieldDidChange(_:)), for: UIControlEvents.editingChanged)
- txtCardNoP4.addTarget(self, action: #selector(MFCardView.textFieldDidChange(_:)), for: UIControlEvents.editingChanged)
- txtCvc.addTarget(self, action: #selector(MFCardView.textFieldDidChange(_:)), for: UIControlEvents.editingChanged)
+ txtCardNoP1.addTarget(self, action: #selector(MFCardView.textFieldDidChange(_:)), for: UIControl.Event.editingChanged)
+ txtCardNoP2.addTarget(self, action: #selector(MFCardView.textFieldDidChange(_:)), for: UIControl.Event.editingChanged)
+ txtCardNoP3.addTarget(self, action: #selector(MFCardView.textFieldDidChange(_:)), for: UIControl.Event.editingChanged)
+ txtCardNoP4.addTarget(self, action: #selector(MFCardView.textFieldDidChange(_:)), for: UIControl.Event.editingChanged)
+ txtCvc.addTarget(self, action: #selector(MFCardView.textFieldDidChange(_:)), for: UIControl.Event.editingChanged)
let leftSwipe = UISwipeGestureRecognizer(target: self, action: #selector(self.flip))
let rightSwipe = UISwipeGestureRecognizer(target: self, action: #selector(self.flip))
@@ -193,17 +193,17 @@ extension MFCardDelegate{
rootViewController.view.addSubview(view)
// center view horizontally in rootViewController.view
- rootViewController.view.addConstraint(NSLayoutConstraint(item: view, attribute: NSLayoutAttribute.centerX, relatedBy: NSLayoutRelation.equal, toItem: rootViewController.view, attribute: NSLayoutAttribute.centerX, multiplier: 1.0, constant: 0.0));
+ rootViewController.view.addConstraint(NSLayoutConstraint(item: view, attribute: NSLayoutConstraint.Attribute.centerX, relatedBy: NSLayoutConstraint.Relation.equal, toItem: rootViewController.view, attribute: NSLayoutConstraint.Attribute.centerX, multiplier: 1.0, constant: 0.0));
// align view from the top
- topConstraints = NSLayoutConstraint.constraints(withVisualFormat: "V:|-\(topDistance)-[view]", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: ["view": view])
+ topConstraints = NSLayoutConstraint.constraints(withVisualFormat: "V:|-\(topDistance)-[view]", options: NSLayoutConstraint.FormatOptions(rawValue: 0), metrics: nil, views: ["view": view])
rootViewController.view.addConstraints(topConstraints!);
// width constraint
- rootViewController.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:[view(==300)]", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: ["view": view]));
+ rootViewController.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:[view(==300)]", options: NSLayoutConstraint.FormatOptions(rawValue: 0), metrics: nil, views: ["view": view]));
// height constraint
- rootViewController.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:[view(==240)]", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: ["view": view]));
+ rootViewController.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:[view(==240)]", options: NSLayoutConstraint.FormatOptions(rawValue: 0), metrics: nil, views: ["view": view]));
animateCard()
// Animate it in
@@ -391,14 +391,14 @@ extension MFCardDelegate{
}
@objc fileprivate func orientationDidChange(){
- if UIDeviceOrientationIsLandscape(UIDevice.current.orientation) {
+ if UIDevice.current.orientation.isLandscape {
if (topConstraints != nil){
topConstraints?[0].constant = 10
}
}
- if UIDeviceOrientationIsPortrait(UIDevice.current.orientation) {
+ if UIDevice.current.orientation.isPortrait {
if (topConstraints != nil){
topConstraints?[0].constant = CGFloat(topDistance)
}
@@ -484,8 +484,8 @@ extension MFCardDelegate{
}
if (cardFrontView.isHidden == false) {
- let transitionOptions: UIViewAnimationOptions = [.transitionFlipFromRight, .showHideTransitionViews]
- btnCvc.setTitle("CARD", for: UIControlState())
+ let transitionOptions: UIView.AnimationOptions = [.transitionFlipFromRight, .showHideTransitionViews]
+ btnCvc.setTitle("CARD", for: UIControl.State())
UIView.transition(with: cardFrontView, duration: 1.0, options: transitionOptions, animations: {
self.cardFrontView.isHidden = true
}, completion: nil)
@@ -496,8 +496,8 @@ extension MFCardDelegate{
}, completion: nil)
}
else {
- let transitionOptions: UIViewAnimationOptions = [.transitionFlipFromLeft, .showHideTransitionViews]
- btnCvc.setTitle("CVC", for: UIControlState())
+ let transitionOptions: UIView.AnimationOptions = [.transitionFlipFromLeft, .showHideTransitionViews]
+ btnCvc.setTitle("CVC", for: UIControl.State())
UIView.transition(with: cardBackView, duration: 1.0, options: transitionOptions, animations: {
self.cardBackView.isHidden = true
}, completion: nil)
diff --git a/MFCard/Card /Toast/Toast.swift b/MFCard/Card /Toast/Toast.swift
index d548a0f..471d09e 100755
--- a/MFCard/Card /Toast/Toast.swift
+++ b/MFCard/Card /Toast/Toast.swift
@@ -2,7 +2,7 @@
// Toast.swift
// Toast-Swift
//
-// Copyright (c) 2015 Charles Scalesse.
+// Copyright (c) 2015-2019 Charles Scalesse.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
@@ -22,19 +22,12 @@
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
import UIKit
import ObjectiveC
-public enum ToastPosition {
- case top
- case center
- case bottom
-}
-
/**
Toast is a Swift extension that adds toast notifications to the `UIView` object class.
- It is intended to be simple, lightweight, and easy to use. Most toast notifications
+ It is intended to be simple, lightweight, and easy to use. Most toast notifications
can be triggered with a single line of code.
The `makeToast` methods create a new view and then display it as toast.
@@ -48,13 +41,13 @@ public extension UIView {
Keys used for associated objects.
*/
private struct ToastKeys {
- static var Timer = "CSToastTimerKey"
- static var Duration = "CSToastDurationKey"
- static var Position = "CSToastPositionKey"
- static var Completion = "CSToastCompletionKey"
- static var ActiveToast = "CSToastActiveToastKey"
- static var ActivityView = "CSToastActivityViewKey"
- static var Queue = "CSToastQueueKey"
+ static var timer = "com.toast-swift.timer"
+ static var duration = "com.toast-swift.duration"
+ static var point = "com.toast-swift.point"
+ static var completion = "com.toast-swift.completion"
+ static var activeToasts = "com.toast-swift.activeToasts"
+ static var activityView = "com.toast-swift.activityView"
+ static var queue = "com.toast-swift.queue"
}
/**
@@ -63,7 +56,7 @@ public extension UIView {
class that can be used with associated objects.
*/
private class ToastCompletionWrapper {
- var completion: ((Bool) -> Void)?
+ let completion: ((Bool) -> Void)?
init(_ completion: ((Bool) -> Void)?) {
self.completion = completion
@@ -71,16 +64,28 @@ public extension UIView {
}
private enum ToastError: Error {
- case insufficientData
+ case missingParameters
+ }
+
+ private var activeToasts: NSMutableArray {
+ get {
+ if let activeToasts = objc_getAssociatedObject(self, &ToastKeys.activeToasts) as? NSMutableArray {
+ return activeToasts
+ } else {
+ let activeToasts = NSMutableArray()
+ objc_setAssociatedObject(self, &ToastKeys.activeToasts, activeToasts, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
+ return activeToasts
+ }
+ }
}
private var queue: NSMutableArray {
get {
- if let queue = objc_getAssociatedObject(self, &ToastKeys.Queue) as? NSMutableArray {
+ if let queue = objc_getAssociatedObject(self, &ToastKeys.queue) as? NSMutableArray {
return queue
} else {
let queue = NSMutableArray()
- objc_setAssociatedObject(self, &ToastKeys.Queue, queue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
+ objc_setAssociatedObject(self, &ToastKeys.queue, queue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
return queue
}
}
@@ -89,70 +94,7 @@ public extension UIView {
// MARK: - Make Toast Methods
/**
- Creates and presents a new toast view with a message and displays it with the
- default duration and position. Styled using the shared style.
-
- @param message The message to be displayed
- */
- public func makeToast(_ message: String) {
- self.makeToast(message, duration: ToastManager.shared.duration, position: ToastManager.shared.position)
- }
-
- /**
- Creates and presents a new toast view with a message. Duration and position
- can be set explicitly. Styled using the shared style.
-
- @param message The message to be displayed
- @param duration The toast duration
- @param position The toast's position
- */
- public func makeToast(_ message: String, duration: TimeInterval, position: ToastPosition) {
- self.makeToast(message, duration: duration, position: position, style: nil)
- }
-
- /**
- Creates and presents a new toast view with a message. Duration and position
- can be set explicitly. Styled using the shared style.
-
- @param message The message to be displayed
- @param duration The toast duration
- @param position The toast's center point
- */
- public func makeToast(_ message: String, duration: TimeInterval, position: CGPoint) {
- self.makeToast(message, duration: duration, position: position, style: nil)
- }
-
- /**
- Creates and presents a new toast view with a message. Duration, position, and
- style can be set explicitly.
-
- @param message The message to be displayed
- @param duration The toast duration
- @param position The toast's position
- @param style The style. The shared style will be used when nil
- */
- public func makeToast(_ message: String, duration: TimeInterval, position: ToastPosition, style: ToastStyle?) {
- self.makeToast(message, duration: duration, position: position, title: nil, image: nil, style: style, completion: nil)
- }
-
- /**
- Creates and presents a new toast view with a message. Duration, position, and
- style can be set explicitly.
-
- @param message The message to be displayed
- @param duration The toast duration
- @param position The toast's center point
- @param style The style. The shared style will be used when nil
- */
- public func makeToast(_ message: String, duration: TimeInterval, position: CGPoint, style: ToastStyle?) {
- self.makeToast(message, duration: duration, position: position, title: nil, image: nil, style: style, completion: nil)
- }
-
- /**
- Creates and presents a new toast view with a message, title, and image. Duration,
- position, and style can be set explicitly. The completion closure executes when the
- toast completes presentation. `didTap` will be `true` if the toast view was dismissed
- from a tap.
+ Creates and presents a new toast view.
@param message The message to be displayed
@param duration The toast duration
@@ -163,60 +105,38 @@ public extension UIView {
@param completion The completion closure, executed after the toast view disappears.
didTap will be `true` if the toast view was dismissed from a tap.
*/
- public func makeToast(_ message: String?, duration: TimeInterval, position: ToastPosition, title: String?, image: UIImage?, style: ToastStyle?, completion: ((_ didTap: Bool) -> Void)?) {
- var toastStyle = ToastManager.shared.style
- if let style = style {
- toastStyle = style
- }
-
+ func makeToast(_ message: String?, duration: TimeInterval = ToastManager.shared.duration, position: ToastPosition = ToastManager.shared.position, title: String? = nil, image: UIImage? = nil, style: ToastStyle = ToastManager.shared.style, completion: ((_ didTap: Bool) -> Void)? = nil) {
do {
- let toast = try self.toastViewForMessage(message, title: title, image: image, style: toastStyle)
- self.showToast(toast, duration: duration, position: position, completion: completion)
- } catch ToastError.insufficientData {
+ let toast = try toastViewForMessage(message, title: title, image: image, style: style)
+ showToast(toast, duration: duration, position: position, completion: completion)
+ } catch ToastError.missingParameters {
print("Error: message, title, and image are all nil")
} catch {}
}
/**
- Creates and presents a new toast view with a message, title, and image. Duration,
- position, and style can be set explicitly. The completion closure executes when the
- toast completes presentation. `didTap` will be `true` if the toast view was dismissed
- from a tap.
+ Creates a new toast view and presents it at a given center point.
@param message The message to be displayed
@param duration The toast duration
- @param position The toast's center point
+ @param point The toast's center point
@param title The title
@param image The image
@param style The style. The shared style will be used when nil
@param completion The completion closure, executed after the toast view disappears.
didTap will be `true` if the toast view was dismissed from a tap.
*/
- public func makeToast(_ message: String?, duration: TimeInterval, position: CGPoint, title: String?, image: UIImage?, style: ToastStyle?, completion: ((_ didTap: Bool) -> Void)?) {
- var toastStyle = ToastManager.shared.style
- if let style = style {
- toastStyle = style
- }
-
+ func makeToast(_ message: String?, duration: TimeInterval = ToastManager.shared.duration, point: CGPoint, title: String?, image: UIImage?, style: ToastStyle = ToastManager.shared.style, completion: ((_ didTap: Bool) -> Void)?) {
do {
- let toast = try self.toastViewForMessage(message, title: title, image: image, style: toastStyle)
- self.showToast(toast, duration: duration, position: position, completion: completion)
- } catch ToastError.insufficientData {
+ let toast = try toastViewForMessage(message, title: title, image: image, style: style)
+ showToast(toast, duration: duration, point: point, completion: completion)
+ } catch ToastError.missingParameters {
print("Error: message, title, and image cannot all be nil")
} catch {}
}
// MARK: - Show Toast Methods
- /**
- Displays any view as toast using the default duration and position.
-
- @param toast The view to be displayed as toast
- */
- public func showToast(_ toast: UIView) {
- self.showToast(toast, duration: ToastManager.shared.duration, position: ToastManager.shared.position, completion: nil)
- }
-
/**
Displays any view as toast at a provided position and duration. The completion closure
executes when the toast view completes. `didTap` will be `true` if the toast view was
@@ -228,35 +148,93 @@ public extension UIView {
@param completion The completion block, executed after the toast view disappears.
didTap will be `true` if the toast view was dismissed from a tap.
*/
- public func showToast(_ toast: UIView, duration: TimeInterval, position: ToastPosition, completion: ((_ didTap: Bool) -> Void)?) {
- let point = self.centerPointForPosition(position, toast: toast)
- self.showToast(toast, duration: duration, position: point, completion: completion)
+ func showToast(_ toast: UIView, duration: TimeInterval = ToastManager.shared.duration, position: ToastPosition = ToastManager.shared.position, completion: ((_ didTap: Bool) -> Void)? = nil) {
+ let point = position.centerPoint(forToast: toast, inSuperview: self)
+ showToast(toast, duration: duration, point: point, completion: completion)
}
/**
- Displays any view as toast at a provided position and duration. The completion closure
+ Displays any view as toast at a provided center point and duration. The completion closure
executes when the toast view completes. `didTap` will be `true` if the toast view was
dismissed from a tap.
@param toast The view to be displayed as toast
@param duration The notification duration
- @param position The toast's center point
+ @param point The toast's center point
@param completion The completion block, executed after the toast view disappears.
didTap will be `true` if the toast view was dismissed from a tap.
*/
- public func showToast(_ toast: UIView, duration: TimeInterval, position: CGPoint, completion: ((_ didTap: Bool) -> Void)?) {
- objc_setAssociatedObject(toast, &ToastKeys.Completion, ToastCompletionWrapper(completion), .OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+ func showToast(_ toast: UIView, duration: TimeInterval = ToastManager.shared.duration, point: CGPoint, completion: ((_ didTap: Bool) -> Void)? = nil) {
+ objc_setAssociatedObject(toast, &ToastKeys.completion, ToastCompletionWrapper(completion), .OBJC_ASSOCIATION_RETAIN_NONATOMIC);
- if let _ = objc_getAssociatedObject(self, &ToastKeys.ActiveToast) as? UIView, ToastManager.shared.queueEnabled {
- objc_setAssociatedObject(toast, &ToastKeys.Duration, NSNumber(value: duration), .OBJC_ASSOCIATION_RETAIN_NONATOMIC);
- objc_setAssociatedObject(toast, &ToastKeys.Position, NSValue(cgPoint: position), .OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+ if ToastManager.shared.isQueueEnabled, activeToasts.count > 0 {
+ objc_setAssociatedObject(toast, &ToastKeys.duration, NSNumber(value: duration), .OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+ objc_setAssociatedObject(toast, &ToastKeys.point, NSValue(cgPoint: point), .OBJC_ASSOCIATION_RETAIN_NONATOMIC);
- self.queue.add(toast)
+ queue.add(toast)
} else {
- self.showToast(toast, duration: duration, position: position)
+ showToast(toast, duration: duration, point: point)
+ }
+ }
+
+ // MARK: - Hide Toast Methods
+
+ /**
+ Hides the active toast. If there are multiple toasts active in a view, this method
+ hides the oldest toast (the first of the toasts to have been presented).
+
+ @see `hideAllToasts()` to remove all active toasts from a view.
+
+ @warning This method has no effect on activity toasts. Use `hideToastActivity` to
+ hide activity toasts.
+
+ */
+ func hideToast() {
+ guard let activeToast = activeToasts.firstObject as? UIView else { return }
+ hideToast(activeToast)
+ }
+
+ /**
+ Hides an active toast.
+
+ @param toast The active toast view to dismiss. Any toast that is currently being displayed
+ on the screen is considered active.
+
+ @warning this does not clear a toast view that is currently waiting in the queue.
+ */
+ func hideToast(_ toast: UIView) {
+ guard activeToasts.contains(toast) else { return }
+ hideToast(toast, fromTap: false)
+ }
+
+ /**
+ Hides all toast views.
+
+ @param includeActivity If `true`, toast activity will also be hidden. Default is `false`.
+ @param clearQueue If `true`, removes all toast views from the queue. Default is `true`.
+ */
+ func hideAllToasts(includeActivity: Bool = false, clearQueue: Bool = true) {
+ if clearQueue {
+ clearToastQueue()
+ }
+
+ activeToasts.compactMap { $0 as? UIView }
+ .forEach { hideToast($0) }
+
+ if includeActivity {
+ hideToastActivity()
}
}
+ /**
+ Removes all toast views from the queue. This has no effect on toast views that are
+ active. Use `hideAllToasts(clearQueue:)` to hide the active toasts views and clear
+ the queue.
+ */
+ func clearToastQueue() {
+ queue.removeAllObjects()
+ }
+
// MARK: - Activity Methods
/**
@@ -271,15 +249,13 @@ public extension UIView {
@param position The toast's position
*/
- public func makeToastActivity(_ position: ToastPosition) {
+ func makeToastActivity(_ position: ToastPosition) {
// sanity
- if let _ = objc_getAssociatedObject(self, &ToastKeys.ActivityView) as? UIView {
- return
- }
+ guard objc_getAssociatedObject(self, &ToastKeys.activityView) as? UIView == nil else { return }
- let toast = self.createToastActivityView()
- let point = self.centerPointForPosition(position, toast: toast)
- self.makeToastActivity(toast, position: point)
+ let toast = createToastActivityView()
+ let point = position.centerPoint(forToast: toast, inSuperview: self)
+ makeToastActivity(toast, point: point)
}
/**
@@ -292,52 +268,50 @@ public extension UIView {
activity views can be presented and dismissed while toast views are being displayed.
`makeToastActivity(position:)` has no effect on the queueing behavior of the `showToast` methods.
- @param position The toast's center point
+ @param point The toast's center point
*/
- public func makeToastActivity(_ position: CGPoint) {
+ func makeToastActivity(_ point: CGPoint) {
// sanity
- if let _ = objc_getAssociatedObject(self, &ToastKeys.ActivityView) as? UIView {
- return
- }
+ guard objc_getAssociatedObject(self, &ToastKeys.activityView) as? UIView == nil else { return }
- let toast = self.createToastActivityView()
- self.makeToastActivity(toast, position: position)
+ let toast = createToastActivityView()
+ makeToastActivity(toast, point: point)
}
/**
Dismisses the active toast activity indicator view.
*/
- public func hideToastActivity() {
- if let toast = objc_getAssociatedObject(self, &ToastKeys.ActivityView) as? UIView {
- UIView.animate(withDuration: ToastManager.shared.style.fadeDuration, delay: 0.0, options: [.curveEaseIn, .beginFromCurrentState], animations: { () -> Void in
+ func hideToastActivity() {
+ if let toast = objc_getAssociatedObject(self, &ToastKeys.activityView) as? UIView {
+ UIView.animate(withDuration: ToastManager.shared.style.fadeDuration, delay: 0.0, options: [.curveEaseIn, .beginFromCurrentState], animations: {
toast.alpha = 0.0
- }, completion: { (finished: Bool) -> Void in
+ }) { _ in
toast.removeFromSuperview()
- objc_setAssociatedObject(self, &ToastKeys.ActivityView, nil, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
- })
+ objc_setAssociatedObject(self, &ToastKeys.activityView, nil, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
+ }
}
}
// MARK: - Private Activity Methods
- private func makeToastActivity(_ toast: UIView, position: CGPoint) {
+ private func makeToastActivity(_ toast: UIView, point: CGPoint) {
toast.alpha = 0.0
- toast.center = position
+ toast.center = point
- objc_setAssociatedObject(self, &ToastKeys.ActivityView, toast, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
+ objc_setAssociatedObject(self, &ToastKeys.activityView, toast, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
self.addSubview(toast)
- UIView.animate(withDuration: ToastManager.shared.style.fadeDuration, delay: 0.0, options: .curveEaseOut, animations: { () -> Void in
+ UIView.animate(withDuration: ToastManager.shared.style.fadeDuration, delay: 0.0, options: .curveEaseOut, animations: {
toast.alpha = 1.0
- }, completion: nil)
+ })
}
private func createToastActivityView() -> UIView {
let style = ToastManager.shared.style
let activityView = UIView(frame: CGRect(x: 0.0, y: 0.0, width: style.activitySize.width, height: style.activitySize.height))
- activityView.backgroundColor = style.backgroundColor
+ activityView.backgroundColor = style.activityBackgroundColor
activityView.autoresizingMask = [.flexibleLeftMargin, .flexibleRightMargin, .flexibleTopMargin, .flexibleBottomMargin]
activityView.layer.cornerRadius = style.cornerRadius
@@ -348,9 +322,10 @@ public extension UIView {
activityView.layer.shadowOffset = style.shadowOffset
}
- let activityIndicatorView = UIActivityIndicatorView(activityIndicatorStyle: .whiteLarge)
+ let activityIndicatorView = UIActivityIndicatorView(style: .whiteLarge)
activityIndicatorView.center = CGPoint(x: activityView.bounds.size.width / 2.0, y: activityView.bounds.size.height / 2.0)
activityView.addSubview(activityIndicatorView)
+ activityIndicatorView.color = style.activityIndicatorColor
activityIndicatorView.startAnimating()
return activityView
@@ -358,67 +333,63 @@ public extension UIView {
// MARK: - Private Show/Hide Methods
- private func showToast(_ toast: UIView, duration: TimeInterval, position: CGPoint) {
- toast.center = position
+ private func showToast(_ toast: UIView, duration: TimeInterval, point: CGPoint) {
+ toast.center = point
toast.alpha = 0.0
- if ToastManager.shared.tapToDismissEnabled {
+ if ToastManager.shared.isTapToDismissEnabled {
let recognizer = UITapGestureRecognizer(target: self, action: #selector(UIView.handleToastTapped(_:)))
toast.addGestureRecognizer(recognizer)
toast.isUserInteractionEnabled = true
toast.isExclusiveTouch = true
}
- objc_setAssociatedObject(self, &ToastKeys.ActiveToast, toast, .OBJC_ASSOCIATION_RETAIN_NONATOMIC);
-
+ activeToasts.add(toast)
self.addSubview(toast)
- UIView.animate(withDuration: ToastManager.shared.style.fadeDuration, delay: 0.0, options: [.curveEaseOut, .allowUserInteraction], animations: { () -> Void in
+ UIView.animate(withDuration: ToastManager.shared.style.fadeDuration, delay: 0.0, options: [.curveEaseOut, .allowUserInteraction], animations: {
toast.alpha = 1.0
- }) { (finished) -> Void in
+ }) { _ in
let timer = Timer(timeInterval: duration, target: self, selector: #selector(UIView.toastTimerDidFinish(_:)), userInfo: toast, repeats: false)
- RunLoop.main.add(timer, forMode: RunLoopMode.commonModes)
- objc_setAssociatedObject(toast, &ToastKeys.Timer, timer, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
+ RunLoop.main.add(timer, forMode: .common)
+ objc_setAssociatedObject(toast, &ToastKeys.timer, timer, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
- private func hideToast(_ toast: UIView) {
- self.hideToast(toast, fromTap: false)
- }
-
private func hideToast(_ toast: UIView, fromTap: Bool) {
+ if let timer = objc_getAssociatedObject(toast, &ToastKeys.timer) as? Timer {
+ timer.invalidate()
+ }
- UIView.animate(withDuration: ToastManager.shared.style.fadeDuration, delay: 0.0, options: [.curveEaseIn, .beginFromCurrentState], animations: { () -> Void in
+ UIView.animate(withDuration: ToastManager.shared.style.fadeDuration, delay: 0.0, options: [.curveEaseIn, .beginFromCurrentState], animations: {
toast.alpha = 0.0
- }) { (didFinish: Bool) -> Void in
+ }) { _ in
toast.removeFromSuperview()
+ self.activeToasts.remove(toast)
- objc_setAssociatedObject(self, &ToastKeys.ActiveToast, nil, .OBJC_ASSOCIATION_RETAIN_NONATOMIC);
-
- if let wrapper = objc_getAssociatedObject(toast, &ToastKeys.Completion) as? ToastCompletionWrapper, let completion = wrapper.completion {
+ if let wrapper = objc_getAssociatedObject(toast, &ToastKeys.completion) as? ToastCompletionWrapper, let completion = wrapper.completion {
completion(fromTap)
}
- if let nextToast = self.queue.firstObject as? UIView, let duration = objc_getAssociatedObject(nextToast, &ToastKeys.Duration) as? NSNumber, let position = objc_getAssociatedObject(nextToast, &ToastKeys.Position) as? NSValue {
+ if let nextToast = self.queue.firstObject as? UIView, let duration = objc_getAssociatedObject(nextToast, &ToastKeys.duration) as? NSNumber, let point = objc_getAssociatedObject(nextToast, &ToastKeys.point) as? NSValue {
self.queue.removeObject(at: 0)
- self.showToast(nextToast, duration: duration.doubleValue, position: position.cgPointValue)
+ self.showToast(nextToast, duration: duration.doubleValue, point: point.cgPointValue)
}
}
}
// MARK: - Events
- @objc func handleToastTapped(_ recognizer: UITapGestureRecognizer) {
- if let toast = recognizer.view, let timer = objc_getAssociatedObject(toast, &ToastKeys.Timer) as? Timer {
- timer.invalidate()
- self.hideToast(toast, fromTap: true)
- }
+ @objc
+ private func handleToastTapped(_ recognizer: UITapGestureRecognizer) {
+ guard let toast = recognizer.view else { return }
+ hideToast(toast, fromTap: true)
}
- @objc func toastTimerDidFinish(_ timer: Timer) {
- if let toast = timer.userInfo as? UIView {
- self.hideToast(toast)
- }
+ @objc
+ private func toastTimerDidFinish(_ timer: Timer) {
+ guard let toast = timer.userInfo as? UIView else { return }
+ hideToast(toast)
}
// MARK: - Toast Construction
@@ -430,19 +401,19 @@ public extension UIView {
methods must be used to present the resulting view.
@warning if message, title, and image are all nil, this method will throw
- `ToastError.InsufficientData`
+ `ToastError.missingParameters`
@param message The message to be displayed
@param title The title
@param image The image
@param style The style. The shared style will be used when nil
- @throws `ToastError.InsufficientData` when message, title, and image are all nil
+ @throws `ToastError.missingParameters` when message, title, and image are all nil
@return The newly created toast view
*/
- public func toastViewForMessage(_ message: String?, title: String?, image: UIImage?, style: ToastStyle) throws -> UIView {
+ func toastViewForMessage(_ message: String?, title: String?, image: UIImage?, style: ToastStyle) throws -> UIView {
// sanity
- if message == nil && title == nil && image == nil {
- throw ToastError.insufficientData
+ guard message != nil || title != nil || image != nil else {
+ throw ToastError.missingParameters
}
var messageLabel: UILabel?
@@ -538,11 +509,13 @@ public extension UIView {
wrapperView.frame = CGRect(x: 0.0, y: 0.0, width: wrapperWidth, height: wrapperHeight)
if let titleLabel = titleLabel {
+ titleRect.size.width = longerWidth
titleLabel.frame = titleRect
wrapperView.addSubview(titleLabel)
}
if let messageLabel = messageLabel {
+ messageRect.size.width = longerWidth
messageLabel.frame = messageRect
wrapperView.addSubview(messageLabel)
}
@@ -554,29 +527,13 @@ public extension UIView {
return wrapperView
}
- // MARK: - Helpers
-
- private func centerPointForPosition(_ position: ToastPosition, toast: UIView) -> CGPoint {
- let padding: CGFloat = ToastManager.shared.style.verticalPadding
-
- switch(position) {
- case .top:
- return CGPoint(x: self.bounds.size.width / 2.0, y: (toast.frame.size.height / 2.0) + padding)
- case .center:
- return CGPoint(x: self.bounds.size.width / 2.0, y: self.bounds.size.height / 2.0)
- case .bottom:
- return CGPoint(x: self.bounds.size.width / 2.0, y: (self.bounds.size.height - (toast.frame.size.height / 2.0)) - padding)
- }
- }
}
// MARK: - Toast Style
-
/**
`ToastStyle` instances define the look and feel for toast views created via the
`makeToast` methods as well for toast views created directly with
`toastViewForMessage(message:title:image:style:)`.
-
@warning `ToastStyle` offers relatively simple styling options for the default
toast view. If you require a toast view with more complex UI, it probably makes more
sense to create your own custom UIView subclass and present it with the `showToast`
@@ -587,19 +544,19 @@ public struct ToastStyle {
public init() {}
/**
- The background color. Default is `UIColor.blackColor()` at 80% opacity.
+ The background color. Default is `.black` at 80% opacity.
*/
- public var backgroundColor = UIColor.black.withAlphaComponent(0.8)
+ public var backgroundColor: UIColor = UIColor.black.withAlphaComponent(0.8)
/**
The title color. Default is `UIColor.whiteColor()`.
*/
- public var titleColor = UIColor.white
+ public var titleColor: UIColor = .white
/**
- The message color. Default is `UIColor.whiteColor()`.
+ The message color. Default is `.white`.
*/
- public var messageColor = UIColor.white
+ public var messageColor: UIColor = .white
/**
A percentage value from 0.0 to 1.0, representing the maximum width of the toast
@@ -625,13 +582,15 @@ public struct ToastStyle {
The spacing from the horizontal edge of the toast view to the content. When an image
is present, this is also used as the padding between the image and the text.
Default is 10.0.
+
*/
public var horizontalPadding: CGFloat = 10.0
/**
The spacing from the vertical edge of the toast view to the content. When a title
is present, this is also used as the padding between the title and the message.
- Default is 10.0.
+ Default is 10.0. On iOS11+, this value is added added to the `safeAreaInset.top`
+ and `safeAreaInsets.bottom`.
*/
public var verticalPadding: CGFloat = 10.0
@@ -641,24 +600,24 @@ public struct ToastStyle {
public var cornerRadius: CGFloat = 10.0;
/**
- The title font. Default is `UIFont.boldSystemFontOfSize(16.0)`.
+ The title font. Default is `.boldSystemFont(16.0)`.
*/
- public var titleFont = UIFont.boldSystemFont(ofSize: 16.0)
+ public var titleFont: UIFont = .boldSystemFont(ofSize: 16.0)
/**
- The message font. Default is `UIFont.systemFontOfSize(16.0)`.
+ The message font. Default is `.systemFont(ofSize: 16.0)`.
*/
- public var messageFont = UIFont.systemFont(ofSize: 16.0)
+ public var messageFont: UIFont = .systemFont(ofSize: 16.0)
/**
The title text alignment. Default is `NSTextAlignment.Left`.
*/
- public var titleAlignment = NSTextAlignment.center
+ public var titleAlignment: NSTextAlignment = .left
/**
The message text alignment. Default is `NSTextAlignment.Left`.
*/
- public var messageAlignment = NSTextAlignment.left
+ public var messageAlignment: NSTextAlignment = .left
/**
The maximum number of lines for the title. The default is 0 (no limit).
@@ -676,9 +635,9 @@ public struct ToastStyle {
public var displayShadow = false
/**
- The shadow color. Default is `UIColor.blackColor()`.
+ The shadow color. Default is `.black`.
*/
- public var shadowColor = UIColor.black
+ public var shadowColor: UIColor = .black
/**
A value from 0.0 to 1.0, representing the opacity of the shadow.
@@ -716,10 +675,19 @@ public struct ToastStyle {
*/
public var fadeDuration: TimeInterval = 0.2
+ /**
+ Activity indicator color. Default is `.white`.
+ */
+ public var activityIndicatorColor: UIColor = .white
+
+ /**
+ Activity background color. Default is `.black` at 80% opacity.
+ */
+ public var activityBackgroundColor: UIColor = UIColor.black.withAlphaComponent(0.8)
+
}
// MARK: - Toast Manager
-
/**
`ToastManager` provides general configuration options for all toast
notifications. Backed by a singleton instance.
@@ -728,33 +696,38 @@ public class ToastManager {
/**
The `ToastManager` singleton instance.
+
*/
public static let shared = ToastManager()
/**
The shared style. Used whenever toastViewForMessage(message:title:image:style:) is called
with with a nil style.
+
*/
public var style = ToastStyle()
/**
Enables or disables tap to dismiss on toast views. Default is `true`.
+
*/
- public var tapToDismissEnabled = true
+ public var isTapToDismissEnabled = true
/**
Enables or disables queueing behavior for toast views. When `true`,
toast views will appear one after the other. When `false`, multiple toast
views will appear at the same time (potentially overlapping depending
on their positions). This has no effect on the toast activity view,
- which operates independently of normal toast views. Default is `true`.
+ which operates independently of normal toast views. Default is `false`.
+
*/
- public var queueEnabled = true
+ public var isQueueEnabled = false
/**
The default duration. Used for the `makeToast` and
`showToast` methods that don't require an explicit duration.
Default is 3.0.
+
*/
public var duration: TimeInterval = 3.0
@@ -762,7 +735,42 @@ public class ToastManager {
Sets the default position. Used for the `makeToast` and
`showToast` methods that don't require an explicit position.
Default is `ToastPosition.Bottom`.
+
*/
- public var position = ToastPosition.bottom
+ public var position: ToastPosition = .bottom
+
+}
+
+// MARK: - ToastPosition
+public enum ToastPosition {
+ case top
+ case center
+ case bottom
+
+ fileprivate func centerPoint(forToast toast: UIView, inSuperview superview: UIView) -> CGPoint {
+ let topPadding: CGFloat = ToastManager.shared.style.verticalPadding + superview.csSafeAreaInsets.top
+ let bottomPadding: CGFloat = ToastManager.shared.style.verticalPadding + superview.csSafeAreaInsets.bottom
+
+ switch self {
+ case .top:
+ return CGPoint(x: superview.bounds.size.width / 2.0, y: (toast.frame.size.height / 2.0) + topPadding)
+ case .center:
+ return CGPoint(x: superview.bounds.size.width / 2.0, y: superview.bounds.size.height / 2.0)
+ case .bottom:
+ return CGPoint(x: superview.bounds.size.width / 2.0, y: (superview.bounds.size.height - (toast.frame.size.height / 2.0)) - bottomPadding)
+ }
+ }
+}
+
+// MARK: - Private UIView Extensions
+private extension UIView {
+
+ var csSafeAreaInsets: UIEdgeInsets {
+ if #available(iOS 11.0, *) {
+ return self.safeAreaInsets
+ } else {
+ return .zero
+ }
+ }
}
diff --git a/MFCardDemo.xcodeproj/project.pbxproj b/MFCardDemo.xcodeproj/project.pbxproj
index ea34b4c..524b30e 100644
--- a/MFCardDemo.xcodeproj/project.pbxproj
+++ b/MFCardDemo.xcodeproj/project.pbxproj
@@ -244,20 +244,20 @@
6B24472F1DF84E62003A8285 = {
CreatedOnToolsVersion = 8.1;
DevelopmentTeam = 536JDUMES6;
- LastSwiftMigration = 0900;
+ LastSwiftMigration = 1120;
ProvisioningStyle = Automatic;
};
6B24473B1DF84E82003A8285 = {
CreatedOnToolsVersion = 8.1;
DevelopmentTeam = 536JDUMES6;
- LastSwiftMigration = 0900;
+ LastSwiftMigration = 1120;
ProvisioningStyle = Automatic;
};
};
};
buildConfigurationList = 6B6CF8161DCB53DA00A29C16 /* Build configuration list for PBXProject "MFCardDemo" */;
compatibilityVersion = "Xcode 3.2";
- developmentRegion = English;
+ developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
@@ -369,7 +369,7 @@
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
SWIFT_SWIFT3_OBJC_INFERENCE = Off;
- SWIFT_VERSION = 4.0;
+ SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
@@ -394,7 +394,7 @@
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
SWIFT_SWIFT3_OBJC_INFERENCE = Off;
- SWIFT_VERSION = 4.0;
+ SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
@@ -414,7 +414,7 @@
PRODUCT_BUNDLE_IDENTIFIER = com.mobilefirst.MFCardDemo;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_SWIFT3_OBJC_INFERENCE = Off;
- SWIFT_VERSION = 4.0;
+ SWIFT_VERSION = 5.0;
};
name = Debug;
};
@@ -431,7 +431,7 @@
PRODUCT_BUNDLE_IDENTIFIER = com.mobilefirst.MFCardDemo;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_SWIFT3_OBJC_INFERENCE = Off;
- SWIFT_VERSION = 4.0;
+ SWIFT_VERSION = 5.0;
};
name = Release;
};
@@ -489,7 +489,7 @@
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_SWIFT3_OBJC_INFERENCE = Off;
- SWIFT_VERSION = 3.0;
+ SWIFT_VERSION = 5.0;
};
name = Debug;
};
@@ -539,7 +539,7 @@
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_SWIFT3_OBJC_INFERENCE = Off;
- SWIFT_VERSION = 3.0;
+ SWIFT_VERSION = 5.0;
VALIDATE_PRODUCT = YES;
};
name = Release;
diff --git a/MFCardDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/MFCardDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
new file mode 100644
index 0000000..18d9810
--- /dev/null
+++ b/MFCardDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
@@ -0,0 +1,8 @@
+
+
+
+
+ IDEDidComputeMac32BitWarning
+
+
+
diff --git a/MFCardDemo/AppDelegate.swift b/MFCardDemo/AppDelegate.swift
index d851ad4..1c765d6 100644
--- a/MFCardDemo/AppDelegate.swift
+++ b/MFCardDemo/AppDelegate.swift
@@ -14,7 +14,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
- func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
+ func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
return true
}
diff --git a/MFCardDemo/ViewController.swift b/MFCardDemo/ViewController.swift
index 9c679cc..33dc5c8 100644
--- a/MFCardDemo/ViewController.swift
+++ b/MFCardDemo/ViewController.swift
@@ -26,7 +26,7 @@ class ViewController: UIViewController,MFCardDelegate {
myCard.delegate = self
myCard.autoDismiss = true
myCard.toast = true
- myCard.blurStyle = UIBlurEffect(style: UIBlurEffectStyle.extraLight)
+ myCard.blurStyle = UIBlurEffect(style: UIBlurEffect.Style.extraLight)
let demoCard :Card? = Card(holderName: "Rahul Chandnani", number: "6552552665526625", month: Month.Dec, year: "2019", cvc: "234", paymentType: Card.PaymentType.bank, cardType: CardType.Discover, userId: 0)
myCard.showCardWithCardDetails(card: demoCard!)
}
@@ -37,7 +37,7 @@ class ViewController: UIViewController,MFCardDelegate {
myCard.delegate = self
myCard.autoDismiss = true
myCard.toast = true
- myCard.blurStyle = UIBlurEffect(style: UIBlurEffectStyle.light)
+ myCard.blurStyle = UIBlurEffect(style: UIBlurEffect.Style.light)
myCard.showCard()
}
diff --git a/README.md b/README.md
index 635637c..8961305 100644
--- a/README.md
+++ b/README.md
@@ -5,6 +5,7 @@
+