diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d370c02..f97fbf2a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,21 @@ # Changelog -### 0.7.14 +### 0.7.17 - **Add**: `RxNetworkOperationModel` base class, `NetworkOperationState` and `NetworkOperationStateType` protocols. +### 0.7.16 +- **[Breaking Change]**: Remove `ModuleConfigurator`, change type of `ConfigurableController.viewModel` property from `IUO` to plain `ViewModelT`. +- **Add**: `InitializableView` protocol with default implementation. +- **Update**: `ConfigurableController` protocol now inherit `InitializableView`. +- **[Breaking Change]**: `setAppearance` of `ConfigurableController` replaced with `configureAppearance` of `InitializableView`. + +### 0.7.15 +- **Fix**: `Double.roundValue(withPrecision:)` rounding issue +- **Add**: `Double+Rounding` test case + +### 0.7.14 +- **[Breaking Change]**: `PaginationWrapper` separating state views from data loading. + ### 0.7.13 - **Update**: Migrate from `Variable` to `BehaviorRelay`. - **Fix**: `PaginationWrapper` retry load more after fail. @@ -25,7 +38,7 @@ - **Remove**: `App`, `Log` and `LogFormatter`. - **Remove**: `CocoaLumberjack` dependency. - **Add**: Rotate operation for image drawing. -- **Add**: `mapViewEvents` overload with closure that returns array of disposables. +- **Add**: `mapViewEvents` overload with closure that returns array of disposables. - **Update**: Update `ObjectMapper` to 3.1. - **Add**: `apiRequestParameters` method to `NetworkServiceConfiguration` extension. - **Update**: Rename setToCenter(withInsets:) to pintToSuperview(withInsets:excluding:) diff --git a/LeadKit.podspec b/LeadKit.podspec index 0a91f9db..eb6e028f 100644 --- a/LeadKit.podspec +++ b/LeadKit.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "LeadKit" - s.version = "0.7.14" + s.version = "0.7.17" 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.xcodeproj/project.pbxproj b/LeadKit.xcodeproj/project.pbxproj index 8389b109..ae3378f9 100644 --- a/LeadKit.xcodeproj/project.pbxproj +++ b/LeadKit.xcodeproj/project.pbxproj @@ -171,10 +171,6 @@ 6714633C1EB3396E00EAB194 /* LoadingIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671462281EB3396E00EAB194 /* LoadingIndicator.swift */; }; 6714633D1EB3396E00EAB194 /* LoadingIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671462281EB3396E00EAB194 /* LoadingIndicator.swift */; }; 6714633F1EB3396E00EAB194 /* LoadingIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671462281EB3396E00EAB194 /* LoadingIndicator.swift */; }; - 671463401EB3396E00EAB194 /* ModuleConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671462291EB3396E00EAB194 /* ModuleConfigurator.swift */; }; - 671463411EB3396E00EAB194 /* ModuleConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671462291EB3396E00EAB194 /* ModuleConfigurator.swift */; }; - 671463421EB3396E00EAB194 /* ModuleConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671462291EB3396E00EAB194 /* ModuleConfigurator.swift */; }; - 671463431EB3396E00EAB194 /* ModuleConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671462291EB3396E00EAB194 /* ModuleConfigurator.swift */; }; 671463481EB3396E00EAB194 /* ResettableType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6714622B1EB3396E00EAB194 /* ResettableType.swift */; }; 671463491EB3396E00EAB194 /* ResettableType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6714622B1EB3396E00EAB194 /* ResettableType.swift */; }; 6714634A1EB3396E00EAB194 /* ResettableType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6714622B1EB3396E00EAB194 /* ResettableType.swift */; }; @@ -375,7 +371,7 @@ 6774526C206249E30024EEEF /* UICollectionView+PaginationWrappable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6774526B206249E30024EEEF /* UICollectionView+PaginationWrappable.swift */; }; 6774526D206249E30024EEEF /* UICollectionView+PaginationWrappable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6774526B206249E30024EEEF /* UICollectionView+PaginationWrappable.swift */; }; 6774526E206249E30024EEEF /* UICollectionView+PaginationWrappable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6774526B206249E30024EEEF /* UICollectionView+PaginationWrappable.swift */; }; - 6774527020624A2A0024EEEF /* PaginationWrapperDelegate+DefaultImplementation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6774526F20624A2A0024EEEF /* PaginationWrapperDelegate+DefaultImplementation.swift */; }; + 6774527020624A2A0024EEEF /* PaginationWrapperUIDelegate+DefaultImplementation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6774526F20624A2A0024EEEF /* PaginationWrapperUIDelegate+DefaultImplementation.swift */; }; 6774527420624E820024EEEF /* DataLoadingModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6774527320624E820024EEEF /* DataLoadingModel.swift */; }; 6774527520624E820024EEEF /* DataLoadingModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6774527320624E820024EEEF /* DataLoadingModel.swift */; }; 6774527620624E820024EEEF /* DataLoadingModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6774527320624E820024EEEF /* DataLoadingModel.swift */; }; @@ -505,8 +501,14 @@ 67EB7FFE206176C900BDD9FB /* AnyPaginationWrappable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67EB7FFC206176C900BDD9FB /* AnyPaginationWrappable.swift */; }; 67EB7FFF206176C900BDD9FB /* AnyPaginationWrappable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67EB7FFC206176C900BDD9FB /* AnyPaginationWrappable.swift */; }; 67EB8001206177D600BDD9FB /* PaginationWrapperDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67EB8000206177D600BDD9FB /* PaginationWrapperDelegate.swift */; }; - 67EB8002206177D600BDD9FB /* PaginationWrapperDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67EB8000206177D600BDD9FB /* PaginationWrapperDelegate.swift */; }; - 67EB8003206177D600BDD9FB /* PaginationWrapperDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67EB8000206177D600BDD9FB /* PaginationWrapperDelegate.swift */; }; + 67ED2BDE20B44DEB00508B3E /* InitializableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67ED2BDD20B44DEB00508B3E /* InitializableView.swift */; }; + 67ED2BDF20B44DEB00508B3E /* InitializableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67ED2BDD20B44DEB00508B3E /* InitializableView.swift */; }; + 67ED2BE020B44DEB00508B3E /* InitializableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67ED2BDD20B44DEB00508B3E /* InitializableView.swift */; }; + 67ED2BE120B44DEB00508B3E /* InitializableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67ED2BDD20B44DEB00508B3E /* InitializableView.swift */; }; + 67ED2BE520B44F4300508B3E /* InitializableView+DefaultImplementation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67ED2BE420B44F4300508B3E /* InitializableView+DefaultImplementation.swift */; }; + 67ED2BE620B44F4300508B3E /* InitializableView+DefaultImplementation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67ED2BE420B44F4300508B3E /* InitializableView+DefaultImplementation.swift */; }; + 67ED2BE720B44F4300508B3E /* InitializableView+DefaultImplementation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67ED2BE420B44F4300508B3E /* InitializableView+DefaultImplementation.swift */; }; + 67ED2BE820B44F4300508B3E /* InitializableView+DefaultImplementation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67ED2BE420B44F4300508B3E /* InitializableView+DefaultImplementation.swift */; }; 67FD4382206BD24B005B0C64 /* EqutableOptionalArray.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67FD4381206BD24B005B0C64 /* EqutableOptionalArray.swift */; }; 67FD4383206BD24B005B0C64 /* EqutableOptionalArray.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67FD4381206BD24B005B0C64 /* EqutableOptionalArray.swift */; }; 67FD4384206BD24B005B0C64 /* EqutableOptionalArray.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67FD4381206BD24B005B0C64 /* EqutableOptionalArray.swift */; }; @@ -515,11 +517,11 @@ 67FDC2601FA310EA00C76A77 /* RequestError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67FDC25E1FA310EA00C76A77 /* RequestError.swift */; }; 67FDC2611FA310EA00C76A77 /* RequestError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67FDC25E1FA310EA00C76A77 /* RequestError.swift */; }; 67FDC2621FA310EA00C76A77 /* RequestError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67FDC25E1FA310EA00C76A77 /* RequestError.swift */; }; + 820CAD8420B43B080033EF94 /* PaginationWrapperDelegate+DefaultImplementation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 820CAD8320B43B080033EF94 /* PaginationWrapperDelegate+DefaultImplementation.swift */; }; + 825F8F2820B3384C00594857 /* PaginationWrapperUIDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825F8F2720B3384C00594857 /* PaginationWrapperUIDelegate.swift */; }; 82F8BB181F5DDED100C1061B /* Single+DeferredJust.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82F8BB171F5DDED100C1061B /* Single+DeferredJust.swift */; }; A658E54D1F8CD7790093527A /* TableRow+SeparatorsExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = A658E54C1F8CD7790093527A /* TableRow+SeparatorsExtensions.swift */; }; - A658E54E1F8CD7790093527A /* TableRow+SeparatorsExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = A658E54C1F8CD7790093527A /* TableRow+SeparatorsExtensions.swift */; }; A658E5501F8CD9350093527A /* Array+SeparatorRowBoxExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = A658E54F1F8CD9350093527A /* Array+SeparatorRowBoxExtensions.swift */; }; - A658E5511F8CD9350093527A /* Array+SeparatorRowBoxExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = A658E54F1F8CD9350093527A /* Array+SeparatorRowBoxExtensions.swift */; }; A676AE481F97D28A001F9214 /* String+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = A676AE471F97D28A001F9214 /* String+Extensions.swift */; }; A676AE491F97D28A001F9214 /* String+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = A676AE471F97D28A001F9214 /* String+Extensions.swift */; }; A676AE4A1F97D28A001F9214 /* String+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = A676AE471F97D28A001F9214 /* String+Extensions.swift */; }; @@ -541,8 +543,6 @@ A6E0DDDE1F8A696F002CA74E /* EmptyCellRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = A66428A71F8A654600C6308D /* EmptyCellRow.swift */; }; A6E0DDDF1F8A696F002CA74E /* SeparatorCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A66428A61F8A653600C6308D /* SeparatorCell.swift */; }; A6E0DDE11F8A696F002CA74E /* SeparatorRowBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = A66428A81F8A655600C6308D /* SeparatorRowBox.swift */; }; - A6E0DDE31F8A696F002CA74E /* SeparatorCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A66428A61F8A653600C6308D /* SeparatorCell.swift */; }; - A6E0DDE51F8A696F002CA74E /* SeparatorRowBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = A66428A81F8A655600C6308D /* SeparatorRowBox.swift */; }; A6E0DDF11F8A6C80002CA74E /* SeparatorConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6E0DDF01F8A6C80002CA74E /* SeparatorConfiguration.swift */; }; A6F32C081F6EBDAA00AC08EE /* String+LocalizedComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6F32C071F6EBDAA00AC08EE /* String+LocalizedComponent.swift */; }; A6F32C0A1F6EBE5B00AC08EE /* String+LocalizedComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6F32C071F6EBDAA00AC08EE /* String+LocalizedComponent.swift */; }; @@ -553,6 +553,9 @@ A6F32C121F6EBE9800AC08EE /* StringExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6F32C0E1F6EBE8E00AC08EE /* StringExtensionTests.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 */; }; + D93221EE20A44896003799D5 /* Double+RoundingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D93221ED20A44896003799D5 /* Double+RoundingTests.swift */; }; + D93221EF20A44896003799D5 /* Double+RoundingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D93221ED20A44896003799D5 /* Double+RoundingTests.swift */; }; + D93221F020A44896003799D5 /* Double+RoundingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D93221ED20A44896003799D5 /* Double+RoundingTests.swift */; }; DEE25FE98D40ED1C168F384A /* Pods_LeadKit_LeadKit_iOS_Extensions.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 887F99C5326BD220C2811BD6 /* Pods_LeadKit_LeadKit_iOS_Extensions.framework */; }; EF24213A2076D5BD00FA9BE6 /* NetworkServiceConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = EF2421392076D5BD00FA9BE6 /* NetworkServiceConfiguration.swift */; }; EF24213B2076D5C700FA9BE6 /* NetworkServiceConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = EF2421392076D5BD00FA9BE6 /* NetworkServiceConfiguration.swift */; }; @@ -670,7 +673,6 @@ 671462251EB3396E00EAB194 /* CursorType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CursorType.swift; sourceTree = ""; }; 671462261EB3396E00EAB194 /* DrawingOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DrawingOperation.swift; sourceTree = ""; }; 671462281EB3396E00EAB194 /* LoadingIndicator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoadingIndicator.swift; sourceTree = ""; }; - 671462291EB3396E00EAB194 /* ModuleConfigurator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ModuleConfigurator.swift; sourceTree = ""; }; 6714622B1EB3396E00EAB194 /* ResettableType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ResettableType.swift; sourceTree = ""; }; 6714622C1EB3396E00EAB194 /* ReuseIdentifierProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReuseIdentifierProtocol.swift; sourceTree = ""; }; 6714622E1EB3396E00EAB194 /* StaticViewHeightProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StaticViewHeightProtocol.swift; sourceTree = ""; }; @@ -732,7 +734,7 @@ 6771DFE91EEA7CB8002DCDAE /* DateFormattingService+MappingTransform.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DateFormattingService+MappingTransform.swift"; sourceTree = ""; }; 67745267206249360024EEEF /* UITableView+PaginationWrappable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITableView+PaginationWrappable.swift"; sourceTree = ""; }; 6774526B206249E30024EEEF /* UICollectionView+PaginationWrappable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UICollectionView+PaginationWrappable.swift"; sourceTree = ""; }; - 6774526F20624A2A0024EEEF /* PaginationWrapperDelegate+DefaultImplementation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PaginationWrapperDelegate+DefaultImplementation.swift"; sourceTree = ""; }; + 6774526F20624A2A0024EEEF /* PaginationWrapperUIDelegate+DefaultImplementation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PaginationWrapperUIDelegate+DefaultImplementation.swift"; sourceTree = ""; }; 6774527320624E820024EEEF /* DataLoadingModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataLoadingModel.swift; sourceTree = ""; }; 67745278206252020024EEEF /* DataLoadingState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataLoadingState.swift; sourceTree = ""; }; 6774527F206256A20024EEEF /* RxDataLoadingModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RxDataLoadingModel.swift; sourceTree = ""; }; @@ -780,9 +782,13 @@ 67EB7FF7206175F700BDD9FB /* PaginationWrappable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaginationWrappable.swift; sourceTree = ""; }; 67EB7FFC206176C900BDD9FB /* AnyPaginationWrappable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnyPaginationWrappable.swift; sourceTree = ""; }; 67EB8000206177D600BDD9FB /* PaginationWrapperDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaginationWrapperDelegate.swift; sourceTree = ""; }; + 67ED2BDD20B44DEB00508B3E /* InitializableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InitializableView.swift; sourceTree = ""; }; + 67ED2BE420B44F4300508B3E /* InitializableView+DefaultImplementation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "InitializableView+DefaultImplementation.swift"; sourceTree = ""; }; 67FD4381206BD24B005B0C64 /* EqutableOptionalArray.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EqutableOptionalArray.swift; sourceTree = ""; }; 67FDC25E1FA310EA00C76A77 /* RequestError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequestError.swift; sourceTree = ""; }; 78405D3B3D3C3E17456877FF /* Pods_LeadKit_iOSTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_LeadKit_iOSTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 820CAD8320B43B080033EF94 /* PaginationWrapperDelegate+DefaultImplementation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PaginationWrapperDelegate+DefaultImplementation.swift"; sourceTree = ""; }; + 825F8F2720B3384C00594857 /* PaginationWrapperUIDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaginationWrapperUIDelegate.swift; sourceTree = ""; }; 82F8BB171F5DDED100C1061B /* Single+DeferredJust.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Single+DeferredJust.swift"; sourceTree = ""; }; 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; }; @@ -808,6 +814,7 @@ CFE9323150A9760008093F73 /* Pods_LeadKit_LeadKit_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_LeadKit_LeadKit_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; }; D0F8D0002B21A4F31981F1ED /* Pods_LeadKit_LeadKit_tvOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_LeadKit_LeadKit_tvOS.framework; sourceTree = BUILT_PRODUCTS_DIR; }; D840E55867DC9BB63460B856 /* Pods-LeadKit tvOSTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-LeadKit tvOSTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-LeadKit tvOSTests/Pods-LeadKit tvOSTests.release.xcconfig"; sourceTree = ""; }; + D93221ED20A44896003799D5 /* Double+RoundingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Double+RoundingTests.swift"; sourceTree = ""; }; DF1148A279C7AC7A42B0A0F8 /* Pods_LeadKit_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_LeadKit_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; }; EF2421392076D5BD00FA9BE6 /* NetworkServiceConfiguration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkServiceConfiguration.swift; sourceTree = ""; }; EFA4C66320864F9C008C4DD8 /* UniversalMappable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UniversalMappable.swift; sourceTree = ""; }; @@ -1168,7 +1175,6 @@ 67274783206CD7E500725163 /* DateFormatingService */, 672947E3206EA63200AC6B6B /* Drawing */, 671462281EB3396E00EAB194 /* LoadingIndicator.swift */, - 671462291EB3396E00EAB194 /* ModuleConfigurator.swift */, 67C7B1772068BADA00C9EDA3 /* NumberFormattingService */, A676AE541F981121001F9214 /* ObservableMappable.swift */, 6714622B1EB3396E00EAB194 /* ResettableType.swift */, @@ -1327,6 +1333,7 @@ isa = PBXGroup; children = ( 6792623A206EB0D800308E62 /* SeparatorCell */, + 67ED2BE420B44F4300508B3E /* InitializableView+DefaultImplementation.swift */, 6727476D206CCDDB00725163 /* ViewBackground+Configuration.swift */, 6727477E206CD3BD00725163 /* ViewText+Extensions.swift */, ); @@ -1480,7 +1487,8 @@ 67745266206248F00024EEEF /* PaginationDataLoading */ = { isa = PBXGroup; children = ( - 6774526F20624A2A0024EEEF /* PaginationWrapperDelegate+DefaultImplementation.swift */, + 6774526F20624A2A0024EEEF /* PaginationWrapperUIDelegate+DefaultImplementation.swift */, + 820CAD8320B43B080033EF94 /* PaginationWrapperDelegate+DefaultImplementation.swift */, 6774526B206249E30024EEEF /* UICollectionView+PaginationWrappable.swift */, 67745267206249360024EEEF /* UITableView+PaginationWrappable.swift */, ); @@ -1560,6 +1568,7 @@ children = ( 67EB7FFC206176C900BDD9FB /* AnyPaginationWrappable.swift */, 67EB8000206177D600BDD9FB /* PaginationWrapperDelegate.swift */, + 825F8F2720B3384C00594857 /* PaginationWrapperUIDelegate.swift */, ); path = PaginationDataLoading; sourceTree = ""; @@ -1578,6 +1587,7 @@ children = ( 67926234206EB08400308E62 /* SeparatorCell */, 678D269D20692BFF00B05B93 /* TextField */, + 67ED2BDD20B44DEB00508B3E /* InitializableView.swift */, ); path = Views; sourceTree = ""; @@ -1772,6 +1782,7 @@ A6F32C0D1F6EBE7700AC08EE /* Extensions */ = { isa = PBXGroup; children = ( + D93221ED20A44896003799D5 /* Double+RoundingTests.swift */, A6F32C0E1F6EBE8E00AC08EE /* StringExtensionTests.swift */, ); path = Extensions; @@ -2609,6 +2620,7 @@ 67EB8001206177D600BDD9FB /* PaginationWrapperDelegate.swift in Sources */, 67FD4382206BD24B005B0C64 /* EqutableOptionalArray.swift in Sources */, 6774529A20625E5B0024EEEF /* PaginationDataLoadingState.swift in Sources */, + 825F8F2820B3384C00594857 /* PaginationWrapperUIDelegate.swift in Sources */, 678D26A020692BFF00B05B93 /* TextFieldViewEvents.swift in Sources */, 6727478F206CD88600725163 /* DateFormattingService.swift in Sources */, 678D26A420692BFF00B05B93 /* TextFieldViewModelEvents.swift in Sources */, @@ -2617,6 +2629,7 @@ 671463541EB3396E00EAB194 /* StaticViewHeightProtocol.swift in Sources */, 673CF4112063ABD100C329F6 /* GeneralDataLoadingState+Extensions.swift in Sources */, 673CF42C2063DE5900C329F6 /* TextPlaceholderView.swift in Sources */, + 67ED2BDE20B44DEB00508B3E /* InitializableView.swift in Sources */, 671463601EB3396E00EAB194 /* SupportProtocol.swift in Sources */, 671462841EB3396E00EAB194 /* CGContext+Initializers.swift in Sources */, EFBE57DB1EC361620040E00A /* UIView+Layout.swift in Sources */, @@ -2628,7 +2641,6 @@ 671463101EB3396E00EAB194 /* UIViewController+DefaultXibName.swift in Sources */, 67386A8C206CF3F6004EDA6C /* DateFormattingService+DefaultImplementation.swift in Sources */, 674AF55C1EC45B1600038A8F /* UIActivityIndicatorView+LoadingIndicator.swift in Sources */, - 671463401EB3396E00EAB194 /* ModuleConfigurator.swift in Sources */, 67A1FF8F1EBCA09B00D6C89F /* UIImage+Spinner.swift in Sources */, 673564F62068C68D00F0CBED /* NumberFormat.swift in Sources */, EFA4C66420864F9C008C4DD8 /* UniversalMappable.swift in Sources */, @@ -2701,6 +2713,7 @@ 671463081EB3396E00EAB194 /* UIView+Rotation.swift in Sources */, 6714626C1EB3396E00EAB194 /* XibView.swift in Sources */, 67274778206CD0B500725163 /* UILabel+ViewTextConfiguration.swift in Sources */, + 67ED2BE520B44F4300508B3E /* InitializableView+DefaultImplementation.swift in Sources */, 6774529220625D170024EEEF /* GeneralDataLoadingModel.swift in Sources */, 6714637C1EB3396E00EAB194 /* ImageDrawingOperation.swift in Sources */, 671463341EB3396E00EAB194 /* DrawingOperation.swift in Sources */, @@ -2710,7 +2723,7 @@ 671463981EB3396E00EAB194 /* AnyLoadingIndicator.swift in Sources */, 671463A71EB340C000EAB194 /* UIViewController+ConfigurableController.swift in Sources */, 671463141EB3396E00EAB194 /* UIViewController+TopVisibleViewController.swift in Sources */, - 6774527020624A2A0024EEEF /* PaginationWrapperDelegate+DefaultImplementation.swift in Sources */, + 6774527020624A2A0024EEEF /* PaginationWrapperUIDelegate+DefaultImplementation.swift in Sources */, 6727478A206CD83600725163 /* DateFormat.swift in Sources */, 67745280206256A20024EEEF /* RxDataLoadingModel.swift in Sources */, A6F32C081F6EBDAA00AC08EE /* String+LocalizedComponent.swift in Sources */, @@ -2736,6 +2749,7 @@ 6714628C1EB3396E00EAB194 /* CGImage+Alpha.swift in Sources */, 671462741EB3396E00EAB194 /* LeadKitError.swift in Sources */, 677452A420625FA90024EEEF /* RxDataSource.swift in Sources */, + 820CAD8420B43B080033EF94 /* PaginationWrapperDelegate+DefaultImplementation.swift in Sources */, 671AD262206A35EC00EAF887 /* UIApplication+Cellular.swift in Sources */, 6713C23C20AF0D5900875921 /* NetworkOperationModel.swift in Sources */, 671462D81EB3396E00EAB194 /* TimeInterval+DateComponents.swift in Sources */, @@ -2763,17 +2777,14 @@ buildActionMask = 2147483647; files = ( A6C9A5051F8BC78F009311CC /* SeparatorConfiguration.swift in Sources */, + D93221EE20A44896003799D5 /* Double+RoundingTests.swift in Sources */, 671463CA1EB34B1E00EAB194 /* TestView.swift in Sources */, 671463B81EB34B1E00EAB194 /* StubCursor.swift in Sources */, - A658E54E1F8CD7790093527A /* TableRow+SeparatorsExtensions.swift in Sources */, - A658E5511F8CD9350093527A /* Array+SeparatorRowBoxExtensions.swift in Sources */, 671463BB1EB34B1E00EAB194 /* CursorTests.swift in Sources */, A6F32C101F6EBE9600AC08EE /* StringExtensionTests.swift in Sources */, 671463BE1EB34B1E00EAB194 /* LoadFromNibTests.swift in Sources */, - A6E0DDE31F8A696F002CA74E /* SeparatorCell.swift in Sources */, A6C9A50F1F8BC79D009311CC /* Comparable+Extensions.swift in Sources */, 671463C41EB34B1E00EAB194 /* Post.swift in Sources */, - A6E0DDE51F8A696F002CA74E /* SeparatorRowBox.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2806,7 +2817,6 @@ 6714626A1EB3396E00EAB194 /* NetworkService.swift in Sources */, 671AD26E206A3E8500EAF887 /* Array+TotalCountCursorListingResult.swift in Sources */, 673CF4132063ABD100C329F6 /* GeneralDataLoadingState+Extensions.swift in Sources */, - 671463421EB3396E00EAB194 /* ModuleConfigurator.swift in Sources */, 6713C24320AF189100875921 /* RxNetworkOperationModel.swift in Sources */, 671462921EB3396E00EAB194 /* CGImage+Crop.swift in Sources */, 671463861EB3396E00EAB194 /* ResizeDrawingOperation.swift in Sources */, @@ -2822,6 +2832,7 @@ 6714638A1EB3396E00EAB194 /* RoundDrawingOperation.swift in Sources */, 67153E3C207DFADA0049D8C0 /* RotateDrawingOperation.swift in Sources */, 6774529C20625E5B0024EEEF /* PaginationDataLoadingState.swift in Sources */, + 67ED2BE020B44DEB00508B3E /* InitializableView.swift in Sources */, 671463821EB3396E00EAB194 /* PaddingDrawingOperation.swift in Sources */, 6714632A1EB3396E00EAB194 /* BaseViewModel.swift in Sources */, 671462AE1EB3396E00EAB194 /* Observable+DeferredJust.swift in Sources */, @@ -2880,6 +2891,7 @@ 67FDC2611FA310EA00C76A77 /* RequestError.swift in Sources */, 671AD25E206A343300EAF887 /* VoidBlock.swift in Sources */, 671462521EB3396E00EAB194 /* StaticCursor.swift in Sources */, + 67ED2BE720B44F4300508B3E /* InitializableView+DefaultImplementation.swift in Sources */, 6714629E1EB3396E00EAB194 /* CursorType+Slice.swift in Sources */, 6714636A1EB3396E00EAB194 /* ConfigurableView.swift in Sources */, ); @@ -2891,16 +2903,17 @@ files = ( 6714634B1EB3396E00EAB194 /* ResettableType.swift in Sources */, 671462E71EB3396E00EAB194 /* UIColor+Hex.swift in Sources */, + 67ED2BE120B44DEB00508B3E /* InitializableView.swift in Sources */, 67274775206CCF1200725163 /* ViewText.swift in Sources */, 6727476B206CCCA500725163 /* ViewBackground.swift in Sources */, 671462831EB3396E00EAB194 /* AlamofireRequest+Extensions.swift in Sources */, + 67ED2BE820B44F4300508B3E /* InitializableView+DefaultImplementation.swift in Sources */, 677452B820627FE00024EEEF /* PaginationWrappable.swift in Sources */, 673CF40E2063AB7C00C329F6 /* GeneralDataLoadingViewModel.swift in Sources */, 67274770206CCDDB00725163 /* ViewBackground+Configuration.swift in Sources */, 678D26A320692BFF00B05B93 /* TextFieldViewEvents.swift in Sources */, 67153E43207DFBA80049D8C0 /* FloatingPoint+DegreesRadiansConvertion.swift in Sources */, 67745283206256A20024EEEF /* RxDataLoadingModel.swift in Sources */, - 67EB8003206177D600BDD9FB /* PaginationWrapperDelegate.swift in Sources */, 671463571EB3396E00EAB194 /* StaticViewHeightProtocol.swift in Sources */, 671463631EB3396E00EAB194 /* SupportProtocol.swift in Sources */, 671462871EB3396E00EAB194 /* CGContext+Initializers.swift in Sources */, @@ -2909,7 +2922,6 @@ 6714626B1EB3396E00EAB194 /* NetworkService.swift in Sources */, 673CF43A2063E7CE00C329F6 /* GeneralDataLoadingController+DefaultImplementation.swift in Sources */, 671463131EB3396E00EAB194 /* UIViewController+DefaultXibName.swift in Sources */, - 671463431EB3396E00EAB194 /* ModuleConfigurator.swift in Sources */, 671462931EB3396E00EAB194 /* CGImage+Crop.swift in Sources */, 6727477A206CD0B500725163 /* UILabel+ViewTextConfiguration.swift in Sources */, 67EB7FE720615DE000BDD9FB /* DataSource.swift in Sources */, @@ -3040,6 +3052,7 @@ 671463BA1EB34B1E00EAB194 /* StubCursor.swift in Sources */, 671463BD1EB34B1E00EAB194 /* CursorTests.swift in Sources */, A6F32C121F6EBE9800AC08EE /* StringExtensionTests.swift in Sources */, + D93221F020A44896003799D5 /* Double+RoundingTests.swift in Sources */, 671463C01EB34B1E00EAB194 /* LoadFromNibTests.swift in Sources */, 671463C61EB34B1E00EAB194 /* Post.swift in Sources */, ); @@ -3075,7 +3088,6 @@ 671462F11EB3396E00EAB194 /* UIImage+SupportExtensions.swift in Sources */, 671462691EB3396E00EAB194 /* NetworkService.swift in Sources */, 671463111EB3396E00EAB194 /* UIViewController+DefaultXibName.swift in Sources */, - 671463411EB3396E00EAB194 /* ModuleConfigurator.swift in Sources */, EFA4C67020865126008C4DD8 /* UniversalMappable+SwiftStandard.swift in Sources */, 67153E41207DFBA80049D8C0 /* FloatingPoint+DegreesRadiansConvertion.swift in Sources */, 671462911EB3396E00EAB194 /* CGImage+Crop.swift in Sources */, @@ -3093,6 +3105,7 @@ 67EB7FEC2061667900BDD9FB /* DefaultTotalCountCursorListingResult.swift in Sources */, 671462991EB3396E00EAB194 /* CGSize+Resize.swift in Sources */, 67274780206CD3BD00725163 /* ViewText+Extensions.swift in Sources */, + 67ED2BE620B44F4300508B3E /* InitializableView+DefaultImplementation.swift in Sources */, 671463311EB3396E00EAB194 /* CursorType.swift in Sources */, 6714624D1EB3396E00EAB194 /* MapCursor.swift in Sources */, 67EB7FD520615D1700BDD9FB /* ResettableCursorType.swift in Sources */, @@ -3109,7 +3122,6 @@ 6774526D206249E30024EEEF /* UICollectionView+PaginationWrappable.swift in Sources */, 6714627D1EB3396E00EAB194 /* AlamofireManager+Extensions.swift in Sources */, 673CF4352063E29B00C329F6 /* TextWithButtonPlaceholder.swift in Sources */, - 67EB8002206177D600BDD9FB /* PaginationWrapperDelegate.swift in Sources */, 6727476F206CCDDB00725163 /* ViewBackground+Configuration.swift in Sources */, 673CF4232063D90600C329F6 /* DisposeBagHolder.swift in Sources */, 677452AA206263360024EEEF /* CursorType+RxDataSourceDefaultImplementation.swift in Sources */, @@ -3122,6 +3134,7 @@ 6713C24220AF189100875921 /* RxNetworkOperationModel.swift in Sources */, 671462A11EB3396E00EAB194 /* Double+Rounding.swift in Sources */, 671463091EB3396E00EAB194 /* UIView+Rotation.swift in Sources */, + 67ED2BDF20B44DEB00508B3E /* InitializableView.swift in Sources */, 6714626D1EB3396E00EAB194 /* XibView.swift in Sources */, 6714637D1EB3396E00EAB194 /* ImageDrawingOperation.swift in Sources */, 671463351EB3396E00EAB194 /* DrawingOperation.swift in Sources */, @@ -3198,6 +3211,7 @@ 671463BF1EB34B1E00EAB194 /* LoadFromNibTests.swift in Sources */, 671463C51EB34B1E00EAB194 /* Post.swift in Sources */, 671463CB1EB34B1E00EAB194 /* TestView.swift in Sources */, + D93221EF20A44896003799D5 /* Double+RoundingTests.swift in Sources */, A6F32C111F6EBE9700AC08EE /* StringExtensionTests.swift in Sources */, 671463BC1EB34B1E00EAB194 /* CursorTests.swift in Sources */, 671463B91EB34B1E00EAB194 /* StubCursor.swift in Sources */, diff --git a/Sources/Classes/DataLoading/PaginationDataLoading/PaginationWrapper.swift b/Sources/Classes/DataLoading/PaginationDataLoading/PaginationWrapper.swift index f07a853e..adbfa541 100644 --- a/Sources/Classes/DataLoading/PaginationDataLoading/PaginationWrapper.swift +++ b/Sources/Classes/DataLoading/PaginationDataLoading/PaginationWrapper.swift @@ -36,6 +36,7 @@ final public class PaginationWrapper UIView { - return TextPlaceholderView(title: .empty) - } - - func customInitialLoadingErrorHandling(for error: Error) -> Bool { - return false - } - - func errorPlaceholder(for error: Error) -> UIView { - return TextPlaceholderView(title: .error) - } - - func initialLoadingIndicator() -> AnyLoadingIndicator { - let indicator = UIActivityIndicatorView(activityIndicatorStyle: .whiteLarge) - indicator.color = .gray - - return AnyLoadingIndicator(indicator) - } - - func loadingMoreIndicator() -> AnyLoadingIndicator { - let indicator = UIActivityIndicatorView(activityIndicatorStyle: .gray) - - return AnyLoadingIndicator(indicator) - } - - func footerRetryButton() -> UIButton { - let retryButton = UIButton(type: .custom) - retryButton.backgroundColor = .lightGray - retryButton.setTitle("Retry load more", for: .normal) - - return retryButton - } - - func footerRetryButtonHeight() -> CGFloat { - return 44 - } - - func footerRetryButtonWillAppear() { - // by default - nothing will happen - } - - func footerRetryButtonWillDisappear() { - // by default - nothing will happen - } - -} - public extension PaginationWrapperDelegate where DataSourceType: ResettableRxDataSourceCursor, - DataSourceType.ResultType == [DataSourceType.Element] { + DataSourceType.ResultType == [DataSourceType.Element] { /// Convenient typealias. typealias PaginationWrapperType = PaginationWrapper - } diff --git a/Sources/Extensions/DataLoading/PaginationDataLoading/PaginationWrapperUIDelegate+DefaultImplementation.swift b/Sources/Extensions/DataLoading/PaginationDataLoading/PaginationWrapperUIDelegate+DefaultImplementation.swift new file mode 100644 index 00000000..ff04088f --- /dev/null +++ b/Sources/Extensions/DataLoading/PaginationDataLoading/PaginationWrapperUIDelegate+DefaultImplementation.swift @@ -0,0 +1,71 @@ +// +// Copyright (c) 2018 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 PaginationWrapperUIDelegate { + + func emptyPlaceholder() -> UIView { + return TextPlaceholderView(title: .empty) + } + + func customInitialLoadingErrorHandling(for error: Error) -> Bool { + return false + } + + func errorPlaceholder(for error: Error) -> UIView { + return TextPlaceholderView(title: .error) + } + + func initialLoadingIndicator() -> AnyLoadingIndicator { + let indicator = UIActivityIndicatorView(activityIndicatorStyle: .whiteLarge) + indicator.color = .gray + + return AnyLoadingIndicator(indicator) + } + + func loadingMoreIndicator() -> AnyLoadingIndicator { + let indicator = UIActivityIndicatorView(activityIndicatorStyle: .gray) + + return AnyLoadingIndicator(indicator) + } + + func footerRetryButton() -> UIButton { + let retryButton = UIButton(type: .custom) + retryButton.backgroundColor = .lightGray + retryButton.setTitle("Retry load more", for: .normal) + + return retryButton + } + + func footerRetryButtonHeight() -> CGFloat { + return 44 + } + + func footerRetryButtonWillAppear() { + // by default - nothing will happen + } + + func footerRetryButtonWillDisappear() { + // by default - nothing will happen + } +} diff --git a/Sources/Extensions/Double/Double+Rounding.swift b/Sources/Extensions/Double/Double+Rounding.swift index 09a406ad..f6f9d54a 100644 --- a/Sources/Extensions/Double/Double+Rounding.swift +++ b/Sources/Extensions/Double/Double+Rounding.swift @@ -23,10 +23,8 @@ import Foundation public extension Double { - /** Type of rounding double value - - Normal: From 167.567 you will get 167.6 - Down: From 167.567 you will get 167.5 */ @@ -37,19 +35,17 @@ public extension Double { /** Rounding of double value - - - parameter persicion: important number of digits after comma + - parameter precision: significant digits after decimal point - parameter roundType: rounding type - - returns: rounded value */ - func roundValue(withPersicion persicion: UInt, + func roundValue(withPrecision precision: UInt, roundType: RoundingType = .normal) -> Double { - let divider = pow(10.0, Double(persicion)) + let divider = pow(10.0, Double(precision)) switch roundType { case .normal: - return (self * divider).rounded(.up) / divider + return (self * divider).rounded(.toNearestOrEven) / divider case .down: return (self * divider).rounded(.down) / divider } diff --git a/Sources/Extensions/UIKit/UIViewController/UIViewController+ConfigurableController.swift b/Sources/Extensions/UIKit/UIViewController/UIViewController+ConfigurableController.swift index 55a3986d..904f38e9 100644 --- a/Sources/Extensions/UIKit/UIViewController/UIViewController+ConfigurableController.swift +++ b/Sources/Extensions/UIKit/UIViewController/UIViewController+ConfigurableController.swift @@ -24,29 +24,13 @@ import UIKit public extension ConfigurableController where Self: UIViewController { - func bindViews() { - // nothing - } - - func addViews() { - // nothing - } - - func setAppearance() { - // nothing - } - func configureBarButtons() { // nothing } - func localize() { - // nothing - } - func initialLoadView() { addViews() - setAppearance() + configureAppearance() configureBarButtons() localize() bindViews() diff --git a/Sources/Protocols/ModuleConfigurator.swift b/Sources/Extensions/Views/InitializableView+DefaultImplementation.swift similarity index 64% rename from Sources/Protocols/ModuleConfigurator.swift rename to Sources/Extensions/Views/InitializableView+DefaultImplementation.swift index ea59b916..c4585978 100644 --- a/Sources/Protocols/ModuleConfigurator.swift +++ b/Sources/Extensions/Views/InitializableView+DefaultImplementation.swift @@ -1,8 +1,8 @@ // -// Copyright (c) 2017 Touch Instinct +// Copyright (c) 2018 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,9 +20,29 @@ // THE SOFTWARE. // -public protocol ModuleConfigurator { +public extension InitializableView { - associatedtype ViewControllerT + func initializeView() { + addViews() + bindViews() + configureAppearance() + localize() + } + + func addViews() { + // + } + + func bindViews() { + // + } + + func configureAppearance() { + // + } + + func localize() { + // + } - func configure(input: ViewControllerT) } diff --git a/Sources/Protocols/ConfigurableController.swift b/Sources/Protocols/ConfigurableController.swift index fd14a19b..d4550061 100644 --- a/Sources/Protocols/ConfigurableController.swift +++ b/Sources/Protocols/ConfigurableController.swift @@ -22,22 +22,14 @@ import Foundation -public protocol ConfigurableController { +public protocol ConfigurableController: InitializableView { associatedtype ViewModelT - var viewModel: ViewModelT! { get } - - func bindViews() - - func addViews() - - func setAppearance() + var viewModel: ViewModelT { get } func configureBarButtons() - func localize() - func initialLoadView() } diff --git a/Sources/Protocols/Views/InitializableView.swift b/Sources/Protocols/Views/InitializableView.swift new file mode 100644 index 00000000..f5229e07 --- /dev/null +++ b/Sources/Protocols/Views/InitializableView.swift @@ -0,0 +1,41 @@ +// +// Copyright (c) 2018 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. +// + +/// Protocol with methods that should be called in constructor methods of view. +public protocol InitializableView { + + /// Main method that should call other in particular order. + func initializeView() + + /// Method for adding views to current view. + func addViews() + + /// Method for binding to data or user actions. + func bindViews() + + /// Appearance configuration method. + func configureAppearance() + + /// Localization method. + func localize() + +} diff --git a/Sources/Structures/DataLoading/PaginationDataLoading/PaginationWrapperDelegate.swift b/Sources/Structures/DataLoading/PaginationDataLoading/PaginationWrapperDelegate.swift index 97f181d6..c33bde08 100644 --- a/Sources/Structures/DataLoading/PaginationDataLoading/PaginationWrapperDelegate.swift +++ b/Sources/Structures/DataLoading/PaginationDataLoading/PaginationWrapperDelegate.swift @@ -20,8 +20,7 @@ // THE SOFTWARE. // -/// PaginationWrapper delegate used for pagination results handling and -/// customization of bound states (loading, empty, error, etc.). +/// PaginationWrapper delegate used for pagination results handling public protocol PaginationWrapperDelegate: class { associatedtype DataSourceType: DataSource @@ -42,56 +41,6 @@ public protocol PaginationWrapperDelegate: class { func paginationWrapper(didReload allItems: DataSourceType.ResultType, using dataSource: DataSourceType) - /// Returns placeholder view for empty state. - /// - /// - Returns: Configured instace of UIView. - func emptyPlaceholder() -> UIView - - /// Called when initial loading error is occured. - /// It should return true if error is handled and false if it doesn't. - /// - /// - Parameters: - /// - error: Error that occured due data loading. - /// - Returns: Bool value. If true - then error placeholder wouldn't be shown. - func customInitialLoadingErrorHandling(for error: Error) -> Bool - - /// Returns placeholder view for error state. - /// - /// - Parameters: - /// - error: Error that occured due data loading. - /// - Returns: Configured instace of UIView. - func errorPlaceholder(for error: Error) -> UIView - - /// Returns loading idicator for initial loading state. - /// This indicator will appear at center of the placeholders container. - /// - /// - Returns: Configured instace of AnyLoadingIndicator. - func initialLoadingIndicator() -> AnyLoadingIndicator - - /// Returns loading idicator for initial loading state. - /// - /// - Returns: Configured instace of AnyLoadingIndicator. - func loadingMoreIndicator() -> AnyLoadingIndicator - - /// Returns instance of UIButton for "retry load more" action. - /// - /// - Returns: Configured instace of AnyLoadingIndicator. - func footerRetryButton() -> UIButton - - /// Returns height for "retry load more" button. - /// - /// - Returns: Height of "retry load more" button. - func footerRetryButtonHeight() -> CGFloat - - /// Method is called before "retry load more" will be shown. - /// Typically, it's used when you need to show custom footer view. - func footerRetryButtonWillAppear() - - /// Method is called before "retry load more" will be hidden. - /// Typically, it's used when you need to hide custom footer view. - func footerRetryButtonWillDisappear() - - /// Clears view when placeholder is shown. - func clearView() - + /// Handles empty data state. + func clearData() } diff --git a/Sources/Structures/DataLoading/PaginationDataLoading/PaginationWrapperUIDelegate.swift b/Sources/Structures/DataLoading/PaginationDataLoading/PaginationWrapperUIDelegate.swift new file mode 100644 index 00000000..039eb2a4 --- /dev/null +++ b/Sources/Structures/DataLoading/PaginationDataLoading/PaginationWrapperUIDelegate.swift @@ -0,0 +1,75 @@ +// +// Copyright (c) 2018 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. +// + +/// PaginationWrapper UI delegate used for customization +/// of bound states (loading, empty, error, etc.). +public protocol PaginationWrapperUIDelegate: class { + + /// Returns placeholder view for empty state. + /// + /// - Returns: Configured instace of UIView. + func emptyPlaceholder() -> UIView? + + /// Called when initial loading error is occured. + /// It should return true if error is handled and false if it doesn't. + /// + /// - Parameters: + /// - error: Error that occured due data loading. + /// - Returns: Bool value. If true - then error placeholder wouldn't be shown. + func customInitialLoadingErrorHandling(for error: Error) -> Bool + + /// Returns placeholder view for error state. + /// + /// - Parameters: + /// - error: Error that occured due data loading. + /// - Returns: Configured instace of UIView. + func errorPlaceholder(for error: Error) -> UIView? + + /// Returns loading idicator for initial loading state. + /// This indicator will appear at center of the placeholders container. + /// + /// - Returns: Configured instace of AnyLoadingIndicator. + func initialLoadingIndicator() -> AnyLoadingIndicator? + + /// Returns loading idicator for initial loading state. + /// + /// - Returns: Configured instace of AnyLoadingIndicator. + func loadingMoreIndicator() -> AnyLoadingIndicator? + + /// Returns instance of UIButton for "retry load more" action. + /// + /// - Returns: Configured instace of AnyLoadingIndicator. + func footerRetryButton() -> UIButton? + + /// Returns height for "retry load more" button. + /// + /// - Returns: Height of "retry load more" button. + func footerRetryButtonHeight() -> CGFloat + + /// Method is called before "retry load more" will be shown. + /// Typically, it's used when you need to show custom footer view. + func footerRetryButtonWillAppear() + + /// Method is called before "retry load more" will be hidden. + /// Typically, it's used when you need to hide custom footer view. + func footerRetryButtonWillDisappear() +} diff --git a/Tests/Extensions/Double+RoundingTests.swift b/Tests/Extensions/Double+RoundingTests.swift new file mode 100644 index 00000000..13de970a --- /dev/null +++ b/Tests/Extensions/Double+RoundingTests.swift @@ -0,0 +1,54 @@ +// +// 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 XCTest + +class Double_RoundingTests: XCTestCase { + + func testPositiveNumbers() { + let pi = 3.1415926 + + XCTAssertTrue(pi.roundValue(withPrecision: 0) == 3.0) + XCTAssertTrue(pi.roundValue(withPrecision: 1) == 3.1) + XCTAssertTrue(pi.roundValue(withPrecision: 2) == 3.14) + XCTAssertTrue(pi.roundValue(withPrecision: 3) == 3.142) + + let some = 1.778297 + XCTAssertTrue(some.roundValue(withPrecision: 1) == 1.8) + XCTAssertTrue(some.roundValue(withPrecision: 1, roundType: .down) == 1.7) + XCTAssertTrue(some.roundValue(withPrecision: 2, roundType: .down) == 1.77) + } + + func testNegativeNumbers() { + let e = 2.7182 + + XCTAssertTrue(-e.roundValue(withPrecision: 0) == -3.0) + XCTAssertTrue(-e.roundValue(withPrecision: 1) == -2.7) + XCTAssertTrue(-e.roundValue(withPrecision: 2) == -2.72) + XCTAssertTrue(-e.roundValue(withPrecision: 3) == -2.718) + + let some = -1.778297 + XCTAssertTrue(some.roundValue(withPrecision: 1) == -1.8) + XCTAssertTrue(some.roundValue(withPrecision: 1, roundType: .down) == -1.8) + XCTAssertTrue(some.roundValue(withPrecision: 2, roundType: .down) == -1.78) + } +}