Last active
July 6, 2017 13:16
-
-
Save Quaggie/0bd560f47491c0aa1c20b68d2c1f7ad9 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Extensions.swift | |
// Swift 3 compatible | |
// | |
// Created by Quaggie. | |
// Copyright © 2017 Quaggie. All rights reserved. | |
// | |
import UIKit | |
extension UIColor { | |
convenience init(hexString: String) { | |
var cString: String = hexString.trimmingCharacters(in: NSCharacterSet.whitespacesAndNewlines).uppercased() | |
if (cString.hasPrefix("#")) { | |
cString = (cString as NSString).substring(from: 1) | |
} | |
if (cString.characters.count != 6) { | |
self.init(white: 0.5, alpha: 1.0) | |
} else { | |
let rString: String = (cString as NSString).substring(to: 2) | |
let gString = ((cString as NSString).substring(from: 2) as NSString).substring(to: 2) | |
let bString = ((cString as NSString).substring(from: 4) as NSString).substring(to: 2) | |
var r: CUnsignedInt = 0, g: CUnsignedInt = 0, b: CUnsignedInt = 0; | |
Scanner(string: rString).scanHexInt32(&r) | |
Scanner(string: gString).scanHexInt32(&g) | |
Scanner(string: bString).scanHexInt32(&b) | |
self.init(red: CGFloat(r) / CGFloat(255.0), green: CGFloat(g) / CGFloat(255.0), blue: CGFloat(b) / CGFloat(255.0), alpha: CGFloat(1)) | |
} | |
} | |
} | |
protocol ReusableView: class { } | |
extension ReusableView where Self: UIView { | |
static var reuseIdentifier: String { | |
return String(describing: self) | |
} | |
} | |
extension UITableViewCell: ReusableView { } | |
protocol NibLoadableView: class { } | |
extension NibLoadableView where Self: UIView { | |
static var nibName: String { | |
return String(describing: self) | |
} | |
} | |
extension UITableView { | |
func register<T: UITableViewCell>(_: T.Type) where T: ReusableView, T: NibLoadableView { | |
let nib = UINib(nibName: T.nibName, bundle: nil) | |
register(nib, forCellReuseIdentifier: T.reuseIdentifier) | |
} | |
func dequeueReusableCell<T: UITableViewCell>(forIndexPath indexPath: IndexPath) -> T where T: ReusableView { | |
guard let cell = dequeueReusableCell(withIdentifier: T.reuseIdentifier, for: indexPath) as? T else { | |
fatalError("Could not dequeue cell with identifier: \(T.reuseIdentifier)") | |
} | |
return cell | |
} | |
} | |
extension String: Error { | |
func floatingPoint () throws -> Double { | |
let value = try self.characters.map { char throws -> String in | |
if String(char).rangeOfCharacter(from: CharacterSet.letters) != nil { | |
throw "Letters not allowed!" | |
} | |
return char == "." ? "" : String(char) | |
}.joined() | |
return Double(value) ?? Double() | |
} | |
func limitDecimals (by num: Int) -> String { | |
return String(format: "%.\(num)f", Double(self) ?? 0) | |
} | |
func toArrayWith(separator: String) -> [String] { | |
return self.characters.split(separator: ",").map { String($0).trimmingCharacters(in: .whitespacesAndNewlines) } | |
} | |
var dateFromISO8601: Date? { | |
return Date.Formatter.iso8601.date(from: self) | |
} | |
func getDataFromUrl (completion: @escaping (_ data: Data?) -> Void) { | |
URLSession.shared.dataTask(with: NSURL(string: self)! as URL, completionHandler: { (data, response, error) -> Void in | |
if let error = error { | |
print(error) | |
return | |
} | |
completion(data) | |
}).resume() | |
} | |
var digits: String { | |
return components(separatedBy: CharacterSet.decimalDigits.inverted) | |
.joined(separator: "") | |
} | |
} | |
// Date ---------------------------------------------------------------------------------------------------------------- | |
extension Date { | |
struct Formatter { | |
static let iso8601: DateFormatter = { | |
let formatter = DateFormatter() | |
formatter.calendar = Calendar(identifier: .iso8601) | |
formatter.locale = Locale(identifier: "en_US_POSIX") | |
formatter.timeZone = TimeZone(secondsFromGMT: 0) | |
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSXXXXX" | |
return formatter | |
}() | |
} | |
var iso8601: String { | |
return Formatter.iso8601.string(from: self) | |
} | |
func string (format: String) -> String { | |
let dateFormatter = DateFormatter() | |
dateFormatter.dateFormat = format | |
return dateFormatter.string(from: self) | |
} | |
/// Returns the amount of years from another date | |
func years(from date: Date) -> Int { | |
return Calendar.current.dateComponents([.year], from: date, to: self).year ?? 0 | |
} | |
/// Returns the amount of months from another date | |
func months(from date: Date) -> Int { | |
return Calendar.current.dateComponents([.month], from: date, to: self).month ?? 0 | |
} | |
/// Returns the amount of weeks from another date | |
func weeks(from date: Date) -> Int { | |
return Calendar.current.dateComponents([.weekOfYear], from: date, to: self).weekOfYear ?? 0 | |
} | |
/// Returns the amount of days from another date | |
func days(from date: Date) -> Int { | |
return Calendar.current.dateComponents([.day], from: date, to: self).day ?? 0 | |
} | |
/// Returns the amount of hours from another date | |
func hours(from date: Date) -> Int { | |
return Calendar.current.dateComponents([.hour], from: date, to: self).hour ?? 0 | |
} | |
/// Returns the amount of minutes from another date | |
func minutes(from date: Date) -> Int { | |
return Calendar.current.dateComponents([.minute], from: date, to: self).minute ?? 0 | |
} | |
/// Returns the amount of seconds from another date | |
func seconds(from date: Date) -> Int { | |
return Calendar.current.dateComponents([.second], from: date, to: self).second ?? 0 | |
} | |
/// Returns the a custom time interval description from another date | |
func offset(from date: Date) -> String { | |
if years(from: date) > 0 { return "\(years(from: date))y" } | |
if months(from: date) > 0 { return "\(months(from: date))M" } | |
if weeks(from: date) > 0 { return "\(weeks(from: date))w" } | |
if days(from: date) > 0 { return "\(days(from: date))d" } | |
if hours(from: date) > 0 { return "\(hours(from: date))h" } | |
if minutes(from: date) > 0 { return "\(minutes(from: date))m" } | |
if seconds(from: date) > 0 { return "\(seconds(from: date))s" } | |
return "" | |
} | |
var fromNow: String { | |
let now = Date() | |
let years = now.years(from: self) | |
let months = now.months(from: self) | |
let weeks = now.weeks(from: self) | |
let days = now.days(from: self) | |
let hours = now.hours(from: self) | |
let minutes = now.minutes(from: self) | |
let seconds = now.seconds(from: self) | |
if years > 0 { | |
if years > 1 { | |
return "\(years) anos atrás" | |
} | |
return "\(years) ano atrás" | |
} | |
if months > 0 { | |
if months > 1 { | |
return "\(months) meses atrás" | |
} | |
return "\(months) mês atrás" | |
} | |
if weeks > 0 { | |
if weeks > 1 { | |
return "\(weeks) semanas atrás" | |
} | |
return "\(weeks) semana atrás" | |
} | |
if days > 0 { | |
if days > 1 { | |
return "\(days) dias atrás" | |
} | |
return "\(days) dia atrás" | |
} | |
if hours > 0 { | |
if hours > 1 { | |
return "\(hours) horas atrás" | |
} | |
return "\(hours) hora atrás" | |
} | |
if minutes > 0 { | |
if minutes > 1 { | |
return "\(minutes) minutos atrás" | |
} | |
return "\(minutes) minuto atrás" | |
} | |
if seconds > 0 { | |
return "Ainda agora" | |
} else { | |
return "Agora" | |
} | |
} | |
} | |
// Timer ---------------------------------------------------------------------------------------------------------------- | |
extension Timer { | |
// Adds a delay to the main Queue | |
static func delay (_ delay: Double, closure: @escaping ()->()) { | |
DispatchQueue.main.asyncAfter( | |
deadline: DispatchTime.now() + Double(Int64(delay * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC), | |
execute: closure | |
) | |
} | |
} | |
// UIView ---------------------------------------------------------------------------------------------------------------- | |
extension UIView { | |
func addContraintsWith (format: String, views: UIView...) { | |
var viewsDictionary = [String: UIView]() | |
for (index, view) in views.enumerated() { | |
let key = "v\(index)" | |
view.translatesAutoresizingMaskIntoConstraints = false | |
viewsDictionary[key] = view | |
} | |
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: format, options: NSLayoutFormatOptions(), metrics: nil, views: viewsDictionary)) | |
} | |
func fillSuperview() { | |
translatesAutoresizingMaskIntoConstraints = false | |
if let superview = superview { | |
leftAnchor.constraint(equalTo: superview.leftAnchor).isActive = true | |
rightAnchor.constraint(equalTo: superview.rightAnchor).isActive = true | |
topAnchor.constraint(equalTo: superview.topAnchor).isActive = true | |
bottomAnchor.constraint(equalTo: superview.bottomAnchor).isActive = true | |
} | |
} | |
@discardableResult | |
func anchor(top: NSLayoutYAxisAnchor? = nil, left: NSLayoutXAxisAnchor? = nil, bottom: NSLayoutYAxisAnchor? = nil, right: NSLayoutXAxisAnchor? = nil, topConstant: CGFloat = 0, leftConstant: CGFloat = 0, bottomConstant: CGFloat = 0, rightConstant: CGFloat = 0, widthConstant: CGFloat = 0, heightConstant: CGFloat = 0) -> [NSLayoutConstraint] { | |
translatesAutoresizingMaskIntoConstraints = false | |
var anchors = [NSLayoutConstraint]() | |
if let top = top { | |
anchors.append(topAnchor.constraint(equalTo: top, constant: topConstant)) | |
} | |
if let left = left { | |
anchors.append(leftAnchor.constraint(equalTo: left, constant: leftConstant)) | |
} | |
if let bottom = bottom { | |
anchors.append(bottomAnchor.constraint(equalTo: bottom, constant: -bottomConstant)) | |
} | |
if let right = right { | |
anchors.append(rightAnchor.constraint(equalTo: right, constant: -rightConstant)) | |
} | |
if widthConstant > 0 { | |
anchors.append(widthAnchor.constraint(equalToConstant: widthConstant)) | |
} | |
if heightConstant > 0 { | |
anchors.append(heightAnchor.constraint(equalToConstant: heightConstant)) | |
} | |
anchors.forEach({$0.isActive = true}) | |
return anchors | |
} | |
func anchorCenterXToSuperview(constant: CGFloat = 0) { | |
translatesAutoresizingMaskIntoConstraints = false | |
if let anchor = superview?.centerXAnchor { | |
centerXAnchor.constraint(equalTo: anchor, constant: constant).isActive = true | |
} | |
} | |
func anchorCenterYToSuperview(constant: CGFloat = 0) { | |
translatesAutoresizingMaskIntoConstraints = false | |
if let anchor = superview?.centerYAnchor { | |
centerYAnchor.constraint(equalTo: anchor, constant: constant).isActive = true | |
} | |
} | |
func anchorCenterSuperview() { | |
anchorCenterXToSuperview() | |
anchorCenterYToSuperview() | |
} | |
var usesAutoLayout: Bool { | |
get { return !translatesAutoresizingMaskIntoConstraints } | |
set { translatesAutoresizingMaskIntoConstraints = !newValue } | |
} | |
} | |
// Array ---------------------------------------------------------------------------------------------------------------- | |
extension Array where Element: Equatable { | |
var unique: [Element] { | |
var uniqueValues: [Element] = [] | |
forEach { item in | |
if !uniqueValues.contains(item) { | |
uniqueValues += [item] | |
} | |
} | |
return uniqueValues | |
} | |
} | |
// Notification Center | |
extension Notification.Name { | |
static let onUserLogin = Notification.Name("onUserLogin") | |
static let onUserLogout = Notification.Name("onUserLogout") | |
} | |
// UITabBar | |
extension UITabBar { | |
override open func sizeThatFits(_ size: CGSize) -> CGSize { | |
super.sizeThatFits(size) | |
var sizeThatFits = super.sizeThatFits(size) | |
sizeThatFits.height = 38 | |
return sizeThatFits | |
} | |
} | |
// NavigationBar | |
extension NavigationBar { | |
func configure () { | |
tintColor = Color.white | |
depthPreset = .depth4 | |
dividerColor = Colors.red | |
backgroundColor = Colors.red | |
isOpaque = true | |
isTranslucent = false | |
} | |
func setTransparent () { | |
setBackgroundImage(UIImage(), for: .default) | |
shadowImage = UIImage() | |
isTranslucent = true | |
backgroundColor = UIColor.clear | |
} | |
} | |
// UIApplication | |
extension UIApplication { | |
class func topViewController(base: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? { | |
if let nav = base as? UINavigationController { | |
return topViewController(base: nav.visibleViewController) | |
} | |
if let tab = base as? UITabBarController { | |
if let selected = tab.selectedViewController { | |
return topViewController(base: selected) | |
} | |
} | |
if let presented = base?.presentedViewController { | |
return topViewController(base: presented) | |
} | |
return base | |
} | |
} | |
// UIImageView | |
extension UIImageView { | |
func roundImgWithBorder (width: CGFloat, color: UIColor) { | |
self.layer.cornerRadius = self.height / 2 | |
self.borderWidth = width | |
self.borderColor = color | |
} | |
func roundImg () { | |
self.layer.cornerRadius = self.height / 2 | |
} | |
func imageFromServerURL(urlString: String) { | |
URLSession.shared.dataTask(with: NSURL(string: urlString)! as URL, completionHandler: { (data, response, error) -> Void in | |
if let error = error { | |
print(error) | |
return | |
} | |
DispatchQueue.main.async(execute: { () -> Void in | |
let image = UIImage(data: data!) | |
self.image = image | |
}) | |
}).resume() | |
} | |
func imageFromServerURL(urlString: String, completion: @escaping (_ img: UIImage?) -> Void) { | |
URLSession.shared.dataTask(with: NSURL(string: urlString)! as URL, completionHandler: { (data, response, error) -> Void in | |
if let error = error { | |
print(error) | |
return | |
} | |
DispatchQueue.main.async(execute: { () -> Void in | |
let image = UIImage(data: data!) | |
self.image = image | |
completion(image) | |
}) | |
}).resume() | |
} | |
} | |
// Int | |
extension Int { | |
var kFormatted: String { | |
if self >= 1000 && self < 1000000 { | |
return String(format: "%iK", self / 1000) | |
} else if self >= 1000000 { | |
return String(format: "%iKK", self / 100000) | |
} else { | |
return String(describing: self) | |
} | |
} | |
} | |
// Double | |
extension Double { | |
var kFormatted: String { | |
if self >= 1000 && self < 1000000 { | |
return String(format: "%.2fK", self / 1000) | |
} else if self >= 1000000 { | |
return String(format: "%.2fKK", self / 1000000) | |
} else { | |
return String(format: "%.2f", self) | |
} | |
} | |
} | |
// UIViewController | |
extension UIViewController { | |
func hideKeyboardWhenTappedAround() { | |
let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard)) | |
view.addGestureRecognizer(tap) | |
} | |
func dismissKeyboard() { | |
view.endEditing(true) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment