diff --git a/LeadKit.podspec b/LeadKit.podspec index 43751a96..17500250 100644 --- a/LeadKit.podspec +++ b/LeadKit.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "LeadKit" - s.version = "0.4.1" + s.version = "0.4.2" s.summary = "iOS framework with a bunch of tools for rapid development" s.homepage = "https://github.com/TouchInstinct/LeadKit" s.license = "Apache License, Version 2.0" diff --git a/LeadKit/LeadKit.xcodeproj/project.pbxproj b/LeadKit/LeadKit.xcodeproj/project.pbxproj index d776544c..4a1c9cd7 100644 --- a/LeadKit/LeadKit.xcodeproj/project.pbxproj +++ b/LeadKit/LeadKit.xcodeproj/project.pbxproj @@ -55,6 +55,7 @@ 78B0FC811C6B2CD500358B64 /* App.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78B0FC801C6B2CD500358B64 /* App.swift */; }; 78C36F7E1D801E3E00E7EBEA /* Double+Rounding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78C36F7D1D801E3E00E7EBEA /* Double+Rounding.swift */; }; 78C36F811D8021DD00E7EBEA /* UIColor+Hex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78C36F801D8021DD00E7EBEA /* UIColor+Hex.swift */; }; + 78C54AFD1E432EEF0051EFBA /* UIViewController+TopVisibleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78C54AFC1E432EEF0051EFBA /* UIViewController+TopVisibleViewController.swift */; }; 78CFEE2E1C5C456B00F50370 /* LeadKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 78CFEE2D1C5C456B00F50370 /* LeadKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; 78CFEE351C5C456B00F50370 /* LeadKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 78CFEE2A1C5C456B00F50370 /* LeadKit.framework */; }; 78CFEE3A1C5C456B00F50370 /* LeadKitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78CFEE391C5C456B00F50370 /* LeadKitTests.swift */; }; @@ -137,6 +138,7 @@ 78B0FC801C6B2CD500358B64 /* App.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = App.swift; sourceTree = ""; }; 78C36F7D1D801E3E00E7EBEA /* Double+Rounding.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Double+Rounding.swift"; sourceTree = ""; }; 78C36F801D8021DD00E7EBEA /* UIColor+Hex.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIColor+Hex.swift"; sourceTree = ""; }; + 78C54AFC1E432EEF0051EFBA /* UIViewController+TopVisibleViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIViewController+TopVisibleViewController.swift"; sourceTree = ""; }; 78CFEE2A1C5C456B00F50370 /* LeadKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = LeadKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 78CFEE2D1C5C456B00F50370 /* LeadKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LeadKit.h; sourceTree = ""; }; 78CFEE2F1C5C456B00F50370 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -475,6 +477,7 @@ isa = PBXGroup; children = ( 78D4B5451DA64D49005B0764 /* UIViewController+DefaultStoryboardIdentifier.swift */, + 78C54AFC1E432EEF0051EFBA /* UIViewController+TopVisibleViewController.swift */, ); path = UIViewController; sourceTree = ""; @@ -733,6 +736,7 @@ 78C36F7E1D801E3E00E7EBEA /* Double+Rounding.swift in Sources */, 78CFEE551C5C45E500F50370 /* NibNameProtocol.swift in Sources */, 787609221E1403830093CE36 /* Observable+DeferredJust.swift in Sources */, + 78C54AFD1E432EEF0051EFBA /* UIViewController+TopVisibleViewController.swift in Sources */, 783AF06B1E41CE6C00EC5ADE /* Observable+ToastErrorLogging.swift in Sources */, 78CFEE561C5C45E500F50370 /* ReuseIdentifierProtocol.swift in Sources */, 78A0FCC81DC366A10070B5E1 /* StoryboardProtocol+Extensions.swift in Sources */, diff --git a/LeadKit/LeadKit/Extensions/Observable/Observable+DeferredJust.swift b/LeadKit/LeadKit/Extensions/Observable/Observable+DeferredJust.swift index 117eeef7..f13394d0 100644 --- a/LeadKit/LeadKit/Extensions/Observable/Observable+DeferredJust.swift +++ b/LeadKit/LeadKit/Extensions/Observable/Observable+DeferredJust.swift @@ -30,7 +30,7 @@ public extension Observable { /// that subscribes to the resulting sequence. /// - Returns: An observable sequence whose observers trigger an invocation of the given element factory function. static func deferredJust(_ elementFactory: @escaping () throws -> Element) -> Observable { - return create { (observer) -> Disposable in + return create { observer -> Disposable in do { observer.onNext(try elementFactory()) observer.onCompleted() diff --git a/LeadKit/LeadKit/Extensions/Observable/Observable+ToastErrorLogging.swift b/LeadKit/LeadKit/Extensions/Observable/Observable+ToastErrorLogging.swift index 586c0212..ee4a326f 100644 --- a/LeadKit/LeadKit/Extensions/Observable/Observable+ToastErrorLogging.swift +++ b/LeadKit/LeadKit/Extensions/Observable/Observable+ToastErrorLogging.swift @@ -29,11 +29,15 @@ public extension Observable { /// /// - Returns: The source sequence with the side-effecting behavior applied. func showErrorsInToastInDebugMode() -> Observable { - return `do`(onError: { (error) in - #if DEBUG - UIApplication.shared.keyWindow?.makeToast(error.localizedDescription) - #endif - }) + #if DEBUG + return `do`(onError: { (error) in + DispatchQueue.main.async { + UIApplication.shared.keyWindow?.makeToast(error.localizedDescription) + } + }) + #else + return self + #endif } } diff --git a/LeadKit/LeadKit/Extensions/UIViewController/UIViewController+TopVisibleViewController.swift b/LeadKit/LeadKit/Extensions/UIViewController/UIViewController+TopVisibleViewController.swift new file mode 100644 index 00000000..953fff5e --- /dev/null +++ b/LeadKit/LeadKit/Extensions/UIViewController/UIViewController+TopVisibleViewController.swift @@ -0,0 +1,39 @@ +// +// Copyright (c) 2017 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 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 + +public extension UIViewController { + + /// Return top visible controller even if we have inner UI(Navigation/TabBar)Controller's inside + public var topVisibleViewController: UIViewController { + switch self { + case let navController as UINavigationController: + return navController.visibleViewController?.topVisibleViewController ?? navController + case let tabController as UITabBarController: + return tabController.selectedViewController?.topVisibleViewController ?? tabController + default: + return self.presentedViewController?.topVisibleViewController ?? self + } + } + +} diff --git a/LeadKit/LeadKit/Extensions/UserDefaults/UserDefaults+MappableDataTypes.swift b/LeadKit/LeadKit/Extensions/UserDefaults/UserDefaults+MappableDataTypes.swift index dbf84a3b..99955fa6 100644 --- a/LeadKit/LeadKit/Extensions/UserDefaults/UserDefaults+MappableDataTypes.swift +++ b/LeadKit/LeadKit/Extensions/UserDefaults/UserDefaults+MappableDataTypes.swift @@ -144,16 +144,7 @@ public extension Reactive where Base: UserDefaults { /// /// - returns: Observable of specified model type. func object(forKey key: String) -> Observable where T: ImmutableMappable { - return Observable.create { observer in - do { - observer.onNext(try self.base.object(forKey: key)) - observer.onCompleted() - } catch { - observer.onError(error) - } - - return Disposables.create() - } + return Observable.deferredJust { try self.base.object(forKey: key) } } /// Reactive version of object(forKey:defaultValue:) -> T. @@ -166,12 +157,7 @@ public extension Reactive where Base: UserDefaults { /// /// - returns: Observable of specified model type. func object(forKey key: String, defaultValue: T) -> Observable where T: ImmutableMappable { - return Observable.create { observer in - observer.onNext(self.base.object(forKey: key, defaultValue: defaultValue)) - observer.onCompleted() - - return Disposables.create() - } + return Observable.deferredJust { self.base.object(forKey: key, defaultValue: defaultValue) } } /// Reactive version of object(forKey:) -> [T]. @@ -180,16 +166,7 @@ public extension Reactive where Base: UserDefaults { /// /// - returns: Observable of specified array type. func object(forKey key: String) -> Observable<[T]> where T: ImmutableMappable { - return Observable.create { observer in - do { - observer.onNext(try self.base.object(forKey: key)) - observer.onCompleted() - } catch { - observer.onError(error) - } - - return Disposables.create() - } + return Observable.deferredJust { try self.base.object(forKey: key) } } /// Reactive version of object(forKey:defaultValue:) -> [T]. @@ -202,12 +179,7 @@ public extension Reactive where Base: UserDefaults { /// /// - returns: Observable of specified array type. func object(forKey key: String, defaultValue: [T]) -> Observable<[T]> where T: ImmutableMappable { - return Observable.create { observer in - observer.onNext(self.base.object(forKey: key, defaultValue: defaultValue)) - observer.onCompleted() - - return Disposables.create() - } + return Observable.deferredJust { self.base.object(forKey: key, defaultValue: defaultValue) } } /// Reactive version of set(_:forKey:).