Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui into feature/unified_grid
This commit is contained in:
commit
ca8884a477
@ -62,6 +62,8 @@
|
||||
01EB369323609801006832FA /* HeaderModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01EB368C23609801006832FA /* HeaderModel.swift */; };
|
||||
01EB369423609801006832FA /* HeadlineBodyModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01EB368D23609801006832FA /* HeadlineBodyModel.swift */; };
|
||||
01F2A03223A4498200D954D8 /* CaretLinkModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01F2A03123A4498200D954D8 /* CaretLinkModel.swift */; };
|
||||
0A0FEC7425D42A5E00AF2548 /* BaseItemPickerEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A0FEC7325D42A5E00AF2548 /* BaseItemPickerEntryField.swift */; };
|
||||
0A0FEC7825D42A8500AF2548 /* BaseItemPickerEntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A0FEC7725D42A8500AF2548 /* BaseItemPickerEntryFieldModel.swift */; };
|
||||
0A1214A022C11A18007C7030 /* ActionDetailWithImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A12149F22C11A17007C7030 /* ActionDetailWithImage.swift */; };
|
||||
0A1B4A96233BB18F005B3FB4 /* CheckboxLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAFA2232BE63400FB8E22 /* CheckboxLabel.swift */; };
|
||||
0A21DB7F235DECC500C160A2 /* EntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A21DB7E235DECC500C160A2 /* EntryField.swift */; };
|
||||
@ -94,7 +96,7 @@
|
||||
0A7EF85D23D8A95600B2AAD1 /* TextEntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7EF85C23D8A95600B2AAD1 /* TextEntryFieldModel.swift */; };
|
||||
0A7EF85F23D8ABC500B2AAD1 /* MdnEntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7EF85E23D8ABC500B2AAD1 /* MdnEntryFieldModel.swift */; };
|
||||
0A7EF86123D8AC2500B2AAD1 /* DigitEntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7EF86023D8AC2500B2AAD1 /* DigitEntryFieldModel.swift */; };
|
||||
0A7EF86323D8AFA000B2AAD1 /* BaseDropdownEntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7EF86223D8AFA000B2AAD1 /* BaseDropdownEntryFieldModel.swift */; };
|
||||
0A7EF86323D8AFA000B2AAD1 /* BaseDropdownFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7EF86223D8AFA000B2AAD1 /* BaseDropdownFieldModel.swift */; };
|
||||
0A7EF86523D8AFFF00B2AAD1 /* ItemDropdownEntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7EF86423D8AFFF00B2AAD1 /* ItemDropdownEntryFieldModel.swift */; };
|
||||
0A7EF86723D8B0AE00B2AAD1 /* DateDropdownEntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7EF86623D8B0AE00B2AAD1 /* DateDropdownEntryFieldModel.swift */; };
|
||||
0A849EFE246F1775009F277F /* RuleEqualsIgnoreCaseModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A849EFD246F1775009F277F /* RuleEqualsIgnoreCaseModel.swift */; };
|
||||
@ -105,6 +107,7 @@
|
||||
0A9D09212433796500D2E6C0 /* CarouselIndicatorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A9D091B2433796500D2E6C0 /* CarouselIndicatorModel.swift */; };
|
||||
0A9D09222433796500D2E6C0 /* CarouselIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A9D091C2433796500D2E6C0 /* CarouselIndicator.swift */; };
|
||||
0AA33B3A2398524F0067DD0F /* Toggle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AA33B392398524F0067DD0F /* Toggle.swift */; };
|
||||
0AA4D2E125CAEC72008DB32D /* AccessibilityModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AA4D2E025CAEC72008DB32D /* AccessibilityModelProtocol.swift */; };
|
||||
0AB000BA24BF63490090C5E7 /* ModalListPageTemplateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AB000B924BF63490090C5E7 /* ModalListPageTemplateModel.swift */; };
|
||||
0AB000BC24BF64A50090C5E7 /* ModalStackPageTemplateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AB000BB24BF64A50090C5E7 /* ModalStackPageTemplateModel.swift */; };
|
||||
0AB764D124460F6300E7FE72 /* UIDatePicker+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AB764D024460F6300E7FE72 /* UIDatePicker+Extension.swift */; };
|
||||
@ -113,6 +116,8 @@
|
||||
0ABD1371237DB0450081388D /* ItemDropdownEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ABD1370237DB0450081388D /* ItemDropdownEntryField.swift */; };
|
||||
0AD93A9F24C0AA5100E56A97 /* ImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7918F423F5E7EA00772FF4 /* ImageView.swift */; };
|
||||
0AE14F64238315D2005417F8 /* TextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AE14F63238315D2005417F8 /* TextField.swift */; };
|
||||
0AE277E925D2ED4B0048A38D /* MultiItemDropdownEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AE277E825D2ED4B0048A38D /* MultiItemDropdownEntryField.swift */; };
|
||||
0AE277EC25D2EE310048A38D /* MultiItemDropdownEntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AE277EB25D2EE310048A38D /* MultiItemDropdownEntryFieldModel.swift */; };
|
||||
0AE98BAF23FEF956004C5109 /* ExternalLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AE98BAE23FEF956004C5109 /* ExternalLink.swift */; };
|
||||
0AE98BB323FF0934004C5109 /* ExternalLinkModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AE98BB223FF0934004C5109 /* ExternalLinkModel.swift */; };
|
||||
0AE98BB523FF18D2004C5109 /* Arrow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AE98BB423FF18D2004C5109 /* Arrow.swift */; };
|
||||
@ -290,6 +295,7 @@
|
||||
BBC0C4FF24811DCA0087C44F /* TagModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BBC0C4FE24811DCA0087C44F /* TagModel.swift */; };
|
||||
C003506123AA94CD00B6AC29 /* Button.swift in Sources */ = {isa = PBXBuildFile; fileRef = C003506023AA94CD00B6AC29 /* Button.swift */; };
|
||||
C07065C42395677300FBF997 /* Link.swift in Sources */ = {isa = PBXBuildFile; fileRef = C07065C32395677300FBF997 /* Link.swift */; };
|
||||
C6687441259D92D400F32D13 /* ActionTopNotificationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6687440259D92D400F32D13 /* ActionTopNotificationModel.swift */; };
|
||||
C695A67F23C9830600BFB94E /* UnOrderedListModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C695A67E23C9830600BFB94E /* UnOrderedListModel.swift */; };
|
||||
C695A68123C9830D00BFB94E /* NumberedListModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C695A68023C9830D00BFB94E /* NumberedListModel.swift */; };
|
||||
C695A69423C9909000BFB94E /* DoughnutChartModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C695A69323C9909000BFB94E /* DoughnutChartModel.swift */; };
|
||||
@ -345,6 +351,8 @@
|
||||
D23EA800247EBD6C00D60C34 /* LabelBarButtonItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D23EA7FF247EBD6C00D60C34 /* LabelBarButtonItem.swift */; };
|
||||
D23EA802247EBED400D60C34 /* ImageBarButtonItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D23EA801247EBED400D60C34 /* ImageBarButtonItem.swift */; };
|
||||
D243859923A16B1800332775 /* Container.swift in Sources */ = {isa = PBXBuildFile; fileRef = D243859823A16B1800332775 /* Container.swift */; };
|
||||
D24918F625D5AD8E00CAB4B1 /* PageVisibilityClosureBehavior.swift in Sources */ = {isa = PBXBuildFile; fileRef = D24918F525D5AD8E00CAB4B1 /* PageVisibilityClosureBehavior.swift */; };
|
||||
D24918FA25D5ADBB00CAB4B1 /* PageScrolledClosureBehavior.swift in Sources */ = {isa = PBXBuildFile; fileRef = D24918F925D5ADBA00CAB4B1 /* PageScrolledClosureBehavior.swift */; };
|
||||
D2509ED12472ED9B001BFB9D /* NavigationItemModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2509ED02472ED9B001BFB9D /* NavigationItemModelProtocol.swift */; };
|
||||
D2509ED62472EE2F001BFB9D /* NavigationImageButtonModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2509ED52472EE2F001BFB9D /* NavigationImageButtonModel.swift */; };
|
||||
D253BB8A24574CC5002DE544 /* StackModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D260106423D0CEA700764D80 /* StackModel.swift */; };
|
||||
@ -401,6 +409,11 @@
|
||||
D28BA74D248589C800B75CB8 /* TabPageModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D28BA74C248589C800B75CB8 /* TabPageModelProtocol.swift */; };
|
||||
D296E14722A5984C0051EBE7 /* MVMCoreUIViewConstrainingProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = D296E14622A597490051EBE7 /* MVMCoreUIViewConstrainingProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
D29B771022C281F400D6ACE0 /* ModuleMolecule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D29B770F22C281F400D6ACE0 /* ModuleMolecule.swift */; };
|
||||
D29C558A25C05C7D0082E7D6 /* BGVideoImageMoleculeModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D29C558925C05C7D0082E7D6 /* BGVideoImageMoleculeModel.swift */; };
|
||||
D29C558D25C05C990082E7D6 /* BGVideoImageMolecule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D29C558C25C05C990082E7D6 /* BGVideoImageMolecule.swift */; };
|
||||
D29C559025C095210082E7D6 /* Video.swift in Sources */ = {isa = PBXBuildFile; fileRef = D29C558F25C095210082E7D6 /* Video.swift */; };
|
||||
D29C559325C0992D0082E7D6 /* VideoModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D29C559225C0992D0082E7D6 /* VideoModel.swift */; };
|
||||
D29C559625C099630082E7D6 /* VideoDataManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D29C559525C099630082E7D6 /* VideoDataManager.swift */; };
|
||||
D29C94D5242901C9003813BA /* MVMCoreUICommonViewsUtility+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D29C94D4242901C9003813BA /* MVMCoreUICommonViewsUtility+Extension.swift */; };
|
||||
D29DF0D121E404D4003B2FB9 /* MVMCoreUI.h in Headers */ = {isa = PBXBuildFile; fileRef = D29DF0CF21E404D4003B2FB9 /* MVMCoreUI.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
D29DF0E621E4F3C7003B2FB9 /* MVMCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D29DF0E521E4F3C7003B2FB9 /* MVMCore.framework */; };
|
||||
@ -603,6 +616,8 @@
|
||||
01EB368C23609801006832FA /* HeaderModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HeaderModel.swift; sourceTree = "<group>"; };
|
||||
01EB368D23609801006832FA /* HeadlineBodyModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HeadlineBodyModel.swift; sourceTree = "<group>"; };
|
||||
01F2A03123A4498200D954D8 /* CaretLinkModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CaretLinkModel.swift; sourceTree = "<group>"; };
|
||||
0A0FEC7325D42A5E00AF2548 /* BaseItemPickerEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseItemPickerEntryField.swift; sourceTree = "<group>"; };
|
||||
0A0FEC7725D42A8500AF2548 /* BaseItemPickerEntryFieldModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseItemPickerEntryFieldModel.swift; sourceTree = "<group>"; };
|
||||
0A12149F22C11A17007C7030 /* ActionDetailWithImage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionDetailWithImage.swift; sourceTree = "<group>"; };
|
||||
0A209CD223A7E2810068F8B0 /* UIStackViewAlignment+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIStackViewAlignment+Extension.swift"; sourceTree = "<group>"; };
|
||||
0A21DB7E235DECC500C160A2 /* EntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EntryField.swift; sourceTree = "<group>"; };
|
||||
@ -636,7 +651,7 @@
|
||||
0A7EF85C23D8A95600B2AAD1 /* TextEntryFieldModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextEntryFieldModel.swift; sourceTree = "<group>"; };
|
||||
0A7EF85E23D8ABC500B2AAD1 /* MdnEntryFieldModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MdnEntryFieldModel.swift; sourceTree = "<group>"; };
|
||||
0A7EF86023D8AC2500B2AAD1 /* DigitEntryFieldModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DigitEntryFieldModel.swift; sourceTree = "<group>"; };
|
||||
0A7EF86223D8AFA000B2AAD1 /* BaseDropdownEntryFieldModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseDropdownEntryFieldModel.swift; sourceTree = "<group>"; };
|
||||
0A7EF86223D8AFA000B2AAD1 /* BaseDropdownFieldModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseDropdownFieldModel.swift; sourceTree = "<group>"; };
|
||||
0A7EF86423D8AFFF00B2AAD1 /* ItemDropdownEntryFieldModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemDropdownEntryFieldModel.swift; sourceTree = "<group>"; };
|
||||
0A7EF86623D8B0AE00B2AAD1 /* DateDropdownEntryFieldModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateDropdownEntryFieldModel.swift; sourceTree = "<group>"; };
|
||||
0A8321AE2355FE9500CB7F00 /* DigitBox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DigitBox.swift; sourceTree = "<group>"; };
|
||||
@ -649,6 +664,7 @@
|
||||
0A9D091C2433796500D2E6C0 /* CarouselIndicator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CarouselIndicator.swift; sourceTree = "<group>"; };
|
||||
0AA33B33239813C50067DD0F /* UIColor+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIColor+Extension.swift"; sourceTree = "<group>"; };
|
||||
0AA33B392398524F0067DD0F /* Toggle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Toggle.swift; sourceTree = "<group>"; };
|
||||
0AA4D2E025CAEC72008DB32D /* AccessibilityModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccessibilityModelProtocol.swift; sourceTree = "<group>"; };
|
||||
0AB000B924BF63490090C5E7 /* ModalListPageTemplateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModalListPageTemplateModel.swift; sourceTree = "<group>"; };
|
||||
0AB000BB24BF64A50090C5E7 /* ModalStackPageTemplateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModalStackPageTemplateModel.swift; sourceTree = "<group>"; };
|
||||
0AB764D024460F6300E7FE72 /* UIDatePicker+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIDatePicker+Extension.swift"; sourceTree = "<group>"; };
|
||||
@ -656,6 +672,8 @@
|
||||
0ABD136C237CAD1E0081388D /* DateDropdownEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateDropdownEntryField.swift; sourceTree = "<group>"; };
|
||||
0ABD1370237DB0450081388D /* ItemDropdownEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemDropdownEntryField.swift; sourceTree = "<group>"; };
|
||||
0AE14F63238315D2005417F8 /* TextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextField.swift; sourceTree = "<group>"; };
|
||||
0AE277E825D2ED4B0048A38D /* MultiItemDropdownEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultiItemDropdownEntryField.swift; sourceTree = "<group>"; };
|
||||
0AE277EB25D2EE310048A38D /* MultiItemDropdownEntryFieldModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultiItemDropdownEntryFieldModel.swift; sourceTree = "<group>"; };
|
||||
0AE98BAE23FEF956004C5109 /* ExternalLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExternalLink.swift; sourceTree = "<group>"; };
|
||||
0AE98BB223FF0934004C5109 /* ExternalLinkModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExternalLinkModel.swift; sourceTree = "<group>"; };
|
||||
0AE98BB423FF18D2004C5109 /* Arrow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Arrow.swift; sourceTree = "<group>"; };
|
||||
@ -833,6 +851,7 @@
|
||||
BBC0C4FE24811DCA0087C44F /* TagModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagModel.swift; sourceTree = "<group>"; };
|
||||
C003506023AA94CD00B6AC29 /* Button.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Button.swift; sourceTree = "<group>"; };
|
||||
C07065C32395677300FBF997 /* Link.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Link.swift; sourceTree = "<group>"; };
|
||||
C6687440259D92D400F32D13 /* ActionTopNotificationModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionTopNotificationModel.swift; sourceTree = "<group>"; };
|
||||
C695A67E23C9830600BFB94E /* UnOrderedListModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UnOrderedListModel.swift; sourceTree = "<group>"; };
|
||||
C695A68023C9830D00BFB94E /* NumberedListModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NumberedListModel.swift; sourceTree = "<group>"; };
|
||||
C695A69323C9909000BFB94E /* DoughnutChartModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DoughnutChartModel.swift; sourceTree = "<group>"; };
|
||||
@ -888,6 +907,8 @@
|
||||
D23EA7FF247EBD6C00D60C34 /* LabelBarButtonItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabelBarButtonItem.swift; sourceTree = "<group>"; };
|
||||
D23EA801247EBED400D60C34 /* ImageBarButtonItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageBarButtonItem.swift; sourceTree = "<group>"; };
|
||||
D243859823A16B1800332775 /* Container.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Container.swift; sourceTree = "<group>"; };
|
||||
D24918F525D5AD8E00CAB4B1 /* PageVisibilityClosureBehavior.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PageVisibilityClosureBehavior.swift; sourceTree = "<group>"; };
|
||||
D24918F925D5ADBA00CAB4B1 /* PageScrolledClosureBehavior.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PageScrolledClosureBehavior.swift; sourceTree = "<group>"; };
|
||||
D2509ED02472ED9B001BFB9D /* NavigationItemModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationItemModelProtocol.swift; sourceTree = "<group>"; };
|
||||
D2509ED52472EE2F001BFB9D /* NavigationImageButtonModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NavigationImageButtonModel.swift; sourceTree = "<group>"; };
|
||||
D253BB9B245874F8002DE544 /* BGImageMolecule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BGImageMolecule.swift; sourceTree = "<group>"; };
|
||||
@ -942,6 +963,11 @@
|
||||
D28BA74C248589C800B75CB8 /* TabPageModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabPageModelProtocol.swift; sourceTree = "<group>"; };
|
||||
D296E14622A597490051EBE7 /* MVMCoreUIViewConstrainingProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreUIViewConstrainingProtocol.h; sourceTree = "<group>"; };
|
||||
D29B770F22C281F400D6ACE0 /* ModuleMolecule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModuleMolecule.swift; sourceTree = "<group>"; };
|
||||
D29C558925C05C7D0082E7D6 /* BGVideoImageMoleculeModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BGVideoImageMoleculeModel.swift; sourceTree = "<group>"; };
|
||||
D29C558C25C05C990082E7D6 /* BGVideoImageMolecule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BGVideoImageMolecule.swift; sourceTree = "<group>"; };
|
||||
D29C558F25C095210082E7D6 /* Video.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Video.swift; sourceTree = "<group>"; };
|
||||
D29C559225C0992D0082E7D6 /* VideoModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoModel.swift; sourceTree = "<group>"; };
|
||||
D29C559525C099630082E7D6 /* VideoDataManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoDataManager.swift; sourceTree = "<group>"; };
|
||||
D29C94D4242901C9003813BA /* MVMCoreUICommonViewsUtility+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MVMCoreUICommonViewsUtility+Extension.swift"; sourceTree = "<group>"; };
|
||||
D29DF0CC21E404D4003B2FB9 /* MVMCoreUI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MVMCoreUI.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
D29DF0CF21E404D4003B2FB9 /* MVMCoreUI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreUI.h; sourceTree = "<group>"; };
|
||||
@ -1107,6 +1133,7 @@
|
||||
011B58EE23A2AA850085F53C /* ModelProtocols */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0AA4D2E025CAEC72008DB32D /* AccessibilityModelProtocol.swift */,
|
||||
D2E2A9A023E095AB000B42E6 /* ButtonModelProtocol.swift */,
|
||||
014AA72323C501E2006F3E93 /* ContainerModelProtocol.swift */,
|
||||
D23EA7FA2475F09800D60C34 /* CarouselItemProtocol.swift */,
|
||||
@ -1164,6 +1191,39 @@
|
||||
path = FormUIHelpers;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
0A0FEC7125D4246000AF2548 /* Dropdown Fields */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0A7EF86223D8AFA000B2AAD1 /* BaseDropdownFieldModel.swift */,
|
||||
0A6BF4712360C56C0028F841 /* BaseDropdownEntryField.swift */,
|
||||
0A0FEC8D25D4487F00AF2548 /* Date Dropdown */,
|
||||
0A0FEC8A25D4486F00AF2548 /* Item Dropdown */,
|
||||
);
|
||||
path = "Dropdown Fields";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
0A0FEC8A25D4486F00AF2548 /* Item Dropdown */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0A0FEC7725D42A8500AF2548 /* BaseItemPickerEntryFieldModel.swift */,
|
||||
0A0FEC7325D42A5E00AF2548 /* BaseItemPickerEntryField.swift */,
|
||||
0A7EF86423D8AFFF00B2AAD1 /* ItemDropdownEntryFieldModel.swift */,
|
||||
0ABD1370237DB0450081388D /* ItemDropdownEntryField.swift */,
|
||||
0AE277EB25D2EE310048A38D /* MultiItemDropdownEntryFieldModel.swift */,
|
||||
0AE277E825D2ED4B0048A38D /* MultiItemDropdownEntryField.swift */,
|
||||
);
|
||||
path = "Item Dropdown";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
0A0FEC8D25D4487F00AF2548 /* Date Dropdown */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0A7EF86623D8B0AE00B2AAD1 /* DateDropdownEntryFieldModel.swift */,
|
||||
0ABD136C237CAD1E0081388D /* DateDropdownEntryField.swift */,
|
||||
);
|
||||
path = "Date Dropdown";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
0A5D59C323AD488600EFD9E9 /* Protocols */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -1223,6 +1283,8 @@
|
||||
children = (
|
||||
27F973522466074500CAB5C5 /* PageBehavior.swift */,
|
||||
27F97369246750BE00CAB5C5 /* ScreenBrightnessModifierBehavior.swift */,
|
||||
D24918F525D5AD8E00CAB4B1 /* PageVisibilityClosureBehavior.swift */,
|
||||
D24918F925D5ADBA00CAB4B1 /* PageScrolledClosureBehavior.swift */,
|
||||
);
|
||||
path = Behaviors;
|
||||
sourceTree = "<group>";
|
||||
@ -1308,6 +1370,7 @@
|
||||
D2ED27E9254B0CE600A1C293 /* ActionAlertModel.swift */,
|
||||
D2ED27EA254B0CE700A1C293 /* AlertModel.swift */,
|
||||
D2ED27E8254B0CE600A1C293 /* ActionPopupModel.swift */,
|
||||
C6687440259D92D400F32D13 /* ActionTopNotificationModel.swift */,
|
||||
);
|
||||
path = Actions;
|
||||
sourceTree = "<group>";
|
||||
@ -1673,6 +1736,8 @@
|
||||
D29B770F22C281F400D6ACE0 /* ModuleMolecule.swift */,
|
||||
D253BB9D2458751F002DE544 /* BGImageMoleculeModel.swift */,
|
||||
D253BB9B245874F8002DE544 /* BGImageMolecule.swift */,
|
||||
D29C558925C05C7D0082E7D6 /* BGVideoImageMoleculeModel.swift */,
|
||||
D29C558C25C05C990082E7D6 /* BGVideoImageMolecule.swift */,
|
||||
);
|
||||
path = OtherContainers;
|
||||
sourceTree = "<group>";
|
||||
@ -1707,6 +1772,8 @@
|
||||
D2092348244A51D40044AD09 /* RadioSwatchModel.swift */,
|
||||
AAB9C109243496DD00151545 /* RadioSwatch.swift */,
|
||||
AA85236B244435A20059CC1E /* RadioSwatchCollectionViewCell.swift */,
|
||||
D260105223CEA61600764D80 /* ToggleModel.swift */,
|
||||
0AA33B392398524F0067DD0F /* Toggle.swift */,
|
||||
AAA7CD68250641F90045B959 /* HeartModel.swift */,
|
||||
AAA7CD6A250642080045B959 /* Heart.swift */,
|
||||
);
|
||||
@ -2004,8 +2071,6 @@
|
||||
D28A838223CCBD3F00DFE4FC /* WheelModel.swift */,
|
||||
943784F3236B77BB006A1E82 /* Wheel.swift */,
|
||||
943784F4236B77BB006A1E82 /* WheelAnimationHandler.swift */,
|
||||
D260105223CEA61600764D80 /* ToggleModel.swift */,
|
||||
0AA33B392398524F0067DD0F /* Toggle.swift */,
|
||||
0AE98BB623FF18E9004C5109 /* ArrowModel.swift */,
|
||||
0AE98BB423FF18D2004C5109 /* Arrow.swift */,
|
||||
94382085243238D100B43AF3 /* WebViewModel.swift */,
|
||||
@ -2017,6 +2082,9 @@
|
||||
AA37CBD42519072F0027344C /* Stars.swift */,
|
||||
AA07EA902510A442009A2AE3 /* StarModel.swift */,
|
||||
AA07EA922510A451009A2AE3 /* Star.swift */,
|
||||
D29C559525C099630082E7D6 /* VideoDataManager.swift */,
|
||||
D29C559225C0992D0082E7D6 /* VideoModel.swift */,
|
||||
D29C558F25C095210082E7D6 /* Video.swift */,
|
||||
);
|
||||
path = Views;
|
||||
sourceTree = "<group>";
|
||||
@ -2024,23 +2092,18 @@
|
||||
D29DF22B21E6A0FA003B2FB9 /* TextFields */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0A7EF85C23D8A95600B2AAD1 /* TextEntryFieldModel.swift */,
|
||||
0A41BA7E23453A6400D4C0BC /* TextEntryField.swift */,
|
||||
0A7EF85A23D8A52800B2AAD1 /* EntryFieldModel.swift */,
|
||||
0A21DB7E235DECC500C160A2 /* EntryField.swift */,
|
||||
0A7EF85C23D8A95600B2AAD1 /* TextEntryFieldModel.swift */,
|
||||
0A41BA7E23453A6400D4C0BC /* TextEntryField.swift */,
|
||||
0A7EF85E23D8ABC500B2AAD1 /* MdnEntryFieldModel.swift */,
|
||||
0A21DB82235DFBC500C160A2 /* MdnEntryField.swift */,
|
||||
0A8321AE2355FE9500CB7F00 /* DigitBox.swift */,
|
||||
0A7EF86023D8AC2500B2AAD1 /* DigitEntryFieldModel.swift */,
|
||||
0A21DB93235E24ED00C160A2 /* DigitEntryField.swift */,
|
||||
0A7EF86223D8AFA000B2AAD1 /* BaseDropdownEntryFieldModel.swift */,
|
||||
0A6BF4712360C56C0028F841 /* BaseDropdownEntryField.swift */,
|
||||
0A7EF86623D8B0AE00B2AAD1 /* DateDropdownEntryFieldModel.swift */,
|
||||
0ABD136C237CAD1E0081388D /* DateDropdownEntryField.swift */,
|
||||
0A7EF86423D8AFFF00B2AAD1 /* ItemDropdownEntryFieldModel.swift */,
|
||||
0ABD1370237DB0450081388D /* ItemDropdownEntryField.swift */,
|
||||
0A25209724645B76000FA9F6 /* TextViewEntryFieldModel.swift */,
|
||||
0A25209524645AFD000FA9F6 /* TextViewEntryField.swift */,
|
||||
0A0FEC7125D4246000AF2548 /* Dropdown Fields */,
|
||||
);
|
||||
path = TextFields;
|
||||
sourceTree = "<group>";
|
||||
@ -2154,6 +2217,7 @@
|
||||
D2B18B7D236090D500A9AEDC /* BaseClasses */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0A5D59C323AD488600EFD9E9 /* Protocols */,
|
||||
0A6682B3243769C700AD3CA1 /* TextView.swift */,
|
||||
C003506023AA94CD00B6AC29 /* Button.swift */,
|
||||
D2B18B7E2360913400A9AEDC /* Control.swift */,
|
||||
@ -2164,7 +2228,6 @@
|
||||
BB105858248DEFF60069D008 /* UICollectionViewLeftAlignedLayout.swift */,
|
||||
D21B7F70243BAC1600051ABF /* CollectionViewCell.swift */,
|
||||
D264FAA92440F97600D98315 /* CollectionView.swift */,
|
||||
0A5D59C323AD488600EFD9E9 /* Protocols */,
|
||||
0A7918F423F5E7EA00772FF4 /* ImageView.swift */,
|
||||
D272F5F82473163100BD1A8F /* BarButtonItem.swift */,
|
||||
D2EC7BDC2527B83700F540AF /* SectionHeaderFooterView.swift */,
|
||||
@ -2432,6 +2495,7 @@
|
||||
32F8804824765C8400C2ACB3 /* ListLeftVariableNumberedListAllTextAndLinks.swift in Sources */,
|
||||
D2CAC7CF2511052300C75681 /* CollapsableNotificationModel.swift in Sources */,
|
||||
DBC4391822442197001AB423 /* CaretView.swift in Sources */,
|
||||
C6687441259D92D400F32D13 /* ActionTopNotificationModel.swift in Sources */,
|
||||
C07065C42395677300FBF997 /* Link.swift in Sources */,
|
||||
0A69F611241BDEA700F7231B /* RuleAnyRequiredModel.swift in Sources */,
|
||||
D29B771022C281F400D6ACE0 /* ModuleMolecule.swift in Sources */,
|
||||
@ -2445,6 +2509,7 @@
|
||||
D264FAAA2440F97600D98315 /* CollectionView.swift in Sources */,
|
||||
AAC23FAD24D92A0D009208DF /* ListThreeColumnSpeedTestModel.swift in Sources */,
|
||||
BBC0C4FF24811DCA0087C44F /* TagModel.swift in Sources */,
|
||||
0AE277EC25D2EE310048A38D /* MultiItemDropdownEntryFieldModel.swift in Sources */,
|
||||
0A7BAD74232A8DC700FB8E22 /* HeadlineBodyButton.swift in Sources */,
|
||||
3265B30424BCA749000D154B /* HeadersH1NoButtonsBodyText.swift in Sources */,
|
||||
AAA7CD69250641F90045B959 /* HeartModel.swift in Sources */,
|
||||
@ -2459,6 +2524,7 @@
|
||||
D2E1FADB2260D3D200AEFD8C /* MVMCoreUIDelegateObject.swift in Sources */,
|
||||
94382086243238D100B43AF3 /* WebViewModel.swift in Sources */,
|
||||
D28764F9245A327200CB882D /* TwoLinkView.swift in Sources */,
|
||||
0AE277E925D2ED4B0048A38D /* MultiItemDropdownEntryField.swift in Sources */,
|
||||
D27CD40E2322EEAF00C1DC07 /* TabsTableViewCell.swift in Sources */,
|
||||
0A6682B5243769C700AD3CA1 /* TextView.swift in Sources */,
|
||||
D224799B231965AD003FCCF9 /* AccordionMoleculeTableViewCell.swift in Sources */,
|
||||
@ -2559,6 +2625,7 @@
|
||||
D2CAC7CB251104E100C75681 /* NotificationXButtonModel.swift in Sources */,
|
||||
014AA73123C5059B006F3E93 /* ListPageTemplateModel.swift in Sources */,
|
||||
AAC23FAF24D92A1E009208DF /* ListThreeColumnSpeedTest.swift in Sources */,
|
||||
0A0FEC7425D42A5E00AF2548 /* BaseItemPickerEntryField.swift in Sources */,
|
||||
D29DF2A221E7AF4E003B2FB9 /* MVMCoreUIUtility.m in Sources */,
|
||||
D29DF12B21E6851E003B2FB9 /* MVMCoreUITopAlertExpandableView.m in Sources */,
|
||||
D2ED27ED254B0CE700A1C293 /* ActionPopupModel.swift in Sources */,
|
||||
@ -2674,6 +2741,7 @@
|
||||
BB55B51D244482C1002001AD /* ListRightVariablePriceChangeBodyText.swift in Sources */,
|
||||
017BEB382360C6AC0024EF95 /* RadioButtonLabel.swift in Sources */,
|
||||
323AC96C24C837FF00F8E4C4 /* ListThreeColumnBillChanges.swift in Sources */,
|
||||
0A0FEC7825D42A8500AF2548 /* BaseItemPickerEntryFieldModel.swift in Sources */,
|
||||
D28A837923C7D5BC00DFE4FC /* PageModelProtocol.swift in Sources */,
|
||||
D2351C7C24A4D4C3007DF0BC /* ListRightVariableToggleAllTextAndLinks.swift in Sources */,
|
||||
017BEB7B236763000024EF95 /* LineModel.swift in Sources */,
|
||||
@ -2681,6 +2749,7 @@
|
||||
94C2D9A523872C350006CF46 /* LabelAttributeFontModel.swift in Sources */,
|
||||
011D958724042492000E3791 /* FormFieldProtocol.swift in Sources */,
|
||||
011D95AF2407266E000E3791 /* RadioButtonModel.swift in Sources */,
|
||||
D24918F625D5AD8E00CAB4B1 /* PageVisibilityClosureBehavior.swift in Sources */,
|
||||
D20492A624329CE200A5EED6 /* LoadImageView.swift in Sources */,
|
||||
017BEB7F23676E870024EF95 /* MoleculeObjectMapping.swift in Sources */,
|
||||
D274CA332236A78900B01B62 /* FooterView.swift in Sources */,
|
||||
@ -2738,6 +2807,7 @@
|
||||
AA104AC924472DC7004D2810 /* HeadersH1ButtonModel.swift in Sources */,
|
||||
0ABD1371237DB0450081388D /* ItemDropdownEntryField.swift in Sources */,
|
||||
D20C7009250BF99B0095B21C /* TopNotificationModel.swift in Sources */,
|
||||
D29C558A25C05C7D0082E7D6 /* BGVideoImageMoleculeModel.swift in Sources */,
|
||||
8D24041123E7FB9E009E23BE /* ListLeftVariableIconWithRightCaret.swift in Sources */,
|
||||
BB2FB3BD247E7EF200DF73CD /* Tags.swift in Sources */,
|
||||
AA104ADC244734EA004D2810 /* HeadersH1LandingPageHeaderModel.swift in Sources */,
|
||||
@ -2765,6 +2835,7 @@
|
||||
012A88DB238ED45900FE3DA1 /* CarouselModel.swift in Sources */,
|
||||
D2092355244FA0FD0044AD09 /* ThreeLayerTemplateModelProtocol.swift in Sources */,
|
||||
0AE14F64238315D2005417F8 /* TextField.swift in Sources */,
|
||||
D24918FA25D5ADBB00CAB4B1 /* PageScrolledClosureBehavior.swift in Sources */,
|
||||
0A51F3E22475CB73002E08B6 /* LoadingSpinnerModel.swift in Sources */,
|
||||
D2169303251E53D9002A6324 /* SectionListTemplateModel.swift in Sources */,
|
||||
0AB764D124460F6300E7FE72 /* UIDatePicker+Extension.swift in Sources */,
|
||||
@ -2777,6 +2848,7 @@
|
||||
D27CD4102339057800C1DC07 /* EyebrowHeadlineBodyLink.swift in Sources */,
|
||||
AAB7EDF1246ADA2A00E54929 /* ListProgressBarThin.swift in Sources */,
|
||||
8D070BB2241B56AD0099AC56 /* ListRightVariableTotalData.swift in Sources */,
|
||||
D29C559325C0992D0082E7D6 /* VideoModel.swift in Sources */,
|
||||
D264FAA5243F66A500D98315 /* CollectionTemplateItemProtocol.swift in Sources */,
|
||||
D29DF11D21E684A9003B2FB9 /* MVMCoreUISplitViewController.m in Sources */,
|
||||
AA71AD3E24A32FCE00ACA76F /* HeadersH2LinkModel.swift in Sources */,
|
||||
@ -2840,8 +2912,10 @@
|
||||
012A889C23889E8400FE3DA1 /* TemplateModelProtocol.swift in Sources */,
|
||||
52267A0723FFE25000906CBA /* ListOneColumnFullWidthTextAllTextAndLinks.swift in Sources */,
|
||||
D2ED2812254B0EB800A1C293 /* MVMCoreTopAlertObject.m in Sources */,
|
||||
0AA4D2E125CAEC72008DB32D /* AccessibilityModelProtocol.swift in Sources */,
|
||||
C003506123AA94CD00B6AC29 /* Button.swift in Sources */,
|
||||
DBC4391B224421A0001AB423 /* CaretLink.swift in Sources */,
|
||||
D29C559025C095210082E7D6 /* Video.swift in Sources */,
|
||||
D264FA90243BCE6800D98315 /* ThreeLayerCollectionViewController.swift in Sources */,
|
||||
AA104B1C24474A76004D2810 /* HeadersH2ButtonsModel.swift in Sources */,
|
||||
0A6BF4722360C56C0028F841 /* BaseDropdownEntryField.swift in Sources */,
|
||||
@ -2855,7 +2929,7 @@
|
||||
D2D2FCF0252B72AF0033EAAA /* MoleculeSectionFooterModel.swift in Sources */,
|
||||
BB1D17E2244EAA46001D2002 /* ListDeviceComplexButtonMedium.swift in Sources */,
|
||||
D2FA83D42514F80C00564112 /* CollapsableNotification.swift in Sources */,
|
||||
0A7EF86323D8AFA000B2AAD1 /* BaseDropdownEntryFieldModel.swift in Sources */,
|
||||
0A7EF86323D8AFA000B2AAD1 /* BaseDropdownFieldModel.swift in Sources */,
|
||||
0A1214A022C11A18007C7030 /* ActionDetailWithImage.swift in Sources */,
|
||||
D236E5B5241FEB1000C38625 /* ListTwoColumnPriceDescriptionModel.swift in Sources */,
|
||||
D2B18B922361E65A00A9AEDC /* CoreUIObject.swift in Sources */,
|
||||
@ -2867,6 +2941,7 @@
|
||||
BB6C6AC924225290005F7224 /* ListOneColumnTextWithWhitespaceDividerShortModel.swift in Sources */,
|
||||
C695A69423C9909000BFB94E /* DoughnutChartModel.swift in Sources */,
|
||||
D2D3957D252FDBCD00047B11 /* ModalSectionListTemplateModel.swift in Sources */,
|
||||
D29C559625C099630082E7D6 /* VideoDataManager.swift in Sources */,
|
||||
8D4687E2242E2DE400802879 /* ListFourColumnDataUsageListItemModel.swift in Sources */,
|
||||
D29E28DD23D7404C00ACEA85 /* ContainerHelper.swift in Sources */,
|
||||
012A88C2238D7BCA00FE3DA1 /* CarouselItemModel.swift in Sources */,
|
||||
@ -2884,6 +2959,7 @@
|
||||
AA633B3324989ED500731E80 /* HeadersH2PricingTwoRows.swift in Sources */,
|
||||
01509D8F2327EC6F00EF99AA /* MoleculeTableViewCell.swift in Sources */,
|
||||
0A6682A22434DB4F00AD3CA1 /* ListLeftVariableRadioButtonBodyText.swift in Sources */,
|
||||
D29C558D25C05C990082E7D6 /* BGVideoImageMolecule.swift in Sources */,
|
||||
EA5124FD243601600051A3A4 /* BGImageHeadlineBodyButton.swift in Sources */,
|
||||
0105618D224BBE7700E1557D /* FormValidator.swift in Sources */,
|
||||
01509D912327ECE600EF99AA /* CornerLabels.swift in Sources */,
|
||||
@ -2957,6 +3033,7 @@
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
@ -3022,6 +3099,7 @@
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
|
||||
24
MVMCoreUI/Atomic/Actions/ActionTopNotificationModel.swift
Normal file
24
MVMCoreUI/Atomic/Actions/ActionTopNotificationModel.swift
Normal file
@ -0,0 +1,24 @@
|
||||
//
|
||||
// ActionTopNotificationModel.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Murugan, Vimal on 31/12/20.
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
@objcMembers public class ActionTopNotificationModel: ActionModelProtocol {
|
||||
|
||||
public static var identifier: String = "topNotification"
|
||||
public var actionType: String = ActionTopNotificationModel.identifier
|
||||
public var topNotification: TopNotificationModel
|
||||
public var extraParameters: JSONValueDictionary?
|
||||
public var analyticsData: JSONValueDictionary?
|
||||
|
||||
public init(topNotification: TopNotificationModel, _ extraParameters: JSONValueDictionary? = nil, _ analyticsData: JSONValueDictionary? = nil) {
|
||||
self.topNotification = topNotification
|
||||
self.extraParameters = extraParameters
|
||||
self.analyticsData = analyticsData
|
||||
}
|
||||
}
|
||||
@ -18,6 +18,7 @@ public class ButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGroupW
|
||||
|
||||
public static var identifier: String = "button"
|
||||
public var backgroundColor: Color?
|
||||
public var accessibilityIdentifier: String?
|
||||
public var title: String
|
||||
public var action: ActionModelProtocol
|
||||
public var enabled: Bool = true
|
||||
@ -93,27 +94,27 @@ public class ButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGroupW
|
||||
//--------------------------------------------------
|
||||
|
||||
public func enabled_fillColor() -> UIColor? {
|
||||
return (inverted ? enabledFillColor_inverted : enabledFillColor)?.uiColor
|
||||
(inverted ? enabledFillColor_inverted : enabledFillColor)?.uiColor
|
||||
}
|
||||
|
||||
public func enabled_textColor() -> UIColor? {
|
||||
return (inverted ? enabledTextColor_inverted : enabledTextColor)?.uiColor
|
||||
(inverted ? enabledTextColor_inverted : enabledTextColor)?.uiColor
|
||||
}
|
||||
|
||||
public func enabled_borderColor() -> UIColor? {
|
||||
return (inverted ? enabledBorderColor_inverted : enabledBorderColor)?.uiColor
|
||||
(inverted ? enabledBorderColor_inverted : enabledBorderColor)?.uiColor
|
||||
}
|
||||
|
||||
public func disabled_fillColor() -> UIColor? {
|
||||
return (inverted ? disabledFillColor_inverted : disabledFillColor)?.uiColor
|
||||
(inverted ? disabledFillColor_inverted : disabledFillColor)?.uiColor
|
||||
}
|
||||
|
||||
public func disabled_textColor() -> UIColor? {
|
||||
return (inverted ? disabledTextColor_inverted : disabledTextColor)?.uiColor
|
||||
(inverted ? disabledTextColor_inverted : disabledTextColor)?.uiColor
|
||||
}
|
||||
|
||||
public func disabled_borderColor() -> UIColor? {
|
||||
return (inverted ? disabledBorderColor_inverted : disabledBorderColor)?.uiColor
|
||||
(inverted ? disabledBorderColor_inverted : disabledBorderColor)?.uiColor
|
||||
}
|
||||
|
||||
/// Defines the default appearance for the primary style.
|
||||
@ -172,6 +173,7 @@ public class ButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGroupW
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case moleculeName
|
||||
case backgroundColor
|
||||
case accessibilityIdentifier
|
||||
case title
|
||||
case inverted
|
||||
case action
|
||||
@ -195,6 +197,7 @@ public class ButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGroupW
|
||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
|
||||
accessibilityIdentifier = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityIdentifier)
|
||||
title = try typeContainer.decode(String.self, forKey: .title)
|
||||
action = try typeContainer.decodeModel(codingKey: .action)
|
||||
|
||||
@ -252,6 +255,7 @@ public class ButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGroupW
|
||||
try container.encode(inverted, forKey: .inverted)
|
||||
try container.encodeModel(action, forKey: .action)
|
||||
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
|
||||
try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier)
|
||||
try container.encodeIfPresent(enabledFillColor, forKey: .fillColor)
|
||||
try container.encodeIfPresent(enabledTextColor, forKey: .textColor)
|
||||
try container.encodeIfPresent(enabledBorderColor, forKey: .borderColor)
|
||||
|
||||
@ -127,7 +127,6 @@ open class CaretLink: Button, MVMCoreUIViewConstrainingProtocol {
|
||||
}
|
||||
|
||||
public func updateCaretSpacing(_ spacing: CGFloat) {
|
||||
|
||||
caretSpacingConstraint?.constant = spacing
|
||||
}
|
||||
|
||||
@ -151,15 +150,9 @@ open class CaretLink: Button, MVMCoreUIViewConstrainingProtocol {
|
||||
setTitle(model.title, for: .normal)
|
||||
}
|
||||
|
||||
public func needsToBeConstrained() -> Bool {
|
||||
return true
|
||||
}
|
||||
public func needsToBeConstrained() -> Bool { true }
|
||||
|
||||
open func horizontalAlignment() -> UIStackView.Alignment {
|
||||
return .leading
|
||||
}
|
||||
open func horizontalAlignment() -> UIStackView.Alignment { .leading }
|
||||
|
||||
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
|
||||
return 10.5
|
||||
}
|
||||
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { 10.5 }
|
||||
}
|
||||
|
||||
@ -17,6 +17,7 @@ public class CaretLinkModel: ButtonModelProtocol, MoleculeModelProtocol, Enablea
|
||||
|
||||
public static var identifier: String = "caretLink"
|
||||
public var backgroundColor: Color?
|
||||
public var accessibilityIdentifier: String?
|
||||
public var title: String
|
||||
public var action: ActionModelProtocol
|
||||
public var enabledColor: Color = Color(uiColor: .mvmBlack)
|
||||
@ -41,6 +42,7 @@ public class CaretLinkModel: ButtonModelProtocol, MoleculeModelProtocol, Enablea
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case backgroundColor
|
||||
case accessibilityIdentifier
|
||||
case title
|
||||
case action
|
||||
case enabledColor_inverted
|
||||
@ -60,6 +62,7 @@ public class CaretLinkModel: ButtonModelProtocol, MoleculeModelProtocol, Enablea
|
||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
|
||||
accessibilityIdentifier = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityIdentifier)
|
||||
title = try typeContainer.decode(String.self, forKey: .title)
|
||||
|
||||
if let enabledColor_inverted = try typeContainer.decodeIfPresent(Color.self, forKey: .enabledColor_inverted) {
|
||||
@ -94,6 +97,7 @@ public class CaretLinkModel: ButtonModelProtocol, MoleculeModelProtocol, Enablea
|
||||
try container.encode(moleculeName, forKey: .moleculeName)
|
||||
try container.encode(title, forKey: .title)
|
||||
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
|
||||
try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier)
|
||||
try container.encodeModel(action, forKey: .action)
|
||||
try container.encode(enabled, forKey: .enabledColor)
|
||||
try container.encodeIfPresent(disabledColor, forKey: .disabledColor)
|
||||
|
||||
@ -11,18 +11,18 @@ import UIKit
|
||||
|
||||
@objcMembers open class Link: Button {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Lifecycle
|
||||
// MARK: - Draw
|
||||
//--------------------------------------------------
|
||||
|
||||
open override func draw(_ rect: CGRect) {
|
||||
|
||||
guard let textRect = titleLabel?.frame else { return }
|
||||
|
||||
let context = UIGraphicsGetCurrentContext()
|
||||
guard let textRect = titleLabel?.frame,
|
||||
let context = UIGraphicsGetCurrentContext()
|
||||
else { return }
|
||||
|
||||
// Set line to the same color as the text
|
||||
if let color = titleLabel?.textColor?.cgColor {
|
||||
context?.setStrokeColor(color)
|
||||
context.setStrokeColor(color)
|
||||
}
|
||||
|
||||
// x should be according to the text, not the button
|
||||
@ -31,9 +31,9 @@ import UIKit
|
||||
// Line is 1 point below the text
|
||||
let y = textRect.origin.y + textRect.size.height + 1
|
||||
|
||||
context?.move(to: CGPoint(x: x, y: y))
|
||||
context?.addLine(to: CGPoint(x: x + textRect.size.width, y: y))
|
||||
context?.strokePath()
|
||||
context.move(to: CGPoint(x: x, y: y))
|
||||
context.addLine(to: CGPoint(x: x + textRect.size.width, y: y))
|
||||
context.strokePath()
|
||||
}
|
||||
|
||||
open override var intrinsicContentSize: CGSize {
|
||||
@ -58,9 +58,7 @@ import UIKit
|
||||
set(with: model.action, delegateObject: delegateObject, additionalData: additionalData)
|
||||
}
|
||||
|
||||
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
|
||||
return 31
|
||||
}
|
||||
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { 31 }
|
||||
}
|
||||
|
||||
// MARK: - MVMCoreViewProtocol
|
||||
@ -69,16 +67,12 @@ extension Link {
|
||||
open override func updateView(_ size: CGFloat) {
|
||||
super.updateView(size)
|
||||
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
guard let self = self else { return }
|
||||
|
||||
var width = size
|
||||
if MVMCoreGetterUtility.fequal(a: Float.leastNormalMagnitude, b: Float(size)) {
|
||||
width = MVMCoreUIUtility.getWidth()
|
||||
}
|
||||
|
||||
self.titleLabel?.font = MFStyler.fontB2(forWidth: width)
|
||||
var width = size
|
||||
if MVMCoreGetterUtility.fequal(a: Float.leastNormalMagnitude, b: Float(size)) {
|
||||
width = MVMCoreUIUtility.getWidth()
|
||||
}
|
||||
|
||||
titleLabel?.font = MFStyler.fontB2(forWidth: width)
|
||||
}
|
||||
|
||||
open override func setupView() {
|
||||
@ -98,7 +92,5 @@ extension Link {
|
||||
// MARK: - MVMCoreUIViewConstrainingProtocol
|
||||
extension Link: MVMCoreUIViewConstrainingProtocol {
|
||||
|
||||
open func horizontalAlignment() -> UIStackView.Alignment {
|
||||
return .leading
|
||||
}
|
||||
open func horizontalAlignment() -> UIStackView.Alignment { .leading }
|
||||
}
|
||||
|
||||
@ -14,11 +14,10 @@ open class LinkModel: ButtonModelProtocol, MoleculeModelProtocol, EnableableMode
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
public class var identifier: String {
|
||||
return "link"
|
||||
}
|
||||
public class var identifier: String { "link" }
|
||||
|
||||
public var backgroundColor: Color?
|
||||
public var accessibilityIdentifier: String?
|
||||
public var title: String
|
||||
public var action: ActionModelProtocol
|
||||
public var enabled = true
|
||||
@ -44,6 +43,7 @@ open class LinkModel: ButtonModelProtocol, MoleculeModelProtocol, EnableableMode
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case moleculeName
|
||||
case backgroundColor
|
||||
case accessibilityIdentifier
|
||||
case title
|
||||
case action
|
||||
case enabled
|
||||
@ -62,6 +62,7 @@ open class LinkModel: ButtonModelProtocol, MoleculeModelProtocol, EnableableMode
|
||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
|
||||
accessibilityIdentifier = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityIdentifier)
|
||||
title = try typeContainer.decode(String.self, forKey: .title)
|
||||
action = try typeContainer.decodeModel(codingKey: .action)
|
||||
|
||||
@ -95,6 +96,7 @@ open class LinkModel: ButtonModelProtocol, MoleculeModelProtocol, EnableableMode
|
||||
try container.encode(title, forKey: .title)
|
||||
try container.encode(moleculeName, forKey: .moleculeName)
|
||||
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
|
||||
try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier)
|
||||
try container.encodeModel(action, forKey: .action)
|
||||
try container.encode(inverted, forKey: .inverted)
|
||||
try container.encode(enabled, forKey: .enabled)
|
||||
|
||||
@ -18,7 +18,7 @@ open class PillButton: Button, MVMCoreUIViewConstrainingProtocol {
|
||||
var size = MVMCoreUIUtility.getWidth()
|
||||
|
||||
var buttonModel: ButtonModel? {
|
||||
get { return model as? ButtonModel }
|
||||
get { model as? ButtonModel }
|
||||
}
|
||||
|
||||
/// Need to re-style on set.
|
||||
@ -27,9 +27,7 @@ open class PillButton: Button, MVMCoreUIViewConstrainingProtocol {
|
||||
}
|
||||
|
||||
open var buttonSize: Styler.Button.Size = .standard {
|
||||
didSet {
|
||||
buttonModel?.size = buttonSize
|
||||
}
|
||||
didSet { buttonModel?.size = buttonSize }
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
@ -47,12 +45,12 @@ open class PillButton: Button, MVMCoreUIViewConstrainingProtocol {
|
||||
//--------------------------------------------------
|
||||
|
||||
public var enabledTitleColor: UIColor? {
|
||||
get { return titleColor(for: .normal) }
|
||||
get { titleColor(for: .normal) }
|
||||
set { setTitleColor(newValue, for: .normal) }
|
||||
}
|
||||
|
||||
public var disabledTitleColor: UIColor? {
|
||||
get { return titleColor(for: .disabled) }
|
||||
get { titleColor(for: .disabled) }
|
||||
set { setTitleColor(newValue, for: .disabled) }
|
||||
}
|
||||
|
||||
@ -106,6 +104,11 @@ open class PillButton: Button, MVMCoreUIViewConstrainingProtocol {
|
||||
self.disabledTitleColor = disabledTitleColor
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
// Useful to detect with isHittable when performing UI testing.
|
||||
isAccessibilityElement = isEnabled
|
||||
#endif
|
||||
|
||||
if isEnabled {
|
||||
if let fillColor = buttonModel?.enabledColors.fill {
|
||||
backgroundColor = fillColor
|
||||
@ -128,7 +131,7 @@ open class PillButton: Button, MVMCoreUIViewConstrainingProtocol {
|
||||
}
|
||||
|
||||
private func getInnerPadding() -> CGFloat {
|
||||
return getHeight() / 2.0
|
||||
getHeight() / 2.0
|
||||
}
|
||||
|
||||
private func getHeight() -> CGFloat {
|
||||
@ -181,9 +184,11 @@ open class PillButton: Button, MVMCoreUIViewConstrainingProtocol {
|
||||
|
||||
guard let model = model as? ButtonModel else { return }
|
||||
setTitle(model.title, for: .normal)
|
||||
|
||||
if let size = model.size {
|
||||
buttonSize = size
|
||||
}
|
||||
|
||||
model.updateUI = { [weak self] in
|
||||
MVMCoreDispatchUtility.performBlock(onMainThread: {
|
||||
self?.enableField(model.enabled)
|
||||
@ -228,9 +233,7 @@ open class PillButton: Button, MVMCoreUIViewConstrainingProtocol {
|
||||
// MARK: - MVMCoreUIViewConstrainingProtocol
|
||||
//--------------------------------------------------
|
||||
|
||||
open func horizontalAlignment() -> UIStackView.Alignment {
|
||||
return .center
|
||||
}
|
||||
open func horizontalAlignment() -> UIStackView.Alignment { .center }
|
||||
|
||||
public func enableField(_ enable: Bool) {
|
||||
isEnabled = enable
|
||||
|
||||
@ -43,7 +43,7 @@ import UIKit
|
||||
//--------------------------------------------------
|
||||
|
||||
public override var showError: Bool {
|
||||
get { return super.showError }
|
||||
get { super.showError }
|
||||
set (error) {
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
guard let self = self else { return }
|
||||
@ -80,7 +80,7 @@ import UIKit
|
||||
|
||||
open override func setupView() {
|
||||
super.setupView()
|
||||
|
||||
|
||||
addSubview(digitField)
|
||||
digitField.delegate = self
|
||||
digitField.didDeleteDelegate = self
|
||||
@ -140,7 +140,7 @@ import UIKit
|
||||
super.updateView(size)
|
||||
|
||||
if !MVMCoreGetterUtility.fequal(a: Float(size), b: Float(previousSize)) {
|
||||
|
||||
|
||||
var width: CGFloat = 0
|
||||
var height: CGFloat = 0
|
||||
var pointSize: CGFloat = 13
|
||||
|
||||
@ -75,7 +75,7 @@ import UIKit
|
||||
private var selectedDigitBox: DigitBox?
|
||||
|
||||
public var digitEntryModel: DigitEntryFieldModel? {
|
||||
return model as? DigitEntryFieldModel
|
||||
model as? DigitEntryFieldModel
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
@ -83,7 +83,7 @@ import UIKit
|
||||
//--------------------------------------------------
|
||||
|
||||
public override var isEnabled: Bool {
|
||||
get { return super.isEnabled }
|
||||
get { super.isEnabled }
|
||||
set (enabled) {
|
||||
digitBoxes.forEach { $0.isEnabled = enabled }
|
||||
super.isEnabled = enabled
|
||||
@ -91,7 +91,7 @@ import UIKit
|
||||
}
|
||||
|
||||
public override var showError: Bool {
|
||||
get { return super.showError }
|
||||
get { super.showError }
|
||||
set (error) {
|
||||
digitBoxes.forEach { $0.showError = error }
|
||||
super.showError = error
|
||||
@ -99,7 +99,7 @@ import UIKit
|
||||
}
|
||||
|
||||
public override var isLocked: Bool {
|
||||
get { return super.isLocked }
|
||||
get { super.isLocked }
|
||||
set (locked) {
|
||||
digitBoxes.forEach { $0.isLocked = locked }
|
||||
super.isLocked = locked
|
||||
@ -162,7 +162,7 @@ import UIKit
|
||||
|
||||
/// If you're using a MFViewController, you must set this to it
|
||||
public override weak var uiTextFieldDelegate: UITextFieldDelegate? {
|
||||
get { return textField.delegate }
|
||||
get { textField.delegate }
|
||||
set {
|
||||
textField.delegate = self
|
||||
proprietorTextDelegate = newValue
|
||||
@ -357,9 +357,7 @@ import UIKit
|
||||
super.set(with: model, delegateObject, additionalData)
|
||||
}
|
||||
|
||||
public override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
|
||||
return 115
|
||||
}
|
||||
public override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { 115 }
|
||||
}
|
||||
|
||||
// MARK: - TextField Delegate
|
||||
@ -452,11 +450,11 @@ extension DigitEntryField {
|
||||
|
||||
@objc public func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
|
||||
|
||||
return proprietorTextDelegate?.textFieldShouldBeginEditing?(textField) ?? true
|
||||
proprietorTextDelegate?.textFieldShouldBeginEditing?(textField) ?? true
|
||||
}
|
||||
|
||||
@objc public func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
|
||||
|
||||
return proprietorTextDelegate?.textFieldShouldEndEditing?(textField) ?? true
|
||||
proprietorTextDelegate?.textFieldShouldEndEditing?(textField) ?? true
|
||||
}
|
||||
}
|
||||
|
||||
@ -12,12 +12,10 @@
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
public override class var identifier: String {
|
||||
return "digitTextField"
|
||||
}
|
||||
public override class var identifier: String { "digitTextField" }
|
||||
|
||||
public var digits: Int = 4
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Keys
|
||||
//--------------------------------------------------
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
//
|
||||
// BaseDropdownEntryField.swift
|
||||
// BaseDropdownField.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Kevin Christiano on 10/23/19.
|
||||
@ -28,8 +28,9 @@ import UIKit
|
||||
}()
|
||||
|
||||
public var baseDropdownEntryFieldModel: BaseDropdownEntryFieldModel? {
|
||||
return model as? BaseDropdownEntryFieldModel
|
||||
model as? BaseDropdownEntryFieldModel
|
||||
}
|
||||
|
||||
var additionalData: [AnyHashable: Any]?
|
||||
|
||||
//--------------------------------------------------
|
||||
@ -54,7 +55,7 @@ import UIKit
|
||||
|
||||
@objc required public init?(coder: NSCoder) {
|
||||
super.init(coder: coder)
|
||||
fatalError("DropdownEntryField does not support xib.")
|
||||
fatalError("\(String(describing: Self.self)) does not support xib.")
|
||||
}
|
||||
|
||||
required public init(model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||
@ -86,15 +87,15 @@ import UIKit
|
||||
dropDownCaretView.setOptional(with: model.caretView, delegateObject, additionalData)
|
||||
}
|
||||
|
||||
public override func dismissFieldInput(_ sender: Any?) {
|
||||
performDropdownAction()
|
||||
super.dismissFieldInput(sender)
|
||||
}
|
||||
@objc public override func dismissFieldInput(_ sender: Any?) {
|
||||
performDropdownAction()
|
||||
super.dismissFieldInput(sender)
|
||||
}
|
||||
|
||||
func performDropdownAction() {
|
||||
if let baseDropdownEntryFieldModel = baseDropdownEntryFieldModel, let actionModel = baseDropdownEntryFieldModel.action, let actionMap = actionModel.toJSON() {
|
||||
if let baseDropdownEntryFieldModel = baseDropdownEntryFieldModel, let actionModel = baseDropdownEntryFieldModel.action {
|
||||
let additionalDataWithSource = additionalData.dictionaryAdding(key: KeySourceModel, value: baseDropdownEntryFieldModel)
|
||||
MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalDataWithSource, delegateObject: delegateObject)
|
||||
MVMCoreActionHandler.shared()?.asyncHandleAction(with: actionModel, additionalData: additionalDataWithSource, delegateObject: delegateObject)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -14,9 +14,7 @@
|
||||
public var caretView: CaretViewModel?
|
||||
public var action: ActionModelProtocol?
|
||||
|
||||
public override class var identifier: String {
|
||||
return ""
|
||||
}
|
||||
public override class var identifier: String { "" }
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Keys
|
||||
@ -29,7 +27,7 @@
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializers
|
||||
// MARK: - Codec
|
||||
//--------------------------------------------------
|
||||
|
||||
required public init(from decoder: Decoder) throws {
|
||||
@ -23,15 +23,15 @@ import UIKit
|
||||
}()
|
||||
|
||||
public var dateFormat: String? {
|
||||
get { dateDropdownModel?.dateFormat }
|
||||
set {
|
||||
guard let newValue = newValue else { return }
|
||||
dateDropdownModel?.dateFormat = newValue
|
||||
}
|
||||
get { return dateDropdownModel?.dateFormat }
|
||||
}
|
||||
|
||||
public var dateDropdownModel: DateDropdownEntryFieldModel? {
|
||||
return model as? DateDropdownEntryFieldModel
|
||||
model as? DateDropdownEntryFieldModel
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
@ -69,6 +69,7 @@ import UIKit
|
||||
datePicker = UIDatePicker.addDatePicker(to: textField)
|
||||
datePicker?.addTarget(self, action: #selector(pickerValueChanged), for: .valueChanged)
|
||||
datePicker?.timeZone = NSTimeZone.system
|
||||
textField.inputView = datePicker
|
||||
UIToolbar.addDismissToolbar(to: textField, delegate: self, action: #selector(dismissFieldInput))
|
||||
}
|
||||
|
||||
@ -11,9 +11,7 @@
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
public override class var identifier: String {
|
||||
return "dateDropdownEntryField"
|
||||
}
|
||||
public override class var identifier: String { "dateDropdownEntryField" }
|
||||
|
||||
public var dateFormatter: DateFormatter = {
|
||||
let formatter = DateFormatter()
|
||||
@ -0,0 +1,85 @@
|
||||
//
|
||||
// BaseItemPickerEntryField.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Kevin Christiano on 2/10/21.
|
||||
// Copyright © 2021 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
public typealias TextFieldAndPickerDelegate = (UITextFieldDelegate & UIPickerViewDelegate & UIPickerViewDataSource)
|
||||
|
||||
|
||||
open class BaseItemPickerEntryField: BaseDropdownEntryField, UIPickerViewDelegate, UIPickerViewDataSource {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Outlets
|
||||
//--------------------------------------------------
|
||||
|
||||
open lazy var pickerView = UIPickerView.addPicker(to: textField, delegate: self, dismissAction: #selector(dismissFieldInput))
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
/// Closure passed here will run as picker changes items.
|
||||
public var observeDropdownChange: ((String, String) -> ())?
|
||||
|
||||
/// Closure passed here will run upon dismissing the selection picker.
|
||||
public var observeDropdownSelection: ((String) -> ())?
|
||||
|
||||
/// When selecting for first responder, allow initial selected value to appear in empty text field.
|
||||
public var setInitialValueInTextField = true
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Methods
|
||||
//--------------------------------------------------
|
||||
|
||||
@objc open override func setupFieldContainerContent(_ container: UIView) {
|
||||
super.setupFieldContainerContent(container)
|
||||
|
||||
textField.hideBlinkingCaret = true
|
||||
textField.autocorrectionType = .no
|
||||
uiTextFieldDelegate = self
|
||||
}
|
||||
|
||||
@objc public func setPickerDelegates(delegate: UIPickerViewDelegate & UIPickerViewDataSource) {
|
||||
|
||||
pickerView.delegate = delegate
|
||||
pickerView.dataSource = delegate
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Molecular
|
||||
//--------------------------------------------------
|
||||
|
||||
public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||
super.set(with: model, delegateObject, additionalData)
|
||||
|
||||
setPickerDelegates(delegate: self)
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Picker Delegate to Override
|
||||
//--------------------------------------------------
|
||||
|
||||
public func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { 0 }
|
||||
|
||||
public func numberOfComponents(in pickerView: UIPickerView) -> Int { 0 }
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Accessibility
|
||||
extension BaseItemPickerEntryField {
|
||||
|
||||
@objc open override func setAccessibilityString(_ accessibilityString: String?) {
|
||||
|
||||
var accessibilityString = accessibilityString ?? ""
|
||||
|
||||
if let textPickerItem = MVMCoreUIUtility.hardcodedString(withKey: "textfield_picker_item") {
|
||||
accessibilityString += textPickerItem
|
||||
}
|
||||
|
||||
textField.accessibilityLabel = "\(accessibilityString) \(textField.isEnabled ? "" : MVMCoreUIUtility.hardcodedString(withKey: "textfield_disabled_state") ?? "")"
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
//
|
||||
// BaseItemPickerEntryFieldModel.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Kevin Christiano on 2/10/21.
|
||||
// Copyright © 2021 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
|
||||
open class BaseItemPickerEntryFieldModel: BaseDropdownEntryFieldModel {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
public override class var identifier: String { "" }
|
||||
}
|
||||
@ -8,28 +8,16 @@
|
||||
|
||||
import UIKit
|
||||
|
||||
public typealias TextFieldAndPickerDelegate = (UITextFieldDelegate & UIPickerViewDelegate & UIPickerViewDataSource)
|
||||
|
||||
|
||||
open class ItemDropdownEntryField: BaseDropdownEntryField {
|
||||
open class ItemDropdownEntryField: BaseItemPickerEntryField {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
open var pickerData: [String] = []
|
||||
open var pickerView: UIPickerView?
|
||||
|
||||
/// When selecting for first responder, allow initial selected value to appear in empty text field.
|
||||
public var setInitialValueInTextField = true
|
||||
|
||||
/// Closure passed here will run as picker changes items.
|
||||
public var observeDropdownChange: ((String, String)->())?
|
||||
|
||||
/// Closure passed here will run upon dismissing the selection picker.
|
||||
public var observeDropdownSelection: ((String)->())?
|
||||
|
||||
public var itemDropdownEntryFieldModel: ItemDropdownEntryFieldModel? {
|
||||
return model as? ItemDropdownEntryFieldModel
|
||||
model as? ItemDropdownEntryFieldModel
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
@ -61,26 +49,13 @@ open class ItemDropdownEntryField: BaseDropdownEntryField {
|
||||
// MARK: - Methods
|
||||
//--------------------------------------------------
|
||||
|
||||
@objc open override func setupFieldContainerContent(_ container: UIView) {
|
||||
super.setupFieldContainerContent(container)
|
||||
|
||||
pickerView = UIPickerView.addPicker(to: textField, delegate: self, dismissAction: #selector(dismissFieldInput))
|
||||
textField.hideBlinkingCaret = true
|
||||
textField.autocorrectionType = .no
|
||||
uiTextFieldDelegate = self
|
||||
}
|
||||
|
||||
@objc public func setPickerDelegates(delegate: UIPickerViewDelegate & UIPickerViewDataSource) {
|
||||
|
||||
pickerView?.delegate = delegate
|
||||
pickerView?.dataSource = delegate
|
||||
}
|
||||
|
||||
/// Sets the textField with the first value of the available picker data.
|
||||
@objc private func setInitialValueFromPicker() {
|
||||
|
||||
guard !pickerData.isEmpty else { return }
|
||||
|
||||
if setInitialValueInTextField, let pickerIndex = pickerView?.selectedRow(inComponent: 0) {
|
||||
if setInitialValueInTextField {
|
||||
let pickerIndex = pickerView.selectedRow(inComponent: 0)
|
||||
observeDropdownChange?(text ?? "", pickerData[pickerIndex])
|
||||
text = pickerData[pickerIndex]
|
||||
itemDropdownEntryFieldModel?.selectedIndex = pickerIndex
|
||||
@ -98,9 +73,7 @@ open class ItemDropdownEntryField: BaseDropdownEntryField {
|
||||
|
||||
guard !pickerData.isEmpty else { return }
|
||||
|
||||
if let pickerIndex = pickerView?.selectedRow(inComponent: 0) {
|
||||
observeDropdownSelection?(pickerData[pickerIndex])
|
||||
}
|
||||
observeDropdownSelection?(pickerData[pickerView.selectedRow(inComponent: 0)])
|
||||
}
|
||||
|
||||
public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||
@ -109,23 +82,21 @@ open class ItemDropdownEntryField: BaseDropdownEntryField {
|
||||
guard let model = model as? ItemDropdownEntryFieldModel else { return }
|
||||
|
||||
pickerData = model.options
|
||||
setPickerDelegates(delegate: self)
|
||||
|
||||
if let pickerView = pickerView, let index = model.selectedIndex {
|
||||
if let index = model.selectedIndex {
|
||||
self.pickerView.selectRow(index, inComponent: 0, animated: false)
|
||||
self.pickerView(pickerView, didSelectRow: index, inComponent: 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK:- Base Picker Delegate
|
||||
extension ItemDropdownEntryField: UIPickerViewDelegate, UIPickerViewDataSource {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Picker Delegate
|
||||
//--------------------------------------------------
|
||||
|
||||
@objc public func numberOfComponents(in pickerView: UIPickerView) -> Int {
|
||||
return 1
|
||||
}
|
||||
@objc public override func numberOfComponents(in pickerView: UIPickerView) -> Int { 1 }
|
||||
|
||||
@objc public func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
|
||||
return pickerData.count
|
||||
@objc public override func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
|
||||
pickerData.count
|
||||
}
|
||||
|
||||
@objc public func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
|
||||
@ -142,18 +113,3 @@ extension ItemDropdownEntryField: UIPickerViewDelegate, UIPickerViewDataSource {
|
||||
itemDropdownEntryFieldModel?.selectedIndex = row
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Accessibility
|
||||
extension ItemDropdownEntryField {
|
||||
|
||||
@objc open override func setAccessibilityString(_ accessibilityString: String?) {
|
||||
|
||||
var accessibilityString = accessibilityString ?? ""
|
||||
|
||||
if let textPickerItem = MVMCoreUIUtility.hardcodedString(withKey: "textfield_picker_item") {
|
||||
accessibilityString += textPickerItem
|
||||
}
|
||||
|
||||
textField.accessibilityLabel = "\(accessibilityString) \(textField.isEnabled ? "" : MVMCoreUIUtility.hardcodedString(withKey: "textfield_disabled_state") ?? "")"
|
||||
}
|
||||
}
|
||||
@ -6,22 +6,24 @@
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
@objcMembers open class ItemDropdownEntryFieldModel: BaseDropdownEntryFieldModel {
|
||||
@objcMembers open class ItemDropdownEntryFieldModel: BaseItemPickerEntryFieldModel {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
public override class var identifier: String {
|
||||
return "dropDown"
|
||||
}
|
||||
public override class var identifier: String { "dropDown" }
|
||||
|
||||
public var options: [String] = []
|
||||
public var selectedIndex: Int?
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Validation
|
||||
//--------------------------------------------------
|
||||
|
||||
public override func formFieldValue() -> AnyHashable? {
|
||||
guard !options.isEmpty,
|
||||
let index = selectedIndex
|
||||
else { return nil }
|
||||
let index = selectedIndex
|
||||
else { return nil }
|
||||
|
||||
return options[index]
|
||||
}
|
||||
@ -34,7 +36,7 @@
|
||||
case options
|
||||
case selectedIndex
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializers
|
||||
//--------------------------------------------------
|
||||
@ -47,10 +49,7 @@
|
||||
|
||||
if let selectedIndex = try typeContainer.decodeIfPresent(Int.self, forKey: .selectedIndex) {
|
||||
self.selectedIndex = selectedIndex
|
||||
}
|
||||
|
||||
if let index = selectedIndex {
|
||||
baseValue = options.indices.contains(index) ? options[index] : nil
|
||||
baseValue = options.indices.contains(selectedIndex) ? options[selectedIndex] : nil
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,144 @@
|
||||
//
|
||||
// MultiItemDropdownEndryField.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Kevin Christiano on 2/9/21.
|
||||
// Copyright © 2021 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
|
||||
open class MultiItemDropdownEntryField: BaseItemPickerEntryField {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
/// Datasource of the picker view.
|
||||
open var pickerComponents: [[String]] {
|
||||
dropdownModel?.components ?? [[]]
|
||||
}
|
||||
|
||||
public var dropdownModel: MultiItemDropdownEntryFieldModel? {
|
||||
model as? MultiItemDropdownEntryFieldModel
|
||||
}
|
||||
|
||||
/// The number of components available
|
||||
public var componentCount: Int {
|
||||
pickerComponents.count
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializers
|
||||
//--------------------------------------------------
|
||||
|
||||
@objc public override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
}
|
||||
|
||||
@objc public convenience init() {
|
||||
self.init(frame: .zero)
|
||||
}
|
||||
|
||||
@objc required public init?(coder: NSCoder) {
|
||||
fatalError("MultiItemDropdownEntryField init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
required public init(model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||
super.init(model: model, delegateObject, additionalData)
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Methods
|
||||
//--------------------------------------------------
|
||||
|
||||
/// Sets the textField with the first value of the available picker data.
|
||||
@objc private func setInitialValueFromPicker() {
|
||||
|
||||
guard setInitialValueInTextField,
|
||||
!pickerComponents.isEmpty,
|
||||
let rowText = dropdownModel?.selectedRowText
|
||||
else { return }
|
||||
|
||||
// Update observing function and update text UI.
|
||||
observeDropdownChange?(text ?? "", rowText)
|
||||
text = rowText
|
||||
|
||||
// Set row index value of selected component.
|
||||
for component in 0..<componentCount {
|
||||
let pickerIndex = pickerView.selectedRow(inComponent: component)
|
||||
dropdownModel?.selectedIndexes[component] = pickerIndex
|
||||
}
|
||||
}
|
||||
|
||||
func pickerHasComponent(_ index: Int) -> Bool {
|
||||
!pickerComponents.isEmpty && !pickerComponents[index].isEmpty
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - TextField Observation
|
||||
//--------------------------------------------------
|
||||
|
||||
/// Observing action of the textfield for initial interaction with the picker.
|
||||
@objc override func startEditing() {
|
||||
super.startEditing()
|
||||
|
||||
setInitialValueFromPicker()
|
||||
}
|
||||
|
||||
/// Observing action for when the user has ended inputting with the picker.
|
||||
@objc override func endInputing() {
|
||||
super.endInputing()
|
||||
|
||||
guard !pickerComponents.isEmpty,
|
||||
let rowText = dropdownModel?.selectedRowText
|
||||
else { return }
|
||||
|
||||
// update observing function with most recent selection.
|
||||
observeDropdownSelection?(rowText)
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - MoleculeViewProtocol
|
||||
//--------------------------------------------------
|
||||
|
||||
public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||
super.set(with: model, delegateObject, additionalData)
|
||||
|
||||
guard let model = model as? MultiItemDropdownEntryFieldModel else { return }
|
||||
|
||||
// Select initial rows if selectedIndexes retains value.
|
||||
for (component, row) in model.selectedIndexes {
|
||||
self.pickerView.selectRow(row, inComponent: component, animated: false)
|
||||
self.pickerView(pickerView, didSelectRow: row, inComponent: component)
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Picker Delegate
|
||||
//--------------------------------------------------
|
||||
|
||||
@objc public override func numberOfComponents(in pickerView: UIPickerView) -> Int { componentCount }
|
||||
|
||||
@objc public override func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
|
||||
pickerComponents[component].count
|
||||
}
|
||||
|
||||
@objc public func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
|
||||
|
||||
guard pickerHasComponent(component) else { return nil }
|
||||
|
||||
return pickerComponents[component][row]
|
||||
}
|
||||
|
||||
@objc public func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
|
||||
|
||||
guard pickerHasComponent(component) else { return }
|
||||
|
||||
let oldText = text ?? ""
|
||||
dropdownModel?.selectedIndexes[component] = row
|
||||
let newText = dropdownModel?.selectedRowText
|
||||
observeDropdownChange?(oldText, newText ?? "")
|
||||
text = newText
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,126 @@
|
||||
//
|
||||
// MultiItemDropdownEntryFieldModel.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Kevin Christiano on 2/9/21.
|
||||
// Copyright © 2021 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
|
||||
@objcMembers open class MultiItemDropdownEntryFieldModel: BaseItemPickerEntryFieldModel {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
public override class var identifier: String { "multiDropdown" }
|
||||
|
||||
public var components: [[String]] = [[]]
|
||||
public var selectedIndexes: [Int: Int] = [:]
|
||||
public var delimiters: [Int: String] = [:]
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Validation
|
||||
//--------------------------------------------------
|
||||
|
||||
public override func formFieldValue() -> AnyHashable? {
|
||||
|
||||
guard !components.isEmpty && !selectedIndexes.isEmpty else { return nil }
|
||||
|
||||
return selectedRowText
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Methods
|
||||
//--------------------------------------------------
|
||||
|
||||
/// - parameter index: The index of the delimiter.
|
||||
/// - returns: The delimiter for a given index. Defaults to whitespace for valid index if no delimiters is provided. If invalid index, empty string.
|
||||
public func delimiter(for index: Int) -> String {
|
||||
|
||||
guard index != components.count - 1 else { return "" }
|
||||
|
||||
return delimiters[index, default: " "]
|
||||
}
|
||||
|
||||
/// A string of the picker row concatenated by whitespace or delimiters if provided.
|
||||
public var selectedRowText: String {
|
||||
|
||||
var text = ""
|
||||
|
||||
for i in 0..<components.count {
|
||||
let pickerIndex = selectedIndexes[i] ?? 0
|
||||
text += components[i][pickerIndex] + delimiter(for: i)
|
||||
}
|
||||
|
||||
return text
|
||||
}
|
||||
|
||||
public var selectedIndexesArray: [Int] {
|
||||
|
||||
var indexArray: [Int] = []
|
||||
|
||||
for i in 0..<selectedIndexes.count {
|
||||
guard let selectIndex = selectedIndexes[i] else { return [] }
|
||||
indexArray.append(selectIndex)
|
||||
}
|
||||
|
||||
return indexArray
|
||||
}
|
||||
|
||||
public var delimiterArray: [String] {
|
||||
|
||||
var array: [String] = []
|
||||
|
||||
for i in 0..<delimiters.count {
|
||||
guard let delimiterIndex = delimiters[i] else { return [] }
|
||||
array.append(delimiterIndex)
|
||||
}
|
||||
|
||||
return array
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Keys
|
||||
//--------------------------------------------------
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case components
|
||||
case selectedIndexes
|
||||
case delimiters
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializers
|
||||
//--------------------------------------------------
|
||||
|
||||
required public init(from decoder: Decoder) throws {
|
||||
try super.init(from: decoder)
|
||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
components = try typeContainer.decode([[String]].self, forKey: .components)
|
||||
|
||||
if let delimiters = try typeContainer.decodeIfPresent([String].self, forKey: .delimiters) {
|
||||
for (index, delimiter) in delimiters.enumerated() {
|
||||
self.delimiters[index] = delimiter
|
||||
}
|
||||
}
|
||||
|
||||
if let indexes = try typeContainer.decodeIfPresent([Int].self, forKey: .selectedIndexes) {
|
||||
for (component, index) in indexes.enumerated() {
|
||||
self.selectedIndexes[component] = index
|
||||
}
|
||||
|
||||
baseValue = selectedRowText
|
||||
}
|
||||
}
|
||||
|
||||
public override func encode(to encoder: Encoder) throws {
|
||||
try super.encode(to: encoder)
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(components, forKey: .components)
|
||||
try container.encode(selectedIndexesArray, forKey: .selectedIndexes)
|
||||
try container.encodeIfPresent(delimiterArray, forKey: .delimiters)
|
||||
}
|
||||
}
|
||||
@ -36,7 +36,7 @@ import UIKit
|
||||
label.setContentCompressionResistancePriority(.required, for: .vertical)
|
||||
return label
|
||||
}()
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Delegate
|
||||
//--------------------------------------------------
|
||||
@ -58,71 +58,74 @@ import UIKit
|
||||
|
||||
/// Toggles enabled (original) or disabled UI.
|
||||
public var isEnabled: Bool {
|
||||
get { return entryFieldContainer.isEnabled }
|
||||
get { entryFieldContainer.isEnabled }
|
||||
set (enabled) {
|
||||
self.titleLabel.textColor = enabled ? .mvmBlack : .mvmCoolGray3
|
||||
self.feedbackLabel.textColor = enabled ? .mvmBlack : .mvmCoolGray3
|
||||
self.entryFieldContainer.isEnabled = enabled
|
||||
self.entryFieldModel?.enabled = enabled
|
||||
titleLabel.textColor = enabled ? .mvmBlack : .mvmCoolGray3
|
||||
feedbackLabel.textColor = enabled ? .mvmBlack : .mvmCoolGray3
|
||||
entryFieldContainer.isEnabled = enabled
|
||||
entryFieldModel?.enabled = enabled
|
||||
}
|
||||
}
|
||||
|
||||
/// Toggles error or original UI.
|
||||
public var showError: Bool {
|
||||
get { return entryFieldContainer.showError }
|
||||
get { entryFieldContainer.showError }
|
||||
set (error) {
|
||||
self.feedback = error ? entryFieldModel?.errorMessage : entryFieldModel?.feedback
|
||||
self.feedbackLabel.textColor = error ? entryFieldModel?.errorTextColor?.uiColor ?? .mvmBlack : .mvmBlack
|
||||
self.entryFieldContainer.showError = error
|
||||
self.entryFieldModel?.showError = error
|
||||
feedback = error ? errorMessage : entryFieldModel?.feedback
|
||||
feedbackLabel.textColor = error ? entryFieldModel?.errorTextColor?.uiColor ?? .mvmBlack : .mvmBlack
|
||||
entryFieldContainer.showError = error
|
||||
entryFieldModel?.showError = error
|
||||
}
|
||||
}
|
||||
|
||||
var errorMessage: String? {
|
||||
entryFieldModel?.dynamicErrorMessage ?? entryFieldModel?.errorMessage
|
||||
}
|
||||
|
||||
/// Toggles original or locked UI.
|
||||
public var isLocked: Bool {
|
||||
get { return entryFieldContainer.isLocked }
|
||||
get { entryFieldContainer.isLocked }
|
||||
set (locked) {
|
||||
self.entryFieldContainer.isLocked = locked
|
||||
self.entryFieldModel?.locked = locked
|
||||
entryFieldContainer.isLocked = locked
|
||||
entryFieldModel?.locked = locked
|
||||
}
|
||||
}
|
||||
|
||||
/// Toggles selected or original (unselected) UI.
|
||||
public var isSelected: Bool {
|
||||
get { return entryFieldContainer.isSelected }
|
||||
get { entryFieldContainer.isSelected }
|
||||
set (selected) {
|
||||
self.entryFieldContainer.isSelected = selected
|
||||
self.entryFieldModel?.selected = selected
|
||||
entryFieldContainer.isSelected = selected
|
||||
entryFieldModel?.selected = selected
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the text of titleLabel
|
||||
public var title: String? {
|
||||
get { return titleLabel.text }
|
||||
set (newText) {
|
||||
titleLabel.text = newText
|
||||
setAccessibilityString(newText)
|
||||
get { titleLabel.text }
|
||||
set {
|
||||
titleLabel.text = newValue
|
||||
setAccessibilityString(newValue)
|
||||
}
|
||||
}
|
||||
|
||||
/// Override this to conveniently get/set the textfield(s).
|
||||
public var text: String? {
|
||||
get { return nil }
|
||||
get { nil }
|
||||
set { fatalError("You MUST override EntryField's 'text' variable in your subclass.") }
|
||||
}
|
||||
|
||||
/// Sets feedback text in the textField.
|
||||
public var feedback: String? {
|
||||
get { return feedbackLabel.text }
|
||||
set (newFeedback) {
|
||||
feedbackLabel.text = newFeedback
|
||||
get { feedbackLabel.text }
|
||||
set {
|
||||
feedbackLabel.text = newValue
|
||||
feedbackLabel.accessibilityElementsHidden = feedbackLabel.text?.isEmpty ?? true
|
||||
entryFieldContainer.refreshUI(updateMoleculeLayout: true)
|
||||
}
|
||||
}
|
||||
|
||||
public var entryFieldModel: EntryFieldModel? {
|
||||
return model as? EntryFieldModel
|
||||
model as? EntryFieldModel
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
@ -219,7 +222,7 @@ import UIKit
|
||||
entryFieldContainer.refreshUI()
|
||||
}
|
||||
|
||||
/// Intended to add the interactive content (i.e. textField) to the entryFieldContainer.
|
||||
/// Intended to add the interactive content (i.e. textField) to the entryFieldContainer.
|
||||
@objc open func setupFieldContainerContent(_ container: UIView) {
|
||||
// To Be Overriden
|
||||
}
|
||||
@ -306,16 +309,30 @@ import UIKit
|
||||
|
||||
if self.isSelected {
|
||||
self.updateValidation(model.isValid ?? true)
|
||||
|
||||
} else if model.isValid ?? true && self.showError {
|
||||
self.showError = false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
model.updateUIDynamicError = { [weak self] in
|
||||
MVMCoreDispatchUtility.performBlock(onMainThread: {
|
||||
guard let self = self else { return }
|
||||
let validState = model.isValid ?? false
|
||||
self.updateValidation(validState)
|
||||
if !validState && model.shouldClearText {
|
||||
self.text = ""
|
||||
model.shouldClearText = false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
title = model.title
|
||||
feedback = model.feedback
|
||||
isEnabled = model.enabled
|
||||
entryFieldContainer.disableAllBorders = model.hideBorders
|
||||
accessibilityIdentifier = model.accessibilityIdentifier ?? model.fieldKey
|
||||
|
||||
if let isLocked = model.locked {
|
||||
self.isLocked = isLocked
|
||||
@ -327,9 +344,7 @@ import UIKit
|
||||
}
|
||||
}
|
||||
|
||||
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
|
||||
return 115
|
||||
}
|
||||
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { 115 }
|
||||
}
|
||||
|
||||
// MARK: - Accessibility
|
||||
|
||||
@ -14,13 +14,19 @@ import Foundation
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
public class var identifier: String {
|
||||
return ""
|
||||
}
|
||||
public class var identifier: String { "" }
|
||||
|
||||
public var backgroundColor: Color?
|
||||
public var accessibilityIdentifier: String?
|
||||
public var title: String?
|
||||
public var feedback: String?
|
||||
public var shouldClearText: Bool = false
|
||||
public var dynamicErrorMessage: String? {
|
||||
didSet {
|
||||
isValid = dynamicErrorMessage?.isEmpty ?? true
|
||||
updateUIDynamicError?()
|
||||
}
|
||||
}
|
||||
public var errorMessage: String?
|
||||
public var errorTextColor: Color?
|
||||
public var enabled: Bool = true
|
||||
@ -41,6 +47,9 @@ import Foundation
|
||||
/// Temporary binding mechanism for the view to update on enable changes.
|
||||
public var updateUI: ActionBlock?
|
||||
|
||||
// TODO: Remove once updateUI is fixed with isSelected
|
||||
public var updateUIDynamicError: ActionBlock?
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Keys
|
||||
//--------------------------------------------------
|
||||
@ -48,6 +57,7 @@ import Foundation
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case moleculeName
|
||||
case backgroundColor
|
||||
case accessibilityIdentifier
|
||||
case title
|
||||
case enabled
|
||||
case feedback
|
||||
@ -67,6 +77,9 @@ import Foundation
|
||||
//--------------------------------------------------
|
||||
|
||||
public func formFieldValue() -> AnyHashable? {
|
||||
if dynamicErrorMessage != nil {
|
||||
dynamicErrorMessage = nil
|
||||
}
|
||||
return text
|
||||
}
|
||||
|
||||
@ -96,6 +109,7 @@ import Foundation
|
||||
required public init(from decoder: Decoder) throws {
|
||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
|
||||
accessibilityIdentifier = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityIdentifier)
|
||||
title = try typeContainer.decodeIfPresent(String.self, forKey: .title)
|
||||
feedback = try typeContainer.decodeIfPresent(String.self, forKey: .feedback)
|
||||
errorMessage = try typeContainer.decodeIfPresent(String.self, forKey: .errorMessage)
|
||||
@ -117,6 +131,7 @@ import Foundation
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encodeIfPresent(moleculeName, forKey: .moleculeName)
|
||||
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
|
||||
try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier)
|
||||
try container.encodeIfPresent(title, forKey: .title)
|
||||
try container.encodeIfPresent(feedback, forKey: .feedback)
|
||||
try container.encodeIfPresent(text, forKey: .text)
|
||||
@ -125,9 +140,9 @@ import Foundation
|
||||
try container.encodeIfPresent(selected, forKey: .selected)
|
||||
try container.encodeIfPresent(errorTextColor, forKey: .errorTextColor)
|
||||
try container.encodeIfPresent(errorMessage, forKey: .errorMessage)
|
||||
try container.encode(enabled, forKey: .enabled)
|
||||
try container.encode(hideBorders, forKey: .hideBorders)
|
||||
try container.encodeIfPresent(fieldKey, forKey: .fieldKey)
|
||||
try container.encodeIfPresent(groupName, forKey: .groupName)
|
||||
try container.encode(enabled, forKey: .enabled)
|
||||
try container.encode(hideBorders, forKey: .hideBorders)
|
||||
}
|
||||
}
|
||||
|
||||
@ -31,7 +31,7 @@ import MVMCore
|
||||
|
||||
/// If you're using a MFViewController, you must set this to it
|
||||
public override weak var uiTextFieldDelegate: UITextFieldDelegate? {
|
||||
get { return textField.delegate }
|
||||
get { textField.delegate }
|
||||
set {
|
||||
textField.delegate = self
|
||||
proprietorTextDelegate = newValue
|
||||
@ -44,7 +44,7 @@ import MVMCore
|
||||
|
||||
/// Formats the MDN when setting and removes format of MDN when reading.
|
||||
public var mdn: String? {
|
||||
get { return MVMCoreUIUtility.removeMdnFormat(text) }
|
||||
get { MVMCoreUIUtility.removeMdnFormat(text) }
|
||||
set { text = MVMCoreUIUtility.formatMdn(newValue) }
|
||||
}
|
||||
|
||||
@ -160,9 +160,9 @@ import MVMCore
|
||||
|
||||
// Sometimes user add extra 1 in front of mdn in their address book
|
||||
if isNationalMDN,
|
||||
let unformedMDN = unformattedMDN,
|
||||
unformedMDN.count == 11,
|
||||
unformedMDN[(unformedMDN.index(unformedMDN.startIndex, offsetBy: 0))] == "1" {
|
||||
let unformedMDN = unformattedMDN,
|
||||
unformedMDN.count == 11,
|
||||
unformedMDN[(unformedMDN.index(unformedMDN.startIndex, offsetBy: 0))] == "1" {
|
||||
|
||||
let startIndex = unformedMDN.index(unformedMDN.startIndex, offsetBy: 1)
|
||||
unformattedMDN = String(unformedMDN[startIndex...])
|
||||
@ -211,17 +211,14 @@ import MVMCore
|
||||
}
|
||||
|
||||
@objc public func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
|
||||
|
||||
return proprietorTextDelegate?.textFieldShouldBeginEditing?(textField) ?? true
|
||||
proprietorTextDelegate?.textFieldShouldBeginEditing?(textField) ?? true
|
||||
}
|
||||
|
||||
@objc public func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
|
||||
|
||||
return proprietorTextDelegate?.textFieldShouldEndEditing?(textField) ?? true
|
||||
proprietorTextDelegate?.textFieldShouldEndEditing?(textField) ?? true
|
||||
}
|
||||
|
||||
@objc public func textFieldShouldClear(_ textField: UITextField) -> Bool {
|
||||
|
||||
return proprietorTextDelegate?.textFieldShouldClear?(textField) ?? true
|
||||
proprietorTextDelegate?.textFieldShouldClear?(textField) ?? true
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,7 +11,5 @@
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
public override class var identifier: String {
|
||||
return "mdnEntryField"
|
||||
}
|
||||
public override class var identifier: String { "mdnEntryField" }
|
||||
}
|
||||
|
||||
@ -54,16 +54,14 @@ import UIKit
|
||||
/// Validate when user resigns editing. Default: true
|
||||
public var validateWhenDoneEditing: Bool = true
|
||||
|
||||
public var textEntryFieldModel: TextEntryFieldModel? {
|
||||
return model as? TextEntryFieldModel
|
||||
}
|
||||
public var textEntryFieldModel: TextEntryFieldModel? { model as? TextEntryFieldModel }
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Computed Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
public override var isEnabled: Bool {
|
||||
get { return super.isEnabled }
|
||||
get { super.isEnabled }
|
||||
set (enabled) {
|
||||
super.isEnabled = enabled
|
||||
|
||||
@ -77,7 +75,7 @@ import UIKit
|
||||
}
|
||||
|
||||
public override var showError: Bool {
|
||||
get { return super.showError }
|
||||
get { super.showError }
|
||||
set (error) {
|
||||
|
||||
if error {
|
||||
@ -96,16 +94,16 @@ import UIKit
|
||||
|
||||
/// The text of this TextField.
|
||||
open override var text: String? {
|
||||
get { return textField.text }
|
||||
get { textField.text }
|
||||
set {
|
||||
textField.text = newValue
|
||||
textEntryFieldModel?.text = newValue
|
||||
textField.text = newValue
|
||||
}
|
||||
}
|
||||
|
||||
/// Placeholder access for the TextField.
|
||||
public var placeholder: String? {
|
||||
get { return textField.placeholder }
|
||||
get { textField.placeholder }
|
||||
set { textField.placeholder = newValue }
|
||||
}
|
||||
|
||||
@ -133,7 +131,7 @@ import UIKit
|
||||
|
||||
/// If you're using a ViewController, you must set this to it
|
||||
public weak var uiTextFieldDelegate: UITextFieldDelegate? {
|
||||
get { return textField.delegate }
|
||||
get { textField.delegate }
|
||||
set { textField.delegate = newValue }
|
||||
}
|
||||
|
||||
@ -222,9 +220,7 @@ import UIKit
|
||||
|
||||
@discardableResult
|
||||
@objc override open func resignFirstResponder() -> Bool {
|
||||
if validateWhenDoneEditing {
|
||||
validateText()
|
||||
}
|
||||
if validateWhenDoneEditing { validateText() }
|
||||
textField.resignFirstResponder()
|
||||
isSelected = false
|
||||
return true
|
||||
@ -239,6 +235,11 @@ import UIKit
|
||||
/// Executes on UITextField.textDidBeginEditingNotification
|
||||
@objc override func startEditing() {
|
||||
super.startEditing()
|
||||
|
||||
if textEntryFieldModel?.clearTextOnTap ?? false {
|
||||
text = ""
|
||||
}
|
||||
|
||||
textField.becomeFirstResponder()
|
||||
}
|
||||
|
||||
@ -257,14 +258,33 @@ import UIKit
|
||||
showError = false
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
if let isValid = textEntryFieldModel?.isValid {
|
||||
self.isValid = isValid
|
||||
}
|
||||
|
||||
regexTextFieldOutputIfAvailable()
|
||||
|
||||
shouldShowError(!isValid)
|
||||
}
|
||||
|
||||
func regexTextFieldOutputIfAvailable() {
|
||||
|
||||
if let regex = textEntryFieldModel?.displayFormat,
|
||||
let mask = textEntryFieldModel?.displayMask,
|
||||
let finalText = text {
|
||||
|
||||
let range = NSRange(finalText.startIndex..., in: finalText)
|
||||
|
||||
if let regex = try? NSRegularExpression(pattern: regex) {
|
||||
let maskedText = regex.stringByReplacingMatches(in: finalText,
|
||||
range: range,
|
||||
withTemplate: mask)
|
||||
textField.text = maskedText
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@objc public func dismissFieldInput(_ sender: Any?) {
|
||||
resignFirstResponder()
|
||||
}
|
||||
@ -317,6 +337,10 @@ import UIKit
|
||||
case .password, .secure:
|
||||
textField.isSecureTextEntry = true
|
||||
|
||||
case .numberSecure:
|
||||
textField.isSecureTextEntry = true
|
||||
textField.keyboardType = .numberPad
|
||||
|
||||
case .number:
|
||||
textField.keyboardType = .numberPad
|
||||
|
||||
@ -326,17 +350,20 @@ import UIKit
|
||||
case .phone:
|
||||
textField.keyboardType = .phonePad
|
||||
|
||||
default:
|
||||
break
|
||||
default: break
|
||||
}
|
||||
|
||||
// Override the preset keyboard set in type.
|
||||
if let keyboardType = model.assignKeyboardType() {
|
||||
textField.keyboardType = keyboardType
|
||||
}
|
||||
|
||||
textField.accessibilityIdentifier = model.accessibilityIdentifier
|
||||
uiTextFieldDelegate = delegateObject?.uiTextFieldDelegate
|
||||
observingTextFieldDelegate = delegateObject?.observingTextFieldDelegate
|
||||
setupTextFieldToolbar()
|
||||
|
||||
if isSelected {
|
||||
startEditing()
|
||||
}
|
||||
if isSelected { startEditing() }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
case password
|
||||
case secure
|
||||
case number
|
||||
case numberSecure
|
||||
case email
|
||||
case text
|
||||
case phone
|
||||
@ -25,15 +26,69 @@
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
public override class var identifier: String {
|
||||
return "textField"
|
||||
}
|
||||
public override class var identifier: String { "textField" }
|
||||
|
||||
public var placeholder: String?
|
||||
public var enabledTextColor: Color = Color(uiColor: .mvmBlack)
|
||||
public var disabledTextColor: Color = Color(uiColor: .mvmCoolGray3)
|
||||
public var textAlignment: NSTextAlignment = .left
|
||||
public var keyboardOverride: String?
|
||||
public var type: EntryType?
|
||||
public var clearTextOnTap: Bool = false
|
||||
public var displayFormat: String?
|
||||
public var displayMask: String?
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Methods
|
||||
//--------------------------------------------------
|
||||
|
||||
/// Reads the keyboardOverride set by server and returns the keyboard type associated with it.
|
||||
func assignKeyboardType() -> UIKeyboardType? {
|
||||
|
||||
guard let keyboardType = keyboardOverride else { return nil }
|
||||
|
||||
var typeInt = 0
|
||||
|
||||
switch keyboardType {
|
||||
case "asciiCapable":
|
||||
typeInt = 1 // Displays a keyboard which can enter ASCII characters
|
||||
|
||||
case "numbersAndPunctuation":
|
||||
typeInt = 2 // Numbers and assorted punctuation.
|
||||
|
||||
case "URL":
|
||||
typeInt = 3 // A type optimized for URL entry (shows . / .com prominently).
|
||||
|
||||
case "numberPad":
|
||||
typeInt = 4 // A number pad with locale-appropriate digits (0-9, ۰-۹, ०-९, etc.). Suitable for PIN entry.
|
||||
|
||||
case "phonePad":
|
||||
typeInt = 5 // A phone pad (1-9, *, 0, #, with letters under the numbers).
|
||||
|
||||
case "namePhonePad":
|
||||
typeInt = 6 // A type optimized for entering a person's name or phone number.
|
||||
|
||||
case "emailAddress":
|
||||
typeInt = 7 // A type optimized for multiple email address entry (shows space @ . prominently).
|
||||
|
||||
case "decimalPad":
|
||||
typeInt = 8 // A number pad with a decimal point.
|
||||
|
||||
case "twitter":
|
||||
typeInt = 9 // A type optimized for twitter text entry (easy access to @ #)
|
||||
|
||||
case "webSearch":
|
||||
typeInt = 10 // A default keyboard type with URL-oriented addition (shows space . prominently).
|
||||
|
||||
case "asciiCapableNumberPad":
|
||||
typeInt = 11 // A number pad (0-9) that will always be ASCII digits.
|
||||
|
||||
default:
|
||||
typeInt = 0 // Default type for the current input method.
|
||||
}
|
||||
|
||||
return UIKeyboardType(rawValue: typeInt)
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Keys
|
||||
@ -44,7 +99,11 @@
|
||||
case textAlignment
|
||||
case enabledTextColor
|
||||
case disabledTextColor
|
||||
case keyboardOverride
|
||||
case type
|
||||
case clearTextOnTap
|
||||
case displayFormat
|
||||
case displayMask
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
@ -56,8 +115,15 @@
|
||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
placeholder = try typeContainer.decodeIfPresent(String.self, forKey: .placeholder)
|
||||
displayFormat = try typeContainer.decodeIfPresent(String.self, forKey: .displayFormat)
|
||||
keyboardOverride = try typeContainer.decodeIfPresent(String.self, forKey: .keyboardOverride)
|
||||
displayMask = try typeContainer.decodeIfPresent(String.self, forKey: .displayMask)
|
||||
type = try typeContainer.decodeIfPresent(EntryType.self, forKey: .type)
|
||||
|
||||
if let clearTextOnTap = try typeContainer.decodeIfPresent(Bool.self, forKey: .clearTextOnTap) {
|
||||
self.clearTextOnTap = clearTextOnTap
|
||||
}
|
||||
|
||||
if let enabledTextColor = try typeContainer.decodeIfPresent(Color.self, forKey: .enabledTextColor) {
|
||||
self.enabledTextColor = enabledTextColor
|
||||
}
|
||||
@ -76,8 +142,12 @@
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encodeIfPresent(placeholder, forKey: .placeholder)
|
||||
try container.encodeIfPresent(textAlignment, forKey: .textAlignment)
|
||||
try container.encodeIfPresent(type, forKey: .type)
|
||||
try container.encodeIfPresent(displayFormat, forKey: .displayFormat)
|
||||
try container.encodeIfPresent(keyboardOverride, forKey: .keyboardOverride)
|
||||
try container.encodeIfPresent(displayMask, forKey: .displayMask)
|
||||
try container.encode(enabledTextColor, forKey: .enabledTextColor)
|
||||
try container.encode(disabledTextColor, forKey: .disabledTextColor)
|
||||
try container.encodeIfPresent(type, forKey: .type)
|
||||
try container.encode(clearTextOnTap, forKey: .clearTextOnTap)
|
||||
}
|
||||
}
|
||||
|
||||
@ -31,11 +31,11 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele
|
||||
//--------------------------------------------------
|
||||
|
||||
public var textViewEntryFieldModel: TextViewEntryFieldModel? {
|
||||
return model as? TextViewEntryFieldModel
|
||||
model as? TextViewEntryFieldModel
|
||||
}
|
||||
|
||||
public override var isEnabled: Bool {
|
||||
get { return super.isEnabled }
|
||||
get { super.isEnabled }
|
||||
set (enabled) {
|
||||
super.isEnabled = enabled
|
||||
|
||||
@ -53,7 +53,7 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele
|
||||
}
|
||||
|
||||
public override var showError: Bool {
|
||||
get { return super.showError }
|
||||
get { super.showError }
|
||||
set (error) {
|
||||
|
||||
if error {
|
||||
@ -68,7 +68,7 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele
|
||||
|
||||
/// The text of this textView.
|
||||
open override var text: String? {
|
||||
get { return textViewEntryFieldModel?.text }
|
||||
get { textViewEntryFieldModel?.text }
|
||||
set {
|
||||
textView.text = newValue
|
||||
textViewEntryFieldModel?.text = newValue
|
||||
@ -77,7 +77,7 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele
|
||||
|
||||
/// Placeholder access for the textView.
|
||||
public var placeholder: String? {
|
||||
get { return textViewEntryFieldModel?.placeholder }
|
||||
get { textViewEntryFieldModel?.placeholder }
|
||||
set {
|
||||
textView.placeholder = newValue ?? ""
|
||||
textViewEntryFieldModel?.placeholder = newValue
|
||||
@ -127,7 +127,7 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele
|
||||
|
||||
/// If you're using a ViewController, you must set this to it
|
||||
public weak var uiTextViewDelegate: UITextViewDelegate? {
|
||||
get { return textView.delegate }
|
||||
get { textView.delegate }
|
||||
set { textView.delegate = newValue }
|
||||
}
|
||||
|
||||
@ -149,17 +149,17 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele
|
||||
@objc open override func setupFieldContainerContent(_ container: UIView) {
|
||||
|
||||
container.addSubview(textView)
|
||||
|
||||
|
||||
topConstraint = textView.topAnchor.constraint(equalTo: container.topAnchor, constant: Padding.Three)
|
||||
leadingConstraint = textView.leadingAnchor.constraint(equalTo: container.leadingAnchor, constant: Padding.Three)
|
||||
trailingConstraint = container.trailingAnchor.constraint(equalTo: textView.trailingAnchor, constant: Padding.Three)
|
||||
bottomConstraint = container.bottomAnchor.constraint(equalTo: textView.bottomAnchor, constant: Padding.Three)
|
||||
|
||||
|
||||
topConstraint?.isActive = true
|
||||
leadingConstraint?.isActive = true
|
||||
trailingConstraint?.isActive = true
|
||||
bottomConstraint?.isActive = true
|
||||
|
||||
|
||||
heightConstraint = textView.heightAnchor.constraint(equalToConstant: 0)
|
||||
accessibilityElements = [titleLabel, textView, feedbackLabel]
|
||||
}
|
||||
@ -203,7 +203,7 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele
|
||||
/// Executes on UITextView.textDidEndEditingNotification
|
||||
@objc override func endInputing() {
|
||||
super.endInputing()
|
||||
|
||||
|
||||
// Don't show error till user starts typing.
|
||||
guard text?.count ?? 0 != 0 else {
|
||||
showError = false
|
||||
@ -241,6 +241,7 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele
|
||||
|
||||
textView.isEditable = model.editable
|
||||
textView.textAlignment = model.textAlignment
|
||||
textView.accessibilityIdentifier = model.accessibilityIdentifier
|
||||
textView.textColor = model.enabled ? model.enabledTextColor.uiColor : model.disabledTextColor.uiColor
|
||||
textView.font = model.fontStyle.getFont()
|
||||
textView.placeholder = model.placeholder ?? ""
|
||||
@ -252,13 +253,17 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele
|
||||
case .secure, .password:
|
||||
textView.isSecureTextEntry = true
|
||||
|
||||
case .numberSecure:
|
||||
textView.isSecureTextEntry = true
|
||||
textView.keyboardType = .numberPad
|
||||
|
||||
case .number:
|
||||
textView.keyboardType = .numberPad
|
||||
|
||||
case .email:
|
||||
textView.keyboardType = .emailAddress
|
||||
|
||||
default: break
|
||||
default: break
|
||||
}
|
||||
|
||||
/// No point in configuring if the TextView is Read-only.
|
||||
|
||||
@ -14,9 +14,7 @@ class TextViewEntryFieldModel: TextEntryFieldModel {
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
public override class var identifier: String {
|
||||
return "textView"
|
||||
}
|
||||
public override class var identifier: String { "textView" }
|
||||
|
||||
public var accessibilityText: String?
|
||||
public var fontStyle: Styler.Font = Styler.Font.RegularBodyLarge
|
||||
@ -25,7 +23,7 @@ class TextViewEntryFieldModel: TextEntryFieldModel {
|
||||
public var placeholderFontStyle: Styler.Font = Styler.Font.RegularMicro
|
||||
public var editable: Bool = true
|
||||
public var showsPlaceholder: Bool = false
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Keys
|
||||
//--------------------------------------------------
|
||||
|
||||
@ -25,7 +25,7 @@ import MVMCore
|
||||
var delegateObject: MVMCoreUIDelegateObject?
|
||||
|
||||
public var checkboxModel: CheckboxModel? {
|
||||
return model as? CheckboxModel
|
||||
model as? CheckboxModel
|
||||
}
|
||||
|
||||
public static let defaultHeightWidth: CGFloat = 18.0
|
||||
@ -59,7 +59,7 @@ import MVMCore
|
||||
|
||||
/// Retrieves ideeal radius value to curve square into a circle.
|
||||
public var cornerRadiusValue: CGFloat {
|
||||
return bounds.size.height / 2
|
||||
bounds.size.height / 2
|
||||
}
|
||||
|
||||
/// Action Block called when the switch is selected.
|
||||
@ -102,23 +102,17 @@ import MVMCore
|
||||
|
||||
/// Color of the check mark.
|
||||
public var checkColor: UIColor = .mvmBlack {
|
||||
didSet {
|
||||
setShapeLayerStrokeColor(checkColor)
|
||||
}
|
||||
didSet { setShapeLayerStrokeColor(checkColor) }
|
||||
}
|
||||
|
||||
/// Border width of the checkbox
|
||||
public var borderWidth: CGFloat = 1 {
|
||||
didSet {
|
||||
layer.borderWidth = borderWidth
|
||||
}
|
||||
didSet { layer.borderWidth = borderWidth }
|
||||
}
|
||||
|
||||
/// border color of the Checkbox
|
||||
public var borderColor: UIColor = .mvmBlack {
|
||||
didSet {
|
||||
layer.borderColor = borderColor.cgColor
|
||||
}
|
||||
didSet { layer.borderColor = borderColor.cgColor }
|
||||
}
|
||||
|
||||
/**
|
||||
@ -359,6 +353,7 @@ import MVMCore
|
||||
}
|
||||
|
||||
override open func accessibilityActivate() -> Bool {
|
||||
guard isEnabled else { return false }
|
||||
sendActions(for: .touchUpInside)
|
||||
return true
|
||||
}
|
||||
@ -367,9 +362,7 @@ import MVMCore
|
||||
// MARK: - Molecular
|
||||
//--------------------------------------------------
|
||||
|
||||
open func needsToBeConstrained() -> Bool {
|
||||
return true
|
||||
}
|
||||
open func needsToBeConstrained() -> Bool { true }
|
||||
|
||||
open override func reset() {
|
||||
super.reset()
|
||||
@ -396,11 +389,9 @@ import MVMCore
|
||||
}
|
||||
|
||||
private func performCheckboxAction(with actionModel: ActionModelProtocol, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
|
||||
if let actionMap = actionModel.toJSON() {
|
||||
var additionalDatatoUpdate = additionalData ?? [:]
|
||||
additionalDatatoUpdate[KeySourceModel] = checkboxModel
|
||||
MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalDatatoUpdate, delegateObject: delegateObject)
|
||||
}
|
||||
var additionalDataToUpdate = additionalData ?? [:]
|
||||
additionalDataToUpdate[KeySourceModel] = checkboxModel
|
||||
MVMCoreActionHandler.shared()?.asyncHandleAction(with: actionModel, additionalData: additionalDataToUpdate, delegateObject: delegateObject)
|
||||
}
|
||||
|
||||
public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||
|
||||
@ -16,6 +16,7 @@ import Foundation
|
||||
|
||||
public static var identifier: String = "checkbox"
|
||||
public var backgroundColor: Color?
|
||||
public var accessibilityIdentifier: String?
|
||||
public var checked: Bool = false
|
||||
public var enabled: Bool = true
|
||||
public var animated: Bool = true
|
||||
@ -44,6 +45,7 @@ import Foundation
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case moleculeName
|
||||
case accessibilityIdentifier
|
||||
case checked
|
||||
case enabled
|
||||
case inverted
|
||||
@ -69,9 +71,7 @@ import Foundation
|
||||
// MARK: - Methods
|
||||
//--------------------------------------------------
|
||||
|
||||
public func formFieldValue() -> AnyHashable? {
|
||||
return checked
|
||||
}
|
||||
public func formFieldValue() -> AnyHashable? { checked }
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializer
|
||||
@ -89,6 +89,8 @@ import Foundation
|
||||
required public init(from decoder: Decoder) throws {
|
||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
accessibilityIdentifier = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityIdentifier)
|
||||
|
||||
if let borderWidth = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .borderWidth) {
|
||||
self.borderWidth = borderWidth
|
||||
}
|
||||
@ -169,6 +171,7 @@ import Foundation
|
||||
try container.encode(borderWidth, forKey: .borderWidth)
|
||||
try container.encode(checked, forKey: .checked)
|
||||
try container.encode(inverted, forKey: .inverted)
|
||||
try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier)
|
||||
try container.encodeIfPresent(checkColor, forKey: .checkColor)
|
||||
try container.encodeIfPresent(invertedColor, forKey: .invertedColor)
|
||||
try container.encodeIfPresent(invertedBackgroundColor, forKey: .invertedBackgroundColor)
|
||||
|
||||
@ -71,6 +71,7 @@ import UIKit
|
||||
//--------------------------------------------------
|
||||
// MARK: - Lifecycle
|
||||
//--------------------------------------------------
|
||||
|
||||
open override func setupView() {
|
||||
super.setupView()
|
||||
addTarget(self, action: #selector(tapAction), for: .touchUpInside)
|
||||
|
||||
@ -6,15 +6,16 @@
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
open class HeartModel: MoleculeModelProtocol, EnableableModelProtocol {
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
public static var identifier: String = "heart"
|
||||
public var backgroundColor: Color?
|
||||
public var accessibilityIdentifier: String?
|
||||
public var isActive: Bool = false
|
||||
public var activeColor: Color = Color(uiColor: .mvmRed)
|
||||
public var inActiveColor: Color = Color(uiColor: .clear)
|
||||
@ -24,9 +25,11 @@ open class HeartModel: MoleculeModelProtocol, EnableableModelProtocol {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Keys
|
||||
//--------------------------------------------------
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case moleculeName
|
||||
case backgroundColor
|
||||
case accessibilityIdentifier
|
||||
case isActive
|
||||
case activeColor
|
||||
case inActiveColor
|
||||
@ -43,13 +46,18 @@ open class HeartModel: MoleculeModelProtocol, EnableableModelProtocol {
|
||||
if let isActive = try typeContainer.decodeIfPresent(Bool.self, forKey: .isActive) {
|
||||
self.isActive = isActive
|
||||
}
|
||||
|
||||
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
|
||||
accessibilityIdentifier = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityIdentifier)
|
||||
|
||||
if let activeColor = try typeContainer.decodeIfPresent(Color.self, forKey: .activeColor) {
|
||||
self.activeColor = activeColor
|
||||
}
|
||||
|
||||
if let inActiveColor = try typeContainer.decodeIfPresent(Color.self, forKey: .inActiveColor) {
|
||||
self.inActiveColor = inActiveColor
|
||||
}
|
||||
|
||||
if let action: ActionModelProtocol = try typeContainer.decodeModelIfPresent(codingKey: .action) {
|
||||
self.action = action
|
||||
}
|
||||
@ -61,6 +69,7 @@ open class HeartModel: MoleculeModelProtocol, EnableableModelProtocol {
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
|
||||
try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier)
|
||||
try container.encode(moleculeName, forKey: .moleculeName)
|
||||
try container.encode(isActive, forKey: .isActive)
|
||||
try container.encode(activeColor, forKey: .activeColor)
|
||||
|
||||
@ -6,9 +6,12 @@
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
open class RadioBox: Control, MFButtonProtocol {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
public let label = Label(fontStyle: .RegularBodySmall)
|
||||
public let subTextLabel = Label(fontStyle: .RegularMicro)
|
||||
public var isOutOfStock = false
|
||||
@ -26,22 +29,20 @@ open class RadioBox: Control, MFButtonProtocol {
|
||||
var additionalData: [AnyHashable: Any]?
|
||||
|
||||
public var radioBoxModel: RadioBoxModel? {
|
||||
return model as? RadioBoxModel
|
||||
model as? RadioBoxModel
|
||||
}
|
||||
|
||||
public override var isSelected: Bool {
|
||||
didSet {
|
||||
updateAccessibility()
|
||||
}
|
||||
didSet { updateAccessibility() }
|
||||
}
|
||||
|
||||
public override var isEnabled: Bool {
|
||||
didSet {
|
||||
updateAccessibility()
|
||||
}
|
||||
didSet { updateAccessibility() }
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - MVMCoreViewProtocol
|
||||
//--------------------------------------------------
|
||||
|
||||
open override func updateView(_ size: CGFloat) {
|
||||
super.updateView(size)
|
||||
@ -75,8 +76,6 @@ open class RadioBox: Control, MFButtonProtocol {
|
||||
isAccessibilityElement = true
|
||||
}
|
||||
|
||||
// MARK: - MoleculeViewProtocol
|
||||
|
||||
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||
super.set(with: model, delegateObject, additionalData)
|
||||
guard let model = model as? RadioBoxModel else { return }
|
||||
@ -99,7 +98,9 @@ open class RadioBox: Control, MFButtonProtocol {
|
||||
accentColor = .mvmRed
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - State Handling
|
||||
//--------------------------------------------------
|
||||
|
||||
open override func draw(_ layer: CALayer, in ctx: CGContext) {
|
||||
// Draw the strikethrough
|
||||
@ -213,21 +214,29 @@ open class RadioBox: Control, MFButtonProtocol {
|
||||
return mask
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Accessibility
|
||||
//--------------------------------------------------
|
||||
|
||||
public func updateAccessibility() {
|
||||
|
||||
var message = ""
|
||||
|
||||
if let labelText = label.text, label.hasText {
|
||||
message += labelText + ", "
|
||||
}
|
||||
|
||||
if let subLabelText = subTextLabel.text, subTextLabel.hasText {
|
||||
message += subLabelText + ", "
|
||||
}
|
||||
accessibilityLabel = message
|
||||
|
||||
accessibilityLabel = message
|
||||
accessibilityTraits = .button
|
||||
|
||||
if isSelected {
|
||||
accessibilityTraits.insert(.selected)
|
||||
}
|
||||
|
||||
if !isEnabled {
|
||||
accessibilityTraits.insert(.notEnabled)
|
||||
}
|
||||
|
||||
@ -6,10 +6,17 @@
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
open class RadioBoxCollectionViewCell: CollectionViewCell {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Outlets
|
||||
//--------------------------------------------------
|
||||
|
||||
public let radioBox = RadioBox()
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Lifecycle
|
||||
//--------------------------------------------------
|
||||
|
||||
open override func reset() {
|
||||
super.reset()
|
||||
backgroundColor = .clear
|
||||
|
||||
@ -6,12 +6,16 @@
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
@objcMembers public class RadioBoxModel: MoleculeModelProtocol {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
public static var identifier: String = "radioBox"
|
||||
public var text: String
|
||||
public var subText: String?
|
||||
public var backgroundColor: Color?
|
||||
public var accessibilityIdentifier: String?
|
||||
public var selectedAccentColor: Color?
|
||||
public var selected: Bool = false
|
||||
public var enabled: Bool = true
|
||||
@ -19,12 +23,17 @@ import Foundation
|
||||
public var fieldValue: String?
|
||||
public var action: ActionModelProtocol?
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Keys
|
||||
//--------------------------------------------------
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case moleculeName
|
||||
case text
|
||||
case subText
|
||||
case selectedAccentColor
|
||||
case backgroundColor
|
||||
case accessibilityIdentifier
|
||||
case selected
|
||||
case enabled
|
||||
case strikethrough
|
||||
@ -32,18 +41,26 @@ import Foundation
|
||||
case action
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Codec
|
||||
//--------------------------------------------------
|
||||
|
||||
required public init(from decoder: Decoder) throws {
|
||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||
text = try typeContainer.decode(String.self, forKey: .text)
|
||||
subText = try typeContainer.decodeIfPresent(String.self, forKey: .subText)
|
||||
selectedAccentColor = try typeContainer.decodeIfPresent(Color.self, forKey: .selectedAccentColor)
|
||||
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
|
||||
accessibilityIdentifier = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityIdentifier)
|
||||
|
||||
if let isSelected = try typeContainer.decodeIfPresent(Bool.self, forKey: .selected) {
|
||||
selected = isSelected
|
||||
}
|
||||
|
||||
if let isEnabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) {
|
||||
enabled = isEnabled
|
||||
}
|
||||
|
||||
if let isStrikeTrough = try typeContainer.decodeIfPresent(Bool.self, forKey: .strikethrough) {
|
||||
strikethrough = isStrikeTrough
|
||||
}
|
||||
@ -59,6 +76,7 @@ import Foundation
|
||||
try container.encodeIfPresent(subText, forKey: .subText)
|
||||
try container.encodeIfPresent(selectedAccentColor, forKey: .selectedAccentColor)
|
||||
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
|
||||
try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier)
|
||||
try container.encode(selected, forKey: .selected)
|
||||
try container.encode(enabled, forKey: .enabled)
|
||||
try container.encode(strikethrough, forKey: .strikethrough)
|
||||
|
||||
@ -57,11 +57,12 @@ open class RadioBoxes: View {
|
||||
super.set(with: model, delegateObject, additionalData)
|
||||
self.delegateObject = delegateObject
|
||||
|
||||
guard let radioBoxesModel = model as? RadioBoxesModel else { return }
|
||||
boxes = radioBoxesModel.boxes
|
||||
FormValidator.setupValidation(for: radioBoxesModel, delegate: delegateObject?.formHolderDelegate)
|
||||
guard let model = model as? RadioBoxesModel else { return }
|
||||
boxes = model.boxes
|
||||
FormValidator.setupValidation(for: model, delegate: delegateObject?.formHolderDelegate)
|
||||
|
||||
backgroundColor = radioBoxesModel.backgroundColor?.uiColor
|
||||
backgroundColor = model.backgroundColor?.uiColor
|
||||
|
||||
registerCells()
|
||||
setHeight()
|
||||
collectionView.reloadData()
|
||||
@ -168,4 +169,3 @@ extension RadioBoxes: UICollectionViewDelegate {
|
||||
cell.updateAccessibility()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -6,17 +6,25 @@
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
@objcMembers public class RadioBoxesModel: MoleculeModelProtocol, FormFieldProtocol {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
public static var identifier: String = "radioBoxes"
|
||||
public var boxes: [RadioBoxModel]
|
||||
public var backgroundColor: Color?
|
||||
public var accessibilityIdentifier: String?
|
||||
public var selectedAccentColor: Color?
|
||||
public var boxesColor: Color?
|
||||
public var fieldKey: String?
|
||||
public var groupName: String = FormValidator.defaultGroupName
|
||||
public var baseValue: AnyHashable?
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Methods
|
||||
//--------------------------------------------------
|
||||
|
||||
/// Returns the fieldValue of the selected box, otherwise the text of the selected box.
|
||||
public func formFieldValue() -> AnyHashable? {
|
||||
let selectedBox = boxes.first { (box) -> Bool in
|
||||
@ -25,20 +33,30 @@ import Foundation
|
||||
return selectedBox?.fieldValue ?? selectedBox?.text
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Keys
|
||||
//--------------------------------------------------
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case moleculeName
|
||||
case selectedAccentColor
|
||||
case backgroundColor
|
||||
case accessibilityIdentifier
|
||||
case boxesColor
|
||||
case boxes
|
||||
case fieldKey
|
||||
case groupName
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Codec
|
||||
//--------------------------------------------------
|
||||
|
||||
required public init(from decoder: Decoder) throws {
|
||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||
selectedAccentColor = try typeContainer.decodeIfPresent(Color.self, forKey: .selectedAccentColor)
|
||||
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
|
||||
accessibilityIdentifier = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityIdentifier)
|
||||
boxesColor = try typeContainer.decodeIfPresent(Color.self, forKey: .boxesColor)
|
||||
boxes = try typeContainer.decode([RadioBoxModel].self, forKey: .boxes)
|
||||
fieldKey = try typeContainer.decodeIfPresent(String.self, forKey: .fieldKey)
|
||||
@ -54,6 +72,7 @@ import Foundation
|
||||
try container.encode(boxes, forKey: .boxes)
|
||||
try container.encodeIfPresent(selectedAccentColor, forKey: .selectedAccentColor)
|
||||
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
|
||||
try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier)
|
||||
try container.encodeIfPresent(fieldKey, forKey: .fieldKey)
|
||||
try container.encode(groupName, forKey: .groupName)
|
||||
}
|
||||
|
||||
@ -15,9 +15,7 @@ import UIKit
|
||||
//--------------------------------------------------
|
||||
|
||||
public var diameter: CGFloat = 30 {
|
||||
didSet {
|
||||
widthConstraint?.constant = diameter
|
||||
}
|
||||
didSet { widthConstraint?.constant = diameter }
|
||||
}
|
||||
|
||||
@objc public override var isSelected: Bool {
|
||||
@ -33,12 +31,10 @@ import UIKit
|
||||
var additionalData: [AnyHashable: Any]?
|
||||
|
||||
public var radioModel: RadioButtonModel? {
|
||||
return model as? RadioButtonModel
|
||||
model as? RadioButtonModel
|
||||
}
|
||||
|
||||
lazy public var radioGroupName: String? = {
|
||||
return radioModel?.fieldKey
|
||||
}()
|
||||
lazy public var radioGroupName: String? = { radioModel?.fieldKey }()
|
||||
|
||||
lazy public var radioButtonSelectionHelper: RadioButtonSelectionHelper? = {
|
||||
|
||||
@ -95,33 +91,34 @@ import UIKit
|
||||
if !isEnabled {
|
||||
return
|
||||
}
|
||||
|
||||
let wasPreviouslySelected = isSelected
|
||||
if let radioButtonModel = radioButtonSelectionHelper {
|
||||
radioButtonModel.selected(self)
|
||||
} else {
|
||||
isSelected = !isSelected
|
||||
}
|
||||
|
||||
if let radioModel = radioModel, let actionModel = radioModel.action, isSelected, !wasPreviouslySelected {
|
||||
Button.performButtonAction(with: actionModel, button: self, delegateObject: delegateObject, additionalData: additionalData, sourceModel: radioModel)
|
||||
}
|
||||
|
||||
_ = FormValidator.validate(delegate: delegateObject?.formHolderDelegate)
|
||||
setNeedsDisplay()
|
||||
}
|
||||
|
||||
public func isValidField() -> Bool {
|
||||
return isSelected
|
||||
}
|
||||
public func isValidField() -> Bool { isSelected }
|
||||
|
||||
public func formFieldName() -> String? {
|
||||
return radioModel?.fieldKey
|
||||
radioModel?.fieldKey
|
||||
}
|
||||
|
||||
public func formFieldGroupName() -> String? {
|
||||
return radioModel?.fieldKey
|
||||
radioModel?.fieldKey
|
||||
}
|
||||
|
||||
public func formFieldValue() -> AnyHashable? {
|
||||
return radioModel?.fieldValue
|
||||
radioModel?.fieldValue
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
|
||||
@ -6,7 +6,6 @@
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import MVMCore
|
||||
|
||||
|
||||
@ -17,6 +16,7 @@ open class RadioButtonModel: MoleculeModelProtocol, FormFieldProtocol {
|
||||
|
||||
public static var identifier: String = "radioButton"
|
||||
public var backgroundColor: Color?
|
||||
public var accessibilityIdentifier: String?
|
||||
public var state: Bool = false
|
||||
public var enabled: Bool = true
|
||||
|
||||
@ -35,6 +35,7 @@ open class RadioButtonModel: MoleculeModelProtocol, FormFieldProtocol {
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case moleculeName
|
||||
case backgroundColor
|
||||
case accessibilityIdentifier
|
||||
case state
|
||||
case enabled
|
||||
case fieldValue
|
||||
@ -56,9 +57,7 @@ open class RadioButtonModel: MoleculeModelProtocol, FormFieldProtocol {
|
||||
// MARK: - Validation
|
||||
//--------------------------------------------------
|
||||
|
||||
public func formFieldValue() -> AnyHashable? {
|
||||
return fieldValue
|
||||
}
|
||||
public func formFieldValue() -> AnyHashable? { fieldValue }
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Codec
|
||||
@ -76,6 +75,7 @@ open class RadioButtonModel: MoleculeModelProtocol, FormFieldProtocol {
|
||||
}
|
||||
|
||||
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
|
||||
accessibilityIdentifier = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityIdentifier)
|
||||
|
||||
baseValue = state
|
||||
fieldKey = try typeContainer.decodeIfPresent(String.self, forKey: .fieldKey)
|
||||
@ -89,6 +89,7 @@ open class RadioButtonModel: MoleculeModelProtocol, FormFieldProtocol {
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
|
||||
try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier)
|
||||
try container.encode(moleculeName, forKey: .moleculeName)
|
||||
try container.encode(state, forKey: .state)
|
||||
try container.encode(enabled, forKey: .enabled)
|
||||
|
||||
@ -6,8 +6,6 @@
|
||||
// Copyright © 2019 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
|
||||
@objcMembers public class RadioButtonSelectionHelper: FormFieldProtocol {
|
||||
//--------------------------------------------------
|
||||
@ -77,7 +75,5 @@ import Foundation
|
||||
// MARK: - FormValidationFormFieldProtocol
|
||||
extension RadioButtonSelectionHelper {
|
||||
|
||||
public func formFieldValue() -> AnyHashable? {
|
||||
return selectedRadioButtonModel?.fieldValue
|
||||
}
|
||||
public func formFieldValue() -> AnyHashable? { selectedRadioButtonModel?.fieldValue }
|
||||
}
|
||||
|
||||
@ -77,6 +77,7 @@ open class RadioSwatch: Control, MFButtonProtocol {
|
||||
//------------------------------------------------------
|
||||
// MARK: - State Handling
|
||||
//------------------------------------------------------
|
||||
|
||||
open override func draw(_ layer: CALayer, in ctx: CGContext) {
|
||||
//Draw the swatch
|
||||
circleLayer?.removeFromSuperlayer()
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
open class RadioSwatchCollectionViewCell: CollectionViewCell {
|
||||
public let radioSwatch = RadioSwatch()
|
||||
|
||||
|
||||
@ -6,11 +6,15 @@
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@objcMembers public class RadioSwatchModel: MoleculeModelProtocol {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
public static var identifier: String = "radioSwatch"
|
||||
public var backgroundColor: Color?
|
||||
public var accessibilityIdentifier: String?
|
||||
public var color: Color = Color(uiColor: .mvmBlue)
|
||||
public var text: String?
|
||||
public var selected: Bool = false
|
||||
@ -19,9 +23,14 @@ import Foundation
|
||||
public var fieldValue: String?
|
||||
public var action: ActionModelProtocol?
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Keys
|
||||
//--------------------------------------------------
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case moleculeName
|
||||
case backgroundColor
|
||||
case accessibilityIdentifier
|
||||
case color
|
||||
case text
|
||||
case selected
|
||||
@ -31,22 +40,33 @@ import Foundation
|
||||
case action
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Codec
|
||||
//--------------------------------------------------
|
||||
|
||||
required public init(from decoder: Decoder) throws {
|
||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
|
||||
accessibilityIdentifier = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityIdentifier)
|
||||
|
||||
if let color = try typeContainer.decodeIfPresent(Color.self, forKey: .color) {
|
||||
self.color = color
|
||||
}
|
||||
|
||||
text = try typeContainer.decodeIfPresent(String.self, forKey: .text)
|
||||
|
||||
if let selected = try typeContainer.decodeIfPresent(Bool.self, forKey: .selected) {
|
||||
self.selected = selected
|
||||
}
|
||||
|
||||
if let enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) {
|
||||
self.enabled = enabled
|
||||
}
|
||||
|
||||
if let strikethrough = try typeContainer.decodeIfPresent(Bool.self, forKey: .strikethrough) {
|
||||
self.strikethrough = strikethrough
|
||||
}
|
||||
|
||||
fieldValue = try typeContainer.decodeIfPresent(String.self, forKey: .fieldValue)
|
||||
action = try typeContainer.decodeModelIfPresent(codingKey: .action)
|
||||
}
|
||||
@ -55,6 +75,7 @@ import Foundation
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(moleculeName, forKey: .moleculeName)
|
||||
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
|
||||
try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier)
|
||||
try container.encode(color, forKey: .color)
|
||||
try container.encodeIfPresent(text, forKey: .text)
|
||||
try container.encode(selected, forKey: .selected)
|
||||
@ -64,5 +85,3 @@ import Foundation
|
||||
try container.encodeModelIfPresent(action, forKey: .action)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -55,9 +55,9 @@ open class RadioSwatches: View {
|
||||
super.set(with: model, delegateObject, additionalData)
|
||||
self.delegateObject = delegateObject
|
||||
|
||||
guard let radioSwatchesModel = model as? RadioSwatchesModel else { return }
|
||||
swatches = radioSwatchesModel.swatches
|
||||
FormValidator.setupValidation(for: radioSwatchesModel, delegate: delegateObject?.formHolderDelegate)
|
||||
guard let model = model as? RadioSwatchesModel else { return }
|
||||
swatches = model.swatches
|
||||
FormValidator.setupValidation(for: model, delegate: delegateObject?.formHolderDelegate)
|
||||
collectionView.reloadData()
|
||||
}
|
||||
|
||||
|
||||
@ -6,16 +6,24 @@
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@objcMembers public class RadioSwatchesModel: MoleculeModelProtocol, FormFieldProtocol {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
public static var identifier: String = "radioSwatches"
|
||||
public var backgroundColor: Color?
|
||||
public var accessibilityIdentifier: String?
|
||||
public var swatches: [RadioSwatchModel]
|
||||
public var fieldKey: String?
|
||||
public var groupName: String = FormValidator.defaultGroupName
|
||||
public var baseValue: AnyHashable?
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Methods
|
||||
//--------------------------------------------------
|
||||
|
||||
/// Returns the fieldValue of the selected swatch, otherwise the text of selected swatch.
|
||||
public func formFieldValue() -> AnyHashable? {
|
||||
let selectedSwatch = swatches.first { (swatch) -> Bool in
|
||||
@ -24,17 +32,27 @@ import Foundation
|
||||
return selectedSwatch?.fieldValue ?? selectedSwatch?.text
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Keys
|
||||
//--------------------------------------------------
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case moleculeName
|
||||
case backgroundColor
|
||||
case accessibilityIdentifier
|
||||
case swatches
|
||||
case fieldKey
|
||||
case groupName
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Codec
|
||||
//--------------------------------------------------
|
||||
|
||||
required public init(from decoder: Decoder) throws {
|
||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
|
||||
accessibilityIdentifier = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityIdentifier)
|
||||
swatches = try typeContainer.decode([RadioSwatchModel].self, forKey: .swatches)
|
||||
fieldKey = try typeContainer.decodeIfPresent(String.self, forKey: .fieldKey)
|
||||
if let groupName = try typeContainer.decodeIfPresent(String.self, forKey: .groupName) {
|
||||
@ -47,6 +65,7 @@ import Foundation
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(moleculeName, forKey: .moleculeName)
|
||||
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
|
||||
try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier)
|
||||
try container.encode(swatches, forKey: .swatches)
|
||||
try container.encodeIfPresent(fieldKey, forKey: .fieldKey)
|
||||
try container.encode(groupName, forKey: .groupName)
|
||||
|
||||
@ -40,7 +40,7 @@ public typealias ActionBlockConfirmation = () -> (Bool)
|
||||
|
||||
/// Executes logic before state change. If false, then toggle state will not change and the didToggleAction will not execute.
|
||||
public var shouldToggleAction: ActionBlockConfirmation? = {
|
||||
return { return true }
|
||||
return { true }
|
||||
}()
|
||||
|
||||
// Sizes are from InVision design specs.
|
||||
@ -69,9 +69,7 @@ public typealias ActionBlockConfirmation = () -> (Bool)
|
||||
|
||||
/// Simple means to prevent user interaction with the toggle.
|
||||
public var isLocked: Bool = false {
|
||||
didSet {
|
||||
isUserInteractionEnabled = !isLocked
|
||||
}
|
||||
didSet { isUserInteractionEnabled = !isLocked }
|
||||
}
|
||||
|
||||
/// The state on the toggle. Default value: false.
|
||||
@ -109,7 +107,7 @@ public typealias ActionBlockConfirmation = () -> (Bool)
|
||||
}
|
||||
|
||||
public var toggleModel: ToggleModel? {
|
||||
return model as? ToggleModel
|
||||
model as? ToggleModel
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
@ -392,21 +390,17 @@ public typealias ActionBlockConfirmation = () -> (Bool)
|
||||
accessibilityLabel = accessibileString
|
||||
}
|
||||
|
||||
let actionMap = model.action?.toJSON()
|
||||
let alternateActionMap = model.alternateAction?.toJSON()
|
||||
let additionalDataWithSource = additionalData.dictionaryAdding(key: KeySourceModel, value: model)
|
||||
if actionMap != nil || alternateActionMap != nil {
|
||||
if model.action != nil || model.alternateAction != nil {
|
||||
didToggleAction = { [weak self] in
|
||||
guard let self = self else { return }
|
||||
if self.isOn {
|
||||
if actionMap != nil {
|
||||
MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalDataWithSource, delegateObject: delegateObject)
|
||||
if let action = model.action {
|
||||
MVMCoreActionHandler.shared()?.asyncHandleAction(with: action, additionalData: additionalDataWithSource, delegateObject: delegateObject)
|
||||
}
|
||||
} else {
|
||||
if alternateActionMap != nil {
|
||||
MVMCoreActionHandler.shared()?.handleAction(with: alternateActionMap, additionalData: additionalDataWithSource, delegateObject: delegateObject)
|
||||
} else if actionMap != nil {
|
||||
MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalDataWithSource, delegateObject: delegateObject)
|
||||
if let action = model.alternateAction ?? model.action {
|
||||
MVMCoreActionHandler.shared()?.asyncHandleAction(with: action, additionalData: additionalDataWithSource, delegateObject: delegateObject)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -414,18 +408,14 @@ public typealias ActionBlockConfirmation = () -> (Bool)
|
||||
}
|
||||
|
||||
public override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
|
||||
return Self.getContainerHeight()
|
||||
Self.getContainerHeight()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - MVMCoreUIViewConstrainingProtocol
|
||||
extension Toggle {
|
||||
|
||||
public func needsToBeConstrained() -> Bool {
|
||||
return true
|
||||
}
|
||||
public func needsToBeConstrained() -> Bool { true }
|
||||
|
||||
public func horizontalAlignment() -> UIStackView.Alignment {
|
||||
return .trailing
|
||||
}
|
||||
public func horizontalAlignment() -> UIStackView.Alignment { .trailing }
|
||||
}
|
||||
@ -6,8 +6,6 @@
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
|
||||
public class ToggleModel: MoleculeModelProtocol, FormFieldProtocol, EnableableModelProtocol {
|
||||
//--------------------------------------------------
|
||||
@ -15,6 +13,7 @@ public class ToggleModel: MoleculeModelProtocol, FormFieldProtocol, EnableableMo
|
||||
//--------------------------------------------------
|
||||
|
||||
public static var identifier: String = "toggle"
|
||||
public var accessibilityIdentifier: String?
|
||||
public var backgroundColor: Color?
|
||||
public var state: Bool = false
|
||||
public var animated: Bool = true
|
||||
@ -42,6 +41,7 @@ public class ToggleModel: MoleculeModelProtocol, FormFieldProtocol, EnableableMo
|
||||
case enabled
|
||||
case action
|
||||
case backgroundColor
|
||||
case accessibilityIdentifier
|
||||
case alternateAction
|
||||
case accessibilityText
|
||||
case onTintColor
|
||||
@ -56,9 +56,7 @@ public class ToggleModel: MoleculeModelProtocol, FormFieldProtocol, EnableableMo
|
||||
// MARK: - Methods
|
||||
//--------------------------------------------------
|
||||
|
||||
public func formFieldValue() -> AnyHashable? {
|
||||
return state
|
||||
}
|
||||
public func formFieldValue() -> AnyHashable? { state }
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializer
|
||||
@ -91,6 +89,7 @@ public class ToggleModel: MoleculeModelProtocol, FormFieldProtocol, EnableableMo
|
||||
action = try typeContainer.decodeModelIfPresent(codingKey: .action)
|
||||
alternateAction = try typeContainer.decodeModelIfPresent(codingKey: .alternateAction)
|
||||
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
|
||||
accessibilityIdentifier = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityIdentifier)
|
||||
|
||||
if let onTintColor = try typeContainer.decodeIfPresent(Color.self, forKey: .onTintColor) {
|
||||
self.onTintColor = onTintColor
|
||||
@ -120,6 +119,7 @@ public class ToggleModel: MoleculeModelProtocol, FormFieldProtocol, EnableableMo
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
|
||||
try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier)
|
||||
try container.encodeModelIfPresent(action, forKey: .action)
|
||||
try container.encodeModelIfPresent(alternateAction, forKey: .alternateAction)
|
||||
try container.encode(moleculeName, forKey: .moleculeName)
|
||||
@ -16,6 +16,7 @@ import Foundation
|
||||
|
||||
public static var identifier: String = "dashLine"
|
||||
public var backgroundColor: Color?
|
||||
public var accessibilityIdentifier: String?
|
||||
public var dashColor: Color = Color(uiColor: .mvmCoolGray3)
|
||||
public var dashColor_inverted: Color = Color(uiColor: .mvmWhite)
|
||||
public var isHidden: Bool = false
|
||||
@ -36,6 +37,7 @@ import Foundation
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case moleculeName
|
||||
case backgroundColor
|
||||
case accessibilityIdentifier
|
||||
case dashColor_inverted
|
||||
case dashColor
|
||||
case isHidden
|
||||
@ -57,6 +59,7 @@ import Foundation
|
||||
}
|
||||
|
||||
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
|
||||
accessibilityIdentifier = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityIdentifier)
|
||||
|
||||
if let isHidden = try typeContainer.decodeIfPresent(Bool.self, forKey: .isHidden) {
|
||||
self.isHidden = isHidden
|
||||
@ -69,5 +72,6 @@ import Foundation
|
||||
try container.encode(dashColor, forKey: .dashColor)
|
||||
try container.encode(isHidden, forKey: .isHidden)
|
||||
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
|
||||
try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier)
|
||||
}
|
||||
}
|
||||
|
||||
@ -38,7 +38,7 @@ public typealias ActionBlock = () -> ()
|
||||
}
|
||||
|
||||
public var getRange: NSRange {
|
||||
return NSRange(location: 0, length: text?.count ?? 0)
|
||||
NSRange(location: 0, length: text?.count ?? 0)
|
||||
}
|
||||
|
||||
//------------------------------------------------------
|
||||
@ -209,7 +209,7 @@ public typealias ActionBlock = () -> ()
|
||||
|
||||
/// Default
|
||||
@objc open class func label() -> Label {
|
||||
return Label(frame: .zero)
|
||||
Label(frame: .zero)
|
||||
}
|
||||
|
||||
//------------------------------------------------------
|
||||
@ -381,9 +381,7 @@ public typealias ActionBlock = () -> ()
|
||||
}
|
||||
case let actionAtt as LabelAttributeActionModel:
|
||||
addTappableLinkAttribute(range: NSRange(location: range.location, length: range.length)) {
|
||||
if let data = try? actionAtt.action.encode(using: JSONEncoder()), let actionMap = try? JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.init()) as? [AnyHashable: Any] {
|
||||
MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegateObject: delegateObject)
|
||||
}
|
||||
MVMCoreActionHandler.shared()?.asyncHandleAction(with: actionAtt.action, additionalData: additionalData, delegateObject: delegateObject)
|
||||
}
|
||||
addActionAttributes(range: range, string: attributedString)
|
||||
|
||||
@ -794,17 +792,11 @@ extension Label {
|
||||
accessibilityTraits = .staticText
|
||||
}
|
||||
|
||||
public func needsToBeConstrained() -> Bool {
|
||||
return true
|
||||
}
|
||||
public func needsToBeConstrained() -> Bool { true }
|
||||
|
||||
public func horizontalAlignment() -> UIStackView.Alignment {
|
||||
return .leading
|
||||
}
|
||||
public func horizontalAlignment() -> UIStackView.Alignment { .leading }
|
||||
|
||||
public func copyBackgroundColor() -> Bool {
|
||||
return true
|
||||
}
|
||||
public func copyBackgroundColor() -> Bool { true }
|
||||
}
|
||||
|
||||
// MARK: - Multi-Link Functionality
|
||||
@ -916,6 +908,7 @@ extension UITapGestureRecognizer {
|
||||
if label.makeWholeViewClickable {
|
||||
return true
|
||||
}
|
||||
|
||||
guard let abstractContainer = label.abstractTextContainer() else { return false }
|
||||
let textContainer = abstractContainer.0
|
||||
let layoutManager = abstractContainer.1
|
||||
@ -990,6 +983,7 @@ extension Label {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
@ -12,9 +12,7 @@ open class LabelAttributeActionModel: LabelAttributeModel {
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
override public class var identifier: String {
|
||||
return "action"
|
||||
}
|
||||
override public class var identifier: String { "action" }
|
||||
|
||||
var action: ActionModelProtocol
|
||||
|
||||
|
||||
@ -12,9 +12,7 @@
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
override public class var identifier: String {
|
||||
return "color"
|
||||
}
|
||||
override public class var identifier: String { "color" }
|
||||
|
||||
var textColor: Color?
|
||||
|
||||
|
||||
@ -12,9 +12,7 @@
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
override public class var identifier: String {
|
||||
return "font"
|
||||
}
|
||||
override public class var identifier: String { "font" }
|
||||
|
||||
var style: Styler.Font?
|
||||
var name: String?
|
||||
|
||||
@ -12,9 +12,7 @@ class LabelAttributeImageModel: LabelAttributeModel {
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
override public class var identifier: String {
|
||||
return "image"
|
||||
}
|
||||
override public class var identifier: String { "image" }
|
||||
|
||||
var size: CGFloat?
|
||||
var name: String?
|
||||
|
||||
@ -12,20 +12,14 @@
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
public static var categoryName: String {
|
||||
return "\(LabelAttributeModel.self)"
|
||||
}
|
||||
public static var categoryName: String { "\(LabelAttributeModel.self)" }
|
||||
|
||||
public static var categoryCodingKey: String {
|
||||
return "type"
|
||||
}
|
||||
public static var categoryCodingKey: String { "type" }
|
||||
|
||||
public class var identifier: String {
|
||||
return ""
|
||||
}
|
||||
public class var identifier: String { "" }
|
||||
|
||||
var type: String {
|
||||
get { return Self.identifier }
|
||||
get { Self.identifier }
|
||||
}
|
||||
|
||||
var location: Int
|
||||
|
||||
@ -12,9 +12,7 @@
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
override public class var identifier: String {
|
||||
return "strikethrough"
|
||||
}
|
||||
override public class var identifier: String { "strikethrough" }
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializer
|
||||
|
||||
@ -14,9 +14,7 @@ import UIKit
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
override public class var identifier: String {
|
||||
return "underline"
|
||||
}
|
||||
override public class var identifier: String { "underline" }
|
||||
|
||||
/// This returns the NSUnderlineStyle used in NSAttributedValue. If there is a pattern, it will return
|
||||
/// a new NSUnderlineStyle derived from the bitmask of style | pattern.
|
||||
|
||||
@ -21,7 +21,8 @@
|
||||
|
||||
public var addSizeConstraintsForAspectRatio = true
|
||||
public var shouldNotifyDelegateOnUpdate = true
|
||||
|
||||
public var shouldNotifyDelegateOnDefaultSizeChange = false
|
||||
|
||||
// Allows for a view to hardcode which height to use if there is none in the json.
|
||||
var imageWidth: CGFloat?
|
||||
var imageHeight: CGFloat?
|
||||
@ -228,13 +229,13 @@
|
||||
|
||||
let widthWillChange = !MVMCoreGetterUtility.cgfequal(widthConstraint?.constant ?? 0, width ?? 0)
|
||||
let heightWillChange = !MVMCoreGetterUtility.cgfequal(heightConstraint?.constant ?? 0, height ?? 0)
|
||||
let sizeWillChange = (width == nil || height == nil) && !(size?.equalTo(imageView.image?.size ?? CGSize.zero) ?? false)
|
||||
let sizeWillChange = shouldNotifyDelegateOnDefaultSizeChange && (width == nil || height == nil) && !(size?.equalTo(imageView.image?.size ?? CGSize.zero) ?? false)
|
||||
let heightChangeFromSpinner = (heightConstraint?.isActive ?? false) ? false : ((height ?? size?.height) ?? 0) < loadingSpinnerHeightConstraint?.constant ?? CGFloat.leastNormalMagnitude
|
||||
return widthWillChange || heightWillChange || sizeWillChange || heightChangeFromSpinner
|
||||
}
|
||||
|
||||
// Constrains the image view to be the size provided. Used to size it to the image to fix aspect fit defect.
|
||||
func addConstraints(width: NSNumber?, height: NSNumber?, size: CGSize?) {
|
||||
func addConstraints(width: CGFloat?, height: CGFloat?, size: CGSize?) {
|
||||
|
||||
widthConstraint?.isActive = false
|
||||
heightConstraint?.isActive = false
|
||||
@ -242,15 +243,15 @@
|
||||
guard addSizeConstraintsForAspectRatio else { return }
|
||||
|
||||
if let width = width, let height = height {
|
||||
setHeight(height.cgfloat())
|
||||
setWidth(width.cgfloat())
|
||||
setHeight(height)
|
||||
setWidth(width)
|
||||
} else if let width = width, let size = size {
|
||||
setWidth(width.cgfloat())
|
||||
setWidth(width)
|
||||
heightConstraint = imageView.heightAnchor.constraint(equalTo: imageView.widthAnchor, multiplier: size.height/size.width)
|
||||
heightConstraint?.priority = UILayoutPriority(rawValue: 900)
|
||||
heightConstraint?.isActive = true
|
||||
} else if let height = height, let size = size {
|
||||
setHeight(height.cgfloat())
|
||||
setHeight(height)
|
||||
widthConstraint = imageView.widthAnchor.constraint(equalTo: imageView.heightAnchor, multiplier: size.width/size.height)
|
||||
widthConstraint?.priority = UILayoutPriority(rawValue: 900)
|
||||
widthConstraint?.isActive = true
|
||||
@ -288,7 +289,7 @@
|
||||
if shouldLoadImage(withName: imageModel.image, width: width, height: height) {
|
||||
imageView.image = nil
|
||||
imageView.animatedImage = nil
|
||||
loadImage(withName: imageModel.image, format: imageModel.imageFormat, width: width as NSNumber?, height: height as NSNumber?, customFallbackImage: imageModel.fallbackImage, localBundle: imageModel.localBundle)
|
||||
loadImage(withName: imageModel.image, format: imageModel.imageFormat, width: width, height: height, customFallbackImage: imageModel.fallbackImage, localBundle: imageModel.localBundle)
|
||||
}
|
||||
|
||||
if let contentMode = imageModel.contentMode {
|
||||
@ -309,13 +310,13 @@
|
||||
// MARK: - Load Methods
|
||||
//--------------------------------------------------
|
||||
|
||||
public func loadImage(withName imageName: String?, format: String? = nil, width: NSNumber? = nil, height: NSNumber? = nil, customFallbackImage: String? = nil, allowServerParameters: Bool = false, localBundle: Bundle? = nil, completionHandler: MVMCoreGetImageBlock? = nil) {
|
||||
public func loadImage(withName imageName: String?, format: String? = nil, width: CGFloat? = nil, height: CGFloat? = nil, customFallbackImage: String? = nil, allowServerParameters: Bool = false, localBundle: Bundle? = nil, completionHandler: MVMCoreGetImageBlock? = nil) {
|
||||
|
||||
let completionBlock = completionHandler ?? defaultCompletionBlock()
|
||||
MVMCoreDispatchUtility.performBlock(onMainThread: { [unowned self] in
|
||||
self.currentImageName = imageName
|
||||
self.currentImageWidth = width?.cgfloat()
|
||||
self.currentImageHeight = height?.cgfloat()
|
||||
self.currentImageWidth = width
|
||||
self.currentImageHeight = height
|
||||
if MVMCoreCache.isHostedImage(imageName) {
|
||||
self.loadingSpinner.resumeSpinnerAfterDelay()
|
||||
self.loadingSpinnerHeightConstraint?.constant = self.spinnerHeight
|
||||
@ -338,9 +339,9 @@
|
||||
let fallbackImageName = customFallbackImage ?? MVMCoreUIUtility.localizedImageName("fallback")
|
||||
if let format = format, format.lowercased().contains("gif") {
|
||||
// Gifs aren't supported by default and need special handling
|
||||
MVMCoreCache.shared()?.getGif(imageName, useWidth: width != nil, widthForS7: width?.intValue ?? 0, useHeight: height != nil, heightForS7: height?.intValue ?? 0, format: format, localFallbackImageName: fallbackImageName, allowServerQueryParameters: allowServerParameters, localBundle: localBundle, completionHandler: finishedLoadingBlock)
|
||||
MVMCoreCache.shared()?.getGif(imageName, useWidth: width != nil, widthForS7: Int(width ?? 0), useHeight: height != nil, heightForS7: Int(height ?? 0), format: format, localFallbackImageName: fallbackImageName, allowServerQueryParameters: allowServerParameters, localBundle: localBundle, completionHandler: finishedLoadingBlock)
|
||||
} else {
|
||||
MVMCoreCache.shared()?.getImage(imageName, useWidth: width != nil, widthForS7: width?.intValue ?? 0, useHeight: height != nil, heightForS7: height?.intValue ?? 0, format: format, localFallbackImageName: fallbackImageName, allowServerQueryParameters: allowServerParameters, localBundle: localBundle, completionHandler: finishedLoadingBlock)
|
||||
MVMCoreCache.shared()?.getImage(imageName, useWidth: width != nil, widthForS7: Int(width ?? 0), useHeight: height != nil, heightForS7: Int(height ?? 0), format: format, localFallbackImageName: fallbackImageName, allowServerQueryParameters: allowServerParameters, localBundle: localBundle, completionHandler: finishedLoadingBlock)
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -409,6 +410,6 @@
|
||||
}
|
||||
|
||||
public func loadImage(withName imageName: String?, format: String?, width: NSNumber?, height: NSNumber?, customFallbackImage: String?, completionHandler: @escaping MVMCoreGetImageBlock) {
|
||||
loadImage(withName: imageName, format: format, width: width, height: height, customFallbackImage: customFallbackImage, allowServerParameters: false, completionHandler: completionHandler)
|
||||
loadImage(withName: imageName, format: format, width: width?.cgfloat(), height: height?.cgfloat(), customFallbackImage: customFallbackImage, allowServerParameters: false, completionHandler: completionHandler)
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,7 +17,7 @@ import UIKit
|
||||
private let stack = Stack<StackModel>()
|
||||
|
||||
var multiProgressModel: MultiProgressBarModel? {
|
||||
get { return model as? MultiProgressBarModel }
|
||||
get { model as? MultiProgressBarModel }
|
||||
}
|
||||
|
||||
var roundedCorners: Bool = false {
|
||||
@ -85,7 +85,7 @@ import UIKit
|
||||
//--------------------------------------------------
|
||||
|
||||
/// Creates the bars
|
||||
open func set(with progressList: Array<SingleProgressBarModel>, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||
open func set(with progressList: [SingleProgressBarModel], _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||
stack.removeAllItemViews()
|
||||
|
||||
guard let stackModel = stack.stackModel else { return }
|
||||
@ -103,7 +103,6 @@ import UIKit
|
||||
stack.set(with: stackModel, delegateObject, additionalData)
|
||||
}
|
||||
|
||||
|
||||
public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||
super.set(with: model, delegateObject, additionalData)
|
||||
|
||||
@ -115,6 +114,6 @@ import UIKit
|
||||
}
|
||||
|
||||
public override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
|
||||
return (model as? MultiProgressBarModel)?.thickness ?? 8
|
||||
(model as? MultiProgressBarModel)?.thickness ?? 8
|
||||
}
|
||||
}
|
||||
|
||||
108
MVMCoreUI/Atomic/Atoms/Views/Video.swift
Normal file
108
MVMCoreUI/Atomic/Atoms/Views/Video.swift
Normal file
@ -0,0 +1,108 @@
|
||||
//
|
||||
// Video.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Scott Pfeil on 1/26/21.
|
||||
// Copyright © 2021 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
import AVKit
|
||||
|
||||
open class Video: View {
|
||||
public let videoViewController = AVPlayerViewController()
|
||||
private weak var containingView: UIView?
|
||||
|
||||
/// Used to track the state and respond..
|
||||
private var stateKVOToken: NSKeyValueObservation?
|
||||
|
||||
open override func setupView() {
|
||||
super.setupView()
|
||||
videoViewController.view.translatesAutoresizingMaskIntoConstraints = false
|
||||
addSubview(videoViewController.view)
|
||||
NSLayoutConstraint.constraintPinSubview(toSuperview: videoViewController.view)
|
||||
videoViewController.videoGravity = .resizeAspectFill
|
||||
}
|
||||
|
||||
/// Checks if the video is visible in the molecule delegate
|
||||
open func isVisibleInDelegate() -> Bool {
|
||||
guard let containingView = containingView else { return true }
|
||||
return isVisible(in: containingView)
|
||||
}
|
||||
|
||||
/// Checks if the video is visible in the passed in view
|
||||
open func isVisible(in view: UIView) -> Bool {
|
||||
return MVMCoreUIUtility.isView(self, visibleIn: view)
|
||||
}
|
||||
|
||||
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||
/// Detach the view from it's previous model before setting.
|
||||
(self.model as? VideoModel)?.view = nil
|
||||
containingView = (delegateObject?.moleculeDelegate as? UIViewController)?.view
|
||||
super.set(with: model, delegateObject, additionalData)
|
||||
|
||||
guard let model = model as? VideoModel else { return }
|
||||
if let controller = delegateObject?.moleculeDelegate as? UIViewController {
|
||||
controller.addChild(videoViewController)
|
||||
videoViewController.didMove(toParent: controller)
|
||||
}
|
||||
videoViewController.showsPlaybackControls = model.showControls
|
||||
videoViewController.player = model.videoDataManager.player
|
||||
addStateObserver()
|
||||
model.addVisibilityHalting(for: self, delegateObject: delegateObject)
|
||||
|
||||
switch (model.videoDataManager.videoState) {
|
||||
case .none:
|
||||
// Begin loading the video
|
||||
model.videoDataManager.loadVideo()
|
||||
case .loaded:
|
||||
guard isVisibleInDelegate() else { return }
|
||||
// Video loaded, unhalt it if necessary.
|
||||
model.halted = false
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
/// Listens and responds to video loading state changes.
|
||||
private func addStateObserver() {
|
||||
removeStateObserver()
|
||||
|
||||
guard stateKVOToken == nil,
|
||||
let model = model as? VideoModel else { return }
|
||||
|
||||
// To know when the video player item is done loading.
|
||||
stateKVOToken =
|
||||
model.videoDataManager.observe(\.videoState) { [weak self] (item, change) in
|
||||
guard let self = self,
|
||||
let model = self.model as? VideoModel,
|
||||
item == model.videoDataManager else { return }
|
||||
|
||||
switch item.videoState {
|
||||
case .loaded:
|
||||
// Setting videoController's player must be in the main thread
|
||||
MVMCoreDispatchUtility.performSyncBlock(onMainThread: {
|
||||
// Play the video
|
||||
self.videoViewController.player = item.player
|
||||
if !model.halted && model.autoPlay && self.isVisibleInDelegate() {
|
||||
item.player?.play()
|
||||
UIAccessibility.post(notification: .screenChanged, argument: self)
|
||||
}
|
||||
})
|
||||
case .failed:
|
||||
if let errorObject = item.loadFailedError {
|
||||
MVMCoreLoggingHandler.shared()?.addError(toLog: errorObject)
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func removeStateObserver() {
|
||||
stateKVOToken?.invalidate()
|
||||
stateKVOToken = nil
|
||||
}
|
||||
|
||||
deinit {
|
||||
removeStateObserver()
|
||||
}
|
||||
}
|
||||
141
MVMCoreUI/Atomic/Atoms/Views/VideoDataManager.swift
Normal file
141
MVMCoreUI/Atomic/Atoms/Views/VideoDataManager.swift
Normal file
@ -0,0 +1,141 @@
|
||||
//
|
||||
// VideoDataManager.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Scott Pfeil on 1/26/21.
|
||||
// Copyright © 2021 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import AVFoundation
|
||||
|
||||
@objcMembers open class VideoDataManager: NSObject {
|
||||
|
||||
/// The state of the video.
|
||||
@objc public enum VideoState: Int {
|
||||
case none
|
||||
case loading
|
||||
case loaded
|
||||
case failed
|
||||
}
|
||||
|
||||
public let videoURLString: String
|
||||
public var player: AVPlayer?
|
||||
|
||||
// Thread Safe video state handling.
|
||||
private var _videoState = VideoState.none
|
||||
private let videoStatueQueue = DispatchQueue(label: "com.vzw.mvmcoreui.videoDataManager.state", attributes: .concurrent)
|
||||
|
||||
/// The state of the video. Use KVO to listen for state changes.
|
||||
@objc public var videoState: VideoState {
|
||||
get {
|
||||
var state = VideoState.none
|
||||
videoStatueQueue.sync {
|
||||
state = _videoState
|
||||
}
|
||||
return state
|
||||
}
|
||||
set {
|
||||
willChangeValue(for: \.videoState)
|
||||
videoStatueQueue.async(flags: .barrier) {
|
||||
self._videoState = newValue
|
||||
}
|
||||
didChangeValue(for: \.videoState)
|
||||
}
|
||||
}
|
||||
|
||||
/// Set when the state is set to failed. Follows the same pattern as apple's AVPlayerItem
|
||||
public var loadFailedError: MVMCoreErrorObject?
|
||||
|
||||
private var kvoToken: NSKeyValueObservation?
|
||||
|
||||
private var memoryWarningListener: Any?
|
||||
|
||||
public init(with videoURLString: String) {
|
||||
self.videoURLString = videoURLString
|
||||
super.init()
|
||||
self.addMemoryWarningListener()
|
||||
}
|
||||
|
||||
public func loadVideo() {
|
||||
guard videoState != .loading else { return }
|
||||
removeVideoObserver()
|
||||
player = nil
|
||||
videoState = .loading
|
||||
|
||||
//Asset loading needs time, calling async method. by tracking asset's propety "duration", if we get the value of duration, we can treat asset load successfully.
|
||||
let tracksKey = "duration"
|
||||
MVMCoreCache.shared()?.playerAsset(fromFileName: videoURLString, trackKeys: [tracksKey], onComplete: { [weak self] (asset, fileName, errorObject) in
|
||||
guard let asset = asset else {
|
||||
self?.loadFailedError = errorObject
|
||||
self?.videoState = .failed
|
||||
return
|
||||
}
|
||||
|
||||
var error: NSError? = nil
|
||||
let tracksStatus = asset.statusOfValue(forKey: tracksKey, error: &error)
|
||||
switch tracksStatus {
|
||||
case .loaded:
|
||||
//When Assets load successfully, we create playerItem and add playerItem into AVPlayer
|
||||
self?.player = AVPlayer(playerItem: AVPlayerItem(asset: asset))
|
||||
self?.addObserverToPlayerItem()
|
||||
case .failed:
|
||||
//Asset load fail
|
||||
//Since checking asset status here, no need to check player.currenItem.asset's media tracks when play button is clicked anymore.
|
||||
if let error = error,
|
||||
let errorObject = MVMCoreErrorObject.createErrorObject(for: error, location: (asset as? AVURLAsset)?.url.absoluteString ?? self?.videoURLString) {
|
||||
self?.loadFailedError = errorObject
|
||||
}
|
||||
self?.videoState = .failed
|
||||
default:
|
||||
break
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private func addObserverToPlayerItem() {
|
||||
removeVideoObserver()
|
||||
|
||||
// To know when the video player item is done loading.
|
||||
guard kvoToken == nil else { return }
|
||||
kvoToken = player?.currentItem?.observe(\.status) { [weak self] (item, change) in
|
||||
guard item == self?.player?.currentItem else { return }
|
||||
switch item.status {
|
||||
case .readyToPlay:
|
||||
self?.videoState = .loaded
|
||||
case .failed:
|
||||
if let error = item.error,
|
||||
let errorObject = MVMCoreErrorObject.createErrorObject(for: error, location: (item.asset as? AVURLAsset)?.url.absoluteString ?? self?.videoURLString) {
|
||||
self?.loadFailedError = errorObject
|
||||
}
|
||||
self?.videoState = .failed
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func removeVideoObserver() {
|
||||
kvoToken?.invalidate()
|
||||
kvoToken = nil
|
||||
}
|
||||
|
||||
private func addMemoryWarningListener() {
|
||||
memoryWarningListener = NotificationCenter.default.addObserver(forName: UIApplication.didReceiveMemoryWarningNotification, object: nil, queue: OperationQueue.main) { [weak self] (notification) in
|
||||
self?.removeVideoObserver()
|
||||
self?.player = nil
|
||||
self?.videoState = .none
|
||||
}
|
||||
}
|
||||
|
||||
private func removeMemoryWarningListener() {
|
||||
guard let observer = memoryWarningListener else { return }
|
||||
NotificationCenter.default.removeObserver(observer)
|
||||
memoryWarningListener = nil
|
||||
}
|
||||
|
||||
deinit {
|
||||
removeVideoObserver()
|
||||
removeMemoryWarningListener()
|
||||
}
|
||||
}
|
||||
167
MVMCoreUI/Atomic/Atoms/Views/VideoModel.swift
Normal file
167
MVMCoreUI/Atomic/Atoms/Views/VideoModel.swift
Normal file
@ -0,0 +1,167 @@
|
||||
//
|
||||
// VideoModel.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Scott Pfeil on 1/26/21.
|
||||
// Copyright © 2021 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
open class VideoModel: MoleculeModelProtocol {
|
||||
public static var identifier = "video"
|
||||
public var backgroundColor: Color?
|
||||
public var video: String
|
||||
public var showControls = false
|
||||
public var autoPlay = true
|
||||
public var alwaysReset = false
|
||||
weak public var view: Video?
|
||||
|
||||
/// When the video is halted because it is no longer visible
|
||||
public var halted: Bool = false {
|
||||
didSet {
|
||||
guard halted != oldValue,
|
||||
videoDataManager.videoState == .loaded else { return }
|
||||
if halted {
|
||||
videoDataManager.player?.pause()
|
||||
} else {
|
||||
if alwaysReset {
|
||||
// Always start video at the beginning.
|
||||
videoDataManager.player?.seek(to: .zero)
|
||||
}
|
||||
if autoPlay {
|
||||
videoDataManager.player?.play()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Keeps a reference to the video data.
|
||||
public var videoDataManager: VideoDataManager
|
||||
|
||||
private weak var visibleBehavior: PageVisibilityClosureBehavior?
|
||||
private weak var scrollBehavior: PageScrolledClosureBehavior?
|
||||
private var activeListener: Any?
|
||||
private var resignActiveListener: Any?
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case moleculeName
|
||||
case video
|
||||
case showControls
|
||||
case autoPlay
|
||||
case alwaysReset
|
||||
}
|
||||
|
||||
public init(_ video: String) {
|
||||
self.video = video
|
||||
videoDataManager = VideoDataManager(with: video)
|
||||
}
|
||||
|
||||
required public init(from decoder: Decoder) throws {
|
||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||
video = try typeContainer.decode(String.self, forKey:.video)
|
||||
if let showControls = try typeContainer.decodeIfPresent(Bool.self, forKey: .showControls) {
|
||||
self.showControls = showControls
|
||||
}
|
||||
if let autoPlay = try typeContainer.decodeIfPresent(Bool.self, forKey: .autoPlay) {
|
||||
self.autoPlay = autoPlay
|
||||
}
|
||||
if let alwaysReset = try typeContainer.decodeIfPresent(Bool.self, forKey: .alwaysReset) {
|
||||
self.alwaysReset = alwaysReset
|
||||
}
|
||||
videoDataManager = VideoDataManager(with: video)
|
||||
}
|
||||
|
||||
open func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(moleculeName, forKey: .moleculeName)
|
||||
try container.encode(video, forKey: .video)
|
||||
try container.encode(showControls, forKey: .showControls)
|
||||
try container.encode(autoPlay, forKey: .autoPlay)
|
||||
try container.encode(alwaysReset, forKey: .alwaysReset)
|
||||
}
|
||||
|
||||
open func addVisibilityHalting(for view: Video, delegateObject: MVMCoreUIDelegateObject?) {
|
||||
self.view = view
|
||||
halted = false
|
||||
addVisibleBehavior(for: view, delegateObject: delegateObject)
|
||||
addScrollBehavior(for: view, delegateObject: delegateObject)
|
||||
addActiveListener(for: view, delegateObject: delegateObject)
|
||||
}
|
||||
|
||||
/// Adds a behavior to pause the video on page hidden behavior and unpause if necessary on page shown.
|
||||
open func addVisibleBehavior(for view: Video, delegateObject: MVMCoreUIDelegateObject?) {
|
||||
|
||||
let onShow = { [weak self] in
|
||||
guard let self = self,
|
||||
let view = self.view,
|
||||
view.isVisibleInDelegate() else { return }
|
||||
self.halted = false
|
||||
}
|
||||
let onHide: () -> Void = { [weak self] in
|
||||
self?.halted = true
|
||||
}
|
||||
|
||||
guard visibleBehavior == nil else {
|
||||
visibleBehavior?.pageShownHandler = onShow
|
||||
visibleBehavior?.pageHiddenHandler = onHide
|
||||
return
|
||||
}
|
||||
|
||||
guard var delegate = delegateObject?.behaviorTemplateDelegate else { return }
|
||||
let pauseBehavior = PageVisibilityClosureBehavior(with: onShow, onPageHiddenHandler: onHide)
|
||||
delegate.add(behavior: pauseBehavior)
|
||||
self.visibleBehavior = pauseBehavior
|
||||
}
|
||||
|
||||
/// Adds a behavior to pause the video if scrolled off of the page and unpause if necessary if scrolled on.
|
||||
open func addScrollBehavior(for view: Video, delegateObject: MVMCoreUIDelegateObject?) {
|
||||
|
||||
let onScroll = { [weak self] (scrollView: UIScrollView) in
|
||||
// If visible to not visible, pause video.
|
||||
// If not visible to visible, unpause if needed, add visible behavior
|
||||
guard let self = self,
|
||||
let view = self.view else { return }
|
||||
self.halted = !view.isVisible(in: scrollView)
|
||||
}
|
||||
|
||||
guard scrollBehavior == nil else {
|
||||
scrollBehavior?.pageScrolledHandler = onScroll
|
||||
return
|
||||
}
|
||||
|
||||
guard var delegate = delegateObject?.behaviorTemplateDelegate else { return }
|
||||
let scrollBehavior = PageScrolledClosureBehavior(with: onScroll)
|
||||
delegate.add(behavior: scrollBehavior)
|
||||
self.scrollBehavior = scrollBehavior
|
||||
}
|
||||
|
||||
open func addActiveListener(for view: Video, delegateObject: MVMCoreUIDelegateObject?) {
|
||||
removeActiveListener()
|
||||
|
||||
resignActiveListener = NotificationCenter.default.addObserver(forName: UIApplication.willResignActiveNotification, object: nil, queue: OperationQueue.main) { [weak self] (notification) in
|
||||
self?.halted = true
|
||||
}
|
||||
activeListener = NotificationCenter.default.addObserver(forName: UIApplication.didBecomeActiveNotification, object: nil, queue: OperationQueue.main) { [weak self] (notification) in
|
||||
guard let self = self,
|
||||
let view = self.view,
|
||||
view.isVisibleInDelegate() else { return }
|
||||
self.halted = false
|
||||
}
|
||||
}
|
||||
|
||||
private func removeActiveListener() {
|
||||
if let observer = activeListener {
|
||||
NotificationCenter.default.removeObserver(observer)
|
||||
activeListener = nil
|
||||
}
|
||||
if let observer = resignActiveListener {
|
||||
NotificationCenter.default.removeObserver(observer)
|
||||
resignActiveListener = nil
|
||||
}
|
||||
}
|
||||
|
||||
deinit {
|
||||
removeActiveListener()
|
||||
}
|
||||
}
|
||||
@ -79,6 +79,7 @@ import Foundation
|
||||
MoleculeObjectMapping.shared()?.register(viewClass: DigitEntryField.self, viewModelClass: DigitEntryFieldModel.self)
|
||||
MoleculeObjectMapping.shared()?.register(viewClass: ItemDropdownEntryField.self, viewModelClass: ItemDropdownEntryFieldModel.self)
|
||||
MoleculeObjectMapping.shared()?.register(viewClass: DateDropdownEntryField.self, viewModelClass: DateDropdownEntryFieldModel.self)
|
||||
MoleculeObjectMapping.shared()?.register(viewClass: MultiItemDropdownEntryField.self, viewModelClass: MultiItemDropdownEntryFieldModel.self)
|
||||
|
||||
// MARK:- Selectors
|
||||
MoleculeObjectMapping.shared()?.register(viewClass: RadioButton.self, viewModelClass: RadioButtonModel.self)
|
||||
@ -106,6 +107,7 @@ import Foundation
|
||||
MoleculeObjectMapping.shared()?.register(viewClass: RadioButtonLabel.self, viewModelClass: RadioButtonLabelModel.self)
|
||||
MoleculeObjectMapping.shared()?.register(viewClass: WebView.self, viewModelClass: WebViewModel.self)
|
||||
MoleculeObjectMapping.shared()?.register(viewClass: LoadingSpinner.self, viewModelClass: LoadingSpinnerModel.self)
|
||||
MoleculeObjectMapping.shared()?.register(viewClass: Video.self, viewModelClass: VideoModel.self)
|
||||
|
||||
// MARK:- Horizontal Combination Molecules
|
||||
MoleculeObjectMapping.shared()?.register(viewClass: StringAndMoleculeView.self, viewModelClass: StringAndMoleculeModel.self)
|
||||
@ -151,6 +153,7 @@ import Foundation
|
||||
MoleculeObjectMapping.shared()?.register(viewClass: Scroller.self, viewModelClass: ScrollerModel.self)
|
||||
MoleculeObjectMapping.shared()?.register(viewClass: ModuleMolecule.self, viewModelClass: ModuleMoleculeModel.self)
|
||||
MoleculeObjectMapping.shared()?.register(viewClass: BGImageMolecule.self, viewModelClass: BGImageMoleculeModel.self)
|
||||
MoleculeObjectMapping.shared()?.register(viewClass: BGVideoImageMolecule.self, viewModelClass: BGVideoImageMoleculeModel.self)
|
||||
MoleculeObjectMapping.shared()?.register(viewClass: MoleculeSectionHeader.self, viewModelClass: MoleculeSectionHeaderModel.self)
|
||||
MoleculeObjectMapping.shared()?.register(viewClass: MoleculeSectionFooter.self, viewModelClass: MoleculeSectionFooterModel.self)
|
||||
|
||||
@ -259,6 +262,7 @@ import Foundation
|
||||
try? ModelRegistry.register(ActionTopAlertModel.self)
|
||||
try? ModelRegistry.register(ActionCollapseNotificationModel.self)
|
||||
try? ModelRegistry.register(ActionOpenPanelModel.self)
|
||||
try? ModelRegistry.register(ActionTopNotificationModel.self)
|
||||
|
||||
// MARK:- Behaviors
|
||||
try? ModelRegistry.register(ScreenBrightnessModifierBehavior.self)
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
// MARK: - Outlets
|
||||
//--------------------------------------------------
|
||||
|
||||
public let leftImage = LoadImageView()
|
||||
public let leftImage = LoadImageView(pinnedEdges: .all)
|
||||
public let eyebrowHeadlineBodyLink = EyebrowHeadlineBodyLink()
|
||||
public let rightLabel = Label(fontStyle: .RegularBodySmall)
|
||||
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
// MARK: - Outlets
|
||||
//--------------------------------------------------
|
||||
|
||||
public let leftImage = LoadImageView()
|
||||
public let leftImage = LoadImageView(pinnedEdges: .all)
|
||||
public let headlineBody = HeadlineBody()
|
||||
public let rightLabel = Label(fontStyle: .RegularBodySmall)
|
||||
public let rightLabelStackItem: StackItem
|
||||
|
||||
@ -21,7 +21,8 @@
|
||||
//--------------------------------------------------
|
||||
|
||||
public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
|
||||
stack = Stack<StackModel>.createStack(with: [(view: eyebrowHeadlineBodyLink, model: StackItemModel(horizontalAlignment: .leading, verticalAlignment: .top)), (view: rightLabel, model: StackItemModel(horizontalAlignment:.fill))], axis: .horizontal)
|
||||
// Fill for left vertical alignment because bottom constraint was breaking with leading. CXTDT-145456
|
||||
stack = Stack<StackModel>.createStack(with: [(view: eyebrowHeadlineBodyLink, model: StackItemModel(horizontalAlignment: .leading, verticalAlignment: .fill)), (view: rightLabel, model: StackItemModel(horizontalAlignment:.fill, verticalAlignment: .leading))], axis: .horizontal)
|
||||
super.init(style: style, reuseIdentifier: reuseIdentifier)
|
||||
}
|
||||
|
||||
@ -47,7 +48,7 @@
|
||||
if let heroCenter = heroCenter,
|
||||
let stackItem = stack.stackItems.last as? StackItem {
|
||||
let convertedPoint = stack.convert(heroCenter, from: self)
|
||||
stackItem.containerHelper.alignCenterVerticalConstraint?.constant = convertedPoint.y - stack.bounds.midY
|
||||
stackItem.containerHelper.topConstraint?.constant = max(convertedPoint.y - rightLabel.bounds.midY, 0.0)
|
||||
}
|
||||
|
||||
return heroCenter
|
||||
@ -61,7 +62,6 @@
|
||||
super.set(with: model, delegateObject, additionalData)
|
||||
|
||||
guard let model = model as? ListRightVariableRightCaretAllTextAndLinksModel else { return }
|
||||
|
||||
rightLabel.set(with: model.rightLabel, delegateObject, additionalData)
|
||||
eyebrowHeadlineBodyLink.set(with: model.eyebrowHeadlineBodyLink, delegateObject, additionalData)
|
||||
updateAccessibilityLabel()
|
||||
|
||||
@ -6,7 +6,6 @@
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
open class HeaderView: Container {
|
||||
public let line = Line()
|
||||
@ -15,7 +14,7 @@ open class HeaderView: Container {
|
||||
open var molecule: MoleculeViewProtocol?
|
||||
|
||||
var headerModel: HeaderModel? {
|
||||
get { return model as? HeaderModel }
|
||||
get { model as? HeaderModel }
|
||||
}
|
||||
|
||||
/// Convenience function to add a molecule to the view.
|
||||
@ -64,6 +63,6 @@ open class HeaderView: Container {
|
||||
}
|
||||
|
||||
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
|
||||
return PaddingDefaultVerticalSpacing + PaddingDefaultVerticalSpacing
|
||||
PaddingDefaultVerticalSpacing + PaddingDefaultVerticalSpacing
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,7 +6,6 @@
|
||||
// Copyright © 2019 Suresh, Kamlesh. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@objcMembers public class MoleculeHeaderModel: HeaderModel, MoleculeModelProtocol, MoleculeContainerModelProtocol {
|
||||
public static var identifier: String = "header"
|
||||
|
||||
@ -17,7 +17,7 @@ public class MoleculeHeaderView: MoleculeContainer {
|
||||
var line = Line()
|
||||
|
||||
var headerModel: MoleculeHeaderModel? {
|
||||
get { return model as? MoleculeHeaderModel }
|
||||
get { model as? MoleculeHeaderModel }
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
|
||||
@ -6,7 +6,6 @@
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@objcMembers open class TabBar: UITabBar, MoleculeViewProtocol, TabBarProtocol, UITabBarDelegate {
|
||||
|
||||
@ -15,9 +14,7 @@ import Foundation
|
||||
public let line = Line()
|
||||
|
||||
required public init(model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||
guard let model = model as? TabBarModel else {
|
||||
fatalError("model is not TabBarModel")
|
||||
}
|
||||
guard let model = model as? TabBarModel else { fatalError("model is not TabBarModel") }
|
||||
self.model = model
|
||||
super.init(frame: .zero)
|
||||
|
||||
@ -32,7 +29,7 @@ import Foundation
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
open func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) {
|
||||
open func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||
guard let model = model as? TabBarModel else { return }
|
||||
self.model = model
|
||||
|
||||
@ -57,8 +54,12 @@ import Foundation
|
||||
var tabs: [UITabBarItem] = []
|
||||
for (index, tab) in model.tabs.enumerated() {
|
||||
let tabBarItem = UITabBarItem(title: tab.title, image: MVMCoreCache.shared()?.getImageFromRegisteredBundles(tab.image), tag: index)
|
||||
tabBarItem.titlePositionAdjustment = UIOffset(horizontal: 0, vertical: -3)
|
||||
tabBarItem.setTitleTextAttributes([NSAttributedString.Key.font: MFFonts.mfFontTXRegular(8)], for: .normal)
|
||||
tabBarItem.accessibilityLabel = tab.accessibilityText
|
||||
if #available(iOS 13.0, *) {
|
||||
} else {
|
||||
tabBarItem.titlePositionAdjustment = UIOffset(horizontal: 0, vertical: -3)
|
||||
tabBarItem.setTitleTextAttributes([NSAttributedString.Key.font: MFFonts.mfFontTXRegular(8)], for: .normal)
|
||||
}
|
||||
tabs.append(tabBarItem)
|
||||
}
|
||||
setItems(tabs, animated: false)
|
||||
@ -100,10 +101,7 @@ import Foundation
|
||||
})
|
||||
}
|
||||
|
||||
public func currentTabIndex() -> Int {
|
||||
return model.selectedTab
|
||||
}
|
||||
public func currentTabIndex() -> Int { model.selectedTab }
|
||||
}
|
||||
|
||||
extension UITabBarItem: MFButtonProtocol {
|
||||
}
|
||||
extension UITabBarItem: MFButtonProtocol { }
|
||||
|
||||
@ -60,17 +60,19 @@ public class TabBarModel: MoleculeModelProtocol {
|
||||
}
|
||||
|
||||
public class TabBarItemModel: Codable {
|
||||
var title: String
|
||||
var title: String?
|
||||
var image: String
|
||||
var action: ActionModelProtocol
|
||||
var accessibilityText: String?
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case title
|
||||
case image
|
||||
case action
|
||||
case accessibilityText
|
||||
}
|
||||
|
||||
public init(with title: String, image: String, action: ActionModelProtocol) {
|
||||
public init(with title: String?, image: String, action: ActionModelProtocol) {
|
||||
self.title = title
|
||||
self.image = image
|
||||
self.action = action
|
||||
@ -78,15 +80,17 @@ public class TabBarItemModel: Codable {
|
||||
|
||||
required public init(from decoder: Decoder) throws {
|
||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||
title = try typeContainer.decode(String.self, forKey: .title)
|
||||
title = try typeContainer.decodeIfPresent(String.self, forKey: .title)
|
||||
image = try typeContainer.decode(String.self, forKey: .image)
|
||||
action = try typeContainer.decodeModel(codingKey: .action)
|
||||
accessibilityText = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityText)
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(title, forKey: .title)
|
||||
try container.encodeIfPresent(title, forKey: .title)
|
||||
try container.encode(image, forKey: .image)
|
||||
try container.encodeModel(action, forKey: .action)
|
||||
try container.encodeIfPresent(accessibilityText, forKey: .accessibilityText)
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,12 +9,12 @@
|
||||
import Foundation
|
||||
|
||||
|
||||
@objcMembers public class CarouselItemModel: MoleculeCollectionItemModel, CarouselItemModelProtocol {
|
||||
@objcMembers open class CarouselItemModel: MoleculeCollectionItemModel, CarouselItemModelProtocol {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
public override class var identifier: String {
|
||||
open override class var identifier: String {
|
||||
return "carouselItem"
|
||||
}
|
||||
|
||||
@ -44,7 +44,7 @@ import Foundation
|
||||
try super.init(from: decoder)
|
||||
}
|
||||
|
||||
public override func encode(to encoder: Encoder) throws {
|
||||
open override func encode(to encoder: Encoder) throws {
|
||||
try super.encode(to: encoder)
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encodeIfPresent(peakingUI, forKey: .peakingUI)
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
import Foundation
|
||||
|
||||
/// A model for a collection item that is a container for any molecule.
|
||||
@objcMembers public class MoleculeCollectionItemModel: MoleculeContainerModel, CollectionItemModelProtocol {
|
||||
@objcMembers open class MoleculeCollectionItemModel: MoleculeContainerModel, CollectionItemModelProtocol {
|
||||
open override class var identifier: String {
|
||||
return "collectionItem"
|
||||
}
|
||||
|
||||
@ -6,17 +6,15 @@
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@objcMembers open class ImageBarButtonItem: BarButtonItem {
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializers
|
||||
//--------------------------------------------------
|
||||
|
||||
public static func create(with image: UIImage?) -> Self {
|
||||
let actionObject = ActionDelegate()
|
||||
let button = self.init(image: image, style: .plain, target: actionObject, action: #selector(actionObject.callActionBlock(_:)))
|
||||
let button = self.init(image: image, style: .plain, target: actionObject, action: #selector(actionObject.callActionBlock))
|
||||
button.actionDelegate = actionObject
|
||||
return button
|
||||
}
|
||||
@ -29,7 +27,7 @@ import Foundation
|
||||
}
|
||||
|
||||
/// Creates the item with the passed in action map.
|
||||
public static func create(with image: UIImage?, actionMap: [AnyHashable : Any], delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> Self {
|
||||
public static func create(with image: UIImage?, actionMap: [AnyHashable: Any], delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> Self {
|
||||
let button = create(with: image)
|
||||
button.set(with: actionMap, delegateObject: delegateObject, additionalData: additionalData)
|
||||
return button
|
||||
@ -42,4 +40,3 @@ import Foundation
|
||||
return button
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -6,10 +6,8 @@
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@objcMembers open class LabelBarButtonItem: BarButtonItem {
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializers
|
||||
//--------------------------------------------------
|
||||
|
||||
@ -5,30 +5,47 @@
|
||||
// Created by Scott Pfeil on 5/18/20.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public class NavigationImageButtonModel: NavigationButtonModelProtocol, MoleculeModelProtocol {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
public var backgroundColor: Color?
|
||||
public var accessibilityIdentifier: String?
|
||||
public static var identifier: String = "navigationImageButton"
|
||||
|
||||
public var image: String
|
||||
public var action: ActionModelProtocol
|
||||
public var accessibilityText: String?
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializer
|
||||
//--------------------------------------------------
|
||||
|
||||
public init(with image: String, action: ActionModelProtocol) {
|
||||
self.image = image
|
||||
self.action = action
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Coding Keys
|
||||
//--------------------------------------------------
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case image
|
||||
case action
|
||||
case accessibilityIdentifier
|
||||
case moleculeName
|
||||
case accessibilityText
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Codec
|
||||
//--------------------------------------------------
|
||||
|
||||
required public init(from decoder: Decoder) throws {
|
||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||
accessibilityIdentifier = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityIdentifier)
|
||||
image = try typeContainer.decode(String.self, forKey: .image)
|
||||
action = try typeContainer.decodeModel(codingKey: .action)
|
||||
accessibilityText = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityText)
|
||||
@ -37,19 +54,26 @@ public class NavigationImageButtonModel: NavigationButtonModelProtocol, Molecule
|
||||
open func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(image, forKey: .image)
|
||||
try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier)
|
||||
try container.encode(moleculeName, forKey: .moleculeName)
|
||||
try container.encodeModel(action, forKey: .action)
|
||||
try container.encodeIfPresent(accessibilityText, forKey: .accessibilityText)
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Method
|
||||
//--------------------------------------------------
|
||||
|
||||
/// Convenience function that creates a BarButtonItem for the model.
|
||||
public func createNavigationItemButton(delegateObject: MVMCoreUIDelegateObject? = nil, additionalData: [AnyHashable: Any]? = nil) -> UIBarButtonItem {
|
||||
let uiImage = MVMCoreCache.shared()?.getImageFromRegisteredBundles(image)
|
||||
let navigationImageButton = ImageBarButtonItem.create(with: uiImage, actionModel: action, delegateObject: delegateObject, additionalData: additionalData)
|
||||
let buttonItem = ImageBarButtonItem.create(with: uiImage, actionModel: action, delegateObject: delegateObject, additionalData: additionalData)
|
||||
buttonItem.accessibilityIdentifier = accessibilityIdentifier ?? image
|
||||
if let accessibilityString = accessibilityText {
|
||||
navigationImageButton.accessibilityLabel = accessibilityString
|
||||
navigationImageButton.isAccessibilityElement = true
|
||||
buttonItem.accessibilityLabel = accessibilityString
|
||||
buttonItem.isAccessibilityElement = true
|
||||
}
|
||||
return navigationImageButton
|
||||
|
||||
return buttonItem
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,28 +6,45 @@
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public class NavigationLabelButtonModel: NavigationButtonModelProtocol, MoleculeModelProtocol {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
public var backgroundColor: Color?
|
||||
public static var identifier: String = "navigationLabelButton"
|
||||
|
||||
public var accessibilityIdentifier: String?
|
||||
public var title: String
|
||||
public var action: ActionModelProtocol
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializer
|
||||
//--------------------------------------------------
|
||||
|
||||
public init(with title: String, action: ActionModelProtocol) {
|
||||
self.title = title
|
||||
self.action = action
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Keys
|
||||
//--------------------------------------------------
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case moleculeName
|
||||
case accessibilityIdentifier
|
||||
case title
|
||||
case action
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Codec
|
||||
//--------------------------------------------------
|
||||
|
||||
required public init(from decoder: Decoder) throws {
|
||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||
accessibilityIdentifier = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityIdentifier)
|
||||
title = try typeContainer.decode(String.self, forKey: .title)
|
||||
action = try typeContainer.decodeModel(codingKey: .action)
|
||||
}
|
||||
@ -35,10 +52,15 @@ public class NavigationLabelButtonModel: NavigationButtonModelProtocol, Molecule
|
||||
open func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(moleculeName, forKey: .moleculeName)
|
||||
try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier)
|
||||
try container.encode(title, forKey: .title)
|
||||
try container.encodeModel(action, forKey: .action)
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Methods
|
||||
//--------------------------------------------------
|
||||
|
||||
/// Convenience function that creates a BarButtonItem for the model.
|
||||
public func createNavigationItemButton(delegateObject: MVMCoreUIDelegateObject? = nil, additionalData: [AnyHashable: Any]? = nil) -> UIBarButtonItem {
|
||||
return LabelBarButtonItem.create(with: title, actionModel: action, delegateObject: delegateObject, additionalData: additionalData)
|
||||
|
||||
@ -6,12 +6,13 @@
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
open class NavigationItemModel: NavigationItemModelProtocol, MoleculeModelProtocol {
|
||||
open class var identifier: String {
|
||||
return "navigationBar"
|
||||
}
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
open class var identifier: String { "navigationBar" }
|
||||
|
||||
open var title: String?
|
||||
open var hidden: Bool
|
||||
@ -28,13 +29,21 @@ open class NavigationItemModel: NavigationItemModelProtocol, MoleculeModelProtoc
|
||||
open var additionalRightButtons: [(NavigationButtonModelProtocol & MoleculeModelProtocol)]?
|
||||
open var titleView: MoleculeModelProtocol?
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializer
|
||||
//--------------------------------------------------
|
||||
|
||||
public init() {
|
||||
hidden = false
|
||||
backgroundColor = Color(uiColor: .white)
|
||||
tintColor = Color(uiColor: .black)
|
||||
backgroundColor = Color(uiColor: .mvmWhite)
|
||||
tintColor = Color(uiColor: .mvmBlack)
|
||||
line = LineModel(type: .standard)
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Keys
|
||||
//--------------------------------------------------
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case moleculeName
|
||||
case title
|
||||
@ -48,13 +57,17 @@ open class NavigationItemModel: NavigationItemModelProtocol, MoleculeModelProtoc
|
||||
case additionalRightButtons
|
||||
case titleView
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Codec
|
||||
//--------------------------------------------------
|
||||
|
||||
required public init(from decoder: Decoder) throws {
|
||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||
title = try typeContainer.decodeIfPresent(String.self, forKey: .title)
|
||||
hidden = try typeContainer.decodeIfPresent(Bool.self, forKey: .hidden) ?? false
|
||||
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) ?? Color(uiColor: .white)
|
||||
tintColor = try typeContainer.decodeIfPresent(Color.self, forKey: .tintColor) ?? Color(uiColor: .black)
|
||||
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) ?? Color(uiColor: .mvmWhite)
|
||||
tintColor = try typeContainer.decodeIfPresent(Color.self, forKey: .tintColor) ?? Color(uiColor: .mvmBlack)
|
||||
line = try typeContainer.decodeIfPresent(LineModel.self, forKey: .line) ?? LineModel(type: .standard)
|
||||
alwaysShowBackButton = try typeContainer.decodeIfPresent(Bool.self, forKey: .alwaysShowBackButton)
|
||||
backButton = try typeContainer.decodeModelIfPresent(codingKey: .backButton)
|
||||
|
||||
@ -27,6 +27,12 @@ open class BGImageMoleculeModel: MoleculeContainerModel {
|
||||
if bottomPadding == nil {
|
||||
bottomPadding = PaddingDefaultVerticalSpacing3
|
||||
}
|
||||
if image.contentMode == nil {
|
||||
image.contentMode = .scaleAspectFill
|
||||
}
|
||||
if image.imageFormat == nil {
|
||||
image.imageFormat = "jpg"
|
||||
}
|
||||
}
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
|
||||
@ -0,0 +1,98 @@
|
||||
//
|
||||
// BGVideoImageMolecule.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Scott Pfeil on 1/26/21.
|
||||
// Copyright © 2021 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
open class BGVideoImageMolecule: BGImageMolecule {
|
||||
|
||||
public let video = Video()
|
||||
|
||||
/// Used to hide video after loaded.
|
||||
private var stateKVOToken: NSKeyValueObservation?
|
||||
private var endObserver: NSObjectProtocol?
|
||||
|
||||
open override func setupView() {
|
||||
super.setupView()
|
||||
insertSubview(video, aboveSubview: image)
|
||||
NSLayoutConstraint.constraintPinSubview(toSuperview: video)
|
||||
}
|
||||
|
||||
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||
super.set(with: model, delegateObject, additionalData)
|
||||
guard let model = model as? BGVideoImageMoleculeModel else { return }
|
||||
video.set(with: model.video, delegateObject, additionalData)
|
||||
video.isHidden = shouldVideoBeHidden()
|
||||
addStateObserver()
|
||||
}
|
||||
|
||||
open func shouldVideoBeHidden() -> Bool {
|
||||
guard let model = model as? BGVideoImageMoleculeModel,
|
||||
model.video.videoDataManager.videoState != .failed else {
|
||||
return true
|
||||
}
|
||||
guard model.video.videoDataManager.videoState == .loaded,
|
||||
let player = model.video.videoDataManager.player,
|
||||
let item = player.currentItem,
|
||||
item.currentTime() == item.duration else {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
/// Listens and responds to video loading state changes to add the end observer.
|
||||
private func addStateObserver() {
|
||||
removeStateObserver()
|
||||
|
||||
guard stateKVOToken == nil,
|
||||
let model = model as? BGVideoImageMoleculeModel else { return }
|
||||
|
||||
// To know when the video player item is done loading.
|
||||
stateKVOToken =
|
||||
model.video.videoDataManager.observe(\.videoState) { [weak self] (item, change) in
|
||||
guard let self = self,
|
||||
let model = self.model as? BGVideoImageMoleculeModel,
|
||||
item == model.video.videoDataManager else { return }
|
||||
|
||||
switch item.videoState {
|
||||
case .loaded:
|
||||
self.addEndObserver()
|
||||
case .failed:
|
||||
MVMCoreDispatchUtility.performBlock(onMainThread: {
|
||||
self.video.isHidden = true
|
||||
})
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func removeStateObserver() {
|
||||
stateKVOToken?.invalidate()
|
||||
stateKVOToken = nil
|
||||
}
|
||||
|
||||
private func addEndObserver() {
|
||||
removeStateObserver()
|
||||
guard let model = model as? BGVideoImageMoleculeModel,
|
||||
let item = model.video.videoDataManager.player?.currentItem else { return }
|
||||
endObserver = NotificationCenter.default.addObserver(forName: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: item, queue: OperationQueue.main) { [weak self] (notification) in
|
||||
self?.video.isHidden = true
|
||||
}
|
||||
}
|
||||
|
||||
private func removeEndObserver() {
|
||||
guard let endObserver = endObserver else { return }
|
||||
NotificationCenter.default.removeObserver(endObserver)
|
||||
self.endObserver = nil
|
||||
}
|
||||
|
||||
deinit {
|
||||
removeStateObserver()
|
||||
removeEndObserver()
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
//
|
||||
// BGVideoImageMoleculeModel.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Scott Pfeil on 1/26/21.
|
||||
// Copyright © 2021 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
open class BGVideoImageMoleculeModel: BGImageMoleculeModel {
|
||||
open override class var identifier: String {
|
||||
return "bgVideoImageContainer"
|
||||
}
|
||||
|
||||
public var video: VideoModel
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case video
|
||||
}
|
||||
|
||||
public init(_ video: VideoModel, image: ImageViewModel, molecule: MoleculeModelProtocol) {
|
||||
self.video = video
|
||||
super.init(image, molecule: molecule)
|
||||
}
|
||||
|
||||
required public init(from decoder: Decoder) throws {
|
||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||
video = try typeContainer.decode(VideoModel.self, forKey:.video)
|
||||
try super.init(from: decoder)
|
||||
}
|
||||
|
||||
open override func encode(to encoder: Encoder) throws {
|
||||
try super.encode(to: encoder)
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(video, forKey: .video)
|
||||
}
|
||||
}
|
||||
@ -6,11 +6,10 @@
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
extension MVMCoreUITopAlertExpandableView: MoleculeViewProtocol {
|
||||
|
||||
public func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) {
|
||||
public func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||
defaultSetup()
|
||||
guard let model = model as? CollapsableNotificationModel else { return }
|
||||
backgroundColor = model.backgroundColor?.uiColor ?? .mvmGreen
|
||||
@ -30,6 +29,10 @@ extension MVMCoreUITopAlertExpandableView: MoleculeViewProtocol {
|
||||
MVMCoreUITopAlertBaseView.addAction(to: button, actionMap: topActionMap, additionalData: nil)
|
||||
shortView?.label?.accessibilityTraits = .button
|
||||
}
|
||||
|
||||
if let accessibilityIdentifier = model.accessibilityIdentifier {
|
||||
self.accessibilityIdentifier = accessibilityIdentifier
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -6,17 +6,24 @@
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
extension MVMCoreUITopAlertMainView: MoleculeViewProtocol {
|
||||
public func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) {
|
||||
|
||||
public func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||
defaultSetup()
|
||||
guard let model = model as? NotificationModel else { return }
|
||||
|
||||
backgroundColor = model.backgroundColor?.uiColor ?? .mvmGreen
|
||||
var actionMap = model.button?.action.toJSON()
|
||||
|
||||
if let title = model.button?.title {
|
||||
actionMap?.updateValue(title, forKey: KeyTitle)
|
||||
}
|
||||
|
||||
if let accessibilityIdentifier = model.accessibilityIdentifier {
|
||||
self.accessibilityIdentifier = accessibilityIdentifier
|
||||
}
|
||||
|
||||
setupCloseButton(model.closeButton != nil, animationDelegate: MVMCoreUITopAlertView.sharedGlobal()?.animationDelegate)
|
||||
setup(withMessage: model.headline.text, subMessage: model.body?.text, color: model.headline.textColor?.uiColor ?? .white, actionMap: actionMap, additionalData: nil)
|
||||
}
|
||||
|
||||
@ -6,52 +6,72 @@
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
open class NotificationModel: MoleculeModelProtocol {
|
||||
public class var identifier: String {
|
||||
return "notification"
|
||||
}
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
public class var identifier: String { "notification" }
|
||||
public var accessibilityIdentifier: String?
|
||||
public var backgroundColor: Color?
|
||||
public var headline: LabelModel
|
||||
public var body: LabelModel?
|
||||
public var button: ButtonModel?
|
||||
public var closeButton: NotificationXButtonModel?
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializer
|
||||
//--------------------------------------------------
|
||||
|
||||
public init(with headline: LabelModel) {
|
||||
self.headline = headline
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Default
|
||||
//--------------------------------------------------
|
||||
|
||||
open func setDefault() {
|
||||
if backgroundColor == nil {
|
||||
backgroundColor = Color(uiColor: .mvmGreen())
|
||||
backgroundColor = Color(uiColor: .mvmGreen)
|
||||
}
|
||||
if headline.textColor == nil {
|
||||
headline.textColor = Color(uiColor: .white)
|
||||
headline.textColor = Color(uiColor: .mvmWhite)
|
||||
}
|
||||
if body?.textColor == nil {
|
||||
body?.textColor = Color(uiColor: .white)
|
||||
body?.textColor = Color(uiColor: .mvmWhite)
|
||||
}
|
||||
if button?.style == nil {
|
||||
button?.style = .secondary
|
||||
}
|
||||
button?.size = .tiny
|
||||
button?.enabledTextColor = Color(uiColor: .white)
|
||||
button?.enabledBorderColor = Color(uiColor: .white)
|
||||
button?.enabledTextColor = Color(uiColor: .mvmWhite)
|
||||
button?.enabledBorderColor = Color(uiColor: .mvmWhite)
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Coding Keys
|
||||
//--------------------------------------------------
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case moleculeName
|
||||
case backgroundColor
|
||||
case accessibilityIdentifier
|
||||
case headline
|
||||
case body
|
||||
case button
|
||||
case closeButton
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Codec
|
||||
//--------------------------------------------------
|
||||
|
||||
required public init(from decoder: Decoder) throws {
|
||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
|
||||
accessibilityIdentifier = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityIdentifier)
|
||||
headline = try typeContainer.decode(LabelModel.self, forKey: .headline)
|
||||
body = try typeContainer.decodeIfPresent(LabelModel.self, forKey: .body)
|
||||
button = try typeContainer.decodeIfPresent(ButtonModel.self, forKey: .button)
|
||||
@ -63,6 +83,7 @@ open class NotificationModel: MoleculeModelProtocol {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(moleculeName, forKey: .moleculeName)
|
||||
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
|
||||
try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier)
|
||||
try container.encode(headline, forKey: .headline)
|
||||
try container.encodeIfPresent(body, forKey: .body)
|
||||
try container.encodeIfPresent(button, forKey: .button)
|
||||
|
||||
@ -26,6 +26,8 @@ import Foundation
|
||||
adjustsImageWhenHighlighted = false
|
||||
accessibilityLabel = MVMCoreUIUtility.hardcodedString(withKey: "AccCloseButton")
|
||||
setContentCompressionResistancePriority(.defaultHigh, for: .horizontal)
|
||||
heightAnchor.constraint(equalToConstant: 16.0).isActive = true
|
||||
widthAnchor.constraint(equalToConstant: 16.0).isActive = true
|
||||
}
|
||||
|
||||
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) {
|
||||
|
||||
@ -19,19 +19,15 @@ open class HeadlineBody: View {
|
||||
// MARK: - Constraints
|
||||
//--------------------------------------------------
|
||||
|
||||
var spaceBetweenLabelsConstant = PaddingOne
|
||||
var spaceBetweenLabelsConstant = Padding.One
|
||||
var spaceBetweenLabels: NSLayoutConstraint?
|
||||
var leftConstraintTitle: NSLayoutConstraint?
|
||||
var rightConstraintTitle: NSLayoutConstraint?
|
||||
var leftConstraintMessage: NSLayoutConstraint?
|
||||
var rightConstraintMessage: NSLayoutConstraint?
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Methods
|
||||
//--------------------------------------------------
|
||||
|
||||
func hasText() -> Bool {
|
||||
return headlineLabel.hasText || messageLabel.hasText
|
||||
headlineLabel.hasText || messageLabel.hasText
|
||||
}
|
||||
|
||||
// MARK: - Styling
|
||||
@ -54,25 +50,25 @@ open class HeadlineBody: View {
|
||||
}
|
||||
}
|
||||
|
||||
func styleLandingPageHeader() {
|
||||
public func styleLandingPageHeader() {
|
||||
headlineLabel.setFontStyle(.Title2XLarge)
|
||||
messageLabel.setFontStyle(.RegularBodySmall)
|
||||
spaceBetweenLabelsConstant = PaddingTwo
|
||||
spaceBetweenLabelsConstant = Padding.Two
|
||||
}
|
||||
|
||||
func stylePageHeader() {
|
||||
public func stylePageHeader() {
|
||||
headlineLabel.setFontStyle(.BoldTitleLarge)
|
||||
messageLabel.setFontStyle(.RegularBodySmall)
|
||||
spaceBetweenLabelsConstant = PaddingOne
|
||||
spaceBetweenLabelsConstant = Padding.One
|
||||
}
|
||||
|
||||
func styleListItem() {
|
||||
public func styleListItem() {
|
||||
headlineLabel.setFontStyle(.BoldBodySmall)
|
||||
messageLabel.setFontStyle(.RegularBodySmall)
|
||||
spaceBetweenLabelsConstant = 0
|
||||
}
|
||||
|
||||
func styleListItemDivider() {
|
||||
public func styleListItemDivider() {
|
||||
headlineLabel.setFontStyle(.BoldTitleMedium)
|
||||
messageLabel.setFontStyle(.RegularBodySmall)
|
||||
spaceBetweenLabelsConstant = 0
|
||||
@ -86,48 +82,41 @@ open class HeadlineBody: View {
|
||||
super.setupView()
|
||||
|
||||
backgroundColor = .clear
|
||||
clipsToBounds = true
|
||||
isAccessibilityElement = false
|
||||
shouldGroupAccessibilityChildren = true
|
||||
accessibilityElements = [headlineLabel, messageLabel]
|
||||
|
||||
let view = MVMCoreUICommonViewsUtility.commonView()
|
||||
addSubview(view)
|
||||
NSLayoutConstraint.constraintPinSubview(toSuperview: view)
|
||||
|
||||
view.isAccessibilityElement = false
|
||||
view.shouldGroupAccessibilityChildren = true
|
||||
view.accessibilityElements = [headlineLabel, messageLabel]
|
||||
|
||||
view.addSubview(headlineLabel)
|
||||
view.addSubview(messageLabel)
|
||||
addSubview(headlineLabel)
|
||||
addSubview(messageLabel)
|
||||
|
||||
headlineLabel.setContentCompressionResistancePriority(.required, for: .vertical)
|
||||
headlineLabel.setContentHuggingPriority(.required, for: .vertical)
|
||||
messageLabel.setContentCompressionResistancePriority(.required, for: .vertical)
|
||||
messageLabel.setContentHuggingPriority(.required, for: .vertical)
|
||||
view.setContentHuggingPriority(.required, for: .vertical)
|
||||
|
||||
headlineLabel.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
|
||||
headlineLabel.topAnchor.constraint(equalTo: topAnchor).isActive = true
|
||||
|
||||
spaceBetweenLabels = messageLabel.topAnchor.constraint(equalTo: headlineLabel.bottomAnchor, constant: spaceBetweenLabelsConstant)
|
||||
spaceBetweenLabels?.isActive = true
|
||||
|
||||
leftConstraintTitle = headlineLabel.leftAnchor.constraint(equalTo: view.leftAnchor)
|
||||
leftConstraintTitle?.isActive = true
|
||||
|
||||
rightConstraintTitle = view.rightAnchor.constraint(equalTo: headlineLabel.rightAnchor)
|
||||
rightConstraintTitle?.isActive = true
|
||||
|
||||
leftConstraintMessage = messageLabel.leftAnchor.constraint(equalTo: view.leftAnchor)
|
||||
leftConstraintMessage?.isActive = true
|
||||
|
||||
rightConstraintMessage = view.rightAnchor.constraint(equalTo: messageLabel.rightAnchor)
|
||||
rightConstraintMessage?.isActive = true
|
||||
|
||||
view.bottomAnchor.constraint(equalTo: messageLabel.bottomAnchor).isActive = true
|
||||
NSLayoutConstraint.activate([
|
||||
headlineLabel.leadingAnchor.constraint(equalTo: leadingAnchor),
|
||||
trailingAnchor.constraint(equalTo: headlineLabel.trailingAnchor),
|
||||
messageLabel.leadingAnchor.constraint(equalTo: leadingAnchor),
|
||||
trailingAnchor.constraint(equalTo: messageLabel.trailingAnchor),
|
||||
bottomAnchor.constraint(equalTo: messageLabel.bottomAnchor)
|
||||
])
|
||||
}
|
||||
|
||||
open override func updateView(_ size: CGFloat) {
|
||||
super.updateView(size)
|
||||
setSpacing()
|
||||
headlineLabel.updateView(size)
|
||||
messageLabel.updateView(size)
|
||||
setSpacing()
|
||||
|
||||
// Provide the label additional size information to help calculate its intrinsic height.
|
||||
let padding = MFStyler.defaultHorizontalPadding(forSize: size) * 2
|
||||
messageLabel.preferredMaxLayoutWidth = size - padding
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
@ -146,19 +135,18 @@ open class HeadlineBody: View {
|
||||
// MARK: - MoleculeViewProtocol
|
||||
//--------------------------------------------------
|
||||
|
||||
public override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
|
||||
return 58
|
||||
}
|
||||
public override class func estimatedHeight(with model: MoleculeModelProtocol,
|
||||
_ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { 58 }
|
||||
|
||||
public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||
super.set(with: model, delegateObject, additionalData)
|
||||
|
||||
guard let headlineBodyModel = model as? HeadlineBodyModel else { return }
|
||||
guard let model = model as? HeadlineBodyModel else { return }
|
||||
|
||||
style(with: headlineBodyModel.style)
|
||||
style(with: model.style)
|
||||
|
||||
headlineLabel.setOptional(with: headlineBodyModel.headline, delegateObject, additionalData)
|
||||
messageLabel.setOptional(with: headlineBodyModel.body, delegateObject, additionalData)
|
||||
headlineLabel.setOptional(with: model.headline, delegateObject, additionalData)
|
||||
messageLabel.setOptional(with: model.body, delegateObject, additionalData)
|
||||
}
|
||||
|
||||
open override func reset() {
|
||||
|
||||
@ -16,7 +16,7 @@ open class Stack<T>: Container where T: (StackModelProtocol & MoleculeModelProto
|
||||
open var stackItems: [UIView] = []
|
||||
|
||||
open var stackModel: T? {
|
||||
get { return model as? T }
|
||||
get { model as? T }
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
|
||||
@ -0,0 +1,23 @@
|
||||
//
|
||||
// AccessibilityModelProtocol.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Kevin Christiano on 2/3/21.
|
||||
// Copyright © 2021 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
|
||||
public protocol AccessibilityModelProtocol {
|
||||
|
||||
var accessibilityIdentifier: String? { get set }
|
||||
}
|
||||
|
||||
public extension AccessibilityModelProtocol {
|
||||
|
||||
var accessibilityIdentifier: String? {
|
||||
get { nil }
|
||||
set { }
|
||||
}
|
||||
}
|
||||
@ -7,22 +7,16 @@ public enum MolecularError: Swift.Error {
|
||||
}
|
||||
|
||||
|
||||
public protocol MoleculeModelProtocol: ModelProtocol {
|
||||
public protocol MoleculeModelProtocol: ModelProtocol, AccessibilityModelProtocol {
|
||||
var moleculeName: String { get }
|
||||
var backgroundColor: Color? { get set }
|
||||
}
|
||||
|
||||
public extension MoleculeModelProtocol {
|
||||
|
||||
var moleculeName: String {
|
||||
get { return Self.identifier }
|
||||
}
|
||||
var moleculeName: String { Self.identifier }
|
||||
|
||||
static var categoryName: String {
|
||||
return "\(MoleculeModelProtocol.self)"
|
||||
}
|
||||
static var categoryName: String { "\(MoleculeModelProtocol.self)" }
|
||||
|
||||
static var categoryCodingKey: String {
|
||||
return "moleculeName"
|
||||
}
|
||||
static var categoryCodingKey: String { "moleculeName" }
|
||||
}
|
||||
|
||||
@ -29,14 +29,10 @@ open class ModalMoleculeListTemplate: MoleculeListTemplate {
|
||||
super.handleNewData()
|
||||
|
||||
closeButton = MVMCoreUICommonViewsUtility.addCloseButton(to: view, action: { [weak self] _ in
|
||||
guard let self = self else {
|
||||
return
|
||||
}
|
||||
guard let model = self.templateModel as? ModalListPageTemplateModel, let actionMap = model.closeAction else {
|
||||
MVMCoreActionHandler.shared()?.handleAction(with: ActionBackModel().toJSON(), additionalData: nil, delegateObject: self.delegateObjectIVar)
|
||||
return
|
||||
}
|
||||
MVMCoreActionHandler.shared()?.handleAction(with: actionMap.toJSON(), additionalData: nil, delegateObject: self.delegateObjectIVar)
|
||||
guard let self = self else { return }
|
||||
let closeAction = (self.templateModel as? ModalListPageTemplateModel)?.closeAction ??
|
||||
ActionBackModel()
|
||||
MVMCoreActionHandler.shared()?.asyncHandleAction(with: closeAction, additionalData: nil, delegateObject: self.delegateObjectIVar)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -18,15 +18,10 @@ open class ModalMoleculeStackTemplate: MoleculeStackTemplate {
|
||||
override open func handleNewData() {
|
||||
super.handleNewData()
|
||||
_ = MVMCoreUICommonViewsUtility.addCloseButton(to: view, action: {[weak self] _ in
|
||||
guard let self = self else {
|
||||
return
|
||||
}
|
||||
|
||||
guard let model = self.templateModel as? ModalStackPageTemplateModel, let actionMap = model.closeAction else {
|
||||
MVMCoreActionHandler.shared()?.handleAction(with: ActionBackModel().toJSON(), additionalData: nil, delegateObject: self.delegateObjectIVar)
|
||||
return
|
||||
}
|
||||
MVMCoreActionHandler.shared()?.handleAction(with: actionMap.toJSON(), additionalData: nil, delegateObject: self.delegateObjectIVar)
|
||||
guard let self = self else { return }
|
||||
let closeAction = (self.templateModel as? ModalStackPageTemplateModel)?.closeAction ??
|
||||
ActionBackModel()
|
||||
MVMCoreActionHandler.shared()?.asyncHandleAction(with: closeAction, additionalData: nil, delegateObject: self.delegateObjectIVar)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -19,12 +19,9 @@ open class ModalSectionListTemplate: SectionListTemplate {
|
||||
super.handleNewData()
|
||||
_ = MVMCoreUICommonViewsUtility.addCloseButton(to: view, action: {[weak self] _ in
|
||||
guard let self = self else { return }
|
||||
guard let model = self.templateModel as? ModalSectionListTemplateModel,
|
||||
let actionMap = model.closeAction else {
|
||||
MVMCoreActionHandler.shared()?.handleAction(with: ActionBackModel().toJSON(), additionalData: nil, delegateObject: self.delegateObjectIVar)
|
||||
return
|
||||
}
|
||||
MVMCoreActionHandler.shared()?.handleAction(with: actionMap.toJSON(), additionalData: nil, delegateObject: self.delegateObjectIVar)
|
||||
let closeAction = (self.templateModel as? ModalSectionListTemplateModel)?.closeAction ??
|
||||
ActionBackModel()
|
||||
MVMCoreActionHandler.shared()?.asyncHandleAction(with: closeAction, additionalData: nil, delegateObject: self.delegateObjectIVar)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -19,7 +19,7 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol
|
||||
var observer: NSKeyValueObservation?
|
||||
|
||||
public var templateModel: ListPageTemplateModel?
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Computed Properties
|
||||
//--------------------------------------------------
|
||||
@ -41,7 +41,7 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol
|
||||
//--------------------------------------------------
|
||||
// MARK: - Methods
|
||||
//--------------------------------------------------
|
||||
|
||||
|
||||
open override func parsePageJSON() throws {
|
||||
try parseTemplate(json: loadObject?.pageJSON)
|
||||
try super.parsePageJSON()
|
||||
@ -54,8 +54,8 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol
|
||||
|
||||
open override func viewForTop() -> UIView {
|
||||
guard let headerModel = templateModel?.header,
|
||||
let molecule = MoleculeObjectMapping.shared()?.createMolecule(headerModel, delegateObject: delegateObjectIVar)
|
||||
else { return super.viewForTop() }
|
||||
let molecule = MoleculeObjectMapping.shared()?.createMolecule(headerModel, delegateObject: delegateObjectIVar)
|
||||
else { return super.viewForTop() }
|
||||
|
||||
// Temporary, Default the horizontal padding
|
||||
if var container = templateModel?.header as? ContainerModelProtocol, container.useHorizontalMargins == nil {
|
||||
@ -67,8 +67,8 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol
|
||||
|
||||
override open func viewForBottom() -> UIView {
|
||||
guard let footerModel = templateModel?.footer,
|
||||
let molecule = MoleculeObjectMapping.shared()?.createMolecule(footerModel, delegateObject: delegateObjectIVar)
|
||||
else { return super.viewForBottom() }
|
||||
let molecule = MoleculeObjectMapping.shared()?.createMolecule(footerModel, delegateObject: delegateObjectIVar)
|
||||
else { return super.viewForBottom() }
|
||||
|
||||
return molecule
|
||||
}
|
||||
@ -86,7 +86,7 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol
|
||||
//Handle scroll
|
||||
handleScrollToSpecificRow()
|
||||
}
|
||||
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Handle scroll to spefic row
|
||||
@ -117,12 +117,12 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol
|
||||
|
||||
open func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
|
||||
guard let moleculeInfo = getMoleculeInfo(for: indexPath),
|
||||
let estimatedHeight = (moleculeInfo.class as? MoleculeViewProtocol.Type)?.estimatedHeight(with: moleculeInfo.molecule, delegateObject() as? MVMCoreUIDelegateObject)
|
||||
else { return 0 }
|
||||
let estimatedHeight = (moleculeInfo.class as? MoleculeViewProtocol.Type)?.estimatedHeight(with: moleculeInfo.molecule, delegateObject() as? MVMCoreUIDelegateObject)
|
||||
else { return 0 }
|
||||
|
||||
return estimatedHeight
|
||||
}
|
||||
|
||||
|
||||
open override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
return moleculesInfo?.count ?? 0
|
||||
}
|
||||
@ -130,8 +130,8 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol
|
||||
open override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
|
||||
guard let moleculeInfo = getMoleculeInfo(for: indexPath),
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: moleculeInfo.identifier)
|
||||
else { return UITableViewCell() }
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: moleculeInfo.identifier)
|
||||
else { return UITableViewCell() }
|
||||
|
||||
(cell as? MoleculeViewProtocol)?.reset()
|
||||
(cell as? MoleculeListCellProtocol)?.setLines(with: templateModel?.line, delegateObject: delegateObjectIVar, additionalData: nil, indexPath: indexPath)
|
||||
@ -222,8 +222,8 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol
|
||||
func createMoleculeInfo(with listItem: MoleculeModelProtocol?) -> (identifier: String, class: AnyClass, molecule: MoleculeModelProtocol)? {
|
||||
|
||||
guard let listItem = listItem,
|
||||
let moleculeClass = MoleculeObjectMapping.shared()?.getMoleculeClass(listItem)
|
||||
else { return nil }
|
||||
let moleculeClass = MoleculeObjectMapping.shared()?.getMoleculeClass(listItem)
|
||||
else { return nil }
|
||||
|
||||
let moleculeName = moleculeClass.nameForReuse(with: listItem, delegateObject() as? MVMCoreUIDelegateObject) ?? listItem.moleculeName
|
||||
|
||||
|
||||
@ -14,6 +14,14 @@ import Foundation
|
||||
return 0
|
||||
}
|
||||
|
||||
open override func loadView() {
|
||||
super.loadView()
|
||||
// The height is used to keep the bottom view at the bottom.
|
||||
if let contentView = contentView, let scrollView = scrollView {
|
||||
contentView.heightAnchor.constraint(greaterThanOrEqualTo: scrollView.safeAreaLayoutGuide.heightAnchor).isActive = true
|
||||
}
|
||||
}
|
||||
|
||||
open override func handleNewData() {
|
||||
super.handleNewData()
|
||||
heightConstraint?.isActive = true
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
|
||||
public typealias BarButtonAction = (BarButtonItem) -> ()
|
||||
|
||||
|
||||
@objc class ActionDelegate: NSObject {
|
||||
var buttonAction: BarButtonAction?
|
||||
@objc func callActionBlock(_ sender: BarButtonItem) {
|
||||
@ -16,7 +17,6 @@ public typealias BarButtonAction = (BarButtonItem) -> ()
|
||||
}
|
||||
|
||||
@objcMembers open class BarButtonItem: UIBarButtonItem, MFButtonProtocol {
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Delegate
|
||||
//--------------------------------------------------
|
||||
@ -43,4 +43,3 @@ public typealias BarButtonAction = (BarButtonItem) -> ()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
|
||||
public typealias ButtonAction = (Button) -> ()
|
||||
|
||||
|
||||
@objcMembers open class Button: UIButton, MFButtonProtocol, MoleculeViewProtocol {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
@ -65,7 +66,7 @@ public typealias ButtonAction = (Button) -> ()
|
||||
/// Adds a block to be performed for the given event.
|
||||
open func addActionBlock(event: Event, _ buttonBlock: @escaping ButtonAction) {
|
||||
self.buttonAction = buttonBlock
|
||||
addTarget(self, action: #selector(callActionBlock(_:)), for: event)
|
||||
addTarget(self, action: #selector(callActionBlock), for: event)
|
||||
}
|
||||
|
||||
@objc func callActionBlock(_ sender: Button) {
|
||||
@ -103,6 +104,10 @@ public typealias ButtonAction = (Button) -> ()
|
||||
self.backgroundColor = backgroundColor.uiColor
|
||||
}
|
||||
|
||||
if let accessibilityIdentifier = model.accessibilityIdentifier {
|
||||
self.accessibilityIdentifier = accessibilityIdentifier
|
||||
}
|
||||
|
||||
if let model = model as? EnableableModelProtocol {
|
||||
isEnabled = model.enabled
|
||||
}
|
||||
@ -119,25 +124,23 @@ public typealias ButtonAction = (Button) -> ()
|
||||
// MARK: Overridables
|
||||
// Base classes need to implement these functions otherwise swift won't respect the subclass functions and use the ones in the protocol extension instead.
|
||||
open class func nameForReuse(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> String? {
|
||||
return model.moleculeName
|
||||
model.moleculeName
|
||||
}
|
||||
|
||||
open class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
|
||||
return nil
|
||||
}
|
||||
open class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { nil }
|
||||
|
||||
open class func requiredModules(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer<MVMCoreErrorObject?>?) -> [String]? {
|
||||
return nil
|
||||
}
|
||||
open class func requiredModules(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer<MVMCoreErrorObject?>?) -> [String]? { nil }
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Accessibility
|
||||
//--------------------------------------------------
|
||||
|
||||
open override func accessibilityActivate() -> Bool {
|
||||
guard isEnabled else { return false }
|
||||
buttonAction?(self)
|
||||
return buttonAction != nil
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: - MVMCoreViewProtocol
|
||||
@ -160,6 +163,6 @@ extension Button: MVMCoreViewProtocol {
|
||||
extension Button: AppleGuidelinesProtocol {
|
||||
|
||||
override open func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
|
||||
return Self.acceptablyOutsideBounds(point: point, bounds: bounds)
|
||||
Self.acceptablyOutsideBounds(point: point, bounds: bounds)
|
||||
}
|
||||
}
|
||||
|
||||
@ -51,9 +51,14 @@ import UIKit
|
||||
// MARK:- MoleculeViewProtocol
|
||||
open func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||
self.model = model
|
||||
|
||||
if let backgroundColor = model.backgroundColor {
|
||||
self.backgroundColor = backgroundColor.uiColor
|
||||
}
|
||||
|
||||
if let accessibilityIdentifier = model.accessibilityIdentifier {
|
||||
self.accessibilityIdentifier = accessibilityIdentifier
|
||||
}
|
||||
}
|
||||
|
||||
open func reset() {
|
||||
@ -63,22 +68,18 @@ import UIKit
|
||||
// MARK: Overridables
|
||||
// Base classes need to implement these functions otherwise swift won't respect the subclass functions and use the ones in the protocol extension instead.
|
||||
open class func nameForReuse(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> String? {
|
||||
return model.moleculeName
|
||||
model.moleculeName
|
||||
}
|
||||
|
||||
open class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
|
||||
return nil
|
||||
}
|
||||
open class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { nil }
|
||||
|
||||
open class func requiredModules(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer<MVMCoreErrorObject?>?) -> [String]? {
|
||||
return nil
|
||||
}
|
||||
open class func requiredModules(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer<MVMCoreErrorObject?>?) -> [String]? { nil }
|
||||
}
|
||||
|
||||
// MARK: - AppleGuidelinesProtocol
|
||||
extension Control: AppleGuidelinesProtocol {
|
||||
override open func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
|
||||
return Self.acceptablyOutsideBounds(point: point, bounds: bounds)
|
||||
Self.acceptablyOutsideBounds(point: point, bounds: bounds)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -53,33 +53,35 @@ open class ImageView: UIImageView, MoleculeViewProtocol {
|
||||
}
|
||||
|
||||
public func reset() {
|
||||
backgroundColor = .clear
|
||||
}
|
||||
|
||||
backgroundColor = .clear
|
||||
}
|
||||
|
||||
public func setAsMolecule() { }
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - ModelMoleculeViewProtocol
|
||||
//--------------------------------------------------
|
||||
|
||||
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
|
||||
|
||||
if let backgroundColor = model.backgroundColor {
|
||||
self.backgroundColor = backgroundColor.uiColor
|
||||
}
|
||||
|
||||
if let accessibilityIdentifier = model.accessibilityIdentifier {
|
||||
self.accessibilityIdentifier = accessibilityIdentifier
|
||||
}
|
||||
}
|
||||
|
||||
open class func nameForReuse(_ model: MoleculeModelProtocol?, _ delegateObject: MVMCoreUIDelegateObject?) -> String? {
|
||||
return model?.moleculeName
|
||||
model?.moleculeName
|
||||
}
|
||||
|
||||
open class func estimatedHeight(forRow molecule: MoleculeModelProtocol?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
|
||||
return nil
|
||||
}
|
||||
open class func estimatedHeight(forRow molecule: MoleculeModelProtocol?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { nil }
|
||||
|
||||
open class func requiredModules(_ molecule: MoleculeModelProtocol?, delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer<MVMCoreErrorObject?>?) -> [String]? {
|
||||
return nil
|
||||
}
|
||||
open class func requiredModules(_ molecule: MoleculeModelProtocol?, delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer<MVMCoreErrorObject?>?) -> [String]? { nil }
|
||||
}
|
||||
|
||||
// MARK:- MVMCoreViewProtocol
|
||||
@ -94,4 +96,3 @@ extension ImageView: MVMCoreViewProtocol {
|
||||
MVMCoreUIUtility.setMarginsFor(self, leading: 0, top: 0, trailing: 0, bottom: 0)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -6,7 +6,6 @@
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@objcMembers open class SectionHeaderFooterView: UITableViewHeaderFooterView, MoleculeViewProtocol {
|
||||
//--------------------------------------------------
|
||||
@ -43,10 +42,16 @@ import Foundation
|
||||
//--------------------------------------------------
|
||||
|
||||
open func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||
|
||||
self.model = model
|
||||
|
||||
if let backgroundColor = model.backgroundColor {
|
||||
contentView.backgroundColor = backgroundColor.uiColor
|
||||
}
|
||||
|
||||
if let accessibilityIdentifier = model.accessibilityIdentifier {
|
||||
self.accessibilityIdentifier = accessibilityIdentifier
|
||||
}
|
||||
}
|
||||
|
||||
open func reset() {
|
||||
@ -56,16 +61,12 @@ import Foundation
|
||||
// MARK: Overridables
|
||||
// Base classes need to implement these functions otherwise swift won't respect the subclass functions and use the ones in the protocol extension instead.
|
||||
open class func nameForReuse(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> String? {
|
||||
return model.moleculeName
|
||||
model.moleculeName
|
||||
}
|
||||
|
||||
open class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
|
||||
return nil
|
||||
}
|
||||
open class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { nil }
|
||||
|
||||
open class func requiredModules(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer<MVMCoreErrorObject?>?) -> [String]? {
|
||||
return nil
|
||||
}
|
||||
open class func requiredModules(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer<MVMCoreErrorObject?>?) -> [String]? { nil }
|
||||
}
|
||||
|
||||
// MARK:- MVMCoreViewProtocol
|
||||
|
||||
@ -11,7 +11,7 @@ import Foundation
|
||||
@objcMembers open class TableView: UITableView {
|
||||
|
||||
/// A block that gets called on tableview frame changes
|
||||
public var frameChangeAction: (() -> Void)?
|
||||
public var frameChangeAction: (() -> ())?
|
||||
|
||||
private var previousFrame = CGRect.zero
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user