Merge branch 'master' into feature/usefull

This commit is contained in:
Alexey Gerasimov 2017-05-10 22:11:24 +03:00 committed by GitHub
commit bf69f5e782
18 changed files with 352 additions and 111 deletions

View File

@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "LeadKit"
s.version = "0.5.0"
s.version = "0.5.1"
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"
@ -42,10 +42,11 @@ Pod::Spec.new do |s|
ss.watchos.exclude_files = [
"LeadKit/Sources/Classes/Pagination/PaginationTableViewWrapper.swift",
"LeadKit/Sources/Classes/Views/XibView.swift",
"LeadKit/Sources/Classes/Views/SpinnerView.swift",
"LeadKit/Sources/Extensions/CABasicAnimation/*",
"LeadKit/Sources/Extensions/CGFloat/CGFloat+Pixels.swift",
"LeadKit/Sources/Extensions/NetworkService/NetworkService+ActivityIndicator.swift",
"LeadKit/Sources/Extensions/NetworkService/NetworkService+RxLoadImage.swift",
"LeadKit/Sources/Extensions/Observable/Observable+ToastErrorLogging.swift",
"LeadKit/Sources/Extensions/PaginationTableViewWrapperDelegate/PaginationTableViewWrapperDelegate+DefaultImplementation.swift",
"LeadKit/Sources/Extensions/StoryboardProtocol/*",
"LeadKit/Sources/Extensions/Support/UIScrollView+Support.swift",
@ -69,7 +70,6 @@ Pod::Spec.new do |s|
"LeadKit/Sources/Classes/Pagination/PaginationTableViewWrapper.swift",
"LeadKit/Sources/Structures/Drawing/CALayerDrawingOperation.swift",
"LeadKit/Sources/Extensions/NetworkService/NetworkService+ActivityIndicator.swift",
"LeadKit/Sources/Extensions/Observable/Observable+ToastErrorLogging.swift",
"LeadKit/Sources/Extensions/PaginationTableViewWrapperDelegate/PaginationTableViewWrapperDelegate+DefaultImplementation.swift",
"LeadKit/Sources/Extensions/Support/UIScrollView+Support.swift",
"LeadKit/Sources/Extensions/TableDirector/TableDirector+Extensions.swift",
@ -81,7 +81,6 @@ Pod::Spec.new do |s|
ss.dependency "RxAlamofire", '3.0.2'
ss.dependency "ObjectMapper", '~> 2.2'
ss.ios.dependency "Toast-Swift", '~> 2.0.0'
ss.ios.dependency "TableKit", '~> 2.3.1'
ss.ios.dependency "UIScrollView-InfiniteScroll", '~> 1.0.0'
end
@ -94,13 +93,10 @@ Pod::Spec.new do |s|
ss.exclude_files = [
"LeadKit/Sources/Classes/Pagination/PaginationTableViewWrapper.swift",
"LeadKit/Sources/Extensions/NetworkService/NetworkService+ActivityIndicator.swift",
"LeadKit/Sources/Extensions/Observable/Observable+ToastErrorLogging.swift",
"LeadKit/Sources/Extensions/PaginationTableViewWrapperDelegate/PaginationTableViewWrapperDelegate+DefaultImplementation.swift",
"LeadKit/Sources/Extensions/TableDirector/TableDirector+Extensions.swift",
]
ss.pod_target_xcconfig = { 'SWIFT_ACTIVE_COMPILATION_CONDITIONS' => 'LEADKIT_EXTENSION_TARGET' }
ss.dependency "CocoaLumberjack/Swift", '~> 3.1.0'
ss.dependency "RxSwift", '3.4.0'
ss.dependency "RxCocoa", '3.4.0'

View File

@ -10,6 +10,9 @@
2D6A0E6105F4A9BF22BF4BB1 /* Pods_LeadKit_iOS_ExtensionsTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3C88ED8C9373F85C06697849 /* Pods_LeadKit_iOS_ExtensionsTests.framework */; };
2D96F18874B9519F5AD74003 /* Pods_LeadKit_LeadKit_tvOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0F8D0002B21A4F31981F1ED /* Pods_LeadKit_LeadKit_tvOS.framework */; };
3614FEACB9E8313C87F7C393 /* Pods_LeadKit_tvOSTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4DB1CCAB1EAAACD3AC42C795 /* Pods_LeadKit_tvOSTests.framework */; };
67051ADB1EBC7C36008EADC0 /* SpinnerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67051ADA1EBC7C36008EADC0 /* SpinnerView.swift */; };
67051ADC1EBC7C36008EADC0 /* SpinnerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67051ADA1EBC7C36008EADC0 /* SpinnerView.swift */; };
67051ADD1EBC7C36008EADC0 /* SpinnerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67051ADA1EBC7C36008EADC0 /* SpinnerView.swift */; };
671462441EB3396E00EAB194 /* Mutex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671461C61EB3396E00EAB194 /* Mutex.swift */; };
671462451EB3396E00EAB194 /* Mutex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671461C61EB3396E00EAB194 /* Mutex.swift */; };
671462461EB3396E00EAB194 /* Mutex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671461C61EB3396E00EAB194 /* Mutex.swift */; };
@ -113,7 +116,6 @@
671462AD1EB3396E00EAB194 /* Observable+DeferredJust.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671461F11EB3396E00EAB194 /* Observable+DeferredJust.swift */; };
671462AE1EB3396E00EAB194 /* Observable+DeferredJust.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671461F11EB3396E00EAB194 /* Observable+DeferredJust.swift */; };
671462AF1EB3396E00EAB194 /* Observable+DeferredJust.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671461F11EB3396E00EAB194 /* Observable+DeferredJust.swift */; };
671462B01EB3396E00EAB194 /* Observable+ToastErrorLogging.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671461F21EB3396E00EAB194 /* Observable+ToastErrorLogging.swift */; };
671462B41EB3396E00EAB194 /* PaginationTableViewWrapperDelegate+DefaultImplementation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671461F41EB3396E00EAB194 /* PaginationTableViewWrapperDelegate+DefaultImplementation.swift */; };
671462B81EB3396E00EAB194 /* Sequence+ConcurrentMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671461F61EB3396E00EAB194 /* Sequence+ConcurrentMap.swift */; };
671462B91EB3396E00EAB194 /* Sequence+ConcurrentMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671461F61EB3396E00EAB194 /* Sequence+ConcurrentMap.swift */; };
@ -351,10 +353,20 @@
67952C3D1EB3266200B3BA1A /* LeadKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 67186B201EB247A200CFAFFB /* LeadKit.h */; settings = {ATTRIBUTES = (Public, ); }; };
67952DCE1EB327B500B3BA1A /* LeadKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 67952DC51EB327B400B3BA1A /* LeadKit.framework */; };
67952DDD1EB3281300B3BA1A /* LeadKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 67186B201EB247A200CFAFFB /* LeadKit.h */; settings = {ATTRIBUTES = (Public, ); }; };
67A1FF8F1EBCA09B00D6C89F /* UIImage+Spinner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67A1FF8E1EBCA09B00D6C89F /* UIImage+Spinner.swift */; };
67A1FF901EBCA09B00D6C89F /* UIImage+Spinner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67A1FF8E1EBCA09B00D6C89F /* UIImage+Spinner.swift */; };
67A1FF911EBCA09B00D6C89F /* UIImage+Spinner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67A1FF8E1EBCA09B00D6C89F /* UIImage+Spinner.swift */; };
67A1FF941EBCA65E00D6C89F /* CABasicAnimation+Rotation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67A1FF931EBCA65E00D6C89F /* CABasicAnimation+Rotation.swift */; };
67A1FF951EBCA65E00D6C89F /* CABasicAnimation+Rotation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67A1FF931EBCA65E00D6C89F /* CABasicAnimation+Rotation.swift */; };
67A1FF971EBCA65E00D6C89F /* CABasicAnimation+Rotation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67A1FF931EBCA65E00D6C89F /* CABasicAnimation+Rotation.swift */; };
67CDEE401EB369BF00895905 /* ConfigurableController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671462241EB3396E00EAB194 /* ConfigurableController.swift */; };
67CDEE421EB3AD1C00895905 /* NetworkService+RxLoadImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67CDEE411EB3AD1C00895905 /* NetworkService+RxLoadImage.swift */; };
67CDEE431EB3AD1C00895905 /* NetworkService+RxLoadImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67CDEE411EB3AD1C00895905 /* NetworkService+RxLoadImage.swift */; };
67CDEE441EB3AD1C00895905 /* NetworkService+RxLoadImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67CDEE411EB3AD1C00895905 /* NetworkService+RxLoadImage.swift */; };
67E6C2351EBB32F5007842A6 /* SingleLoadCursor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67E6C2341EBB32F5007842A6 /* SingleLoadCursor.swift */; };
67E6C2361EBB32F5007842A6 /* SingleLoadCursor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67E6C2341EBB32F5007842A6 /* SingleLoadCursor.swift */; };
67E6C2371EBB32F5007842A6 /* SingleLoadCursor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67E6C2341EBB32F5007842A6 /* SingleLoadCursor.swift */; };
67E6C2381EBB32F5007842A6 /* SingleLoadCursor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67E6C2341EBB32F5007842A6 /* SingleLoadCursor.swift */; };
BA6C6DB45950382041948FC5 /* Pods_LeadKit_LeadKit_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CFE9323150A9760008093F73 /* Pods_LeadKit_LeadKit_iOS.framework */; };
D6EE55093E404DEA62B03DDF /* Pods_LeadKit_LeadKit_watchOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8590CA7831555C295C5DC572 /* Pods_LeadKit_LeadKit_watchOS.framework */; };
DEE25FE98D40ED1C168F384A /* Pods_LeadKit_LeadKit_iOS_Extensions.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 887F99C5326BD220C2811BD6 /* Pods_LeadKit_LeadKit_iOS_Extensions.framework */; };
@ -416,6 +428,7 @@
563DDE9CACD515FDCB5A2FFF /* Pods-LeadKit-LeadKit tvOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-LeadKit-LeadKit tvOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-LeadKit-LeadKit tvOS/Pods-LeadKit-LeadKit tvOS.release.xcconfig"; sourceTree = "<group>"; };
56C11305E2B44404FFFD12AA /* Pods_LeadKit_watchOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_LeadKit_watchOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
65B19DB0B65A1EE1A1E2C907 /* Pods-LeadKit tvOSTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-LeadKit tvOSTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-LeadKit tvOSTests/Pods-LeadKit tvOSTests.debug.xcconfig"; sourceTree = "<group>"; };
67051ADA1EBC7C36008EADC0 /* SpinnerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SpinnerView.swift; sourceTree = "<group>"; };
671461C61EB3396E00EAB194 /* Mutex.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Mutex.swift; sourceTree = "<group>"; };
671461C81EB3396E00EAB194 /* FixedPageCursor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FixedPageCursor.swift; sourceTree = "<group>"; };
671461C91EB3396E00EAB194 /* MapCursor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MapCursor.swift; sourceTree = "<group>"; };
@ -443,7 +456,6 @@
671461ED1EB3396E00EAB194 /* IndexPath+ImmutableIndexPath.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "IndexPath+ImmutableIndexPath.swift"; sourceTree = "<group>"; };
671461EF1EB3396E00EAB194 /* ImmutableMappable+ObservableMappable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ImmutableMappable+ObservableMappable.swift"; sourceTree = "<group>"; };
671461F11EB3396E00EAB194 /* Observable+DeferredJust.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Observable+DeferredJust.swift"; sourceTree = "<group>"; };
671461F21EB3396E00EAB194 /* Observable+ToastErrorLogging.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Observable+ToastErrorLogging.swift"; sourceTree = "<group>"; };
671461F41EB3396E00EAB194 /* PaginationTableViewWrapperDelegate+DefaultImplementation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "PaginationTableViewWrapperDelegate+DefaultImplementation.swift"; sourceTree = "<group>"; };
671461F61EB3396E00EAB194 /* Sequence+ConcurrentMap.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Sequence+ConcurrentMap.swift"; sourceTree = "<group>"; };
671461F81EB3396E00EAB194 /* StoryboardProtocol+DefaultBundle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "StoryboardProtocol+DefaultBundle.swift"; sourceTree = "<group>"; };
@ -528,7 +540,10 @@
67952DCD1EB327B400B3BA1A /* LeadKit iOS ExtensionsTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "LeadKit iOS ExtensionsTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
67952DDC1EB3280900B3BA1A /* Info-iOS-Extensions.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Info-iOS-Extensions.plist"; sourceTree = "<group>"; };
67952DDE1EB3285A00B3BA1A /* Info-iOS-Extensions.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Info-iOS-Extensions.plist"; sourceTree = "<group>"; };
67A1FF8E1EBCA09B00D6C89F /* UIImage+Spinner.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIImage+Spinner.swift"; sourceTree = "<group>"; };
67A1FF931EBCA65E00D6C89F /* CABasicAnimation+Rotation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CABasicAnimation+Rotation.swift"; sourceTree = "<group>"; };
67CDEE411EB3AD1C00895905 /* NetworkService+RxLoadImage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NetworkService+RxLoadImage.swift"; sourceTree = "<group>"; };
67E6C2341EBB32F5007842A6 /* SingleLoadCursor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SingleLoadCursor.swift; sourceTree = "<group>"; };
78405D3B3D3C3E17456877FF /* Pods_LeadKit_iOSTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_LeadKit_iOSTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
8590CA7831555C295C5DC572 /* Pods_LeadKit_LeadKit_watchOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_LeadKit_LeadKit_watchOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
887F99C5326BD220C2811BD6 /* Pods_LeadKit_LeadKit_iOS_Extensions.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_LeadKit_LeadKit_iOS_Extensions.framework; sourceTree = BUILT_PRODUCTS_DIR; };
@ -638,6 +653,7 @@
671461C81EB3396E00EAB194 /* FixedPageCursor.swift */,
671461C91EB3396E00EAB194 /* MapCursor.swift */,
671461CA1EB3396E00EAB194 /* StaticCursor.swift */,
67E6C2341EBB32F5007842A6 /* SingleLoadCursor.swift */,
);
path = Cursors;
sourceTree = "<group>";
@ -673,6 +689,7 @@
isa = PBXGroup;
children = (
671461D51EB3396E00EAB194 /* XibView.swift */,
67051ADA1EBC7C36008EADC0 /* SpinnerView.swift */,
);
path = Views;
sourceTree = "<group>";
@ -692,6 +709,7 @@
children = (
671461DB1EB3396E00EAB194 /* Alamofire */,
EFBE57CE1EC35ED90040E00A /* Array */,
67A1FF921EBCA64A00D6C89F /* CABasicAnimation */,
671461DE1EB3396E00EAB194 /* CGContext */,
671461E01EB3396E00EAB194 /* CGFloat */,
671461E21EB3396E00EAB194 /* CGImage */,
@ -803,7 +821,6 @@
isa = PBXGroup;
children = (
671461F11EB3396E00EAB194 /* Observable+DeferredJust.swift */,
671461F21EB3396E00EAB194 /* Observable+ToastErrorLogging.swift */,
);
path = Observable;
sourceTree = "<group>";
@ -904,6 +921,7 @@
children = (
6714620D1EB3396E00EAB194 /* UIImage+Extensions.swift */,
6714620E1EB3396E00EAB194 /* UIImage+SupportExtensions.swift */,
67A1FF8E1EBCA09B00D6C89F /* UIImage+Spinner.swift */,
);
path = UIImage;
sourceTree = "<group>";
@ -1102,6 +1120,14 @@
path = Tests;
sourceTree = "<group>";
};
67A1FF921EBCA64A00D6C89F /* CABasicAnimation */ = {
isa = PBXGroup;
children = (
67A1FF931EBCA65E00D6C89F /* CABasicAnimation+Rotation.swift */,
);
path = CABasicAnimation;
sourceTree = "<group>";
};
78CFEE201C5C456B00F50370 = {
isa = PBXGroup;
children = (
@ -1897,6 +1923,7 @@
671462441EB3396E00EAB194 /* Mutex.swift in Sources */,
671463401EB3396E00EAB194 /* ModuleConfigurator.swift in Sources */,
671462641EB3396E00EAB194 /* PaginationViewModel.swift in Sources */,
67A1FF8F1EBCA09B00D6C89F /* UIImage+Spinner.swift in Sources */,
671462901EB3396E00EAB194 /* CGImage+Crop.swift in Sources */,
671462FC1EB3396E00EAB194 /* UIView+DefaultXibName.swift in Sources */,
671463841EB3396E00EAB194 /* ResizeDrawingOperation.swift in Sources */,
@ -1905,7 +1932,9 @@
6714630C1EB3396E00EAB194 /* UIViewController+DefaultStoryboardIdentifier.swift in Sources */,
671462981EB3396E00EAB194 /* CGSize+Resize.swift in Sources */,
671462F81EB3396E00EAB194 /* UIView+DefaultReuseIdentifier.swift in Sources */,
67051ADB1EBC7C36008EADC0 /* SpinnerView.swift in Sources */,
671463581EB3396E00EAB194 /* StoryboardIdentifierProtocol.swift in Sources */,
67A1FF941EBCA65E00D6C89F /* CABasicAnimation+Rotation.swift in Sources */,
671463301EB3396E00EAB194 /* CursorType.swift in Sources */,
6714624C1EB3396E00EAB194 /* MapCursor.swift in Sources */,
671463241EB3396E00EAB194 /* Any+TypeName.swift in Sources */,
@ -1945,13 +1974,13 @@
671463141EB3396E00EAB194 /* UIViewController+TopVisibleViewController.swift in Sources */,
671462881EB3396E00EAB194 /* CGFloat+Pixels.swift in Sources */,
671462941EB3396E00EAB194 /* CGSize+CGContextSize.swift in Sources */,
671462B01EB3396E00EAB194 /* Observable+ToastErrorLogging.swift in Sources */,
671463641EB3396E00EAB194 /* ViewHeightProtocol.swift in Sources */,
671462481EB3396E00EAB194 /* FixedPageCursor.swift in Sources */,
671462C81EB3396E00EAB194 /* String+Localization.swift in Sources */,
671462B81EB3396E00EAB194 /* Sequence+ConcurrentMap.swift in Sources */,
671463741EB3396E00EAB194 /* BorderDrawingOperation.swift in Sources */,
6714633C1EB3396E00EAB194 /* LoadingIndicator.swift in Sources */,
67E6C2351EBB32F5007842A6 /* SingleLoadCursor.swift in Sources */,
671463181EB3396E00EAB194 /* UIWindow+Extensions.swift in Sources */,
671462541EB3396E00EAB194 /* App.swift in Sources */,
6714635C1EB3396E00EAB194 /* StoryboardProtocol.swift in Sources */,
@ -1996,6 +2025,7 @@
EFBE57D21EC35EF20040E00A /* Array+Extensions.swift in Sources */,
671462821EB3396E00EAB194 /* AlamofireRequest+Extensions.swift in Sources */,
671462C61EB3396E00EAB194 /* String+Extensions.swift in Sources */,
67E6C2371EBB32F5007842A6 /* SingleLoadCursor.swift in Sources */,
671463561EB3396E00EAB194 /* StaticViewHeightProtocol.swift in Sources */,
671462AA1EB3396E00EAB194 /* ImmutableMappable+ObservableMappable.swift in Sources */,
671463621EB3396E00EAB194 /* SupportProtocol.swift in Sources */,
@ -2111,6 +2141,7 @@
671462A71EB3396E00EAB194 /* IndexPath+ImmutableIndexPath.swift in Sources */,
671462BF1EB3396E00EAB194 /* StoryboardProtocol+DefaultBundle.swift in Sources */,
EFBE57DE1EC361620040E00A /* UIView+Layout.swift in Sources */,
67A1FF971EBCA65E00D6C89F /* CABasicAnimation+Rotation.swift in Sources */,
671462A31EB3396E00EAB194 /* Double+Rounding.swift in Sources */,
6714625F1EB3396E00EAB194 /* LogFormatter.swift in Sources */,
6714630B1EB3396E00EAB194 /* UIView+Rotation.swift in Sources */,
@ -2126,6 +2157,7 @@
6714628B1EB3396E00EAB194 /* CGFloat+Pixels.swift in Sources */,
671462971EB3396E00EAB194 /* CGSize+CGContextSize.swift in Sources */,
671463671EB3396E00EAB194 /* ViewHeightProtocol.swift in Sources */,
67A1FF911EBCA09B00D6C89F /* UIImage+Spinner.swift in Sources */,
6714624B1EB3396E00EAB194 /* FixedPageCursor.swift in Sources */,
671462CB1EB3396E00EAB194 /* String+Localization.swift in Sources */,
671462BB1EB3396E00EAB194 /* Sequence+ConcurrentMap.swift in Sources */,
@ -2139,9 +2171,11 @@
6714633B1EB3396E00EAB194 /* EstimatedViewHeightProtocol.swift in Sources */,
6714632F1EB3396E00EAB194 /* ConfigurableController.swift in Sources */,
6714628F1EB3396E00EAB194 /* CGImage+Alpha.swift in Sources */,
67051ADD1EBC7C36008EADC0 /* SpinnerView.swift in Sources */,
671462771EB3396E00EAB194 /* LeadKitError.swift in Sources */,
671462DB1EB3396E00EAB194 /* TimeInterval+DateComponents.swift in Sources */,
6714638F1EB3396E00EAB194 /* SolidFillDrawingOperation.swift in Sources */,
67E6C2381EBB32F5007842A6 /* SingleLoadCursor.swift in Sources */,
671462531EB3396E00EAB194 /* StaticCursor.swift in Sources */,
6714629F1EB3396E00EAB194 /* CursorType+Slice.swift in Sources */,
6714636B1EB3396E00EAB194 /* ViewModelProtocol.swift in Sources */,
@ -2170,8 +2204,10 @@
671463491EB3396E00EAB194 /* ResettableType.swift in Sources */,
671462E51EB3396E00EAB194 /* UIColor+Hex.swift in Sources */,
671462CD1EB3396E00EAB194 /* String+SizeCalculation.swift in Sources */,
67A1FF951EBCA65E00D6C89F /* CABasicAnimation+Rotation.swift in Sources */,
671462811EB3396E00EAB194 /* AlamofireRequest+Extensions.swift in Sources */,
671462C51EB3396E00EAB194 /* String+Extensions.swift in Sources */,
67E6C2361EBB32F5007842A6 /* SingleLoadCursor.swift in Sources */,
671463551EB3396E00EAB194 /* StaticViewHeightProtocol.swift in Sources */,
671462A91EB3396E00EAB194 /* ImmutableMappable+ObservableMappable.swift in Sources */,
671463611EB3396E00EAB194 /* SupportProtocol.swift in Sources */,
@ -2186,6 +2222,7 @@
671463411EB3396E00EAB194 /* ModuleConfigurator.swift in Sources */,
671462651EB3396E00EAB194 /* PaginationViewModel.swift in Sources */,
671462911EB3396E00EAB194 /* CGImage+Crop.swift in Sources */,
67051ADC1EBC7C36008EADC0 /* SpinnerView.swift in Sources */,
671462FD1EB3396E00EAB194 /* UIView+DefaultXibName.swift in Sources */,
671463851EB3396E00EAB194 /* ResizeDrawingOperation.swift in Sources */,
671462D11EB3396E00EAB194 /* UIScrollView+Support.swift in Sources */,
@ -2239,6 +2276,7 @@
EFBE57DC1EC361620040E00A /* UIView+Layout.swift in Sources */,
671462551EB3396E00EAB194 /* App.swift in Sources */,
6714635D1EB3396E00EAB194 /* StoryboardProtocol.swift in Sources */,
67A1FF901EBCA09B00D6C89F /* UIImage+Spinner.swift in Sources */,
671462F51EB3396E00EAB194 /* UIStoryboard+InstantiateViewController.swift in Sources */,
671463791EB3396E00EAB194 /* CALayerDrawingOperation.swift in Sources */,
671463391EB3396E00EAB194 /* EstimatedViewHeightProtocol.swift in Sources */,
@ -2549,7 +2587,7 @@
PRODUCT_BUNDLE_IDENTIFIER = "ru.touchin.LeadKit-iOS-Extensions";
PRODUCT_NAME = LeadKit;
SKIP_INSTALL = YES;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG LEADKIT_EXTENSION_TARGET";
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_VERSION = 3.0;
};
name = Debug;
@ -2575,7 +2613,6 @@
PRODUCT_BUNDLE_IDENTIFIER = "ru.touchin.LeadKit-iOS-Extensions";
PRODUCT_NAME = LeadKit;
SKIP_INSTALL = YES;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = LEADKIT_EXTENSION_TARGET;
SWIFT_VERSION = 3.0;
};
name = Release;

