Merge pull request #3 in BPHVB/mvm_core_ui from feature/migration to develop

* commit '0d141163a3e01336a1c927909f4d569f9c96695a':
  fix project to public
  Label with internal button, first template
  TopLabelsAndBottomButtonsTableViewController move
  file move
  remove duplicate function Move back to delegate. Throw error when using exact class, don't throw error when using protocol. remove unused search path
This commit is contained in:
Pfeil, Scott Robert 2019-01-23 14:29:20 -05:00
commit 6a6f92524a
27 changed files with 2762 additions and 51 deletions

View File

@ -7,9 +7,19 @@
objects = {
/* Begin PBXBuildFile section */
D29770C821F7C4AE00B2F0D0 /* TopLabelsView.m in Sources */ = {isa = PBXBuildFile; fileRef = D29770C621F7C4AE00B2F0D0 /* TopLabelsView.m */; };
D29770C921F7C4AE00B2F0D0 /* TopLabelsView.h in Headers */ = {isa = PBXBuildFile; fileRef = D29770C721F7C4AE00B2F0D0 /* TopLabelsView.h */; settings = {ATTRIBUTES = (Public, ); }; };
D29770F221F7C6D600B2F0D0 /* TopLabelsAndBottomButtonsTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D29770EE21F7C6D600B2F0D0 /* TopLabelsAndBottomButtonsTableViewController.m */; };
D29770F321F7C6D600B2F0D0 /* TopLabelsAndBottomButtonsTableViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = D29770EF21F7C6D600B2F0D0 /* TopLabelsAndBottomButtonsTableViewController.h */; settings = {ATTRIBUTES = (Public, ); }; };
D29770F421F7C6D600B2F0D0 /* TopLabelsAndBottomButtonsViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = D29770F021F7C6D600B2F0D0 /* TopLabelsAndBottomButtonsViewController.h */; settings = {ATTRIBUTES = (Public, ); }; };
D29770F521F7C6D600B2F0D0 /* TopLabelsAndBottomButtonsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D29770F121F7C6D600B2F0D0 /* TopLabelsAndBottomButtonsViewController.m */; };
D29770F821F7C73800B2F0D0 /* PrimaryButtonView.h in Headers */ = {isa = PBXBuildFile; fileRef = D29770F621F7C73800B2F0D0 /* PrimaryButtonView.h */; settings = {ATTRIBUTES = (Public, ); }; };
D29770F921F7C73800B2F0D0 /* PrimaryButtonView.m in Sources */ = {isa = PBXBuildFile; fileRef = D29770F721F7C73800B2F0D0 /* PrimaryButtonView.m */; };
D29770FC21F7C77400B2F0D0 /* TextFieldView.m in Sources */ = {isa = PBXBuildFile; fileRef = D29770FA21F7C77400B2F0D0 /* TextFieldView.m */; };
D29770FD21F7C77400B2F0D0 /* TextFieldView.h in Headers */ = {isa = PBXBuildFile; fileRef = D29770FB21F7C77400B2F0D0 /* TextFieldView.h */; settings = {ATTRIBUTES = (Public, ); }; };
D29DF0D121E404D4003B2FB9 /* MVMCoreUI.h in Headers */ = {isa = PBXBuildFile; fileRef = D29DF0CF21E404D4003B2FB9 /* MVMCoreUI.h */; settings = {ATTRIBUTES = (Public, ); }; };
D29DF0E221E4F3B6003B2FB9 /* LargeHeaderSingleLabelViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = D29DF0E021E4F3B6003B2FB9 /* LargeHeaderSingleLabelViewController.h */; };
D29DF0E321E4F3B6003B2FB9 /* LargeHeaderSingleLabelViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D29DF0E121E4F3B6003B2FB9 /* LargeHeaderSingleLabelViewController.m */; };
D29DF0E221E4F3B6003B2FB9 /* MVMCoreUILargeHeaderSingleLabelTemplate.h in Headers */ = {isa = PBXBuildFile; fileRef = D29DF0E021E4F3B6003B2FB9 /* MVMCoreUILargeHeaderSingleLabelTemplate.h */; settings = {ATTRIBUTES = (Public, ); }; };
D29DF0E321E4F3B6003B2FB9 /* MVMCoreUILargeHeaderSingleLabelTemplate.m in Sources */ = {isa = PBXBuildFile; fileRef = D29DF0E121E4F3B6003B2FB9 /* MVMCoreUILargeHeaderSingleLabelTemplate.m */; };
D29DF0E621E4F3C7003B2FB9 /* MVMCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D29DF0E521E4F3C7003B2FB9 /* MVMCore.framework */; };
D29DF11521E6805F003B2FB9 /* UIColor+MFConvenience.h in Headers */ = {isa = PBXBuildFile; fileRef = D29DF11121E6805F003B2FB9 /* UIColor+MFConvenience.h */; settings = {ATTRIBUTES = (Public, ); }; };
D29DF11621E6805F003B2FB9 /* NSLayoutConstraint+MFConvenience.h in Headers */ = {isa = PBXBuildFile; fileRef = D29DF11221E6805F003B2FB9 /* NSLayoutConstraint+MFConvenience.h */; settings = {ATTRIBUTES = (Public, ); }; };
@ -125,14 +135,28 @@
D29DF32521ED0DA2003B2FB9 /* TextButtonView.h in Headers */ = {isa = PBXBuildFile; fileRef = D29DF32321ED0DA2003B2FB9 /* TextButtonView.h */; settings = {ATTRIBUTES = (Public, ); }; };
D29DF32C21EE8736003B2FB9 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = D29DF32821EE8736003B2FB9 /* Localizable.strings */; };
D29DF32E21EE8C3D003B2FB9 /* Media.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D29DF32D21EE8C3D003B2FB9 /* Media.xcassets */; };
D2C5001821F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.h in Headers */ = {isa = PBXBuildFile; fileRef = D2C5001621F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.h */; settings = {ATTRIBUTES = (Public, ); }; };
D2C5001921F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m in Sources */ = {isa = PBXBuildFile; fileRef = D2C5001721F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m */; };
D2C5001D21F8EE67001DA659 /* LabelWithInternalButton.h in Headers */ = {isa = PBXBuildFile; fileRef = D2C5001B21F8EE66001DA659 /* LabelWithInternalButton.h */; settings = {ATTRIBUTES = (Public, ); }; };
D2C5001E21F8EE67001DA659 /* LabelWithInternalButton.m in Sources */ = {isa = PBXBuildFile; fileRef = D2C5001C21F8EE66001DA659 /* LabelWithInternalButton.m */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
D29770C621F7C4AE00B2F0D0 /* TopLabelsView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TopLabelsView.m; sourceTree = "<group>"; };
D29770C721F7C4AE00B2F0D0 /* TopLabelsView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TopLabelsView.h; sourceTree = "<group>"; };
D29770EE21F7C6D600B2F0D0 /* TopLabelsAndBottomButtonsTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TopLabelsAndBottomButtonsTableViewController.m; sourceTree = "<group>"; };
D29770EF21F7C6D600B2F0D0 /* TopLabelsAndBottomButtonsTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TopLabelsAndBottomButtonsTableViewController.h; sourceTree = "<group>"; };
D29770F021F7C6D600B2F0D0 /* TopLabelsAndBottomButtonsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TopLabelsAndBottomButtonsViewController.h; sourceTree = "<group>"; };
D29770F121F7C6D600B2F0D0 /* TopLabelsAndBottomButtonsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TopLabelsAndBottomButtonsViewController.m; sourceTree = "<group>"; };
D29770F621F7C73800B2F0D0 /* PrimaryButtonView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PrimaryButtonView.h; sourceTree = "<group>"; };
D29770F721F7C73800B2F0D0 /* PrimaryButtonView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PrimaryButtonView.m; sourceTree = "<group>"; };
D29770FA21F7C77400B2F0D0 /* TextFieldView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TextFieldView.m; sourceTree = "<group>"; };
D29770FB21F7C77400B2F0D0 /* TextFieldView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TextFieldView.h; sourceTree = "<group>"; };
D29DF0CC21E404D4003B2FB9 /* MVMCoreUI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MVMCoreUI.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D29DF0CF21E404D4003B2FB9 /* MVMCoreUI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreUI.h; sourceTree = "<group>"; };
D29DF0D021E404D4003B2FB9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
D29DF0E021E4F3B6003B2FB9 /* LargeHeaderSingleLabelViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LargeHeaderSingleLabelViewController.h; sourceTree = "<group>"; };
D29DF0E121E4F3B6003B2FB9 /* LargeHeaderSingleLabelViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LargeHeaderSingleLabelViewController.m; sourceTree = "<group>"; };
D29DF0E021E4F3B6003B2FB9 /* MVMCoreUILargeHeaderSingleLabelTemplate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreUILargeHeaderSingleLabelTemplate.h; sourceTree = "<group>"; };
D29DF0E121E4F3B6003B2FB9 /* MVMCoreUILargeHeaderSingleLabelTemplate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MVMCoreUILargeHeaderSingleLabelTemplate.m; sourceTree = "<group>"; };
D29DF0E521E4F3C7003B2FB9 /* MVMCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = MVMCore.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D29DF11121E6805F003B2FB9 /* UIColor+MFConvenience.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIColor+MFConvenience.h"; sourceTree = "<group>"; };
D29DF11221E6805F003B2FB9 /* NSLayoutConstraint+MFConvenience.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSLayoutConstraint+MFConvenience.h"; sourceTree = "<group>"; };
@ -250,6 +274,10 @@
D29DF32A21EE8736003B2FB9 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = "<group>"; };
D29DF32B21EE8736003B2FB9 /* es-MX */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "es-MX"; path = "es-MX.lproj/Localizable.strings"; sourceTree = "<group>"; };
D29DF32D21EE8C3D003B2FB9 /* Media.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Media.xcassets; sourceTree = "<group>"; };
D2C5001621F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreUIViewControllerMappingObject.h; sourceTree = "<group>"; };
D2C5001721F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MVMCoreUIViewControllerMappingObject.m; sourceTree = "<group>"; };
D2C5001B21F8EE66001DA659 /* LabelWithInternalButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LabelWithInternalButton.h; sourceTree = "<group>"; };
D2C5001C21F8EE66001DA659 /* LabelWithInternalButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LabelWithInternalButton.m; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -306,8 +334,8 @@
D29DF0DF21E418B2003B2FB9 /* Templates */ = {
isa = PBXGroup;
children = (
D29DF0E021E4F3B6003B2FB9 /* LargeHeaderSingleLabelViewController.h */,
D29DF0E121E4F3B6003B2FB9 /* LargeHeaderSingleLabelViewController.m */,
D29DF0E021E4F3B6003B2FB9 /* MVMCoreUILargeHeaderSingleLabelTemplate.h */,
D29DF0E121E4F3B6003B2FB9 /* MVMCoreUILargeHeaderSingleLabelTemplate.m */,
);
path = Templates;
sourceTree = "<group>";
@ -334,6 +362,10 @@
D29DF10E21E67A77003B2FB9 /* Molecules */ = {
isa = PBXGroup;
children = (
D29770C721F7C4AE00B2F0D0 /* TopLabelsView.h */,
D29770C621F7C4AE00B2F0D0 /* TopLabelsView.m */,
D29770F621F7C73800B2F0D0 /* PrimaryButtonView.h */,
D29770F721F7C73800B2F0D0 /* PrimaryButtonView.m */,
);
path = Molecules;
sourceTree = "<group>";
@ -353,6 +385,10 @@
D29DF28E21E7ADB8003B2FB9 /* StackableViewController.m */,
D29DF2CC21E7C104003B2FB9 /* MFLoadingViewController.h */,
D29DF2CD21E7C104003B2FB9 /* MFLoadingViewController.m */,
D29770F021F7C6D600B2F0D0 /* TopLabelsAndBottomButtonsViewController.h */,
D29770F121F7C6D600B2F0D0 /* TopLabelsAndBottomButtonsViewController.m */,
D29770EF21F7C6D600B2F0D0 /* TopLabelsAndBottomButtonsTableViewController.h */,
D29770EE21F7C6D600B2F0D0 /* TopLabelsAndBottomButtonsTableViewController.m */,
);
path = BaseControllers;
sourceTree = "<group>";
@ -465,6 +501,8 @@
D29DF28621E7AC2B003B2FB9 /* MFLabel.m */,
D29DF31E21ED0CBA003B2FB9 /* LabelView.h */,
D29DF31F21ED0CBA003B2FB9 /* LabelView.m */,
D2C5001B21F8EE66001DA659 /* LabelWithInternalButton.h */,
D2C5001C21F8EE66001DA659 /* LabelWithInternalButton.m */,
D29DF28721E7AC2B003B2FB9 /* ViewConstrainingView.h */,
D29DF28821E7AC2B003B2FB9 /* ViewConstrainingView.m */,
D29DF26221E6A9D9003B2FB9 /* MFTransparentGIFView.h */,
@ -484,6 +522,8 @@
D29DF2B221E7B76D003B2FB9 /* MFLoadingSpinner.m */,
D29DF32321ED0DA2003B2FB9 /* TextButtonView.h */,
D29DF32221ED0DA2003B2FB9 /* TextButtonView.m */,
D29770FB21F7C77400B2F0D0 /* TextFieldView.h */,
D29770FA21F7C77400B2F0D0 /* TextFieldView.m */,
);
path = Views;
sourceTree = "<group>";
@ -530,6 +570,8 @@
children = (
D29DF27321E79E81003B2FB9 /* MVMCoreUILoggingHandler.h */,
D29DF27421E79E81003B2FB9 /* MVMCoreUILoggingHandler.m */,
D2C5001621F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.h */,
D2C5001721F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m */,
);
path = OtherHandlers;
sourceTree = "<group>";
@ -609,6 +651,7 @@
D29DF29921E7ADB8003B2FB9 /* ProgrammaticScrollViewController.h in Headers */,
D29DF11C21E684A9003B2FB9 /* MVMCoreUISplitViewController.h in Headers */,
D29DF29B21E7ADB9003B2FB9 /* StackableViewController.h in Headers */,
D29770F421F7C6D600B2F0D0 /* TopLabelsAndBottomButtonsViewController.h in Headers */,
D29DF15421E69760003B2FB9 /* MVMCoreUIPanelButtonProtocol.h in Headers */,
D29DF0D121E404D4003B2FB9 /* MVMCoreUI.h in Headers */,
D29DF29A21E7ADB8003B2FB9 /* MFProgrammaticTableViewController.h in Headers */,
@ -623,7 +666,7 @@
D29DF28B21E7AC2B003B2FB9 /* ViewConstrainingView.h in Headers */,
D29DF2B321E7B76D003B2FB9 /* MFLoadingSpinner.h in Headers */,
D29DF28921E7AC2B003B2FB9 /* MFLabel.h in Headers */,
D29DF0E221E4F3B6003B2FB9 /* LargeHeaderSingleLabelViewController.h in Headers */,
D29DF0E221E4F3B6003B2FB9 /* MVMCoreUILargeHeaderSingleLabelTemplate.h in Headers */,
D29DF32521ED0DA2003B2FB9 /* TextButtonView.h in Headers */,
D29DF25021E6A177003B2FB9 /* MFDigitTextBox.h in Headers */,
D29DF2C621E7BF57003B2FB9 /* MFTabBarInteractor.h in Headers */,
@ -633,17 +676,22 @@
D29DF26E21E6AA0B003B2FB9 /* FLAnimatedImage.h in Headers */,
D29DF17321E69E1F003B2FB9 /* MFCaretButton.h in Headers */,
D29DF2A621E7B2A0003B2FB9 /* MFCaretView.h in Headers */,
D2C5001D21F8EE67001DA659 /* LabelWithInternalButton.h in Headers */,
D29DF11621E6805F003B2FB9 /* NSLayoutConstraint+MFConvenience.h in Headers */,
D29DF17721E69E1F003B2FB9 /* MFTextButton.h in Headers */,
D29DF16221E69996003B2FB9 /* MFViewController.h in Headers */,
D29DF13121E6851E003B2FB9 /* MVMCoreUITopAlertExpandableView.h in Headers */,
D29DF2C421E7BF57003B2FB9 /* MFTabBarSwipeAnimator.h in Headers */,
D29DF2CA21E7BFC8003B2FB9 /* MFSizeThreshold.h in Headers */,
D29770F821F7C73800B2F0D0 /* PrimaryButtonView.h in Headers */,
D29DF28021E7AA51003B2FB9 /* MVMCoreUIDetailViewProtocol.h in Headers */,
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 */,
D2C5001821F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.h in Headers */,
D29770FD21F7C77400B2F0D0 /* TextFieldView.h in Headers */,
D29DF17421E69E1F003B2FB9 /* MFCustomButton.h in Headers */,
D29DF29721E7ADB8003B2FB9 /* MFScrollingViewController.h in Headers */,
D29DF26F21E6AA0B003B2FB9 /* FLAnimatedImageView.h in Headers */,
@ -652,6 +700,7 @@
D29DF17621E69E1F003B2FB9 /* PrimaryButton.h in Headers */,
D29DF2C821E7BFC1003B2FB9 /* MFSizeObject.h in Headers */,
D29DF32021ED0CBA003B2FB9 /* LabelView.h in Headers */,
D29770C921F7C4AE00B2F0D0 /* TopLabelsView.h in Headers */,
D29DF2E121E9240B003B2FB9 /* MVMCoreUIPanelProtocol.h in Headers */,
D29DF12921E6851E003B2FB9 /* MVMCoreUITopAlertMainView.h in Headers */,
D29DF12C21E6851E003B2FB9 /* MVMCoreUITopAlertShortView.h in Headers */,
@ -738,13 +787,16 @@
buildActionMask = 2147483647;
files = (
D29DF32121ED0CBA003B2FB9 /* LabelView.m in Sources */,
D29770F221F7C6D600B2F0D0 /* TopLabelsAndBottomButtonsTableViewController.m in Sources */,
D29DF29621E7ADB8003B2FB9 /* StackableViewController.m in Sources */,
D29DF11721E6805F003B2FB9 /* UIColor+MFConvenience.m in Sources */,
D29DF25321E6A177003B2FB9 /* MFDigitTextField.m in Sources */,
D29770F921F7C73800B2F0D0 /* PrimaryButtonView.m in Sources */,
D29DF12F21E6851E003B2FB9 /* MVMCoreUITopAlertMainView.m in Sources */,
D29DF17C21E69E1F003B2FB9 /* MFTextButton.m in Sources */,
D29DF2C521E7BF57003B2FB9 /* MFTabBarSwipeAnimator.m in Sources */,
D29DF2B421E7B76D003B2FB9 /* MFLoadingSpinner.m in Sources */,
D2C5001921F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m in Sources */,
D29DF12E21E6851E003B2FB9 /* MVMCoreUITopAlertView.m in Sources */,
D29DF2CF21E7C104003B2FB9 /* MFLoadingViewController.m in Sources */,
D29DF27621E79E81003B2FB9 /* MVMCoreUILoggingHandler.m in Sources */,
@ -775,18 +827,22 @@
D29DF17B21E69E1F003B2FB9 /* PrimaryButton.m in Sources */,
D29DF11D21E684A9003B2FB9 /* MVMCoreUISplitViewController.m in Sources */,
D29DF29821E7ADB8003B2FB9 /* MFScrollingViewController.m in Sources */,
D29770C821F7C4AE00B2F0D0 /* TopLabelsView.m in Sources */,
D29DF2AA21E7B2F9003B2FB9 /* MVMCoreUIConstants.m in Sources */,
D29DF17821E69E1F003B2FB9 /* MFCaretButton.m in Sources */,
D29DF11821E6805F003B2FB9 /* NSLayoutConstraint+MFConvenience.m in Sources */,
D29DF26C21E6AA0B003B2FB9 /* FLAnimatedImage.m in Sources */,
D29770FC21F7C77400B2F0D0 /* TextFieldView.m in Sources */,
D29DF25121E6A177003B2FB9 /* MFDigitTextBox.m in Sources */,
D29DF13221E6851E003B2FB9 /* MVMCoreUITopAlertBaseView.m in Sources */,
D29DF0E321E4F3B6003B2FB9 /* LargeHeaderSingleLabelViewController.m in Sources */,
D29DF0E321E4F3B6003B2FB9 /* MVMCoreUILargeHeaderSingleLabelTemplate.m in Sources */,
D2C5001E21F8EE67001DA659 /* LabelWithInternalButton.m in Sources */,
D29DF29C21E7ADB9003B2FB9 /* MFProgrammaticTableViewController.m in Sources */,
D29DF2BE21E7BEA4003B2FB9 /* TopTabbar.m in Sources */,
D29DF32421ED0DA2003B2FB9 /* TextButtonView.m in Sources */,
D29DF29E21E7AE3B003B2FB9 /* MFStyler.m in Sources */,
D29DF2CB21E7BFCC003B2FB9 /* MFSizeThreshold.m in Sources */,
D29770F521F7C6D600B2F0D0 /* TopLabelsAndBottomButtonsViewController.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View File

@ -18,7 +18,6 @@ extern CGFloat const CloseButtonWidth;
@interface MFCustomButton : UIButton <MFButtonProtocol>
@property (nullable, nonatomic, strong) id dataPassed;
@property (nullable, nonatomic, strong) NSDictionary *actionMap;
@property (nullable, nonatomic, weak) id <ButtonDelegateProtocol> buttonDelegate;
@property (nullable, nonatomic, strong) NSLayoutConstraint *heightConstraint;

View File

@ -0,0 +1,94 @@
//
// TextMixedWithButtonView.h
// mobilefirst
//
// Created by Chris Yang on 2/25/16.
// Copyright © 2016 Verizon Wireless. All rights reserved.
//
#import<UIKit/UIKit.h>
#import <MVMCore/MVMCoreActionDelegateProtocol.h>
#import <MVMCoreUI/MFView.h>
#import <MVMCoreUI/MFLabel.h>
#import <MVMCoreUI/ButtonDelegateProtocol.h>
#import <MVMCoreUI/MFButtonProtocol.h>
typedef void (^ActionBlock)(void);
@interface LabelWithInternalButton : UIControl <MVMCoreViewProtocol, MFButtonProtocol>
@property (nullable, copy, nonatomic) ActionBlock actionBlock;
@property (nullable, weak, nonatomic) MFLabel *label;
@property (nullable, strong, nonatomic) NSString *frontText;
@property (nullable, strong, nonatomic) NSString *actionText;
@property (nullable, strong, nonatomic) NSString *backText;
@property (nullable, strong, nonatomic) NSAttributedString *attributedText;
//by default, it will follow most of the font standard in zepplin, and should need to be changed
@property (nullable, strong, nonatomic) UIFont *normalTextFont;
@property (nullable, strong, nonatomic) UIFont *actionTextFont;
@property (nullable, strong, nonatomic) UIColor *normalTextColor;
@property (nullable, strong, nonatomic) UIColor *actionTextColor;
@property (nullable, strong, nonatomic) NSString *alternateAttributeForActionText;
@property (assign, nonatomic) BOOL makeWholeViewClickable;
// with button delegate
- (nullable instancetype)initWithActionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData actionDelegate:(nullable NSObject<MVMCoreActionDelegateProtocol> *)delegate buttonDelegate:(nullable NSObject<ButtonDelegateProtocol> *)buttonDelegate;
- (nullable instancetype)initWithFrontText:(nullable NSString *)frontText backText:(nullable NSString *)backText actionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData actionDelegate:(nullable NSObject<MVMCoreActionDelegateProtocol> *)delegate buttonDelegate:(nullable NSObject<ButtonDelegateProtocol> *)buttonDelegate;
- (nullable instancetype)initWithFrontText:(nullable NSString *)frontText actionText:(nullable NSString *)actionText backText:(nullable NSString *)backText actionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData actionDelegate:(nullable NSObject<MVMCoreActionDelegateProtocol> *)delegate buttonDelegate:(nullable NSObject<ButtonDelegateProtocol> *)buttonDelegate;
// set with button delegate
- (void)setActionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData actionDelegate:(nullable NSObject<MVMCoreActionDelegateProtocol> *)delegate buttonDelegate:(nullable NSObject<ButtonDelegateProtocol> *)buttonDelegate;
- (void)setFrontText:(nullable NSString *)frontText actionMap:(nullable NSDictionary *)actionMap backText:(nullable NSString *)backText additionalData:(nullable NSDictionary *)additionalData delegate:(nullable NSObject<MVMCoreActionDelegateProtocol> *)delegate buttonDelegate:(nullable NSObject<ButtonDelegateProtocol> *)buttonDelegate;
- (void)setFrontAttributedText:(nullable NSAttributedString *)frontAttributedText actionMap:(nullable NSDictionary *)actionMap backAttributedText:(nullable NSAttributedString *)backText additionalData:(nullable NSDictionary *)additionalData delegate:(nullable NSObject<MVMCoreActionDelegateProtocol> *)delegate buttonDelegate:(nullable NSObject<ButtonDelegateProtocol> *)buttonDelegate;
- (void)setFrontAttributedText:(nullable NSAttributedString *)frontAttributedText actionMap:(nullable NSDictionary *)actionMap backAttributedText:(nullable NSAttributedString *)backAttributedText addNewLine:(BOOL) addNewLine additionalData:(nullable NSDictionary *)additionalData delegate:(nullable NSObject<MVMCoreActionDelegateProtocol> *)delegate buttonDelegate:(nullable NSObject<ButtonDelegateProtocol> *)buttonDelegate;
// legacy
- (nullable instancetype)initWithFrontText:(nullable NSString *)frontText actionText:(nullable NSString *)actionText backText:(nullable NSString *)backText actionBlock:(nullable ActionBlock)block;
- (nullable instancetype)initWithFrontText:(nullable NSString *)frontText actionText:(nullable NSString *)actionText backText:(nullable NSString *)backText actionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData actionDelegate:(nullable NSObject<MVMCoreActionDelegateProtocol> *)delegate;
- (nullable instancetype)initWithActionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData actionDelegate:(nullable NSObject<MVMCoreActionDelegateProtocol> *)delegate;
//this assume that the action text is the "title" key in action map
- (nullable instancetype)initWithFrontText:(nullable NSString *)frontText backText:(nullable NSString *)backText actionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData actionDelegate:(nullable NSObject<MVMCoreActionDelegateProtocol> *)delegate;
// Convenience Initializer which assumes that the clickable text will be embedded in curly braces {}.
- (nullable instancetype)initWithClickableTextEmbeddedInCurlyBraces:(nullable NSString *)fullText actionMapForClickableText:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData actionDelegate:(nullable NSObject<MVMCoreActionDelegateProtocol> *)delegate;
// Convenience Initializer which assumes that the clickable text will be embedded in any tag.
- (nullable instancetype)initWithText:(nullable NSString *)fullText startTag:(nullable NSString *)startTag endTag:(nullable NSString *)endTag actionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData actionDelegate:(nullable NSObject<MVMCoreActionDelegateProtocol> *)delegate;
//set action map
- (void)setActionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData actionDelegate:(nullable NSObject<MVMCoreActionDelegateProtocol> *)delegate;
//set text with curly braces
- (void)setCurlyBracedText:(nonnull NSString *)text;
// set text with any tags
- (void)setWithText:(nullable NSString *)fullText startTag:(nullable NSString *)startTag endTag:(nullable NSString *)endTag actionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData actionDelegate:(nullable NSObject<MVMCoreActionDelegateProtocol> *)delegate;
// Reset the text, action map and delegate
- (void)setTextWithClickableTextEmbeddedInCurlyBraces:(nullable NSString *)text textAttributes:(nullable NSDictionary *)attributes actionMapForClickableText:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData actionDelegate:(nullable NSObject<MVMCoreActionDelegateProtocol> *)delegate;
// Reset the front text, back text, action map
- (void)setFrontText:(nullable NSString *)frontText actionMap:(nullable NSDictionary *)actionMap backText:(nullable NSString *)backText additionalData:(nullable NSDictionary *)additionalData delegate:(nullable NSObject<MVMCoreActionDelegateProtocol> *)delegate;
// Reset the front text, back text, action map
- (void)setFrontAttributedText:(nullable NSAttributedString *)frontAttributedText actionMap:(nullable NSDictionary *)actionMap backAttributedText:(nullable NSAttributedString *)backText additionalData:(nullable NSDictionary *)additionalData delegate:(nullable NSObject<MVMCoreActionDelegateProtocol> *)delegate;
- (void)setFrontAttributedText:(nullable NSAttributedString *)frontAttributedText actionMap:(nullable NSDictionary *)actionMap backAttributedText:(nullable NSAttributedString *)backAttributedText addNewLine:(BOOL) addNewLine additionalData:(nullable NSDictionary *)additionalData delegate:(nullable NSObject<MVMCoreActionDelegateProtocol> *)delegate;
- (void)resetWithActionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary * )additionalData delegate:(nullable NSObject<MVMCoreActionDelegateProtocol> *)delegate;
- (void)setAlignment:(NSTextAlignment)textAlignment;
- (void)setEnabled:(BOOL)enabled;
- (void)setAlternateActionTextAttributes:(nullable NSDictionary *)attributes;
- (void)setActionTextString:(nullable NSString *)actionText;
- (nonnull UIAccessibilityCustomAction *)accessibilityCustomAction;
@end

View File

@ -0,0 +1,557 @@
//
// TextMixedWithButtonView.m
// mobilefirst
//
// Created by Chris Yang on 2/25/16.
// Copyright © 2016 Verizon Wireless. All rights reserved.
//
#import "LabelWithInternalButton.h"
#import <MVMCore/UILabel+MFCustom.h>
#import <MVMCore/NSDictionary+MFConvenience.h>
#import <MVMCoreUI/MFFonts.h>
#import <MVMCore/MVMCoreJSONConstants.h>
#import <MVMCoreUI/UIColor+MFConvenience.h>
#import <MVMCoreUI/MFStyler.h>
#import <MVMCoreUI/MVMCoreUIConstants.h>
#import <MVMCore/MVMCoreConstants.h>
#import <MVMCore/MVMCoreActionHandler.h>
@interface LabelWithInternalButton ()
@property (nullable, strong, nonatomic) NSString *text;
@end
@implementation LabelWithInternalButton
- (nullable instancetype)initWithActionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData actionDelegate:(nullable NSObject <MVMCoreActionDelegateProtocol> *)delegate buttonDelegate:(nullable NSObject<ButtonDelegateProtocol> *)buttonDelegate {
return [self initWithFrontText:[actionMap stringForKey:KeyTitlePrefix] actionText:[actionMap stringForKey:KeyTitle] backText:[actionMap stringForKey:KeyTitlePostfix] actionMap:actionMap additionalData:additionalData actionDelegate:delegate buttonDelegate:buttonDelegate];
}
- (nullable instancetype)initWithFrontText:(nullable NSString *)frontText backText:(nullable NSString *)backText actionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData actionDelegate:(nullable NSObject<MVMCoreActionDelegateProtocol> *)delegate buttonDelegate:(nullable NSObject<ButtonDelegateProtocol> *)buttonDelegate {
return [self initWithFrontText:frontText actionText:[actionMap stringForKey:KeyTitle] backText:backText actionMap:actionMap additionalData:additionalData actionDelegate:delegate buttonDelegate:buttonDelegate];
}
- (nullable instancetype)initWithFrontText:(nullable NSString *)frontText actionText:(nullable NSString *)actionText backText:(nullable NSString *)backText actionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData actionDelegate:(nullable NSObject<MVMCoreActionDelegateProtocol> *)delegate buttonDelegate:(nullable NSObject<ButtonDelegateProtocol> *)buttonDelegate {
if (self = [super init]) {
[self setFrontText:frontText actionText:actionText actionMap:actionMap backText:backText additionalData:additionalData delegate:delegate buttonDelegate:buttonDelegate];
}
return self;
}
- (void)setActionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData actionDelegate:(nullable NSObject<MVMCoreActionDelegateProtocol> *)delegate buttonDelegate:(nullable NSObject<ButtonDelegateProtocol> *)buttonDelegate {
__weak typeof(self) weakSelf = self;
__weak typeof(delegate) weakDelegate = delegate;
__weak typeof(buttonDelegate) weakButtonDelegate = buttonDelegate;
self.actionBlock = ^{
BOOL performAction = YES;
if (weakButtonDelegate && [weakButtonDelegate respondsToSelector:@selector(button:shouldPerformActionWithMap:additionalData:)]) {
performAction = [weakButtonDelegate button:weakSelf shouldPerformActionWithMap:actionMap additionalData:additionalData];
}
if (performAction) {
[[MVMCoreActionHandler sharedActionHandler] handleActionWithDictionary:actionMap additionalData:additionalData delegate:weakDelegate];
}
};
}
- (void)setFrontText:(NSString *)frontText actionMap:(NSDictionary *)actionMap backText:(NSString *)backText additionalData:(NSDictionary *)additionalData delegate:(nullable NSObject<MVMCoreActionDelegateProtocol> *)delegate buttonDelegate:(nullable NSObject<ButtonDelegateProtocol> *)buttonDelegate {
[self setFrontText:frontText actionText:[actionMap stringForKey:KeyTitle] actionMap:actionMap backText:backText additionalData:additionalData delegate:delegate buttonDelegate:buttonDelegate];
}
- (void)setFrontText:(NSString *)frontText actionText:(NSString *)actionText actionMap:(NSDictionary *)actionMap backText:(NSString *)backText additionalData:(NSDictionary *)additionalData delegate:(nullable NSObject<MVMCoreActionDelegateProtocol> *)delegate buttonDelegate:(nullable NSObject<ButtonDelegateProtocol> *)buttonDelegate {
self.frontText = frontText;
[self setActionMap:actionMap additionalData:additionalData actionDelegate:delegate buttonDelegate:buttonDelegate];
self.actionText = actionText;
self.backText = backText;
self.text = [self getTextFromStringComponents];
[self setup];
}
- (void)setFrontAttributedText:(nullable NSAttributedString *)frontAttributedText actionMap:(nullable NSDictionary *)actionMap backAttributedText:(nullable NSAttributedString *)backText additionalData:(nullable NSDictionary *)additionalData delegate:(nullable NSObject<MVMCoreActionDelegateProtocol> *)delegate buttonDelegate:(nullable NSObject<ButtonDelegateProtocol> *)buttonDelegate {
[self setFrontAttributedText:frontAttributedText actionMap:actionMap backAttributedText:backText addNewLine:NO additionalData:additionalData delegate:delegate buttonDelegate:buttonDelegate];
}
- (void)setFrontAttributedText:(nullable NSAttributedString *)frontAttributedText actionMap:(nullable NSDictionary *)actionMap backAttributedText:(nullable NSAttributedString *)backAttributedText addNewLine:(BOOL) addNewLine additionalData:(nullable NSDictionary *)additionalData delegate:(nullable NSObject<MVMCoreActionDelegateProtocol> *)delegate buttonDelegate:(nullable NSObject<ButtonDelegateProtocol> *)buttonDelegate {
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] init];
if (frontAttributedText) {
[attributedString appendAttributedString:frontAttributedText];
// need to do this to fix the range issue
self.frontText = frontAttributedText.string;
}
NSString *newLineAttributed = [[NSString alloc] initWithString:addNewLine?@"\n":@" "];
if (actionMap.allKeys.count > 0) {
NSMutableString *actionString = [[actionMap stringForKey:KeyTitle] mutableCopy];
if (actionString.length > 0) {
[actionString appendString:newLineAttributed];
NSAttributedString *actionAttributedString = [MFStyler styleGetAttributedString:actionString font:[MFStyler fontB2] color:[UIColor blackColor]];
self.actionText = actionString;
[self setActionMap:actionMap additionalData:additionalData actionDelegate:delegate buttonDelegate:buttonDelegate];
[attributedString appendAttributedString:actionAttributedString];
}
} else {
self.actionText = nil;
self.actionBlock = nil;
}
if (backAttributedText) {
[attributedString appendAttributedString:backAttributedText];
}
self.attributedText = attributedString;
//added this line for underlining
[self setAlternateActionTextAttributes:@{NSUnderlineStyleAttributeName: @(NSUnderlineStyleSingle)}];
}
#pragma mark - legacy
- (nullable instancetype)initWithFrontText:(nullable NSString *)frontText actionText:(nullable NSString *)actionText backText:(nullable NSString *)backText actionBlock:(nullable ActionBlock)block {
if (self = [super init]) {
self.frontText = frontText;
self.actionText = actionText;
self.backText = backText;
self.actionBlock = block;
self.text = [self getTextFromStringComponents];
[self setup];
}
return self;
}
- (nullable instancetype)initWithFrontText:(nullable NSString *)frontText actionText:(nullable NSString *)actionText backText:(nullable NSString *)backText actionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData actionDelegate:(nullable NSObject<MVMCoreActionDelegateProtocol> *)delegate {
return [self initWithFrontText:frontText actionText:actionText backText:backText actionMap:actionMap additionalData:additionalData actionDelegate:delegate buttonDelegate:nil];
}
- (nullable instancetype)initWithActionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData actionDelegate:(nullable NSObject <MVMCoreActionDelegateProtocol> *)delegate {
return [self initWithFrontText:[actionMap stringForKey:KeyTitlePrefix] actionText:[actionMap stringForKey:KeyTitle] backText:[actionMap stringForKey:KeyTitlePostfix] actionMap:actionMap additionalData:additionalData actionDelegate:delegate];
}
- (instancetype)init
{
self = [super init];
if (self) {
[self setup];
}
return self;
}
- (instancetype)initWithCoder:(NSCoder *)coder
{
self = [super initWithCoder:coder];
if (self) {
[self setup];
}
return self;
}
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self setup];
}
return self;
}
- (nullable instancetype)initWithFrontText:(nullable NSString *)frontText backText:(nullable NSString *)backText actionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData actionDelegate:(nullable NSObject<MVMCoreActionDelegateProtocol> *)delegate {
return [self initWithFrontText:frontText actionText:[actionMap stringForKey:KeyTitle] backText:backText actionMap:actionMap additionalData:additionalData actionDelegate:delegate];
}
// Convenience Initializer which assumes that the clickable text will be embedded in curly braces {}.
- (nullable instancetype)initWithClickableTextEmbeddedInCurlyBraces:(nullable NSString *)fullText actionMapForClickableText:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData actionDelegate:(nullable NSObject<MVMCoreActionDelegateProtocol> *)delegate {
return [self initWithText:fullText startTag:@"{" endTag:@"}" actionMap:actionMap additionalData:additionalData actionDelegate:delegate];
}
- (instancetype)initWithText:(nullable NSString *)fullText startTag:(nullable NSString *)startTag endTag:(nullable NSString *)endTag actionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData actionDelegate:(nullable NSObject<MVMCoreActionDelegateProtocol> *)delegate
{
self = [super init];
if (self) {
[self setText:fullText startTag:startTag endTag:endTag];
__weak typeof(delegate) weakDelegate = delegate;
self.actionBlock = ^{
[[MVMCoreActionHandler sharedActionHandler] handleActionWithDictionary:actionMap additionalData:additionalData delegate:weakDelegate];
};
}
return self;
}
- (void)setup {
if (!self.label) {
MFLabel *label = [[MFLabel alloc] initWithFrame:CGRectZero];
self.backgroundColor = [UIColor clearColor];
label.translatesAutoresizingMaskIntoConstraints = NO;
label.userInteractionEnabled = NO;
label.numberOfLines = 0;
label.lineBreakMode = NSLineBreakByWordWrapping;
[label setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
[self addSubview:label];
[NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[label]-0-|" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(label)]];
[NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[label]-0-|" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(label)]];
self.label = label;
[label sizeToFit];
}
if (!self.normalTextColor) {
self.normalTextColor = [UIColor blackColor];
}
if (!self.actionTextColor) {
self.actionTextColor = [UIColor blackColor];
}
if (!self.normalTextFont) {
self.normalTextFont = [MFStyler fontB2];
}
if (!self.actionTextFont) {
self.actionTextFont = [MFStyler fontB2];
}
//adding the underline
[self setAlternateActionTextAttributes:@{NSUnderlineStyleAttributeName: @(NSUnderlineStyleSingle)}];
self.label.attributedText = self.attributedText;
[self.label setAccessibilityTraits:UIAccessibilityTraitButton];
}
- (void)updateView:(CGFloat)size {
//reset font for app size change
self.normalTextFont = [MFStyler fontB2];
self.actionTextFont = [MFStyler fontB2];
self.label.attributedText = self.attributedText;
}
#pragma mark - UIControl overide
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
if ([self areTouchesInActionString:touches]) {
[self sendActionsForControlEvents:UIControlEventTouchUpInside];
[self performAction];
} else {
[self sendActionsForControlEvents:UIControlEventTouchUpOutside];
}
}
#pragma mark - helper
- (NSString *)getTextFromStringComponents {
if (self.frontText.length == 0) {
self.frontText = @"";
} else {
self.frontText = [self.frontText stringByAppendingString:[self spaceBetweenPartOne:self.frontText andPartTwo:self.actionText]];
}
if (self.actionText.length == 0) {
self.actionText = @"";
} else {
self.actionText = [self.actionText stringByAppendingString:[self spaceBetweenPartOne:self.actionText andPartTwo:self.backText]];
}
if (self.backText.length == 0) {
self.backText = @"";
}
return [[NSString alloc] initWithFormat:@"%@%@%@",self.frontText, self.actionText, self.backText];
}
- (NSString *)spaceBetweenPartOne:(NSString *)partOne andPartTwo:(NSString *)partTwo {
/*if (!partTwo || partTwo.length == 0 || [MFUtility validateString:partTwo withRegularExpression:@"[.,?!;:]"] || [partOne hasSuffix:@" "]) {
return @"";
}*/
return @" ";
}
- (NSRange)getActionRange {
return NSMakeRange(self.frontText.length, self.actionText.length);
}
- (NSRange)getFrontRange {
return NSMakeRange(0, self.frontText.length);
}
- (NSRange)getBackRange {
return NSMakeRange(self.frontText.length + self.actionText.length, self.backText.length);}
- (void)performAction {
if (self.actionBlock) {
self.actionBlock();
}
}
- (NSArray *)getRangeArrayOfWordsInString:(NSString *)string withInitalIndex:(NSInteger)index {
NSArray *words = [string componentsSeparatedByString:@" "];
NSMutableArray *rangeArray = [[NSMutableArray alloc] init];
for (NSString *subString in words) {
NSString *finalSubString = [subString stringByAppendingString:@" "];
NSInteger wordIndex = index;
NSInteger length = finalSubString.length;
NSRange subStringRange = NSMakeRange(wordIndex, length);
NSValue *rangeValue = [NSValue valueWithRange:subStringRange];
[rangeArray addObject:rangeValue];
index += length;
}
return rangeArray;
}
- (NSArray *)getRectArrayFromRangeArray:(NSArray *)rangeArray {
NSMutableArray *rectArray = [[NSMutableArray alloc] init];
for (NSValue *aValueOfRange in rangeArray) {
NSRange wordRange = [aValueOfRange rangeValue];
CGRect rect = [self.label boundingRectForCharacterRange:wordRange];
NSValue *rectValue = [NSValue valueWithCGRect:rect];
[rectArray addObject:rectValue];
}
return rectArray;
}
- (BOOL)areTouchesInActionString:(NSSet<UITouch *> *)touches {
if (UIAccessibilityIsVoiceOverRunning() || self.makeWholeViewClickable) {
return YES;
}
CGPoint location = [[touches anyObject] locationInView:self.label];
NSString *actionString = self.actionText;
NSInteger index = [self getActionRange].location;
NSArray *rangeArray = [self getRangeArrayOfWordsInString:actionString withInitalIndex:index];
NSArray *rectArray = [self getRectArrayFromRangeArray:rangeArray];
BOOL result = NO;
for (NSValue *aValueOfRect in rectArray) {
CGRect wordRect = [aValueOfRect CGRectValue];
if (CGRectContainsPoint(wordRect, location)){
result = YES;
break;
} else if (wordRect.origin.x == 0 && wordRect.origin.y == 0 && wordRect.size.height == 0 && wordRect.size.width == 0) {
//incase word rect is not found for any reason, make the whole label to be clicable to avoid non functioning link in production.
result = YES;
break;
}
}
return result;
}
#pragma mark - setter
- (void)setText:(NSString *)text {
if (text) {
_text = text;
self.attributedText = [[NSAttributedString alloc] initWithString:text];
//call the setters to properly set the attributes
[self setNormalTextFont:self.normalTextFont];
[self setActionTextFont:self.actionTextFont];
[self setNormalTextColor:self.normalTextColor];
[self setActionTextColor:self.actionTextColor];
}
}
- (void)setCurlyBracedText:(nonnull NSString *)text {
[self setText:text startTag:@"{" endTag:@"}"];
}
- (void)setText:(NSString *)text startTag:(NSString *)startTag endTag:(NSString *)endTag {
NSRange actionRange = [self rangeOfText:&text startTag:startTag endTag:endTag];
self.frontText = [text substringWithRange:NSMakeRange(0,actionRange.location)];
self.actionText = [text substringWithRange:actionRange];
self.backText = [text substringWithRange:NSMakeRange(self.frontText.length+self.actionText.length, text.length - self.frontText.length-self.actionText.length)];
self.text = [self getTextFromStringComponents];
[self setup];
}
- (NSRange)rangeOfCurlyBracedText:(NSString **)text {
return [self rangeOfText:text startTag:@"{" endTag:@"}"];
}
- (NSRange)rangeOfText:(NSString **)text startTag:(NSString *)startTag endTag:(NSString *)endTag {
NSString *fullText = *text;
NSRange range = NSMakeRange(0, 0);
NSRange rangeOfLeftBrace = [fullText rangeOfString:startTag];
if (rangeOfLeftBrace.location != NSNotFound) {
fullText = [fullText stringByReplacingCharactersInRange:rangeOfLeftBrace withString:@""];
NSRange rangeOfRightBrace = [fullText rangeOfString:endTag];
if (rangeOfRightBrace.location != NSNotFound) {
NSInteger length = (rangeOfRightBrace.location - rangeOfLeftBrace.location);
if (length > 0) {
range = NSMakeRange(rangeOfLeftBrace.location, length);
fullText = [fullText stringByReplacingCharactersInRange:rangeOfRightBrace withString:@""];
}
}
}
*text = fullText;
return range;
}
- (void)setNormalTextColor:(UIColor *)normalTextColor {
if (normalTextColor) {
_normalTextColor = normalTextColor;
[self setAlternateNormalTextAttributes:@{NSForegroundColorAttributeName:normalTextColor}];
}
}
- (void)setActionTextColor:(UIColor *)actionTextColor {
if (actionTextColor) {
_actionTextColor = actionTextColor;
[self setAlternateActionTextAttributes:@{NSForegroundColorAttributeName:actionTextColor}];
}
}
- (void)setAttributedText:(NSAttributedString *)attributedText {
_attributedText = attributedText;
NSMutableAttributedString *mutableAttributedText = [attributedText mutableCopy];
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
paragraphStyle.lineSpacing = LabelWithInternalButtonLineSpace;
[mutableAttributedText addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange(0, attributedText.length)];
if (self.label && mutableAttributedText) {
self.label.attributedText = mutableAttributedText;
}
}
- (void)setNormalTextFont:(UIFont *)normalTextFont {
if (normalTextFont) {
_normalTextFont = normalTextFont;
[self setAlternateNormalTextAttributes:@{NSFontAttributeName:normalTextFont}];
}
}
- (void)setActionTextFont:(UIFont *)actionTextFont {
if (actionTextFont) {
_actionTextFont = actionTextFont;
[self setAlternateActionTextAttributes:@{NSFontAttributeName:actionTextFont}];
}
}
- (void)setActionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData actionDelegate:(nullable NSObject <MVMCoreActionDelegateProtocol> *)delegate {
[self setActionMap:actionMap additionalData:additionalData actionDelegate:delegate buttonDelegate:nil];
}
// Reset the text and action map
- (void)setTextWithClickableTextEmbeddedInCurlyBraces:(nullable NSString *)text textAttributes:(nullable NSDictionary *)attributes actionMapForClickableText:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData actionDelegate:(nullable NSObject<MVMCoreActionDelegateProtocol> *)delegate {
self.attributedText = [[NSAttributedString alloc] initWithString:text attributes:attributes];
[self setActionMap:actionMap additionalData:additionalData actionDelegate:delegate];
}
- (void)setWithText:(nullable NSString *)fullText startTag:(nullable NSString *)startTag endTag:(nullable NSString *)endTag actionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData actionDelegate:(nullable NSObject<MVMCoreActionDelegateProtocol> *)delegate {
[self setText:fullText startTag:startTag endTag:endTag];
[self setActionMap:actionMap additionalData:additionalData actionDelegate:delegate];
}
- (void)setEnabled:(BOOL)enabled {
[super setEnabled:enabled];
if (enabled) {
self.alpha = 1;
} else {
self.alpha = DisableOppacity;
}
}
- (void)setFrontText:(NSString *)frontText actionMap:(NSDictionary *)actionMap backText:(NSString *)backText additionalData:(NSDictionary *)additionalData delegate:(nullable NSObject<MVMCoreActionDelegateProtocol> *)delegate {
[self setFrontText:frontText actionMap:actionMap backText:backText additionalData:additionalData delegate:delegate buttonDelegate:nil];
}
// Reset the front text, back text, action map
- (void)setFrontAttributedText:(nullable NSAttributedString *)frontAttributedText actionMap:(nullable NSDictionary *)actionMap backAttributedText:(nullable NSAttributedString *)backAttributedText additionalData:(nullable NSDictionary *)additionalData delegate:(nullable NSObject<MVMCoreActionDelegateProtocol> *)delegate {
[self setFrontAttributedText:frontAttributedText actionMap:actionMap backAttributedText:backAttributedText addNewLine:NO additionalData:additionalData delegate:delegate];
}
- (void)setFrontAttributedText:(nullable NSAttributedString *)frontAttributedText actionMap:(nullable NSDictionary *)actionMap backAttributedText:(nullable NSAttributedString *)backAttributedText addNewLine:(BOOL) addNewLine additionalData:(nullable NSDictionary *)additionalData delegate:(nullable NSObject<MVMCoreActionDelegateProtocol> *)delegate {
[self setFrontAttributedText:frontAttributedText actionMap:actionMap backAttributedText:backAttributedText addNewLine:addNewLine additionalData:additionalData delegate:delegate buttonDelegate:nil];
}
- (void)setAlignment:(NSTextAlignment)textAlignment {
self.label.textAlignment = textAlignment;
}
- (void)setAlternateActionTextAttributes:(nullable NSDictionary *)attributes {
if (attributes) {
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithAttributedString:self.attributedText];
[attributedString addAttributes:attributes range:[self getActionRange]];
self.attributedText = attributedString;
}
}
- (void)setAlternateNormalTextAttributes:(nullable NSDictionary *)attributes {
if (attributes) {
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithAttributedString:self.attributedText];
[attributedString addAttributes:attributes range:[self getFrontRange]];
[attributedString addAttributes:attributes range:[self getBackRange]];
self.attributedText = attributedString;
}
}
- (void)setActionTextString:(nullable NSString *)actionText {
self.actionText = actionText;
self.text = [self getTextFromStringComponents];
[self setup];
}
/// Used to just reset the texts and actions if already initialized
- (void)resetWithActionMap:(NSDictionary *)actionMap additionalData:(NSDictionary *)additionalData delegate:(NSObject<MVMCoreActionDelegateProtocol> *)delegate {
self.frontText = [actionMap stringForKey:KeyTitlePrefix];
self.actionText = [actionMap stringForKey:KeyTitle];
self.backText = [actionMap stringForKey:KeyTitlePostfix];
__weak typeof(delegate) weakDelegate = delegate;
self.actionBlock = ^{
[[MVMCoreActionHandler sharedActionHandler] handleActionWithDictionary:actionMap additionalData:additionalData delegate:weakDelegate];
};
self.text = [self getTextFromStringComponents];
[self setup];
}
//#pragma mark - Accessibility
//
//-(BOOL)isAccessibilityElement{
// return YES;
//}
//
//-(UIAccessibilityTraits)accessibilityTraits{
// return UIAccessibilityTraitLink;
//}
- (NSString *)replaceSpaceWithFakeSpace:(NSString *)string {
NSArray *words = [string componentsSeparatedByString:@" "];
return [words componentsJoinedByString:@"\u00a0"];
}
- (BOOL)accessibilityActivate {
if (self.actionBlock) {
self.actionBlock();
return YES;
} else {
return NO;
}
}
- (UIAccessibilityCustomAction *)accessibilityCustomAction {
if (self.actionText.length) {
NSString *name = self.actionText;
return [[UIAccessibilityCustomAction alloc] initWithName:name target:self selector:@selector(accessibilityActivate)];
} else {
return [[UIAccessibilityCustomAction alloc] init];
}
}
@end

