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

View File

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

View File

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

View File

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

View File

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

View File

@ -7,8 +7,7 @@
// //
import UIKit import UIKit
import VDSColorTokens import VDSTokens
import VDSFormControlsTokens
@objcMembers open class RadioButton: Control, MFButtonProtocol { @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. // Created by Kevin Christiano on 1/30/20.
// Copyright © 2020 Verizon Wireless. All rights reserved. // Copyright © 2020 Verizon Wireless. All rights reserved.
// //
import VDSColorTokens import VDSTokens
open class CarouselIndicator: Control, CarouselPageControlProtocol { open class CarouselIndicator: Control, CarouselPageControlProtocol {
//-------------------------------------------------- //--------------------------------------------------

View File

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

View File

@ -64,9 +64,8 @@
bottomLabelConstraint.isActive = true bottomLabelConstraint.isActive = true
alignCheckbox(.center) alignCheckbox(.center)
isAccessibilityElement = true isAccessibilityElement = false
accessibilityHint = checkbox.accessibilityHint accessibilityElements = [checkbox, label]
accessibilityTraits = checkbox.accessibilityTraits
observation = observe(\.checkbox.isSelected, options: [.new]) { [weak self] _, _ in observation = observe(\.checkbox.isSelected, options: [.new]) { [weak self] _, _ in
self?.updateAccessibilityLabel() self?.updateAccessibilityLabel()
} }
@ -139,6 +138,8 @@
open func updateAccessibilityLabel() { open func updateAccessibilityLabel() {
checkbox.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 Foundation
import VDS import VDS
import VDSColorTokens import VDSTokens
open class IconModel: MoleculeModelProtocol { open class IconModel: MoleculeModelProtocol {

View File

@ -7,7 +7,7 @@
// //
import UIKit import UIKit
import VDSColorTokens import VDSTokens
import VDS import VDS
public class LineModel: MoleculeModelProtocol, Invertable { 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 // MARK: - Public
//-------------------------------------------------- //--------------------------------------------------
public func viewModelDidUpdate() { public func viewModelDidUpdate() {
color = viewModel.color //tilelet specific properties
padding = viewModel.padding
aspectRatio = viewModel.aspectRatio
width = viewModel.width
if let value = viewModel.textWidth { if let value = viewModel.textWidth {
textWidth = .value(value) textWidth = .value(value)
} else if let percentage = viewModel.textPercentage { } else if let percentage = viewModel.textPercentage {
@ -64,6 +61,51 @@ open class Tilelet: VDS.Tilelet, VDSMoleculeViewProtocol{
delegateObject: self.delegateObject) 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 Foundation
import VDS import VDS
open class TileletModel: MoleculeModelProtocol { open class TileletModel: TileContainerBaseModel<Tilelet.Padding, Tilelet>, MoleculeModelProtocol {
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Properties // MARK: - Properties
@ -17,52 +17,37 @@ open class TileletModel: MoleculeModelProtocol {
public static var identifier: String = "tilelet" public static var identifier: String = "tilelet"
public var id: String = UUID().uuidString public var id: String = UUID().uuidString
public var backgroundColor: Color? 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 badge: Tilelet.BadgeModel?
public var title: LabelModel? public var title: LabelModel?
public var subTitle: LabelModel? public var subTitle: LabelModel?
public var descriptiveIcon: Tilelet.DescriptiveIcon? public var descriptiveIcon: Tilelet.DescriptiveIcon?
public var directionalIcon: Tilelet.DirectionalIcon? public var directionalIcon: Tilelet.DirectionalIcon?
public var width: CGFloat?
public var textWidth: CGFloat? public var textWidth: CGFloat?
public var textPercentage: CGFloat? public var textPercentage: CGFloat?
public var action: ActionModelProtocol?
private enum CodingKeys: String, CodingKey { private enum CodingKeys: String, CodingKey {
case id case id
case moleculeName case moleculeName
case backgroundColor
case color
case padding
case aspectRatio
case badge case badge
case title case title
case subTitle case subTitle
case descriptiveIcon case descriptiveIcon
case directionalIcon case directionalIcon
case width
case textWidth case textWidth
case textPercentage case textPercentage
case action
} }
required public init(from decoder: Decoder) throws { required public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self) let container = try decoder.container(keyedBy: CodingKeys.self)
self.id = try container.decodeIfPresent(String.self, forKey: .id) ?? UUID().uuidString id = try container.decodeIfPresent(String.self, forKey: .id) ?? UUID().uuidString
self.backgroundColor = try container.decodeIfPresent(Color.self, forKey: .backgroundColor) badge = try container.decodeIfPresent(Tilelet.BadgeModel.self, forKey: .badge)
self.color = try container.decodeIfPresent(Tilelet.BackgroundColor.self, forKey: .color) ?? Tilelet.BackgroundColor.black title = try container.decodeIfPresent(LabelModel.self, forKey: .title)
self.padding = try container.decodeIfPresent(Tilelet.Padding.self, forKey: .padding) ?? Tilelet.Padding.small subTitle = try container.decodeIfPresent(LabelModel.self, forKey: .subTitle)
self.aspectRatio = try container.decodeIfPresent(Tilelet.AspectRatio.self, forKey: .aspectRatio) ?? Tilelet.AspectRatio.none descriptiveIcon = try container.decodeIfPresent(Tilelet.DescriptiveIcon.self, forKey: .descriptiveIcon)
self.badge = try container.decodeIfPresent(Tilelet.BadgeModel.self, forKey: .badge) directionalIcon = try container.decodeIfPresent(Tilelet.DirectionalIcon.self, forKey: .directionalIcon)
self.title = try container.decodeIfPresent(LabelModel.self, forKey: .title) textWidth = try container.decodeIfPresent(CGFloat.self, forKey: .textWidth)
self.subTitle = try container.decodeIfPresent(LabelModel.self, forKey: .subTitle) textPercentage = try container.decodeIfPresent(CGFloat.self, forKey: .textPercentage)
self.descriptiveIcon = try container.decodeIfPresent(Tilelet.DescriptiveIcon.self, forKey: .descriptiveIcon) try super.init(from: decoder)
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)
} }
public func titleModel(delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> Tilelet.TitleModel? { 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) 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) var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id) try container.encode(id, forKey: .id)
try container.encode(moleculeName, forKey: .moleculeName) 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(badge, forKey: .badge)
try container.encodeIfPresent(title, forKey: .title) try container.encodeIfPresent(title, forKey: .title)
try container.encodeIfPresent(subTitle, forKey: .subTitle) try container.encodeIfPresent(subTitle, forKey: .subTitle)
try container.encodeIfPresent(descriptiveIcon, forKey: .descriptiveIcon) try container.encodeIfPresent(descriptiveIcon, forKey: .descriptiveIcon)
try container.encodeIfPresent(directionalIcon, forKey: .directionalIcon) try container.encodeIfPresent(directionalIcon, forKey: .directionalIcon)
try container.encodeIfPresent(width, forKey: .width)
try container.encodeIfPresent(textWidth, forKey: .textWidth) try container.encodeIfPresent(textWidth, forKey: .textWidth)
try container.encodeIfPresent(textPercentage, forKey: .textPercentage) 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 Foundation
import VDS import VDS
import VDSColorTokens import VDSTokens
import MVMCore import MVMCore
open class TooltipModel: MoleculeModelProtocol { open class TooltipModel: MoleculeModelProtocol {

View File

@ -8,7 +8,7 @@
import Foundation import Foundation
import VDS import VDS
import VDSColorTokens import VDSTokens
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Codable Extensions // MARK: - Codable Extensions
@ -16,6 +16,14 @@ import VDSColorTokens
extension VDS.Surface: Codable {} extension VDS.Surface: Codable {}
extension VDS.Badge.FillColor: 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.ButtonGroup.Alignment: Codable {}
extension VDS.Icon.Name: Codable {} extension VDS.Icon.Name: Codable {}
extension VDS.Icon.Size: 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 { extension VDS.TileContainer.Padding: Codable {
enum PaddingError: Error { enum PaddingError: Error {
case valueNotFound(type: String) case valueNotFound(type: String)
@ -112,8 +167,8 @@ extension VDS.TileContainer.Padding: Codable {
do { do {
let type = try container.decode(String.self) let type = try container.decode(String.self)
switch type { switch type {
case "padding2X": case "padding3X":
self = .padding2X self = .padding3X
case "padding4X": case "padding4X":
self = .padding4X self = .padding4X
case "padding6X": case "padding6X":

View File

@ -74,7 +74,7 @@ public class HeadersH2ButtonsModel: HeaderModel, MoleculeModelProtocol, ParentMo
required public init(from decoder: Decoder) throws { required public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self) 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) buttons = try typeContainer.decode(TwoButtonViewModel.self, forKey: .buttons)
try super.init(from: decoder) try super.init(from: decoder)
} }

View File

@ -67,7 +67,7 @@ public class HeadersH2CaretLinkModel: HeaderModel, MoleculeModelProtocol, Parent
//-------------------------------------------------- //--------------------------------------------------
required public init(from decoder: Decoder) throws { required public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self) 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) caretLink = try typeContainer.decode(CaretLinkModel.self, forKey: .caretLink)
try super.init(from: decoder) try super.init(from: decoder)
} }

View File

@ -73,7 +73,7 @@ public class HeadersH2LinkModel: HeaderModel, MoleculeModelProtocol, ParentMolec
required public init(from decoder: Decoder) throws { required public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self) 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) link = try typeContainer.decode(LinkModel.self, forKey: .link)
try super.init(from: decoder) try super.init(from: decoder)
} }

View File

@ -76,7 +76,7 @@ public class HeadersH2TinyButtonModel: HeaderModel, MoleculeModelProtocol, Paren
required public init(from decoder: Decoder) throws { required public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self) 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) button = try typeContainer.decode(ButtonModel.self, forKey: .button)
try super.init(from: decoder) try super.init(from: decoder)
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -26,21 +26,13 @@ open class CollapsableNotificationModel: NotificationMoleculeModel {
self.collapseTime = collapseTime self.collapseTime = collapseTime
} }
super.init(with: headline, style: style, backgroundColor: backgroundColor, body: body, button: button, closeButton: closeButton) super.init(with: headline, style: style, backgroundColor: backgroundColor, body: body, button: button, closeButton: closeButton)
setDefaults()
} }
open override func setDefaults() { open func setDefaults() {
super.setDefaults()
if topLabel.numberOfLines == nil { if topLabel.numberOfLines == nil {
topLabel.numberOfLines = 1 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 { if topLabel.textAlignment == nil {
topLabel.textAlignment = .center topLabel.textAlignment = .center
} }
@ -69,6 +61,7 @@ open class CollapsableNotificationModel: NotificationMoleculeModel {
self.initiallyCollapsed = initiallyCollapsed self.initiallyCollapsed = initiallyCollapsed
} }
try super.init(from: decoder) try super.init(from: decoder)
setDefaults()
} }
open override func encode(to encoder: Encoder) throws { open override func encode(to encoder: Encoder) throws {

View File

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

View File

@ -5,9 +5,9 @@
// Created by Scott Pfeil on 9/15/20. // Created by Scott Pfeil on 9/15/20.
// Copyright © 2020 Verizon Wireless. All rights reserved. // Copyright © 2020 Verizon Wireless. All rights reserved.
// //
import VDS
open class NotificationMoleculeModel: MoleculeModelProtocol {
open class NotificationMoleculeModel: ContainerModel, MoleculeModelProtocol {
/** /**
The style of the notification: The style of the notification:
@ -21,91 +21,48 @@ open class NotificationMoleculeModel: ContainerModel, MoleculeModelProtocol {
case error case error
case warning case warning
case information case information
var toVDSStyle: VDS.Notification.Style {
switch self {
case .success:
.success
case .error:
.error
case .warning:
.warning
case .information:
.info
}
}
} }
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Properties // MARK: - Properties
//-------------------------------------------------- //--------------------------------------------------
public var id: String = UUID().uuidString
public class var identifier: String { "notification" } public class var identifier: String { "notification" }
public var accessibilityIdentifier: String? public var accessibilityIdentifier: String?
public var backgroundColor: Color? public var backgroundColor: Color?
public var headline: LabelModel public var headline: LabelModel
public var body: LabelModel? public var body: LabelModel?
public var button: ButtonModel? public var button: ButtonModel?
public var secondaryButton: ButtonModel?
public var closeButton: NotificationXButtonModel? public var closeButton: NotificationXButtonModel?
public var style: NotificationMoleculeModel.Style = .success public var style: Style = .success
public var inverted: Bool = false
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Initializer // 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.headline = headline
self.style = style self.style = style
self.backgroundColor = backgroundColor self.backgroundColor = backgroundColor
self.body = body self.body = body
self.button = button self.button = button
self.secondaryButton = secondaryButton
self.closeButton = closeButton 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 headline
case body case body
case button case button
case secondaryButton
case closeButton case closeButton
case inverted
case style case style
} }
@ -129,27 +88,34 @@ open class NotificationMoleculeModel: ContainerModel, MoleculeModelProtocol {
required public init(from decoder: Decoder) throws { required public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self) let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
accessibilityIdentifier = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityIdentifier) accessibilityIdentifier = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityIdentifier)
headline = try typeContainer.decode(LabelModel.self, forKey: .headline) headline = try typeContainer.decode(LabelModel.self, forKey: .headline)
body = try typeContainer.decodeIfPresent(LabelModel.self, forKey: .body) body = try typeContainer.decodeIfPresent(LabelModel.self, forKey: .body)
button = try typeContainer.decodeIfPresent(ButtonModel.self, forKey: .button) button = try typeContainer.decodeIfPresent(ButtonModel.self, forKey: .button)
secondaryButton = try typeContainer.decodeIfPresent(ButtonModel.self, forKey: .secondaryButton)
closeButton = try typeContainer.decodeIfPresent(NotificationXButtonModel.self, forKey: .closeButton) 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) { if let style = try typeContainer.decodeIfPresent(NotificationMoleculeModel.Style.self, forKey: .style) {
self.style = 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) var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(moleculeName, forKey: .moleculeName) try container.encode(moleculeName, forKey: .moleculeName)
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier) try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier)
try container.encode(headline, forKey: .headline) try container.encode(headline, forKey: .headline)
try container.encodeIfPresent(body, forKey: .body) try container.encodeIfPresent(body, forKey: .body)
try container.encodeIfPresent(button, forKey: .button) try container.encodeIfPresent(button, forKey: .button)
try container.encodeIfPresent(secondaryButton, forKey: .secondaryButton)
try container.encodeIfPresent(closeButton, forKey: .closeButton) try container.encodeIfPresent(closeButton, forKey: .closeButton)
try container.encodeIfPresent(inverted, forKey: .inverted)
try container.encode(style, forKey: .style) try container.encode(style, forKey: .style)
} }
} }
extension NotificationMoleculeModel {
public var surface: Surface {
inverted ? .dark : .light
}
}

View File

@ -7,90 +7,101 @@
// //
import Foundation import Foundation
import VDS
@objcMembers open class NotificationMoleculeView: Container { @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 // 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 // Legacy constant
private static let viewHeight: CGFloat = 96.0 private static let viewHeight: CGFloat = 96.0
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Life Cycle // MARK: - Life Cycle
//-------------------------------------------------- //--------------------------------------------------
open override func updateAccessibility() {
public override func setupView() { super.updateAccessibility()
super.setupView() Self.amendAccesibilityLabel(for: titleLabel)
reset() Self.amendAccesibilityLabel(for: subTitleLabel)
Self.amendAccesibilityLabel(for: primaryButton)
// Buttons should have highest priority, then headline, then body Self.amendAccesibilityLabel(for: secondaryButton)
headline.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 500), for: .horizontal) Self.amendAccesibilityLabel(for: closeButton)
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
} }
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Molecule // MARK: - Molecule
//-------------------------------------------------- //--------------------------------------------------
public func updateView(_ size: CGFloat) { }
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
super.set(with: model, delegateObject, additionalData) open class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
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? {
return viewHeight 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. /// Formats the accessibilityLabel so voice over users know it's in the notification.
static public func amendAccesibilityLabel(for view: UIView) { public class func amendAccesibilityLabel(for view: UIView?) {
guard let amendment = MVMCoreUIUtility.hardcodedString(withKey: "top_alert_notification"), guard let view,
let accessibilityLabel = view.accessibilityLabel, let amendment = MVMCoreUIUtility.hardcodedString(withKey: "top_alert_notification")
!accessibilityLabel.hasPrefix(amendment) else { return } else { return }
view.accessibilityLabel = "\(amendment) - \(accessibilityLabel)" view.amendAccesibilityLabel(with: amendment)
} }
} }
extension NotificationMoleculeView: AccessibilityProtocol { extension NotificationMoleculeView: AccessibilityProtocol {
public func getAccessibilityLayoutChangedArgument() -> Any? { 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]?) { open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) {
super.set(with: model, delegateObject, additionalData) super.set(with: model, delegateObject, additionalData)
guard let model = model as? NotificationXButtonModel else { return } guard let model = model as? NotificationXButtonModel else { return }
tintColor = model.color?.uiColor ?? .white
// TODO: Temporary, consider action for dismissing top alert // TODO: Temporary, consider action for dismissing top alert
if model.action.actionType == ActionNoopModel.identifier { 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 id: String = UUID().uuidString
public var backgroundColor: Color? public var backgroundColor: Color?
public var color: Color?
public var action: ActionModelProtocol = ActionNoopModel() public var action: ActionModelProtocol = ActionNoopModel()
private enum CodingKeys: String, CodingKey { private enum CodingKeys: String, CodingKey {
case id case id
case moleculeName case moleculeName
case color
case action case action
} }
public init(color: Color? = nil, action: ActionModelProtocol = ActionNoopModel()) { public init(action: ActionModelProtocol = ActionNoopModel()) {
self.color = color
self.action = action self.action = action
} }
public required init(from decoder: Decoder) throws { public required init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self) let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
id = try typeContainer.decodeIfPresent(String.self, forKey: .id) ?? UUID().uuidString 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) { if let action: ActionModelProtocol = try typeContainer.decodeModelIfPresent(codingKey: .action) {
self.action = action self.action = action
} }
@ -43,7 +39,6 @@ public class NotificationXButtonModel: ButtonModelProtocol, MoleculeModelProtoco
var container = encoder.container(keyedBy: CodingKeys.self) var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id) try container.encode(id, forKey: .id)
try container.encode(moleculeName, forKey: .moleculeName) try container.encode(moleculeName, forKey: .moleculeName)
try container.encodeIfPresent(color, forKey: .color)
try container.encodeModel(action, forKey: .action) 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. /// 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 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 { extension MoleculeDelegateProtocol {

View File

@ -66,6 +66,14 @@ extension MoleculeViewProtocol {
set(with: model, delegateObject, additionalData) 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 // Convenience Functions

View File

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

View File

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

View File

@ -21,8 +21,6 @@ public class ReplaceableMoleculeBehavior: PageMoleculeTransformationBehavior {
private var observingForResponses: NSObjectProtocol? private var observingForResponses: NSObjectProtocol?
private var delegateObject: MVMCoreUIDelegateObject? private var delegateObject: MVMCoreUIDelegateObject?
public var transcendsPageUpdates: Bool { true }
public required init(model: PageBehaviorModelProtocol, delegateObject: MVMCoreUIDelegateObject?) { public required init(model: PageBehaviorModelProtocol, delegateObject: MVMCoreUIDelegateObject?) {
moleculeIds = (model as! ReplaceableMoleculeBehaviorModel).moleculeIds moleculeIds = (model as! ReplaceableMoleculeBehaviorModel).moleculeIds
let shouldListenForListUpdates = delegateObject?.moleculeListDelegate != nil let shouldListenForListUpdates = delegateObject?.moleculeListDelegate != nil
@ -62,7 +60,7 @@ public class ReplaceableMoleculeBehavior: PageMoleculeTransformationBehavior {
} }
} }
if moleculeModels.count > 0 { if moleculeModels.count > 0 {
delegateObject?.moleculeDelegate?.replaceMoleculeData(moleculeModels) delegateObject?.moleculeDelegate?.replaceMoleculeData(moleculeModels, completionHandler: nil)
} }
} }
@ -95,8 +93,15 @@ public class ReplaceableMoleculeBehavior: PageMoleculeTransformationBehavior {
return nil return nil
} }
} }
if modules.count > 0 { guard modules.count > 0 else { return }
delegateObject?.moleculeDelegate?.replaceMoleculeData(modules) #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"), "upGold2": (.vzupGold2, "#F4CA53"),
"upGold3": (.vzupGold3, "#CC9B2D")] "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 // MARK: - Brand
//-------------------------------------------------- //--------------------------------------------------

View File

@ -34,6 +34,7 @@ import Combine
public static func setupNavigationControllerAsMainController() -> Self? { public static func setupNavigationControllerAsMainController() -> Self? {
guard let navigationController = setupNavigationController() else { return nil } guard let navigationController = setupNavigationController() else { return nil }
MVMCoreUISession.sharedGlobal()?.setup(asStandardLoadViewDelegate: navigationController) MVMCoreUISession.sharedGlobal()?.setup(asStandardLoadViewDelegate: navigationController)
MVMCoreObject.sharedInstance()?.viewControllerManager = navigationController
return navigationController return navigationController
} }
@ -136,6 +137,31 @@ extension NavigationController: MVMCoreViewManagerProtocol {
public func displayedViewController(_ viewController: UIViewController) { public func displayedViewController(_ viewController: UIViewController) {
manager?.displayedViewController?(viewController) 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 { extension UIColor {

View File

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

View File

@ -269,6 +269,10 @@ extension MVMCoreUISplitViewController: MVMCoreViewManagerProtocol {
public func newDataReceived(in viewController: UIViewController) { public func newDataReceived(in viewController: UIViewController) {
updateState(with: viewController) 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 { @objc public extension MVMCoreUISplitViewController {

View File

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

View File

@ -8,7 +8,7 @@
import Foundation import Foundation
import MVMCore import MVMCore
import VDSColorTokens import VDSTokens
open class SubNavManagerController: ViewController, MVMCoreViewManagerProtocol, TabsDelegate, MVMCorePresentationDelegateProtocol, SubNavSwipeNavigationProtocol { open class SubNavManagerController: ViewController, MVMCoreViewManagerProtocol, TabsDelegate, MVMCorePresentationDelegateProtocol, SubNavSwipeNavigationProtocol {
/// The number of tabs count or less that will turn on the fillContainer /// 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) 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 // MARK: - MVMCoreUISwipeNavigationProtocol
public func swipeLeft() { public func swipeLeft() {

View File

@ -73,8 +73,11 @@ open class CoreUIModelMapping: ModelMapping {
ModelRegistry.register(handler: LoadingSpinner.self, for: LoadingSpinnerModel.self) ModelRegistry.register(handler: LoadingSpinner.self, for: LoadingSpinnerModel.self)
ModelRegistry.register(handler: Video.self, for: VideoModel.self) ModelRegistry.register(handler: Video.self, for: VideoModel.self)
ModelRegistry.register(handler: Tilelet.self, for: TileletModel.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: Badge.self, for: BadgeModel.self)
ModelRegistry.register(handler: BadgeIndicator.self, for: BadgeIndicatorModel.self)
ModelRegistry.register(handler: Icon.self, for: IconModel.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) ModelRegistry.register(handler: Tooltip.self, for: TooltipModel.self)
// MARK:- Horizontal Combination Molecules // MARK:- Horizontal Combination Molecules

View File

@ -13,4 +13,7 @@
// Action Logging // Action Logging
@objc open func defaultLogAction(forController controller: MVMCoreViewControllerProtocol?, actionInformation: [AnyHashable : Any]?, additionalData: [AnyHashable : Any]?) { } @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 @objc
public extension MVMCoreUIUtility { public extension MVMCoreUIUtility {
/// Returns the current visible viewcontroller.
@objc @MainActor @objc @MainActor
static func getVisibleViewController() -> UIViewController? { static func getVisibleViewController() -> UIViewController? {
var viewController = NavigationHandler.shared().getViewControllerToPresentOn() var viewController = NavigationHandler.shared().getViewControllerToPresentOn()