Skip to content

Commit

Permalink
* Added new useful system types.
Browse files Browse the repository at this point in the history
  • Loading branch information
Domagoj Kulundžić committed Oct 5, 2019
1 parent db2d9fd commit bf7cdd5
Show file tree
Hide file tree
Showing 17 changed files with 528 additions and 18 deletions.
13 changes: 13 additions & 0 deletions Template/System/Sources/Assets/Asset.swift
@@ -0,0 +1,13 @@
//
// Asset.swift
// System
//
// Created by Domagoj Kulundzic on 13/08/2019.
// Copyright © 2019 Martian & Machine. All rights reserved.
//

import Foundation

public protocol Asset {
var name: String { get }
}
28 changes: 28 additions & 0 deletions Template/System/Sources/Assets/ColorAsset.swift
@@ -0,0 +1,28 @@
//
// ColorAsset.swift
// System
//
// Created by Domagoj Kulundzic on 13/08/2019.
// Copyright © 2019 Martian & Machine. All rights reserved.
//

import Foundation

public protocol ColorAsset: Asset {
var color: UIColor { get }
}

public extension ColorAsset {
var color: UIColor {
guard let color = UIColor(named: name) else {
fatalError("Can't find the \(name) image asset.")
}
return color
}
}

public extension ColorAsset where Self: RawRepresentable, Self.RawValue == String {
var name: String {
return rawValue
}
}
36 changes: 36 additions & 0 deletions Template/System/Sources/Assets/ImageAsset.swift
@@ -0,0 +1,36 @@
//
// ImageAsset.swift
// System
//
// Created by Domagoj Kulundzic on 13/08/2019.
// Copyright © 2019 Martian & Machine. All rights reserved.
//

import Foundation

public protocol ImageAsset: Asset {
var image: UIImage { get }
}

public extension ImageAsset {
var image: UIImage {
guard let image = UIImage(named: name) else {
fatalError("Can't find the \(name) image asset.")
}
return image
}

var imageTemplate: UIImage {
return image.withRenderingMode(.alwaysTemplate)
}

var imageOriginal: UIImage {
return image.withRenderingMode(.alwaysOriginal)
}
}

public extension ImageAsset where Self: RawRepresentable, Self.RawValue == String {
var name: String {
return rawValue
}
}
39 changes: 39 additions & 0 deletions Template/System/Sources/Environment.swift
@@ -0,0 +1,39 @@
//
// Environment.swift
// Template
//
// Created by Domagoj Kulundzic on 07/08/2019.
// Copyright © 2019 Martian & Machine. All rights reserved.
//

import Foundation

public enum Environment: String {
case debug
case staging
case release
}

public extension Environment {
static var current: Environment {
#if DEBUG
return .debug
#elseif STAGING
return .staging
#elseif RELEASE
return .release
#endif
}

static var isDebug: Bool {
return current == .debug
}

static var isStaging: Bool {
return current == .staging
}

static var isProduction: Bool {
return current == .release
}
}
39 changes: 39 additions & 0 deletions Template/System/Sources/Global.swift
@@ -0,0 +1,39 @@
//
// Global.swift
// Template
//
// Created by Domagoj Kulundzic on 24/07/2018.
// Copyright © 2018 Martian & Machine. All rights reserved.
//

import Foundation

/// Typealiases a single argumentless/voidless closure.
public typealias Action = () -> Void

/// Typealiases a parametrised single voidless closure.
public typealias ParametrisedAction<T> = (T) -> Void

/// Typealiases a success handler.
public typealias SuccessHandler<T> = ((T) -> Void)?

/// Typealiases a argumentless success handler.
public typealias ArgumentlessSuccessHandler = (() -> Void)?

/// Typealiases a failure handler.
public typealias FailureHandler = ((Error) -> Void)?

/// Invokes the action only if the current configuration is DEBUG.
public func whenDebug(_ action: Action?) {
#if DEBUG
action?()
#endif
}

/// Invokes the action only if the current configuration is RELEASE.
public func whenRelease(_ action: Action?) {
#if DEBUG
#else
action?()
#endif
}
72 changes: 72 additions & 0 deletions Template/System/Sources/KeyboardObserver.swift
@@ -0,0 +1,72 @@
//
// KeyboardObserver.swift
// Template
//
// Created by Domagoj Kulundzic on 03/10/2018.
// Copyright © 2018 Martian & Machine. All rights reserved.
//

import UIKit

/// Defines methods to respond to keyboard appearance events. All methods have empty default implementations.
public protocol KeyboardObserverDelegate: class {
func keyboardWillShow(keyboardHeight: CGFloat, animationDuration: TimeInterval, animationCurve: UIView.AnimationCurve)
func keyboardWillHide(keyboardHeight: CGFloat, animationDuration: TimeInterval, animationCurve: UIView.AnimationCurve)
func keyboardDidShow(keyboardHeight: CGFloat, animationDuration: TimeInterval, animationCurve: UIView.AnimationCurve)
func keyboardDidHide(keyboardHeight: CGFloat, animationDuration: TimeInterval, animationCurve: UIView.AnimationCurve)
}

public extension KeyboardObserverDelegate {
func keyboardWillShow(keyboardHeight: CGFloat, animationDuration: TimeInterval, animationCurve: UIView.AnimationCurve) { }
func keyboardWillHide(keyboardHeight: CGFloat, animationDuration: TimeInterval, animationCurve: UIView.AnimationCurve) { }
func keyboardDidShow(keyboardHeight: CGFloat, animationDuration: TimeInterval, animationCurve: UIView.AnimationCurve) { }
func keyboardDidHide(keyboardHeight: CGFloat, animationDuration: TimeInterval, animationCurve: UIView.AnimationCurve) { }
}

/// A convenience utility that eases responding to keyboard appearance events by
/// wrapping around the keyboard appearance notifications.
///
/// The supported appearance methods are defined by the **KeyboardObserverDelegate**.
public final class KeyboardObserver {
/// The delegate to notify of keyboard appearance events.
public weak var delegate: KeyboardObserverDelegate?

/// Initialises a new instance.
/// - parameter delegate: A **KeyboardObserverDelegate** conforming type. Defaults to **nil**.
public init(delegate: KeyboardObserverDelegate? = nil) {
self.delegate = delegate
setupKeyboardObserving()
}

/// Since the **KeyboardObserver** will (in most cases) be defined as a **lazy var**, this method
/// provides a sensical way of triggering the instance creation.
public func observe() { }
}

private extension KeyboardObserver {
func setupKeyboardObserving() {
_ = NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillShowNotification, object: nil, queue: nil) { [weak self] in
self?.processKeyboardNotification($0) { self?.delegate?.keyboardWillShow(keyboardHeight: $0, animationDuration: $1, animationCurve: $2) }
}
_ = NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillHideNotification, object: nil, queue: nil) { [weak self] in
self?.processKeyboardNotification($0) { self?.delegate?.keyboardWillHide(keyboardHeight: $0, animationDuration: $1, animationCurve: $2) }
}
_ = NotificationCenter.default.addObserver(forName: UIResponder.keyboardDidShowNotification, object: nil, queue: nil) { [weak self] in
self?.processKeyboardNotification($0) { self?.delegate?.keyboardDidShow(keyboardHeight: $0, animationDuration: $1, animationCurve: $2) }
}
_ = NotificationCenter.default.addObserver(forName: UIResponder.keyboardDidHideNotification, object: nil, queue: nil) { [weak self] in
self?.processKeyboardNotification($0) { self?.delegate?.keyboardDidHide(keyboardHeight: $0, animationDuration: $1, animationCurve: $2) }
}
}

func processKeyboardNotification(_ notification: Foundation.Notification, processingHandler: ((CGFloat, TimeInterval, UIView.AnimationCurve) -> Void)?) {
guard
let keyboardHeight = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue.height,
let animationDuration = (notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue,
let animationCurveRawValue = (notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? NSNumber)?.intValue,
let animationCurve = UIView.AnimationCurve(rawValue: animationCurveRawValue) else {
return
}
processingHandler?(keyboardHeight, animationDuration, animationCurve)
}
}
52 changes: 52 additions & 0 deletions Template/System/Sources/PropertyWrappers.swift
@@ -0,0 +1,52 @@
//
// PropertyWrappers.swift
// Template
//
// Created by Domagoj Kulundzic on 02/10/2019.
// Copyright © 2019 Martian & Machine. All rights reserved.
//

import Foundation

@propertyWrapper
public struct UserDefault<T> {
public let key: String
public let defaultValue: T

public init(_ key: String, defaultValue: T) {
self.key = key
self.defaultValue = defaultValue
}

public var wrappedValue: T {
get { return UserDefaults.standard.object(forKey: key) as? T ?? defaultValue }
set { UserDefaults.standard.set(newValue, forKey: key) }
}
}

@propertyWrapper
public struct Atomic<T> {
private var value: T
private let lock = NSLock()

public init(wrappedValue value: T) {
self.value = value
}

public var wrappedValue: T {
get { return load() }
set { store(newValue: newValue) }
}

public func load() -> T {
lock.lock()
defer { lock.unlock() }
return value
}

public mutating func store(newValue: T) {
lock.lock()
defer { lock.unlock() }
value = newValue
}
}
6 changes: 3 additions & 3 deletions Template/System/Sources/Protocols/DataSourceProtocol.swift
@@ -1,20 +1,20 @@
//
// DataSourceProtocol.swift
// O2O
// Template
//
// Created by Domagoj Kulundzic on 17/07/2018.
// Copyright © 2018 Martian & Machine. All rights reserved.
//

import Foundation

protocol DataSourceProtocol {
public protocol DataSourceProtocol {
associatedtype Section: SectionProtocol
var sections: [Section] { get }
var isEmpty: Bool { get }
}

extension DataSourceProtocol {
public extension DataSourceProtocol {
var isEmpty: Bool {
guard numberOfSections() > 0 else {
return true
Expand Down
6 changes: 3 additions & 3 deletions Template/System/Sources/Protocols/SectionProtocol.swift
@@ -1,20 +1,20 @@
//
// SectionProtocol.swift
// O2O
// Template
//
// Created by Domagoj Kulundzic on 17/07/2018.
// Copyright © 2018 Martian & Machine. All rights reserved.
//

import Foundation

protocol SectionProtocol {
public protocol SectionProtocol {
associatedtype Item
var items: [Item] { get }
var isCollapsed: Bool { get }
}

extension SectionProtocol {
public extension SectionProtocol {
var isCollapsed: Bool {
return false
}
Expand Down

0 comments on commit bf7cdd5

Please sign in to comment.