View File

@ -0,0 +1,15 @@
//
// TextFieldView.h
// mobilefirst
//
// Created by Seshamani, Shreyas on 6/24/16.
// Copyright © 2016 Verizon Wireless. All rights reserved.
//
#import <MVMCoreUI/ViewConstrainingView.h>
@interface TextFieldView : ViewConstrainingView
@property (nonatomic, weak, nullable) UITextField *textField;
@end

View File

@ -0,0 +1,44 @@
//
// TextFieldView.m
// mobilefirst
//
// Created by Seshamani, Shreyas on 6/24/16.
// Copyright © 2016 Verizon Wireless. All rights reserved.
//
#import "TextFieldView.h"
@implementation TextFieldView
- (void)setupView {
if (!self.textField) {
self.backgroundColor = [UIColor clearColor];
UITextField *textField = [[UITextField alloc]initWithFrame:CGRectZero];
[self addSubview:textField];
textField.translatesAutoresizingMaskIntoConstraints = NO;
self.textField = textField;
self.textField.backgroundColor = [UIColor whiteColor];
// Align left and right constants.
NSLayoutConstraint *leftPin = [NSLayoutConstraint constraintWithItem:textField attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeft multiplier:1.0 constant:0];
self.leftPin = leftPin;
leftPin.active = YES;
NSLayoutConstraint *topPin = [NSLayoutConstraint constraintWithItem:textField attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTop multiplier:1.0 constant:0];
topPin.priority = 999;
self.topPin = topPin;
topPin.active = YES;
NSLayoutConstraint *bottomPin = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:textField attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0];
self.bottomPin = bottomPin;
bottomPin.active = YES;
NSLayoutConstraint *rightPin = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:textField attribute:NSLayoutAttributeRight multiplier:1.0 constant:0];
rightPin.priority = 999;
self.rightPin = rightPin;
rightPin.active = YES;
}
}
@end