View File

@ -12,7 +12,6 @@ abstract_target 'LeadKit' do
use_frameworks!
pod "Toast-Swift", '~> 2.0.0'
pod "TableKit", '~> 2.3.1'
pod "UIScrollView-InfiniteScroll", '~> 1.0.0'

View File

@ -49,10 +49,10 @@ public class FixedPageCursor<Cursor: CursorType>: CursorType {
return cursor[index]
}
public func loadNextBatch() -> Observable<[Cursor.Element]> {
return Observable.deferred {
public func loadNextBatch() -> Single<[Cursor.Element]> {
return Single.deferred {
if self.exhausted {
throw CursorError.exhausted
return .error(CursorError.exhausted)
}
let restOfLoaded = self.cursor.count - self.count

View File

@ -77,7 +77,7 @@ public class MapCursor<Cursor: CursorType, T>: CursorType {
return elements[index]
}
public func loadNextBatch() -> Observable<[T]> {
public func loadNextBatch() -> Single<[T]> {
return cursor.loadNextBatch().map { newItems in
let transformedNewItems = newItems.flatMap(self.transform)
self.elements += transformedNewItems

View File

@ -0,0 +1,70 @@
//
// 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 RxSwift
/// Cursor implementation for single load operation
public class SingleLoadCursor<Element>: ResettableCursorType {
private let loadingObservable: Single<[Element]>
private var content: [Element] = []
/// Initializer for array content type
///
/// - Parameter loadingObservable: Single observable with element of [Element] type
public init(loadingObservable: Single<[Element]>) {
self.loadingObservable = loadingObservable
}
public required init(initialFrom other: SingleLoadCursor) {
self.loadingObservable = other.loadingObservable
}
public private(set) var exhausted = false
public var count: Int {
return content.count
}
public subscript(index: Int) -> Element {
return content[index]
}
public func loadNextBatch() -> Single<[Element]> {
return Single.deferred {
if self.exhausted {
return .error(CursorError.exhausted)
}
return self.loadingObservable.do(onNext: { [weak self] newItems in
self?.onGot(result: newItems)
})
}
}
private func onGot(result: [Element]) {
content = result
exhausted = true
}
}

View File

@ -29,7 +29,7 @@ public class StaticCursor<Element>: ResettableCursorType {
/// Initializer for array content type
///
/// - Parameter content: array with elements of Elemet type
/// - Parameter content: array with elements of Element type
public init(content: [Element]) {
self.content = content
}
@ -46,10 +46,10 @@ public class StaticCursor<Element>: ResettableCursorType {
return content[index]
}
public func loadNextBatch() -> Observable<[Element]> {
return Observable.deferred {
public func loadNextBatch() -> Single<[Element]> {
return Single.deferred {
if self.exhausted {
throw CursorError.exhausted
return .error(CursorError.exhausted)
}
self.count = self.content.count

View File

@ -236,7 +236,7 @@ where Delegate.Cursor == Cursor {
retryButton.frame = CGRect(x: 0, y: 0, width: tableView.bounds.width, height: retryButtonHeigth)
retryButton.rx.controlEvent(.touchUpInside)
.bindNext { [weak self] in
.bind { [weak self] in
self?.paginationViewModel.load(.next)
}
.addDisposableTo(disposeBag)
@ -274,7 +274,7 @@ where Delegate.Cursor == Cursor {
private func createRefreshControl() {
let refreshControl = UIRefreshControl()
refreshControl.rx.controlEvent(.valueChanged)
.bindNext { [weak self] in
.bind { [weak self] in
self?.reload()
}
.addDisposableTo(disposeBag)

View File

@ -110,7 +110,7 @@ public final class PaginationViewModel<C: ResettableCursorType> {
currentRequest = currentCursor.loadNextBatch()
.subscribeOn(internalScheduler)
.subscribe(onNext: { [weak self] newItems in
.subscribe(onSuccess: { [weak self] newItems in
self?.onGot(newItems: newItems, using: currentCursor)
}, onError: { [weak self] error in
self?.onGot(error: error)

View File

@ -53,18 +53,8 @@ open class NetworkService {
public func rxRequest<T: ObservableMappable>(with parameters: ApiRequestParameters)
-> Observable<(response: HTTPURLResponse, model: T)> where T.ModelType == T {
let responseObservable = sessionManager.rx.responseObservableModel(requestParameters: parameters)
.counterTracking(for: self) as Observable<(response: HTTPURLResponse, model: T)>
#if os(iOS)
#if LEADKIT_EXTENSION_TARGET
return responseObservable
#else
return responseObservable.showErrorsInToastInDebugMode()
#endif
#else
return responseObservable
#endif
return sessionManager.rx.responseObservableModel(requestParameters: parameters)
.counterTracking(for: self)
}
/// Perform reactive request to get mapped ImmutableMappable model and http response
@ -74,18 +64,8 @@ open class NetworkService {
public func rxRequest<T: ImmutableMappable>(with parameters: ApiRequestParameters)
-> Observable<(response: HTTPURLResponse, model: T)> {
let responseObservable = sessionManager.rx.responseModel(requestParameters: parameters)
.counterTracking(for: self) as Observable<(response: HTTPURLResponse, model: T)>
#if os(iOS)
#if LEADKIT_EXTENSION_TARGET
return responseObservable
#else
return responseObservable.showErrorsInToastInDebugMode()
#endif
#else
return responseObservable
#endif
return sessionManager.rx.responseModel(requestParameters: parameters)
.counterTracking(for: self)
}
fileprivate func increaseRequestCounter() {

View File

@ -0,0 +1,143 @@
//
// 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
class SpinnerView: UIView, Animatable, LoadingIndicator {
private(set) var animating: Bool = false
private var startTime = CFTimeInterval(0)
private var stopTime = CFTimeInterval(0)
private weak var imageView: UIImageView?
private let animationDuration: CFTimeInterval
private let animationRepeatCount: Float
private let clockwiseAnimation: Bool
init(image: UIImage,
animationDuration: CFTimeInterval = 1,
animationRepeatCount: Float = Float.infinity,
clockwiseAnimation: Bool = true) {
self.animationDuration = animationDuration
self.animationRepeatCount = animationRepeatCount
self.clockwiseAnimation = clockwiseAnimation
super.init(frame: CGRect(origin: .zero, size: image.size))
let imageView = UIImageView(image: image)
imageView.frame = bounds
imageView.autoresizingMask = [
.flexibleLeftMargin,
.flexibleRightMargin,
.flexibleTopMargin,
.flexibleBottomMargin
]
addSubview(imageView)
self.imageView = imageView
NotificationCenter.default.addObserver(self,
selector: #selector(SpinnerView.restartAnimationIfNeeded),
name: .UIApplicationWillEnterForeground,
object: nil)
}
required public init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
deinit {
NotificationCenter.default.removeObserver(self)
}
override func didMoveToWindow() {
super.didMoveToWindow()
if window != nil {
restartAnimationIfNeeded()
}
}
// MARK: Animatable
func startAnimating() {
guard !animating else {
return
}
animating = true
imageView?.isHidden = false
addAnimation()
}
func stopAnimating() {
guard animating else {
return
}
animating = false
imageView?.isHidden = true
removeAnimation()
}
// MARK: private stuff
private func addAnimation() {
guard let imageView = imageView else {
return
}
let anim = CABasicAnimation.zRotationAnimationWith(duration: animationDuration,
repeatCount: animationRepeatCount,
clockwise: clockwiseAnimation)
anim.timeOffset = stopTime - startTime
imageView.layer.add(anim, forKey: CABasicAnimation.rotationKeyPath)
startTime = imageView.layer.convertTime(CACurrentMediaTime(), from: nil)
}
private func removeAnimation() {
guard let imageView = imageView else {
return
}
imageView.layer.removeAnimation(forKey: CABasicAnimation.rotationKeyPath)
stopTime = imageView.layer.convertTime(CACurrentMediaTime(), from: nil)
}
@objc private func restartAnimationIfNeeded() {
if animating {
removeAnimation()
addAnimation()
}
}
}

View File

@ -2,7 +2,7 @@
// 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
// 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
@ -11,7 +11,7 @@
// 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
// 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
@ -20,24 +20,24 @@
// THE SOFTWARE.
//
import RxSwift
import Toast_Swift
import QuartzCore
public extension Observable {
extension CABasicAnimation {
/// Method which shows toast with localized description of error in DEBUG mode
///
/// - Returns: The source sequence with the side-effecting behavior applied.
func showErrorsInToastInDebugMode() -> Observable<Observable.E> {
#if DEBUG
return `do`(onError: { (error) in
DispatchQueue.main.async {
UIApplication.shared.keyWindow?.makeToast(error.localizedDescription)
}
})
#else
return self
#endif
static let rotationKeyPath = "transform.rotation.z"
static func zRotationAnimationWith(duration: CFTimeInterval = 1,
repeatCount: Float = Float.infinity,
clockwise: Bool = true) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: CABasicAnimation.rotationKeyPath)
let direction = clockwise ? 1.0 : -1.0
animation.toValue = NSNumber(value: .pi * 2 * direction)
animation.duration = duration
animation.isCumulative = true
animation.repeatCount = repeatCount
return animation
}
}

View File

@ -32,22 +32,12 @@ public extension NetworkService {
public func rxLoadImage(url: String) -> Observable<(HTTPURLResponse, UIImage?)> {
let request = RxAlamofire.requestData(.get, url, headers: [:])
let requestObservable = request
return request
.observeOn(ConcurrentDispatchQueueScheduler(qos: .background))
.map { (response, data) -> (HTTPURLResponse, UIImage?) in
(response, UIImage(data: data))
}
.counterTracking(for: self)
#if os(iOS)
#if LEADKIT_EXTENSION_TARGET
return requestObservable
#else
return requestObservable.showErrorsInToastInDebugMode()
#endif
#else
return requestObservable
#endif
}
}

View File

@ -0,0 +1,46 @@
//
// 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 UIImage {
/// Creates AnyLoadingIndicator that rotates as spinner around Z axis.
///
/// - Parameters:
/// - animationDuration: Duration of one full 360 degrees rotation. One second is default.
/// - animationRepeatCount: How many times the spin should be done. If not provided, the view will spin forever.
/// - clockwiseAnimation: Direction of the rotation. Default is clockwise (true).
/// - Returns: Instance of AnyLoadingIndicator.
func asSpinner(animationDuration: CFTimeInterval = 1,
animationRepeatCount: Float = Float.infinity,
clockwiseAnimation: Bool = true) -> AnyLoadingIndicator {
let spinner = SpinnerView(image: self,
animationDuration: animationDuration,
animationRepeatCount: animationRepeatCount,
clockwiseAnimation: clockwiseAnimation)
return AnyLoadingIndicator(spinner)
}
}

View File

@ -24,8 +24,6 @@ import UIKit
public extension UIView {
private static let rotationKeyPath = "transform.rotation.z"
/**
Starts rotating the view around Z axis.
@ -34,18 +32,15 @@ public extension UIView {
- parameter clockwise: Direction of the rotation. Default is clockwise (true).
*/
public func startZRotation(duration: CFTimeInterval = 1, repeatCount: Float = Float.infinity, clockwise: Bool = true) {
let animation = CABasicAnimation(keyPath: UIView.rotationKeyPath)
let direction = clockwise ? 1.0 : -1.0
animation.toValue = NSNumber(value: .pi * 2 * direction)
animation.duration = duration
animation.isCumulative = true
animation.repeatCount = repeatCount
layer.add(animation, forKey: UIView.rotationKeyPath)
let animation = CABasicAnimation.zRotationAnimationWith(duration: duration,
repeatCount: repeatCount,
clockwise: clockwise)
layer.add(animation, forKey: CABasicAnimation.rotationKeyPath)
}
/// Stop rotating the view around Z axis.
public func stopZRotation() {
layer.removeAnimation(forKey: UIView.rotationKeyPath)
layer.removeAnimation(forKey: CABasicAnimation.rotationKeyPath)
}
}

View File

@ -38,6 +38,6 @@ public protocol CursorType {
/// Loads next batch of results
///
/// - Returns: Observable of LoadResultType
func loadNextBatch() -> Observable<[Element]>
func loadNextBatch() -> Single<[Element]>
}

View File

@ -42,7 +42,7 @@ class CursorTests: XCTestCase {
let cursorExpectation = expectation(description: "Stub cursor expectation")
entityCursor.loadNextBatch()
.subscribe(onNext: { _ in
.subscribe(onSuccess: { _ in
cursorExpectation.fulfill()
})
.addDisposableTo(disposeBag)
@ -55,29 +55,15 @@ class CursorTests: XCTestCase {
let fixedPageCursor = FixedPageCursor(cursor: stubCursor, pageSize: 16)
let cursorExpectation = expectation(description: "Fixed page cursor expectation")
let cursorExpectationError = expectation(description: "Fixed page cursor error expectation")
fixedPageCursor.loadNextBatch()
.subscribe(onNext: { loadedItems in
.subscribe(onSuccess: { loadedItems in
XCTAssertEqual(loadedItems.count, 15)
cursorExpectation.fulfill()
})
.addDisposableTo(disposeBag)
fixedPageCursor.loadNextBatch()
.subscribe(onNext: { _ in
XCTFail("Cursor should be exhausted!")
}, onError: { error in
switch try? cast(error) as CursorError {
case .exhausted?:
cursorExpectationError.fulfill()
default:
XCTFail("Cursor should be exhausted!")
}
})
.addDisposableTo(disposeBag)
waitForExpectations(timeout: 10, handler: nil)
}
@ -89,7 +75,7 @@ class CursorTests: XCTestCase {
let cursorExpectation = expectation(description: "Fixed page cursor expectation")
fixedPageCursor.loadNextBatch()
.subscribe(onNext: { loadedItems in
.subscribe(onSuccess: { loadedItems in
XCTAssertEqual(loadedItems.count, 8)
cursorExpectation.fulfill()

View File

@ -55,10 +55,10 @@ class StubCursor: ResettableCursorType {
self.requestDelay = other.requestDelay
}
func loadNextBatch() -> Observable<[Post]> {
return Observable.create { observer -> Disposable in
func loadNextBatch() -> Single<[Post]> {
return Single.create { observer -> Disposable in
if self.exhausted {
observer.onError(CursorError.exhausted)
observer(.error(CursorError.exhausted))
} else {
DispatchQueue.global().asyncAfter(deadline: .now() + self.requestDelay, execute: {
let countBefore = self.count
@ -69,8 +69,7 @@ class StubCursor: ResettableCursorType {
self.posts = Array((self.posts + newPosts)[0..<maxNewPosts])
observer.onNext(self[countBefore..<self.count])
observer.onCompleted()
observer(.success(self[countBefore..<self.count]))
})
}