trying out a new subclass.
This commit is contained in:
parent
929b825e11
commit
6c8ced47c9
@ -19,16 +19,22 @@
|
||||
01E569D3223FFFA500327251 /* ThreeLayerViewController.swift in Headers */ = {isa = PBXBuildFile; fileRef = D2A5146A2214905000345BFB /* ThreeLayerViewController.swift */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
0A1214A022C11A18007C7030 /* ActionDetailWithImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A12149F22C11A17007C7030 /* ActionDetailWithImage.swift */; };
|
||||
0A1B4A96233BB18F005B3FB4 /* CheckboxWithLabelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAFA2232BE63400FB8E22 /* CheckboxWithLabelView.swift */; };
|
||||
0A21DB6E2359EEF800C160A2 /* DigitTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A8321AC2355FC2600CB7F00 /* DigitTextField.swift */; };
|
||||
0A21DB7F235DECC500C160A2 /* FieldEntryForm.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A21DB7E235DECC500C160A2 /* FieldEntryForm.swift */; };
|
||||
0A21DB83235DFBC500C160A2 /* MdnEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A21DB82235DFBC500C160A2 /* MdnEntryField.swift */; };
|
||||
0A21DB84235E06EF00C160A2 /* MFTextField.h in Headers */ = {isa = PBXBuildFile; fileRef = D29DF24C21E6A177003B2FB9 /* MFTextField.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
0A21DB85235E06EF00C160A2 /* MFTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = D29DF24221E6A176003B2FB9 /* MFTextField.m */; };
|
||||
0A21DB86235E06EF00C160A2 /* MFTextField.xib in Resources */ = {isa = PBXBuildFile; fileRef = D29DF24421E6A176003B2FB9 /* MFTextField.xib */; };
|
||||
0A21DB87235E06EF00C160A2 /* MFTextFieldSubclassExtension.h in Headers */ = {isa = PBXBuildFile; fileRef = D29DF24B21E6A177003B2FB9 /* MFTextFieldSubclassExtension.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
0A21DB88235E06EF00C160A2 /* MFMdnTextField.h in Headers */ = {isa = PBXBuildFile; fileRef = D29DF24721E6A176003B2FB9 /* MFMdnTextField.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
0A21DB89235E06EF00C160A2 /* MFMdnTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = D29DF24921E6A177003B2FB9 /* MFMdnTextField.m */; };
|
||||
0A21DB8A235E06EF00C160A2 /* MFDigitTextBox.h in Headers */ = {isa = PBXBuildFile; fileRef = D29DF24521E6A176003B2FB9 /* MFDigitTextBox.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
0A21DB8B235E06EF00C160A2 /* MFDigitTextBox.m in Sources */ = {isa = PBXBuildFile; fileRef = D29DF24621E6A176003B2FB9 /* MFDigitTextBox.m */; };
|
||||
0A21DB8C235E06EF00C160A2 /* MFDigitTextField.h in Headers */ = {isa = PBXBuildFile; fileRef = D29DF24321E6A176003B2FB9 /* MFDigitTextField.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
0A21DB8D235E06EF00C160A2 /* MFDigitTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = D29DF24821E6A177003B2FB9 /* MFDigitTextField.m */; };
|
||||
0A21DB8E235E06EF00C160A2 /* MFDigitTextField.xib in Resources */ = {isa = PBXBuildFile; fileRef = D29DF24A21E6A177003B2FB9 /* MFDigitTextField.xib */; };
|
||||
0A41BA6E2344FCD400D4C0BC /* CATransaction+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A41BA6D2344FCD400D4C0BC /* CATransaction+Extension.swift */; };
|
||||
0A41BA7F23453A6400D4C0BC /* TextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A41BA7E23453A6400D4C0BC /* TextField.swift */; };
|
||||
0A52C1492357B5380051AECD /* MdnTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A8321A72355062F00CB7F00 /* MdnTextField.swift */; };
|
||||
0A52C14A2358B57E0051AECD /* DigitTextBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A8321AE2355FE9500CB7F00 /* DigitTextBox.swift */; };
|
||||
0A41BA7F23453A6400D4C0BC /* TextEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A41BA7E23453A6400D4C0BC /* TextEntryField.swift */; };
|
||||
0A7BAFA1232BE61800FB8E22 /* Checkbox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAFA0232BE61800FB8E22 /* Checkbox.swift */; };
|
||||
0A8321C523563D3500CB7F00 /* MFTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = D29DF24221E6A176003B2FB9 /* MFTextField.m */; };
|
||||
0A8321C623563D3800CB7F00 /* MFTextField.h in Headers */ = {isa = PBXBuildFile; fileRef = D29DF24C21E6A177003B2FB9 /* MFTextField.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
0A8321C723563D4000CB7F00 /* MFMdnTextField.h in Headers */ = {isa = PBXBuildFile; fileRef = D29DF24721E6A176003B2FB9 /* MFMdnTextField.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
0A8321C823563D4300CB7F00 /* MFMdnTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = D29DF24921E6A177003B2FB9 /* MFMdnTextField.m */; };
|
||||
9455B19C234F8A0400A574DB /* MVMAnimationFramework.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9455B19B234F8A0400A574DB /* MVMAnimationFramework.framework */; };
|
||||
948DB67E2326DCD90011F916 /* MultiProgress.swift in Sources */ = {isa = PBXBuildFile; fileRef = 948DB67D2326DCD90011F916 /* MultiProgress.swift */; };
|
||||
B8200E152280C4CF007245F4 /* ProgressBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8200E142280C4CF007245F4 /* ProgressBar.swift */; };
|
||||
@ -104,13 +110,6 @@
|
||||
D29DF18121E69E50003B2FB9 /* MFView.m in Sources */ = {isa = PBXBuildFile; fileRef = D29DF17F21E69E2E003B2FB9 /* MFView.m */; };
|
||||
D29DF18221E69E54003B2FB9 /* SeparatorView.h in Headers */ = {isa = PBXBuildFile; fileRef = D29DF15921E697DA003B2FB9 /* SeparatorView.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
D29DF18321E69E54003B2FB9 /* SeparatorView.m in Sources */ = {isa = PBXBuildFile; fileRef = D29DF15A21E697DA003B2FB9 /* SeparatorView.m */; };
|
||||
D29DF24E21E6A177003B2FB9 /* MFDigitTextField.h in Headers */ = {isa = PBXBuildFile; fileRef = D29DF24321E6A176003B2FB9 /* MFDigitTextField.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
D29DF24F21E6A177003B2FB9 /* MFTextField.xib in Resources */ = {isa = PBXBuildFile; fileRef = D29DF24421E6A176003B2FB9 /* MFTextField.xib */; };
|
||||
D29DF25021E6A177003B2FB9 /* MFDigitTextBox.h in Headers */ = {isa = PBXBuildFile; fileRef = D29DF24521E6A176003B2FB9 /* MFDigitTextBox.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
D29DF25121E6A177003B2FB9 /* MFDigitTextBox.m in Sources */ = {isa = PBXBuildFile; fileRef = D29DF24621E6A176003B2FB9 /* MFDigitTextBox.m */; };
|
||||
D29DF25321E6A177003B2FB9 /* MFDigitTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = D29DF24821E6A177003B2FB9 /* MFDigitTextField.m */; };
|
||||
D29DF25521E6A177003B2FB9 /* MFDigitTextField.xib in Resources */ = {isa = PBXBuildFile; fileRef = D29DF24A21E6A177003B2FB9 /* MFDigitTextField.xib */; };
|
||||
D29DF25621E6A177003B2FB9 /* MFTextFieldSubclassExtension.h in Headers */ = {isa = PBXBuildFile; fileRef = D29DF24B21E6A177003B2FB9 /* MFTextFieldSubclassExtension.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
D29DF25921E6A22D003B2FB9 /* MFButtonProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = D29DF25821E6A22D003B2FB9 /* MFButtonProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
D29DF26C21E6AA0B003B2FB9 /* FLAnimatedImage.m in Sources */ = {isa = PBXBuildFile; fileRef = D29DF26821E6AA0B003B2FB9 /* FLAnimatedImage.m */; };
|
||||
D29DF26D21E6AA0B003B2FB9 /* FLAnimatedImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = D29DF26921E6AA0B003B2FB9 /* FLAnimatedImageView.m */; };
|
||||
@ -210,8 +209,11 @@
|
||||
01DF55DF21F8FAA800CC099B /* MFTextFieldListView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MFTextFieldListView.swift; sourceTree = "<group>"; };
|
||||
01DF566F21FA5AB300CC099B /* TextFieldListFormViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextFieldListFormViewController.swift; sourceTree = "<group>"; };
|
||||
0A12149F22C11A17007C7030 /* ActionDetailWithImage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionDetailWithImage.swift; sourceTree = "<group>"; };
|
||||
0A21DB7E235DECC500C160A2 /* FieldEntryForm.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FieldEntryForm.swift; sourceTree = "<group>"; };
|
||||
0A21DB80235DF87300C160A2 /* TextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextField.swift; sourceTree = "<group>"; };
|
||||
0A21DB82235DFBC500C160A2 /* MdnEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MdnEntryField.swift; sourceTree = "<group>"; };
|
||||
0A41BA6D2344FCD400D4C0BC /* CATransaction+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CATransaction+Extension.swift"; sourceTree = "<group>"; };
|
||||
0A41BA7E23453A6400D4C0BC /* TextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextField.swift; sourceTree = "<group>"; };
|
||||
0A41BA7E23453A6400D4C0BC /* TextEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextEntryField.swift; sourceTree = "<group>"; };
|
||||
0A7BAFA0232BE61800FB8E22 /* Checkbox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Checkbox.swift; sourceTree = "<group>"; };
|
||||
0A7BAFA2232BE63400FB8E22 /* CheckboxWithLabelView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckboxWithLabelView.swift; sourceTree = "<group>"; };
|
||||
0A8321A72355062F00CB7F00 /* MdnTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MdnTextField.swift; sourceTree = "<group>"; };
|
||||
@ -757,10 +759,13 @@
|
||||
D29DF24321E6A176003B2FB9 /* MFDigitTextField.h */,
|
||||
D29DF24821E6A177003B2FB9 /* MFDigitTextField.m */,
|
||||
D29DF24A21E6A177003B2FB9 /* MFDigitTextField.xib */,
|
||||
0A41BA7E23453A6400D4C0BC /* TextField.swift */,
|
||||
0A41BA7E23453A6400D4C0BC /* TextEntryField.swift */,
|
||||
0A8321A72355062F00CB7F00 /* MdnTextField.swift */,
|
||||
0A8321AC2355FC2600CB7F00 /* DigitTextField.swift */,
|
||||
0A8321AE2355FE9500CB7F00 /* DigitTextBox.swift */,
|
||||
0A21DB7E235DECC500C160A2 /* FieldEntryForm.swift */,
|
||||
0A21DB80235DF87300C160A2 /* TextField.swift */,
|
||||
0A21DB82235DFBC500C160A2 /* MdnEntryField.swift */,
|
||||
);
|
||||
path = TextFields;
|
||||
sourceTree = "<group>";
|
||||
@ -881,27 +886,27 @@
|
||||
D29DF11C21E684A9003B2FB9 /* MVMCoreUISplitViewController.h in Headers */,
|
||||
D29DF29B21E7ADB9003B2FB9 /* StackableViewController.h in Headers */,
|
||||
D29770F421F7C6D600B2F0D0 /* TopLabelsAndBottomButtonsViewController.h in Headers */,
|
||||
0A8321C723563D4000CB7F00 /* MFMdnTextField.h in Headers */,
|
||||
D29DF15421E69760003B2FB9 /* MVMCoreUIPanelButtonProtocol.h in Headers */,
|
||||
D2A514582211C53C00345BFB /* MVMCoreUIMoleculeMappingObject.h in Headers */,
|
||||
D29DF0D121E404D4003B2FB9 /* MVMCoreUI.h in Headers */,
|
||||
D29DF29A21E7ADB8003B2FB9 /* MFProgrammaticTableViewController.h in Headers */,
|
||||
D29DF25621E6A177003B2FB9 /* MFTextFieldSubclassExtension.h in Headers */,
|
||||
D29DF11521E6805F003B2FB9 /* UIColor+MFConvenience.h in Headers */,
|
||||
D29DF2BC21E7BEA4003B2FB9 /* TopTabbar.h in Headers */,
|
||||
D29DF25921E6A22D003B2FB9 /* MFButtonProtocol.h in Headers */,
|
||||
D22D1F46220496A30077CEC0 /* MVMCoreUISwitch.h in Headers */,
|
||||
0A8321C623563D3800CB7F00 /* MFTextField.h in Headers */,
|
||||
D22D1F1E220343560077CEC0 /* MVMCoreUICheckMarkView.h in Headers */,
|
||||
D29DF28421E7AB24003B2FB9 /* MVMCoreUICommonViewsUtility.h in Headers */,
|
||||
0A21DB87235E06EF00C160A2 /* MFTextFieldSubclassExtension.h in Headers */,
|
||||
D22D1F562204CE5D0077CEC0 /* MVMCoreUIStackableViewController.h in Headers */,
|
||||
D29DF2CE21E7C104003B2FB9 /* MFLoadingViewController.h in Headers */,
|
||||
0A21DB84235E06EF00C160A2 /* MFTextField.h in Headers */,
|
||||
D29DF12A21E6851E003B2FB9 /* MVMCoreUITopAlertView.h in Headers */,
|
||||
D29DF27521E79E81003B2FB9 /* MVMCoreUILoggingHandler.h in Headers */,
|
||||
D29DF28B21E7AC2B003B2FB9 /* ViewConstrainingView.h in Headers */,
|
||||
D29DF2B321E7B76D003B2FB9 /* MFLoadingSpinner.h in Headers */,
|
||||
0A21DB8A235E06EF00C160A2 /* MFDigitTextBox.h in Headers */,
|
||||
D29DF32521ED0DA2003B2FB9 /* TextButtonView.h in Headers */,
|
||||
D29DF25021E6A177003B2FB9 /* MFDigitTextBox.h in Headers */,
|
||||
0A21DB8C235E06EF00C160A2 /* MFDigitTextField.h in Headers */,
|
||||
D296E14722A5984C0051EBE7 /* MVMCoreUIViewConstrainingProtocol.h in Headers */,
|
||||
D29DF2C621E7BF57003B2FB9 /* MFTabBarInteractor.h in Headers */,
|
||||
D29DF17521E69E1F003B2FB9 /* ButtonDelegateProtocol.h in Headers */,
|
||||
@ -911,6 +916,7 @@
|
||||
D29DF17721E69E1F003B2FB9 /* MFTextButton.h in Headers */,
|
||||
01E569D3223FFFA500327251 /* ThreeLayerViewController.swift in Headers */,
|
||||
D29DF16221E69996003B2FB9 /* MFViewController.h in Headers */,
|
||||
0A21DB88235E06EF00C160A2 /* MFMdnTextField.h in Headers */,
|
||||
D29DF13121E6851E003B2FB9 /* MVMCoreUITopAlertExpandableView.h in Headers */,
|
||||
D29DF2C421E7BF57003B2FB9 /* MFTabBarSwipeAnimator.h in Headers */,
|
||||
D2A5145D2211D22A00345BFB /* MVMCoreUIMoleculeViewProtocol.h in Headers */,
|
||||
@ -920,7 +926,6 @@
|
||||
D29DF2BD21E7BEA4003B2FB9 /* MVMCoreUITabBarPageControlViewController.h in Headers */,
|
||||
D29DF2EE21ECEADF003B2FB9 /* MFFonts.h in Headers */,
|
||||
D29DF12D21E6851E003B2FB9 /* MVMCoreUITopAlertBaseView.h in Headers */,
|
||||
D29DF24E21E6A177003B2FB9 /* MFDigitTextField.h in Headers */,
|
||||
D29770F321F7C6D600B2F0D0 /* TopLabelsAndBottomButtonsTableViewController.h in Headers */,
|
||||
D296E1412295EBBA0051EBE7 /* MoleculeDelegateProtocol.h in Headers */,
|
||||
D2C5001821F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.h in Headers */,
|
||||
@ -1002,12 +1007,12 @@
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
D29DF25521E6A177003B2FB9 /* MFDigitTextField.xib in Resources */,
|
||||
D29DF2AF21E7B3A4003B2FB9 /* MFTextView.xib in Resources */,
|
||||
D29DF31C21ECECC0003B2FB9 /* NHaasGroteskDSStd-75Bd.otf in Resources */,
|
||||
D29DF24F21E6A177003B2FB9 /* MFTextField.xib in Resources */,
|
||||
D29DF31D21ECECC0003B2FB9 /* NHaasGroteskDSStd-55Rg.otf in Resources */,
|
||||
0A21DB8E235E06EF00C160A2 /* MFDigitTextField.xib in Resources */,
|
||||
D29DF32C21EE8736003B2FB9 /* Localizable.strings in Resources */,
|
||||
0A21DB86235E06EF00C160A2 /* MFTextField.xib in Resources */,
|
||||
D29DF31A21ECECC0003B2FB9 /* NHaasGroteskDSStd-45Lt.otf in Resources */,
|
||||
D29DF32E21EE8C3D003B2FB9 /* Media.xcassets in Resources */,
|
||||
D29DF31B21ECECC0003B2FB9 /* OCRAExtended.ttf in Resources */,
|
||||
@ -1033,13 +1038,13 @@
|
||||
D22D1F1F220343560077CEC0 /* MVMCoreUICheckMarkView.m in Sources */,
|
||||
D282AAB4223FDDAE00C46919 /* MFLoadImageView.swift in Sources */,
|
||||
D29DF11721E6805F003B2FB9 /* UIColor+MFConvenience.m in Sources */,
|
||||
D29DF25321E6A177003B2FB9 /* MFDigitTextField.m in Sources */,
|
||||
D29DF12F21E6851E003B2FB9 /* MVMCoreUITopAlertMainView.m in Sources */,
|
||||
DBC4392122491730001AB423 /* LabelWithInternalButton.swift in Sources */,
|
||||
D224798C231450C8003FCCF9 /* HeadlineBodySwitch.swift in Sources */,
|
||||
D29DF17C21E69E1F003B2FB9 /* MFTextButton.m in Sources */,
|
||||
D29DF2C521E7BF57003B2FB9 /* MFTabBarSwipeAnimator.m in Sources */,
|
||||
D29DF2B421E7B76D003B2FB9 /* MFLoadingSpinner.m in Sources */,
|
||||
0A21DB7F235DECC500C160A2 /* FieldEntryForm.swift in Sources */,
|
||||
D2C5001921F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m in Sources */,
|
||||
D29DF12E21E6851E003B2FB9 /* MVMCoreUITopAlertView.m in Sources */,
|
||||
D29DF2CF21E7C104003B2FB9 /* MFLoadingViewController.m in Sources */,
|
||||
@ -1047,9 +1052,9 @@
|
||||
01DF567021FA5AB300CC099B /* TextFieldListFormViewController.swift in Sources */,
|
||||
D2A5145F2211DDC100345BFB /* MoleculeStackView.swift in Sources */,
|
||||
D29DF27621E79E81003B2FB9 /* MVMCoreUILoggingHandler.m in Sources */,
|
||||
0A8321C823563D4300CB7F00 /* MFMdnTextField.m in Sources */,
|
||||
D29DF2A221E7AF4E003B2FB9 /* MVMCoreUIUtility.m in Sources */,
|
||||
D29DF12B21E6851E003B2FB9 /* MVMCoreUITopAlertExpandableView.m in Sources */,
|
||||
0A21DB85235E06EF00C160A2 /* MFTextField.m in Sources */,
|
||||
B8200E152280C4CF007245F4 /* ProgressBar.swift in Sources */,
|
||||
D282AABA224131D100C46919 /* MFTransparentGIFView.swift in Sources */,
|
||||
D2A514672213885800345BFB /* StandardHeaderView.swift in Sources */,
|
||||
@ -1058,11 +1063,11 @@
|
||||
D29DF13021E6851E003B2FB9 /* MVMCoreUITopAlertShortView.m in Sources */,
|
||||
D28B4F8B21FF967C00712C7A /* MVMCoreUIObject.m in Sources */,
|
||||
0A1B4A96233BB18F005B3FB4 /* CheckboxWithLabelView.swift in Sources */,
|
||||
0A21DB8B235E06EF00C160A2 /* MFDigitTextBox.m in Sources */,
|
||||
D260D7B222D65BDD007E7233 /* MVMCoreUIPageControl.m in Sources */,
|
||||
D29DF26D21E6AA0B003B2FB9 /* FLAnimatedImageView.m in Sources */,
|
||||
D29DF2EF21ECEAE1003B2FB9 /* MFFonts.m in Sources */,
|
||||
D22479942316AE5E003FCCF9 /* NSLayoutConstraintExtension.swift in Sources */,
|
||||
0A8321C523563D3500CB7F00 /* MFTextField.m in Sources */,
|
||||
D282AACB2243C61700C46919 /* ButtonView.swift in Sources */,
|
||||
D2D6CD4222E78FAB00D701B8 /* ThreeLayerTemplate.swift in Sources */,
|
||||
0105618F224BBE7700E1557D /* FormValidator+FormParams.swift in Sources */,
|
||||
@ -1070,7 +1075,7 @@
|
||||
D22479962316AF6E003FCCF9 /* HeadlineBodyTextButton.swift in Sources */,
|
||||
D2E1FADD2268B25E00AEFD8C /* MoleculeTableViewCell.swift in Sources */,
|
||||
D29DF2AE21E7B3A4003B2FB9 /* MFTextView.m in Sources */,
|
||||
0A41BA7F23453A6400D4C0BC /* TextField.swift in Sources */,
|
||||
0A41BA7F23453A6400D4C0BC /* TextEntryField.swift in Sources */,
|
||||
D29DF18121E69E50003B2FB9 /* MFView.m in Sources */,
|
||||
D29DF18321E69E54003B2FB9 /* SeparatorView.m in Sources */,
|
||||
D29DF17A21E69E1F003B2FB9 /* MFCustomButton.m in Sources */,
|
||||
@ -1091,6 +1096,7 @@
|
||||
D29DF16121E69996003B2FB9 /* MFViewController.m in Sources */,
|
||||
D2E1FAE12268E81D00AEFD8C /* MoleculeListTemplate.swift in Sources */,
|
||||
DB06250B2293456500B72DD3 /* LeftRightLabelView.swift in Sources */,
|
||||
0A21DB89235E06EF00C160A2 /* MFMdnTextField.m in Sources */,
|
||||
D224798A2314445E003FCCF9 /* LabelSwitch.swift in Sources */,
|
||||
D22D1F47220496A30077CEC0 /* MVMCoreUISwitch.m in Sources */,
|
||||
D29DF28C21E7AC2B003B2FB9 /* ViewConstrainingView.m in Sources */,
|
||||
@ -1100,20 +1106,19 @@
|
||||
0198F79F225679880066C936 /* FormValidationProtocol.swift in Sources */,
|
||||
D29DF29821E7ADB8003B2FB9 /* MFScrollingViewController.m in Sources */,
|
||||
D29770C821F7C4AE00B2F0D0 /* TopLabelsView.m in Sources */,
|
||||
0A21DB6E2359EEF800C160A2 /* DigitTextField.swift in Sources */,
|
||||
D2E1FADF2268B8E700AEFD8C /* ThreeLayerTableViewController.swift in Sources */,
|
||||
0A21DB83235DFBC500C160A2 /* MdnEntryField.swift in Sources */,
|
||||
D20A9A5E2243D3E300ADE781 /* TwoButtonView.swift in Sources */,
|
||||
D2B1E3E522F37D6A0065F95C /* ImageHeadlineBody.swift in Sources */,
|
||||
0A21DB8D235E06EF00C160A2 /* MFDigitTextField.m in Sources */,
|
||||
D29DF2AA21E7B2F9003B2FB9 /* MVMCoreUIConstants.m in Sources */,
|
||||
948DB67E2326DCD90011F916 /* MultiProgress.swift in Sources */,
|
||||
D2A5146122121FBF00345BFB /* MoleculeStackTemplate.swift in Sources */,
|
||||
D29DF11821E6805F003B2FB9 /* NSLayoutConstraint+MFConvenience.m in Sources */,
|
||||
D29DF26C21E6AA0B003B2FB9 /* FLAnimatedImage.m in Sources */,
|
||||
D29770FC21F7C77400B2F0D0 /* MVMCoreUITextFieldView.m in Sources */,
|
||||
D29DF25121E6A177003B2FB9 /* MFDigitTextBox.m in Sources */,
|
||||
DBC4391B224421A0001AB423 /* CaretButton.swift in Sources */,
|
||||
0198F7A82256A80B0066C936 /* MFRadioButton.m in Sources */,
|
||||
0A52C1492357B5380051AECD /* MdnTextField.swift in Sources */,
|
||||
0A41BA6E2344FCD400D4C0BC /* CATransaction+Extension.swift in Sources */,
|
||||
D29DF13221E6851E003B2FB9 /* MVMCoreUITopAlertBaseView.m in Sources */,
|
||||
D29DF29C21E7ADB9003B2FB9 /* MFProgrammaticTableViewController.m in Sources */,
|
||||
@ -1122,7 +1127,6 @@
|
||||
D29DF2BE21E7BEA4003B2FB9 /* TopTabbar.m in Sources */,
|
||||
D2A514632213643100345BFB /* MoleculeStackCenteredTemplate.swift in Sources */,
|
||||
D29DF32421ED0DA2003B2FB9 /* TextButtonView.m in Sources */,
|
||||
0A52C14A2358B57E0051AECD /* DigitTextBox.swift in Sources */,
|
||||
D29DF29E21E7AE3B003B2FB9 /* MFStyler.m in Sources */,
|
||||
B8200E192281DC1A007245F4 /* CornerLabels.swift in Sources */,
|
||||
D2A514592211C53C00345BFB /* MVMCoreUIMoleculeMappingObject.m in Sources */,
|
||||
|
||||
@ -14,7 +14,7 @@ import UIKit
|
||||
// MARK: - Outlets
|
||||
//--------------------------------------------------
|
||||
|
||||
private weak var textFieldsView: UIView?
|
||||
private weak var digitFieldsView: UIView?
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
@ -22,7 +22,97 @@ import UIKit
|
||||
|
||||
private var numberOfDigits = 0
|
||||
private var switchedAutomatically = false
|
||||
public var textFields: [DigitTextBox]?
|
||||
public var digitFields: [DigitTextBox]?
|
||||
|
||||
/// Setgs placeholder text in the textField.
|
||||
public override var placeholder: String? {
|
||||
get {
|
||||
var string = ""
|
||||
|
||||
for digitField in digitFields ?? [] {
|
||||
if let placeholderText = digitField.attributedPlaceholder?.string {
|
||||
string += placeholderText
|
||||
}
|
||||
}
|
||||
|
||||
return !string.isEmpty ? string : nil
|
||||
}
|
||||
set {
|
||||
guard let placeholderValue = newValue else { return }
|
||||
|
||||
(digitFields as NSArray?)?.enumerateObjects({ obj, idx, stop in
|
||||
|
||||
if idx < (newValue?.count ?? 0) {
|
||||
|
||||
let stringForIndex = (newValue as NSString?)?.substring(with: NSRange(location: idx, length: 1))
|
||||
obj.attributedPlaceholder = NSAttributedString(string: stringForIndex ?? "", attributes: [
|
||||
NSAttributedString.Key.foregroundColor: UIColor.mfBattleshipGrey()])
|
||||
} else if stop != nil {
|
||||
stop = true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// If there is already text in the textfield, set the place holder label below.
|
||||
if placeholderErrorLabel.length > 0 && !errorShowing {
|
||||
placeholderErrorLabel.text = newValue
|
||||
|
||||
} else if !errorShowing {
|
||||
placeholderErrorLabel.text = ""
|
||||
}
|
||||
|
||||
if label.text.length > 0 {
|
||||
labelToTextFieldPin?.constant = 10
|
||||
} else {
|
||||
labelToTextFieldPin?.constant = 0
|
||||
}
|
||||
|
||||
// adding missing accessibilityLabel value
|
||||
// if we have some value in accessibilityLabel,
|
||||
// then only can append regular and picker item
|
||||
textField.accessibilityLabel() = newValue ?? "" + (MVMCoreUIUtility.hardcodedString(withKey: "mfdigittextfield_regular"))
|
||||
|
||||
}
|
||||
|
||||
public override var text: String? {
|
||||
get {
|
||||
var string = ""
|
||||
|
||||
for digitField in digitFields ?? [] {
|
||||
if let digitText = digitField.text {
|
||||
string += digitText
|
||||
}
|
||||
}
|
||||
|
||||
return string
|
||||
}
|
||||
set {
|
||||
(textFields as NSArray?)?.enumerateObjects( { obj, idx, stop in
|
||||
|
||||
if idx < (text?.count ?? 0) {
|
||||
let stringForIndex = (text as NSString?)?.substring(with: NSRange(location: idx, length: 1))
|
||||
obj.text = stringForIndex
|
||||
} else if stop != nil {
|
||||
stop = true
|
||||
}
|
||||
})
|
||||
valueChanged()
|
||||
}
|
||||
}
|
||||
|
||||
public override var formText: String? {
|
||||
get {
|
||||
return formLabel?.text
|
||||
}
|
||||
set {
|
||||
if let formText = newValue, !formText.isEmpty > 0 {
|
||||
messageToTextFieldPin?.constant = 10
|
||||
} else {
|
||||
messageToTextFieldPin?.constant = 0
|
||||
}
|
||||
super.formText = newValue
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Constraints
|
||||
@ -44,81 +134,84 @@ import UIKit
|
||||
super.init(frame: .zero)
|
||||
|
||||
self.numberOfDigits = numberOfDigits
|
||||
buildTextFieldsView(forSize: MVMCoreUISplitViewController.getDetailViewWidth())
|
||||
buildTextFieldsView(size: MVMCoreUISplitViewController.getDetailViewWidth())
|
||||
}
|
||||
|
||||
public init(numberOfDigits: Int, bothDelegates delegates: (UITextFieldDelegate & MFTextFieldDelegate)?) {
|
||||
super.init(bothDelegates: delegates as? (TextFieldDelegate & UITextFieldDelegate))
|
||||
|
||||
self.numberOfDigits = numberOfDigits
|
||||
buildTextFieldsView(forSize: MVMCoreUISplitViewController.getDetailViewWidth())
|
||||
buildTextFieldsView(size: MVMCoreUISplitViewController.getDetailViewWidth())
|
||||
}
|
||||
|
||||
public init(withNumberOfDigits numberOfDigits: Int, withBothDelegates delegate: (UITextFie.ldDelegate & MFTextFieldDelegate)?, size: CGFloat) {
|
||||
public init(withNumberOfDigits numberOfDigits: Int, withBothDelegates delegate: (UITextFieldDelegate & MFTextFieldDelegate)?, size: CGFloat) {
|
||||
super.init(bothDelegates: delegate as? (TextFieldDelegate & UITextFieldDelegate))
|
||||
|
||||
self.numberOfDigits = numberOfDigits
|
||||
buildTextFieldsView(forSize: size)
|
||||
buildTextFieldsView(size: size)
|
||||
}
|
||||
|
||||
private func setup() {
|
||||
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Methods
|
||||
//--------------------------------------------------
|
||||
|
||||
func createDigitField() -> DigitTextBox? {
|
||||
func createDigitField() -> DigitTextBox {
|
||||
|
||||
let textField = DigitTextBox()
|
||||
textField.delegate = self
|
||||
textField.textBoxDelegate = self
|
||||
|
||||
return textField
|
||||
}
|
||||
|
||||
func buildTextFieldsView(forSize size: CGFloat) {
|
||||
func buildTextFieldsView(size: CGFloat) {
|
||||
|
||||
// Remove all current UI.
|
||||
if let textFields = textFields, !textFields.isEmpty {
|
||||
StackableViewController.remove(textFields)
|
||||
if let digitFields = digitFields, !digitFields.isEmpty {
|
||||
StackableViewController.remove(digitFields)
|
||||
}
|
||||
|
||||
if numberOfDigits > 0 {
|
||||
|
||||
var textFields = [AnyHashable](repeating: 0, count: numberOfDigits)
|
||||
let digitFields = [DigitTextBox](repeating: createDigitField(), count: numberOfDigits)
|
||||
|
||||
for i in 0..<numberOfDigits {
|
||||
let textField = createDigitField()
|
||||
textField?.updateView(size)
|
||||
|
||||
if let textField = textField {
|
||||
textFields.append(textField)
|
||||
}
|
||||
for digitField in digitFields {
|
||||
digitField.updateView(size)
|
||||
}
|
||||
self.textFields = textFields as? [DigitTextBox]
|
||||
|
||||
self.digitFields = digitFields
|
||||
setupTextFieldsView(forSize: size)
|
||||
|
||||
} else {
|
||||
textFields = nil
|
||||
digitFields = nil
|
||||
}
|
||||
}
|
||||
|
||||
func setupTextFieldsView(forSize size: CGFloat) {
|
||||
|
||||
guard let space = MFSizeObject(standardSize: 5, smalliPhoneSize: 3)?.getValueBasedOnScreenSize(),
|
||||
let textFieldsView = textFieldsView,
|
||||
let textFields = textFields
|
||||
let digitFieldsView = digitFieldsView,
|
||||
let digitFields = digitFields
|
||||
else { return }
|
||||
|
||||
StackableViewController.populateViewHorizontally(textFieldsView, withUIArray: textFields, withSpacingBlock: { object in
|
||||
StackableViewController.populateViewHorizontally(digitFieldsView, withUIArray: digitFields, withSpacingBlock: { object in
|
||||
|
||||
var inset = UIEdgeInsets(top: 0, left: space, bottom: 0, right: space)
|
||||
|
||||
if self.textFields?.count == 1 {
|
||||
guard let digitFields = self.digitFields else { return inset }
|
||||
|
||||
if digitFields.count == 1 {
|
||||
inset.left = 0
|
||||
inset.right = 0
|
||||
|
||||
} else if (object as? UITextField) == self.textFields?.first {
|
||||
} else if let field = object as? UITextField, field == digitFields.first {
|
||||
inset.left = 0
|
||||
|
||||
} else if (object as? UITextField) == self.textFields?.last {
|
||||
} else if let field = object as? UITextField, field == digitFields.last {
|
||||
inset.right = 0
|
||||
}
|
||||
|
||||
@ -130,12 +223,13 @@ import UIKit
|
||||
super.valueChanged()
|
||||
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
|
||||
if (self?.placeholder!.count)! > 0 {
|
||||
self?.labelToTextFieldPin?.constant = 10
|
||||
|
||||
guard let self = self else { return }
|
||||
|
||||
if let placeholder = self.placeholder, !placeholder.isEmpty {
|
||||
self.labelToTextFieldPin?.constant = 10
|
||||
|
||||
} else {
|
||||
self?.labelToTextFieldPin?.constant = 0
|
||||
self.labelToTextFieldPin?.constant = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -144,24 +238,26 @@ import UIKit
|
||||
super.updateView(size)
|
||||
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
self.formLabel!.updateView(size)
|
||||
|
||||
// Remove all current UI.
|
||||
if (self.textFields?.count ?? 0) > 0 {
|
||||
StackableViewController.remove(self.textFields)
|
||||
guard let self = self else { return }
|
||||
|
||||
self.formLabel?.updateView(size)
|
||||
|
||||
if let digitFields = self.digitFields, !digitFields.isEmpty {
|
||||
|
||||
// Remove all current UI.
|
||||
StackableViewController.remove(digitFields)
|
||||
|
||||
// Update text boxes.
|
||||
for digitField in digitFields {
|
||||
digitField.updateView(size)
|
||||
}
|
||||
}
|
||||
|
||||
// Update text boxes.
|
||||
for textField in self.textFields ?? [] {
|
||||
guard let textField = textField as? MFDigitTextBox else { continue }
|
||||
textField.updateView(size)
|
||||
}
|
||||
|
||||
|
||||
// Layout text boxes.
|
||||
self.setupTextFieldsView(forSize: size)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
open override func setupView() {
|
||||
super.setupView()
|
||||
|
||||
@ -174,14 +270,17 @@ import UIKit
|
||||
// MARK: - Molecule
|
||||
//--------------------------------------------------
|
||||
|
||||
open override func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) {
|
||||
open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
|
||||
|
||||
let digitsNumber = json?.optionalNumber(forKey: "digits")
|
||||
let digits = digitsNumber != nil ? digitsNumber?.intValue ?? 0 : 4
|
||||
guard let dictionary = json else { return }
|
||||
|
||||
let digits = dictionary["digits"] as? Int ?? 4
|
||||
if digits != numberOfDigits {
|
||||
numberOfDigits = digits
|
||||
buildTextFieldsView(forSize: MVMCoreUIUtility.getWidth())
|
||||
}
|
||||
|
||||
buildTextFieldsView(size: MVMCoreUIUtility.getWidth())
|
||||
|
||||
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
|
||||
}
|
||||
|
||||
@ -190,99 +289,28 @@ import UIKit
|
||||
return 44
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Getters
|
||||
//--------------------------------------------------
|
||||
|
||||
func placeholder() -> String? {
|
||||
|
||||
var string = ""
|
||||
for textField in textFields ?? [] {
|
||||
if textField.attributedPlaceholder?.string != nil {
|
||||
string += textField.attributedPlaceholder?.string ?? ""
|
||||
}
|
||||
}
|
||||
return string.count > 0 ? string : nil
|
||||
}
|
||||
|
||||
func text() -> String? {
|
||||
|
||||
var string = ""
|
||||
for textField in textFields ?? [] {
|
||||
if textField.text != nil {
|
||||
string += textField.text ?? ""
|
||||
}
|
||||
}
|
||||
return string
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Setters
|
||||
//--------------------------------------------------
|
||||
|
||||
func setFormText(_ formText: String?) {
|
||||
|
||||
if (formText?.count ?? 0) > 0 {
|
||||
messageToTextFieldPin?.constant = 10
|
||||
} else {
|
||||
messageToTextFieldPin?.constant = 0
|
||||
}
|
||||
super.setFormText(formText)
|
||||
}
|
||||
|
||||
func setAsSecureTextEntry(_ secureTextEntry: Bool) {
|
||||
func setAsSecureTextEntry(_ secureEntry: Bool) {
|
||||
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
|
||||
(self.textFields as NSArray?)?.enumerateObjects({ obj, idx, stop in
|
||||
obj.isSecureTextEntry = secureTextEntry
|
||||
(self.digitFields as NSArray?)?.enumerateObjects({ obj, idx, stop in
|
||||
obj.isSecureTextEntry = secureEntry
|
||||
|
||||
//accessibility - 33704 fix voice over will read what pin user is filling
|
||||
obj.accessibilityLabel() = String(format: "PIN %lu of %lu", UInt(idx) + 1, UInt(self.textFields?.count ?? 0))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func setPlaceholder(_ placeholder: String?) {
|
||||
|
||||
if placeholder != nil {
|
||||
(textFields as NSArray?)?.enumerateObjects({ obj, idx, stop in
|
||||
|
||||
if idx < (placeholder?.count ?? 0) {
|
||||
|
||||
let stringForIndex = (placeholder as NSString?)?.substring(with: NSRange(location: idx, length: 1))
|
||||
obj.attributedPlaceholder = NSAttributedString(string: stringForIndex ?? "", attributes: [
|
||||
NSAttributedString.Key.foregroundColor: UIColor.mfBattleshipGrey()
|
||||
])
|
||||
} else if stop != nil {
|
||||
stop = true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// If there is already text in the textfield, set the place holder label below.
|
||||
if text.length > 0 && !errorShowing {
|
||||
label.text = placeholder
|
||||
|
||||
} else if !errorShowing {
|
||||
label.text = ""
|
||||
}
|
||||
|
||||
if label.text.length > 0 {
|
||||
labelToTextFieldPin?.constant = 10
|
||||
} else {
|
||||
labelToTextFieldPin?.constant = 0
|
||||
}
|
||||
|
||||
// adding missing accessibilityLabel value
|
||||
// if we have some value in accessibilityLabel,
|
||||
// then only can append regular and picker item
|
||||
textField.accessibilityLabel() = placeholder ?? "" + (MVMCoreUIUtility.hardcodedString(withKey: "mfdigittextfield_regular"))
|
||||
}
|
||||
|
||||
func setErrorMessage(_ errorMessage: String?) {
|
||||
override public func showErrorMessage(_ errorMessage: String?) {
|
||||
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
super.setErrorMessage(errorMessage)
|
||||
super.showErrorMessage (errorMessage)
|
||||
|
||||
if self.errorShowing {
|
||||
self.labelToTextFieldPin?.constant = 10
|
||||
}
|
||||
@ -293,28 +321,19 @@ import UIKit
|
||||
}
|
||||
|
||||
public override func hideError() {
|
||||
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
|
||||
super.hideError()
|
||||
(self.textFields as NSArray?)?.enumerateObjects({ obj, idx, stop in
|
||||
obj.hideError()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func setText(_ text: String?) {
|
||||
(textFields as NSArray?)?.enumerateObjects({ obj, idx, stop in
|
||||
if idx < (text?.count ?? 0) {
|
||||
let stringForIndex = (text as NSString?)?.substring(with: NSRange(location: idx, length: 1))
|
||||
obj.text = stringForIndex
|
||||
} else if stop != nil {
|
||||
stop = true
|
||||
}
|
||||
})
|
||||
valueChanged()
|
||||
}
|
||||
|
||||
func setWithMap(_ map: [AnyHashable : Any]?, bothDelegates delegate: (UITextFieldDelegate & MFTextFieldDelegate)?) {
|
||||
super.setWithMap(map, bothDelegates: delegate)
|
||||
super.setWithMap(map, bothDelegates: delegate as? (TextFieldDelegate & UITextFieldDelegate))
|
||||
|
||||
if (map?.count ?? 0) > 0 {
|
||||
for textField in textFields ?? [] {
|
||||
MVMCoreUICommonViewsUtility.addDismissToolbar(textField, delegate: delegate)
|
||||
@ -325,6 +344,7 @@ import UIKit
|
||||
func setDefaultValidationBlock() {
|
||||
|
||||
weak var weakSelf = self
|
||||
|
||||
self.validationBlock = { enteredValue in
|
||||
if (enteredValue?.count ?? 0) > 0 && (enteredValue?.count ?? 0) == weakSelf?.textFields?.count {
|
||||
return true
|
||||
@ -346,6 +366,7 @@ import UIKit
|
||||
for textField in textFields ?? [] {
|
||||
textField.isUserInteractionEnabled = enable
|
||||
textField.isEnabled = enable
|
||||
|
||||
if enable {
|
||||
textField.textColor = UIColor.black
|
||||
} else {
|
||||
@ -361,6 +382,7 @@ import UIKit
|
||||
func selectPreviousTextField(_ currentTextField: UITextField?, clear: Bool) {
|
||||
|
||||
var selectNextField = false
|
||||
|
||||
(textFields as NSArray?)?.enumerateObjects(options: .reverse, using: { obj, idx, stop in
|
||||
if obj == currentTextField {
|
||||
selectNextField = true
|
||||
@ -382,8 +404,10 @@ import UIKit
|
||||
|
||||
var selectNextField = false
|
||||
(textFields as NSArray?)?.enumerateObjects({ obj, idx, stop in
|
||||
|
||||
if obj == currentTextField {
|
||||
selectNextField = true
|
||||
|
||||
} else if selectNextField {
|
||||
if !clear {
|
||||
self.switchedAutomatically = true
|
||||
@ -403,8 +427,9 @@ import UIKit
|
||||
//--------------------------------------------------
|
||||
|
||||
open override var accessibilityElements: [Any]? {
|
||||
|
||||
if (self.textFields) {
|
||||
return [self.textFields arrayByAddingObject:(MFDigitTextBox *)self.label];
|
||||
return [self.textFields arrayByAddingObject:(DigitTextBox *)self.label];
|
||||
} else {
|
||||
return @[self.label];
|
||||
}
|
||||
@ -457,27 +482,31 @@ import UIKit
|
||||
}
|
||||
|
||||
func textFieldDidDelete(_ textField: UITextField?) {
|
||||
|
||||
// empty cell, go back to previous cell and clear.
|
||||
selectPreviousTextField(textField, clear: true)
|
||||
}
|
||||
|
||||
@objc public func textFieldDidBeginEditing(_ textField: UITextField) {
|
||||
|
||||
if !switchedAutomatically {
|
||||
textField.text = ""
|
||||
valueChanged()
|
||||
}
|
||||
if uiTextFieldDelegate?.responds(to: #selector(UITextFieldDelegate.textFieldDidBeginEditing(_:))) {
|
||||
uiTextFieldDelegate?.textFieldDidBeginEditing(textField)
|
||||
if (uiTextFieldDelegate?.responds(to: #selector(UITextFieldDelegate.textFieldDidBeginEditing(_:))))! {
|
||||
uiTextFieldDelegate?.textFieldDidBeginEditing!(textField)
|
||||
}
|
||||
}
|
||||
|
||||
@objc public func textFieldDidEndEditing(_ textField: UITextField) {
|
||||
|
||||
if uiTextFieldDelegate!.responds(to: #selector(UITextFieldDelegate.textFieldDidEndEditing(_:))) {
|
||||
uiTextFieldDelegate!.textFieldDidEndEditing(textField)
|
||||
uiTextFieldDelegate!.textFieldDidEndEditing!(textField)
|
||||
}
|
||||
}
|
||||
|
||||
@objc public func textFieldShouldClear(_ textField: UITextField) -> Bool {
|
||||
|
||||
selectPreviousTextField(textField, clear: false)
|
||||
|
||||
if uiTextFieldDelegate?.responds(to: #selector(UITextFieldDelegate.textFieldShouldClear(_:))) {
|
||||
@ -488,6 +517,7 @@ import UIKit
|
||||
|
||||
// MARK: - Passed Along TextField delegate
|
||||
@objc public func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
|
||||
|
||||
if uiTextFieldDelegate?.responds(to: #selector(UITextFieldDelegate.textFieldShouldBeginEditing(_:))) {
|
||||
return uiTextFieldDelegate?.textFieldShouldBeginEditing(textField)
|
||||
}
|
||||
@ -495,6 +525,7 @@ import UIKit
|
||||
}
|
||||
|
||||
@objc public func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
|
||||
|
||||
if uiTextFieldDelegate!.responds(to: #selector(UITextFieldDelegate.textFieldShouldEndEditing(_:))) {
|
||||
return uiTextFieldDelegate?.textFieldShouldEndEditing(textField)
|
||||
}
|
||||
|
||||
466
MVMCoreUI/Atoms/TextFields/FieldEntryForm.swift
Normal file
466
MVMCoreUI/Atoms/TextFields/FieldEntryForm.swift
Normal file
@ -0,0 +1,466 @@
|
||||
//
|
||||
// FieldEntryForm.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Kevin Christiano on 10/21/19.
|
||||
// Copyright © 2019 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
|
||||
/**
|
||||
* This class is intended to be subclassed by a class that will add views subclassed under UIControl.
|
||||
* The FieldEntryForm provides the base logic for the description label, placeholder/error label and field container.
|
||||
*/
|
||||
open class FieldEntryForm: ViewConstrainingView {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Outlets
|
||||
//--------------------------------------------------
|
||||
|
||||
public var backgroundView: UIView?
|
||||
public var formDescriptionLabel: Label?
|
||||
public var fieldContainer: UIView?
|
||||
public var placeholderErrorLabel: Label?
|
||||
public var separatorView: UIView?
|
||||
public var dashLine: DashLine?
|
||||
public var dropDownCaretLabel: UILabel?
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Accessories
|
||||
//--------------------------------------------------
|
||||
|
||||
public weak var datePicker: UIDatePicker?
|
||||
public var pickerView: UIPickerView?
|
||||
private(set) weak var toolbar: UIToolbar?
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
public var showError = false
|
||||
public var hasDropDown = false
|
||||
private var borderPath: UIBezierPath?
|
||||
public var isEnabled = true
|
||||
|
||||
/// Determines if a border should be drawn.
|
||||
public var hideBorder = false {
|
||||
didSet { setNeedsLayout() }
|
||||
}
|
||||
|
||||
public var formText: String? {
|
||||
get { return formDescriptionLabel?.text }
|
||||
set {
|
||||
formDescriptionLabel?.text = newValue
|
||||
setAccessibilityString(newValue)
|
||||
}
|
||||
}
|
||||
|
||||
// Override this with logic of the textfield(s) that are of focus in this form.
|
||||
public var text: String? {
|
||||
get { return "" }
|
||||
set { }
|
||||
}
|
||||
|
||||
public var placeholderTextColor: UIColor = .black
|
||||
|
||||
/// Setgs placeholder text in the textField.
|
||||
public var placeholder: String? {
|
||||
get { return placeholderErrorLabel?.text }
|
||||
set {
|
||||
guard let newPlaceholderText = newValue else { return }
|
||||
|
||||
if !showError {
|
||||
placeholderErrorLabel?.text = newPlaceholderText
|
||||
}
|
||||
|
||||
setAccessibilityString(newPlaceholderText)
|
||||
}
|
||||
}
|
||||
|
||||
public var formatter: DateFormatter = {
|
||||
|
||||
let formatter = DateFormatter()
|
||||
formatter.dateStyle = .medium
|
||||
formatter.timeZone = NSTimeZone.system
|
||||
formatter.locale = .current
|
||||
formatter.formatterBehavior = .default
|
||||
|
||||
return formatter
|
||||
}()
|
||||
|
||||
public var isValid = false
|
||||
public var fieldKey: String?
|
||||
|
||||
public var enabledTextColor: UIColor?
|
||||
public var disabledTextColor: UIColor?
|
||||
|
||||
public var errorMessage: String?
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Constraints
|
||||
//--------------------------------------------------
|
||||
|
||||
public var heightConstraint: NSLayoutConstraint?
|
||||
|
||||
public var dropDownCarrotWidth: NSLayoutConstraint?
|
||||
|
||||
public var textContainerLeftPin: NSLayoutConstraint?
|
||||
public var textContainerRightPin: NSLayoutConstraint?
|
||||
|
||||
public var errorLableRightPin: NSLayoutConstraint?
|
||||
public var errorLableLeftPin: NSLayoutConstraint?
|
||||
|
||||
public var formDescriptionLabelLeftPin: NSLayoutConstraint?
|
||||
public var formDescriptionLabelRightPin: NSLayoutConstraint?
|
||||
|
||||
public var separatorHeightConstraint: NSLayoutConstraint?
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializers
|
||||
//--------------------------------------------------
|
||||
|
||||
/// This must be overriden by a subclass.
|
||||
public override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
setupView()
|
||||
self.hasDropDown = false
|
||||
}
|
||||
|
||||
/// This must be overriden by a subclass.
|
||||
public convenience init() {
|
||||
self.init(frame: .zero)
|
||||
}
|
||||
|
||||
required public init?(coder: NSCoder) {
|
||||
super.init(coder: coder)
|
||||
fatalError("TextEntryField does not support xib.")
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Lifecycle
|
||||
//--------------------------------------------------
|
||||
|
||||
/// Initial configuration of class and view.
|
||||
final public override func setupView() {
|
||||
|
||||
guard subviews.isEmpty else { return }
|
||||
|
||||
translatesAutoresizingMaskIntoConstraints = false
|
||||
setContentHuggingPriority(.required, for: .vertical)
|
||||
setContentCompressionResistancePriority(.required, for: .vertical)
|
||||
backgroundColor = .clear
|
||||
|
||||
let formDescriptionLabel = Label()
|
||||
self.formDescriptionLabel = formDescriptionLabel
|
||||
formDescriptionLabel.font = MFStyler.fontB3()
|
||||
formDescriptionLabel.textColor = UIColor.mfBattleshipGrey()
|
||||
formDescriptionLabel.setContentHuggingPriority(UILayoutPriority(251), for: .horizontal)
|
||||
formDescriptionLabel.setContentHuggingPriority(UILayoutPriority(251), for: .vertical)
|
||||
formDescriptionLabel.setContentCompressionResistancePriority(.required, for: .vertical)
|
||||
|
||||
addSubview(formDescriptionLabel)
|
||||
|
||||
formDescriptionLabel.topAnchor.constraint(equalTo: layoutMarginsGuide.topAnchor).isActive = true
|
||||
formDescriptionLabelLeftPin = formDescriptionLabel.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor)
|
||||
formDescriptionLabelLeftPin?.isActive = true
|
||||
formDescriptionLabelRightPin = layoutMarginsGuide.trailingAnchor.constraint(equalTo: formDescriptionLabel.trailingAnchor)
|
||||
formDescriptionLabelRightPin?.isActive = true
|
||||
|
||||
let fieldContainer = UIView(frame: .zero)
|
||||
self.fieldContainer = fieldContainer
|
||||
fieldContainer.translatesAutoresizingMaskIntoConstraints = false
|
||||
|
||||
addSubview(fieldContainer)
|
||||
setupFieldContainer(fieldContainer)
|
||||
|
||||
fieldContainer.topAnchor.constraint(equalTo: formDescriptionLabel.bottomAnchor, constant: 4).isActive = true
|
||||
textContainerLeftPin = fieldContainer.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor)
|
||||
textContainerLeftPin?.isActive = true
|
||||
textContainerRightPin = layoutMarginsGuide.trailingAnchor.constraint(equalTo: fieldContainer.trailingAnchor)
|
||||
textContainerRightPin?.isActive = true
|
||||
|
||||
let placeholderErrorLabel = Label()
|
||||
self.placeholderErrorLabel = placeholderErrorLabel
|
||||
placeholderErrorLabel.font = MFStyler.fontForTextFieldUnderLabel()
|
||||
placeholderErrorLabel.textColor = .black
|
||||
placeholderErrorLabel.setContentHuggingPriority(UILayoutPriority(251), for: .horizontal)
|
||||
placeholderErrorLabel.setContentHuggingPriority(UILayoutPriority(251), for: .horizontal)
|
||||
placeholderErrorLabel.setContentCompressionResistancePriority(.required, for: .vertical)
|
||||
|
||||
addSubview(placeholderErrorLabel)
|
||||
|
||||
placeholderErrorLabel.topAnchor.constraint(equalTo: fieldContainer.bottomAnchor).isActive = true
|
||||
errorLableLeftPin = placeholderErrorLabel.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor)
|
||||
errorLableLeftPin?.isActive = true
|
||||
errorLableRightPin = layoutMarginsGuide.trailingAnchor.constraint(equalTo: placeholderErrorLabel.trailingAnchor)
|
||||
errorLableRightPin?.isActive = true
|
||||
layoutMarginsGuide.bottomAnchor.constraint(equalTo: placeholderErrorLabel.bottomAnchor).isActive = true
|
||||
|
||||
setNeedsLayout()
|
||||
}
|
||||
|
||||
/// Method to override.
|
||||
/// Intended to add the interactive content (textField) to the fieldContainer.
|
||||
open func fieldContainerContent(_ container: UIView) {
|
||||
|
||||
}
|
||||
|
||||
/// Configuration logic for the text container view.
|
||||
private func setupFieldContainer(_ parentView: UIView) {
|
||||
|
||||
let backgroundView = UIView(frame: .zero)
|
||||
self.backgroundView = backgroundView
|
||||
backgroundView.translatesAutoresizingMaskIntoConstraints = false
|
||||
|
||||
parentView.addSubview(backgroundView)
|
||||
|
||||
NSLayoutConstraint.activate([
|
||||
backgroundView.topAnchor.constraint(equalTo: parentView.topAnchor, constant: 1),
|
||||
backgroundView.leadingAnchor.constraint(equalTo: parentView.leadingAnchor, constant: 1),
|
||||
parentView.trailingAnchor.constraint(equalTo: backgroundView.trailingAnchor, constant: 1),
|
||||
parentView.bottomAnchor.constraint(equalTo: backgroundView.bottomAnchor, constant: 1)])
|
||||
|
||||
fieldContainerContent(parentView)
|
||||
|
||||
let separatorView = UIView(frame: .zero)
|
||||
self.separatorView = separatorView
|
||||
separatorView.translatesAutoresizingMaskIntoConstraints = false
|
||||
separatorView.backgroundColor = .black
|
||||
|
||||
parentView.addSubview(separatorView)
|
||||
|
||||
separatorHeightConstraint = separatorView.heightAnchor.constraint(equalToConstant: 1)
|
||||
separatorHeightConstraint?.isActive = true
|
||||
separatorView.leadingAnchor.constraint(equalTo: parentView.leadingAnchor).isActive = true
|
||||
parentView.trailingAnchor.constraint(equalTo: separatorView.trailingAnchor).isActive = true
|
||||
parentView.bottomAnchor.constraint(equalTo: separatorView.bottomAnchor).isActive = true
|
||||
|
||||
let dashLine = DashLine()
|
||||
dashLine.translatesAutoresizingMaskIntoConstraints = false
|
||||
dashLine.backgroundColor = .white
|
||||
dashLine.isHidden = true
|
||||
|
||||
parentView.addSubview(dashLine)
|
||||
|
||||
NSLayoutConstraint.activate([
|
||||
dashLine.centerYAnchor.constraint(equalTo: separatorView.centerYAnchor),
|
||||
dashLine.centerXAnchor.constraint(equalTo: separatorView.centerXAnchor),
|
||||
dashLine.topAnchor.constraint(equalTo: separatorView.topAnchor),
|
||||
dashLine.leadingAnchor.constraint(equalTo: separatorView.leadingAnchor)])
|
||||
}
|
||||
|
||||
open override func updateView(_ size: CGFloat) {
|
||||
super.updateView(size)
|
||||
|
||||
formDescriptionLabel?.updateView(size)
|
||||
placeholderErrorLabel?.font = MFStyler.fontForTextFieldUnderLabel()
|
||||
dashLine?.updateView(size)
|
||||
|
||||
layoutIfNeeded()
|
||||
}
|
||||
|
||||
open override func draw(_ rect: CGRect) {
|
||||
super.draw(rect)
|
||||
|
||||
borderPath?.removeAllPoints()
|
||||
|
||||
if !hideBorder, let frame = fieldContainer?.frame {
|
||||
|
||||
borderPath = UIBezierPath()
|
||||
borderPath?.move(to: CGPoint(x: frame.origin.x, y: frame.origin.y + frame.size.height))
|
||||
borderPath?.addLine(to: CGPoint(x: frame.origin.x, y: frame.origin.y))
|
||||
borderPath?.addLine(to: CGPoint(x: frame.origin.x + frame.size.width, y: frame.origin.y))
|
||||
borderPath?.addLine(to: CGPoint(x: frame.origin.x + frame.size.width, y: frame.origin.y + frame.size.height))
|
||||
borderPath?.lineWidth = 1
|
||||
|
||||
let strokeColor = showError ? UIColor.mfPumpkin() : UIColor.mfSilver()
|
||||
strokeColor.setStroke()
|
||||
|
||||
borderPath?.stroke()
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Methods
|
||||
//--------------------------------------------------
|
||||
|
||||
open func showErrorDropdown(_ show: Bool) {
|
||||
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
|
||||
self?.showError = show
|
||||
self?.separatorHeightConstraint?.constant = show ? 4 : 1
|
||||
self?.separatorView?.backgroundColor = show ? UIColor.mfPumpkin() : .black
|
||||
self?.setNeedsDisplay()
|
||||
self?.layoutIfNeeded()
|
||||
}
|
||||
}
|
||||
|
||||
open func showErrorMessage(_ errorMessage: String?) {
|
||||
|
||||
guard isEnabled else { return }
|
||||
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
|
||||
self?.separatorHeightConstraint?.constant = 4
|
||||
self?.showError = true
|
||||
self?.separatorView?.backgroundColor = UIColor.mfPumpkin()
|
||||
self?.placeholderErrorLabel?.text = errorMessage
|
||||
self?.placeholderErrorLabel?.numberOfLines = 0
|
||||
self?.setNeedsDisplay()
|
||||
self?.layoutIfNeeded()
|
||||
self?.showErrorDropdown(self?.showError ?? false)
|
||||
}
|
||||
}
|
||||
|
||||
open func hideError() {
|
||||
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
self?.separatorHeightConstraint?.constant = 1
|
||||
self?.separatorView?.backgroundColor = .black
|
||||
self?.layoutIfNeeded()
|
||||
self?.showError = false
|
||||
self?.placeholderErrorLabel?.textColor = .black
|
||||
self?.placeholderErrorLabel?.text = ""
|
||||
self?.setNeedsDisplay()
|
||||
self?.layoutIfNeeded()
|
||||
}
|
||||
}
|
||||
|
||||
public func setWithMap(_ map: [AnyHashable: Any]?) {
|
||||
|
||||
guard let map = map, !map.isEmpty else { return }
|
||||
|
||||
if let formText = map[KeyLabel] as? String {
|
||||
self.formText = formText
|
||||
}
|
||||
|
||||
if let text = map[KeyDisable] as? String, text.isEqual(StringY) || map.boolForKey(KeyDisable) {
|
||||
formIsDisabled()
|
||||
}
|
||||
|
||||
if let errMessage = map[KeyErrorMessage] as? String {
|
||||
self.errorMessage = errMessage
|
||||
}
|
||||
|
||||
if let hideBorder = map["hideBorder"] as? Bool {
|
||||
self.hideBorder = hideBorder
|
||||
}
|
||||
|
||||
// Key used to send text value to server
|
||||
if let fieldKey = map[KeyFieldKey] as? String {
|
||||
self.fieldKey = fieldKey
|
||||
}
|
||||
}
|
||||
|
||||
open override func setLeftPinConstant(_ constant: CGFloat) {
|
||||
|
||||
textContainerLeftPin?.constant = constant
|
||||
errorLableLeftPin?.constant = constant
|
||||
formDescriptionLabelLeftPin?.constant = constant
|
||||
}
|
||||
|
||||
open override func setRightPinConstant(_ constant: CGFloat) {
|
||||
|
||||
textContainerRightPin?.constant = constant
|
||||
errorLableRightPin?.constant = constant
|
||||
formDescriptionLabelRightPin?.constant = constant
|
||||
}
|
||||
|
||||
public func showDropDown(_ show: Bool) {
|
||||
|
||||
if hasDropDown {
|
||||
dropDownCaretLabel?.isHidden = !show
|
||||
dropDownCarrotWidth?.isActive = !show
|
||||
setNeedsLayout()
|
||||
layoutIfNeeded()
|
||||
}
|
||||
}
|
||||
|
||||
open func formIsEnabled() {
|
||||
|
||||
// Set outside the dispatch so that registerAnimations can know about it
|
||||
isEnabled = true
|
||||
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
self?.isUserInteractionEnabled = true
|
||||
self?.formDescriptionLabel?.textColor = UIColor.mfBattleshipGrey()
|
||||
self?.placeholderErrorLabel?.textColor = .black
|
||||
self?.separatorView?.backgroundColor = (self?.showError ?? false) ? UIColor.mfPumpkin() : .black
|
||||
self?.showDropDown(true)
|
||||
}
|
||||
}
|
||||
|
||||
open func formIsDisabled() {
|
||||
|
||||
// Set outside the dispatch so that registerAnimations can know about it
|
||||
isEnabled = false
|
||||
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
self?.isUserInteractionEnabled = false
|
||||
self?.formDescriptionLabel?.textColor = UIColor.mfSilver()
|
||||
self?.placeholderErrorLabel?.textColor = UIColor.mfSilver()
|
||||
self?.showDropDown(false)
|
||||
self?.hideError() // Should not have error if the field is disabled
|
||||
self?.separatorView?.backgroundColor = UIColor.mfSilver()
|
||||
}
|
||||
}
|
||||
|
||||
open func showPlaceholderErrorLabel(_ show: Bool) {
|
||||
|
||||
placeholderErrorLabel?.isHidden = !show
|
||||
}
|
||||
|
||||
open func showDashSeperatorView(_ dash: Bool) {
|
||||
|
||||
// Never hide seperator view because it could be possiblely used by other classes for positioning
|
||||
dashLine?.isHidden = !dash
|
||||
separatorView?.backgroundColor = dash ? .clear : .black
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Molecular
|
||||
extension FieldEntryForm {
|
||||
|
||||
override open func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
|
||||
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
|
||||
}
|
||||
|
||||
override open class func estimatedHeight(forRow json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
|
||||
return 76
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Form Validation
|
||||
extension FieldEntryForm: FormValidationProtocol {
|
||||
|
||||
public func isValidField() -> Bool {
|
||||
return isValid
|
||||
}
|
||||
|
||||
public func formFieldName() -> String? {
|
||||
return fieldKey
|
||||
}
|
||||
|
||||
public func formFieldValue() -> Any? {
|
||||
return text
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Accessibility
|
||||
extension FieldEntryForm {
|
||||
|
||||
@objc open func pushAccessibilityNotification() {
|
||||
// To Be Overriden
|
||||
}
|
||||
|
||||
/**
|
||||
Adding missing accessibilityLabel value
|
||||
if we have some value in accessibilityLabel,
|
||||
then only can append regular and picker item
|
||||
*/
|
||||
@objc open func setAccessibilityString(_ accessibilityString: String?) {
|
||||
// To Be Overriden
|
||||
}
|
||||
}
|
||||
232
MVMCoreUI/Atoms/TextFields/MdnEntryField.swift
Normal file
232
MVMCoreUI/Atoms/TextFields/MdnEntryField.swift
Normal file
@ -0,0 +1,232 @@
|
||||
//
|
||||
// MdnEntryField.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Kevin Christiano on 10/21/19.
|
||||
// Copyright © 2019 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import AddressBookUI
|
||||
import ContactsUI
|
||||
import UIKit
|
||||
import MVMCore
|
||||
|
||||
class MdnEntryField: TextEntryField, UITextFieldDelegate, ABPeoplePickerNavigationControllerDelegate, CNContactPickerDelegate {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
public weak var customDelegate: UITextFieldDelegate?
|
||||
public var isNationalMdn = false
|
||||
public var shouldValidateMDN = false
|
||||
|
||||
public var mdn: String? {
|
||||
get {
|
||||
guard let text = text else { return nil }
|
||||
|
||||
return MVMCoreUIUtility.removeMdnFormat(text)
|
||||
}
|
||||
set {
|
||||
guard let MDN = newValue else { return }
|
||||
text = MVMCoreUIUtility.formatMdn(MDN)
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializers
|
||||
//--------------------------------------------------
|
||||
|
||||
public override init(frame: CGRect) {
|
||||
super.init(frame: .zero)
|
||||
setup()
|
||||
}
|
||||
|
||||
public convenience init() {
|
||||
self.init(frame: .zero)
|
||||
}
|
||||
|
||||
required public init?(coder: NSCoder) {
|
||||
super.init(coder: coder)
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Setup
|
||||
//--------------------------------------------------
|
||||
|
||||
private func setup() {
|
||||
|
||||
textField?.delegate = self
|
||||
customDelegate = uiTextFieldDelegate
|
||||
isNationalMdn = true
|
||||
textField?.keyboardType = .numberPad
|
||||
|
||||
let toolbar = MVMCoreUICommonViewsUtility.makeEmptyToolbar()
|
||||
let space = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
|
||||
let contacts = UIBarButtonItem(title: MVMCoreUIUtility.hardcodedString(withKey: "textfield_contacts_barbutton"), style: .plain, target: self, action: #selector(getContacts(_:)))
|
||||
let dismissButton = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(dismissFieldInput(_:)))
|
||||
toolbar.items = [contacts, space, dismissButton]
|
||||
textField?.inputAccessoryView = toolbar
|
||||
}
|
||||
|
||||
// If you're using a MFViewController, you must set this to it.
|
||||
public override weak var uiTextFieldDelegate: UITextFieldDelegate? {
|
||||
get {
|
||||
return textField?.delegate
|
||||
}
|
||||
set {
|
||||
super.uiTextFieldDelegate = newValue
|
||||
customDelegate = uiTextFieldDelegate
|
||||
|
||||
if newValue != nil {
|
||||
textField?.delegate = self
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Methods
|
||||
//--------------------------------------------------
|
||||
|
||||
func hasValidMdn() -> Bool {
|
||||
|
||||
guard let MDN = mdn else { return true }
|
||||
|
||||
if MDN.isEmpty {
|
||||
return true
|
||||
}
|
||||
|
||||
if isNationalMdn {
|
||||
return MVMCoreUIUtility.validateMDNString(MDN)
|
||||
}
|
||||
|
||||
return MVMCoreUIUtility.validateInternationalMDNString(MDN)
|
||||
}
|
||||
|
||||
func validateAndColor() -> Bool {
|
||||
|
||||
if !shouldValidateMDN {
|
||||
let isValid = hasValidMdn()
|
||||
|
||||
if isValid {
|
||||
hideError()
|
||||
} else {
|
||||
self.errorMessage = getErrorMessage() ?? MVMCoreUIUtility.hardcodedString(withKey: "textfield_phone_format_error_message")
|
||||
UIAccessibility.post(notification: UIAccessibility.Notification.layoutChanged, argument: textField)
|
||||
}
|
||||
|
||||
return isValid
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func getErrorMessage() -> String? {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@objc func dismissFieldInput(_ sender: Any?) {
|
||||
|
||||
if let delegate = uiTextFieldDelegate {
|
||||
delegate.perform(#selector(dismissFieldInput(_:)), with: textField)
|
||||
} else {
|
||||
textField?.resignFirstResponder()
|
||||
}
|
||||
}
|
||||
|
||||
func getContacts(_ sender: Any?) {
|
||||
|
||||
let picker = CNContactPickerViewController()
|
||||
picker.delegate = self
|
||||
picker.displayedPropertyKeys = ["phoneNumbers"]
|
||||
picker.predicateForEnablingContact = NSPredicate(format: "phoneNumbers.@count > 0")
|
||||
picker.predicateForSelectionOfProperty = NSPredicate(format: "key == 'phoneNumbers'")
|
||||
MVMCoreNavigationHandler.shared()?.present(picker, animated: true)
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - ContactPicker Delegate
|
||||
//--------------------------------------------------
|
||||
|
||||
public func contactPicker(_ picker: CNContactPickerViewController, didSelect contactProperty: CNContactProperty) {
|
||||
|
||||
if contactProperty.value != nil && (contactProperty.value is CNPhoneNumber) {
|
||||
|
||||
let phoneNumber = contactProperty.value as? CNPhoneNumber
|
||||
let MDN = phoneNumber?.stringValue
|
||||
var unformattedMDN = MVMCoreUIUtility.removeMdnFormat(MDN)
|
||||
|
||||
// Sometimes user add extra 1 in front of mdn in their address book
|
||||
if isNationalMdn,
|
||||
let unformedMDN = unformattedMDN,
|
||||
unformedMDN.count == 11,
|
||||
unformedMDN[(unformedMDN.index(unformedMDN.startIndex, offsetBy: 0))] == "1" {
|
||||
|
||||
unformattedMDN = (unformedMDN as NSString).substring(from: 1)
|
||||
}
|
||||
|
||||
text = unformattedMDN
|
||||
|
||||
if let textField = textField {
|
||||
textFieldShouldReturn(textField)
|
||||
textFieldDidEndEditing(textField)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - ImplementedTextField Delegate
|
||||
//--------------------------------------------------
|
||||
|
||||
@discardableResult
|
||||
@objc public func textFieldShouldReturn(_ textField: UITextField) -> Bool {
|
||||
|
||||
textField.resignFirstResponder()
|
||||
|
||||
return customDelegate?.textFieldShouldReturn?(textField) ?? true
|
||||
}
|
||||
|
||||
@objc public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
|
||||
|
||||
if !MVMCoreUIUtility.validate(string, withRegularExpression: RegularExpressionDigitOnly) {
|
||||
return false
|
||||
}
|
||||
|
||||
return customDelegate?.textField?(textField, shouldChangeCharactersIn: range, replacementString: string) ?? true
|
||||
}
|
||||
|
||||
public func textFieldDidBeginEditing(_ textField: UITextField) {
|
||||
|
||||
textField.text = MVMCoreUIUtility.removeMdnFormat(textField.text)
|
||||
customDelegate?.textFieldDidBeginEditing?(textField)
|
||||
}
|
||||
|
||||
public func textFieldDidEndEditing(_ textField: UITextField) {
|
||||
|
||||
customDelegate?.textFieldDidEndEditing?(textField)
|
||||
|
||||
if validateAndColor() && isNationalMdn {
|
||||
textField.text = MVMCoreUIUtility.formatMdn(textField.text)
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Passed Along TextField delegate
|
||||
//--------------------------------------------------
|
||||
|
||||
@objc public func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
|
||||
|
||||
return customDelegate?.textFieldShouldBeginEditing?(textField) ?? true
|
||||
}
|
||||
|
||||
@objc public func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
|
||||
|
||||
return customDelegate?.textFieldShouldEndEditing?(textField) ?? true
|
||||
}
|
||||
|
||||
@objc public func textFieldShouldClear(_ textField: UITextField) -> Bool {
|
||||
|
||||
return customDelegate?.textFieldShouldClear?(textField) ?? true
|
||||
}
|
||||
}
|
||||
528
MVMCoreUI/Atoms/TextFields/TextEntryField.swift
Normal file
528
MVMCoreUI/Atoms/TextFields/TextEntryField.swift
Normal file
@ -0,0 +1,528 @@
|
||||
//
|
||||
// TextField.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Kevin Christiano on 10/2/19.
|
||||
// Copyright © 2019 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
|
||||
@objc public protocol TextFieldDelegate: NSObjectProtocol {
|
||||
/// Called when the entered text becomes valid based on the validation block
|
||||
@objc optional func isValid(textfield: TextEntryField?)
|
||||
/// Called when the entered text becomes invalid based on the validation block
|
||||
@objc optional func isInvalid(textfield: TextEntryField?)
|
||||
/// Dismisses the keyboard.
|
||||
@objc optional func dismissField(sender: Any?)
|
||||
}
|
||||
|
||||
|
||||
@objcMembers open class TextEntryField: FieldEntryForm {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Outlets
|
||||
//--------------------------------------------------
|
||||
|
||||
public var textField: UITextField?
|
||||
|
||||
private var calendar: Calendar?
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Delegate Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
/// The delegate and block for validation. Validates if the text that the user has entered is valid or not. Checked after each change if there is a delegate.
|
||||
public weak var mfTextFieldDelegate: TextFieldDelegate? {
|
||||
didSet {
|
||||
if mfTextFieldDelegate != nil && !observingForChanges {
|
||||
observingForChanges = true
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(valueChanged), name: UITextField.textDidChangeNotification, object: textField)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(endInputing), name: UITextField.textDidEndEditingNotification, object: textField)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(startEditing), name: UITextField.textDidBeginEditingNotification, object: textField)
|
||||
} else if mfTextFieldDelegate == nil && observingForChanges {
|
||||
observingForChanges = false
|
||||
NotificationCenter.default.removeObserver(self, name: UITextField.textDidChangeNotification, object: textField)
|
||||
NotificationCenter.default.removeObserver(self, name: UITextField.textDidEndEditingNotification, object: textField)
|
||||
NotificationCenter.default.removeObserver(self, name: UITextField.textDidBeginEditingNotification, object: textField)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// If you're using a MFViewController, you must set this to it
|
||||
public weak var uiTextFieldDelegate: UITextFieldDelegate? {
|
||||
get { return textField?.delegate }
|
||||
set {
|
||||
textField?.delegate = newValue
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
public var observingForChanges = false
|
||||
|
||||
private var borderPath: UIBezierPath?
|
||||
|
||||
// The text of this textField.
|
||||
public override var text: String? {
|
||||
get { return textField?.text }
|
||||
set {
|
||||
textField?.text = newValue
|
||||
valueChanged()
|
||||
}
|
||||
}
|
||||
|
||||
public override var formText: String? {
|
||||
get { return formDescriptionLabel?.text }
|
||||
set {
|
||||
formDescriptionLabel?.text = newValue
|
||||
setAccessibilityString(newValue)
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets placeholder text in the textField.
|
||||
public var placeholder: String? {
|
||||
get {
|
||||
guard let attributedPlaceholder = textField?.attributedPlaceholder else { return nil }
|
||||
return attributedPlaceholder.string
|
||||
}
|
||||
set {
|
||||
guard let newPlaceholderText = newValue else {
|
||||
textField?.attributedPlaceholder = nil
|
||||
return
|
||||
}
|
||||
|
||||
textField?.attributedPlaceholder = NSAttributedString(string: newPlaceholderText, attributes: [NSAttributedString.Key.foregroundColor: placeholderTextColor])
|
||||
|
||||
if !showError {
|
||||
placeholderErrorLabel?.text = (textField?.text?.count ?? 0) > 0 ? newPlaceholderText : ""
|
||||
}
|
||||
|
||||
setAccessibilityString(newPlaceholderText)
|
||||
}
|
||||
}
|
||||
|
||||
public var validationBlock: ((_ enteredValue: String?) -> Bool)? {
|
||||
didSet {
|
||||
valueChanged()
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializers
|
||||
//--------------------------------------------------
|
||||
|
||||
public override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
setupView()
|
||||
}
|
||||
|
||||
/// Basic initializer.
|
||||
public convenience init() {
|
||||
self.init(frame: .zero)
|
||||
}
|
||||
|
||||
required public init?(coder: NSCoder) {
|
||||
super.init(coder: coder)
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
/// - parameter bothDelegates: Sets both MF/UI Text Field Delegates.
|
||||
public init(bothDelegates: (UITextFieldDelegate & TextEntryFieldDelegate)?) {
|
||||
super.init(frame: .zero)
|
||||
setupView()
|
||||
setBothTextFieldDelegates(bothDelegates)
|
||||
}
|
||||
|
||||
/// - parameter hasDropDown: tbd
|
||||
/// - parameter map: Dictionary of values to setup this TextField
|
||||
/// - parameter bothDelegate: Sets both MF/UI Text Field Delegates.
|
||||
public init(hasDropDown: Bool = false, map: [AnyHashable: Any]?, bothDelegates: (UITextFieldDelegate & TextFieldDelegate)?) {
|
||||
super.init(frame: .zero)
|
||||
setupView()
|
||||
dropDownCaretLabel?.isHidden = hasDropDown
|
||||
self.hasDropDown = !hasDropDown
|
||||
setWithMap(map, bothDelegates: bothDelegates)
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Lifecycle
|
||||
//--------------------------------------------------
|
||||
|
||||
open override func fieldContainerContent(_ container: UIView) {
|
||||
|
||||
let textField = UITextField(frame: .zero)
|
||||
self.textField = textField
|
||||
textField.translatesAutoresizingMaskIntoConstraints = false
|
||||
textField.setContentCompressionResistancePriority(.required, for: .vertical)
|
||||
textField.heightAnchor.constraint(equalToConstant: 24).isActive = true
|
||||
textField.font = MFStyler.fontForTextField()
|
||||
textField.smartQuotesType = .no
|
||||
textField.smartDashesType = .no
|
||||
textField.smartInsertDeleteType = .no
|
||||
MFStyler.styleTextField(textField)
|
||||
|
||||
container.addSubview(textField)
|
||||
|
||||
NSLayoutConstraint.activate([
|
||||
textField.topAnchor.constraint(equalTo: parentView.topAnchor, constant: 10),
|
||||
textField.leadingAnchor.constraint(equalTo: parentView.leadingAnchor, constant: 16),
|
||||
parentView.bottomAnchor.constraint(equalTo: textField.bottomAnchor, constant: 10)])
|
||||
|
||||
let dropDownCaretLabel = Label()
|
||||
self.dropDownCaretLabel = dropDownCaretLabel
|
||||
dropDownCaretLabel.setContentHuggingPriority(UILayoutPriority(900), for: .horizontal)
|
||||
dropDownCaretLabel.setContentHuggingPriority(UILayoutPriority(251), for: .vertical)
|
||||
dropDownCaretLabel.setContentCompressionResistancePriority(UILayoutPriority(900), for: .horizontal)
|
||||
dropDownCaretLabel.isHidden = true
|
||||
dropDownCaretLabel.isUserInteractionEnabled = true
|
||||
let tapOnCarrot = UITapGestureRecognizer(target: self, action: #selector(startEditing))
|
||||
dropDownCaretLabel.addGestureRecognizer(tapOnCarrot)
|
||||
|
||||
container.addSubview(dropDownCaretLabel)
|
||||
|
||||
dropDownCaretLabel.topAnchor.constraint(equalTo: container.topAnchor).isActive = true
|
||||
dropDownCaretLabel.leadingAnchor.constraint(equalTo: textField.trailingAnchor, constant: 6).isActive = true
|
||||
container.trailingAnchor.constraint(equalTo: dropDownCaretLabel.trailingAnchor, constant: 16).isActive = true
|
||||
container.bottomAnchor.constraint(equalTo: dropDownCaretLabel.bottomAnchor).isActive = true
|
||||
dropDownCarrotWidth = dropDownCaretLabel.widthAnchor.constraint(equalToConstant: 0)
|
||||
dropDownCarrotWidth?.isActive = true
|
||||
}
|
||||
|
||||
open override func updateView(_ size: CGFloat) {
|
||||
super.updateView(size)
|
||||
|
||||
if let textField = textField {
|
||||
MFStyler.styleTextField(textField)
|
||||
}
|
||||
|
||||
layoutIfNeeded()
|
||||
}
|
||||
|
||||
deinit {
|
||||
mfTextFieldDelegate = nil
|
||||
uiTextFieldDelegate = nil
|
||||
}
|
||||
|
||||
open override func draw(_ rect: CGRect) {
|
||||
super.draw(rect)
|
||||
|
||||
borderPath?.removeAllPoints()
|
||||
|
||||
if !hideBorder, let frame = fieldContainer?.frame {
|
||||
|
||||
borderPath = UIBezierPath()
|
||||
borderPath?.move(to: CGPoint(x: frame.origin.x, y: frame.origin.y + frame.size.height))
|
||||
borderPath?.addLine(to: CGPoint(x: frame.origin.x, y: frame.origin.y))
|
||||
borderPath?.addLine(to: CGPoint(x: frame.origin.x + frame.size.width, y: frame.origin.y))
|
||||
borderPath?.addLine(to: CGPoint(x: frame.origin.x + frame.size.width, y: frame.origin.y + frame.size.height))
|
||||
borderPath?.lineWidth = 1
|
||||
|
||||
let strokeColor = showError ? UIColor.mfPumpkin() : UIColor.mfSilver()
|
||||
strokeColor.setStroke()
|
||||
|
||||
borderPath?.stroke()
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Methods
|
||||
//--------------------------------------------------
|
||||
|
||||
open override func showErrorMessage(_ errorMessage: String?) {
|
||||
super.showErrorMessage(errorMessage)
|
||||
|
||||
textField?.accessibilityValue = String(format: MVMCoreUIUtility.hardcodedString(withKey: "textfield_error_message") ?? "", textField?.text ?? "", errorMessage ?? "")
|
||||
}
|
||||
|
||||
open override func hideError() {
|
||||
super.hideError()
|
||||
|
||||
textField?.accessibilityValue = nil
|
||||
}
|
||||
|
||||
public func setBothTextFieldDelegates(_ delegate: (UITextFieldDelegate & TextFieldDelegate)?) {
|
||||
|
||||
mfTextFieldDelegate = delegate
|
||||
uiTextFieldDelegate = delegate
|
||||
}
|
||||
|
||||
public override func setWithMap(_ map: [AnyHashable: Any]?) {
|
||||
super.setWithMap(map)
|
||||
|
||||
guard let map = map, !map.isEmpty else { return }
|
||||
|
||||
if let formText = map[KeyLabel] as? String {
|
||||
self.formText = formText
|
||||
}
|
||||
|
||||
if let text = map[KeyValue] as? String {
|
||||
self.text = text
|
||||
}
|
||||
|
||||
if let text = map[KeyDisable] as? String, text.isEqual(StringY) || map.boolForKey(KeyDisable) {
|
||||
formIsDisabled()
|
||||
}
|
||||
|
||||
if let dropDown = map[KeyType] as? String {
|
||||
dropDownCaretLabel?.isHidden = false
|
||||
self.hasDropDown = true
|
||||
}
|
||||
|
||||
// Key used to send text value to server
|
||||
if let fieldKey = map[KeyFieldKey] as? String {
|
||||
self.fieldKey = fieldKey
|
||||
}
|
||||
|
||||
switch map.stringForkey(KeyType) {
|
||||
case "dropDown":
|
||||
dropDownCaretLabel?.isHidden = false
|
||||
self.hasDropDown = true
|
||||
|
||||
case "password":
|
||||
textField?.isSecureTextEntry = true
|
||||
|
||||
case "number":
|
||||
textField?.keyboardType = .numberPad
|
||||
|
||||
case "email":
|
||||
textField?.keyboardType = .emailAddress
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
let regex = map.stringForkey("regex")
|
||||
|
||||
if !regex.isEmpty {
|
||||
validationBlock = { enteredValue in
|
||||
guard let value = enteredValue else { return false }
|
||||
return MVMCoreUIUtility.validate(value, withRegularExpression: regex)
|
||||
}
|
||||
} else {
|
||||
defaultValidationBlock()
|
||||
}
|
||||
}
|
||||
|
||||
public func setWithMap(_ map: [AnyHashable: Any]?, bothDelegates delegate: (UITextFieldDelegate & TextFieldDelegate)?) {
|
||||
|
||||
guard let textField = textField else { return }
|
||||
|
||||
MVMCoreUICommonViewsUtility.addDismissToolbar(textField, delegate: delegate)
|
||||
setBothTextFieldDelegates(delegate)
|
||||
setWithMap(map)
|
||||
}
|
||||
|
||||
public func defaultValidationBlock() {
|
||||
|
||||
validationBlock = { enteredValue in
|
||||
return (enteredValue?.count ?? 0) > 0
|
||||
}
|
||||
}
|
||||
|
||||
open override func formIsEnabled() {
|
||||
super.formIsEnabled()
|
||||
|
||||
textField?.isUserInteractionEnabled = true
|
||||
textField?.isEnabled = true
|
||||
}
|
||||
|
||||
open override func formIsDisabled() {
|
||||
super.formIsDisabled()
|
||||
|
||||
textField?.isUserInteractionEnabled = false
|
||||
textField?.isEnabled = false
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Observing for change
|
||||
//--------------------------------------------------
|
||||
|
||||
func valueChanged() {
|
||||
|
||||
// Update label for placeholder
|
||||
if !showError {
|
||||
placeholderErrorLabel?.text = ""
|
||||
}
|
||||
|
||||
let previousValidity = isValid
|
||||
|
||||
// If validation not set, input will always be valid
|
||||
isValid = validationBlock?(text) ?? true
|
||||
|
||||
if previousValidity && !isValid {
|
||||
if let errMessage = errorMessage {
|
||||
showErrorMessage(errMessage)
|
||||
}
|
||||
|
||||
if let mfTextFieldDelegate = mfTextFieldDelegate {
|
||||
mfTextFieldDelegate.isInvalid?(textfield: self)
|
||||
}
|
||||
} else if !previousValidity && isValid {
|
||||
hideError()
|
||||
|
||||
if let mfTextFieldDelegate = mfTextFieldDelegate {
|
||||
mfTextFieldDelegate.isValid?(textfield: self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func endInputing() {
|
||||
|
||||
if isValid {
|
||||
hideError()
|
||||
separatorView?.backgroundColor = .black
|
||||
} else if let errMessage = errorMessage {
|
||||
showErrorMessage(errMessage)
|
||||
}
|
||||
}
|
||||
|
||||
func startEditing() {
|
||||
|
||||
textField?.becomeFirstResponder()
|
||||
showErrorDropdown(!showError)
|
||||
}
|
||||
|
||||
class func getEnabledTextfields(_ textFieldToDetermine: [TextEntryField]?) -> [AnyHashable]? {
|
||||
|
||||
var enabledTextFields = [AnyHashable]()
|
||||
|
||||
for textfield in textFieldToDetermine ?? [] {
|
||||
if textfield.isEnabled {
|
||||
enabledTextFields.append(textfield)
|
||||
}
|
||||
}
|
||||
|
||||
return enabledTextFields
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Date Picker
|
||||
extension TextEntryField {
|
||||
|
||||
private func createDatePicker() {
|
||||
|
||||
guard let textField = textField else { return }
|
||||
|
||||
MVMCoreUICommonViewsUtility.addDismissToolbar(textField, delegate: textField.delegate)
|
||||
datePicker = MVMCoreUICommonViewsUtility.addDatePicker(to: textField)
|
||||
|
||||
var calendar: Calendar = .current
|
||||
calendar.timeZone = NSTimeZone.system
|
||||
self.calendar = calendar
|
||||
}
|
||||
|
||||
public func inputFromDatePicker(from fromDate: Date?, to toDate: Date?, showFromDateAsDefaultInput show: Bool) {
|
||||
|
||||
createDatePicker()
|
||||
|
||||
if show, let fromDate = fromDate {
|
||||
if let calendar = calendar, calendar.isDate(fromDate, inSameDayAs: Date()) {
|
||||
text = MVMCoreUIUtility.hardcodedString(withKey: "textfield_today_string")
|
||||
} else {
|
||||
self.text = formatter.string(from: fromDate)
|
||||
}
|
||||
}
|
||||
|
||||
datePicker?.minimumDate = fromDate
|
||||
datePicker?.maximumDate = toDate
|
||||
}
|
||||
|
||||
public func setDatePickerFrom(_ fromDate: Date?, to toDate: Date?) {
|
||||
|
||||
if let fromDate = fromDate {
|
||||
if let calendar = calendar, calendar.isDate(fromDate, inSameDayAs: Date()) {
|
||||
text = MVMCoreUIUtility.hardcodedString(withKey: "textfield_today_string")
|
||||
} else {
|
||||
text = formatter.string(from: fromDate)
|
||||
}
|
||||
}
|
||||
|
||||
datePicker?.minimumDate = fromDate
|
||||
datePicker?.maximumDate = toDate
|
||||
datePicker?.timeZone = NSTimeZone.system
|
||||
}
|
||||
|
||||
public func dismissDatePicker() -> Date? {
|
||||
|
||||
let pickedDate = datePicker?.date
|
||||
|
||||
if let pickedDate = pickedDate {
|
||||
if let calendar = calendar, calendar.isDate(pickedDate, inSameDayAs: Date()) {
|
||||
text = MVMCoreUIUtility.hardcodedString(withKey: "textfield_today_string")
|
||||
} else {
|
||||
text = formatter.string(from: pickedDate)
|
||||
}
|
||||
}
|
||||
|
||||
textField?.resignFirstResponder()
|
||||
return pickedDate
|
||||
}
|
||||
|
||||
public func dismissPicker() {
|
||||
|
||||
textField?.resignFirstResponder()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Molecular
|
||||
extension TextEntryField {
|
||||
|
||||
override open func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
|
||||
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
|
||||
|
||||
if let delegateObject = delegateObject {
|
||||
FormValidator.setupValidation(molecule: self, delegate: delegateObject.formValidationProtocol)
|
||||
setWithMap(json)
|
||||
|
||||
if let formValidationProtocol = delegateObject.formValidationProtocol {
|
||||
mfTextFieldDelegate = FormValidator.getFormValidatorFor(delegate: formValidationProtocol)
|
||||
}
|
||||
|
||||
uiTextFieldDelegate = delegateObject.uiTextFieldDelegate
|
||||
|
||||
if let textField = textField {
|
||||
MVMCoreUICommonViewsUtility.addDismissToolbar(textField, delegate: uiTextFieldDelegate)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override open class func estimatedHeight(forRow json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
|
||||
return 76
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Accessibility
|
||||
extension TextEntryField {
|
||||
|
||||
open override func pushAccessibilityNotification() {
|
||||
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
UIAccessibility.post(notification: .layoutChanged, argument: self?.textField)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Adding missing accessibilityLabel value
|
||||
if we have some value in accessibilityLabel,
|
||||
then only can append regular and picker item
|
||||
*/
|
||||
open override func setAccessibilityString(_ accessibilityString: String?) {
|
||||
|
||||
guard let textField = textField else { return }
|
||||
|
||||
var accessibilityString = accessibilityString ?? ""
|
||||
|
||||
if hasDropDown, let txtPickerItem = MVMCoreUIUtility.hardcodedString(withKey: "textfield_picker_item") {
|
||||
accessibilityString += txtPickerItem
|
||||
|
||||
} else if let txtRegular = MVMCoreUIUtility.hardcodedString(withKey: "textfield_regular") {
|
||||
accessibilityString += txtRegular
|
||||
}
|
||||
|
||||
textField.accessibilityLabel = "\(accessibilityString) \(textField.isEnabled ? "" : MVMCoreUIUtility.hardcodedString(withKey: "textfield_disabled_state") ?? "")"
|
||||
}
|
||||
|
||||
}
|
||||
@ -395,74 +395,6 @@ import UIKit
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Date Picker
|
||||
//--------------------------------------------------
|
||||
|
||||
private func createDatePicker() {
|
||||
|
||||
guard let textField = textField else { return }
|
||||
|
||||
MVMCoreUICommonViewsUtility.addDismissToolbar(textField, delegate: textField.delegate)
|
||||
datePicker = MVMCoreUICommonViewsUtility.addDatePicker(to: textField)
|
||||
|
||||
var calendar: Calendar = .current
|
||||
calendar.timeZone = NSTimeZone.system
|
||||
self.calendar = calendar
|
||||
}
|
||||
|
||||
public func inputFromDatePicker(from fromDate: Date?, to toDate: Date?, showFromDateAsDefaultInput show: Bool) {
|
||||
|
||||
createDatePicker()
|
||||
|
||||
if show, let fromDate = fromDate {
|
||||
if let calendar = calendar, calendar.isDate(fromDate, inSameDayAs: Date()) {
|
||||
text = MVMCoreUIUtility.hardcodedString(withKey: "textfield_today_string")
|
||||
} else {
|
||||
self.text = formatter.string(from: fromDate)
|
||||
}
|
||||
}
|
||||
|
||||
datePicker?.minimumDate = fromDate
|
||||
datePicker?.maximumDate = toDate
|
||||
}
|
||||
|
||||
public func setDatePickerFrom(_ fromDate: Date?, to toDate: Date?) {
|
||||
|
||||
if let fromDate = fromDate {
|
||||
if let calendar = calendar, calendar.isDate(fromDate, inSameDayAs: Date()) {
|
||||
text = MVMCoreUIUtility.hardcodedString(withKey: "textfield_today_string")
|
||||
} else {
|
||||
text = formatter.string(from: fromDate)
|
||||
}
|
||||
}
|
||||
|
||||
datePicker?.minimumDate = fromDate
|
||||
datePicker?.maximumDate = toDate
|
||||
datePicker?.timeZone = NSTimeZone.system
|
||||
}
|
||||
|
||||
public func dismissDatePicker() -> Date? {
|
||||
|
||||
let pickedDate = datePicker?.date
|
||||
|
||||
if let pickedDate = pickedDate {
|
||||
if let calendar = calendar, calendar.isDate(pickedDate, inSameDayAs: Date()) {
|
||||
text = MVMCoreUIUtility.hardcodedString(withKey: "textfield_today_string")
|
||||
} else {
|
||||
text = formatter.string(from: pickedDate)
|
||||
}
|
||||
}
|
||||
|
||||
textField?.resignFirstResponder()
|
||||
return pickedDate
|
||||
}
|
||||
|
||||
public func dismissPicker() {
|
||||
|
||||
textField?.resignFirstResponder()
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Methods
|
||||
//--------------------------------------------------
|
||||
@ -721,6 +653,74 @@ import UIKit
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Date Picker
|
||||
extension TextField {
|
||||
|
||||
private func createDatePicker() {
|
||||
|
||||
guard let textField = textField else { return }
|
||||
|
||||
MVMCoreUICommonViewsUtility.addDismissToolbar(textField, delegate: textField.delegate)
|
||||
datePicker = MVMCoreUICommonViewsUtility.addDatePicker(to: textField)
|
||||
|
||||
var calendar: Calendar = .current
|
||||
calendar.timeZone = NSTimeZone.system
|
||||
self.calendar = calendar
|
||||
}
|
||||
|
||||
public func inputFromDatePicker(from fromDate: Date?, to toDate: Date?, showFromDateAsDefaultInput show: Bool) {
|
||||
|
||||
createDatePicker()
|
||||
|
||||
if show, let fromDate = fromDate {
|
||||
if let calendar = calendar, calendar.isDate(fromDate, inSameDayAs: Date()) {
|
||||
text = MVMCoreUIUtility.hardcodedString(withKey: "textfield_today_string")
|
||||
} else {
|
||||
self.text = formatter.string(from: fromDate)
|
||||
}
|
||||
}
|
||||
|
||||
datePicker?.minimumDate = fromDate
|
||||
datePicker?.maximumDate = toDate
|
||||
}
|
||||
|
||||
public func setDatePickerFrom(_ fromDate: Date?, to toDate: Date?) {
|
||||
|
||||
if let fromDate = fromDate {
|
||||
if let calendar = calendar, calendar.isDate(fromDate, inSameDayAs: Date()) {
|
||||
text = MVMCoreUIUtility.hardcodedString(withKey: "textfield_today_string")
|
||||
} else {
|
||||
text = formatter.string(from: fromDate)
|
||||
}
|
||||
}
|
||||
|
||||
datePicker?.minimumDate = fromDate
|
||||
datePicker?.maximumDate = toDate
|
||||
datePicker?.timeZone = NSTimeZone.system
|
||||
}
|
||||
|
||||
public func dismissDatePicker() -> Date? {
|
||||
|
||||
let pickedDate = datePicker?.date
|
||||
|
||||
if let pickedDate = pickedDate {
|
||||
if let calendar = calendar, calendar.isDate(pickedDate, inSameDayAs: Date()) {
|
||||
text = MVMCoreUIUtility.hardcodedString(withKey: "textfield_today_string")
|
||||
} else {
|
||||
text = formatter.string(from: pickedDate)
|
||||
}
|
||||
}
|
||||
|
||||
textField?.resignFirstResponder()
|
||||
return pickedDate
|
||||
}
|
||||
|
||||
public func dismissPicker() {
|
||||
|
||||
textField?.resignFirstResponder()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Molecular
|
||||
extension TextField {
|
||||
|
||||
|
||||
@ -37,7 +37,7 @@
|
||||
@"caretView": CaretView.class,
|
||||
@"caretButton": CaretButton.class,
|
||||
@"textField" : TextField.class,
|
||||
@"digitTextField" : MFDigitTextField.class,
|
||||
@"digitTextField" : DigitTextField.class,
|
||||
@"checkbox" : Checkbox.class,
|
||||
@"checkboxWithLabelView" : CheckboxWithLabelView.class,
|
||||
@"cornerLabels" : CornerLabels.class,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user