View File

@ -688,7 +688,7 @@
if (!error && (loadObject.requestParameters.openSupportPanel || [loadObject.systemParametersJSON boolForKey:KeyOpenSupport])) {
[[MVMCoreUISession sharedGlobal].splitViewController showRightPanelAnimated:YES];
}
[[MVMCoreUILoggingHandler sharedLoggingHandler] defaultTrackLoadFinishedForController:self loadObject:loadObject];
[MVMCoreUILoggingHandler logWithDelegateLoadFinished:loadObject loadedViewController:loadedViewController error:error];
}
- (void)loadCancelled:(nullable MVMCoreLoadObject *)loadObject {

View File

@ -0,0 +1,76 @@
//
// TopLabelsAndBottomButtonsTableViewController.h
// myverizon
//
// Created by Chris Yang on 2/3/16.
// Copyright © 2016 Verizon Wireless. All rights reserved.
//
#import <MVMCoreUI/MFProgrammaticTableViewController.h>
#import <MVMCoreUI/TopLabelsView.h>
@class PrimaryButton;
@interface TopLabelsAndBottomButtonsTableViewController : MFProgrammaticTableViewController
@property (nullable, weak, nonatomic) TopLabelsView *topLabelsView;
@property (nullable, weak, nonatomic) PrimaryButton *primaryButton;
@property (nullable, weak, nonatomic) PrimaryButton *secondaryButton;
@property (nullable, weak, nonatomic) UIView *viewInScroll;
@property (nullable, weak, nonatomic) UIView *viewOutOfScroll;
@property (nullable, strong, nonatomic) UIView *bottomView;
@property (nullable, strong, nonatomic) UIView *safeAreaView;
@property (nullable, strong, nonatomic) UIView *tableFooterAccessoryView;
// Can override. This is put in because to cover 90% of the screens for initial ipad release, need to rebuild ui (newDataBuildScreen) of size of view change in updateViews. Disable this to handle manually with more finess.
@property (nonatomic) BOOL rebuildUIOnSizeChange;
// For manually showing and hiding top or bottom view. Most likely not needed. May be useful for if a header is not there but then appears under certain conditions.
- (void)showHeader;
- (void)hideHeader;
- (void)showFooter;
- (void)hideFooter;
- (void)tryToCleanUpMemory;
// showing/hiding left and right primary buttons
- (void)setPrimaryLeftButtonHidden:(BOOL)left rightButtonHidden:(BOOL)right;
#pragma mark - Subclass
//*********
// Can overwrite the default padding below top view or above middle view(between view)
- (nonnull NSNumber *)spaceAboveBetweenView;
// If both are subclassed to return NO, then the buttons will not be pinned towards the bottom because neither spacing would try to fill the screen. Below top is default NO, above bottom is default YES.
- (BOOL)spaceBelowTopViewSetToFill;
- (BOOL)spaceAboveBottomViewSetToFill;
// Can overwrite the default padding for labels and buttons.
- (UIEdgeInsets)paddingForTopLabels;
- (UIEdgeInsets)paddingForBottomButtons;
// default button map will automatically get from response, or you can set these to have your own button map used.
- (nullable NSDictionary *)secondaryButtonMap;
- (nullable NSDictionary *)primaryButtonMap;
//populate the footer accerssory view
- (nonnull NSArray <UIView *>*)populateHeaderAccessoryView;
//populate the footer accerssory view
- (nonnull NSArray <UIView *>*)populateFooterAccessoryView;
// The space between objects for the footer accessory.
- (UIEdgeInsets)spaceAroundUIObject:(nullable id)object;
// Should not sub class it, for most cases, the headline and message will be in page map, but who knows how server wants to send them in certain pages
- (nullable NSDictionary *)mapForTopLabels;
// Use these if you want to replace the top labels or bottom button views with your own views.
- (nullable UIView *)useCustomViewInsteadOfLabels;
- (nullable UIView *)useCustomViewInsteadOfButtons;
// Can override if the buttons should be outside of the scroll or not. Default is no.
- (BOOL)bottomViewOutsideOfScroll;
//override for setting attributed headline and message
-(void)setHeadlineAndMessage;
@end

View File

@ -0,0 +1,494 @@
//
// TopLabelsAndBottomButtonsTableViewController.m
// myverizon
//
// Created by Chris Yang on 2/3/16.
// Copyright © 2016 Verizon Wireless. All rights reserved.
//
#import "TopLabelsAndBottomButtonsTableViewController.h"
#import <MVMCoreUI/PrimaryButtonView.h>
#import <MVMCoreUI/MVMCoreUIUtility.h>
#import <MVMCoreUI/StackableViewController.h>
#import <MVMCoreUI/MVMCoreUICommonViewsUtility.h>
#import <MVMCoreUI/MFStyler.h>
#import <MVMCoreUI/NSLayoutConstraint+MFConvenience.h>
#import <MVMCoreUI/UIColor+MFConvenience.h>
#import <MVMCoreUI/MVMCoreUIConstants.h>
#import <MVMCore/NSDictionary+MFConvenience.h>
#import <MVMCore/MVMCoreLoadObject.h>
#import <MVMCore/MVMCoreJSONConstants.h>
@import MVMAnimationFramework;
@interface TopLabelsAndBottomButtonsTableViewController ()
@property (strong, nonatomic) UIView *topView;
@property (strong, nonatomic) UIView *headerView;
@property (strong, nonatomic) NSLayoutConstraint *topViewBottomConstraint;
@property (strong, nonatomic) UIView *footerView;
@property (strong, nonatomic) UIView *footerViewOutsideOfScroll;
@property (strong, nonatomic) NSLayoutConstraint *bottomViewTopConstraint;
@property (strong, nonatomic) UIView *headerAccessoryView;
@end
@implementation TopLabelsAndBottomButtonsTableViewController
- (void)backButtonPressed {
[super backButtonPressed];
//[self tryToCleanUpMemory];
}
- (void)tryToCleanUpMemory {
//[self.footerView removeFromSuperview];
//self.footerView = nil;
//self.footerAccessoryView = nil;
//self.bottomView = nil;
}
- (void)initialLoad {
[super initialLoad];
self.rebuildUIOnSizeChange = YES;
}
- (void)updateViews {
[super updateViews];
// If the screen size changed.... just rebuild everything.... this will cover all sizes and help for ipad slide over.
if ([self screenSizeChanged]) {
if (self.rebuildUIOnSizeChange) {
// If the screen size changed.... just rebuild everything.... this will cover all sizes and help for ipad slide over.
[self newDataBuildScreen];
} else {
// Update top labels and bottom buttons.
CGFloat width = CGRectGetWidth(self.view.bounds);
if ([self.topView respondsToSelector:@selector(updateView:)]) {
[((UIView <MVMCoreViewProtocol>*)self.topView) updateView:width];
[self showHeader];
}
[self.topLabelsView updateView:width];
if ([self.bottomView respondsToSelector:@selector(updateView:)]) {
[((UIView <MVMCoreViewProtocol>*)self.bottomView) updateView:width];
[self showFooter];
}
[self.tableView reloadData];
}
}
}
- (void)newDataBuildScreen {
[super newDataBuildScreen];
// Checks if subclass is using a different view than the top labels.
self.topView = [self useCustomViewInsteadOfLabels];
if (!self.topView) {
// The labels are toward the top of the screen.
TopLabelsView *topLabelsView = [[TopLabelsView alloc] initWithTableView:self];
[topLabelsView setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
UIEdgeInsets paddingForTopLabels = [self paddingForTopLabels];
topLabelsView.topLabelConstraint.constant = paddingForTopLabels.top;
topLabelsView.bottomLabelConstraint.constant = paddingForTopLabels.bottom;
[topLabelsView setLeftConstant:paddingForTopLabels.left];
[topLabelsView setRightConstant:paddingForTopLabels.right];
topLabelsView.separatorView.hidden = NO;
self.topLabelsView = topLabelsView;
[self setHeadlineAndMessage];
self.topView = topLabelsView;
}
// Setup accessory view.
[self setUpHeaderAccessoryView];
// add top view to table header
if (self.topView) {
self.topView.translatesAutoresizingMaskIntoConstraints = NO;
[self createViewForHeader];
[self showHeader];
} else {
[self hideHeader];
}
// Setup accessory view.
[self setUpFooterAccessoryView];
// Checks if subclass is using a different view than the bottom buttons.
[self.bottomView removeFromSuperview];
self.tableView.tableFooterView = nil;
self.bottomView = [self useCustomViewInsteadOfButtons];
if (!self.bottomView) {
// Sets up the buttons/button.
NSDictionary *primaryButtonDictionary = [self primaryButtonMap];
NSDictionary *secondaryButtonDictionary = [self secondaryButtonMap];
PrimaryButtonView *buttonView = [[PrimaryButtonView alloc] initWithPrimaryButtonMap:primaryButtonDictionary secondaryButtonMap:secondaryButtonDictionary actionDelegate:self additionalData:nil buttonDelegate:self];
self.secondaryButton = buttonView.secondaryButton;
self.primaryButton = buttonView.primaryButton;
self.bottomView = buttonView;
buttonView.topPin.constant = [self paddingForBottomButtons].top;
buttonView.bottomPin.constant = [self paddingForBottomButtons].bottom;
buttonView.leftPin.constant = [self paddingForBottomButtons].left;
buttonView.rightPin.constant = [self paddingForBottomButtons].right;
if (self.bottomViewOutsideOfScroll) {
buttonView.backgroundColor = [UIColor mfBackgroundGray];
}
}
// add bottom view to table footer
if (self.bottomView) {
self.bottomView.translatesAutoresizingMaskIntoConstraints = NO;
[self createViewForFooter];
[self showFooter];
} else {
[self hideFooter];
}
[self.tableView reloadData];
}
-(void)setHeadlineAndMessage {
[self.topLabelsView setHeadlineString:[[self mapForTopLabels] stringForKey:KeyTitle] messageString:[[self mapForTopLabels] stringForKey:KeyMessage]];
}
- (void)updateViewConstraints {
[super updateViewConstraints];
BOOL spaceToFillTop = NO;
CGFloat currentSpace = 0;
if ([self spaceBelowTopViewSetToFill] && self.tableView.tableHeaderView) {
// Space top view.
spaceToFillTop = YES;
currentSpace = self.topViewBottomConstraint.constant;
}
BOOL spaceToFillBottom = NO;
if (!self.bottomViewOutsideOfScroll && [self spaceAboveBottomViewSetToFill] && self.tableView.tableFooterView) {
// Space to fill bottom view.
spaceToFillBottom = YES;
currentSpace += self.bottomViewTopConstraint.constant;
}
if (spaceToFillTop || spaceToFillBottom) {
// This logic only works because the minimum height is zero, otherwise we'd have to add both minimum heights like we did the current space.
CGFloat newSpace = [MVMCoreUIUtility getVariableConstraintHeight:currentSpace inScrollView:self.tableView minimumHeight:0];
// If the bottom view is outside of the scroll, then only the top view constraint is being used, so we have to double it to account for the bottom constraint not being there when we compare to the new value.
CGFloat currentSpaceForCompare = currentSpace;
if (spaceToFillTop && self.bottomViewOutsideOfScroll) {
currentSpaceForCompare = currentSpace * 2;
}
if (!fequalwiththreshold(newSpace,currentSpaceForCompare,0.1)) {
if (spaceToFillTop && spaceToFillBottom) {
// Both are being spaced.
self.topViewBottomConstraint.constant = newSpace / 2;
self.bottomViewTopConstraint.constant = newSpace / 2;
[self showHeader];
[self showFooter];
} else if (spaceToFillTop) {
// Only top is spaced (half the size if the bottom view is out of the scroll because it needs to be sized as if there are two spacers but there is only one.
if (self.bottomViewOutsideOfScroll) {
self.topViewBottomConstraint.constant = newSpace / 2;
} else {
self.topViewBottomConstraint.constant = newSpace;
}
[self showHeader];
} else {
// Only bottom is spaced.
self.bottomViewTopConstraint.constant = newSpace;
[self showFooter];
}
}
}
}
- (void)viewDidLoad {
[super viewDidLoad];
}
- (void)setUpHeaderAccessoryView {
UIView *headerAccessoryView = [[UIView alloc] initWithFrame:CGRectZero];
headerAccessoryView.translatesAutoresizingMaskIntoConstraints = NO;
self.headerAccessoryView = headerAccessoryView;
NSArray *accessoryViews = [self populateHeaderAccessoryView];
if (accessoryViews.count > 0) {
__block typeof(self) weakSelf = self;
[StackableViewController populateView:self.headerAccessoryView withUIArray:accessoryViews withSpacingBlock:^UIEdgeInsets(id _Nullable object) {
return [weakSelf spaceAroundUIObject:object];
}];
} else {
[NSLayoutConstraint constraintPinView:headerAccessoryView heightConstraint:YES heightConstant:0 widthConstraint:NO widthConstant:0];
}
}
- (nonnull NSArray <UIView *>*)populateHeaderAccessoryView {
return @[];
}
- (void)setUpFooterAccessoryView {
UIView *footerAccessoryView = [[UIView alloc] initWithFrame:CGRectZero];
footerAccessoryView.translatesAutoresizingMaskIntoConstraints = NO;
self.tableFooterAccessoryView = footerAccessoryView;
NSArray *accessoryViews = [self populateFooterAccessoryView];
if (accessoryViews.count > 0) {
__block typeof(self) weakSelf = self;
[StackableViewController populateView:self.tableFooterAccessoryView withUIArray:accessoryViews withSpacingBlock:^UIEdgeInsets(id _Nullable object) {
return [weakSelf spaceAroundUIObject:object];
}];
} else {
[NSLayoutConstraint constraintPinView:footerAccessoryView heightConstraint:YES heightConstant:0 widthConstraint:NO widthConstant:0];
}
}
- (nonnull NSArray <UIView *>*)populateFooterAccessoryView {
return @[];
}
- (void)createViewForHeader {
// Creates the header view.
UIView *header = [[UIView alloc] initWithFrame:CGRectZero];
header.translatesAutoresizingMaskIntoConstraints = NO;
UIView *topView = self.topView;
UIView *headerAccessoryView = self.headerAccessoryView;
[header addSubview:topView];
[header addSubview:headerAccessoryView];
// Sets up the constraints
if (headerAccessoryView) {
[NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[topView]-0-[headerAccessoryView]" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(topView,headerAccessoryView)]];
[NSLayoutConstraint constraintPinSubview:topView pinTop:YES topConstant:0 pinBottom:NO bottomConstant:0 pinLeft:YES leftConstant:0 pinRight:YES rightConstant:0];
self.topViewBottomConstraint = [[NSLayoutConstraint constraintPinSubview:headerAccessoryView pinTop:NO topConstant:0 pinBottom:YES bottomConstant:[[self spaceAboveBetweenView] floatValue] pinLeft:YES leftConstant:0 pinRight:YES rightConstant:0] objectForKey:ConstraintBot ofType:[NSLayoutConstraint class]];
}
else {
self.topViewBottomConstraint = [[NSLayoutConstraint constraintPinSubview:topView pinTop:YES topConstant:0 pinBottom:YES bottomConstant:[[self spaceAboveBetweenView] floatValue] pinLeft:YES leftConstant:0 pinRight:YES rightConstant:0] objectForKey:ConstraintBot ofType:[NSLayoutConstraint class]];
}
self.headerView = header;
}
- (void)createViewForFooter {
// Creates the footer view.
UIView *footer = [[UIView alloc] initWithFrame:CGRectZero];
footer.translatesAutoresizingMaskIntoConstraints = NO;
[footer addSubview:self.tableFooterAccessoryView];
[footer addSubview:self.bottomView];
self.bottomViewTopConstraint = [[NSLayoutConstraint constraintPinSubview:self.tableFooterAccessoryView pinTop:YES topConstant:0 pinBottom:NO bottomConstant:0 pinLeft:YES leftConstant:0 pinRight:YES rightConstant:0] objectForKey:ConstraintTop ofType:[NSLayoutConstraint class]];
[NSLayoutConstraint constraintPinSubview:self.bottomView pinTop:NO topConstant:0 pinBottom:YES bottomConstant:0 pinLeft:YES leftConstant:0 pinRight:YES rightConstant:0];
[NSLayoutConstraint constraintWithItem:self.bottomView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.tableFooterAccessoryView attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0].active = YES;
self.footerView = footer;
}
- (void)showHeader {
if (self.headerView) {
[self.headerView removeFromSuperview];
self.tableView.tableHeaderView = nil;
UIView *headerView = self.headerView;
UIView *tableHeader = [[UIView alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 0)];
[MVMCoreUIUtility sizeViewToFit:headerView];
CGRect frame = tableHeader.frame;
frame.size.height = CGRectGetHeight(headerView.frame);
tableHeader.frame = frame;
[tableHeader addSubview:headerView];
[NSLayoutConstraint constraintPinSubview:headerView pinTop:YES pinBottom:YES pinLeft:YES pinRight:YES];
self.tableView.tableHeaderView = tableHeader;
}
}
- (void)showFooter {
if (self.footerView) {
[self.footerView removeFromSuperview];
[self.safeAreaView removeFromSuperview];
if (self.bottomViewOutsideOfScroll) {
if (self.tableView.tableFooterView) {
self.tableView.tableFooterView.frame = CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 0);
}
self.bottomConstraint.active = NO;
// Bottom view will be outside of the scrolling view.
[self.view addSubview:self.footerView];
UITableView *tableView = self.tableView;
UIView *footerView = self.footerView;
NSLayoutConstraint *bottomViewTop = [NSLayoutConstraint constraintWithItem:footerView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:tableView attribute:NSLayoutAttributeBottom multiplier:1 constant:0];
bottomViewTop.active = YES;
NSLayoutConstraint *bottomViewBot = nil;
if (@available(iOS 11.0, *)) {
bottomViewBot = [self.view.safeAreaLayoutGuide.bottomAnchor constraintEqualToAnchor:footerView.bottomAnchor];
UIView *safeAreaView = [MVMCoreUICommonViewsUtility getAndSetupSafeAreaViewOnView:self.view];
safeAreaView.backgroundColor = footerView.backgroundColor;
self.safeAreaView = safeAreaView;
} else {
// Fallback on earlier versions
bottomViewBot = [NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:footerView attribute:NSLayoutAttributeBottom multiplier:1 constant:0];
}
bottomViewBot.priority = 900;
bottomViewBot.active = YES;
[NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[footerView]-0@900-|" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(footerView)]];
} else {
self.bottomConstraint.active = YES;
CGFloat y = 0;
//if footer already exists, use the same y location to avoid the strange animation
if (self.tableView.tableFooterView) {
y = self.tableView.tableFooterView.frame.origin.y;
}
UIView *tableFooter = [[UIView alloc] initWithFrame:CGRectMake(0, y, [UIScreen mainScreen].bounds.size.width, 0)];
[MVMCoreUIUtility sizeViewToFit:self.footerView];
CGRect frame = tableFooter.frame;
frame.size.height = CGRectGetHeight(self.footerView.frame);
tableFooter.frame = frame;
[tableFooter addSubview:self.footerView];
[NSLayoutConstraint constraintPinSubview:self.footerView pinTop:YES pinBottom:YES pinLeft:YES pinRight:YES];
self.tableView.tableFooterView = tableFooter;
}
}
}
- (void)hideHeader {
CGRect frame = CGRectZero;
frame.size.height = CGFLOAT_MIN;
self.tableView.tableHeaderView = [[UIView alloc] initWithFrame:frame];
[self.view layoutIfNeeded];
}
- (void)hideFooter {
[self.footerView removeFromSuperview];
[self.safeAreaView removeFromSuperview];
self.bottomConstraint.active = YES;
self.tableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 0, CGFLOAT_MIN)];
[self.view layoutIfNeeded];
}
#pragma mark - Can Subclass These
- (nonnull NSNumber *)spaceAboveBetweenView {
return @0;
}
- (BOOL)spaceBelowTopViewSetToFill {
return NO;
}
- (BOOL)spaceAboveBottomViewSetToFill {
return YES;
}
- (UIEdgeInsets)paddingForTopLabels {
return UIEdgeInsetsMake(PaddingFive, [MFStyler defaultHorizontalPaddingForApplicationWidth], PaddingDefaultVerticalSpacing, [MFStyler defaultHorizontalPaddingForApplicationWidth]);
}
- (UIEdgeInsets)paddingForBottomButtons {
return UIEdgeInsetsMake(PaddingDefaultVerticalSpacing, PaddingDefaultHorizontalSpacing, PaddingDefaultVerticalSpacing, PaddingDefaultHorizontalSpacing);
}
- (NSDictionary *)secondaryButtonMap {
NSDictionary *buttonMap = [self.loadObject.pageJSON dict:KeyButtonMap];
return [buttonMap dict:KeySecondaryButton];
}
- (NSDictionary *)primaryButtonMap {
NSDictionary *buttonMap = [self.loadObject.pageJSON dict:KeyButtonMap];
return [buttonMap dict:KeyPrimaryButton];
}
- (nullable NSDictionary *)mapForTopLabels {
return self.loadObject.pageJSON;
}
- (nullable UIView *)useCustomViewInsteadOfLabels {
return nil;
}
- (nullable UIView *)useCustomViewInsteadOfButtons {
return nil;
}
- (BOOL)bottomViewOutsideOfScroll {
return NO;
}
- (void)setPrimaryLeftButtonHidden:(BOOL)left rightButtonHidden:(BOOL)right {
if ([self.bottomView isKindOfClass:[PrimaryButtonView class]]) {
PrimaryButtonView *buttonView = (PrimaryButtonView *)self.bottomView;
if (right && !left) {
[buttonView hidePrimaryRightButton];
} else if (!right && left) {
[buttonView hidePrimaryLeftButton];
} else if (right && left) {
[buttonView hideBothPrimaryButtons];
} else if (!right && !left) {
[buttonView showBothPrimaryButtons];
}
}
}
#pragma mark - helper
- (UIEdgeInsets)spaceAroundUIObject:(nullable id)object {
CGFloat horizontal = [MFStyler defaultHorizontalPaddingForApplicationWidth];
return UIEdgeInsetsMake(PaddingDefault, horizontal, PaddingDefault, horizontal);
}
#pragma mark - ScrollView
-(void)scrollViewDidScroll:(UIScrollView *)scrollView {
// To stop handscroll animation if animating after scroll
[self stopHandScrollAnimation:YES];
}
- (void)dealloc {
[self.tableView setDelegate:nil];
}
#pragma mark - Animation
-(void)setupIntroAnimations {
if (self.topView.subviews.count) {
[self.introAnimationManager addAnimationWithAnimation:[MVMAnimations fadeUpAnimationWithView:self.topView]];
}
if (self.headerAccessoryView.subviews.count) {
[self.introAnimationManager addAnimationWithAnimation:[MVMAnimations fadeUpAnimationWithView:self.headerAccessoryView]];
}
[self.introAnimationManager addAnimationWithAnimation:[MVMAnimations animateTableViewFadeInCellsWithTableView:self.tableView]];
if (self.bottomView.subviews.count) {
[self.introAnimationManager addAnimationWithAnimation:[MVMAnimations fadeUpAnimationWithView:self.bottomView]];
}
}
@end

View File

@ -0,0 +1,76 @@
//
// TopLabelsAndBottomButtonsViewController.h
// myverizon
//
// Created by Scott Pfeil on 1/26/16.
// Copyright © 2016 Verizon Wireless. All rights reserved.
//
// Has top labels docked on top, buttons docked on bottom, and anything you'd like in between when subclassed.
#import <MVMCoreUI/StackableViewController.h>
#import <MVMCoreUI/ViewConstrainingView.h>
#import <MVMCoreUI/TopLabelsView.h>
@class LabelView;
@class PrimaryButton;
@interface TopLabelsAndBottomButtonsViewController : StackableViewController
@property (nullable, weak, nonatomic) TopLabelsView *topLabelsView;
@property (nullable, weak, nonatomic) PrimaryButton *primaryButton;
@property (nullable, weak, nonatomic) PrimaryButton *secondaryButton;
@property (nullable, weak, nonatomic, readonly) UIView *bottomView;
@property (nullable, weak, nonatomic, readonly) UIView *topView;
@property (nullable, weak, nonatomic) UIView *viewInScroll;
@property (nullable, weak, nonatomic) UIView *viewOutOfScroll;
@property (nullable, strong, nonatomic) UIView *safeAreaView;
// Set to overwrite which view is the top edge and/or bottom edge of the between view. must be added to the ui and constrained before buildViewsBetweenLabelsAndButtons.
// Use these to create views that are pinned near the labels or buttons and are separate from any centered content. Add and set in buildInAdditionalViewsBeforeCenteredContent.
@property (nullable, weak, nonatomic) UIView *topBetweenEdgeView;
@property (nullable, weak, nonatomic) UIView *bottomBetweenEdgeView;
// The constraint connecting the topLabelsView to the content view.
@property (nullable, strong, nonatomic) NSLayoutConstraint *topConstraintForTopView;
// Can override. This is put in because to cover 90% of the screens for initial ipad release, need to rebuild ui (newDataBuildScreen) of size of view change in updateViews. Disable this to handle manually with more finess.
@property (nonatomic) BOOL rebuildUIOnSizeChange;
#pragma mark - Subclass
// Allow you to add any additional ui before buildViewsBetweenLabelsAndButtons gets called. Can use this to set the topBetweenEdgeView or bottomBetweenEdgeView
- (void)buildInAdditionalViewsBeforeCenteredContent;
// For subclassing. Should return all the views that will be in between labels and buttons. Override standardSpaceAroundUIObject to handle spacing.
- (nullable NSArray <UIView *>*)buildViewsBetweenLabelsAndButtons;
//*********
// If both are subclassed to return a value, then the buttons will not be pinned towards the bottom.
// If anything is returned, the class will fill in the space between the top labels and views with the passed in value.
- (nullable NSNumber *)spaceAboveBetweenView;
// If anything is returned, the class will fill in the space between the views and bottom buttons with the passed in value.
- (nullable NSNumber *)spaceBelowBetweenView;
// Can overwrite the default padding for labels and buttons.
- (UIEdgeInsets)paddingForTopLabels;
- (UIEdgeInsets)paddingForBottomButtons;
// default button map will automatically get from response, you can also overide this to have your own button map
- (nullable NSDictionary *)secondaryButtonMap;
- (nullable NSDictionary *)primaryButtonMap;
// Should not sub class it, for most cases, the headline and message will be in page map, but who knows how server wants to send them in certain pages
- (nullable NSDictionary *)mapForTopLabels;
// Use these if you want to replace the top labels or bottom button views with your own views.
- (nullable UIView *)useCustomViewInsteadOfLabels;
- (nullable UIView *)useCustomViewInsteadOfButtons;
// Can override if the buttons should be outside of the scroll or not. Default is no.
- (BOOL)bottomViewOutsideOfScroll;
// Build above the button view
- (nullable UIView *)buttonsAccessoryView;
@end

View File

@ -0,0 +1,447 @@
//
// TopLabelsAndBottomButtonsViewController.m
// myverizon
//
// Created by Scott Pfeil on 1/26/16.
// Copyright © 2016 Verizon Wireless. All rights reserved.
//
#import "TopLabelsAndBottomButtonsViewController.h"
#import <MVMCoreUI/PrimaryButtonView.h>
#import <MVMCoreUI/MFSizeObject.h>
#import <MVMCoreUI/MVMCoreUICommonViewsUtility.h>
#import <MVMCoreUI/UIColor+MFConvenience.h>
#import <MVMCoreUI/NSLayoutConstraint+MFConvenience.h>
#import <MVMCoreUI/MVMCoreUIConstants.h>
#import <MVMCoreUI/MFStyler.h>
#import <MVMCore/NSDictionary+MFConvenience.h>
#import <MVMCore/MVMCoreLoadObject.h>
#import <MVMCore/MVMCoreJSONConstants.h>
#import <MVMCore/MVMCoreConstants.h>
@import MVMAnimationFramework;
@interface TopLabelsAndBottomButtonsViewController ()
@property (nullable, strong, nonatomic) NSLayoutConstraint *heightConstraint;
@property (nullable, weak, nonatomic) UIView *topView;
@property (nullable, weak, nonatomic) UIView *bottomView;
@property (nonatomic) BOOL customBottemView;
@property (nullable, weak, nonatomic) NSArray *middleViews;
@property (nullable, weak, nonatomic) UIView *betweenView;
@property (nullable, weak, nonatomic) ViewConstrainingView *bottomAccessoryView;
// Adds the button view to the screen. Out of the scroll or in.
- (void)addViewOutsideOfScrollView:(UIView *)bottomView;
- (void)addViewToContentView:(UIView *)bottomView;
@end
@implementation TopLabelsAndBottomButtonsViewController
- (void)initialLoad {
[super initialLoad];
self.rebuildUIOnSizeChange = YES;
}
- (void)updateViews {
[super updateViews];
if ([self screenSizeChanged]) {
if (self.rebuildUIOnSizeChange) {
// If the screen size changed.... just rebuild everything.... this will cover all sizes and help for ipad slide over.
[self newDataBuildScreen];
} else {
// Update top labels and bottom buttons.
CGFloat width = CGRectGetWidth(self.view.bounds);
if ([self.topView respondsToSelector:@selector(updateView:)]) {
[((UIView <MVMCoreViewProtocol>*)self.topView) updateView:width];
}
if ([self.bottomView respondsToSelector:@selector(updateView:)]) {
[((UIView <MVMCoreViewProtocol>*)self.bottomView) updateView:width];
}
[self updateTopLabelsBottomButtonsPadding];
[self.bottomAccessoryView updateView:width];
[self resetSpaceForFormArrayWithConstrainingViews];
}
}
}
- (void)updateTopLabelsBottomButtonsPadding {
if (self.topLabelsView) {
UIEdgeInsets paddingForTopLabels = [self paddingForTopLabels];
self.topLabelsView.topLabelConstraint.constant = paddingForTopLabels.top;
self.topLabelsView.bottomLabelConstraint.constant = paddingForTopLabels.bottom;
[self.topLabelsView setLeftConstant:paddingForTopLabels.left];
[self.topLabelsView setRightConstant:paddingForTopLabels.right];
}
if (!self.customBottemView) {
PrimaryButtonView *buttonView = (PrimaryButtonView *)self.bottomView;
if (self.secondaryButton || self.primaryButton) {
UIEdgeInsets paddingForBottomButtons = [self paddingForBottomButtons];
buttonView.leftPin.constant = paddingForBottomButtons.left;
buttonView.rightPin.constant = paddingForBottomButtons.right;
buttonView.topPin.constant = paddingForBottomButtons.top;
buttonView.bottomPin.constant = paddingForBottomButtons.bottom;
} else {
buttonView.topPin.constant = 0;
buttonView.bottomPin.constant = 0;
buttonView.leftPin.constant = 0;
buttonView.rightPin.constant = 0;
}
}
}
- (void)newDataBuildScreen {
[super newDataBuildScreen];
// Removes the bottom view out of scroll if it is there.
[self.viewOutOfScroll removeFromSuperview];
[StackableViewController removeUIViews:[self.contentView subviews]];
// Checks if we are using a different object than top labels.
UIView *topView = [self useCustomViewInsteadOfLabels];
self.topView = topView;
if (!topView) {
// Sets up the labels toward the top of the screen.
TopLabelsView *topLabelsView = [[TopLabelsView alloc] initWithFrame:CGRectZero];
topLabelsView.separatorView.hidden = NO;
self.topLabelsView = topLabelsView;
topView = topLabelsView;
self.topView = topView;
}
[self.contentView addSubview:topView];
[NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[topView]-0-|" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(topView)]];
self.topConstraintForTopView = [NSLayoutConstraint constraintWithItem:topView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeTop multiplier:1.0 constant:0];
self.topConstraintForTopView.active = YES;
// Checks if we are using a different object than the bottom buttons.
UIView *bottomView = [self useCustomViewInsteadOfButtons];
self.customBottemView = (bottomView != nil);
if (!self.customBottemView) {
// Sets up the buttons/button.
NSDictionary *primaryButtonDictionary = [self primaryButtonMap];
NSDictionary *secondaryButtonDictionary = [self secondaryButtonMap];
PrimaryButtonView *buttonView = [[PrimaryButtonView alloc] initWithPrimaryButtonMap:primaryButtonDictionary secondaryButtonMap:secondaryButtonDictionary actionDelegate:self additionalData:nil buttonDelegate:self];
self.secondaryButton = buttonView.secondaryButton;
self.primaryButton = buttonView.primaryButton;
bottomView = buttonView;
self.bottomView = bottomView;
} else {
self.bottomView = bottomView;
}
[self updateTopLabelsBottomButtonsPadding];
// Adds the bottom view outside the scroll if directed.
[self.safeAreaView removeFromSuperview];
if ([self bottomViewOutsideOfScroll]) {
if (!self.customBottemView) {
bottomView.backgroundColor = [UIColor mfBackgroundGray];
}
[self addViewOutsideOfScrollView:bottomView];
self.viewOutOfScroll = bottomView;
// Sets this so that the button view added to the content view will be empty.
bottomView = [ViewConstrainingView emptyView];
}
// Adds either the bottom view or a blank view inside the scroll.
self.viewInScroll = bottomView;
[self addViewToContentView:bottomView];
// Allows addition of any custom ui before custom center view.
[self buildInAdditionalViewsBeforeCenteredContent];
// Positions the views in between the labels and buttons.
UIView *viewBetween = nil;
NSArray *views = [self buildViewsBetweenLabelsAndButtons];
self.middleViews = views;
if (views.count > 0) {
viewBetween = [MVMCoreUICommonViewsUtility commonView];
[self generateFormView:viewBetween withUIArrayForConstrainingViews:views];
[self.contentView addSubview:viewBetween];
[NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[viewBetween]-0@900-|" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(viewBetween)]];
[viewBetween setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
}
self.betweenView = viewBetween;
// This whole section is for handling vertical spacing.
//-------------------------------------------------------------
UIView *topBetweenEdgeView = topView;
if (self.topBetweenEdgeView) {
topBetweenEdgeView = self.topBetweenEdgeView;
}
UIView *bottomBetweenEdgeView = bottomView;
if (self.bottomBetweenEdgeView) {
bottomBetweenEdgeView = self.bottomBetweenEdgeView;
}
// Sets the height so when there is not enough content, the bottom buttons will stay pinned. But if there is too much content, the constraint has low priority so the screen will scroll. Only made active in certain conditions.
NSLayoutConstraint *heightConstraint = [NSLayoutConstraint constraintWithItem:self.contentView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:self.scrollView attribute:NSLayoutAttributeHeight multiplier:1.0 constant:0];
heightConstraint.priority = UILayoutPriorityDefaultLow;
self.heightConstraint = heightConstraint;
if (viewBetween) {
// These spacer views are what causes the buttons to be pinned to the bottom.
NSNumber *spaceAbove = [self spaceAboveBetweenView];
NSNumber *spaceBelow = [self spaceBelowBetweenView];
if (spaceAbove && spaceBelow) {
// Both top and bottom space set, buttons not pinned to bottom.
NSDictionary *verticalMetrics = @{@"top":spaceAbove,@"bottom":spaceBelow};
[NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[topBetweenEdgeView]-top-[viewBetween]-bottom-[bottomBetweenEdgeView]" options:NSLayoutFormatDirectionLeadingToTrailing metrics:verticalMetrics views:NSDictionaryOfVariableBindings(topBetweenEdgeView,viewBetween,bottomBetweenEdgeView)]];
} else {
// Needs the height constraint
heightConstraint.active = YES;
if (!spaceAbove && !spaceBelow) {
// No set space above or below, make the spacers the same height with a default minimum.
UIView *topSpacer = [MVMCoreUICommonViewsUtility commonView];
UIView *bottomSpacer = [MVMCoreUICommonViewsUtility commonView];
[self.contentView addSubview:topSpacer];
[self.contentView addSubview:bottomSpacer];
[NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[topSpacer]-0-|" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(topSpacer)]];
[NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[bottomSpacer]-0-|" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(bottomSpacer)]];
NSLayoutConstraint *sameHeightSpacer = [NSLayoutConstraint constraintWithItem:topSpacer attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:bottomSpacer attribute:NSLayoutAttributeHeight multiplier:1.0 constant:0];
sameHeightSpacer.active = YES;
NSLayoutConstraint *minimumHeightSpacer = [NSLayoutConstraint constraintWithItem:topSpacer attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:PaddingDefaultVerticalSpacing];
minimumHeightSpacer.active = YES;
[NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[topBetweenEdgeView]-0-[topSpacer]-0-[viewBetween]-0-[bottomSpacer]-0-[bottomBetweenEdgeView]" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(topBetweenEdgeView,topSpacer,viewBetween,bottomSpacer,bottomBetweenEdgeView)]];
} else if (spaceAbove) {
// Space above is set, space below is free.
UIView *bottomSpacer = [MVMCoreUICommonViewsUtility commonView];
[self.contentView addSubview:bottomSpacer];
[NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[bottomSpacer]-0-|" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(bottomSpacer)]];
NSLayoutConstraint *bottomSpacerHeight = [NSLayoutConstraint constraintWithItem:bottomSpacer attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:PaddingDefaultVerticalSpacing];
bottomSpacerHeight.active = YES;
NSDictionary *verticalMetrics = @{@"top":spaceAbove};
[NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[topBetweenEdgeView]-top-[viewBetween]-0-[bottomSpacer]-0-[bottomBetweenEdgeView]" options:NSLayoutFormatDirectionLeadingToTrailing metrics:verticalMetrics views:NSDictionaryOfVariableBindings(topBetweenEdgeView,viewBetween,bottomSpacer,bottomBetweenEdgeView)]];
} else if (spaceBelow) {
// Space below is set, space above is free.
UIView *topSpacer = [MVMCoreUICommonViewsUtility commonView];
[self.contentView addSubview:topSpacer];
[NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[topSpacer]-0-|" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(topSpacer)]];
NSLayoutConstraint *topSpacerHeight = [NSLayoutConstraint constraintWithItem:topSpacer attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:PaddingDefaultVerticalSpacing];
topSpacerHeight.active = YES;
NSDictionary *verticalMetrics = @{@"bottom":spaceBelow};
[NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[topBetweenEdgeView]-0-[topSpacer]-0-[viewBetween]-bottom-[bottomBetweenEdgeView]" options:NSLayoutFormatDirectionLeadingToTrailing metrics:verticalMetrics views:NSDictionaryOfVariableBindings(topBetweenEdgeView,topSpacer,viewBetween,bottomBetweenEdgeView)]];
}
}
} else {
// No views in between. Just messages and buttons
UIView *spacer = [MVMCoreUICommonViewsUtility commonView];
[self.contentView addSubview:spacer];
[NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[spacer]-0-|" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(spacer)]];
// Needs the height constraint
heightConstraint.active = YES;
[NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[topBetweenEdgeView]-0-[spacer]-0-[bottomBetweenEdgeView]" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(topBetweenEdgeView,spacer,bottomBetweenEdgeView)]];
}
if (self.topLabelsView) {
[self.topLabelsView setHeadlineString:[[self mapForTopLabels] stringForKey:KeyTitle] messageString:[[self mapForTopLabels] stringForKey:KeyMessage]];
}
}
- (void)updateViewConstraints {
[super updateViewConstraints];
// Updates for ios 11
if (@available(iOS 11.0, *)) {
if (self.scrollView.contentInsetAdjustmentBehavior == UIScrollViewContentInsetAdjustmentAutomatic) {
self.heightConstraint.constant = -self.scrollView.adjustedContentInset.top - self.scrollView.adjustedContentInset.bottom;
} else {
self.heightConstraint.constant = -self.scrollView.contentInset.top - self.scrollView.contentInset.bottom;
}
} else {
self.heightConstraint.constant = -self.scrollView.contentInset.top - self.scrollView.contentInset.bottom;
}
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (UIEdgeInsets)spaceAroundUIObject:(nullable id)object {
CGFloat horizontal = [MFStyler defaultHorizontalPaddingForApplicationWidth];
if (self.bottomAccessoryView == object) {
return UIEdgeInsetsMake(0, horizontal, PaddingDefaultVerticalSpacing, horizontal);
}
return UIEdgeInsetsMake(0, horizontal, 0, horizontal);
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)addViewToContentView:(UIView *)bottomView {
self.bottomConstraint.active = YES;
// Buttons will be at the bottom of the content view.
[self.contentView addSubview:bottomView];
[NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[bottomView]-0-|" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(bottomView)]];
[NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[bottomView]-0@900-|" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(bottomView)]];
}
- (void)addViewOutsideOfScrollView:(UIView *)bottomView {
self.bottomConstraint.active = NO;
// Buttons will be outside of the scrolling view.
[self.view addSubview:bottomView];
UIScrollView *scrollview = self.scrollView;
if (@available(iOS 11.0, *)) {
[NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[scrollview]-0-[bottomView]" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(scrollview,bottomView)]];
[self.view.safeAreaLayoutGuide.bottomAnchor constraintEqualToAnchor:bottomView.bottomAnchor].active = YES;
UIView *safeAreaView = [MVMCoreUICommonViewsUtility getAndSetupSafeAreaViewOnView:self.view];
safeAreaView.backgroundColor = bottomView.backgroundColor;
self.safeAreaView = safeAreaView;
} else {
// Fallback on earlier versions
[NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[scrollview]-0-[bottomView]-0-|" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(scrollview,bottomView)]];
}
[NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[bottomView]-0@900-|" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(bottomView)]];
}
#pragma mark - Can Subclass These
- (nullable UIView *)buttonsAccessoryView {
return nil;
}
- (void)buildInAdditionalViewsBeforeCenteredContent {
UIView *accessoryView = [self buttonsAccessoryView];
if (accessoryView) {
accessoryView.translatesAutoresizingMaskIntoConstraints = NO;
ViewConstrainingView *constrainingView = [ViewConstrainingView viewConstrainingView:accessoryView];
constrainingView.updateViewHorizontalDefaults = YES;
[self.contentView addSubview:constrainingView];
self.bottomBetweenEdgeView = constrainingView;
self.bottomAccessoryView = constrainingView;
[constrainingView setPinConstantsWithInsets:[self spaceAroundUIObject:constrainingView]];
[NSLayoutConstraint constraintPinLeftSubview:constrainingView leftConstant:0];
[NSLayoutConstraint constraintPinRightSubview:constrainingView rightConstant:0];
[NSLayoutConstraint constraintPinFirstView:constrainingView toSecondView:self.viewInScroll
withConstant:0 directionVertical:YES];
} else {
self.bottomAccessoryView = nil;
}
}
- (nullable NSArray <UIView *>*)buildViewsBetweenLabelsAndButtons {
return nil;
}
- (nullable NSNumber *)spaceAboveBetweenView {
return nil;
}
- (nullable NSNumber *)spaceBelowBetweenView {
return nil;
}
- (UIEdgeInsets)paddingForTopLabels {
return UIEdgeInsetsMake(PaddingFive, [MFStyler defaultHorizontalPaddingForApplicationWidth], PaddingDefaultVerticalSpacing, [MFStyler defaultHorizontalPaddingForApplicationWidth]);
}
- (UIEdgeInsets)paddingForBottomButtons {
// Smaller space for smaller devices. Also, top is 0 by default when in scroll.
CGFloat verticalSpacing = [[MFSizeObject sizeObjectWithStandardSize:PaddingDefaultVerticalSpacing smalliPhoneSize:PaddingDefault] getValueBasedOnScreenSize];
return UIEdgeInsetsMake(([self bottomViewOutsideOfScroll] ? verticalSpacing : 0), PaddingDefaultHorizontalSpacing, verticalSpacing, PaddingDefaultHorizontalSpacing);
}
- (NSDictionary*)primaryButtonMap {
NSDictionary *buttonMap = [self.loadObject.pageJSON dict:KeyButtonMap];
return [buttonMap dict:KeyPrimaryButton];
}
- (NSDictionary*)secondaryButtonMap {
NSDictionary *buttonMap = [self.loadObject.pageJSON dict:KeyButtonMap];
return [buttonMap dict:KeySecondaryButton];
}
- (nullable NSDictionary *)mapForTopLabels {
return self.loadObject.pageJSON;
}
- (nullable UIView *)useCustomViewInsteadOfLabels {
return nil;
}
- (nullable UIView *)useCustomViewInsteadOfButtons {
return nil;
}
- (BOOL)bottomViewOutsideOfScroll {
return NO;
}
#pragma mark - Animations
-(void)setupIntroAnimations {
if (self.topView.subviews) {
[self.introAnimationManager addAnimationWithAnimation:[MVMAnimations fadeUpAnimationWithView:self.topView]];
}
if (self.topBetweenEdgeView.subviews.count) {
[self.introAnimationManager addAnimationWithAnimation:[MVMAnimations fadeUpAnimationWithView:self.topBetweenEdgeView]];
}
// NSMutableArray *centerAnimationObjects = [NSMutableArray new];
// for (int i = 0; i < self.middleViews.count; i++) {
// MVMAnimationObject *aobj =[MVMAnimations fadeUpAnimationWithView:self.middleViews[i]];
// [centerAnimationObjects addObject:aobj];
// }
// [self.introAnimationManager addAnimationGroupWithAnimations:centerAnimationObjects];
[self.introAnimationManager addAnimationWithAnimation:[MVMAnimations fadeUpAnimationWithView:self.betweenView]];
if (self.bottomBetweenEdgeView.subviews.count) {
[self.introAnimationManager addAnimationWithAnimation:[MVMAnimations fadeUpAnimationWithView:self.bottomBetweenEdgeView]];
}
if (self.bottomView.subviews) {
[self.introAnimationManager addAnimationWithAnimation:[MVMAnimations fadeUpAnimationWithView:self.bottomView]];
}
}
@end

View File

@ -26,6 +26,7 @@ FOUNDATION_EXPORT const unsigned char MVMCoreUIVersionString[];
#pragma mark - OtherHandlers
#import <MVMCoreUI/MVMCoreUILoggingHandler.h>
#import <MVMCoreUI/MVMCoreUIViewControllerMappingObject.h>
#pragma mark - Categories
#import <MVMCoreUI/NSLayoutConstraint+MFConvenience.h>
@ -49,6 +50,8 @@ FOUNDATION_EXPORT const unsigned char MVMCoreUIVersionString[];
#import <MVMCoreUI/MFProgrammaticTableViewController.h>
#import <MVMCoreUI/StackableViewController.h>
#import <MVMCoreUI/MFLoadingViewController.h>
#import <MVMCoreUI/TopLabelsAndBottomButtonsViewController.h>
#import <MVMCoreUI/TopLabelsAndBottomButtonsTableViewController.h>
#pragma mark - Containers
#import <MVMCoreUI/MVMCoreUIPanelProtocol.h>
@ -63,6 +66,7 @@ FOUNDATION_EXPORT const unsigned char MVMCoreUIVersionString[];
#pragma mark Views
#import <MVMCoreUI/MFView.h>
#import <MVMCoreUI/MFLabel.h>
#import <MVMCoreUI/LabelWithInternalButton.h>
#import <MVMCoreUI/ViewConstrainingView.h>
#import <MVMCoreUI/MFTransparentGIFView.h>
#import <MVMCoreUI/MFLoadImageView.h>
@ -73,6 +77,7 @@ FOUNDATION_EXPORT const unsigned char MVMCoreUIVersionString[];
#import <MVMCoreUI/LabelView.h>
#import <MVMCoreUI/TextButtonView.h>
#import <MVMCoreUI/DashLine.h>
#import <MVMCoreUI/TextFieldView.h>
#pragma mark Buttons
#import <MVMCoreUI/MFButtonProtocol.h>
@ -92,3 +97,10 @@ FOUNDATION_EXPORT const unsigned char MVMCoreUIVersionString[];
#pragma mark - Third Party
#import <MVMCoreUI/FLAnimatedImageView.h>
#import <MVMCoreUI/FLAnimatedImage.h>
#pragma mark - Molecules
#import <MVMCoreUI/TopLabelsView.h>
#import <MVMCoreUI/PrimaryButtonView.h>
#pragma mark - Templates
#import <MVMCoreUI/MVMCoreUILargeHeaderSingleLabelTemplate.h>

View File

@ -0,0 +1,53 @@
//
// PrimaryButtonView.h
// myverizon
//
// Created by Scott Pfeil on 12/11/15.
// Copyright © 2015 Verizon Wireless. All rights reserved.
//
#import <UIKit/UIKit.h>
#import <MVMCoreUI/ViewConstrainingView.h>
#import <MVMCoreUI/PrimaryButton.h>
@interface PrimaryButtonView : ViewConstrainingView
// Set when there is one button or it is the right button when there are two.
@property (nullable, weak, nonatomic) PrimaryButton *primaryButton;
// The left button when there are two buttons.
@property (nullable, weak, nonatomic) PrimaryButton *secondaryButton;
// Inits with a single button.
- (nonnull instancetype)initButtonSmall:(BOOL)small enabled:(BOOL)enabled;
// Inits with two buttons.
- (nonnull instancetype)initWithTwoButtons;
// Inits with whatever is in the passed in button map. (could be 0, 1, or 2 buttons)
- (nonnull instancetype)initButtonSmall:(BOOL)small buttonMap:(nullable NSDictionary *)buttonMap actionDelegate:(nullable NSObject <MVMCoreActionDelegateProtocol>*)actionDelegate additionalData:(nullable NSDictionary *)additionalData buttonDelegate:(nullable id <ButtonDelegateProtocol>)buttonDelegate;
- (nonnull instancetype)initWithPrimaryButtonMap:(nullable NSDictionary *)primaryButtonMap secondaryButtonMap:(nullable NSDictionary *)secondaryButtonMap actionDelegate:(nullable NSObject <MVMCoreActionDelegateProtocol>*)actionDelegate additionalData:(nullable NSDictionary *)additionalData buttonDelegate:(nullable id <ButtonDelegateProtocol>)buttonDelegate;
// Sets up with whatever is in the passed in button map. (could be 0, 1, or 2 buttons)
- (void)setupWithButtonMap:(nullable NSDictionary *)buttonMap actionDelegate:(nullable NSObject <MVMCoreActionDelegateProtocol>*)actionDelegate additionalData:(nullable NSDictionary *)additionalData buttonDelegate:(nullable id <ButtonDelegateProtocol>)buttonDelegate;
- (void)setupWithPrimaryButtonMap:(nullable NSDictionary *)primaryButtonMap secondaryButtonMap:(nullable NSDictionary *)secondaryButtonMap actionDelegate:(nullable NSObject <MVMCoreActionDelegateProtocol>*)actionDelegate additionalData:(nullable NSDictionary *)additionalData buttonDelegate:(nullable id <ButtonDelegateProtocol>)buttonDelegate;
// Sets up with two buttons.
- (void)setupWithTwoButtons;
// For subclassing, just returns the button.
- (nonnull id)createButton;
// Change the alignment of the button
- (void)alignLeft;
- (void)alignCenter;
- (void)alignRight;
- (void)alignFill;//default behavior
// Show/hide left and right primary buttons. This does not impact the vertical space of the view.
- (void)hidePrimaryLeftButton;
- (void)hidePrimaryRightButton;
- (void)showBothPrimaryButtons;
- (void)hideBothPrimaryButtons;
@end

View File

@ -0,0 +1,329 @@
//
// PrimaryButtonView.m
// myverizon
//
// Created by Scott Pfeil on 12/11/15.
// Copyright © 2015 Verizon Wireless. All rights reserved.
//
#import "PrimaryButtonView.h"
#import <MVMCore/NSDictionary+MFConvenience.h>
#import <MVMCore/MVMCoreDispatchUtility.h>
#import <MVMCore/MVMCoreJSONConstants.h>
#import "MVMCoreUICommonViewsUtility.h"
#import "MVMCoreUIConstants.h"
@interface PrimaryButtonView ()
@property (weak, nonatomic) UIView *twoButtonView;
@property (weak, nonatomic) NSLayoutConstraint *alignCenterPin;
@property (weak, nonatomic) NSLayoutConstraint *alignCenterLeftPin;
@property (weak, nonatomic) NSLayoutConstraint *alignCenterRightPin;
@property (weak, nonatomic) NSLayoutConstraint *height;
@property (nonatomic, strong) NSArray<NSLayoutConstraint *> *horizontalConstraints;
@end
@implementation PrimaryButtonView
- (instancetype)init {
if (self = [super init]) {
self.backgroundColor = [UIColor clearColor];
self.translatesAutoresizingMaskIntoConstraints = NO;
[self setupWithSingleButton];
}
return self;
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
if (self = [super initWithCoder:aDecoder]) {
self.backgroundColor = [UIColor clearColor];
self.translatesAutoresizingMaskIntoConstraints = NO;
[self setupWithSingleButton];
}
return self;
}
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
self.backgroundColor = [UIColor clearColor];
self.translatesAutoresizingMaskIntoConstraints = NO;
[self setupWithSingleButton];
}
return self;
}
- (nonnull instancetype)initButtonSmall:(BOOL)small enabled:(BOOL)enabled {
if (self = [self init]) {
[self.primaryButton setAsSmallButton:small];
[self.primaryButton setEnabled:enabled];
}
return self;
}
- (nonnull instancetype)initWithTwoButtons {
if (self = [self init]) {
[self setupWithTwoButtons];
}
return self;
}
- (nonnull instancetype)initButtonSmall:(BOOL)small buttonMap:(nullable NSDictionary *)buttonMap actionDelegate:(nullable NSObject <MVMCoreActionDelegateProtocol>*)actionDelegate additionalData:(nullable NSDictionary *)additionalData buttonDelegate:(nullable id <ButtonDelegateProtocol>)buttonDelegate {
if (self = [self init]) {
[self setupWithButtonMap:buttonMap actionDelegate:actionDelegate additionalData:additionalData buttonDelegate:buttonDelegate];
[self.primaryButton setAsSmallButton:small];
[self.secondaryButton setAsSmallButton:small];
}
return self;
}
- (nonnull instancetype)initWithPrimaryButtonMap:(nullable NSDictionary *)primaryButtonMap secondaryButtonMap:(nullable NSDictionary *)secondaryButtonMap actionDelegate:(nullable NSObject <MVMCoreActionDelegateProtocol>*)actionDelegate additionalData:(nullable NSDictionary *)additionalData buttonDelegate:(nullable id <ButtonDelegateProtocol>)buttonDelegate {
if (self = [self init]) {
[self setupWithPrimaryButtonMap:primaryButtonMap secondaryButtonMap:secondaryButtonMap actionDelegate:actionDelegate additionalData:additionalData buttonDelegate:buttonDelegate];
}
return self;
}
- (void)setupWithButtonMap:(nullable NSDictionary *)buttonMap actionDelegate:(nullable NSObject <MVMCoreActionDelegateProtocol>*)actionDelegate additionalData:(nullable NSDictionary *)additionalData buttonDelegate:(nullable id <ButtonDelegateProtocol>)buttonDelegate {
NSDictionary *secondaryButtonMap = [buttonMap dict:KeySecondaryButton];
NSDictionary *primaryButtonMap = [buttonMap dict:KeyPrimaryButton];
[self setupWithPrimaryButtonMap:primaryButtonMap secondaryButtonMap:secondaryButtonMap actionDelegate:actionDelegate additionalData:additionalData buttonDelegate:buttonDelegate];
}
- (void)setupWithPrimaryButtonMap:(nullable NSDictionary *)primaryButtonMap secondaryButtonMap:(nullable NSDictionary *)secondaryButtonMap actionDelegate:(nullable NSObject <MVMCoreActionDelegateProtocol>*)actionDelegate additionalData:(nullable NSDictionary *)additionalData buttonDelegate:(nullable id <ButtonDelegateProtocol>)buttonDelegate {
if (primaryButtonMap && secondaryButtonMap) {
self.height.active = NO;
// Setup with two buttons
if (!self.primaryButton || !self.secondaryButton) {
[self removeSubviews];
self.twoButtonView = nil;
[self setupWithTwoButtons];
}
[self.primaryButton setWithActionMap:primaryButtonMap actionDelegate:actionDelegate additionalData:additionalData buttonDelegate:buttonDelegate];
[self.secondaryButton setWithActionMap:secondaryButtonMap actionDelegate:actionDelegate additionalData:additionalData buttonDelegate:buttonDelegate];
} else if (primaryButtonMap || secondaryButtonMap) {
self.height.active = NO;
// Setup with one button.
if (!self.primaryButton || self.secondaryButton) {
[self removeSubviews];
self.primaryButton = nil;
self.secondaryButton = nil;
[self setupWithSingleButton];
}
[self alignCenter];
if (primaryButtonMap) {
// Only primary button
[self.primaryButton setWithActionMap:primaryButtonMap actionDelegate:actionDelegate additionalData:additionalData buttonDelegate:buttonDelegate];
self.primaryButton.bordered = NO;
} else {
// Only secondary button
[self.primaryButton setWithActionMap:secondaryButtonMap actionDelegate:actionDelegate additionalData:additionalData buttonDelegate:buttonDelegate];
self.primaryButton.bordered = YES;
}
} else {
[self removeSubviews];
if (!self.height) {
NSLayoutConstraint *height = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:0];
height.active = YES;
self.height = height;
}
}
}
- (id)createButton {
return [PrimaryButton primaryButton:NO];
}
- (void)setupWithTwoButtons {
if (self.primaryButton) {
[self.primaryButton removeFromSuperview];
self.primaryButton = nil;
}
if (!self.twoButtonView) {
self.backgroundColor = [UIColor clearColor];
self.translatesAutoresizingMaskIntoConstraints = NO;
UIView *buttonView = [MVMCoreUICommonViewsUtility commonView];
PrimaryButton *leftButton = [PrimaryButton primaryButton];
leftButton.bordered = YES;
leftButton.translatesAutoresizingMaskIntoConstraints = NO;
[buttonView addSubview:leftButton];
self.secondaryButton = leftButton;
PrimaryButton *rightButton = [PrimaryButton primaryButton];
rightButton.translatesAutoresizingMaskIntoConstraints = NO;
[buttonView addSubview:rightButton];
self.primaryButton = rightButton;
[rightButton.widthAnchor constraintEqualToAnchor:leftButton.widthAnchor multiplier:1].active = YES;
[NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[leftButton]-0-|" options:NSLayoutFormatAlignAllCenterY metrics:nil views:NSDictionaryOfVariableBindings(leftButton)]];
[NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[rightButton]-0-|" options:NSLayoutFormatAlignAllCenterY metrics:nil views:NSDictionaryOfVariableBindings(rightButton)]];
self.horizontalConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[leftButton]-10-[rightButton]-0-|" options:NSLayoutFormatAlignAllCenterY metrics:nil views:NSDictionaryOfVariableBindings(leftButton,rightButton)];
[NSLayoutConstraint activateConstraints:self.horizontalConstraints];
[self addSubview:buttonView];
[self setupAlignmentsWithView:buttonView];
self.twoButtonView = buttonView;
[self alignCenter];
}
}
- (void)setupWithSingleButton {
if (!self.primaryButton) {
self.backgroundColor = [UIColor clearColor];
self.translatesAutoresizingMaskIntoConstraints = NO;
PrimaryButton *button = [self createButton];
button.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:button];
self.primaryButton = button;
[self setupAlignmentsWithView:button];
[self alignCenter];
}
}
- (void)setupAlignmentsWithView:(UIView *)view {
// Align left and right constants.
NSLayoutConstraint *leftPin = [NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeft multiplier:1.0 constant:0];
self.leftPin = leftPin;
leftPin.active = YES;
NSLayoutConstraint *topPin = [NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTop multiplier:1.0 constant:0];
self.topPin = topPin;
topPin.active = YES;
NSLayoutConstraint *bottomPin = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:view attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0];
self.bottomPin = bottomPin;
bottomPin.active = YES;
NSLayoutConstraint *rightPin = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:view attribute:NSLayoutAttributeRight multiplier:1.0 constant:0];
self.rightPin = rightPin;
rightPin.active = YES;
// Center alignments
NSLayoutConstraint *alignCenter = [NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0];
self.alignCenterPin = alignCenter;
alignCenter.active = YES;
NSLayoutConstraint *centerLeftPin = [NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:self attribute:NSLayoutAttributeLeft multiplier:1.0 constant:0];
self.alignCenterLeftPin = centerLeftPin;
centerLeftPin.active = YES;
NSLayoutConstraint *centerRightPin = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:view attribute:NSLayoutAttributeRight multiplier:1.0 constant:0];
self.alignCenterRightPin = centerRightPin;
centerRightPin.active = YES;
}
- (void)updateView:(CGFloat)size {
[super updateView:size];
[MVMCoreDispatchUtility performBlockOnMainThread:^{
[self.primaryButton updateView:size];
[self.secondaryButton updateView:size];
}];
}
- (void)alignLeft {
self.alignCenterPin.active = NO;
self.alignCenterLeftPin.active = NO;
self.alignCenterRightPin.active = YES;
self.leftPin.active = YES;
self.rightPin.active = NO;
}
- (void)alignCenter {
self.alignCenterPin.active = YES;
self.alignCenterLeftPin.active = YES;
self.alignCenterRightPin.active = YES;
self.leftPin.active = NO;
self.rightPin.active = NO;
}
- (void)alignFill {
self.alignCenterPin.active = NO;
self.alignCenterLeftPin.active = NO;
self.alignCenterRightPin.active = NO;
self.leftPin.active = YES;
self.rightPin.active = YES;
}
- (void)alignRight {
self.alignCenterPin.active = NO;
self.alignCenterLeftPin.active = YES;
self.alignCenterRightPin.active = NO;
self.leftPin.active = NO;
self.rightPin.active = YES;
}
- (void)setLeftPinConstant:(CGFloat)constant {
[super setLeftPinConstant:constant];
self.alignCenterLeftPin.constant = constant;
}
- (void)setRightPinConstant:(CGFloat)constant {
[super setRightPinConstant:constant];
self.alignCenterRightPin.constant = constant;
}
- (void)resetConstraints {
[super resetConstraints];
self.primaryButton.enabled = NO;
}
- (void)hidePrimaryLeftButton {
if (!self.secondaryButton.hidden) {
self.secondaryButton.hidden = YES;
PrimaryButton *rightButton = self.primaryButton;
[NSLayoutConstraint deactivateConstraints:self.horizontalConstraints];
self.horizontalConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[rightButton]-0-|" options:NSLayoutFormatAlignAllCenterY metrics:nil views:NSDictionaryOfVariableBindings(rightButton)];
[NSLayoutConstraint activateConstraints:self.horizontalConstraints];
}
}
- (void)hidePrimaryRightButton {
if (!self.primaryButton.hidden) {
self.primaryButton.hidden = YES;
PrimaryButton *leftButton = self.secondaryButton;
[NSLayoutConstraint deactivateConstraints:self.horizontalConstraints];
self.horizontalConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[leftButton]-0-|" options:NSLayoutFormatAlignAllCenterY metrics:nil views:NSDictionaryOfVariableBindings(leftButton)];
[NSLayoutConstraint activateConstraints:self.horizontalConstraints];
}
}
- (void)showBothPrimaryButtons {
self.primaryButton.hidden = NO;
self.secondaryButton.hidden = NO;
PrimaryButton *rightButton = self.primaryButton;
PrimaryButton *leftButton = self.secondaryButton;
[NSLayoutConstraint deactivateConstraints:self.horizontalConstraints];
self.horizontalConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[leftButton]-10-[rightButton]-0-|" options:NSLayoutFormatAlignAllCenterY metrics:nil views:NSDictionaryOfVariableBindings(leftButton,rightButton)];
[NSLayoutConstraint activateConstraints:self.horizontalConstraints];
}
- (void)hideBothPrimaryButtons {
self.primaryButton.hidden = YES;
self.secondaryButton.hidden = YES;
}
- (void)removeSubviews {
for (UIView *view in self.subviews) {
[view removeFromSuperview];
}
}
@end

View File

@ -0,0 +1,53 @@
//
// TopLabelsView.h
// mobilefirst
//
// Created by Scott Pfeil on 2/24/16.
// Copyright © 2016 Verizon Wireless. All rights reserved.
//
#import <UIKit/UIKit.h>
#import <MVMCoreUI/MFView.h>
#import <MVMCoreUI/MFLabel.h>
#import <MVMCoreUI/SeparatorView.h>
@class TopLabelsAndBottomButtonsTableViewController;
@interface TopLabelsView : MFView
@property (nullable, weak, nonatomic) MFLabel *headlineLabel;
@property (nullable, weak, nonatomic) MFLabel *messageLabel;
@property (nullable, strong, nonatomic) NSLayoutConstraint *topLabelConstraint;
@property (nullable, weak, nonatomic) NSLayoutConstraint *spaceBetweenLabels;
@property (nullable, weak, nonatomic) NSLayoutConstraint *bottomLabelConstraint;
@property (nullable, weak, nonatomic) TopLabelsAndBottomButtonsTableViewController *tableView;
@property (nullable, strong, nonatomic) SeparatorView *separatorView;//hidden by default
// Use this when using this class as the header in top labels and bottom buttons table view controller. The header has to be set a certain way.
- (nullable instancetype)initWithTableView:(nullable TopLabelsAndBottomButtonsTableViewController *)tableView;
// Shows and hides the top labels.
- (void)showTopLabels;
- (void)hideTopLabels;
- (void)hideBottomLabels;
// Setter for message label
- (void)setMessageString:(nullable NSString *)messageString;
- (void)setMessageAttributedString:(nullable NSAttributedString *)messageString;
// Will adjust spacing as needed.
- (void)setHeadlineString:(nullable NSString *)headlineString messageString:(nullable NSString *)messageString;
- (void)setHeadlineAttributedString:(nullable NSAttributedString *)headlineString messageAttributedString:(nullable NSAttributedString *)messageString;
- (void)setAsLargeHeadline;
// Common styles (make sure to call them after newDataBuildScreen), IMPORTANT: seems most of the screens canceled this style.
- (void)styleMessageLabelBold;
- (void)setLeftConstant:(CGFloat)leftConstant;
- (void)setRightConstant:(CGFloat)rightConstant;
@end

View File

@ -0,0 +1,220 @@
//
// TopLabelsView.m
// mobilefirst
//
// Created by Scott Pfeil on 2/24/16.
// Copyright © 2016 Verizon Wireless. All rights reserved.
//
#import "TopLabelsView.h"
#import "TopLabelsAndBottomButtonsTableViewController.h"
#import <MVMCoreUI/MFSizeObject.h>
#import <MVMCoreUI/MFFonts.h>
#import <MVMCore/MVMCoreDispatchUtility.h>
#import <MVMCoreUI/MFStyler.h>
#import <MVMCore/MVMCoreConstants.h>
#import <MVMCoreUI/NSLayoutConstraint+MFConvenience.h>
@interface TopLabelsView ()
@property (nullable, weak, nonatomic) NSLayoutConstraint *leftConstraintTitle;
@property (nullable, weak, nonatomic) NSLayoutConstraint *rightConstraintTitle;
@property (nullable, weak, nonatomic) NSLayoutConstraint *leftConstraintMessage;
@property (nullable, weak, nonatomic) NSLayoutConstraint *rightConstraintMessage;
@property (nullable, weak, nonatomic) NSLayoutConstraint *leftConstraintSeparator;
@property (nullable, weak, nonatomic) NSLayoutConstraint *rightConstraintSeparator;
@property (nullable, strong, nonatomic) NSLayoutConstraint *heightConstraint;
@end
@implementation TopLabelsView
- (nullable instancetype)initWithTableView:(nullable TopLabelsAndBottomButtonsTableViewController *)tableView {
if (self = [super init]) {
self.tableView = tableView;
}
return self;
}
- (void)updateView:(CGFloat)size {
[super updateView:size];
[MVMCoreDispatchUtility performBlockOnMainThread:^{
[self.headlineLabel updateView:size];
[self.messageLabel updateView:size];
[self.separatorView setLeftAndRightPinConstant:[MFStyler defaultHorizontalPaddingForSize:size]];
}];
}
- (void)setupView {
[super setupView];
self.translatesAutoresizingMaskIntoConstraints = NO;
self.backgroundColor = [UIColor clearColor];
self.clipsToBounds = YES;
[self.headlineLabel removeFromSuperview];
MFLabel *headlineLabel = [MFLabel commonLabelH2:YES];
[self addSubview:headlineLabel];
self.headlineLabel = headlineLabel;
[self.messageLabel removeFromSuperview];
MFLabel *messageLabel = [MFLabel commonLabelB2:YES];
[self addSubview:messageLabel];
self.messageLabel = messageLabel;
[headlineLabel setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
[messageLabel setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
[self setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
NSLayoutConstraint *topLabelConstraint = [NSLayoutConstraint constraintWithItem:headlineLabel attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTop multiplier:1.0 constant:PaddingFive];
topLabelConstraint.priority = 999;
topLabelConstraint.active = YES;
self.topLabelConstraint = topLabelConstraint;
self.spaceBetweenLabels = [NSLayoutConstraint constraintWithItem:messageLabel attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:headlineLabel attribute:NSLayoutAttributeBottom multiplier:1.0 constant:PaddingTwo];
self.spaceBetweenLabels.active = YES;
NSLayoutConstraint *leftConstraint = [NSLayoutConstraint constraintWithItem:headlineLabel attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeft multiplier:1.0 constant:[MFStyler defaultHorizontalPaddingForApplicationWidth]];
leftConstraint.active = YES;
self.leftConstraintTitle = leftConstraint;
NSLayoutConstraint *rightConstraint = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:headlineLabel attribute:NSLayoutAttributeRight multiplier:1.0 constant:[MFStyler defaultHorizontalPaddingForApplicationWidth]];
rightConstraint.priority = 900;
rightConstraint.active = YES;
self.rightConstraintTitle = rightConstraint;
NSLayoutConstraint *leftConstraintMessage = [NSLayoutConstraint constraintWithItem:messageLabel attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeft multiplier:1.0 constant:[MFStyler defaultHorizontalPaddingForApplicationWidth]];
leftConstraintMessage.active = YES;
self.leftConstraintMessage = leftConstraintMessage;
NSLayoutConstraint *rightConstraintMessage = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:messageLabel attribute:NSLayoutAttributeRight multiplier:1.0 constant:[MFStyler defaultHorizontalPaddingForApplicationWidth]];
rightConstraintMessage.priority = 900;
rightConstraintMessage.active = YES;
self.rightConstraintMessage = rightConstraintMessage;
NSLayoutConstraint *bottomLabelConstraint = [self.bottomAnchor constraintEqualToAnchor:messageLabel.bottomAnchor constant:PaddingDefaultVerticalSpacing];
bottomLabelConstraint.active = YES;
self.bottomLabelConstraint = bottomLabelConstraint;
NSLayoutConstraint *heightConstraint = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.f constant:0];
heightConstraint.priority = 950;
self.heightConstraint = heightConstraint;
[self.separatorView removeFromSuperview];
SeparatorView *separatorView = [SeparatorView separatorAddToView:self position:SeparatorPositionBot withHorizontalPadding:[MFStyler defaultHorizontalPaddingForApplicationWidth]];
separatorView.translatesAutoresizingMaskIntoConstraints = NO;
[separatorView setAsHeavy];
separatorView.hidden = YES;
self.separatorView = separatorView;
}
- (void)showTopLabels {
self.topLabelConstraint.active = YES;
self.heightConstraint.active = NO;
[self layoutIfNeeded];
// Need to inform the tableview to unpdate the size of its header
if (self.tableView) {
[self.tableView showHeader];
}
}
- (void)hideTopLabels {
self.topLabelConstraint.active = NO;
self.heightConstraint.active = YES;
[self layoutIfNeeded];
// Need to inform the tableview to unpdate the size of its footer
if (self.tableView) {
[self.tableView hideHeader];
}
}
- (void)hideBottomLabels {
self.spaceBetweenLabels.constant = 0;
[self setMessageString:nil];
[self layoutIfNeeded];
// Need to inform the tableview to unpdate the size of its footer
if (self.tableView) {
[self.tableView hideHeader];
}
}
- (void)spaceLabels:(nullable NSString *)headlineString messageString:(nullable NSString *)messageString {
if (headlineString.length > 0 && messageString.length > 0) {
self.spaceBetweenLabels.constant = PaddingTwo;
[self showTopLabels];
} else if (headlineString.length > 0 || messageString.length > 0) {
self.spaceBetweenLabels.constant = 0;
[self showTopLabels];
} else {
[self hideTopLabels];
}
}
- (void)setMessageString:(nullable NSString *)messageString {
self.messageLabel.text = messageString;
}
- (void)setMessageAttributedString:(nullable NSAttributedString *)messageString {
self.messageLabel.attributedText = messageString;
}
- (void)setHeadlineString:(nullable NSString *)headlineString messageString:(nullable NSString *)messageString {
self.headlineLabel.text = headlineString;
[self setMessageString:messageString];
[self spaceLabels:headlineString messageString:messageString];
}
- (void)setHeadlineAttributedString:(nullable NSAttributedString *)headlineString messageAttributedString:(nullable NSAttributedString *)messageString {
self.headlineLabel.attributedText = headlineString;
[self setMessageAttributedString:messageString];
[self spaceLabels:headlineString.string messageString:messageString.string];
}
#pragma mark - Common styles
- (void)setAsLargeHeadline {
[MFStyler styleLabelHeadlineLarge:self.headlineLabel];
[self layoutIfNeeded];
if (self.tableView) {
[self.tableView showHeader];
}
}
- (void)styleMessageLabelBold {
[self removeFromSuperview];
[MFStyler styleLabelH3:self.messageLabel];
[self layoutIfNeeded];
if (self.tableView) {
//[MFUtility sizeViewToFit:self];
CGRect frame = self.frame;
frame.size.height = CGRectGetHeight(self.frame);
//self.tableView.tableView.tableHeaderView = [[UIView alloc]initWithFrame:frame];
//[self.tableView.tableView.tableHeaderView addSubview:self];
[NSLayoutConstraint constraintPinSubviewToSuperview:self];
}
}
- (void)setLeftConstant:(CGFloat)leftConstant {
self.leftConstraintTitle.constant = leftConstant;
self.leftConstraintMessage.constant = leftConstant;
self.leftConstraintSeparator.constant = leftConstant;
}
- (void)setRightConstant:(CGFloat)rightConstant {
self.rightConstraintTitle.constant = rightConstant;
self.rightConstraintMessage.constant = rightConstant;
self.rightConstraintSeparator.constant = rightConstant;
}
@end

View File

@ -21,9 +21,6 @@ NS_ASSUME_NONNULL_BEGIN
- (void)defaultLogActionForController:(nonnull MFViewController *)controller actionInformation:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData;
- (nullable NSDictionary *)defaultGetActionTrackDataDictionaryForController:(nonnull MFViewController *)controller actionInformation:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData;
// Load Logging
- (void)defaultTrackLoadFinishedForController:(nonnull MFViewController *)controller loadObject:(nullable MVMCoreLoadObject *)loadObject;
@end
NS_ASSUME_NONNULL_END

View File

@ -20,7 +20,4 @@
return nil;
}
- (void)defaultTrackLoadFinishedForController:(nonnull MFViewController *)controller loadObject:(nullable MVMCoreLoadObject *)loadObject {
}
@end

View File

@ -0,0 +1,17 @@
//
// MVMCoreUIViewControllerMappingObject.h
// MVMCoreUI
//
// Created by Scott Pfeil on 1/23/19.
// Copyright © 2019 Verizon Wireless. All rights reserved.
//
#import <MVMCore/MVMCore.h>
NS_ASSUME_NONNULL_BEGIN
@interface MVMCoreUIViewControllerMappingObject : MVMCoreViewControllerMappingObject
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,26 @@
//
// MVMCoreUIViewControllerMappingObject.m
// MVMCoreUI
//
// Created by Scott Pfeil on 1/23/19.
// Copyright © 2019 Verizon Wireless. All rights reserved.
//
#import "MVMCoreUIViewControllerMappingObject.h"
#import <MVMCore/MVMCoreViewControllerProgrammaticMappingObject.h>
#import "MVMCoreUILargeHeaderSingleLabelTemplate.h"
@implementation MVMCoreUIViewControllerMappingObject
- (NSMutableDictionary *)viewControllerMapping {
// Keeps a mapping of the given page type
static dispatch_once_t onceToken;
static NSMutableDictionary *viewControllerMapping;
dispatch_once(&onceToken, ^{
viewControllerMapping = [@{ @"LargeHeaderSingleLabel": [[MVMCoreViewControllerProgrammaticMappingObject alloc] initWithClass:[MVMCoreUILargeHeaderSingleLabelTemplate class]]} mutableCopy];
});
return viewControllerMapping;
}
@end

View File

@ -1,32 +0,0 @@
//
// LargeHeaderSingleLabelViewController.m
// MVMCoreUI
//
// Created by Scott Pfeil on 1/8/19.
// Copyright © 2019 Verizon Wireless. All rights reserved.
//
#import "LargeHeaderSingleLabelViewController.h"
@interface LargeHeaderSingleLabelViewController ()
@end
@implementation LargeHeaderSingleLabelViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
@end

View File

@ -1,5 +1,5 @@
//
// LargeHeaderSingleLabelViewController.h
// MVMCoreUILargeHeaderSingleLabelTemplate.h
// MVMCoreUI
//
// Created by Scott Pfeil on 1/8/19.
@ -7,11 +7,11 @@
//
#import <UIKit/UIKit.h>
#import <MVMCore/MVMCoreViewControllerProtocol.h>
#import <MVMCoreUI/TopLabelsAndBottomButtonsViewController.h>
NS_ASSUME_NONNULL_BEGIN
@interface LargeHeaderSingleLabelViewController : UIViewController <MVMCoreViewControllerProtocol>
@interface MVMCoreUILargeHeaderSingleLabelTemplate : TopLabelsAndBottomButtonsViewController
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,102 @@
//
// MVMCoreUILargeHeaderSingleLabelTemplate.m
// MVMCoreUI
//
// Created by Scott Pfeil on 1/8/19.
// Copyright © 2019 Verizon Wireless. All rights reserved.
//
#import "MVMCoreUILargeHeaderSingleLabelTemplate.h"
#import "LabelView.h"
#import "LabelWithInternalButton.h"
#import "UIColor+MFConvenience.h"
@interface MVMCoreUILargeHeaderSingleLabelTemplate ()
// A label that can go below the top labels. Can be a normal label or one with internal buttons.
@property (nullable, weak, nonatomic) LabelView *labelViewUnderTopLabels;
@property (nullable, weak, nonatomic) LabelWithInternalButton *labelUnderTopLabelsWithInternalButton;
@end
@implementation MVMCoreUILargeHeaderSingleLabelTemplate
- (void)newDataBuildScreen {
[super newDataBuildScreen];
[self.topLabelsView.headlineLabel styleH1:YES];
self.topLabelsView.separatorView.hidden = YES;
[self updateTopLabelsColor];
}
- (void)initialLoad {
[super initialLoad];
self.rebuildUIOnSizeChange = NO;
}
- (nullable NSArray <UIView *>*)buildViewsBetweenLabelsAndButtons {
NSDictionary *labelActionMap = [self actionMapForLabelUnderTopLabelsWithInternalButton];
NSString *labelString = [self stringForLabelUnderTopLabels];
NSMutableArray *views = [[NSMutableArray alloc] init];
if (labelActionMap.count > 0) {
// Use label with internal button.
LabelWithInternalButton *labelWithInternalButton = [[LabelWithInternalButton alloc] initWithActionMap:labelActionMap additionalData:nil actionDelegate:self buttonDelegate:self];
labelWithInternalButton.translatesAutoresizingMaskIntoConstraints = NO;
[labelWithInternalButton setAlignment:NSTextAlignmentLeft];
self.labelUnderTopLabelsWithInternalButton = labelWithInternalButton;
[views addObject:labelWithInternalButton];
} else if (labelString.length > 0){
// Use regular label
LabelView *labelView = [[LabelView alloc] init];
labelView.translatesAutoresizingMaskIntoConstraints = NO;
[labelView alignLeft];
[labelView.label styleB2:YES];
labelView.label.text = labelString;
[labelView.label setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
self.labelViewUnderTopLabels = labelView;
[views addObject:labelView];
}
return views;
}
- (nullable NSString *)stringForLabelUnderTopLabels {
return [self.loadObject.pageJSON stringForKey:@"description"];
}
- (nullable NSDictionary *)actionMapForLabelUnderTopLabelsWithInternalButton {
return [self.loadObject.pageJSON dictWithChainOfKeysOrIndexes:@[KeyButtonMap,@"Link"]];
}
- (NSNumber *)spaceAboveBetweenView {
return @(0);
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Top labels style
- (void)updateTopLabelsColor {
self.topLabelsView.headlineLabel.textColor = [UIColor blackColor];
self.topLabelsView.messageLabel.textColor = [UIColor blackColor];
NSString *titleColor = [[self mapForTopLabels] string:@"titleBgColor"];
if (titleColor) {
self.topLabelsView.headlineLabel.textColor = [UIColor mfGetColorForHex:titleColor];
self.topLabelsView.messageLabel.textColor = [UIColor mfGetColorForHex:titleColor];
}
}
- (UIEdgeInsets)paddingForTopLabels {
UIEdgeInsets edge = [super paddingForTopLabels];
edge.bottom = PaddingTwo;
return edge;
}
@end

View File

@ -23,6 +23,11 @@ extern NSString * const KeyFieldName;
extern NSString * const KeyHideMainMenu;
extern NSString * const KeyProgressPercent;
extern NSString * const KeyPrimaryButton;
extern NSString * const KeySecondaryButton;
extern NSString * const KeyTitlePrefix;
extern NSString * const KeyTitlePostfix;
#pragma mark - Values
extern NSString * const StringY;

View File

@ -22,6 +22,11 @@ NSString * const KeyFieldName = @"fieldName";
NSString * const KeyHideMainMenu = @"hideMainMenu";
NSString * const KeyProgressPercent = @"progressPercent";
NSString * const KeyPrimaryButton = @"PrimaryButton";
NSString * const KeySecondaryButton = @"SecondaryButton";
NSString * const KeyTitlePrefix = @"titlePrefix";
NSString * const KeyTitlePostfix = @"titlePostfix";
#pragma mark - Values
NSString * const StringY = @"Y";

View File

@ -52,6 +52,18 @@ NS_ASSUME_NONNULL_BEGIN
// Gets the space needed at the top of the view for the status bar.
+ (CGFloat)getTopSpaceWithStatusBarForView:(UIView *_Nonnull)view;
// Returns the height of the view. If nil is passed for the width, it will use the detail view width.
+ (CGFloat)getHeightOfView:(nonnull UIView *)view forWidth:(nullable NSNumber *)width;
// Returns the space between the content and the frame. Can use this to get the space for items to fill out the screen.
+ (CGFloat)getRemainingSpaceBetweenContentAndFrame:(nonnull UIScrollView *)scrollview;
// Gets the constraint height to be whatever space is left in the scroll view.
+ (CGFloat)getVariableConstraintHeight:(CGFloat)currentConstant inScrollView:(nonnull UIScrollView *)scrollView minimumHeight:(CGFloat)minimumHeight;
// Sets the view's frame according to constraint.
+ (void)sizeViewToFit:(nullable UIView *)view;
#pragma mark - Keyboard
/** Handles setting the content inset for a passed in scroll view.

View File

@ -8,6 +8,8 @@
#import "MVMCoreUIUtility.h"
#import "MVMCoreUIConstants.h"
@import MVMCore.MVMCoreNavigationHandler;
@import MVMCore.MVMCoreGetterUtility;
@implementation MVMCoreUIUtility
@ -105,6 +107,61 @@
}
}
+ (CGFloat)getHeightOfView:(nonnull UIView *)view forWidth:(nullable NSNumber *)width {
CGFloat floatWidth = (width ? width.floatValue : CGRectGetWidth([MVMCoreNavigationHandler sharedNavigationHandler].navigationController.view.bounds));
return [view systemLayoutSizeFittingSize:CGSizeMake(floatWidth, UILayoutFittingCompressedSize.height) withHorizontalFittingPriority:1000 verticalFittingPriority:250].height;
}
+ (CGFloat)getRemainingSpaceBetweenContentAndFrame:(nonnull UIScrollView *)scrollview {
// -1 at the end to avoid scrolling due to a thousandth of a float value.
CGFloat frameHeight = CGRectGetHeight(scrollview.frame);
CGFloat contentSizeHeight = scrollview.contentSize.height;
// For some reason the content size calculates differently for the table view (doesn't include status bar).
CGFloat topInset = scrollview.contentInset.top;
CGFloat bottomInset = scrollview.contentInset.bottom;
// Updates for ios 11
if (@available(iOS 11.0, *)) {
if (scrollview.contentInsetAdjustmentBehavior == UIScrollViewContentInsetAdjustmentAutomatic) {
topInset = scrollview.adjustedContentInset.top;
bottomInset = scrollview.adjustedContentInset.bottom;
}
}
CGFloat remainingSpace = frameHeight - contentSizeHeight - topInset - bottomInset;
return remainingSpace - 1;
}
+ (CGFloat)getVariableConstraintHeight:(CGFloat)currentConstant inScrollView:(nonnull UIScrollView *)scrollView minimumHeight:(CGFloat)minimumHeight {
if (scrollView.contentSize.height > 0) {
CGFloat remainingSpace = [MVMCoreUIUtility getRemainingSpaceBetweenContentAndFrame:scrollView];
// There's a chance this can get called multiple times and the current constant has already been set to the remaining space previously, but now the remaining space is slightly different. If the current constant is not the minimum, we will assume that this happened and we have to append the current space.
CGFloat newSpace = remainingSpace;
if (!fequal(currentConstant, minimumHeight)) {
newSpace += currentConstant;
}
if (newSpace > minimumHeight) {
return newSpace;
} else {
return minimumHeight;
}
}
return minimumHeight;
}
+ (void)sizeViewToFit:(UIView *)view {
CGFloat height = [MVMCoreUIUtility getHeightOfView:view forWidth:nil];
CGRect frame = view.frame;
frame.size.height = height;
view.frame = frame;
}
#pragma mark - Keyboard
+ (void)setScrollViewInsetForKeyboardShow:(nonnull NSNotification *)notification scrollView:(nonnull UIScrollView *)scrollView viewController:(nonnull UIViewController *)viewController rectToScrollTo:(nonnull CGRect (^)(void))rectToScrollTo {