Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui.git into feature/ACT-192-Year-In-Review

This commit is contained in:
Jarrod Courtney 2024-04-26 08:28:36 -05:00
commit d5783fb072
56 changed files with 1125 additions and 245 deletions

View File

@ -126,7 +126,6 @@
0AE98BB523FF18D2004C5109 /* Arrow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AE98BB423FF18D2004C5109 /* Arrow.swift */; };
0AE98BB723FF18E9004C5109 /* ArrowModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AE98BB623FF18E9004C5109 /* ArrowModel.swift */; };
0AF60F0926B3316E00AC3DB4 /* MVMCoreUIUtility+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AF60F0826B3316E00AC3DB4 /* MVMCoreUIUtility+Extension.swift */; };
187FEB2A2844D2A600BF29C2 /* VDSFormControlsTokens.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 187FEB292844D2A600BF29C2 /* VDSFormControlsTokens.xcframework */; };
1D6D258826899B0C00DEBB08 /* ImageButtonModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D6D258626899B0B00DEBB08 /* ImageButtonModel.swift */; };
1D6D258926899B0C00DEBB08 /* ImageButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D6D258726899B0B00DEBB08 /* ImageButton.swift */; };
22B678F929E7944E00CF4196 /* GetNotificationAuthStatusBehavior.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22B678F829E7944E00CF4196 /* GetNotificationAuthStatusBehavior.swift */; };
@ -153,6 +152,7 @@
444FB7C12821B73200DFE692 /* TitleLockup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 444FB7C02821B73200DFE692 /* TitleLockup.swift */; };
444FB7C32821B76B00DFE692 /* TitleLockupModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 444FB7C22821B76B00DFE692 /* TitleLockupModel.swift */; };
4457904E27ECE989002B1E1E /* UIImageRenderingMode+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4457904D27ECE989002B1E1E /* UIImageRenderingMode+Extension.swift */; };
4B002ACA2BD855EC009BC9C1 /* DateDropdownEntryFieldModel+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B002AC92BD855EC009BC9C1 /* DateDropdownEntryFieldModel+Extension.swift */; };
522679C123FE886900906CBA /* ListLeftVariableCheckboxAllTextAndLinks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 522679BF23FE886900906CBA /* ListLeftVariableCheckboxAllTextAndLinks.swift */; };
522679C223FE886900906CBA /* ListLeftVariableCheckboxAllTextAndLinksModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 522679C023FE886900906CBA /* ListLeftVariableCheckboxAllTextAndLinksModel.swift */; };
52267A0723FFE25000906CBA /* ListOneColumnFullWidthTextAllTextAndLinks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52267A0623FFE25000906CBA /* ListOneColumnFullWidthTextAllTextAndLinks.swift */; };
@ -174,8 +174,6 @@
5870636F2ACF238E00CA18D5 /* ReadableDecodingErrors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5870636E2ACF238E00CA18D5 /* ReadableDecodingErrors.swift */; };
58A9DD7D2AC2103300F5E0B0 /* ReplaceableMoleculeBehaviorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58A9DD7C2AC2103300F5E0B0 /* ReplaceableMoleculeBehaviorModel.swift */; };
608211282AC6B57E00C3FC39 /* MVMCoreUILoggingHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 608211262AC6AF8200C3FC39 /* MVMCoreUILoggingHandler.swift */; };
7199C8162A4F3A64001568B7 /* AccessibilityHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7199C8152A4F3A64001568B7 /* AccessibilityHandler.swift */; };
71BE969E2AD96BE6000B5DB7 /* RotorHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71BE969D2AD96BE6000B5DB7 /* RotorHandler.swift */; };
8D070BB0241B56530099AC56 /* ListRightVariableTotalDataModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D070BAF241B56530099AC56 /* ListRightVariableTotalDataModel.swift */; };
8D070BB2241B56AD0099AC56 /* ListRightVariableTotalData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D070BB1241B56AD0099AC56 /* ListRightVariableTotalData.swift */; };
8D084AD02410BF4800951227 /* ListOneColumnFullWidthTextBodyTextModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D084ACF2410BF4800951227 /* ListOneColumnFullWidthTextBodyTextModel.swift */; };
@ -302,7 +300,6 @@
AFA4932229E5EF2E001A9663 /* NotificationHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFA4932129E5EF2E001A9663 /* NotificationHandler.swift */; };
AFA4933F29E874F0001A9663 /* MVMCoreUILoggingDelegateProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFA4933E29E874F0001A9663 /* MVMCoreUILoggingDelegateProtocol.swift */; };
AFA4935729EE3DCC001A9663 /* AlertDelegateProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFA4935629EE3DCC001A9663 /* AlertDelegateProtocol.swift */; };
AFE4A1D127DFB5EE00C458D0 /* VDSColorTokens.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = AFE4A1D027DFB5EE00C458D0 /* VDSColorTokens.xcframework */; };
AFE4A1D627DFBB6F00C458D0 /* UINavigationController+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFE4A1D527DFBB6F00C458D0 /* UINavigationController+Extension.swift */; };
B4CC8FBD29DF34680005D28B /* Badge.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4CC8FBC29DF34680005D28B /* Badge.swift */; };
B4CC8FBF29DF34730005D28B /* BadgeModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4CC8FBE29DF34730005D28B /* BadgeModel.swift */; };
@ -575,9 +572,15 @@
DBEFFA04225A829700230692 /* Label.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB891E822253FA8500022516 /* Label.swift */; };
EA05EFA9278DDE2C00828819 /* ClearFormFieldEffectModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA05EFA8278DDE2C00828819 /* ClearFormFieldEffectModel.swift */; };
EA05EFAB278DE53600828819 /* ClearableModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA05EFAA278DE53600828819 /* ClearableModelProtocol.swift */; };
EA1758482BC97ED800A5C0D9 /* BadgeIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA1758472BC97ED800A5C0D9 /* BadgeIndicator.swift */; };
EA17584A2BC97EF100A5C0D9 /* BadgeIndicatorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA1758492BC97EF100A5C0D9 /* BadgeIndicatorModel.swift */; };
EA17584C2BC9894800A5C0D9 /* ButtonIconModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA17584B2BC9894800A5C0D9 /* ButtonIconModel.swift */; };
EA17584E2BC9895A00A5C0D9 /* ButtonIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA17584D2BC9895A00A5C0D9 /* ButtonIcon.swift */; };
EA41F4AC2787927100F5B377 /* DynamicRuleFormFieldEffectModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA41F4AB2787927100F5B377 /* DynamicRuleFormFieldEffectModel.swift */; };
EA5124FD243601600051A3A4 /* BGImageHeadlineBodyButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA5124FC243601600051A3A4 /* BGImageHeadlineBodyButton.swift */; };
EA5124FF2436018E0051A3A4 /* BGImageHeadlineBodyButtonModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA5124FE2436018E0051A3A4 /* BGImageHeadlineBodyButtonModel.swift */; };
EA6642912BCDA97300D81DC4 /* TileContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA6642902BCDA97300D81DC4 /* TileContainer.swift */; };
EA6642932BCDA97D00D81DC4 /* TileContainerModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA6642922BCDA97D00D81DC4 /* TileContainerModel.swift */; };
EA6E8B952B504A43000139B4 /* ButtonGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA6E8B942B504A43000139B4 /* ButtonGroup.swift */; };
EA6E8B972B504A4D000139B4 /* ButtonGroupModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA6E8B962B504A4D000139B4 /* ButtonGroupModel.swift */; };
EA7D81602B2B6E6800D29F9E /* Icon.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA7D815F2B2B6E6800D29F9E /* Icon.swift */; };
@ -589,7 +592,6 @@
EA985C3E2970938F00F2FF2E /* Tilelet.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA985C3D2970938F00F2FF2E /* Tilelet.swift */; };
EA985C402970939A00F2FF2E /* TileletModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA985C3F2970939A00F2FF2E /* TileletModel.swift */; };
EA985C602970A3F000F2FF2E /* VDS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EA985C5F2970A3F000F2FF2E /* VDS.framework */; };
EA985C642970A40E00F2FF2E /* VDSTypographyTokens.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = EA985C632970A40E00F2FF2E /* VDSTypographyTokens.xcframework */; };
EA985C852981AA9C00F2FF2E /* VDS-Enums+Codable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA985C842981AA9C00F2FF2E /* VDS-Enums+Codable.swift */; };
EA985C872981AB0F00F2FF2E /* VDS-Tilelet+Codable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA985C862981AB0F00F2FF2E /* VDS-Tilelet+Codable.swift */; };
EA985C892981AB7100F2FF2E /* VDS-TextStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA985C882981AB7100F2FF2E /* VDS-TextStyle.swift */; };
@ -604,6 +606,7 @@
EABFC1412763BB8D00E78B40 /* FormLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EABFC1402763BB8D00E78B40 /* FormLabel.swift */; };
EABFC152276913E800E78B40 /* FormLabelModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EABFC151276913E800E78B40 /* FormLabelModel.swift */; };
EACCF38C2ABB346700E0F104 /* VDS-Interpreters.swift in Sources */ = {isa = PBXBuildFile; fileRef = EACCF38B2ABB346700E0F104 /* VDS-Interpreters.swift */; };
EAD715AA2BBC8FAF00DEDA6A /* VDSTokens.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = EAD715A92BBC8FAF00DEDA6A /* VDSTokens.xcframework */; };
FD99130028E21E4900542CC3 /* RuleNotEqualsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD9912FF28E21E4900542CC3 /* RuleNotEqualsModel.swift */; };
/* End PBXBuildFile section */
@ -756,6 +759,7 @@
444FB7C02821B73200DFE692 /* TitleLockup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TitleLockup.swift; sourceTree = "<group>"; };
444FB7C22821B76B00DFE692 /* TitleLockupModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TitleLockupModel.swift; sourceTree = "<group>"; };
4457904D27ECE989002B1E1E /* UIImageRenderingMode+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImageRenderingMode+Extension.swift"; sourceTree = "<group>"; };
4B002AC92BD855EC009BC9C1 /* DateDropdownEntryFieldModel+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DateDropdownEntryFieldModel+Extension.swift"; sourceTree = "<group>"; };
522679BF23FE886900906CBA /* ListLeftVariableCheckboxAllTextAndLinks.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListLeftVariableCheckboxAllTextAndLinks.swift; sourceTree = "<group>"; };
522679C023FE886900906CBA /* ListLeftVariableCheckboxAllTextAndLinksModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListLeftVariableCheckboxAllTextAndLinksModel.swift; sourceTree = "<group>"; };
52267A0623FFE25000906CBA /* ListOneColumnFullWidthTextAllTextAndLinks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListOneColumnFullWidthTextAllTextAndLinks.swift; sourceTree = "<group>"; };
@ -775,10 +779,10 @@
5822720A2B1FC55F00F75BAE /* RotorHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RotorHandler.swift; sourceTree = "<group>"; };
5846ABF52B4762A600FA6C76 /* PollingBehaviorModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PollingBehaviorModel.swift; sourceTree = "<group>"; };
5870636E2ACF238E00CA18D5 /* ReadableDecodingErrors.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadableDecodingErrors.swift; sourceTree = "<group>"; };
5878F0A42BD7E68800ADE23D /* mvmcoreui.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = mvmcoreui.xcconfig; sourceTree = "<group>"; };
5878F0A52BD7E6BE00ADE23D /* mvmcoreui_dev.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = mvmcoreui_dev.xcconfig; sourceTree = "<group>"; };
58A9DD7C2AC2103300F5E0B0 /* ReplaceableMoleculeBehaviorModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReplaceableMoleculeBehaviorModel.swift; sourceTree = "<group>"; };
608211262AC6AF8200C3FC39 /* MVMCoreUILoggingHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MVMCoreUILoggingHandler.swift; sourceTree = "<group>"; };
7199C8152A4F3A64001568B7 /* AccessibilityHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccessibilityHandler.swift; sourceTree = "<group>"; };
71BE969D2AD96BE6000B5DB7 /* RotorHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RotorHandler.swift; sourceTree = "<group>"; };
8D070BAF241B56530099AC56 /* ListRightVariableTotalDataModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListRightVariableTotalDataModel.swift; sourceTree = "<group>"; };
8D070BB1241B56AD0099AC56 /* ListRightVariableTotalData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListRightVariableTotalData.swift; sourceTree = "<group>"; };
8D084ACF2410BF4800951227 /* ListOneColumnFullWidthTextBodyTextModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListOneColumnFullWidthTextBodyTextModel.swift; sourceTree = "<group>"; };
@ -1179,9 +1183,15 @@
DBC4391A224421A0001AB423 /* CaretLink.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CaretLink.swift; sourceTree = "<group>"; };
EA05EFA8278DDE2C00828819 /* ClearFormFieldEffectModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClearFormFieldEffectModel.swift; sourceTree = "<group>"; };
EA05EFAA278DE53600828819 /* ClearableModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClearableModelProtocol.swift; sourceTree = "<group>"; };
EA1758472BC97ED800A5C0D9 /* BadgeIndicator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BadgeIndicator.swift; sourceTree = "<group>"; };
EA1758492BC97EF100A5C0D9 /* BadgeIndicatorModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BadgeIndicatorModel.swift; sourceTree = "<group>"; };
EA17584B2BC9894800A5C0D9 /* ButtonIconModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonIconModel.swift; sourceTree = "<group>"; };
EA17584D2BC9895A00A5C0D9 /* ButtonIcon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonIcon.swift; sourceTree = "<group>"; };
EA41F4AB2787927100F5B377 /* DynamicRuleFormFieldEffectModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DynamicRuleFormFieldEffectModel.swift; sourceTree = "<group>"; };
EA5124FC243601600051A3A4 /* BGImageHeadlineBodyButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BGImageHeadlineBodyButton.swift; sourceTree = "<group>"; };
EA5124FE2436018E0051A3A4 /* BGImageHeadlineBodyButtonModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BGImageHeadlineBodyButtonModel.swift; sourceTree = "<group>"; };
EA6642902BCDA97300D81DC4 /* TileContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TileContainer.swift; sourceTree = "<group>"; };
EA6642922BCDA97D00D81DC4 /* TileContainerModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TileContainerModel.swift; sourceTree = "<group>"; };
EA6E8B942B504A43000139B4 /* ButtonGroup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonGroup.swift; sourceTree = "<group>"; };
EA6E8B962B504A4D000139B4 /* ButtonGroupModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonGroupModel.swift; sourceTree = "<group>"; };
EA7D815F2B2B6E6800D29F9E /* Icon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Icon.swift; sourceTree = "<group>"; };
@ -1208,6 +1218,7 @@
EABFC1402763BB8D00E78B40 /* FormLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormLabel.swift; sourceTree = "<group>"; };
EABFC151276913E800E78B40 /* FormLabelModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormLabelModel.swift; sourceTree = "<group>"; };
EACCF38B2ABB346700E0F104 /* VDS-Interpreters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "VDS-Interpreters.swift"; sourceTree = "<group>"; };
EAD715A92BBC8FAF00DEDA6A /* VDSTokens.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = VDSTokens.xcframework; path = ../SharedFrameworks/VDSTokens.xcframework; sourceTree = "<group>"; };
FD9912FF28E21E4900542CC3 /* RuleNotEqualsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuleNotEqualsModel.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
@ -1217,10 +1228,8 @@
buildActionMask = 2147483647;
files = (
D29DF0E621E4F3C7003B2FB9 /* MVMCore.framework in Frameworks */,
AFE4A1D127DFB5EE00C458D0 /* VDSColorTokens.xcframework in Frameworks */,
EA985C602970A3F000F2FF2E /* VDS.framework in Frameworks */,
187FEB2A2844D2A600BF29C2 /* VDSFormControlsTokens.xcframework in Frameworks */,
EA985C642970A40E00F2FF2E /* VDSTypographyTokens.xcframework in Frameworks */,
EAD715AA2BBC8FAF00DEDA6A /* VDSTokens.xcframework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -1344,6 +1353,7 @@
children = (
0A7EF86623D8B0AE00B2AAD1 /* DateDropdownEntryFieldModel.swift */,
0ABD136C237CAD1E0081388D /* DateDropdownEntryField.swift */,
4B002AC92BD855EC009BC9C1 /* DateDropdownEntryFieldModel+Extension.swift */,
);
path = "Date Dropdown";
sourceTree = "<group>";
@ -2081,6 +2091,7 @@
D29DF0E421E4F3C7003B2FB9 /* Frameworks */ = {
isa = PBXGroup;
children = (
EAD715A92BBC8FAF00DEDA6A /* VDSTokens.xcframework */,
EA985C632970A40E00F2FF2E /* VDSTypographyTokens.xcframework */,
EA985C5F2970A3F000F2FF2E /* VDS.framework */,
187FEB292844D2A600BF29C2 /* VDSFormControlsTokens.xcframework */,
@ -2268,6 +2279,12 @@
AA07EA922510A451009A2AE3 /* Star.swift */,
B4CC8FBE29DF34730005D28B /* BadgeModel.swift */,
B4CC8FBC29DF34680005D28B /* Badge.swift */,
EA1758492BC97EF100A5C0D9 /* BadgeIndicatorModel.swift */,
EA1758472BC97ED800A5C0D9 /* BadgeIndicator.swift */,
EA17584B2BC9894800A5C0D9 /* ButtonIconModel.swift */,
EA17584D2BC9895A00A5C0D9 /* ButtonIcon.swift */,
EA6642922BCDA97D00D81DC4 /* TileContainerModel.swift */,
EA6642902BCDA97300D81DC4 /* TileContainer.swift */,
EA985C3F2970939A00F2FF2E /* TileletModel.swift */,
EA985C3D2970938F00F2FF2E /* Tilelet.swift */,
EA7D81612B2B6E7F00D29F9E /* IconModel.swift */,
@ -2351,6 +2368,8 @@
D29DF31421ECECA7003B2FB9 /* SupportingFiles */ = {
isa = PBXGroup;
children = (
5878F0A52BD7E6BE00ADE23D /* mvmcoreui_dev.xcconfig */,
5878F0A42BD7E68800ADE23D /* mvmcoreui.xcconfig */,
D29DF32721EE8736003B2FB9 /* Strings */,
D29DF26621E6A9E4003B2FB9 /* ThirdParty */,
D29DF31521ECECC0003B2FB9 /* Fonts */,
@ -2684,6 +2703,7 @@
D29B771022C281F400D6ACE0 /* ModuleMolecule.swift in Sources */,
AAE96FA225341F6A0037A989 /* ListStoreLocatorModel.swift in Sources */,
D28A838923CCCFCB00DFE4FC /* LinkModel.swift in Sources */,
EA17584A2BC97EF100A5C0D9 /* BadgeIndicatorModel.swift in Sources */,
AA56A20F243C5EE900303286 /* ListTwoColumnSubsectionDividerModel.swift in Sources */,
AAB9C10824346F4B00151545 /* RadioSwatches.swift in Sources */,
94C2D9A923872E5E0006CF46 /* LabelAttributeImageModel.swift in Sources */,
@ -2908,6 +2928,7 @@
D22479942316AE5E003FCCF9 /* NSLayoutConstraintExtension.swift in Sources */,
D2B18B94236214AD00A9AEDC /* NavigationController.swift in Sources */,
0A9D09222433796500D2E6C0 /* CarouselIndicator.swift in Sources */,
EA17584E2BC9895A00A5C0D9 /* ButtonIcon.swift in Sources */,
D29E28DA23D21AFA00ACEA85 /* StringAndMoleculeModel.swift in Sources */,
D260105D23D0BCD400764D80 /* Stack.swift in Sources */,
0A7EF85D23D8A95600B2AAD1 /* TextEntryFieldModel.swift in Sources */,
@ -2935,6 +2956,7 @@
D22479962316AF6E003FCCF9 /* HeadlineBodyLink.swift in Sources */,
8DE5BECD2456F7A200772E76 /* ListTwoColumnDropdownSelectorsModel.swift in Sources */,
AA7F47732541AD560015A2C1 /* ListStarRatingModel.swift in Sources */,
EA17584C2BC9894800A5C0D9 /* ButtonIconModel.swift in Sources */,
AA7F47762541AD6A0015A2C1 /* ListStarRating.swift in Sources */,
0A41BA7F23453A6400D4C0BC /* TextEntryField.swift in Sources */,
AF7E509829E477C1009DC2AD /* AlertHandler.swift in Sources */,
@ -2989,6 +3011,7 @@
D264FAAC2441009400D98315 /* RadioBoxCollectionViewCell.swift in Sources */,
BB2C969224330F73006FF80C /* ListRightVariableTextLinkAllTextAndLinks.swift in Sources */,
D2D90B42240463E100DD6EC9 /* MoleculeHeaderModel.swift in Sources */,
EA1758482BC97ED800A5C0D9 /* BadgeIndicator.swift in Sources */,
012A88B1238C880100FE3DA1 /* CarouselPagingModelProtocol.swift in Sources */,
0A9D091E2433796500D2E6C0 /* NumericCarouselIndicatorModel.swift in Sources */,
D29DF2C921E7BFC6003B2FB9 /* MFSizeObject.m in Sources */,
@ -3053,6 +3076,7 @@
0AE14F64238315D2005417F8 /* TextField.swift in Sources */,
0A51F3E22475CB73002E08B6 /* LoadingSpinnerModel.swift in Sources */,
D2169303251E53D9002A6324 /* SectionListTemplateModel.swift in Sources */,
EA6642932BCDA97D00D81DC4 /* TileContainerModel.swift in Sources */,
AF7E509929E477C1009DC2AD /* AlertController.swift in Sources */,
0AB764D124460F6300E7FE72 /* UIDatePicker+Extension.swift in Sources */,
BB105859248DEFF70069D008 /* UICollectionViewLeftAlignedLayout.swift in Sources */,
@ -3086,6 +3110,7 @@
8DE5BECF2456F7B100772E76 /* ListTwoColumnDropdownSelectors.swift in Sources */,
D2E1FADF2268B8E700AEFD8C /* ThreeLayerTableViewController.swift in Sources */,
0A21DB83235DFBC500C160A2 /* MdnEntryField.swift in Sources */,
4B002ACA2BD855EC009BC9C1 /* DateDropdownEntryFieldModel+Extension.swift in Sources */,
0AE98BB723FF18E9004C5109 /* ArrowModel.swift in Sources */,
01F2C20427C81F9700DC3D36 /* SubNavInteractor.swift.swift in Sources */,
D28A837D23CCA86A00DFE4FC /* TabsListItemModel.swift in Sources */,
@ -3179,6 +3204,7 @@
D29C559625C099630082E7D6 /* VideoDataManager.swift in Sources */,
8D4687E2242E2DE400802879 /* ListFourColumnDataUsageListItemModel.swift in Sources */,
D29E28DD23D7404C00ACEA85 /* ContainerHelper.swift in Sources */,
EA6642912BCDA97300D81DC4 /* TileContainer.swift in Sources */,
012A88C2238D7BCA00FE3DA1 /* CarouselItemModel.swift in Sources */,
27F6B08C26052AFF008529AA /* ParentMoleculeModelProtocol.swift in Sources */,
EA985C402970939A00F2FF2E /* TileletModel.swift in Sources */,
@ -3236,6 +3262,7 @@
/* Begin XCBuildConfiguration section */
D29DF0D221E404D4003B2FB9 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 5878F0A52BD7E6BE00ADE23D /* mvmcoreui_dev.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
BUILD_LIBRARY_FOR_DISTRIBUTION = YES;
@ -3294,7 +3321,7 @@
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) DEBUG";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
@ -3303,6 +3330,7 @@
};
D29DF0D321E404D4003B2FB9 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 5878F0A42BD7E68800ADE23D /* mvmcoreui.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
BUILD_LIBRARY_FOR_DISTRIBUTION = YES;

View File

@ -7,7 +7,7 @@
//
import UIKit
import VDSColorTokens
import VDSTokens
import VDS
import MVMCore

View File

@ -7,7 +7,7 @@
//
import UIKit
import VDSColorTokens
import VDSTokens
import VDS
open class Link: VDS.TextLink, VDSMoleculeViewProtocol {

View File

@ -7,7 +7,7 @@
//
import UIKit
import VDSColorTokens
import VDSTokens
import VDS
import MVMCore
import Combine
@ -36,7 +36,7 @@ open class PillButton: VDS.Button, MVMCoreUIViewConstrainingProtocol, MFButtonPr
text = viewModel.title
isEnabled = viewModel.enabled
size = viewModel.size
use = viewModel.style ?? .primary
use = viewModel.style
surface = viewModel.inverted ? .dark : .light
if let accessibilityText = viewModel.accessibilityText {
accessibilityLabel = accessibilityText

View File

@ -16,12 +16,6 @@ import UIKit
public weak var datePicker: UIDatePicker?
private var calendar: Calendar = {
var calendar: Calendar = .current
calendar.timeZone = NSTimeZone.system
return calendar
}()
public var dateFormat: String? {
get { dateDropdownModel?.dateFormat }
set {
@ -97,7 +91,7 @@ import UIKit
dateDropdownModel?.date = date
if calendar.isDate(date, inSameDayAs: Date()) {
if let isToday = dateDropdownModel?.isSelectedToday(), isToday {
text = MVMCoreUIUtility.hardcodedString(withKey: "textfield_today_string")
} else {
text = dateDropdownModel?.dateFormatter.string(from: date)

View File

@ -0,0 +1,21 @@
//
// DateDropdownEntryFieldModel+Extension.swift
// MVMCoreUI
//
// Created by Xi Zhang on 4/23/24.
// Copyright © 2024 Verizon Wireless. All rights reserved.
//
import Foundation
extension DateDropdownEntryFieldModel {
public func isSelectedToday() -> Bool {
guard let date = date else {
return false
}
return calendar.isDate(date, inSameDayAs: Date())
}
}

View File

@ -31,6 +31,12 @@
public var minDate: Date?
public var maxDate: Date?
var calendar: Calendar = {
var calendar: Calendar = .current
calendar.timeZone = NSTimeZone.system
return calendar
}()
//--------------------------------------------------
// MARK: - Keys
//--------------------------------------------------

View File

@ -7,8 +7,7 @@
//
import UIKit
import VDSColorTokens
import VDSFormControlsTokens
import VDSTokens
@objcMembers open class RadioButton: Control, MFButtonProtocol {
//--------------------------------------------------

View File

@ -0,0 +1,70 @@
//
// BadgeIndicator.swift
// MVMCoreUI
//
// Created by Matt Bruce on 4/12/24.
// Copyright © 2024 Verizon Wireless. All rights reserved.
//
import Foundation
import VDS
open class BadgeIndicator: VDS.BadgeIndicator, VDSMoleculeViewProtocol {
//--------------------------------------------------
// MARK: - Public Properties
//--------------------------------------------------
public var viewModel: BadgeIndicatorModel!
public var delegateObject: MVMCoreUIDelegateObject?
public var additionalData: [AnyHashable : Any]?
//--------------------------------------------------
// MARK: - Public Methods
//--------------------------------------------------
public func viewModelDidUpdate() {
surface = viewModel.surface
number = viewModel.number
fillColor = viewModel.fillColor
borderColorLight = viewModel.borderColorLight?.uiColor
borderColorDark = viewModel.borderColorDark?.uiColor
kind = viewModel.kind
maximumDigits = viewModel.maximumDigits
size = viewModel.size
leadingCharacter = viewModel.leadingCharacter
trailingText = viewModel.trailingText
dotSize = viewModel.dotSize
verticalPadding = viewModel.verticalPadding
horizontalPadding = viewModel.horizontalPadding
hideDot = viewModel.hideDot
hideBorder = viewModel.hideBorder
width = viewModel.width
height = viewModel.height
}
public func updateView(_ size: CGFloat) {}
//--------------------------------------------------
// MARK: - Overrides
//--------------------------------------------------
open override func updateAccessibility() {
super.updateAccessibility()
if let viewModel {
if let accessibilityText = viewModel.accessibilityText {
self.accessibilityLabel = accessibilityText
}
}
}
}
//to deal with how it's parent constrains this control
extension BadgeIndicator: MVMCoreUIViewConstrainingProtocol {
public func needsToBeConstrained() -> Bool { true }
public func horizontalAlignment() -> UIStackView.Alignment { .leading }
}

View File

@ -0,0 +1,111 @@
//
// BadgeIndicatorModel.swift
// MVMCoreUI
//
// Created by Matt Bruce on 4/12/24.
// Copyright © 2024 Verizon Wireless. All rights reserved.
//
import Foundation
import VDS
open class BadgeIndicatorModel: MoleculeModelProtocol {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
public static var identifier: String { "badgeIndicator" }
public var id: String = UUID().uuidString
public var backgroundColor: Color?
//--------------------------------------------------
// MARK: - VDS Properties
//--------------------------------------------------
public var surface: Surface { inverted ? .dark : .light }
public var inverted: Bool = false
public var number: Int?
public var accessibilityText: String?
public var fillColor = BadgeIndicator.FillColor.red
public var borderColorLight: Color?
public var borderColorDark: Color?
public var kind = BadgeIndicator.Kind.simple
public var maximumDigits = BadgeIndicator.MaximumDigits.two
public var size = BadgeIndicator.Size.xxlarge
public var leadingCharacter: String?
public var trailingText: String?
public var dotSize: CGFloat?
public var verticalPadding: CGFloat?
public var horizontalPadding: CGFloat?
public var hideDot: Bool = false
public var hideBorder: Bool = false
public var width: CGFloat?
public var height: CGFloat?
private enum CodingKeys: String, CodingKey {
case id
case inverted
case accessibilityText
case number
case fillColor
case borderColorLight
case borderColorDark
case kind
case maximumDigits
case size
case leadingCharacter
case trailingText
case dotSize
case verticalPadding
case horizontalPadding
case hideDot
case hideBorder
case width
case height
}
required public convenience init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.init()
id = try container.decodeIfPresent(String.self, forKey: .id) ?? UUID().uuidString
inverted = try container.decodeIfPresent(Bool.self, forKey: .inverted) ?? false
accessibilityText = try container.decodeIfPresent(String.self, forKey: .accessibilityText)
number = try container.decodeIfPresent(Int.self, forKey: .number)
fillColor = try container.decodeIfPresent(BadgeIndicator.FillColor.self, forKey: .fillColor) ?? .red
borderColorLight = try container.decodeIfPresent(Color.self, forKey: .borderColorLight)
borderColorDark = try container.decodeIfPresent(Color.self, forKey: .borderColorDark)
kind = try container.decodeIfPresent(BadgeIndicator.Kind.self, forKey: .kind) ?? .simple
maximumDigits = try container.decodeIfPresent(BadgeIndicator.MaximumDigits.self, forKey: .maximumDigits) ?? .two
size = try container.decodeIfPresent(BadgeIndicator.Size.self, forKey: .size) ?? .xxlarge
leadingCharacter = try container.decodeIfPresent(String.self, forKey: .leadingCharacter)
trailingText = try container.decodeIfPresent(String.self, forKey: .trailingText)
dotSize = try container.decodeIfPresent(CGFloat.self, forKey: .dotSize)
verticalPadding = try container.decodeIfPresent(CGFloat.self, forKey: .verticalPadding)
horizontalPadding = try container.decodeIfPresent(CGFloat.self, forKey: .horizontalPadding)
hideDot = try container.decodeIfPresent(Bool.self, forKey: .hideDot) ?? false
hideBorder = try container.decodeIfPresent(Bool.self, forKey: .hideBorder) ?? false
width = try container.decodeIfPresent(CGFloat.self, forKey: .width)
height = try container.decodeIfPresent(CGFloat.self, forKey: .height)
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encode(inverted, forKey: .inverted)
try container.encodeIfPresent(accessibilityText, forKey: .accessibilityText)
try container.encodeIfPresent(number, forKey: .number)
try container.encodeIfPresent(fillColor, forKey: .fillColor)
try container.encodeIfPresent(borderColorLight, forKey: .borderColorLight)
try container.encodeIfPresent(borderColorDark, forKey: .borderColorDark)
try container.encodeIfPresent(kind, forKey: .kind)
try container.encodeIfPresent(maximumDigits, forKey: .maximumDigits)
try container.encodeIfPresent(size, forKey: .size)
try container.encodeIfPresent(leadingCharacter, forKey: .leadingCharacter)
try container.encodeIfPresent(trailingText, forKey: .trailingText)
try container.encodeIfPresent(dotSize, forKey: .dotSize)
try container.encodeIfPresent(verticalPadding, forKey: .verticalPadding)
try container.encodeIfPresent(hideDot, forKey: .hideDot)
try container.encodeIfPresent(hideBorder, forKey: .hideBorder)
try container.encodeIfPresent(width, forKey: .width)
try container.encodeIfPresent(height, forKey: .height)
}
}

View File

@ -0,0 +1,80 @@
//
// ButtonIcon.swift
// MVMCoreUI
//
// Created by Matt Bruce on 4/12/24.
// Copyright © 2024 Verizon Wireless. All rights reserved.
//
import Foundation
import VDS
open class ButtonIcon: VDS.ButtonIcon, VDSMoleculeViewProtocol {
//--------------------------------------------------
// MARK: - Public Properties
//--------------------------------------------------
public var viewModel: ButtonIconModel!
public var delegateObject: MVMCoreUIDelegateObject?
public var additionalData: [AnyHashable : Any]?
//--------------------------------------------------
// MARK: - Public Methods
//--------------------------------------------------
public func viewModelDidUpdate() {
surface = viewModel.surface
onClick = { [weak self] control in
guard let self, let viewModel = self.viewModel else { return }
MVMCoreUIActionHandler.performActionUnstructured(with: viewModel.action,
sourceModel: viewModel,
additionalData: self.additionalData,
delegateObject: self.delegateObject)
}
badgeIndicatorModel = viewModel.badgeIndicatorModel
kind = viewModel.kind
surfaceType = viewModel.surfaceType
iconName = viewModel.iconName
selectedIconName = viewModel.selectedIconName
size = viewModel.size
customSize = viewModel.customSize
floating = viewModel.floating
fitToIcon = viewModel.fitToIcon
hideBorder = viewModel.hideBorder
showBadgeIndicator = viewModel.showBadgeIndicator
selectable = viewModel.selectable
iconOffset = viewModel.iconOffset
}
public func updateView(_ size: CGFloat) {}
//--------------------------------------------------
// MARK: - Overrides
//--------------------------------------------------
open override func updateAccessibility() {
super.updateAccessibility()
if let viewModel {
if let accessibilityText = viewModel.accessibilityText {
//since this is a container control and the
//icon & badgeIndicator (gets from it's own model) are traversed separatly
icon.accessibilityLabel = accessibilityText
}
}
}
}
//to deal with how it's parent constrains this control
extension ButtonIcon: MVMCoreUIViewConstrainingProtocol {
public func needsToBeConstrained() -> Bool { true }
public func horizontalAlignment() -> UIStackView.Alignment { .leading }
}

View File

@ -0,0 +1,142 @@
//
// ButtonIconModel.swift
// MVMCoreUI
//
// Created by Matt Bruce on 4/12/24.
// Copyright © 2024 Verizon Wireless. All rights reserved.
//
import Foundation
import VDS
open class ButtonIconModel: ButtonModelProtocol, MoleculeModelProtocol {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
public static var identifier: String = "buttonIcon"
public var id: String = UUID().uuidString
public var backgroundColor: Color?
//--------------------------------------------------
// MARK: - VDS Properties
//--------------------------------------------------
public var surface: Surface { inverted ? .dark : .light }
public var inverted: Bool = false
public var accessibilityText: String?
public var action: ActionModelProtocol
public var kind = ButtonIcon.Kind.ghost
public var surfaceType = ButtonIcon.SurfaceType.colorFill
public var iconName: Icon.Name = .info
public var selectedIconName: Icon.Name?
public var size = ButtonIcon.Size.large
public var customSize : Int?
public var floating: Bool = false
public var fitToIcon: Bool = false
public var hideBorder: Bool = true
public var showBadgeIndicator: Bool = false
public var selectable: Bool = false
public var iconOffset: CGPoint = .zero
public var badgeIndicatorModel: VDS.ButtonIcon.BadgeIndicatorModel? {
guard let model = badgeIndicator else { return nil }
return .init(kind: model.kind,
fillColor: model.fillColor,
expandDirection: expandDirection,
size: model.size,
maximumDigits: model.maximumDigits,
width: model.width,
height: model.height,
number: model.number,
leadingCharacter: model.leadingCharacter,
trailingText: model.trailingText,
dotSize: model.dotSize,
verticalPadding: model.verticalPadding,
horizontalPadding: model.horizontalPadding,
hideDot: model.hideDot,
hideBorder: model.hideBorder)
}
private var badgeIndicator: BadgeIndicatorModel?
private var expandDirection = ButtonIcon.BadgeIndicatorModel.ExpandDirection.right
//--------------------------------------------------
// MARK: - Initializers
//--------------------------------------------------
public init(with iconName: VDS.Icon.Name, action: ActionModelProtocol) {
self.iconName = iconName
self.action = action
}
//--------------------------------------------------
// MARK: - Keys
//--------------------------------------------------
private enum CodingKeys: String, CodingKey {
case id
case inverted
case accessibilityText
case action
case badgeIndicator
case expandDirection
case kind
case surfaceType
case iconName
case selectedIconName
case size
case customSize
case floating
case fitToIcon
case hideBorder
case showBadgeIndicator
case selectable
case iconOffset
}
//--------------------------------------------------
// MARK: - Codec
//--------------------------------------------------
required public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
action = try container.decodeModel(codingKey: .action)
id = try container.decodeIfPresent(String.self, forKey: .id) ?? UUID().uuidString
inverted = try container.decodeIfPresent(Bool.self, forKey: .inverted) ?? false
accessibilityText = try container.decodeIfPresent(String.self, forKey: .accessibilityText)
badgeIndicator = try container.decodeIfPresent(BadgeIndicatorModel.self, forKey: .badgeIndicator)
expandDirection = try container.decodeIfPresent(ButtonIcon.BadgeIndicatorModel.ExpandDirection.self, forKey: .expandDirection) ?? .right
kind = try container.decodeIfPresent(ButtonIcon.Kind.self, forKey: .kind) ?? .ghost
surfaceType = try container.decodeIfPresent(ButtonIcon.SurfaceType.self, forKey: .kind) ?? .colorFill
iconName = try container.decode(Icon.Name.self, forKey: .iconName)
selectedIconName = try container.decodeIfPresent(Icon.Name.self, forKey: .selectedIconName)
size = try container.decodeIfPresent(ButtonIcon.Size.self, forKey: .size) ?? .large
customSize = try container.decodeIfPresent(Int.self, forKey: .customSize)
floating = try container.decodeIfPresent(Bool.self, forKey: .floating) ?? false
fitToIcon = try container.decodeIfPresent(Bool.self, forKey: .fitToIcon) ?? false
hideBorder = try container.decodeIfPresent(Bool.self, forKey: .hideBorder) ?? false
showBadgeIndicator = try container.decodeIfPresent(Bool.self, forKey: .showBadgeIndicator) ?? false
selectable = try container.decodeIfPresent(Bool.self, forKey: .selectable) ?? false
iconOffset = try container.decodeIfPresent(CGPoint.self, forKey: .iconOffset) ?? .zero
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encode(inverted, forKey: .inverted)
try container.encodeIfPresent(accessibilityText, forKey: .accessibilityText)
try container.encodeIfPresent(badgeIndicator, forKey: .badgeIndicator)
try container.encodeIfPresent(expandDirection, forKey: .expandDirection)
try container.encodeIfPresent(kind, forKey: .kind)
try container.encodeIfPresent(surfaceType, forKey: .kind)
try container.encode(iconName, forKey: .iconName)
try container.encodeIfPresent(selectedIconName, forKey: .selectedIconName)
try container.encodeIfPresent(size, forKey: .size)
try container.encodeIfPresent(customSize, forKey: .customSize)
try container.encodeIfPresent(floating, forKey: .floating)
try container.encodeIfPresent(fitToIcon, forKey: .fitToIcon)
try container.encodeIfPresent(hideBorder, forKey: .hideBorder)
try container.encodeIfPresent(showBadgeIndicator, forKey: .showBadgeIndicator)
try container.encodeIfPresent(selectable, forKey: .selectable)
try container.encodeIfPresent(iconOffset, forKey: .iconOffset)
}
}

View File

@ -5,7 +5,7 @@
// Created by Kevin Christiano on 1/30/20.
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import VDSColorTokens
import VDSTokens
open class CarouselIndicator: Control, CarouselPageControlProtocol {
//--------------------------------------------------

View File

@ -7,7 +7,7 @@
//
import Foundation
import VDSColorTokens
import VDSTokens
open class CarouselIndicatorModel: CarouselPagingModelProtocol, MoleculeModelProtocol, EnableableModelProtocol {
//--------------------------------------------------

View File

@ -64,9 +64,8 @@
bottomLabelConstraint.isActive = true
alignCheckbox(.center)
isAccessibilityElement = true
accessibilityHint = checkbox.accessibilityHint
accessibilityTraits = checkbox.accessibilityTraits
isAccessibilityElement = false
accessibilityElements = [checkbox, label]
observation = observe(\.checkbox.isSelected, options: [.new]) { [weak self] _, _ in
self?.updateAccessibilityLabel()
}
@ -139,6 +138,8 @@
open func updateAccessibilityLabel() {
checkbox.updateAccessibilityLabel()
accessibilityLabel = [checkbox.accessibilityLabel, label.text].compactMap { $0 }.joined(separator: ",")
if let text = label.text {
checkbox.accessibilityLabel?.append(", \(text)")
}
}
}

View File

@ -8,7 +8,7 @@
import Foundation
import VDS
import VDSColorTokens
import VDSTokens
open class IconModel: MoleculeModelProtocol {

View File

@ -7,7 +7,7 @@
//
import UIKit
import VDSColorTokens
import VDSTokens
import VDS
public class LineModel: MoleculeModelProtocol, Invertable {

View File

@ -0,0 +1,139 @@
//
// TileContainer.swift
// MVMCoreUI
//
// Created by Matt Bruce on 4/15/24.
// Copyright © 2024 Verizon Wireless. All rights reserved.
//
import Foundation
import VDS
import Combine
open class TileContainer: VDS.TileContainer, VDSMoleculeViewProtocol{
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
public var model: MoleculeModelProtocol?
public var viewModel: TileContainerModel!
public var delegateObject: MVMCoreUIDelegateObject?
public var additionalData: [AnyHashable: Any]?
public var molecule: MoleculeViewProtocol? {
willSet {
if newValue == nil {
molecule?.removeFromSuperview()
}
}
}
//--------------------------------------------------
// MARK: - Initializers
//--------------------------------------------------
public convenience required init() {
self.init(frame: .zero)
}
//--------------------------------------------------
// MARK: - Public
//--------------------------------------------------
public func viewModelDidUpdate() {
if let moleculeModel = viewModel.molecule {
if let molecule,
moleculeModel.moleculeName == molecule.model?.moleculeName {
molecule.set(with: moleculeModel, delegateObject, additionalData)
} else if let moleculeView = ModelRegistry.createMolecule(moleculeModel, delegateObject: delegateObject, additionalData: additionalData) {
molecule = moleculeView
addContentView(moleculeView)
}
}
// set backgroundImage
if let imageName = viewModel.backgroundImage {
loadImage(imageName)
}
//set action
if let action = viewModel.action {
//add the subscriber
onClick = { [weak self] control in
guard let self, let viewModel = self.viewModel else { return }
MVMCoreUIActionHandler.performActionUnstructured(with: action,
sourceModel: viewModel,
additionalData: self.additionalData,
delegateObject: self.delegateObject)
}
}
//set the rest of the properties
surface = viewModel.surface
imageFallbackColor = viewModel.imageFallbackColor
width = viewModel.width
height = viewModel.height
showBorder = viewModel.showBorder
showDropShadow = viewModel.showDropShadow
padding = viewModel.padding
color = viewModel.color
aspectRatio = viewModel.aspectRatio
backgroundEffect = viewModel.backgroundEffect
}
private func loadImage(_ imageName: String? = nil) {
guard let imageName else {
if backgroundImage != nil {
backgroundImage = nil
}
return
}
let finishedLoadingBlock: MVMCoreGetImageBlock = {[weak self] (image, data, isFallbackImage) in MVMCoreDispatchUtility.performBlock(onMainThread: { [weak self] in
guard let self = self else { return }
self.backgroundImage = image
})}
MVMCoreCache.shared()?.getImage(imageName, useWidth: false, widthForS7: 0, useHeight: false, heightForS7: 0, format: nil, localFallbackImageName: nil, allowServerQueryParameters: false, localBundle: nil, completionHandler: finishedLoadingBlock)
}
//--------------------------------------------------
// MARK: - MVMCoreViewProtocol
//--------------------------------------------------
open func updateView(_ size: CGFloat) {}
//--------------------------------------------------
// MARK: - MoleculeViewProtocol
//--------------------------------------------------
//since this is a class func, we can't reference it directly
public static func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
100
}
/// Allows the molecule to set its name for reuse. Default could be moleculeName. Mainly used for list or collections.
public static func nameForReuse(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> String? {
// This will aggregate names of molecules to make an id.
guard let containerModel = model as? TileContainerModel,
let molecule = containerModel.molecule,
let moleculeClass = ModelRegistry.getMoleculeClass(molecule),
let moleculeName = moleculeClass.nameForReuse(with: molecule, delegateObject)
else { return "\(model.moleculeName)<>" }
return "\(model.moleculeName)<\(moleculeName)>"
}
//--------------------------------------------------
// MARK: - Overrides
//--------------------------------------------------
open override func layoutSubviews() {
super.layoutSubviews()
// Accounts for any collection size changes
DispatchQueue.main.async { [weak self] in
guard let self else { return }
self.delegateObject?.moleculeDelegate?.moleculeLayoutUpdated(self)
}
}
}
extension TileContainer: MVMCoreUIViewConstrainingProtocol {
public func horizontalAlignment() -> UIStackView.Alignment { .leading }
}

View File

@ -0,0 +1,117 @@
//
// TileContainerModel.swift
// MVMCoreUI
//
// Created by Matt Bruce on 4/15/24.
// Copyright © 2024 Verizon Wireless. All rights reserved.
//
import Foundation
import VDS
open class TileContainerModel: TileContainerBaseModel<TileContainer.Padding, TileContainer>, ParentMoleculeModelProtocol, MoleculeModelProtocol {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
public static var identifier: String = "tileContainer"
public var id: String = UUID().uuidString
public var backgroundColor: Color?
public var molecule: MoleculeModelProtocol?
public var children: [any MoleculeModelProtocol] {
guard let molecule else { return [] }
return [molecule]
}
public func replaceChildMolecule(with molecule: MoleculeModelProtocol) throws -> Bool {
return try replaceChildMolecule(at: &self.molecule, with: molecule)
}
private enum CodingKeys: String, CodingKey {
case id
case moleculeName
case molecule
}
required public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decodeIfPresent(String.self, forKey: .id) ?? UUID().uuidString
molecule = try container.decodeModelIfPresent(codingKey: .molecule)
try super.init(from: decoder)
}
public override func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encode(moleculeName, forKey: .moleculeName)
try container.encodeModelIfPresent(molecule, forKey: .molecule)
try super.encode(to: encoder)
}
}
open class TileContainerBaseModel<PaddingType: DefaultValuing & Codable, TileContainerType:TileContainerBase<PaddingType>> : Codable{
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
public var inverted: Bool = false
public var backgroundImage: String?
public var action: ActionModelProtocol?
public var imageFallbackColor: Surface = .light
public var width: CGFloat?
public var height: CGFloat?
public var showBorder: Bool = false
public var showDropShadow: Bool = false
public var padding = PaddingType.defaultValue
public var color: TileContainerType.BackgroundColor = .black
public var aspectRatio: TileContainerType.AspectRatio = .ratio1x1
public var backgroundEffect: TileContainerType.BackgroundEffect = .none
public var surface: Surface { inverted ? .dark : .light }
private enum CodingKeys: String, CodingKey {
case inverted
case backgroundImage
case action
case imageFallbackColor
case width
case height
case showBorder
case showDropShadow
case padding
case color
case aspectRatio
case backgroundEffect
}
required public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
inverted = try container.decodeIfPresent(Bool.self, forKey: .inverted) ?? false
backgroundImage = try container.decodeIfPresent(String.self, forKey: .backgroundImage)
action = try container.decodeModelIfPresent(codingKey: .action)
imageFallbackColor = try container.decodeIfPresent(VDS.Surface.self, forKey: .imageFallbackColor) ?? .light
width = try container.decodeIfPresent(CGFloat.self, forKey: .width)
height = try container.decodeIfPresent(CGFloat.self, forKey: .height)
showBorder = try container.decodeIfPresent(Bool.self, forKey: .showBorder) ?? false
showDropShadow = try container.decodeIfPresent(Bool.self, forKey: .showDropShadow) ?? false
padding = try container.decodeIfPresent(PaddingType.self, forKey: .padding) ?? PaddingType.defaultValue
color = try container.decodeIfPresent(TileContainerType.BackgroundColor.self, forKey: .color) ?? .black
aspectRatio = try container.decodeIfPresent(TileContainerType.AspectRatio.self, forKey: .aspectRatio) ?? .ratio1x1
backgroundEffect = try container.decodeIfPresent(TileContainerType.BackgroundEffect.self, forKey: .backgroundEffect) ?? .none
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encodeIfPresent(backgroundImage, forKey: .backgroundImage)
try container.encodeModelIfPresent(action, forKey: .action)
try container.encodeIfPresent(imageFallbackColor, forKey: .imageFallbackColor)
try container.encodeIfPresent(width, forKey: .width)
try container.encodeIfPresent(height, forKey: .height)
try container.encodeIfPresent(showBorder, forKey: .showBorder)
try container.encodeIfPresent(showDropShadow, forKey: .showDropShadow)
try container.encodeIfPresent(padding, forKey: .padding)
try container.encodeIfPresent(color, forKey: .color)
try container.encodeIfPresent(aspectRatio, forKey: .aspectRatio)
try container.encodeIfPresent(backgroundEffect, forKey: .backgroundEffect)
}
}

View File

@ -39,10 +39,7 @@ open class Tilelet: VDS.Tilelet, VDSMoleculeViewProtocol{
// MARK: - Public
//--------------------------------------------------
public func viewModelDidUpdate() {
color = viewModel.color
padding = viewModel.padding
aspectRatio = viewModel.aspectRatio
width = viewModel.width
//tilelet specific properties
if let value = viewModel.textWidth {
textWidth = .value(value)
} else if let percentage = viewModel.textPercentage {
@ -64,6 +61,51 @@ open class Tilelet: VDS.Tilelet, VDSMoleculeViewProtocol{
delegateObject: self.delegateObject)
}
}
// TileContainer properties
// set backgroundImage
if let imageName = viewModel.backgroundImage {
loadImage(imageName)
}
//set action
if let action = viewModel.action {
//add the subscriber
onClick = { [weak self] control in
guard let self, let viewModel = self.viewModel else { return }
MVMCoreUIActionHandler.performActionUnstructured(with: action,
sourceModel: viewModel,
additionalData: self.additionalData,
delegateObject: self.delegateObject)
}
}
//set the rest of the properties
surface = viewModel.surface
imageFallbackColor = viewModel.imageFallbackColor
width = viewModel.width
height = viewModel.height
showBorder = viewModel.showBorder
showDropShadow = viewModel.showDropShadow
padding = viewModel.padding
color = viewModel.color
aspectRatio = viewModel.aspectRatio
backgroundEffect = viewModel.backgroundEffect
}
private func loadImage(_ imageName: String? = nil) {
guard let imageName else {
if backgroundImage != nil {
backgroundImage = nil
}
return
}
let finishedLoadingBlock: MVMCoreGetImageBlock = {[weak self] (image, data, isFallbackImage) in MVMCoreDispatchUtility.performBlock(onMainThread: { [weak self] in
guard let self = self else { return }
self.backgroundImage = image
})}
MVMCoreCache.shared()?.getImage(imageName, useWidth: false, widthForS7: 0, useHeight: false, heightForS7: 0, format: nil, localFallbackImageName: nil, allowServerQueryParameters: false, localBundle: nil, completionHandler: finishedLoadingBlock)
}
//--------------------------------------------------

View File

@ -9,7 +9,7 @@
import Foundation
import VDS
open class TileletModel: MoleculeModelProtocol {
open class TileletModel: TileContainerBaseModel<Tilelet.Padding, Tilelet>, MoleculeModelProtocol {
//--------------------------------------------------
// MARK: - Properties
@ -17,52 +17,37 @@ open class TileletModel: MoleculeModelProtocol {
public static var identifier: String = "tilelet"
public var id: String = UUID().uuidString
public var backgroundColor: Color?
public var color: Tilelet.BackgroundColor
public var padding: Tilelet.Padding
public var aspectRatio: Tilelet.AspectRatio
public var badge: Tilelet.BadgeModel?
public var title: LabelModel?
public var subTitle: LabelModel?
public var descriptiveIcon: Tilelet.DescriptiveIcon?
public var directionalIcon: Tilelet.DirectionalIcon?
public var width: CGFloat?
public var textWidth: CGFloat?
public var textPercentage: CGFloat?
public var action: ActionModelProtocol?
private enum CodingKeys: String, CodingKey {
case id
case moleculeName
case backgroundColor
case color
case padding
case aspectRatio
case badge
case title
case subTitle
case descriptiveIcon
case directionalIcon
case width
case textWidth
case textPercentage
case action
}
required public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.id = try container.decodeIfPresent(String.self, forKey: .id) ?? UUID().uuidString
self.backgroundColor = try container.decodeIfPresent(Color.self, forKey: .backgroundColor)
self.color = try container.decodeIfPresent(Tilelet.BackgroundColor.self, forKey: .color) ?? Tilelet.BackgroundColor.black
self.padding = try container.decodeIfPresent(Tilelet.Padding.self, forKey: .padding) ?? Tilelet.Padding.small
self.aspectRatio = try container.decodeIfPresent(Tilelet.AspectRatio.self, forKey: .aspectRatio) ?? Tilelet.AspectRatio.none
self.badge = try container.decodeIfPresent(Tilelet.BadgeModel.self, forKey: .badge)
self.title = try container.decodeIfPresent(LabelModel.self, forKey: .title)
self.subTitle = try container.decodeIfPresent(LabelModel.self, forKey: .subTitle)
self.descriptiveIcon = try container.decodeIfPresent(Tilelet.DescriptiveIcon.self, forKey: .descriptiveIcon)
self.directionalIcon = try container.decodeIfPresent(Tilelet.DirectionalIcon.self, forKey: .directionalIcon)
self.width = try container.decodeIfPresent(CGFloat.self, forKey: .width)
self.textWidth = try container.decodeIfPresent(CGFloat.self, forKey: .textWidth)
self.textPercentage = try container.decodeIfPresent(CGFloat.self, forKey: .textPercentage)
action = try container.decodeModelIfPresent(codingKey: .action)
id = try container.decodeIfPresent(String.self, forKey: .id) ?? UUID().uuidString
badge = try container.decodeIfPresent(Tilelet.BadgeModel.self, forKey: .badge)
title = try container.decodeIfPresent(LabelModel.self, forKey: .title)
subTitle = try container.decodeIfPresent(LabelModel.self, forKey: .subTitle)
descriptiveIcon = try container.decodeIfPresent(Tilelet.DescriptiveIcon.self, forKey: .descriptiveIcon)
directionalIcon = try container.decodeIfPresent(Tilelet.DirectionalIcon.self, forKey: .directionalIcon)
textWidth = try container.decodeIfPresent(CGFloat.self, forKey: .textWidth)
textPercentage = try container.decodeIfPresent(CGFloat.self, forKey: .textPercentage)
try super.init(from: decoder)
}
public func titleModel(delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> Tilelet.TitleModel? {
@ -99,22 +84,17 @@ open class TileletModel: MoleculeModelProtocol {
return .init(text: subTitle.text, textAttributes: attrs)
}
public func encode(to encoder: Encoder) throws {
public override func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encode(moleculeName, forKey: .moleculeName)
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
try container.encodeIfPresent(color, forKey: .color)
try container.encodeIfPresent(padding, forKey: .padding)
try container.encodeIfPresent(aspectRatio, forKey: .aspectRatio)
try container.encodeIfPresent(badge, forKey: .badge)
try container.encodeIfPresent(title, forKey: .title)
try container.encodeIfPresent(subTitle, forKey: .subTitle)
try container.encodeIfPresent(descriptiveIcon, forKey: .descriptiveIcon)
try container.encodeIfPresent(directionalIcon, forKey: .directionalIcon)
try container.encodeIfPresent(width, forKey: .width)
try container.encodeIfPresent(textWidth, forKey: .textWidth)
try container.encodeIfPresent(textPercentage, forKey: .textPercentage)
try container.encodeModelIfPresent(action, forKey: .action)
try super.encode(to: encoder)
}
}

View File

@ -8,7 +8,7 @@
import Foundation
import VDS
import VDSColorTokens
import VDSTokens
import MVMCore
open class TooltipModel: MoleculeModelProtocol {

View File

@ -8,7 +8,7 @@
import Foundation
import VDS
import VDSColorTokens
import VDSTokens
//--------------------------------------------------
// MARK: - Codable Extensions
@ -16,6 +16,14 @@ import VDSColorTokens
extension VDS.Surface: Codable {}
extension VDS.Badge.FillColor: Codable {}
extension VDS.BadgeIndicator.FillColor: Codable {}
extension VDS.BadgeIndicator.Kind: Codable {}
extension VDS.BadgeIndicator.MaximumDigits: Codable {}
extension VDS.BadgeIndicator.Size: Codable {}
extension VDS.ButtonIcon.Kind: Codable {}
extension VDS.ButtonIcon.Size: Codable {}
extension VDS.ButtonIcon.BadgeIndicatorModel.ExpandDirection: Codable {}
extension VDS.ButtonIcon.SurfaceType: Codable {}
extension VDS.ButtonGroup.Alignment: Codable {}
extension VDS.Icon.Name: Codable {}
extension VDS.Icon.Size: Codable {}
@ -92,6 +100,53 @@ extension VDS.TileContainerBase.BackgroundColor: Codable {
}
}
extension VDS.TileContainerBase.BackgroundEffect: Codable {
enum CodingKeys: String, CodingKey {
case type
case firstColor
case secondColor
}
enum BackgroundEffectType: String, Codable {
case transparency
case none
case gradient
}
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let type = try container.decode(BackgroundEffectType.self, forKey: .type)
switch type {
case .transparency:
self = .transparency
case .none:
self = .none
case .gradient:
let firstColor = try container.decode(String.self, forKey: .firstColor)
let secondColor = try container.decode(String.self, forKey: .secondColor)
self = .gradient(firstColor, secondColor)
}
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
switch self {
case .transparency:
try container.encode(BackgroundEffectType.transparency.rawValue, forKey: .type)
case .none:
try container.encode(BackgroundEffectType.none.rawValue, forKey: .type)
case .gradient(let firstColor, let secondColor):
try container.encode(BackgroundEffectType.gradient.rawValue, forKey: .type)
try container.encode(firstColor, forKey: .firstColor)
try container.encode(secondColor, forKey: .secondColor)
@unknown default:
break
}
}
}
extension VDS.TileContainer.Padding: Codable {
enum PaddingError: Error {
case valueNotFound(type: String)
@ -112,8 +167,8 @@ extension VDS.TileContainer.Padding: Codable {
do {
let type = try container.decode(String.self)
switch type {
case "padding2X":
self = .padding2X
case "padding3X":
self = .padding3X
case "padding4X":
self = .padding4X
case "padding6X":

View File

@ -74,7 +74,7 @@ public class HeadersH2ButtonsModel: HeaderModel, MoleculeModelProtocol, ParentMo
required public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
titleLockup = try typeContainer.decodeMolecule(codingKey: .titleLockup)
titleLockup = try helper.deprecatedCreate(from: decoder) ?? typeContainer.decodeMolecule(codingKey: .titleLockup)
buttons = try typeContainer.decode(TwoButtonViewModel.self, forKey: .buttons)
try super.init(from: decoder)
}

View File

@ -67,7 +67,7 @@ public class HeadersH2CaretLinkModel: HeaderModel, MoleculeModelProtocol, Parent
//--------------------------------------------------
required public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
titleLockup = try typeContainer.decodeMolecule(codingKey: .titleLockup)
titleLockup = try helper.deprecatedCreate(from: decoder) ?? typeContainer.decodeMolecule(codingKey: .titleLockup)
caretLink = try typeContainer.decode(CaretLinkModel.self, forKey: .caretLink)
try super.init(from: decoder)
}

View File

@ -73,7 +73,7 @@ public class HeadersH2LinkModel: HeaderModel, MoleculeModelProtocol, ParentMolec
required public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
titleLockup = try typeContainer.decodeMolecule(codingKey: .titleLockup)
titleLockup = try helper.deprecatedCreate(from: decoder) ?? typeContainer.decodeMolecule(codingKey: .titleLockup)
link = try typeContainer.decode(LinkModel.self, forKey: .link)
try super.init(from: decoder)
}

View File

@ -76,7 +76,7 @@ public class HeadersH2TinyButtonModel: HeaderModel, MoleculeModelProtocol, Paren
required public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
titleLockup = try typeContainer.decodeMolecule(codingKey: .titleLockup)
titleLockup = try helper.deprecatedCreate(from: decoder) ?? typeContainer.decodeMolecule(codingKey: .titleLockup)
button = try typeContainer.decode(ButtonModel.self, forKey: .button)
try super.init(from: decoder)
}

View File

@ -6,7 +6,7 @@
// Copyright © 2022 Verizon Wireless. All rights reserved.
//
import VDSColorTokens
import VDSTokens
import VDS
public class TitleLockupModel: MoleculeModelProtocol, ParentMoleculeModelProtocol {

View File

@ -5,7 +5,7 @@
// Created by Scott Pfeil on 5/28/20.
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import VDSColorTokens
import VDSTokens
@objcMembers open class TabBar: UITabBar, MoleculeViewProtocol, TabBarProtocol, UITabBarDelegate {

View File

@ -7,7 +7,7 @@
//
import Foundation
import VDSColorTokens
import VDSTokens
open class TabBarModel: MoleculeModelProtocol {
public static var identifier: String = "tabBar"

View File

@ -7,7 +7,7 @@
//
import UIKit
import VDSColorTokens
import VDSTokens
import VDS
@objc public protocol TabsDelegate {

View File

@ -7,7 +7,7 @@
//
import UIKit
import VDSColorTokens
import VDSTokens
import VDS
open class TabsModel: MoleculeModelProtocol {

View File

@ -6,7 +6,7 @@
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import VDSColorTokens
import VDSTokens
public enum NavigationItemStyle: String, Codable {
case light

View File

@ -10,6 +10,7 @@ import Foundation
import Combine
import Dispatch
import MVMCore
import VDSTokens
@objcMembers open class CollapsableNotification: View {
//--------------------------------------------------
@ -50,7 +51,7 @@ import MVMCore
open override func reset() {
super.reset()
verticalStack.reset()
backgroundColor = .mvmGreen()
backgroundColor = bottomView.backgroundColor
}
open func subscribeForNotifications() {
@ -98,6 +99,8 @@ import MVMCore
guard let model = model as? CollapsableNotificationModel else { return }
topView.set(with: model, delegateObject, additionalData)
bottomView.set(with: model, delegateObject, additionalData)
topView.label.textColorConfiguration = bottomView.titleLabel.textColorConfiguration
topView.label.surface = bottomView.surface
// Update top view default noop to expand.
if let topAction = model.topAction,
@ -110,6 +113,7 @@ import MVMCore
}
}
initialState()
backgroundColor = bottomView.backgroundColor
}
open func performBlockOperation(with block: @escaping (MVMCoreBlockOperation) -> Void) {
@ -214,7 +218,7 @@ import MVMCore
extension CollapsableNotification: StatusBarUI {
public func getStatusBarUI() -> (color: UIColor, style: UIStatusBarStyle) {
let color = backgroundColor ?? UIColor.mvmGreen
let color = backgroundColor ?? VDSColor.feedbackInformationBackgroundOnlight
var greyScale: CGFloat = 0
topView.label.textColor.getWhite(&greyScale, alpha: nil)
return (color, greyScale > 0.5 ? .lightContent : .default)
@ -226,7 +230,7 @@ extension CollapsableNotification: AccessibilityProtocol {
if !topView.isHidden {
return topView
} else {
return bottomView.headline
return bottomView.titleLabel
}
}
}

View File

@ -26,21 +26,13 @@ open class CollapsableNotificationModel: NotificationMoleculeModel {
self.collapseTime = collapseTime
}
super.init(with: headline, style: style, backgroundColor: backgroundColor, body: body, button: button, closeButton: closeButton)
setDefaults()
}
open override func setDefaults() {
super.setDefaults()
open func setDefaults() {
if topLabel.numberOfLines == nil {
topLabel.numberOfLines = 1
}
if topLabel.textColor == nil {
switch style {
case .error, .warning:
topLabel.textColor = Color(uiColor: .mvmBlack)
default:
topLabel.textColor = Color(uiColor: .mvmWhite)
}
}
if topLabel.textAlignment == nil {
topLabel.textAlignment = .center
}
@ -69,6 +61,7 @@ open class CollapsableNotificationModel: NotificationMoleculeModel {
self.initiallyCollapsed = initiallyCollapsed
}
try super.init(from: decoder)
setDefaults()
}
open override func encode(to encoder: Encoder) throws {

View File

@ -52,7 +52,7 @@ import Foundation
open override func reset() {
super.reset()
label.setFontStyle(.BoldBodySmall)
label.textColor = .white
label.textColor = .black
label.textAlignment = .center
}

View File

@ -5,9 +5,9 @@
// Created by Scott Pfeil on 9/15/20.
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import VDS
open class NotificationMoleculeModel: ContainerModel, MoleculeModelProtocol {
open class NotificationMoleculeModel: MoleculeModelProtocol {
/**
The style of the notification:
@ -21,91 +21,48 @@ open class NotificationMoleculeModel: ContainerModel, MoleculeModelProtocol {
case error
case warning
case information
var toVDSStyle: VDS.Notification.Style {
switch self {
case .success:
.success
case .error:
.error
case .warning:
.warning
case .information:
.info
}
}
}
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
public var id: String = UUID().uuidString
public class var identifier: String { "notification" }
public var accessibilityIdentifier: String?
public var backgroundColor: Color?
public var headline: LabelModel
public var body: LabelModel?
public var button: ButtonModel?
public var secondaryButton: ButtonModel?
public var closeButton: NotificationXButtonModel?
public var style: NotificationMoleculeModel.Style = .success
public var style: Style = .success
public var inverted: Bool = false
//--------------------------------------------------
// MARK: - Initializer
//--------------------------------------------------
public init(with headline: LabelModel, style: NotificationMoleculeModel.Style = .success, backgroundColor: Color? = nil, body: LabelModel? = nil, button: ButtonModel? = nil, closeButton: NotificationXButtonModel? = nil) {
public init(with headline: LabelModel, style: NotificationMoleculeModel.Style = .success, backgroundColor: Color? = nil, body: LabelModel? = nil, button: ButtonModel? = nil, secondaryButton: ButtonModel? = nil, closeButton: NotificationXButtonModel? = nil) {
self.headline = headline
self.style = style
self.backgroundColor = backgroundColor
self.body = body
self.button = button
self.secondaryButton = secondaryButton
self.closeButton = closeButton
super.init()
}
//--------------------------------------------------
// MARK: - Default
//--------------------------------------------------
open override func setDefaults() {
useHorizontalMargins = true
useVerticalMargins = true
topPadding = PaddingTwo
bottomPadding = PaddingTwo
if backgroundColor == nil {
switch style {
case .error:
backgroundColor = Color(uiColor: .mvmOrange)
case .warning:
backgroundColor = Color(uiColor: .mvmYellow)
case .information:
backgroundColor = Color(uiColor: .mvmBlue)
default:
backgroundColor = Color(uiColor: .mvmGreen)
}
}
if headline.textColor == nil {
switch style {
case .error, .warning:
headline.textColor = Color(uiColor: .mvmBlack)
default:
headline.textColor = Color(uiColor: .mvmWhite)
}
}
if body?.textColor == nil {
switch style {
case .error, .warning:
body?.textColor = Color(uiColor: .mvmBlack)
default:
body?.textColor = Color(uiColor: .mvmWhite)
}
}
button?.size = .small
button?.style = .secondary
switch style {
case .error, .warning:
button?.inverted = false
default:
button?.inverted = true
}
if closeButton?.color == nil {
switch style {
case .error, .warning:
closeButton?.color = Color(uiColor: .mvmBlack)
default:
closeButton?.color = Color(uiColor: .mvmWhite)
}
}
}
//--------------------------------------------------
@ -119,7 +76,9 @@ open class NotificationMoleculeModel: ContainerModel, MoleculeModelProtocol {
case headline
case body
case button
case secondaryButton
case closeButton
case inverted
case style
}
@ -129,27 +88,34 @@ open class NotificationMoleculeModel: ContainerModel, MoleculeModelProtocol {
required public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
accessibilityIdentifier = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityIdentifier)
headline = try typeContainer.decode(LabelModel.self, forKey: .headline)
body = try typeContainer.decodeIfPresent(LabelModel.self, forKey: .body)
button = try typeContainer.decodeIfPresent(ButtonModel.self, forKey: .button)
secondaryButton = try typeContainer.decodeIfPresent(ButtonModel.self, forKey: .secondaryButton)
closeButton = try typeContainer.decodeIfPresent(NotificationXButtonModel.self, forKey: .closeButton)
inverted = try typeContainer.decodeIfPresent(Bool.self, forKey: .inverted) ?? false
if let style = try typeContainer.decodeIfPresent(NotificationMoleculeModel.Style.self, forKey: .style) {
self.style = style
}
super.init()
}
open override func encode(to encoder: Encoder) throws {
open func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(moleculeName, forKey: .moleculeName)
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier)
try container.encode(headline, forKey: .headline)
try container.encodeIfPresent(body, forKey: .body)
try container.encodeIfPresent(button, forKey: .button)
try container.encodeIfPresent(secondaryButton, forKey: .secondaryButton)
try container.encodeIfPresent(closeButton, forKey: .closeButton)
try container.encodeIfPresent(inverted, forKey: .inverted)
try container.encode(style, forKey: .style)
}
}
extension NotificationMoleculeModel {
public var surface: Surface {
inverted ? .dark : .light
}
}

View File

@ -7,90 +7,101 @@
//
import Foundation
@objcMembers open class NotificationMoleculeView: Container {
import VDS
@objcMembers open class NotificationMoleculeView: VDS.Notification, VDSMoleculeViewProtocol {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
open var viewModel: NotificationMoleculeModel!
public var delegateObject: MVMCoreUIDelegateObject?
public var additionalData: [AnyHashable: Any]?
//--------------------------------------------------
// MARK: - VDSMoleculeViewProtocol
//--------------------------------------------------
open func viewModelDidUpdate() {
surface = viewModel.surface
title = viewModel.headline.text
subTitle = viewModel.body?.text
if let button = viewModel.button {
primaryButtonModel = .init(text: button.title, onClick: {[weak self] _ in
guard let self else { return }
self.executeAction(model: button, delegateObject: self.delegateObject, additionalData: self.additionalData)
})
}
if let secondaryButton = viewModel.secondaryButton {
secondaryButtonModel = .init(text: secondaryButton.title, onClick: {[weak self] _ in
guard let self else { return }
self.executeAction(model: secondaryButton, delegateObject: self.delegateObject, additionalData: self.additionalData)
})
}
if let accessibilityIdentifier = viewModel.accessibilityIdentifier {
self.accessibilityIdentifier = accessibilityIdentifier
}
if let closeButton = viewModel.closeButton {
onCloseClick = { [weak self] _ in
guard let self else { return }
self.executeAction(model: closeButton, delegateObject: self.delegateObject, additionalData: self.additionalData) }
}
hideCloseButton = viewModel.closeButton == nil
style = viewModel.style.toVDSStyle
}
//--------------------------------------------------
// MARK: - Outlets
//--------------------------------------------------
public let headline = Label(fontStyle: .BoldBodySmall)
public let body = Label(fontStyle: .RegularBodySmall)
public let button = PillButton()
public let closeButton = NotificationXButton()
public var labelStack: Stack<StackModel>!
public var horizontalStack: Stack<StackModel>!
// Legacy constant
private static let viewHeight: CGFloat = 96.0
//--------------------------------------------------
// MARK: - Life Cycle
//--------------------------------------------------
public override func setupView() {
super.setupView()
reset()
// Buttons should have highest priority, then headline, then body
headline.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 500), for: .horizontal)
headline.setContentHuggingPriority(.required, for: .vertical)
body.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 500), for: .horizontal)
body.setContentHuggingPriority(.required, for: .vertical)
headline.setContentCompressionResistancePriority(UILayoutPriority(rawValue: body.contentCompressionResistancePriority(for: .vertical).rawValue + 40), for: .vertical)
headline.lineBreakMode = .byTruncatingTail
body.lineBreakMode = .byTruncatingTail
button.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal)
labelStack = Stack<StackModel>.createStack(with: [headline, body], spacing: 0)
horizontalStack = Stack<StackModel>.createStack(with: [(view: labelStack, model: StackItemModel()),(view: button, model: StackItemModel(horizontalAlignment: .fill)),(view: closeButton, model: StackItemModel(horizontalAlignment: .fill))], axis: .horizontal)
addAndContain(horizontalStack)
labelStack.restack()
horizontalStack.restack()
heightAnchor.constraint(equalToConstant: Self.viewHeight).isActive = true
}
open override func reset() {
super.reset()
backgroundColor = .mvmGreen()
headline.textColor = .white
body.textColor = .white
open override func updateAccessibility() {
super.updateAccessibility()
Self.amendAccesibilityLabel(for: titleLabel)
Self.amendAccesibilityLabel(for: subTitleLabel)
Self.amendAccesibilityLabel(for: primaryButton)
Self.amendAccesibilityLabel(for: secondaryButton)
Self.amendAccesibilityLabel(for: closeButton)
}
//--------------------------------------------------
// MARK: - Molecule
//--------------------------------------------------
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
super.set(with: model, delegateObject, additionalData)
guard let model = model as? NotificationMoleculeModel else { return }
labelStack.updateContainedMolecules(with: [model.headline, model.body], delegateObject, nil)
horizontalStack.updateContainedMolecules(with: [labelStack.stackModel, model.button, model.closeButton], delegateObject, nil)
updateAccessibility()
}
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
public func updateView(_ size: CGFloat) { }
open class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
return viewHeight
}
open func updateAccessibility() {
NotificationMoleculeView.amendAccesibilityLabel(for: headline)
NotificationMoleculeView.amendAccesibilityLabel(for: body)
NotificationMoleculeView.amendAccesibilityLabel(for: button)
NotificationMoleculeView.amendAccesibilityLabel(for: closeButton)
}
/// Formats the accessibilityLabel so voice over users know it's in the notification.
static public func amendAccesibilityLabel(for view: UIView) {
guard let amendment = MVMCoreUIUtility.hardcodedString(withKey: "top_alert_notification"),
let accessibilityLabel = view.accessibilityLabel,
!accessibilityLabel.hasPrefix(amendment) else { return }
view.accessibilityLabel = "\(amendment) - \(accessibilityLabel)"
public class func amendAccesibilityLabel(for view: UIView?) {
guard let view,
let amendment = MVMCoreUIUtility.hardcodedString(withKey: "top_alert_notification")
else { return }
view.amendAccesibilityLabel(with: amendment)
}
}
extension NotificationMoleculeView: AccessibilityProtocol {
public func getAccessibilityLayoutChangedArgument() -> Any? {
return headline
return titleLabel
}
}
extension UIView {
/// Formats the accessibilityLabel so voice over users know it's in the notification.
public func amendAccesibilityLabel(with amendment: String) {
guard let accessibilityLabel, !accessibilityLabel.hasPrefix(amendment) else { return }
self.accessibilityLabel = "\(amendment) - \(accessibilityLabel)"
}
}

View File

@ -30,7 +30,6 @@ import MVMCore
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) {
super.set(with: model, delegateObject, additionalData)
guard let model = model as? NotificationXButtonModel else { return }
tintColor = model.color?.uiColor ?? .white
// TODO: Temporary, consider action for dismissing top alert
if model.action.actionType == ActionNoopModel.identifier {

View File

@ -15,25 +15,21 @@ public class NotificationXButtonModel: ButtonModelProtocol, MoleculeModelProtoco
public var id: String = UUID().uuidString
public var backgroundColor: Color?
public var color: Color?
public var action: ActionModelProtocol = ActionNoopModel()
private enum CodingKeys: String, CodingKey {
case id
case moleculeName
case color
case action
}
public init(color: Color? = nil, action: ActionModelProtocol = ActionNoopModel()) {
self.color = color
public init(action: ActionModelProtocol = ActionNoopModel()) {
self.action = action
}
public required init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
id = try typeContainer.decodeIfPresent(String.self, forKey: .id) ?? UUID().uuidString
color = try typeContainer.decodeIfPresent(Color.self, forKey: .color)
if let action: ActionModelProtocol = try typeContainer.decodeModelIfPresent(codingKey: .action) {
self.action = action
}
@ -43,7 +39,6 @@ public class NotificationXButtonModel: ButtonModelProtocol, MoleculeModelProtoco
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encode(moleculeName, forKey: .moleculeName)
try container.encodeIfPresent(color, forKey: .color)
try container.encodeModel(action, forKey: .action)
}
}

View File

@ -22,7 +22,8 @@ public protocol MoleculeDelegateProtocol: AnyObject {
/// Notifies the delegate that the molecule layout update. Should be called when the layout may change due to an async method. Mainly used for list or collections.
func moleculeLayoutUpdated(_ molecule: MoleculeViewProtocol) //optional
func replaceMoleculeData(_ moleculeModels: [MoleculeModelProtocol])
/// Attempts to replace the molecules provided. Returns the ones that replaced successfully.
func replaceMoleculeData(_ moleculeModels: [MoleculeModelProtocol], completionHandler: (([MoleculeModelProtocol])->Void)?)
}
extension MoleculeDelegateProtocol {

View File

@ -66,6 +66,14 @@ extension MoleculeViewProtocol {
set(with: model, delegateObject, additionalData)
}
}
public func executeAction<T: ButtonModelProtocol & MoleculeModelProtocol>(model: T, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
Task(priority: .userInitiated) {
try await (delegateObject?.actionDelegate as? ActionDelegateProtocol)?.performAction(with: model.action,
additionalData: MVMCoreUIActionHandler.add(sourceModel: model, to: additionalData),
delegateObject: delegateObject)
}
}
}
// Convenience Functions

View File

@ -21,7 +21,11 @@ public protocol VDSMoleculeViewProtocol: MoleculeViewProtocol, MVMCoreViewProtoc
}
extension VDSMoleculeViewProtocol {
public var model: MoleculeModelProtocol {
get { viewModel }
set { }
}
public func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
self.model = model
guard let castedModel = model as? ViewModel else { return }

View File

@ -511,7 +511,7 @@ import MVMCore
// Needed otherwise when subclassed, the extension gets called.
open func moleculeLayoutUpdated(_ molecule: MoleculeViewProtocol) { }
public func replaceMoleculeData(_ moleculeModels: [MoleculeModelProtocol]) {
public func replaceMoleculeData(_ moleculeModels: [MoleculeModelProtocol], completionHandler: (([MoleculeModelProtocol])->Void)? = nil) {
pageUpdateQueue.addOperation {
let replacedModels:[MoleculeModelProtocol] = moleculeModels.compactMap { model in
guard self.attemptToReplace(with: model) else {
@ -524,6 +524,7 @@ import MVMCore
self.updateUI(for: replacedModels)
}
}
completionHandler?(replacedModels)
}
}

View File

@ -21,8 +21,6 @@ public class ReplaceableMoleculeBehavior: PageMoleculeTransformationBehavior {
private var observingForResponses: NSObjectProtocol?
private var delegateObject: MVMCoreUIDelegateObject?
public var transcendsPageUpdates: Bool { true }
public required init(model: PageBehaviorModelProtocol, delegateObject: MVMCoreUIDelegateObject?) {
moleculeIds = (model as! ReplaceableMoleculeBehaviorModel).moleculeIds
let shouldListenForListUpdates = delegateObject?.moleculeListDelegate != nil
@ -62,7 +60,7 @@ public class ReplaceableMoleculeBehavior: PageMoleculeTransformationBehavior {
}
}
if moleculeModels.count > 0 {
delegateObject?.moleculeDelegate?.replaceMoleculeData(moleculeModels)
delegateObject?.moleculeDelegate?.replaceMoleculeData(moleculeModels, completionHandler: nil)
}
}
@ -95,8 +93,15 @@ public class ReplaceableMoleculeBehavior: PageMoleculeTransformationBehavior {
return nil
}
}
if modules.count > 0 {
delegateObject?.moleculeDelegate?.replaceMoleculeData(modules)
guard modules.count > 0 else { return }
#if LOGGING
let requestParams = (notification.userInfo?["MVMCoreLoadObject"] as? MVMCoreLoadObject)?.requestParameters
MVMCoreLoggingHandler.shared()?.handleDebugMessage("Replacing \(modules.map { $0.id }) from \(requestParams?.url?.absoluteString ?? "unknown"), e2eId: \(requestParams?.identifier ?? "unknown")")
#endif
delegateObject?.moleculeDelegate?.replaceMoleculeData(modules) { replacedModels in
let modules = replacedModels.compactMap { modulesLoaded.dictionaryForKey($0.id) }
guard let viewController = self.delegateObject?.moleculeDelegate as? MVMCoreViewControllerProtocol else { return }
modules.forEach { MVMCoreUILoggingHandler.shared()?.defaultLogPageUpdate(forController: viewController, from: $0) }
}
}

View File

@ -56,6 +56,18 @@ extension UIColor {
"upGold2": (.vzupGold2, "#F4CA53"),
"upGold3": (.vzupGold3, "#CC9B2D")]
//--------------------------------------------------
// MARK: - Helper
//--------------------------------------------------
public var rgbComponents: (red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) {
var red: CGFloat = 0
var green: CGFloat = 0
var blue: CGFloat = 0
var alpha: CGFloat = 0
getRed(&red, green: &green, blue: &blue, alpha: &alpha)
return (red, green, blue, alpha)
}
//--------------------------------------------------
// MARK: - Brand
//--------------------------------------------------

View File

@ -34,6 +34,7 @@ import Combine
public static func setupNavigationControllerAsMainController() -> Self? {
guard let navigationController = setupNavigationController() else { return nil }
MVMCoreUISession.sharedGlobal()?.setup(asStandardLoadViewDelegate: navigationController)
MVMCoreObject.sharedInstance()?.viewControllerManager = navigationController
return navigationController
}
@ -136,6 +137,31 @@ extension NavigationController: MVMCoreViewManagerProtocol {
public func displayedViewController(_ viewController: UIViewController) {
manager?.displayedViewController?(viewController)
}
private func go(to index: Int) async {
guard index != viewControllers.count - 1 else { return }
await NavigationHandler.shared().set(viewControllers: Array(viewControllers[0...index]), navigationController: self)
}
public func navigate(toViewControllerOfPageType pageType: String, controllerType: AnyClass?) async -> UIViewController? {
for (index, controller) in viewControllers.enumerated() {
if let manager = controller as? MVMCoreViewManagerProtocol,
let viewController = await manager.navigate(toViewControllerOfPageType: pageType, controllerType: controllerType) {
await go(to: index)
return viewController
} else if let controller = controller as? MVMCoreViewControllerProtocol & UIViewController,
controller.pageType == pageType {
guard let controllerType = controllerType else {
await go(to: index)
return controller
}
guard (type(of: controller) == controllerType) else { continue }
await go(to: index)
return controller
}
}
return nil
}
}
extension UIColor {

View File

@ -102,7 +102,7 @@ public extension UINavigationController {
navigationBar.standardAppearance = appearance
navigationBar.scrollEdgeAppearance = appearance
setNavigationBarHidden(model.hidden, animated: true)
setNavigationBarHidden(model.hidden, animated: false)
}
@objc @MainActor

View File

@ -269,6 +269,10 @@ extension MVMCoreUISplitViewController: MVMCoreViewManagerProtocol {
public func newDataReceived(in viewController: UIViewController) {
updateState(with: viewController)
}
public func navigate(toViewControllerOfPageType pageType: String, controllerType: AnyClass?) async -> UIViewController? {
return await navigationController?.navigate(toViewControllerOfPageType: pageType, controllerType: controllerType)
}
}
@objc public extension MVMCoreUISplitViewController {

View File

@ -95,6 +95,7 @@ CGFloat const PanelAnimationDuration = 0.2;
if (topAlertView) {
[splitViewController subscribeForNotifications];
}
[MVMCoreObject sharedInstance].viewControllerManager = splitViewController;
return splitViewController;
}

View File

@ -8,7 +8,7 @@
import Foundation
import MVMCore
import VDSColorTokens
import VDSTokens
open class SubNavManagerController: ViewController, MVMCoreViewManagerProtocol, TabsDelegate, MVMCorePresentationDelegateProtocol, SubNavSwipeNavigationProtocol {
/// The number of tabs count or less that will turn on the fillContainer
@ -362,6 +362,35 @@ open class SubNavManagerController: ViewController, MVMCoreViewManagerProtocol,
manager?.displayedViewController?(viewController)
}
private func go(to index: Int) async {
// Load controller from the cache
guard index != self.index,
let controller = viewControllers[index] else { return }
needToTrackTabSelect = true
self.index = index
await NavigationHandler.shared().replace(viewController: controller, navigationController:subNavigationController, delegateObject:delegateObject(), tryToReplace: false, animated: true)
}
public func navigate(toViewControllerOfPageType pageType: String, controllerType: AnyClass?) async -> UIViewController? {
for (index, controller) in viewControllers.enumerated() {
if let manager = controller as? MVMCoreViewManagerProtocol,
let viewController = await manager.navigate(toViewControllerOfPageType: pageType, controllerType: controllerType) {
await go(to: index)
return viewController
} else if let controller = controller as? MVMCoreViewControllerProtocol & UIViewController,
controller.pageType == pageType {
guard let controllerType = controllerType else {
await go(to: index)
return controller
}
guard (type(of: controller) == controllerType) else { continue }
await go(to: index)
return controller
}
}
return nil
}
// MARK: - MVMCoreUISwipeNavigationProtocol
public func swipeLeft() {

View File

@ -73,8 +73,11 @@ open class CoreUIModelMapping: ModelMapping {
ModelRegistry.register(handler: LoadingSpinner.self, for: LoadingSpinnerModel.self)
ModelRegistry.register(handler: Video.self, for: VideoModel.self)
ModelRegistry.register(handler: Tilelet.self, for: TileletModel.self)
ModelRegistry.register(handler: TileContainer.self, for: TileContainerModel.self)
ModelRegistry.register(handler: Badge.self, for: BadgeModel.self)
ModelRegistry.register(handler: BadgeIndicator.self, for: BadgeIndicatorModel.self)
ModelRegistry.register(handler: Icon.self, for: IconModel.self)
ModelRegistry.register(handler: ButtonIcon.self, for: ButtonIconModel.self)
ModelRegistry.register(handler: Tooltip.self, for: TooltipModel.self)
// MARK:- Horizontal Combination Molecules

View File

@ -13,4 +13,7 @@
// Action Logging
@objc open func defaultLogAction(forController controller: MVMCoreViewControllerProtocol?, actionInformation: [AnyHashable : Any]?, additionalData: [AnyHashable : Any]?) { }
// Module Update Logging
@objc open func defaultLogPageUpdate(forController controller: MVMCoreViewControllerProtocol, from module: [AnyHashable: Any]) { }
}

View File

@ -0,0 +1,13 @@
//
// mvmcore_ui.xcconfig
// MVMCoreUI
//
// Created by Kyle Hedden on 4/23/24.
// Copyright © 2024 Verizon Wireless. All rights reserved.
//
// Configuration settings file format documentation can be found at:
// https://help.apple.com/xcode/#/dev745c5c974
// Refer back to the workspace settings if they exist.
#include? "../../../workspaceSettings.xcconfig"

View File

@ -0,0 +1,16 @@
//
// mvmcore_ui_dev.xcconfig
// MVMCoreUI
//
// Created by Kyle Hedden on 4/23/24.
// Copyright © 2024 Verizon Wireless. All rights reserved.
//
// Configuration settings file format documentation can be found at:
// https://help.apple.com/xcode/#/dev745c5c974
SWIFT_ACTIVE_COMPILATION_CONDITIONS = $(inherited) LOGGING
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) LOGGING=1
// Refer back to the workspace settings if they exist.
#include? "../../../workspaceSettings.xcconfig"

View File

@ -73,6 +73,7 @@ public extension MVMCoreUIUtility {
@objc
public extension MVMCoreUIUtility {
/// Returns the current visible viewcontroller.
@objc @MainActor
static func getVisibleViewController() -> UIViewController? {
var viewController = NavigationHandler.shared().getViewControllerToPresentOn()