diff --git a/LeadKitAdditions.xcodeproj/project.pbxproj b/LeadKitAdditions.xcodeproj/project.pbxproj index 4e90d3f..9df7444 100644 --- a/LeadKitAdditions.xcodeproj/project.pbxproj +++ b/LeadKitAdditions.xcodeproj/project.pbxproj @@ -7,10 +7,17 @@ objects = { /* Begin PBXBuildFile section */ - 0A08E37F1F2A13BF00F9AB62 /* CellTextFieldToolBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A08E37E1F2A13BF00F9AB62 /* CellTextFieldToolBar.swift */; }; 248389A288C0A6D7914F0546 /* Pods_LeadKitAdditions_LeadKitAdditions_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0ED4A1B793EAA73C9E95969F /* Pods_LeadKitAdditions_LeadKitAdditions_iOS.framework */; }; + 67779CBC206986390098F024 /* BaseTextFieldViewEvents+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67779CBB206986390098F024 /* BaseTextFieldViewEvents+Extensions.swift */; }; + 67779CBD206986390098F024 /* BaseTextFieldViewEvents+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67779CBB206986390098F024 /* BaseTextFieldViewEvents+Extensions.swift */; }; 678D26AA206935B900B05B93 /* BiometricsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 678D26A9206935B900B05B93 /* BiometricsService.swift */; }; 67B4E6EB206941CE00E233EA /* BiometricsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 678D26A9206935B900B05B93 /* BiometricsService.swift */; }; + 67B4E6F3206945D200E233EA /* BaseTextFieldViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67B4E6F1206945D200E233EA /* BaseTextFieldViewModel.swift */; }; + 67B4E6F6206945DD00E233EA /* OnlineValidationResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67B4E6F5206945DC00E233EA /* OnlineValidationResult.swift */; }; + 67B4E6F7206945DD00E233EA /* OnlineValidationResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67B4E6F5206945DC00E233EA /* OnlineValidationResult.swift */; }; + 67B4E6F9206945F900E233EA /* OnlineValidationState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67B4E6F8206945F900E233EA /* OnlineValidationState.swift */; }; + 67B4E6FA206945F900E233EA /* OnlineValidationState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67B4E6F8206945F900E233EA /* OnlineValidationState.swift */; }; + 67B4E6FB20694A4200E233EA /* BaseTextFieldViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67B4E6F1206945D200E233EA /* BaseTextFieldViewModel.swift */; }; A6CFB8D91F5024A500A42CC2 /* Error+NetworkingExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6CFB8D81F5024A500A42CC2 /* Error+NetworkingExtensions.swift */; }; B326804BA6CC8B8BB136A46A /* Pods_LeadKitAdditions_LeadKitAdditions_iOS_Extensions.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CFD5627139CAB27705F75C07 /* Pods_LeadKitAdditions_LeadKitAdditions_iOS_Extensions.framework */; }; CAE698E81E968820000394B0 /* LeadKitAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = CAE698E61E968820000394B0 /* LeadKitAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -44,22 +51,10 @@ ED0C34201F2906EC00FAE9FD /* UIBarButtonItem+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED0C33E81F2906EC00FAE9FD /* UIBarButtonItem+Extensions.swift */; }; ED0C34211F2906EC00FAE9FD /* UserDefaults+UserService.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED0C33E91F2906EC00FAE9FD /* UserDefaults+UserService.swift */; }; ED0C34221F2906EC00FAE9FD /* UserDefaults+UserService.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED0C33E91F2906EC00FAE9FD /* UserDefaults+UserService.swift */; }; - ED0C34231F2906EC00FAE9FD /* CellFieldJumpingProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED0C33EB1F2906EC00FAE9FD /* CellFieldJumpingProtocol.swift */; }; - ED0C34241F2906EC00FAE9FD /* CellFieldJumpingProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED0C33EB1F2906EC00FAE9FD /* CellFieldJumpingProtocol.swift */; }; - ED0C34251F2906EC00FAE9FD /* CellFieldMaskProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED0C33EC1F2906EC00FAE9FD /* CellFieldMaskProtocol.swift */; }; - ED0C34261F2906EC00FAE9FD /* CellFieldMaskProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED0C33EC1F2906EC00FAE9FD /* CellFieldMaskProtocol.swift */; }; - ED0C34271F2906EC00FAE9FD /* CellFieldsToolBarProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED0C33ED1F2906EC00FAE9FD /* CellFieldsToolBarProtocol.swift */; }; - ED0C34281F2906EC00FAE9FD /* CellFieldsToolBarProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED0C33ED1F2906EC00FAE9FD /* CellFieldsToolBarProtocol.swift */; }; - ED0C34291F2906EC00FAE9FD /* CellFieldValidationProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED0C33EE1F2906EC00FAE9FD /* CellFieldValidationProtocol.swift */; }; - ED0C342A1F2906EC00FAE9FD /* CellFieldValidationProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED0C33EE1F2906EC00FAE9FD /* CellFieldValidationProtocol.swift */; }; - ED0C342B1F2906EC00FAE9FD /* FormCellViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED0C33EF1F2906EC00FAE9FD /* FormCellViewModelProtocol.swift */; }; - ED0C342C1F2906EC00FAE9FD /* FormCellViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED0C33EF1F2906EC00FAE9FD /* FormCellViewModelProtocol.swift */; }; ED0C342D1F2906EC00FAE9FD /* BasePassCodeService.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED0C33F11F2906EC00FAE9FD /* BasePassCodeService.swift */; }; ED0C342E1F2906EC00FAE9FD /* BasePassCodeService.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED0C33F11F2906EC00FAE9FD /* BasePassCodeService.swift */; }; ED0C342F1F2906EC00FAE9FD /* BaseUserService.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED0C33F21F2906EC00FAE9FD /* BaseUserService.swift */; }; ED0C34301F2906EC00FAE9FD /* BaseUserService.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED0C33F21F2906EC00FAE9FD /* BaseUserService.swift */; }; - ED0C34311F2906EC00FAE9FD /* CellFieldsJumpingService.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED0C33F31F2906EC00FAE9FD /* CellFieldsJumpingService.swift */; }; - ED0C34321F2906EC00FAE9FD /* CellFieldsJumpingService.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED0C33F31F2906EC00FAE9FD /* CellFieldsJumpingService.swift */; }; ED0C34331F2906EC00FAE9FD /* MaskFieldTextProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED0C33F41F2906EC00FAE9FD /* MaskFieldTextProxy.swift */; }; ED0C34341F2906EC00FAE9FD /* MaskFieldTextProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED0C33F41F2906EC00FAE9FD /* MaskFieldTextProxy.swift */; }; ED0C34351F2906EC00FAE9FD /* ApiNetworkService.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED0C33F61F2906EC00FAE9FD /* ApiNetworkService.swift */; }; @@ -74,20 +69,18 @@ ED0C34421F2906EC00FAE9FD /* ValidationItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED0C33FD1F2906EC00FAE9FD /* ValidationItem.swift */; }; ED0C34431F2906EC00FAE9FD /* ValidationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED0C33FE1F2906EC00FAE9FD /* ValidationService.swift */; }; ED0C34441F2906EC00FAE9FD /* ValidationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED0C33FE1F2906EC00FAE9FD /* ValidationService.swift */; }; - ED0C34451F2906EC00FAE9FD /* CellTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED0C34011F2906EC00FAE9FD /* CellTextField.swift */; }; - ED0C34461F2906EC00FAE9FD /* CellTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED0C34011F2906EC00FAE9FD /* CellTextField.swift */; }; - ED0C34471F2906EC00FAE9FD /* CellTextFieldViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED0C34021F2906EC00FAE9FD /* CellTextFieldViewModel.swift */; }; - ED0C34481F2906EC00FAE9FD /* CellTextFieldViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED0C34021F2906EC00FAE9FD /* CellTextFieldViewModel.swift */; }; - ED69E7E81F2AC7CC00C74895 /* CellTextFieldToolBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A08E37E1F2A13BF00F9AB62 /* CellTextFieldToolBar.swift */; }; EFBD55921EBB9A980062AA63 /* LeadKitAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = CAE698E61E968820000394B0 /* LeadKitAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ 01605ECA03749D49C27FA3DD /* Pods-LeadKitAdditions-LeadKitAdditions iOS Extensions.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-LeadKitAdditions-LeadKitAdditions iOS Extensions.release.xcconfig"; path = "Pods/Target Support Files/Pods-LeadKitAdditions-LeadKitAdditions iOS Extensions/Pods-LeadKitAdditions-LeadKitAdditions iOS Extensions.release.xcconfig"; sourceTree = ""; }; - 0A08E37E1F2A13BF00F9AB62 /* CellTextFieldToolBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CellTextFieldToolBar.swift; sourceTree = ""; }; 0ED4A1B793EAA73C9E95969F /* Pods_LeadKitAdditions_LeadKitAdditions_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_LeadKitAdditions_LeadKitAdditions_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 49738551AC648B0AFA74E57F /* Pods-LeadKitAdditions-LeadKitAdditions iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-LeadKitAdditions-LeadKitAdditions iOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-LeadKitAdditions-LeadKitAdditions iOS/Pods-LeadKitAdditions-LeadKitAdditions iOS.debug.xcconfig"; sourceTree = ""; }; + 67779CBB206986390098F024 /* BaseTextFieldViewEvents+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BaseTextFieldViewEvents+Extensions.swift"; sourceTree = ""; }; 678D26A9206935B900B05B93 /* BiometricsService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BiometricsService.swift; sourceTree = ""; }; + 67B4E6F1206945D200E233EA /* BaseTextFieldViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseTextFieldViewModel.swift; sourceTree = ""; }; + 67B4E6F5206945DC00E233EA /* OnlineValidationResult.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OnlineValidationResult.swift; sourceTree = ""; }; + 67B4E6F8206945F900E233EA /* OnlineValidationState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OnlineValidationState.swift; sourceTree = ""; }; 7B7F57C5E5275C4D8DC71992 /* Pods_LeadKitAdditions.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_LeadKitAdditions.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 9D549FA5A7579702358E07DF /* Pods-LeadKitAdditions-LeadKitAdditions iOS Extensions.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-LeadKitAdditions-LeadKitAdditions iOS Extensions.debug.xcconfig"; path = "Pods/Target Support Files/Pods-LeadKitAdditions-LeadKitAdditions iOS Extensions/Pods-LeadKitAdditions-LeadKitAdditions iOS Extensions.debug.xcconfig"; sourceTree = ""; }; A6CFB8D81F5024A500A42CC2 /* Error+NetworkingExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Error+NetworkingExtensions.swift"; sourceTree = ""; }; @@ -110,14 +103,8 @@ ED0C33E71F2906EC00FAE9FD /* Observable+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Observable+Extensions.swift"; sourceTree = ""; }; ED0C33E81F2906EC00FAE9FD /* UIBarButtonItem+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIBarButtonItem+Extensions.swift"; sourceTree = ""; }; ED0C33E91F2906EC00FAE9FD /* UserDefaults+UserService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UserDefaults+UserService.swift"; sourceTree = ""; }; - ED0C33EB1F2906EC00FAE9FD /* CellFieldJumpingProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CellFieldJumpingProtocol.swift; sourceTree = ""; }; - ED0C33EC1F2906EC00FAE9FD /* CellFieldMaskProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CellFieldMaskProtocol.swift; sourceTree = ""; }; - ED0C33ED1F2906EC00FAE9FD /* CellFieldsToolBarProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CellFieldsToolBarProtocol.swift; sourceTree = ""; }; - ED0C33EE1F2906EC00FAE9FD /* CellFieldValidationProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CellFieldValidationProtocol.swift; sourceTree = ""; }; - ED0C33EF1F2906EC00FAE9FD /* FormCellViewModelProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FormCellViewModelProtocol.swift; sourceTree = ""; }; ED0C33F11F2906EC00FAE9FD /* BasePassCodeService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BasePassCodeService.swift; sourceTree = ""; }; ED0C33F21F2906EC00FAE9FD /* BaseUserService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseUserService.swift; sourceTree = ""; }; - ED0C33F31F2906EC00FAE9FD /* CellFieldsJumpingService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CellFieldsJumpingService.swift; sourceTree = ""; }; ED0C33F41F2906EC00FAE9FD /* MaskFieldTextProxy.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MaskFieldTextProxy.swift; sourceTree = ""; }; ED0C33F61F2906EC00FAE9FD /* ApiNetworkService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ApiNetworkService.swift; sourceTree = ""; }; ED0C33F71F2906EC00FAE9FD /* DefaultNetworkService+ActivityIndicator+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DefaultNetworkService+ActivityIndicator+Extension.swift"; sourceTree = ""; }; @@ -126,8 +113,6 @@ ED0C33FC1F2906EC00FAE9FD /* ValidationError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ValidationError.swift; sourceTree = ""; }; ED0C33FD1F2906EC00FAE9FD /* ValidationItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ValidationItem.swift; sourceTree = ""; }; ED0C33FE1F2906EC00FAE9FD /* ValidationService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ValidationService.swift; sourceTree = ""; }; - ED0C34011F2906EC00FAE9FD /* CellTextField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CellTextField.swift; sourceTree = ""; }; - ED0C34021F2906EC00FAE9FD /* CellTextFieldViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CellTextFieldViewModel.swift; sourceTree = ""; }; EFBD55701EBB87100062AA63 /* LeadKitAdditions.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = LeadKitAdditions.framework; sourceTree = BUILT_PRODUCTS_DIR; }; EFBD55781EBB893F0062AA63 /* Info-iOS-Extensions.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Info-iOS-Extensions.plist"; sourceTree = ""; }; EFBD55791EBB893F0062AA63 /* Info-iOS.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Info-iOS.plist"; sourceTree = ""; }; @@ -153,6 +138,22 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 67B4E6F0206945D200E233EA /* BaseTextFieldViewModel */ = { + isa = PBXGroup; + children = ( + 67B4E6F1206945D200E233EA /* BaseTextFieldViewModel.swift */, + ); + path = BaseTextFieldViewModel; + sourceTree = ""; + }; + 67B4E6F4206945DC00E233EA /* ValidationService */ = { + isa = PBXGroup; + children = ( + 67B4E6F5206945DC00E233EA /* OnlineValidationResult.swift */, + ); + path = ValidationService; + sourceTree = ""; + }; A3117951840B8B7D2E7A8A80 /* Frameworks */ = { isa = PBXGroup; children = ( @@ -202,6 +203,7 @@ ED0C33D21F2906EC00FAE9FD /* Classes */ = { isa = PBXGroup; children = ( + 67B4E6F0206945D200E233EA /* BaseTextFieldViewModel */, ED0C33D31F2906EC00FAE9FD /* ApiResponse.swift */, ED0C33D41F2906EC00FAE9FD /* BaseDateFormatter.swift */, ED0C33D51F2906EC00FAE9FD /* LoadingBarButton.swift */, @@ -271,6 +273,7 @@ ED0C33E81F2906EC00FAE9FD /* UIBarButtonItem+Extensions.swift */, ED0C33E91F2906EC00FAE9FD /* UserDefaults+UserService.swift */, A6CFB8D81F5024A500A42CC2 /* Error+NetworkingExtensions.swift */, + 67779CBB206986390098F024 /* BaseTextFieldViewEvents+Extensions.swift */, ); path = Extensions; sourceTree = ""; @@ -278,11 +281,7 @@ ED0C33EA1F2906EC00FAE9FD /* Protocols */ = { isa = PBXGroup; children = ( - ED0C33EB1F2906EC00FAE9FD /* CellFieldJumpingProtocol.swift */, - ED0C33EC1F2906EC00FAE9FD /* CellFieldMaskProtocol.swift */, - ED0C33EE1F2906EC00FAE9FD /* CellFieldValidationProtocol.swift */, - ED0C33ED1F2906EC00FAE9FD /* CellFieldsToolBarProtocol.swift */, - ED0C33EF1F2906EC00FAE9FD /* FormCellViewModelProtocol.swift */, + 67B4E6F4206945DC00E233EA /* ValidationService */, ); path = Protocols; sourceTree = ""; @@ -294,7 +293,6 @@ ED0C33FB1F2906EC00FAE9FD /* ValidationService */, ED0C33F11F2906EC00FAE9FD /* BasePassCodeService.swift */, ED0C33F21F2906EC00FAE9FD /* BaseUserService.swift */, - ED0C33F31F2906EC00FAE9FD /* CellFieldsJumpingService.swift */, ED0C33F41F2906EC00FAE9FD /* MaskFieldTextProxy.swift */, 678D26A9206935B900B05B93 /* BiometricsService.swift */, ); @@ -315,6 +313,7 @@ ED0C33FB1F2906EC00FAE9FD /* ValidationService */ = { isa = PBXGroup; children = ( + 67B4E6F8206945F900E233EA /* OnlineValidationState.swift */, ED0C33FC1F2906EC00FAE9FD /* ValidationError.swift */, ED0C33FD1F2906EC00FAE9FD /* ValidationItem.swift */, ED0C33FE1F2906EC00FAE9FD /* ValidationService.swift */, @@ -325,21 +324,10 @@ ED0C33FF1F2906EC00FAE9FD /* Views */ = { isa = PBXGroup; children = ( - 0A08E37E1F2A13BF00F9AB62 /* CellTextFieldToolBar.swift */, - ED0C34001F2906EC00FAE9FD /* CellTextField */, ); path = Views; sourceTree = ""; }; - ED0C34001F2906EC00FAE9FD /* CellTextField */ = { - isa = PBXGroup; - children = ( - ED0C34011F2906EC00FAE9FD /* CellTextField.swift */, - ED0C34021F2906EC00FAE9FD /* CellTextFieldViewModel.swift */, - ); - path = CellTextField; - sourceTree = ""; - }; F8A65FEC7C0EB4B93746E50F /* Pods */ = { isa = PBXGroup; children = ( @@ -573,39 +561,34 @@ buildActionMask = 2147483647; files = ( ED0C34171F2906EC00FAE9FD /* ApiError.swift in Sources */, + 67B4E6FB20694A4200E233EA /* BaseTextFieldViewModel.swift in Sources */, ED0C343B1F2906EC00FAE9FD /* DefaultNetworkService.swift in Sources */, ED0C34351F2906EC00FAE9FD /* ApiNetworkService.swift in Sources */, ED0C340F1F2906EC00FAE9FD /* PassCodeHolderProtocol.swift in Sources */, ED0C343F1F2906EC00FAE9FD /* ValidationError.swift in Sources */, ED0C342F1F2906EC00FAE9FD /* BaseUserService.swift in Sources */, - ED0C34231F2906EC00FAE9FD /* CellFieldJumpingProtocol.swift in Sources */, 678D26AA206935B900B05B93 /* BiometricsService.swift in Sources */, ED0C34411F2906EC00FAE9FD /* ValidationItem.swift in Sources */, ED0C341F1F2906EC00FAE9FD /* UIBarButtonItem+Extensions.swift in Sources */, ED0C34091F2906EC00FAE9FD /* PassCodeConfiguration.swift in Sources */, - ED0C342B1F2906EC00FAE9FD /* FormCellViewModelProtocol.swift in Sources */, ED0C341D1F2906EC00FAE9FD /* Observable+Extensions.swift in Sources */, - ED0C34471F2906EC00FAE9FD /* CellTextFieldViewModel.swift in Sources */, ED0C34191F2906EC00FAE9FD /* ApiErrorProtocol.swift in Sources */, ED0C34131F2906EC00FAE9FD /* BasePassCodeViewController.swift in Sources */, ED0C342D1F2906EC00FAE9FD /* BasePassCodeService.swift in Sources */, + 67B4E6F9206945F900E233EA /* OnlineValidationState.swift in Sources */, + 67779CBC206986390098F024 /* BaseTextFieldViewEvents+Extensions.swift in Sources */, ED0C340D1F2906EC00FAE9FD /* PassCodeHolder.swift in Sources */, - ED0C34451F2906EC00FAE9FD /* CellTextField.swift in Sources */, - ED0C34271F2906EC00FAE9FD /* CellFieldsToolBarProtocol.swift in Sources */, - ED0C34291F2906EC00FAE9FD /* CellFieldValidationProtocol.swift in Sources */, - 0A08E37F1F2A13BF00F9AB62 /* CellTextFieldToolBar.swift in Sources */, ED0C34031F2906EC00FAE9FD /* ApiResponse.swift in Sources */, A6CFB8D91F5024A500A42CC2 /* Error+NetworkingExtensions.swift in Sources */, ED0C34071F2906EC00FAE9FD /* LoadingBarButton.swift in Sources */, - ED0C34251F2906EC00FAE9FD /* CellFieldMaskProtocol.swift in Sources */, ED0C34211F2906EC00FAE9FD /* UserDefaults+UserService.swift in Sources */, ED0C34391F2906EC00FAE9FD /* DefaultNetworkService+ActivityIndicator.swift in Sources */, - ED0C34311F2906EC00FAE9FD /* CellFieldsJumpingService.swift in Sources */, ED0C34111F2906EC00FAE9FD /* PassCodeValidationResult.swift in Sources */, ED0C34051F2906EC00FAE9FD /* BaseDateFormatter.swift in Sources */, ED0C34431F2906EC00FAE9FD /* ValidationService.swift in Sources */, ED0C34331F2906EC00FAE9FD /* MaskFieldTextProxy.swift in Sources */, ED0C340B1F2906EC00FAE9FD /* PassCodeError.swift in Sources */, + 67B4E6F6206945DD00E233EA /* OnlineValidationResult.swift in Sources */, ED0C34151F2906EC00FAE9FD /* BasePassCodeViewModel.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -616,32 +599,27 @@ files = ( ED0C34181F2906EC00FAE9FD /* ApiError.swift in Sources */, ED0C343C1F2906EC00FAE9FD /* DefaultNetworkService.swift in Sources */, + 67779CBD206986390098F024 /* BaseTextFieldViewEvents+Extensions.swift in Sources */, ED0C34361F2906EC00FAE9FD /* ApiNetworkService.swift in Sources */, ED0C34101F2906EC00FAE9FD /* PassCodeHolderProtocol.swift in Sources */, ED0C34401F2906EC00FAE9FD /* ValidationError.swift in Sources */, ED0C34301F2906EC00FAE9FD /* BaseUserService.swift in Sources */, - ED0C34241F2906EC00FAE9FD /* CellFieldJumpingProtocol.swift in Sources */, ED0C34421F2906EC00FAE9FD /* ValidationItem.swift in Sources */, ED0C34201F2906EC00FAE9FD /* UIBarButtonItem+Extensions.swift in Sources */, ED0C340A1F2906EC00FAE9FD /* PassCodeConfiguration.swift in Sources */, - ED0C342C1F2906EC00FAE9FD /* FormCellViewModelProtocol.swift in Sources */, + 67B4E6FA206945F900E233EA /* OnlineValidationState.swift in Sources */, ED0C34381F2906EC00FAE9FD /* DefaultNetworkService+ActivityIndicator+Extension.swift in Sources */, ED0C341E1F2906EC00FAE9FD /* Observable+Extensions.swift in Sources */, - ED0C34481F2906EC00FAE9FD /* CellTextFieldViewModel.swift in Sources */, 67B4E6EB206941CE00E233EA /* BiometricsService.swift in Sources */, ED0C341A1F2906EC00FAE9FD /* ApiErrorProtocol.swift in Sources */, ED0C34141F2906EC00FAE9FD /* BasePassCodeViewController.swift in Sources */, ED0C342E1F2906EC00FAE9FD /* BasePassCodeService.swift in Sources */, + 67B4E6F7206945DD00E233EA /* OnlineValidationResult.swift in Sources */, ED0C340E1F2906EC00FAE9FD /* PassCodeHolder.swift in Sources */, - ED0C34461F2906EC00FAE9FD /* CellTextField.swift in Sources */, - ED0C34281F2906EC00FAE9FD /* CellFieldsToolBarProtocol.swift in Sources */, - ED69E7E81F2AC7CC00C74895 /* CellTextFieldToolBar.swift in Sources */, - ED0C342A1F2906EC00FAE9FD /* CellFieldValidationProtocol.swift in Sources */, + 67B4E6F3206945D200E233EA /* BaseTextFieldViewModel.swift in Sources */, ED0C34041F2906EC00FAE9FD /* ApiResponse.swift in Sources */, ED0C34081F2906EC00FAE9FD /* LoadingBarButton.swift in Sources */, - ED0C34261F2906EC00FAE9FD /* CellFieldMaskProtocol.swift in Sources */, ED0C34221F2906EC00FAE9FD /* UserDefaults+UserService.swift in Sources */, - ED0C34321F2906EC00FAE9FD /* CellFieldsJumpingService.swift in Sources */, ED0C34121F2906EC00FAE9FD /* PassCodeValidationResult.swift in Sources */, ED0C34061F2906EC00FAE9FD /* BaseDateFormatter.swift in Sources */, ED0C34441F2906EC00FAE9FD /* ValidationService.swift in Sources */, diff --git a/Podfile b/Podfile index 5f32cb8..ffff999 100644 --- a/Podfile +++ b/Podfile @@ -15,7 +15,7 @@ abstract_target 'LeadKitAdditions' do use_frameworks! - pod "LeadKit", '~> 0.6.0' + pod 'LeadKit', :git => 'https://github.com/TouchInstinct/LeadKit', :branch => 'feature/text_field_view_model' end target 'LeadKitAdditions iOS Extensions' do @@ -23,7 +23,7 @@ abstract_target 'LeadKitAdditions' do use_frameworks! - pod "LeadKit/Core-iOS-Extension", '~> 0.6.0' + pod "LeadKit/Core-iOS-Extension", :git => 'https://github.com/TouchInstinct/LeadKit', :branch => 'feature/text_field_view_model' end end diff --git a/Podfile.lock b/Podfile.lock index 9f71675..2c30ef4 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -1,7 +1,7 @@ PODS: - Alamofire (4.7.0) - - CocoaLumberjack/Default (3.3.0) - - CocoaLumberjack/Swift (3.3.0): + - CocoaLumberjack/Default (3.4.1) + - CocoaLumberjack/Swift (3.4.1): - CocoaLumberjack/Default - IDZSwiftCommonCrypto (0.10.0) - InputMask (3.0.0) @@ -9,58 +9,68 @@ PODS: - LeadKit (0.6.7): - LeadKit/Core (= 0.6.7) - LeadKit/Core (0.6.7): - - CocoaLumberjack/Swift (~> 3.3.0) - - ObjectMapper (~> 3.0.0) - - RxAlamofire (= 4.0.0) - - RxCocoa (= 4.0.0) - - RxSwift (= 4.0.0) - - TableKit (~> 2.5.0) + - CocoaLumberjack/Swift (~> 3.4) + - ObjectMapper (~> 3.0) + - RxAlamofire (~> 4.1) + - RxCocoa (~> 4.1) + - RxSwift (~> 4.1) + - TableKit (~> 2.6) - UIScrollView-InfiniteScroll (~> 1.0.0) - LeadKit/Core-iOS-Extension (0.6.7): - - CocoaLumberjack/Swift (~> 3.3.0) - - ObjectMapper (~> 3.0.0) - - RxAlamofire (= 4.0.0) - - RxCocoa (= 4.0.0) - - RxSwift (= 4.0.0) - - ObjectMapper (3.0.0) - - RxAlamofire (4.0.0): - - RxAlamofire/Core (= 4.0.0) - - RxAlamofire/Core (4.0.0): + - CocoaLumberjack/Swift (~> 3.4) + - ObjectMapper (~> 3.0) + - RxAlamofire (~> 4.1) + - RxCocoa (~> 4.1) + - RxSwift (~> 4.1) + - ObjectMapper (3.1.0) + - RxAlamofire (4.1.0): + - RxAlamofire/Core (= 4.1.0) + - RxAlamofire/Core (4.1.0): - Alamofire (~> 4.5) - RxSwift (~> 4.0) - - RxCocoa (4.0.0): + - RxCocoa (4.1.2): - RxSwift (~> 4.0) - - RxSwift (4.0.0) + - RxSwift (4.1.2) - SwiftLint (0.25.0) - SwiftValidator (5.0.0) - - TableKit (2.5.0) + - TableKit (2.6.0) - UIScrollView-InfiniteScroll (1.0.2) DEPENDENCIES: - IDZSwiftCommonCrypto - InputMask (= 3.0.0) - KeychainAccess (= 3.1.0) - - LeadKit (~> 0.6.0) - - LeadKit/Core-iOS-Extension (~> 0.6.0) + - LeadKit (from `https://github.com/TouchInstinct/LeadKit`, branch `feature/text_field_view_model`) + - LeadKit/Core-iOS-Extension (from `https://github.com/TouchInstinct/LeadKit`, branch `feature/text_field_view_model`) - SwiftLint (~> 0.25) - SwiftValidator (= 5.0.0) +EXTERNAL SOURCES: + LeadKit: + :branch: feature/text_field_view_model + :git: https://github.com/TouchInstinct/LeadKit + +CHECKOUT OPTIONS: + LeadKit: + :commit: 463279d2865b2e77bd727e18d7bc9793c9539160 + :git: https://github.com/TouchInstinct/LeadKit + SPEC CHECKSUMS: Alamofire: 907e0a98eb68cdb7f9d1f541a563d6ac5dc77b25 - CocoaLumberjack: 3c8c74683302f9012bb168e1c4b7ae3c0b558431 + CocoaLumberjack: 2e258a064cacc8eb9a2aca318e24d02a0a7fd56d IDZSwiftCommonCrypto: 4eef2c46e262dfbcbc1fd76365e066336680ad7d InputMask: 37c273bde6705187d80cf0b4240cb42ea92096c3 KeychainAccess: 94c5540b32eabf7bc32bfb976a268e8ea05fd6da - LeadKit: 7d84bb111e7b6aca0c5d3ac5aee6f99d375d94d4 - ObjectMapper: 92230db59bf8f341a5c3a3cf0b9fbdde3cf0d87f - RxAlamofire: 6ea579ac53bf14cb4bc7049a3866e5a769989b1d - RxCocoa: d62846ca96495d862fa4c59ea7d87e5031d7340e - RxSwift: fd680d75283beb5e2559486f3c0ff852f0d35334 + LeadKit: d6dd4ec58e535c3a76cbc78b53d283278f61cbfa + ObjectMapper: 20505058f54e5c3ca69e1d6de9897d152a5369a6 + RxAlamofire: 96a2bff4694a1609bb59c57b53d99ea7a0ddc64a + RxCocoa: d88ba0f1f6abf040011a9eb4b539324fc426843a + RxSwift: e49536837d9901277638493ea537394d4b55f570 SwiftLint: e14651157288e9e01d6e1a71db7014fb5744a8ea SwiftValidator: 46cdd2061962df3ee8bab3c536dea9b34191d459 - TableKit: 42d4dff2944f273cdeec2ef6352064eb6a9a355b + TableKit: 61880e4c13ac0ba396a308fcb1ae48f6dec8b458 UIScrollView-InfiniteScroll: c132d6d5851daff229ab4a1060ccf70a05a051c9 -PODFILE CHECKSUM: d2f39766e2e1169f9216c0dc43b52873927b77cc +PODFILE CHECKSUM: d35945b0ded474b18dc52df4f9b12cb7fdf59377 COCOAPODS: 1.4.0 diff --git a/Sources/Classes/BaseTextFieldViewModel/BaseTextFieldViewModel.swift b/Sources/Classes/BaseTextFieldViewModel/BaseTextFieldViewModel.swift new file mode 100644 index 0000000..7a885b8 --- /dev/null +++ b/Sources/Classes/BaseTextFieldViewModel/BaseTextFieldViewModel.swift @@ -0,0 +1,169 @@ +// +// 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 LeadKit +import RxSwift +import RxCocoa + +/// Base implementation of TextFieldViewEvents. +open class BaseTextFieldViewEvents: TextFieldViewEvents { + + public let textChangedDriver: Driver + + /// Memberwise initializer. + /// + /// - Parameter textChangedDriver: Driver that emits text changes from a view. + public init(textChangedDriver: Driver) { + self.textChangedDriver = textChangedDriver + } + +} + +/// Base implementation of text field view model events. +open class BaseTextFieldViewModelEvents: TextFieldViewModelEvents { + + public let setTextDriver: Driver + public let changeValidationStateDriver: Driver + public let changeOnlineValidationStateDriver: Driver + + /// Memberwise initializer. + /// + /// - Parameters: + /// - setTextDriver: Driver that emit text that should be set inside a view. + /// - changeValidationStateDriver: Driver that emit validation state changes events. + /// - changeOnlineValidationStateDriver: Driver that emit online validation state changes events. + public init(setTextDriver: Driver, + changeValidationStateDriver: Driver, + changeOnlineValidationStateDriver: Driver) { + + self.setTextDriver = setTextDriver + self.changeValidationStateDriver = changeValidationStateDriver + self.changeOnlineValidationStateDriver = changeOnlineValidationStateDriver + } + +} + +import SwiftValidator + +public extension BaseTextFieldViewModelEvents { + + /// Method that binds text driver to validation service via validation rules. + /// + /// - Parameters: + /// - textDriver: Driver that emits text changes. + /// - rules: Rules to validate for. + /// - validationService: Validation service to register in. + /// - Returns: Driver that emit validation state changes. + static func offlineValidationDriver(with textDriver: Driver, + using rules: [Rule] = [RequiredRule()], + in validationService: ValidationService) -> Driver { + + let validationItem = ValidationItem(rules: rules, textDriver: textDriver) + + validationService.register(item: validationItem) + + let validationStateDriver = validationItem + .validationStateObservable + .asDriver(onErrorJustReturn: .initial) + + return validationStateDriver + } + + typealias OnlineValidationClosure = (String) -> Single + + /// Method that binds text driver to validation chain (offline validation -> online validation) + /// and returns online validation state driver. + /// + /// - Parameters: + /// - textDriver: Driver that emits text changes. + /// - offlineRules: Rules to validate before online validation will be requested. + /// - validationClosure: Closure that will be called for online validation request. + /// - Returns: Driver that emit online validation state changes. + static func onlineValidationDriver(with textDriver: Driver, + using offlineRules: [Rule] = [], + validationClosure: @escaping OnlineValidationClosure) -> Driver { + + return textDriver.flatMap { string -> Driver in + guard let nonEmptyString = string, !nonEmptyString.isEmpty else { + return .just(.initial) + } + + let passedRules = offlineRules + .map { $0.validate(nonEmptyString) } + .reduce(true) { $0 && $1 } + + guard passedRules else { + return .just(.initial) + } + + let validationDriver = validationClosure(nonEmptyString).map { result -> OnlineValidationState in + if result.isValid { + return .valid + } else { + return .invalid(error: result.error) + } + } + .asDriver(onErrorJustReturn: .initial) + + return Driver.merge([.just(.initial), .just(.processing), validationDriver]) + } + } + + /// Convenience initializer with offline and online validation. + /// + /// - Parameters: + /// - binding: Data model field binding. + /// - rules: Rules to validate before online validation will be requested. + /// - validationService: Validation service to register in. + /// - onlineValidationClosure: Closure that will be called for online validation request. + /// - onlineValidationThrottle: Throttling duration for each text change. + convenience init(binding: DataModelFieldBinding, + rules: [Rule] = [RequiredRule()], + validationService: ValidationService, + onlineValidationClosure: OnlineValidationClosure? = nil, + onlineValidationThrottle: RxTimeInterval = 0.5) { + + let dataModelFieldDriver = binding.fieldDriver + + let offlineValidationDriver = BaseTextFieldViewModelEvents.offlineValidationDriver(with: dataModelFieldDriver, + using: rules, + in: validationService) + + let onlineValidationDriver: Driver + + if let onlineValidationClosure = onlineValidationClosure { + let throttledTextDriver = dataModelFieldDriver.throttle(onlineValidationThrottle) + + onlineValidationDriver = BaseTextFieldViewModelEvents + .onlineValidationDriver(with: throttledTextDriver, + using: rules, + validationClosure: onlineValidationClosure) + } else { + onlineValidationDriver = .just(.initial) + } + + self.init(setTextDriver: dataModelFieldDriver, + changeValidationStateDriver: offlineValidationDriver, + changeOnlineValidationStateDriver: onlineValidationDriver) + } + +} diff --git a/Sources/Extensions/BaseTextFieldViewEvents+Extensions.swift b/Sources/Extensions/BaseTextFieldViewEvents+Extensions.swift new file mode 100644 index 0000000..ec435ed --- /dev/null +++ b/Sources/Extensions/BaseTextFieldViewEvents+Extensions.swift @@ -0,0 +1,39 @@ +// +// 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 RxSwift + +public extension BaseTextFieldViewEvents { + + /// Convenience init with UITextField as textChangedDriver. + /// + /// - Parameter textField: UITextField to use for text events. + convenience init(textField: UITextField) { + let textChangedDriver = textField.rx + .text + .asDriver() + .distinctUntilChanged { $0 == $1 } + + self.init(textChangedDriver: textChangedDriver) + } + +} diff --git a/Sources/Protocols/CellFieldJumpingProtocol.swift b/Sources/Protocols/CellFieldJumpingProtocol.swift deleted file mode 100644 index 359ffe5..0000000 --- a/Sources/Protocols/CellFieldJumpingProtocol.swift +++ /dev/null @@ -1,38 +0,0 @@ -import RxSwift -import RxCocoa -import UIKit - -typealias ItemSettingsBlock = (UIItem) -> Void where UIItem: UIView - -protocol CellFieldJumpingProtocol: FormCellViewModelProtocol { - - var toolBar: UIToolbar? { get set } - - var shouldGoForward: PublishSubject { get } - - var shouldBecomeFirstResponder: PublishSubject { get } - var shouldResignFirstResponder: PublishSubject { get } - - var returnButtonType: UIReturnKeyType { get set } - -} - -extension CellFieldJumpingProtocol { - - func bind(for textField: UITextField, to disposeBag: DisposeBag) { - shouldResignFirstResponder.asObservable() - .observeOn(MainScheduler.instance) - .subscribe(onNext: { [weak textField] _ in - textField?.resignFirstResponder() - }) - .disposed(by: disposeBag) - - shouldBecomeFirstResponder.asObservable() - .observeOn(MainScheduler.instance) - .subscribe(onNext: { [weak textField] _ in - textField?.becomeFirstResponder() - }) - .disposed(by: disposeBag) - } - -} diff --git a/Sources/Protocols/CellFieldMaskProtocol.swift b/Sources/Protocols/CellFieldMaskProtocol.swift deleted file mode 100644 index e3e9df3..0000000 --- a/Sources/Protocols/CellFieldMaskProtocol.swift +++ /dev/null @@ -1,14 +0,0 @@ -protocol CellFieldMaskProtocol { - - var haveMask: Bool { get } - var maskFieldTextProxy: MaskFieldTextProxy? { get set } - -} - -extension CellFieldMaskProtocol { - - var haveMask: Bool { - return maskFieldTextProxy != nil - } - -} diff --git a/Sources/Protocols/CellFieldValidationProtocol.swift b/Sources/Protocols/CellFieldValidationProtocol.swift deleted file mode 100644 index b294adb..0000000 --- a/Sources/Protocols/CellFieldValidationProtocol.swift +++ /dev/null @@ -1,5 +0,0 @@ -protocol CellFieldValidationProtocol { - - var validationItem: ValidationItem? { get set } - -} diff --git a/Sources/Protocols/CellFieldsToolBarProtocol.swift b/Sources/Protocols/CellFieldsToolBarProtocol.swift deleted file mode 100644 index c2bf138..0000000 --- a/Sources/Protocols/CellFieldsToolBarProtocol.swift +++ /dev/null @@ -1,16 +0,0 @@ -import UIKit -import RxSwift - -protocol CellFieldsToolBarProtocol: class { - - var needArrows: Bool { get set } - - var canGoForward: Bool { get set } - var canGoBackward: Bool { get set } - - var shouldGoForward: PublishSubject { get } - var shouldGoBackward: PublishSubject { get } - - var shouldEndEditing: PublishSubject { get } - -} diff --git a/Sources/Protocols/FormCellViewModelProtocol.swift b/Sources/Protocols/FormCellViewModelProtocol.swift deleted file mode 100644 index 84a85c9..0000000 --- a/Sources/Protocols/FormCellViewModelProtocol.swift +++ /dev/null @@ -1,15 +0,0 @@ -import RxCocoa -import RxSwift - -protocol FormCellViewModelProtocol: class { - var isActive: Bool { get set } -} - -extension FormCellViewModelProtocol { - - func activate(_ isActive: Bool) -> Self { - self.isActive = isActive - return self - } - -} diff --git a/Sources/Protocols/ValidationService/OnlineValidationResult.swift b/Sources/Protocols/ValidationService/OnlineValidationResult.swift new file mode 100644 index 0000000..f4cdbcd --- /dev/null +++ b/Sources/Protocols/ValidationService/OnlineValidationResult.swift @@ -0,0 +1,34 @@ +// +// 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 Foundation + +/// Prototol with two fields that describes result of online validation. +public protocol OnlineValidationResult { + + /// Contains true if online validation did passed. + var isValid: Bool { get } + + /// May contain an error if validation did failed. + var error: Error? { get } + +} diff --git a/Sources/Services/CellFieldsJumpingService.swift b/Sources/Services/CellFieldsJumpingService.swift deleted file mode 100644 index 463a021..0000000 --- a/Sources/Services/CellFieldsJumpingService.swift +++ /dev/null @@ -1,138 +0,0 @@ -import RxSwift -import UIKit - -struct CellFieldsJumpingServiceConfig { - - var toolBarNeedArrows = true - - init() {} - - static var `default`: CellFieldsJumpingServiceConfig { - return CellFieldsJumpingServiceConfig() - } - -} - -class CellFieldsJumpingService { - - private var disposeBag = DisposeBag() - - // MARK: - Private properties - - private var cellFields: [CellFieldJumpingProtocol] = [] - - // MARK: - Public propertries - - var config: CellFieldsJumpingServiceConfig = .default { - didSet { - configure() - } - } - - let didDone = PublishSubject() - - // MARK: - Initialization - - init() {} - - // MARK: - Public - - func removeAll() { - cellFields.removeAll() - disposeBag = DisposeBag() - } - - func add(fieled: CellFieldJumpingProtocol, shouldConfigure: Bool = true) { - add(fieleds: [fieled], shouldConfigure: shouldConfigure) - } - - func add(fieleds: [CellFieldJumpingProtocol], shouldConfigure: Bool = true) { - cellFields += fieleds - - if shouldConfigure { - configure() - } - } - - func configure() { - disposeBag = DisposeBag() - - let cellFields = self.cellFields - - cellFields - .filter { $0.isActive } - .enumerated() - .forEach { offset, field in - field.toolBar = toolBar(for: field, with: offset) - field.returnButtonType = .next - - field.shouldGoForward.asObservable() - .subscribe(onNext: { [weak self] in - self?.shouldGoForwardAction(from: offset) - }) - .disposed(by: disposeBag) - } - - cellFields.lastActive?.returnButtonType = .done - } - - private func toolBar(for field: CellFieldJumpingProtocol, with index: Int) -> UIToolbar { - let toolBar = CellTextFieldToolBar() - toolBar.canGoForward = cellFields.nextActive(from: index) != nil - toolBar.canGoBackward = cellFields.previousActive(from: index) != nil - - toolBar.needArrows = config.toolBarNeedArrows - - toolBar.shouldGoForward.asObservable() - .subscribe(onNext: { [weak self] in - self?.shouldGoForwardAction(from: index) - }) - .disposed(by: disposeBag) - - toolBar.shouldGoBackward - .subscribe(onNext: { [weak self] in - if let previousActive = self?.cellFields.previousActive(from: index) { - previousActive.shouldBecomeFirstResponder.onNext(Void()) - } - }) - .disposed(by: disposeBag) - - toolBar.shouldEndEditing - .subscribe(onNext: { [field] in - field.shouldResignFirstResponder.onNext(Void()) - }) - .disposed(by: disposeBag) - - return toolBar - } - - private func shouldGoForwardAction(from index: Int) { - if let nextActive = cellFields.nextActive(from: index) { - nextActive.shouldBecomeFirstResponder.onNext(Void()) - } else { - didDone.onNext(Void()) - } - } - -} - -extension Array where Element == CellFieldJumpingProtocol { - - var firstActive: CellFieldJumpingProtocol? { - return first { $0.isActive } - } - - var lastActive: CellFieldJumpingProtocol? { - return reversed().first { $0.isActive } - } - - func nextActive(from index: Int) -> CellFieldJumpingProtocol? { - return enumerated().first { $0 > index && $1.isActive }?.element - } - - func previousActive(from index: Int) -> CellFieldJumpingProtocol? { - let reversedIndex = count - index - 1 - return reversed().enumerated().first { $0 > reversedIndex && $1.isActive }?.element - } - -} diff --git a/Sources/Services/ValidationService/OnlineValidationState.swift b/Sources/Services/ValidationService/OnlineValidationState.swift new file mode 100644 index 0000000..fd94af0 --- /dev/null +++ b/Sources/Services/ValidationService/OnlineValidationState.swift @@ -0,0 +1,36 @@ +// +// 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. +// + +/// Enum that describes current state of online validation. +/// +/// - initial: Nothing did happen. +/// - processing: Processing validation. +/// - valid: Got a valid result. +/// - invalid: Got an invalid result. +public enum OnlineValidationState { + + case initial + case processing + case valid + case invalid(error: Error?) + +} diff --git a/Sources/Views/CellTextField/CellTextField.swift b/Sources/Views/CellTextField/CellTextField.swift deleted file mode 100644 index b351573..0000000 --- a/Sources/Views/CellTextField/CellTextField.swift +++ /dev/null @@ -1,46 +0,0 @@ -import UIKit -import RxCocoa -import RxSwift - -class CellTextField: UITextField { - - private var disposeBag = DisposeBag() - - var viewModel: CellTextFieldViewModel? { - didSet { - configure() - } - } - - // MARK: - Init - - private func configure() { - disposeBag = DisposeBag() - - guard let viewModel = viewModel else { - return - } - - inputAccessoryView = viewModel.toolBar - returnKeyType = viewModel.returnButtonType - - text = viewModel.textValue - placeholder = viewModel.placeholder - viewModel.textFieldSettingsBlock?(self) - - viewModel.bind(for: self, to: disposeBag) - - rx.text.asDriver() - .drive(onNext: { - viewModel.setTextValue($0) - }) - .disposed(by: disposeBag) - - rx.controlEvent(.editingDidEndOnExit) - .subscribe(onNext: { [viewModel] in - viewModel.shouldGoForward.onNext(Void()) - }) - .disposed(by: disposeBag) - } - -} diff --git a/Sources/Views/CellTextField/CellTextFieldViewModel.swift b/Sources/Views/CellTextField/CellTextFieldViewModel.swift deleted file mode 100644 index b3508f8..0000000 --- a/Sources/Views/CellTextField/CellTextFieldViewModel.swift +++ /dev/null @@ -1,41 +0,0 @@ -import UIKit -import RxSwift - -class CellTextFieldViewModel: CellFieldJumpingProtocol { - - private let text: Variable - - let placeholder: String - - let textFieldSettingsBlock: ItemSettingsBlock? - - // MARK: - CellFieldJumpingProtocol - - var toolBar: UIToolbar? - - let shouldGoForward = PublishSubject() - - let shouldBecomeFirstResponder = PublishSubject() - let shouldResignFirstResponder = PublishSubject() - - var returnButtonType: UIReturnKeyType = .default - - var isActive: Bool = true - - init(initialText: String = "", placeholder: String = "", textFieldSettingsBlock: ItemSettingsBlock? = nil) { - text = Variable(initialText) - self.placeholder = placeholder - self.textFieldSettingsBlock = textFieldSettingsBlock - } - - // MARK: - Internal - - var textValue: String? { - return text.value - } - - func setTextValue(_ value: String?) { - text.value = value - } - -} diff --git a/Sources/Views/CellTextFieldToolBar.swift b/Sources/Views/CellTextFieldToolBar.swift deleted file mode 100644 index 724870d..0000000 --- a/Sources/Views/CellTextFieldToolBar.swift +++ /dev/null @@ -1,107 +0,0 @@ -import UIKit -import RxSwift -import RxCocoa -import LeadKit - -class CellTextFieldToolBar: UIToolbar, CellFieldsToolBarProtocol { - - private let buttonSpace: CGFloat = 20 - - // MARK: - CellFieldsToolBarProtocol - - var needArrows: Bool = true - - var canGoForward: Bool = false { - didSet { - forwardButton.isEnabled = canGoForward - } - } - var canGoBackward: Bool = false { - didSet { - backButton.isEnabled = canGoBackward - } - } - - var shouldGoForward = PublishSubject() - var shouldGoBackward = PublishSubject() - var shouldEndEditing = PublishSubject() - - // MARK: - UIBarButtonItems - - var backButtonImage: UIImage? { - didSet { - backButton.image = backButtonImage - } - } - var forwardButtonImage: UIImage? { - didSet { - backButton.image = backButtonImage - } - } - - private(set) lazy var backButton: UIBarButtonItem = { - let backButton = UIBarButtonItem(image: self.backButtonImage, - style: .plain, - target: self, - action: #selector(backAction)) - return backButton - }() - - private(set) lazy var forwardButton: UIBarButtonItem = { - let forwardButton = UIBarButtonItem(image: self.forwardButtonImage, - style: .plain, - target: self, - action: #selector(forwardAction)) - return forwardButton - }() - - private(set) lazy var closeButton: UIBarButtonItem = { - let doneButton = UIBarButtonItem(barButtonSystemItem: .done, - target: self, - action: #selector(doneAction)) - return doneButton - }() - - // MARK: - Initialization - - override init(frame: CGRect) { - super.init(frame: frame) - initialization() - } - - required init?(coder aDecoder: NSCoder) { - super.init(coder: aDecoder) - initialization() - } - - private func initialization() { - barStyle = .default - isTranslucent = true - tintColor = UIColor(hex6: 0x0A84DF) - sizeToFit() - - let leftSpacer = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil) - let firstButtonsSpacer = UIBarButtonItem(barButtonSystemItem: .fixedSpace, target: nil, action: nil) - firstButtonsSpacer.width = buttonSpace - let secondButtonsSpacer = UIBarButtonItem(barButtonSystemItem: .fixedSpace, target: nil, action: nil) - secondButtonsSpacer.width = buttonSpace - - setItems([leftSpacer, backButton, firstButtonsSpacer, forwardButton, secondButtonsSpacer, closeButton], animated: true) - items?.forEach { $0.tintColor = tintColor } - } - - // MARK: - Actions - - @objc private func backAction() { - shouldGoBackward.onNext(Void()) - } - - @objc private func forwardAction() { - shouldGoForward.onNext(Void()) - } - - @objc private func doneAction() { - shouldEndEditing.onNext(Void()) - } - -}