Merge branch 'master' into feature/refresh_control
# Conflicts: # CHANGELOG.md # LeadKit.podspec
This commit is contained in:
commit
79d8f2a05e
|
|
@ -1 +0,0 @@
|
|||
5.0
|
||||
11
CHANGELOG.md
11
CHANGELOG.md
|
|
@ -1,8 +1,17 @@
|
|||
# Changelog
|
||||
|
||||
### 0.9.45
|
||||
### 0.10.2
|
||||
- **Add**: `RefreshControl` - a basic UIRefreshControl with fixed refresh action.
|
||||
|
||||
### 0.10.1
|
||||
- **Update**: Third party dependencies: `Alamofire` 5.2.2, `RxAlamofire` 5.6.1
|
||||
|
||||
### 0.10.0
|
||||
- **Update**: Third party dependencies: `RxSwift` (and all sub-dependencies) to 5.1.0, `Alamofire` 5.0, `SnapKit` 5.0
|
||||
- **Refactored**: NetworkManager to use new Alamofire API
|
||||
- **API BreakingChanges**: NetworkServiceConfiguration no longer accepts `ServerTrustPolicy`, it is now replaced by an instance of a `ServerTrustEvaluating` protocol. Full description and default implementations can be found at Alamofire [sources](https://github.com/Alamofire/Alamofire/blob/master/Source/ServerTrustEvaluation.swift). Since new evaluation is used, evaluation against self-signed certificates will now throw an AfError and abort any outcoming request. To support self-signed certificates use `DisabledTrustEvaluator` for specified host in configuration.
|
||||
- **Removed**: UIImage+SupportExtensions, UIScrollView+Support
|
||||
|
||||
### 0.9.44
|
||||
- **Add**: `TIFoundationUtils` - set of helpers for Foundation framework classes.
|
||||
|
||||
|
|
|
|||
6
Cartfile
6
Cartfile
|
|
@ -1,7 +1,7 @@
|
|||
github "malcommac/SwiftDate"
|
||||
github "Alamofire/Alamofire"
|
||||
github "RxSwiftCommunity/RxAlamofire" ~> 4.5
|
||||
github "RxSwiftCommunity/RxAlamofire" ~> 5.6.0
|
||||
github "TouchInstinct/TableKit"
|
||||
github "ReactiveX/RxSwift" ~> 4.5
|
||||
github "ReactiveX/RxSwift" ~> 5.1.0
|
||||
github "pronebird/UIScrollView-InfiniteScroll"
|
||||
github "SnapKit/SnapKit" ~> 4.2
|
||||
github "SnapKit/SnapKit" ~> 5.0
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
github "Alamofire/Alamofire" "4.9.1"
|
||||
github "ReactiveX/RxSwift" "4.5.0"
|
||||
github "RxSwiftCommunity/RxAlamofire" "4.5.0"
|
||||
github "SnapKit/SnapKit" "4.2.0"
|
||||
github "Alamofire/Alamofire" "5.2.2"
|
||||
github "ReactiveX/RxSwift" "5.1.1"
|
||||
github "RxSwiftCommunity/RxAlamofire" "v5.6.1"
|
||||
github "SnapKit/SnapKit" "5.0.1"
|
||||
github "TouchInstinct/TableKit" "2.10008.1"
|
||||
github "malcommac/SwiftDate" "6.1.0"
|
||||
github "pronebird/UIScrollView-InfiniteScroll" "1.1.0"
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = "LeadKit"
|
||||
s.version = "0.9.45"
|
||||
s.version = "0.10.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"
|
||||
s.author = "Touch Instinct"
|
||||
s.source = { :git => "https://github.com/TouchInstinct/LeadKit.git", :tag => s.version }
|
||||
s.platform = :ios, '9.0'
|
||||
s.platform = :ios, '10.0'
|
||||
s.swift_versions = ['5.0']
|
||||
|
||||
s.subspec 'UIColorHex' do |ss|
|
||||
ss.ios.deployment_target = '8.0'
|
||||
|
|
@ -17,9 +18,9 @@ Pod::Spec.new do |s|
|
|||
end
|
||||
|
||||
s.subspec 'Core' do |ss|
|
||||
ss.ios.deployment_target = '9.0'
|
||||
ss.tvos.deployment_target = '9.0'
|
||||
ss.watchos.deployment_target = '2.0'
|
||||
ss.ios.deployment_target = '10.0'
|
||||
ss.tvos.deployment_target = '10.0'
|
||||
ss.watchos.deployment_target = '3.0'
|
||||
|
||||
ss.source_files = "Sources/**/*.swift"
|
||||
ss.watchos.exclude_files = [
|
||||
|
|
@ -43,7 +44,6 @@ Pod::Spec.new do |s|
|
|||
"Sources/Extensions/NetworkService/NetworkService+RxLoadImage.swift",
|
||||
"Sources/Extensions/DataLoading/GeneralDataLoading/GeneralDataLoadingController+DefaultImplementation.swift",
|
||||
"Sources/Extensions/DataLoading/PaginationDataLoading/*",
|
||||
"Sources/Extensions/Support/UIScrollView+Support.swift",
|
||||
"Sources/Extensions/Support/UINavigationItem+Support.swift",
|
||||
"Sources/Extensions/TableKit/**/*.swift",
|
||||
"Sources/Extensions/Array/Array+SeparatorRowBoxExtensions.swift",
|
||||
|
|
@ -80,7 +80,6 @@ Pod::Spec.new do |s|
|
|||
"Sources/Structures/Drawing/CALayerDrawingOperation.swift",
|
||||
"Sources/Enums/Search/*",
|
||||
"Sources/Extensions/DataLoading/PaginationDataLoading/*",
|
||||
"Sources/Extensions/Support/UIScrollView+Support.swift",
|
||||
"Sources/Extensions/Support/UINavigationItem+Support.swift",
|
||||
"Sources/Extensions/TableKit/**/*.swift",
|
||||
"Sources/Extensions/Array/Array+SeparatorRowBoxExtensions.swift",
|
||||
|
|
@ -93,13 +92,13 @@ Pod::Spec.new do |s|
|
|||
"Sources/Structures/DataLoading/PaginationDataLoading/*"
|
||||
]
|
||||
|
||||
ss.dependency "RxSwift", '~> 4'
|
||||
ss.dependency "RxCocoa", '~> 4'
|
||||
ss.dependency "RxAlamofire", '~> 4'
|
||||
ss.dependency "RxSwift", '~> 5.1.0'
|
||||
ss.dependency "RxCocoa", '~> 5.1.0'
|
||||
ss.dependency "RxAlamofire", '~> 5.6.0'
|
||||
ss.dependency "SwiftDate", '~> 6'
|
||||
|
||||
ss.ios.dependency "TableKit", '~> 2.8'
|
||||
ss.ios.dependency "SnapKit", '~> 4.0.0'
|
||||
ss.ios.dependency "SnapKit", '~> 5.0.0'
|
||||
ss.ios.dependency "UIScrollView-InfiniteScroll", '~> 1.1.0'
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -95,7 +95,6 @@
|
|||
671462C81EB3396E00EAB194 /* String+Localization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671461FC1EB3396E00EAB194 /* String+Localization.swift */; };
|
||||
671462CA1EB3396E00EAB194 /* String+Localization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671461FC1EB3396E00EAB194 /* String+Localization.swift */; };
|
||||
671462CB1EB3396E00EAB194 /* String+Localization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671461FC1EB3396E00EAB194 /* String+Localization.swift */; };
|
||||
671462D01EB3396E00EAB194 /* UIScrollView+Support.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671461FF1EB3396E00EAB194 /* UIScrollView+Support.swift */; };
|
||||
671462D41EB3396E00EAB194 /* TableDirector+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671462011EB3396E00EAB194 /* TableDirector+Extensions.swift */; };
|
||||
671462D81EB3396E00EAB194 /* TimeInterval+DateComponents.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671462031EB3396E00EAB194 /* TimeInterval+DateComponents.swift */; };
|
||||
671462DA1EB3396E00EAB194 /* TimeInterval+DateComponents.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671462031EB3396E00EAB194 /* TimeInterval+DateComponents.swift */; };
|
||||
|
|
@ -105,8 +104,6 @@
|
|||
671462E71EB3396E00EAB194 /* UIColor+Hex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671462091EB3396E00EAB194 /* UIColor+Hex.swift */; };
|
||||
671462EC1EB3396E00EAB194 /* UIImage+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6714620D1EB3396E00EAB194 /* UIImage+Extensions.swift */; };
|
||||
671462EF1EB3396E00EAB194 /* UIImage+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6714620D1EB3396E00EAB194 /* UIImage+Extensions.swift */; };
|
||||
671462F01EB3396E00EAB194 /* UIImage+SupportExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6714620E1EB3396E00EAB194 /* UIImage+SupportExtensions.swift */; };
|
||||
671462F31EB3396E00EAB194 /* UIImage+SupportExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6714620E1EB3396E00EAB194 /* UIImage+SupportExtensions.swift */; };
|
||||
671462FC1EB3396E00EAB194 /* UIView+XibNameProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671462131EB3396E00EAB194 /* UIView+XibNameProtocol.swift */; };
|
||||
671462FF1EB3396E00EAB194 /* UIView+XibNameProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671462131EB3396E00EAB194 /* UIView+XibNameProtocol.swift */; };
|
||||
671463001EB3396E00EAB194 /* UIView+LoadFromNib.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671462141EB3396E00EAB194 /* UIView+LoadFromNib.swift */; };
|
||||
|
|
@ -589,12 +586,10 @@
|
|||
671461F11EB3396E00EAB194 /* Observable+DeferredJust.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Observable+DeferredJust.swift"; sourceTree = "<group>"; };
|
||||
671461F61EB3396E00EAB194 /* Sequence+ConcurrentMap.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Sequence+ConcurrentMap.swift"; sourceTree = "<group>"; };
|
||||
671461FC1EB3396E00EAB194 /* String+Localization.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+Localization.swift"; sourceTree = "<group>"; };
|
||||
671461FF1EB3396E00EAB194 /* UIScrollView+Support.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIScrollView+Support.swift"; sourceTree = "<group>"; };
|
||||
671462011EB3396E00EAB194 /* TableDirector+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "TableDirector+Extensions.swift"; sourceTree = "<group>"; };
|
||||
671462031EB3396E00EAB194 /* TimeInterval+DateComponents.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "TimeInterval+DateComponents.swift"; sourceTree = "<group>"; };
|
||||
671462091EB3396E00EAB194 /* UIColor+Hex.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIColor+Hex.swift"; sourceTree = "<group>"; };
|
||||
6714620D1EB3396E00EAB194 /* UIImage+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIImage+Extensions.swift"; sourceTree = "<group>"; };
|
||||
6714620E1EB3396E00EAB194 /* UIImage+SupportExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIImage+SupportExtensions.swift"; sourceTree = "<group>"; };
|
||||
671462131EB3396E00EAB194 /* UIView+XibNameProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+XibNameProtocol.swift"; sourceTree = "<group>"; };
|
||||
671462141EB3396E00EAB194 /* UIView+LoadFromNib.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+LoadFromNib.swift"; sourceTree = "<group>"; };
|
||||
671462151EB3396E00EAB194 /* UIView+LoadingIndicator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+LoadingIndicator.swift"; sourceTree = "<group>"; };
|
||||
|
|
@ -1110,7 +1105,6 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
7295474121E6628C009558E7 /* UINavigationItem+Support.swift */,
|
||||
671461FF1EB3396E00EAB194 /* UIScrollView+Support.swift */,
|
||||
);
|
||||
path = Support;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -1145,7 +1139,6 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
6714620D1EB3396E00EAB194 /* UIImage+Extensions.swift */,
|
||||
6714620E1EB3396E00EAB194 /* UIImage+SupportExtensions.swift */,
|
||||
);
|
||||
path = UIImage;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -2470,7 +2463,6 @@
|
|||
671462841EB3396E00EAB194 /* CGContext+Initializers.swift in Sources */,
|
||||
EFBE57DB1EC361620040E00A /* UIView+Layout.swift in Sources */,
|
||||
6714634C1EB3396E00EAB194 /* ReuseIdentifierProtocol.swift in Sources */,
|
||||
671462F01EB3396E00EAB194 /* UIImage+SupportExtensions.swift in Sources */,
|
||||
6741CEAF20E242A500FEC4D9 /* TableViewHolder+ScrollViewHolder.swift in Sources */,
|
||||
67CAF8C620652E2A00527085 /* TextFieldViewModel.swift in Sources */,
|
||||
671462681EB3396E00EAB194 /* NetworkService.swift in Sources */,
|
||||
|
|
@ -2493,7 +2485,6 @@
|
|||
72005A1F2266226800ECE090 /* CustomizableButtonViewModel.swift in Sources */,
|
||||
677B06C4211884F3006C947D /* BaseTextAttributes.swift in Sources */,
|
||||
675E0AA921072FF400CDC143 /* BaseScrollContentController.swift in Sources */,
|
||||
671462D01EB3396E00EAB194 /* UIScrollView+Support.swift in Sources */,
|
||||
671463901EB3396E00EAB194 /* TemplateDrawingOperation.swift in Sources */,
|
||||
A658E54D1F8CD7790093527A /* TableRow+SeparatorsExtensions.swift in Sources */,
|
||||
85A5D49522AA975000C7D254 /* Decimal+Rounding.swift in Sources */,
|
||||
|
|
@ -2814,7 +2805,6 @@
|
|||
671463631EB3396E00EAB194 /* SupportProtocol.swift in Sources */,
|
||||
671462871EB3396E00EAB194 /* CGContext+Initializers.swift in Sources */,
|
||||
6714634F1EB3396E00EAB194 /* ReuseIdentifierProtocol.swift in Sources */,
|
||||
671462F31EB3396E00EAB194 /* UIImage+SupportExtensions.swift in Sources */,
|
||||
6714626B1EB3396E00EAB194 /* NetworkService.swift in Sources */,
|
||||
67E352612119B7570035BDDB /* BasePlaceholerView.swift in Sources */,
|
||||
673CF43A2063E7CE00C329F6 /* GeneralDataLoadingController+DefaultImplementation.swift in Sources */,
|
||||
|
|
|
|||
|
|
@ -162,7 +162,7 @@ final public class PaginationWrapper<Cursor: ResettableRxDataSourceCursor, Deleg
|
|||
|
||||
removeAllPlaceholderView()
|
||||
|
||||
wrappedView.scrollView.support.refreshControl?.endRefreshing()
|
||||
wrappedView.scrollView.refreshControl?.endRefreshing()
|
||||
|
||||
addInfiniteScroll(withHandler: true)
|
||||
} else if case .loadingMore = afterState {
|
||||
|
|
@ -176,7 +176,7 @@ final public class PaginationWrapper<Cursor: ResettableRxDataSourceCursor, Deleg
|
|||
private func onErrorState(error: Error, afterState: LoadingState) {
|
||||
if case .initialLoading = afterState {
|
||||
defer {
|
||||
wrappedView.scrollView.support.refreshControl?.endRefreshing()
|
||||
wrappedView.scrollView.refreshControl?.endRefreshing()
|
||||
}
|
||||
|
||||
delegate?.clearData()
|
||||
|
|
@ -222,7 +222,7 @@ final public class PaginationWrapper<Cursor: ResettableRxDataSourceCursor, Deleg
|
|||
|
||||
private func onEmptyState() {
|
||||
defer {
|
||||
wrappedView.scrollView.support.refreshControl?.endRefreshing()
|
||||
wrappedView.scrollView.refreshControl?.endRefreshing()
|
||||
}
|
||||
|
||||
delegate?.clearData()
|
||||
|
|
@ -297,7 +297,7 @@ final public class PaginationWrapper<Cursor: ResettableRxDataSourceCursor, Deleg
|
|||
let refreshControl = UIRefreshControl()
|
||||
refreshControl.addTarget(self, action: #selector(refreshAction), for: .valueChanged)
|
||||
|
||||
wrappedView.scrollView.support.setRefreshControl(refreshControl)
|
||||
wrappedView.scrollView.refreshControl = refreshControl
|
||||
}
|
||||
|
||||
@objc private func refreshAction() {
|
||||
|
|
@ -309,7 +309,7 @@ final public class PaginationWrapper<Cursor: ResettableRxDataSourceCursor, Deleg
|
|||
}
|
||||
|
||||
private func removeRefreshControl() {
|
||||
wrappedView.scrollView.support.setRefreshControl(nil)
|
||||
wrappedView.scrollView.refreshControl = nil
|
||||
}
|
||||
|
||||
private func bindViewModelStates() {
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ open class BaseSearchViewModel<Item, ItemViewModel>: GeneralDataLoadingViewModel
|
|||
}
|
||||
|
||||
open var searchDebounceInterval: RxTimeInterval {
|
||||
return 1
|
||||
return .seconds(1)
|
||||
}
|
||||
|
||||
open var searchResultsDriver: Driver<[ItemViewModel]> {
|
||||
|
|
|
|||
|
|
@ -144,7 +144,7 @@ public extension Observable {
|
|||
///
|
||||
/// - Parameter networkService: NetworkService to operate on it
|
||||
/// - Returns: The source sequence with the side-effecting behavior applied.
|
||||
func counterTracking(for networkService: NetworkService) -> Observable<Observable.E> {
|
||||
func counterTracking(for networkService: NetworkService) -> Observable<Observable.Element> {
|
||||
return `do`(onSubscribe: {
|
||||
networkService.increaseRequestCounter()
|
||||
}, onDispose: {
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
import Alamofire
|
||||
|
||||
/// Session Manager stored in NetworkService
|
||||
open class SessionManager: Alamofire.SessionManager {
|
||||
open class SessionManager: Alamofire.Session {
|
||||
|
||||
/// Response with HTTP URL Response and target object
|
||||
public typealias ModelResponse<T> = (response: HTTPURLResponse, model: T)
|
||||
|
|
@ -38,25 +38,40 @@ open class SessionManager: Alamofire.SessionManager {
|
|||
public let mappingQueue: DispatchQueue
|
||||
|
||||
public init(configuration: URLSessionConfiguration,
|
||||
serverTrustPolicyManager: ServerTrustPolicyManager,
|
||||
serverTrustManager: ServerTrustManager,
|
||||
acceptableStatusCodes: Set<Int>,
|
||||
mappingQueue: DispatchQueue) {
|
||||
|
||||
self.acceptableStatusCodes = acceptableStatusCodes
|
||||
self.mappingQueue = mappingQueue
|
||||
|
||||
super.init(configuration: configuration, serverTrustPolicyManager: serverTrustPolicyManager)
|
||||
let delegate = SessionDelegate()
|
||||
|
||||
let delegateQueue = OperationQueue()
|
||||
delegateQueue.underlyingQueue = mappingQueue
|
||||
|
||||
let session = URLSession(configuration: configuration, delegate: delegate, delegateQueue: delegateQueue)
|
||||
|
||||
super.init(session: session,
|
||||
delegate: delegate,
|
||||
rootQueue: mappingQueue,
|
||||
serverTrustManager: serverTrustManager)
|
||||
}
|
||||
|
||||
public init?(session: URLSession,
|
||||
delegate: SessionDelegate,
|
||||
serverTrustPolicyManager: ServerTrustPolicyManager,
|
||||
acceptableStatusCodes: Set<Int>,
|
||||
mappingQueue: DispatchQueue) {
|
||||
public init(session: URLSession,
|
||||
delegate: SessionDelegate,
|
||||
serverTrustManager: ServerTrustManager,
|
||||
acceptableStatusCodes: Set<Int>,
|
||||
mappingQueue: DispatchQueue) {
|
||||
|
||||
self.acceptableStatusCodes = acceptableStatusCodes
|
||||
self.mappingQueue = mappingQueue
|
||||
|
||||
super.init(session: session, delegate: delegate, serverTrustPolicyManager: serverTrustPolicyManager)
|
||||
session.delegateQueue.underlyingQueue = mappingQueue
|
||||
|
||||
super.init(session: session,
|
||||
delegate: delegate,
|
||||
rootQueue: mappingQueue,
|
||||
serverTrustManager: serverTrustManager)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -109,8 +109,9 @@ public extension BehaviorRelay {
|
|||
/// - getFieldClosure: Closure for getting field string reprerentation from data model.
|
||||
/// - mergeFieldClosure: Closure for merging new field value into data model.
|
||||
/// - Returns: DataModelFieldBinding instance.
|
||||
func fieldBinding(getFieldClosure: @escaping DataModelFieldBinding<E>.GetFieldClosure,
|
||||
mergeFieldClosure: @escaping DataModelFieldBinding<E>.MergeFieldClosure) -> DataModelFieldBinding<E> {
|
||||
func fieldBinding(getFieldClosure: @escaping DataModelFieldBinding<Element>.GetFieldClosure,
|
||||
mergeFieldClosure: @escaping DataModelFieldBinding<Element>.MergeFieldClosure)
|
||||
-> DataModelFieldBinding<Element> {
|
||||
|
||||
return DataModelFieldBinding(modelRelay: self,
|
||||
getFieldClosure: getFieldClosure,
|
||||
|
|
@ -123,7 +124,7 @@ public extension BehaviorRelay where Element == String? {
|
|||
/// Creates DataModelFieldBinding configured with behaviour relay itself.
|
||||
///
|
||||
/// - Returns: DataModelFieldBinding instance.
|
||||
func fieldBinding() -> DataModelFieldBinding<E> {
|
||||
func fieldBinding() -> DataModelFieldBinding<Element> {
|
||||
return DataModelFieldBinding(modelRelay: self)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,25 +70,25 @@ public extension Reactive where Base: DataRequest {
|
|||
}
|
||||
|
||||
private func response(onQueue queue: DispatchQueue) -> Observable<(HTTPURLResponse, Data)> {
|
||||
return responseResult(queue: queue, responseSerializer: DataRequest.dataResponseSerializer())
|
||||
return responseResult(queue: queue, responseSerializer: DataResponseSerializer())
|
||||
}
|
||||
}
|
||||
|
||||
public extension ObservableType where E == DataRequest {
|
||||
public extension ObservableType where Element == DataRequest {
|
||||
|
||||
/// Method that validates status codes and catch network errors
|
||||
///
|
||||
/// - Parameter statusCodes: set of status codes to validate
|
||||
/// - Returns: Observable on self
|
||||
func validate(statusCodes: Set<Int>) -> Observable<E> {
|
||||
func validate(statusCodes: Set<Int>) -> Observable<Element> {
|
||||
return map { $0.validate(statusCode: statusCodes) }
|
||||
.catchAsRequestError()
|
||||
}
|
||||
}
|
||||
|
||||
private extension ObservableType where E == ServerResponse {
|
||||
private extension ObservableType where Element == ServerResponse {
|
||||
|
||||
func tryMapResult<R>(_ transform: @escaping (E) throws -> R) -> Observable<R> {
|
||||
func tryMapResult<R>(_ transform: @escaping (Element) throws -> R) -> Observable<R> {
|
||||
return map {
|
||||
do {
|
||||
return try transform($0)
|
||||
|
|
@ -98,7 +98,7 @@ private extension ObservableType where E == ServerResponse {
|
|||
}
|
||||
}
|
||||
|
||||
func tryMapObservableResult<R>(_ transform: @escaping (E) throws -> Observable<R>) -> Observable<R> {
|
||||
func tryMapObservableResult<R>(_ transform: @escaping (Element) throws -> Observable<R>) -> Observable<R> {
|
||||
return flatMap { response, result -> Observable<R> in
|
||||
do {
|
||||
return try transform((response, result))
|
||||
|
|
@ -114,10 +114,10 @@ private extension ObservableType where E == ServerResponse {
|
|||
|
||||
private extension ObservableType {
|
||||
|
||||
func catchAsRequestError(with request: DataRequest? = nil) -> Observable<E> {
|
||||
func catchAsRequestError(with request: DataRequest? = nil) -> Observable<Element> {
|
||||
return catchError { error in
|
||||
let resultError: RequestError
|
||||
let response = request?.delegate.data
|
||||
let response = request?.data
|
||||
|
||||
switch error {
|
||||
case let requestError as RequestError:
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ public extension Reactive where Base: SessionManager {
|
|||
_ url: URLConvertible,
|
||||
parameters: [Any]? = nil,
|
||||
encoding: JSONEncoding = .default,
|
||||
headers: [String: String]? = nil)
|
||||
headers: HTTPHeaders? = nil)
|
||||
-> Observable<DataRequest> {
|
||||
|
||||
return Observable.deferred {
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@
|
|||
|
||||
import UIKit
|
||||
|
||||
@available(iOS 10.0, tvOS 10.0, *)
|
||||
public extension UIImage {
|
||||
|
||||
/// Creates an image filled by given color.
|
||||
|
|
@ -235,7 +234,6 @@ public extension UIImage {
|
|||
}
|
||||
}
|
||||
|
||||
@available(iOS 10.0, tvOS 10.0, *)
|
||||
internal extension DrawingOperation {
|
||||
|
||||
func imageFromNewRenderer(scale: CGFloat) -> UIImage {
|
||||
|
|
|
|||
|
|
@ -1,283 +0,0 @@
|
|||
//
|
||||
// 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 Support where Base: UIImage {
|
||||
|
||||
/// Creates an image filled by given color.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - color: The color to fill
|
||||
/// - size: The size of an new image.
|
||||
/// - Returns: A new instanse of UIImage with given size and color or nil if something goes wrong.
|
||||
static func imageWith(color: UIColor, size: CGSize) -> Support<UIImage>? {
|
||||
let width = Int(ceil(size.width))
|
||||
let height = Int(ceil(size.height))
|
||||
|
||||
let operation = SolidFillDrawingOperation(color: color.cgColor, width: width, height: height)
|
||||
|
||||
return operation.imageFromNewContext(scale: UIScreen.main.scale)?.support
|
||||
}
|
||||
|
||||
/// Creates an image from a UIView.
|
||||
///
|
||||
/// - Parameter fromView: The source view.
|
||||
/// - Returns: A new instance of UIImage or nil if something goes wrong.
|
||||
static func imageFrom(view: UIView) -> Support<UIImage>? {
|
||||
let operation = CALayerDrawingOperation(layer: view.layer, size: view.bounds.size)
|
||||
|
||||
guard let rotatedImage = operation.imageFromNewContext(scale: UIScreen.main.scale) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let flipOperation = rotatedImage.cgImage?.flipYOperation(size: rotatedImage.size)
|
||||
|
||||
return flipOperation?.imageFromNewContext(scale: rotatedImage.scale)?.support
|
||||
}
|
||||
|
||||
/// Render current template UIImage into new image using given color.
|
||||
///
|
||||
/// - Parameter color: Color to fill template image.
|
||||
/// - Returns: A new UIImage rendered with given color or nil if something goes wrong.
|
||||
func renderTemplate(withColor color: UIColor) -> Support<UIImage>? {
|
||||
return withCGImage { image in
|
||||
let operation = TemplateDrawingOperation(image: image,
|
||||
imageSize: base.size,
|
||||
color: color.cgColor)
|
||||
|
||||
guard let templateImage = operation.imageFromNewContext(scale: base.scale) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let flipOperation = templateImage.cgImage?.flipYOperation(size: templateImage.size)
|
||||
|
||||
return flipOperation?.imageFromNewContext(scale: templateImage.scale)
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new image with rounded corners and border.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - cornerRadius: The corner radius.
|
||||
/// - borderWidth: The size of the border.
|
||||
/// - color: The color of the border.
|
||||
/// - extendSize: Extend result image size and don't overlap source image by border.
|
||||
/// - Returns: A new image with rounded corners or nil if something goes wrong.
|
||||
func roundCorners(cornerRadius: CGFloat,
|
||||
borderWidth: CGFloat,
|
||||
color: UIColor,
|
||||
extendSize: Bool = false) -> Support<UIImage>? {
|
||||
|
||||
return withCGImage { image in
|
||||
let roundOperation = RoundDrawingOperation(image: image,
|
||||
imageSize: base.size,
|
||||
radius: cornerRadius)
|
||||
|
||||
guard let roundImage = roundOperation.cgImageFromNewContext(scale: base.scale) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let borderOperation = BorderDrawingOperation(image: roundImage,
|
||||
imageSize: base.size,
|
||||
border: borderWidth,
|
||||
color: color.cgColor,
|
||||
radius: cornerRadius,
|
||||
extendSize: extendSize)
|
||||
|
||||
return borderOperation.imageFromNewContext(scale: base.scale)
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new circle image.
|
||||
///
|
||||
/// - Returns: A new circled image or nil if something goes wrong.
|
||||
func roundCornersToCircle() -> Support<UIImage>? {
|
||||
return withCGImage { image in
|
||||
let radius = CGFloat(min(base.size.width, base.size.height) / 2)
|
||||
|
||||
let operation = RoundDrawingOperation(image: image,
|
||||
imageSize: base.size,
|
||||
radius: radius)
|
||||
|
||||
return operation.imageFromNewContext(scale: base.scale)
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new circle image with a border.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - borderWidth: The size of the border.
|
||||
/// - borderColor: The color of the border.
|
||||
/// - extendSize: Extend result image size and don't overlap source image by border (default = false).
|
||||
/// - Returns: A new image with rounded corners or nil if something goes wrong.
|
||||
func roundCornersToCircle(borderWidth: CGFloat,
|
||||
borderColor: UIColor,
|
||||
extendSize: Bool = false) -> Support<UIImage>? {
|
||||
|
||||
return withCGImage { image in
|
||||
let radius = CGFloat(min(base.size.width, base.size.height) / 2)
|
||||
|
||||
let roundOperation = RoundDrawingOperation(image: image,
|
||||
imageSize: base.size,
|
||||
radius: radius)
|
||||
|
||||
guard let roundImage = roundOperation.cgImageFromNewContext(scale: base.scale) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let borderOperation = BorderDrawingOperation(image: roundImage,
|
||||
imageSize: base.size,
|
||||
border: borderWidth,
|
||||
color: borderColor.cgColor,
|
||||
radius: radius,
|
||||
extendSize: extendSize)
|
||||
|
||||
return borderOperation.imageFromNewContext(scale: base.scale)
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a resized copy of an image.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - newSize: The new size of the image.
|
||||
/// - contentMode: The way to handle the content in the new size.
|
||||
/// - cropToImageBounds: Should output image size match resized image size.
|
||||
/// Note: If passed true with ResizeMode.scaleAspectFit content mode it will give the original image.
|
||||
/// - Returns: A new image scaled to new size.
|
||||
func resize(newSize: CGSize,
|
||||
contentMode: ResizeMode = .scaleToFill,
|
||||
cropToImageBounds: Bool = false) -> Support<UIImage>? {
|
||||
|
||||
return withCGImage { image in
|
||||
let operation = ResizeDrawingOperation(image: image,
|
||||
imageSize: base.size,
|
||||
preferredNewSize: newSize,
|
||||
resizeMode: contentMode,
|
||||
cropToImageBounds: cropToImageBounds)
|
||||
|
||||
return operation.imageFromNewContext(scale: base.scale)
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds an alpha channel if UIImage doesn't already have one.
|
||||
///
|
||||
/// - Returns: A copy of the given image, adding an alpha channel if it doesn't already have one.
|
||||
func applyAlpha() -> Support<UIImage>? {
|
||||
return withCGImage { image in
|
||||
let operation = ImageDrawingOperation(image: image,
|
||||
newSize: base.size,
|
||||
opaque: false)
|
||||
|
||||
return operation.imageFromNewContext(scale: base.scale)
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a copy of the image with border of the given size added around its edges.
|
||||
///
|
||||
/// - Parameter padding: The padding amount.
|
||||
/// - Returns: A new padded image or nil if something goes wrong.
|
||||
func applyPadding(_ padding: CGFloat) -> Support<UIImage>? {
|
||||
return withCGImage { image in
|
||||
let operation = PaddingDrawingOperation(image: image,
|
||||
imageSize: base.size,
|
||||
padding: padding)
|
||||
|
||||
return operation.imageFromNewContext(scale: base.scale)
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a copy of the image rotated by the given amount of degrees.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - degrees: The number of degrees.
|
||||
/// - clockwise: Should rotate image clockwise.
|
||||
/// - Returns: A new rotated image or nil if something goes wrong.
|
||||
func rotate(degrees: CGFloat, clockwise: Bool = true) -> Support<UIImage>? {
|
||||
return withCGImage { image in
|
||||
let radians = degrees.degreesToRadians()
|
||||
|
||||
let operation = RotateDrawingOperation(image: image,
|
||||
imageSize: base.size,
|
||||
radians: radians,
|
||||
clockwise: clockwise)
|
||||
|
||||
guard let rotatedImage = operation.imageFromNewContext(scale: base.scale) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let flipOperation = rotatedImage.cgImage?.flipYOperation(size: rotatedImage.size)
|
||||
|
||||
return flipOperation?.imageFromNewContext(scale: rotatedImage.scale)
|
||||
}
|
||||
}
|
||||
|
||||
private func withCGImage(_ actionClosure: (CGImage) -> UIImage?) -> Support<UIImage>? {
|
||||
guard let image = base.cgImage else {
|
||||
return Support<UIImage>(base)
|
||||
}
|
||||
|
||||
return actionClosure(image)?.support
|
||||
}
|
||||
}
|
||||
|
||||
private extension CGImage {
|
||||
|
||||
func flipYOperation(size: CGSize) -> ImageDrawingOperation {
|
||||
return ImageDrawingOperation(image: self,
|
||||
newSize: size,
|
||||
origin: .zero,
|
||||
opaque: false,
|
||||
flipY: true)
|
||||
}
|
||||
}
|
||||
|
||||
private extension DrawingOperation {
|
||||
|
||||
func cgImageFromNewContext(scale: CGFloat) -> CGImage? {
|
||||
let ctxSize = contextSize
|
||||
|
||||
let intScale = Int(scale)
|
||||
|
||||
let context = CGContext.create(width: ctxSize.width * intScale,
|
||||
height: ctxSize.height * intScale,
|
||||
bitmapInfo: opaque ? .opaqueBitmapInfo : .alphaBitmapInfo)
|
||||
|
||||
guard let ctx = context else {
|
||||
return nil
|
||||
}
|
||||
|
||||
ctx.scaleBy(x: scale, y: scale)
|
||||
|
||||
apply(in: ctx)
|
||||
|
||||
return ctx.makeImage()
|
||||
}
|
||||
|
||||
func imageFromNewContext(scale: CGFloat) -> UIImage? {
|
||||
guard let image = cgImageFromNewContext(scale: scale) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return UIImage(cgImage: image, scale: scale, orientation: .up)
|
||||
}
|
||||
}
|
||||
|
|
@ -51,7 +51,7 @@ public extension ObservableType {
|
|||
/// - handler: closure that recieves serialized response
|
||||
/// - Returns: Observable on caller
|
||||
func handleMappingError<T: Decodable>(with decoder: JSONDecoder = JSONDecoder(),
|
||||
handler: @escaping ParameterClosure<T>) -> Observable<E> {
|
||||
handler: @escaping ParameterClosure<T>) -> Observable<Element> {
|
||||
return self.do(onError: { error in
|
||||
guard let errorModel = try error.handleMappingError(with: decoder) as T? else {
|
||||
return
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ public extension ObservableType {
|
|||
/// - Parameter elementFactory: Element factory function to invoke for each observer
|
||||
/// 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 -> E) -> Observable<E> {
|
||||
static func deferredJust(_ elementFactory: @escaping () throws -> Element) -> Observable<Element> {
|
||||
return .create { observer in
|
||||
do {
|
||||
observer.onNext(try elementFactory())
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ public extension ObservableType {
|
|||
/// Cast all emitted elements to optional type.
|
||||
///
|
||||
/// - Returns: An observable sequence whose elements are equals to optional type of element.
|
||||
func asOptional() -> Observable<E?> {
|
||||
func asOptional() -> Observable<Element?> {
|
||||
return map { $0 }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,5 +63,6 @@ public extension Sequence {
|
|||
array.sorted { $0.idx < $1.idx }
|
||||
.flatMap { $0.results }
|
||||
}
|
||||
.asObservable()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,47 +0,0 @@
|
|||
//
|
||||
// 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 Support where Base: UIScrollView {
|
||||
|
||||
var refreshControl: UIRefreshControl? {
|
||||
if #available(iOS 10.0, *) {
|
||||
return base.refreshControl
|
||||
} else {
|
||||
return base.subviews.first { $0 is UIRefreshControl } as? UIRefreshControl
|
||||
}
|
||||
}
|
||||
|
||||
func setRefreshControl(_ newRefreshControl: UIRefreshControl?) {
|
||||
if #available(iOS 10.0, *) {
|
||||
base.refreshControl = newRefreshControl
|
||||
} else {
|
||||
if let newControl = newRefreshControl {
|
||||
refreshControl?.removeFromSuperview()
|
||||
base.addSubview(newControl)
|
||||
} else {
|
||||
refreshControl?.removeFromSuperview()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -15,7 +15,7 @@
|
|||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.9.28</string>
|
||||
<string>$(MARKETING_VERSION)</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ public struct NetworkServiceConfiguration {
|
|||
public let additionalHttpHeaders: HTTPHeaders
|
||||
|
||||
/// Server trust policies.
|
||||
public var serverTrustPolicies: [String: ServerTrustPolicy]
|
||||
public var serverTrustPolicies: [String: ServerTrustEvaluating]
|
||||
|
||||
/// HTTP response status codes regarded as non-erroneous
|
||||
public var acceptableStatusCodes: Set<Int> = Set(200..<300)
|
||||
|
|
@ -48,20 +48,19 @@ public struct NetworkServiceConfiguration {
|
|||
public init(baseUrl: String,
|
||||
timeoutInterval: TimeInterval = 20,
|
||||
encoding: ParameterEncoding = URLEncoding.default,
|
||||
additionalHttpHeaders: HTTPHeaders = [:],
|
||||
trustPolicies: [String: ServerTrustPolicy] = [:]) {
|
||||
additionalHttpHeaders: [String: String] = [:],
|
||||
trustPolicies: [String: ServerTrustEvaluating] = [:]) {
|
||||
|
||||
self.baseUrl = baseUrl
|
||||
self.timeoutInterval = timeoutInterval
|
||||
self.encoding = encoding
|
||||
self.additionalHttpHeaders = additionalHttpHeaders.merging(SessionManager.defaultHTTPHeaders) { current, _ in current }
|
||||
self.additionalHttpHeaders = HTTPHeaders(additionalHttpHeaders)
|
||||
|
||||
sessionConfiguration = URLSessionConfiguration.default
|
||||
sessionConfiguration.timeoutIntervalForResource = timeoutInterval
|
||||
sessionConfiguration.httpAdditionalHeaders = additionalHttpHeaders
|
||||
|
||||
let updatedPolicies = Dictionary(uniqueKeysWithValues: trustPolicies.map { ($0.key.asHost, $0.value) })
|
||||
serverTrustPolicies = trustPolicies.isEmpty ? [baseUrl.asHost: .disableEvaluation] : updatedPolicies
|
||||
serverTrustPolicies = Dictionary(uniqueKeysWithValues: trustPolicies.map { ($0.key.asHost, $0.value) })
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -70,7 +69,8 @@ public extension NetworkServiceConfiguration {
|
|||
/// SessionManager constructed with given parameters (session configuration and trust policies)
|
||||
var sessionManager: SessionManager {
|
||||
return SessionManager(configuration: sessionConfiguration,
|
||||
serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies),
|
||||
serverTrustManager: ServerTrustManager(allHostsMustBeEvaluated: !serverTrustPolicies.isEmpty,
|
||||
evaluators: serverTrustPolicies),
|
||||
acceptableStatusCodes: acceptableStatusCodes,
|
||||
mappingQueue: .global())
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue